diff --git a/cronjobs/blockupdate.php b/cronjobs/blockupdate.php index f7938dee..c1ef23b5 100755 --- a/cronjobs/blockupdate.php +++ b/cronjobs/blockupdate.php @@ -54,10 +54,18 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { $log->logInfo(sprintf($strLogMask, $aBlock['id'], $aBlock['height'], $aBlock['blockhash'], $aBlock['confirmations'], $aBlockInfo['confirmations'], $status)); continue; } - if ($aBlock['confirmations'] == $aBlockInfo['confirmations']) { + if (isset($aBlockInfo['confirmations'])) { + $iRPCConfirmations = $aBlockInfo['confirmations']; + } else if (isset($aTxDetails['confirmations'])) { + $iRPCConfirmations = $aTxDetails['confirmations']; + } else { + $log->logFatal(' RPC does not return any usable block confirmation information'); + $monitoring->endCronjob($cron_name, 'E0082', 1, true); + } + if ($iRPCConfirmations == $aBlock['confirmations']) { continue; } else { - if (!$block->setConfirmations($aBlock['id'], $aBlockInfo['confirmations'])) { + if (!$block->setConfirmations($aBlock['id'], $iRPCConfirmations)) { $log->logError(' Failed to update block confirmations: ' . $block->getCronMessage()); $status = 'ERROR'; } else { @@ -67,7 +75,7 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { $log->logInfo(sprintf($strLogMask, 'ID', 'Height', 'Blockhash', 'Old', 'New', 'Status')); $header = true; } - $log->logInfo(sprintf($strLogMask, $aBlock['id'], $aBlock['height'], $aBlock['blockhash'], $aBlock['confirmations'], $aBlockInfo['confirmations'], $status)); + $log->logInfo(sprintf($strLogMask, $aBlock['id'], $aBlock['height'], $aBlock['blockhash'], $aBlock['confirmations'], $iRPCConfirmations, $status)); } } diff --git a/cronjobs/etc/logrotate.conf b/cronjobs/etc/logrotate.conf index 341b89e7..5ec8786e 100644 --- a/cronjobs/etc/logrotate.conf +++ b/cronjobs/etc/logrotate.conf @@ -1,4 +1,4 @@ -"./logs/*.txt" { +"./logs/*/*.txt" { copytruncate rotate 7 compress diff --git a/cronjobs/findblock.php b/cronjobs/findblock.php index 4ee9f644..42e347a0 100755 --- a/cronjobs/findblock.php +++ b/cronjobs/findblock.php @@ -26,7 +26,7 @@ chdir(dirname(__FILE__)); require_once('shared.inc.php'); // Fetch our last block found from the DB as a starting point -$aLastBlock = @$block->getLast(); +$aLastBlock = @$block->getLastValid(); $strLastBlockHash = $aLastBlock['blockhash']; if (!$strLastBlockHash) $strLastBlockHash = ''; @@ -58,6 +58,15 @@ if (empty($aTransactions['transactions'])) { $aBlockRPCInfo = $bitcoin->getblock($aData['blockhash']); $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'])) { + $aData['confirmations'] = $aBlockRPCInfo['confirmations']; + } else if (isset($aTxDetails['confirmations'])) { + $aData['confirmations'] = $aTxDetails['confirmations']; + } else { + $log->logFatal(' RPC does not return any usable block confirmation information'); + $monitoring->endCronjob($cron_name, 'E0082', 1, true); + } $aData['difficulty'] = $aBlockRPCInfo['difficulty']; $log->logInfo(sprintf($strLogMask, substr($aData['blockhash'], 0, 17)."...", $aData['height'], $aData['amount'], $aData['confirmations'], $aData['difficulty'], strftime("%Y-%m-%d %H:%M:%S", $aData['time']))); if ( ! empty($aBlockRPCInfo['flags']) && preg_match('/proof-of-stake/', $aBlockRPCInfo['flags']) ) { diff --git a/cronjobs/notifications.php b/cronjobs/notifications.php index 7baf5bf1..ffbc6943 100755 --- a/cronjobs/notifications.php +++ b/cronjobs/notifications.php @@ -29,47 +29,49 @@ if ($setting->getValue('disable_notifications') == 1) { $monitoring->endCronjob($cron_name, 'E0009', 0, true, false); } -$log->logDebug(" IDLE Worker Notifications ..."); -// Find all IDLE workers -$aWorkers = $worker->getAllIdleWorkers(); -if (empty($aWorkers)) { - $log->logDebug(" no idle workers found"); -} else { - $log->logInfo(" found " . count($aWorkers) . " IDLE workers"); - foreach ($aWorkers as $aWorker) { - $aData = $aWorker; - $aData['username'] = $user->getUserName($aWorker['account_id']); - $aData['subject'] = 'IDLE Worker : ' . $aWorker['username']; - $aData['worker'] = $aWorker['username']; - $aData['email'] = $user->getUserEmail($aData['username']); - $log->logDebug(" " . $aWorker['username'] . "..."); - if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData)) - $log->logDebug(" Failed sending notifications: " . $notification->getCronError()); - } -} - - -$log->logDebug(" Reset IDLE Worker Notifications ..."); -// We notified, lets check which recovered -$aNotifications = $notification->getAllActive('idle_worker'); -if (!empty($aNotifications)) { - $log->logInfo(" found " . count($aNotifications) . " active notification(s)"); - foreach ($aNotifications as $aNotification) { - $aData = json_decode($aNotification['data'], true); - $aWorker = $worker->getWorker($aData['id']); - $log->logDebug(" " . $aWorker['username'] . " ..."); - if ($aWorker['hashrate'] > 0) { - if ($notification->setInactive($aNotification['id'])) { - $log->logDebug(" updated #" . $aNotification['id'] . " for " . $aWorker['username'] . " as inactive"); - } else { - $log->logError(" failed to update #" . $aNotification['id'] . " for " . $aWorker['username']); - } - } else { - $log->logDebug(" still inactive"); +if ($setting->getValue('notifications_disable_idle_worker') != 1) { + $log->logDebug(" IDLE Worker Notifications ..."); + // Find all IDLE workers + $aWorkers = $worker->getAllIdleWorkers(); + if (empty($aWorkers)) { + $log->logDebug(" no idle workers found"); + } else { + $log->logInfo(" found " . count($aWorkers) . " IDLE workers"); + foreach ($aWorkers as $aWorker) { + $aData = $aWorker; + $aData['username'] = $user->getUserName($aWorker['account_id']); + $aData['subject'] = 'IDLE Worker : ' . $aWorker['username']; + $aData['worker'] = $aWorker['username']; + $aData['email'] = $user->getUserEmail($aData['username']); + $log->logDebug(" " . $aWorker['username'] . "..."); + if (!$notification->sendNotification($aWorker['account_id'], 'idle_worker', $aData)) + $log->logDebug(" Failed sending notifications: " . $notification->getCronError()); } } -} else { - $log->logDebug(" no active IDLE worker notifications"); + + + $log->logDebug(" Reset IDLE Worker Notifications ..."); + // We notified, lets check which recovered + $aNotifications = $notification->getAllActive('idle_worker'); + if (!empty($aNotifications)) { + $log->logInfo(" found " . count($aNotifications) . " active notification(s)"); + foreach ($aNotifications as $aNotification) { + $aData = json_decode($aNotification['data'], true); + $aWorker = $worker->getWorker($aData['id']); + $log->logDebug(" " . $aWorker['username'] . " ..."); + if ($aWorker['hashrate'] > 0) { + if ($notification->setInactive($aNotification['id'])) { + $log->logDebug(" updated #" . $aNotification['id'] . " for " . $aWorker['username'] . " as inactive"); + } else { + $log->logError(" failed to update #" . $aNotification['id'] . " for " . $aWorker['username']); + } + } else { + $log->logDebug(" still inactive"); + } + } + } else { + $log->logDebug(" no active IDLE worker notifications"); + } } require_once('cron_end.inc.php'); diff --git a/cronjobs/payouts.php b/cronjobs/payouts.php index 23730052..5b9caa73 100755 --- a/cronjobs/payouts.php +++ b/cronjobs/payouts.php @@ -48,10 +48,10 @@ if (!$dWalletBalance = $bitcoin->getrealbalance()) empty($config['network_confirmations']) ? $confirmations = 120 : $confirmations = $config['network_confirmations']; $aBlocksUnconfirmed = $block->getAllUnconfirmed($confirmations); $dBlocksUnconfirmedBalance = 0; - if (!empty($aBlocksUnconfirmed))foreach ($aBlocksUnconfirmed as $aData) $dBlocksUnconfirmedBalance += $aData['amount']; - -$dWalletBalance -= $dBlocksUnconfirmedBalance; - +if (!empty($aBlocksUnconfirmed))foreach ($aBlocksUnconfirmed as $aData) $dBlocksUnconfirmedBalance += $aData['amount']; +if ($config['getbalancewithunconfirmed']) { + $dWalletBalance -= $dBlocksUnconfirmedBalance; +} // Fetch Newmint $aGetInfo = $bitcoin->getinfo(); if (is_array($aGetInfo) && array_key_exists('newmint', $aGetInfo)) { @@ -135,10 +135,10 @@ if (!$dWalletBalance = $bitcoin->getrealbalance()) empty($config['network_confirmations']) ? $confirmations = 120 : $confirmations = $config['network_confirmations']; $aBlocksUnconfirmed = $block->getAllUnconfirmed($confirmations); $dBlocksUnconfirmedBalance = 0; - if (!empty($aBlocksUnconfirmed))foreach ($aBlocksUnconfirmed as $aData) $dBlocksUnconfirmedBalance += $aData['amount']; - -$dWalletBalance -= $dBlocksUnconfirmedBalance; - +if (!empty($aBlocksUnconfirmed))foreach ($aBlocksUnconfirmed as $aData) $dBlocksUnconfirmedBalance += $aData['amount']; +if ($config['getbalancewithunconfirmed']) { + $dWalletBalance -= $dBlocksUnconfirmedBalance; +} // Fetch Newmint $aGetInfo = $bitcoin->getinfo(); if (is_array($aGetInfo) && array_key_exists('newmint', $aGetInfo)) { diff --git a/cronjobs/pplns_payout.php b/cronjobs/pplns_payout.php index 08656ed7..c256b279 100755 --- a/cronjobs/pplns_payout.php +++ b/cronjobs/pplns_payout.php @@ -181,8 +181,8 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { } // Table header for account shares - $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %20.20s | %20.20s | %20.20s |"; - $log->logInfo(sprintf($strLogMask, 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee')); + $strLogMask = "| %5.5s | %-15.15s | %15.15s | %15.15s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; + $log->logInfo(sprintf($strLogMask, 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee', 'Bonus')); // Loop through all accounts that have found shares for this round foreach ($aTotalAccountShares as $key => $aData) { @@ -201,16 +201,28 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { // Defaults $aData['fee' ] = 0; $aData['donation'] = 0; + $aData['pool_bonus'] = 0; + // Calculate pool fees if ($config['fees'] > 0 && $aData['no_fees'] == 0) $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + + // 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); + } else { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + } + } + // Calculate donation amount, fees not included $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); // Verbose output of this users calculations $log->logInfo( sprintf($strLogMask, $aData['id'], $aData['username'], $aData['pplns_valid'], $aData['pplns_invalid'], - number_format($aData['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8) + 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) ) ); @@ -225,6 +237,10 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { if ($aData['donation'] > 0) if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation', $aBlock['id'])) $log->logFatal('Failed to insert new Donation transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError() . 'on block ' . $aBlock['id']); + // Add new bonus credit + if ($aData['pool_bonus'] > 0) + if (!$transaction->addTransaction($aData['id'], $aData['pool_bonus'], 'Bonus', $aBlock['id'])) + $log->logFatal('Failed to insert new Bonus transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); } // Add full round share statistics diff --git a/cronjobs/pps_payout.php b/cronjobs/pps_payout.php index 4b5a0e9e..509176d2 100755 --- a/cronjobs/pps_payout.php +++ b/cronjobs/pps_payout.php @@ -63,7 +63,7 @@ if ($config['pps']['reward']['type'] == 'blockavg' && $block->getBlockCount() > } // Per-share value to be paid out to users -$pps_value = round($pps_reward / (pow(2, $config['target_bits']) * $dDifficulty), 12); +$pps_value = round($coin->calcPPSValue($pps_reward, $dDifficulty), 12); // Find our last share accounted and last inserted share for PPS calculations if (!$iPreviousShareId = $setting->getValue('pps_last_share_id')) { @@ -105,9 +105,8 @@ foreach ($aAccountShares as $aData) { continue; } - // MPOS uses a base difficulty setting to avoid showing weightened shares - // Since we need weightened shares here, we go back to the proper value for payouts - $aData['payout'] = round($aData['valid'] * pow(2, ($config['difficulty'] - 16)) * $pps_value, 12); + // Payout for this user + $aData['payout'] = round($aData['valid'] * $pps_value, 12); // Defaults $aData['fee' ] = 0; @@ -120,7 +119,7 @@ foreach ($aAccountShares as $aData) { $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 12); $log->logInfo(sprintf( - $strLogMask, $aData['id'], $aData['username'], $aData['invalid'], $aData['valid'] * pow(2, ($config['difficulty'] - 16)), + $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) )); diff --git a/cronjobs/proportional_payout.php b/cronjobs/proportional_payout.php index a91ba7a4..58f47ee9 100755 --- a/cronjobs/proportional_payout.php +++ b/cronjobs/proportional_payout.php @@ -40,8 +40,8 @@ if (empty($aAllBlocks)) { $count = 0; // Table header for account shares -$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %20.20s | %20.20s | %20.20s |"; -$log->logInfo(sprintf($strLogMask, 'Block', 'ID', 'Username', 'Valid', 'Invalid', 'Percentage', 'Payout', 'Donation', 'Fee')); +$strLogMask = "| %10.10s | %-5.5s | %15.15s | %15.15s | %12.12s | %12.12s | %15.15s | %15.15s | %15.15s | %15.15s |"; +$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 if (!$aBlock['share_id']) { @@ -86,18 +86,30 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { // Defaults $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); + // Calculate pool fees if they apply if ($config['fees'] > 0 && $aData['no_fees'] == 0) $aData['fee'] = round($config['fees'] / 100 * $aData['payout'], 8); + + // 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); + } else { + $aData['pool_bonus'] = round(( $config['pool_bonus'] / 100 ) * $aData['payout'], 8); + } + } + // Calculate donation amount, fees not included $aData['donation'] = round($user->getDonatePercent($user->getUserId($aData['username'])) / 100 * ( $aData['payout'] - $aData['fee']), 8); // 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['percentage'], 8), number_format($aData['payout'], 8), number_format($aData['donation'], 8), number_format($aData['fee'], 8), number_format($aData['pool_bonus'], 8)) ); // Update user share statistics @@ -114,6 +126,10 @@ foreach ($aAllBlocks as $iIndex => $aBlock) { if ($aData['donation'] > 0) if (!$transaction->addTransaction($aData['id'], $aData['donation'], 'Donation', $aBlock['id'])) $log->logFatal('Failed to insert new Donation transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); + // Add new bonus credit + if ($aData['pool_bonus'] > 0) + if (!$transaction->addTransaction($aData['id'], $aData['pool_bonus'], 'Bonus', $aBlock['id'])) + $log->logFatal('Failed to insert new Bonus transaction to database for ' . $aData['username'] . ': ' . $transaction->getCronError()); } // Add block as accounted for into settings table diff --git a/cronjobs/run-crons.sh b/cronjobs/run-crons.sh index d1cca24b..90fe718f 100755 --- a/cronjobs/run-crons.sh +++ b/cronjobs/run-crons.sh @@ -1,5 +1,7 @@ #!/bin/bash +echo "Please be aware: This cron is deprecated and will be removed. Please read: https://github.com/MPOS/php-mpos/wiki/Cronjobs#setup" +sleep 2 ######################### # # diff --git a/cronjobs/tickerupdate.php b/cronjobs/tickerupdate.php index 7d25abf5..0075a260 100755 --- a/cronjobs/tickerupdate.php +++ b/cronjobs/tickerupdate.php @@ -33,18 +33,26 @@ $log->logInfo('Running periodic tasks to update database values for GUI access') $strLogMask = "| %-25.25s | %15.15s | %8.8s | %-6.6s | %-80.80s |"; $log->logInfo(sprintf($strLogMask, 'Method', 'Value', 'Runtime', 'Status', 'Message')); +empty($config['price']['enabled']) ? $tickerupdate = false : $tickerupdate = $config['price']['enabled']; + // Fetch latest coin price via API call $start = microtime(true); -$message = 'Updated latest ' . $config['currency'] . ' price from ' . $config['price']['url'] . ' API'; -$status = 'OK'; -if ($price = $tools->getPrice()) { - if (!$setting->setValue('price', $price)) { - $message = 'Unable to store new price value: ' . $setting->getCronError(); +if ($tickerupdate) { + $message = 'Updated latest ' . $config['currency'] . ' price from ' . $config['price']['url'] . ' API'; + $status = 'OK'; + if ($price = $tools->getPrice()) { + if (!$setting->setValue('price', $price)) { + $message = 'Unable to store new price value: ' . $setting->getCronError(); + $status = 'ERROR'; + } + } else { + $message = 'Failed to fetch price from API: ' . $tools->getCronError(); $status = 'ERROR'; } } else { - $message = 'Failed to fetch price from API: ' . $tools->getCronError(); - $status = 'ERROR'; + $message = 'Tickerupdate is disabled'; + $status = 'OK'; + $price = 0; } $log->logInfo(sprintf($strLogMask, 'Price Update', $price, number_format(microtime(true) - $start, 3), $status, $message)); diff --git a/public/include/admin_checks.php b/public/include/admin_checks.php index b10e9dfa..179d873a 100644 --- a/public/include/admin_checks.php +++ b/public/include/admin_checks.php @@ -6,25 +6,27 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $notice = array(); $enotice = array(); $error = array(); - + // setup some basic stuff for checking - getuid/getpwuid not available on mac/windows $apache_user = 'unknown'; - if (substr_count(strtolower(PHP_OS), 'nix') > 0) { + if (substr_count(strtolower(PHP_OS), 'nix') > 0 || substr_count(strtolower(PHP_OS), 'linux') > 0) { $apache_user = (function_exists('posix_getuid')) ? posix_getuid() : 'unknown'; $apache_user = (function_exists('posix_getpwuid')) ? posix_getpwuid($apache_user) : $apache_user; } - + // setup checks // logging if ($config['logging']['enabled']) { if (!is_writable($config['logging']['path'])) { - $error[] = "Logging is enabled but we can't write in the logging path"; + $error[] = "Logging is enabled but we can't write in the logfile path"; } } + // check if memcache isn't available but enabled in config -> error if (!class_exists('Memcached') && $config['memcache']['enabled']) { - $error[] = "You have memcache enabled in your config and it's not available. Install the package on your system."; + $error[] = "You have memcached enabled in your config and it's not available as a PHP module. Install the package on your system."; } + // if it's not enabled, test it if it exists, if it works -> error tell them to enable, -> otherwise notice it's disabled if (!$config['memcache']['enabled']) { if (PHP_OS == 'WINNT') { @@ -38,16 +40,18 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $memcache_test_get = @$memcache_test->get('test_mpos_setval'); } if (class_exists('Memcached') && $memcache_test_get == $randmctv) { - $error[] = "You have memcache disabled in the config and it's available & works! Enable it."; + $error[] = "You have memcache disabled in the config but it's available and works! Enable it for best performance."; } else { $notice[] = "Memcache is disabled; Almost every linux distro has packages for it, you should be using it if you can."; } } + // check if htaccess exists if (!file_exists(BASEPATH.".htaccess")) { $htaccess_link = ".htaccess"; - $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using apache set it up $htaccess_link"; + $notice[] = "You don't seem to have a .htaccess in your public folder, if you're using Apache set it up: $htaccess_link"; } + // check if we can write templates/cache and templates/compile -> error if (!is_writable(THEME_DIR.'/cache')) { $error[] = "templates/cache folder is not writable for uid {$apache_user['name']}"; @@ -55,11 +59,13 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ if (!is_writable(THEME_DIR.'/compile')) { $error[] = "templates/compile folder is not writable for uid {$apache_user['name']}"; } + // check if we can write the config files, we should NOT be able to -> error if (is_writable(INCLUDE_DIR.'/config/global.inc.php') || is_writable(INCLUDE_DIR.'/config/global.inc.dist.php') || is_writable(INCLUDE_DIR.'/config/security.inc.php') || is_writable(INCLUDE_DIR.'/config/security.inc.dist.php')) { $error[] = "Your config files SHOULD NOT be writable to this user!"; } + // check if daemon can connect -> error try { if ($bitcoin->can_connect() !== true) { @@ -76,7 +82,7 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ if (!$bitcoin->validateaddress($config['coldwallet']['address'])) $error[] = "Your cold wallet address is SET and INVALID"; } - + // check if there is more than one account set on wallet $accounts = $bitcoin->listaccounts(); if (count($accounts) > 1 && $accounts[''] <= 0) { @@ -85,34 +91,34 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ } } catch (Exception $e) { } - // if database connection fails -> error - $db_connect = new mysqli($config['db']['host'], $config['db']['user'], $config['db']['pass'], $config['db']['name'], $config['db']['port']); - if (mysqli_connect_errno() || !array_key_exists('client_info', $db_connect)) { - $error[] = "Unable to connect to mysql using provided credentials"; - } + // check anti DOS protection, we need memcache for that if ($config['mc_antidos'] && !$config['memcache']['enabled']) { $error[] = "mc_antidos is enabled and memcache is not, memcache is required to use this"; } + // poke stratum using gettingstarted details -> enotice - if (substr_count(strtolower(PHP_OS), 'nix') > 0) { - // unix *poke* - $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP); - if ($socket !== false) { - $address = @gethostbyname($config['gettingstarted']['stratumurl']); - $result = @socket_connect($socket, $address, $config['gettingstarted']['stratumport']); - if ($result !== 1) { - $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; - } - $close = @socket_close($socket); + if (function_exists('socket_create')) { + $host = @gethostbyname($config['gettingstarted']['stratumurl']); + $port = $config['gettingstarted']['stratumport']; + + if (isset($host) and + isset($port) and + ($socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) and + (socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array('sec' => 3, 'usec' => 0))) and + (@socket_connect($socket, $host, $port))) + { + socket_close($socket); + } else { + $enotice[] = 'We tried to poke your Stratum server using your $config[\'gettingstarted\'] settings but it didn\'t respond - ' . socket_strerror(socket_last_error()); } } else { - // mac/windows *poke* - if (! $fp = @fsockopen($config['gettingstarted']['stratumurl'],$config['gettingstarted']['stratumport'],$errCode,$errStr,1)) { - $enotice[] = "We tried to poke your Stratum server using config->gettingstarted details but it didn't respond"; + // Connect via fsockopen as fallback + if (! $fp = @fsockopen($config['gettingstarted']['stratumurl'], $config['gettingstarted']['stratumport'], $errCode, $errStr, 1)) { + $enotice[] = 'We tried to poke your Stratum server using your $config[\'gettingstarted\'] settings but it didn\'t respond'; } @fclose($fp); } - + // security checks // salts too short -> notice, salts default -> error if ((strlen($config['SALT']) < 24) || (strlen($config['SALTY']) < 24) || $config['SALT'] == 'PLEASEMAKEMESOMETHINGRANDOM' || $config['SALTY'] == 'THISSHOULDALSOBERRAANNDDOOM') { @@ -122,19 +128,19 @@ if (@$_SESSION['USERDATA']['is_admin'] && $user->isAdmin(@$_SESSION['USERDATA'][ $notice[] = "SALT or SALTY is too short, they should be more than 24 characters and changing them will require registering again"; } } - + // display the errors foreach ($enotice as $en) { - $_SESSION['POPUP'][] = array('CONTENT' => $en, 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $en, 'TYPE' => 'alert alert-info'); } if (!count($notice) && !count($error)) { - $_SESSION['POPUP'][] = array('CONTENT' => 'The config options we checked seem OK', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'The config options we checked seem OK', 'TYPE' => 'alert alert-success'); } else { foreach ($notice as $n) { - $_SESSION['POPUP'][] = array('CONTENT' => $n, 'TYPE' => 'warning'); + $_SESSION['POPUP'][] = array('CONTENT' => $n, 'TYPE' => 'alert alert-warning'); } foreach ($error as $e) { - $_SESSION['POPUP'][] = array('CONTENT' => $e, 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $e, 'TYPE' => 'alert alert-danger'); } } } diff --git a/public/include/autoloader.inc.php b/public/include/autoloader.inc.php index cea1a7a3..c81a4812 100644 --- a/public/include/autoloader.inc.php +++ b/public/include/autoloader.inc.php @@ -2,13 +2,6 @@ (SECURITY == "*)WT#&YHfd" && SECHASH_CHECK) ? die("public/index.php -> Set a new SECURITY value to continue") : 0; $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; -// SHA/Scrypt check -if (empty($config['algorithm']) || $config['algorithm'] == 'scrypt') { - $config['target_bits'] = 16; -} else { - $config['target_bits'] = 32; -} - // Default classes require_once(INCLUDE_DIR . '/lib/KLogger.php'); require_once(CLASS_DIR . '/logger.class.php'); @@ -20,24 +13,31 @@ require_once(INCLUDE_DIR . '/database.inc.php'); require_once(INCLUDE_DIR . '/config/memcache_keys.inc.php'); require_once(INCLUDE_DIR . '/config/error_codes.inc.php'); -// We need to load these two first +// 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 . '/setting.class.php'); -// We need this one in here to properly set our theme -require_once(INCLUDE_DIR . '/lib/Mobile_Detect.php'); +// Now decide on which coin class to load and instantiate +if (file_exists(CLASS_DIR . '/coins/coin_' . $config['algorithm'] . '.class.php')) { + require_once(CLASS_DIR . '/coins/coin_' . $config['algorithm'] . '.class.php'); + $coin = new Coin(); + $coin->setConfig($config); +} else { + die('Unable to load your coins class definition for ' . $config['algorithm']); +} + +// Swiftmailer +require_once(INCLUDE_DIR . '/lib/swiftmailer/swift_required.php'); // Detect device -if ($detect->isMobile() && $setting->getValue('website_mobile_theme')) { - // Set to mobile theme - $setting->getValue('website_mobile_theme') ? $theme = $setting->getValue('website_mobile_theme') : $theme = 'mobile'; -} else if ( PHP_SAPI == 'cli') { +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 = 'mpos'; + $setting->getValue('website_theme') ? $theme = $setting->getValue('website_theme') : $theme = 'bootstrap'; } define('THEME', $theme); diff --git a/public/include/bootstrap.php b/public/include/bootstrap.php index fc300de6..fe6a9d02 100644 --- a/public/include/bootstrap.php +++ b/public/include/bootstrap.php @@ -11,21 +11,21 @@ define('THEME_DIR', BASEPATH . 'templates'); $quickstartlink = "Quick Start Guide"; // 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/global.inc.php')) die('Unable to load your global config - '.$quickstartlink); +if (!include_once(BASEPATH . 'include/config/global.inc.dist.php')) die('Unable to load base global config from ['.BASEPATH . 'include/config/global.inc.dist.php' . '] - '.$quickstartlink); +if (!@include_once(BASEPATH . 'include/config/global.inc.php')) die('Unable to load your global config from ['.BASEPATH . 'include/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 (!include_once(BASEPATH . 'include/config/security.inc.dist.php')) die('Unable to load base security config from ['.BASEPATH . 'include/config/security.inc.dist.php' . '] - '.$quickstartlink); if (@file_exists(BASEPATH . 'include/config/security.inc.php')) include_once(BASEPATH . 'include/config/security.inc.php'); // start our session, we need it for smarty caching -$session_start = @session_start(); session_set_cookie_params(time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); +$session_start = @session_start(); if (!$session_start) { - $log->log("info", "Forcing session id regeneration, session failed to start [hijack attempt?]"); - session_destroy(); - session_regenerate_id(true); - session_start(); + $log->log("info", "Forcing session id regeneration, session failed to start [hijack attempt?]"); + session_destroy(); + session_regenerate_id(true); + session_start(); } @setcookie(session_name(), session_id(), time()+$config['cookie']['duration'], $config['cookie']['path'], $config['cookie']['domain'], $config['cookie']['secure'], $config['cookie']['httponly']); @@ -36,4 +36,4 @@ $master_template = 'master.tpl'; // We include all needed files here, even though our templates could load them themself require_once(INCLUDE_DIR . '/autoloader.inc.php'); -?> +?> \ No newline at end of file diff --git a/public/include/classes/api.class.php b/public/include/classes/api.class.php index 8e245a22..913a1f03 100644 --- a/public/include/classes/api.class.php +++ b/public/include/classes/api.class.php @@ -15,6 +15,7 @@ class Api extends Base { return true; } else { if ($error == true) { + unset($_SESSION['POPUP']); header('HTTP/1.1 501 Not implemented'); die('501 Not implemented'); } diff --git a/public/include/classes/base.class.php b/public/include/classes/base.class.php index 34aa33cd..1bb27e3a 100644 --- a/public/include/classes/base.class.php +++ b/public/include/classes/base.class.php @@ -19,6 +19,9 @@ class Base { public function setDebug($debug) { $this->debug = $debug; } + public function setCoin($coin) { + $this->coin = $coin; + } public function setLog($log) { $this->log = $log; } diff --git a/public/include/classes/bitcoinwrapper.class.php b/public/include/classes/bitcoinwrapper.class.php index 91af6ad2..3679ee43 100644 --- a/public/include/classes/bitcoinwrapper.class.php +++ b/public/include/classes/bitcoinwrapper.class.php @@ -74,6 +74,10 @@ class BitcoinWrapper extends BitcoinClient { if (is_array($dNetworkHashrate)) { if (array_key_exists('networkhashps', $dNetworkHashrate)) { $dNetworkHashrate = $dNetworkHashrate['networkhashps']; + } else if (array_key_exists('networkmhps', $dNetworkHashrate)) { + $dNetworkHashrate = $dNetworkHashrate['networkmhps'] * 1000 * 1000; + } else if (array_key_exists('networkghps', $dNetworkHashrate)) { + $dNetworkHashrate = $dNetworkHashrate['networkghps'] * 1000 * 1000 * 1000; } else if (array_key_exists('hashespersec', $dNetworkHashrate)) { $dNetworkHashrate = $dNetworkHashrate['hashespersec']; } else if (array_key_exists('netmhashps', $dNetworkHashrate)) { diff --git a/public/include/classes/block.class.php b/public/include/classes/block.class.php index 76ccf43d..cf0ea7ee 100644 --- a/public/include/classes/block.class.php +++ b/public/include/classes/block.class.php @@ -15,6 +15,18 @@ class Block extends Base { return $result->fetch_assoc(); return $this->sqlError(); } + + /** + * Specific method to fetch the latest block found that is VALID + * @param none + * @return data array Array with database fields as keys + **/ + public function getLastValid() { + $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE confirmations > -1 ORDER BY height DESC LIMIT 1"); + if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) + return $result->fetch_assoc(); + return $this->sqlError(); + } /** * Get a specific block, by block height diff --git a/public/include/classes/coins/coin_base.class.php b/public/include/classes/coins/coin_base.class.php new file mode 100644 index 00000000..7eeb3ee1 --- /dev/null +++ b/public/include/classes/coins/coin_base.class.php @@ -0,0 +1,69 @@ +target_bits; + } + + /** + * Calculate the PPS value for this coin + * WARNING: Get this wrong and you will over- or underpay your miners! + **/ + public function calcPPSValue($pps_reward, $dDifficulty) { + return ($pps_reward / (pow(2, $this->target_bits) * $dDifficulty)); + } + + /** + * Calculate our hashrate based on shares inserted to DB + * We use diff1 share values, not a baseline one + **/ + public function calcHashrate($shares, $interval) { + return $shares * pow(2, $this->target_bits) / $interval / 1000; + } + + /** + * Calculate estimated shares of this coin, this is using baseline + * according to our configuration difficulty + **/ + public function calcEstaimtedShares($dDifficulty) { + return (int)round(pow(2, (32 - $this->target_bits)) * $dDifficulty, 0); + } + + /** + * Calculate our networks expected time per block + **/ + public function calcNetworkExpectedTimePerBlock($dDifficulty, $dNetworkHashrate) { + if ($dNetworkHashrate > 0) { + return pow(2, 32) * $dDifficulty / $dNetworkHashrate; + } else { + return 0; + } + } + /** + * Calculate next expected difficulty based on current difficulty + **/ + public function calcExpectedNextDifficulty($dDifficulty, $dNetworkHashrate) { + $iExpectedTimePerBlock = $this->calcNetworkExpectedTimePerBlock($dDifficulty, $dNetworkHashrate); + if (!empty($iExpectedTimePerBlock) && $iExpectedTimePerBlock > 0) { + return round($dDifficulty * $this->config['cointarget'] / $iExpectedTimePerBlock, 8); + } else { + return 0; + } + } +} + +?> diff --git a/public/include/classes/coins/coin_scrypt.class.php b/public/include/classes/coins/coin_scrypt.class.php new file mode 100644 index 00000000..bf829ab1 --- /dev/null +++ b/public/include/classes/coins/coin_scrypt.class.php @@ -0,0 +1,13 @@ + diff --git a/public/include/classes/coins/coin_sha256d.class.php b/public/include/classes/coins/coin_sha256d.class.php new file mode 100644 index 00000000..1147770e --- /dev/null +++ b/public/include/classes/coins/coin_sha256d.class.php @@ -0,0 +1,13 @@ + diff --git a/public/include/classes/mail.class.php b/public/include/classes/mail.class.php index 329989df..3a26b089 100644 --- a/public/include/classes/mail.class.php +++ b/public/include/classes/mail.class.php @@ -34,7 +34,7 @@ class Mail extends Base { $aData['senderEmail'] = $senderEmail; $aData['senderSubject'] = $senderSubject; $aData['senderMessage'] = $senderMessage; - $aData['email'] = $this->setting->getValue('website_email'); + $aData['email'] = $this->setting->getValue('website_email', 'test@example.com'); $aData['subject'] = 'Contact Form'; if ($this->sendMail('contactform/body', $aData)) { return true; @@ -46,26 +46,64 @@ class Mail extends Base { } /** - * Send a mail with templating via Smarty + * Send a mail with templating via Smarty and Siftmailer * @param template string Template name within the mail folder, no extension * @param aData array Data array with some required fields - * SUBJECT : Mail Subject + * subject : Mail Subject * email : Destination address **/ - public function sendMail($template, $aData) { - // Make sure we don't load a cached filed + public function sendMail($template, $aData, $throttle=false) { + // Prepare SMTP transport and mailer + $transport_type = $this->config['swiftmailer']['type']; + 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']); + } + } + $mailer = Swift_Mailer::newInstance($transport); + + // 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 + )); + } + + // Prepare the smarty templates used $this->smarty->clearCache(BASEPATH . 'templates/mail/' . $template . '.tpl'); $this->smarty->clearCache(BASEPATH . 'templates/mail/subject.tpl'); $this->smarty->assign('WEBSITENAME', $this->setting->getValue('website_name')); $this->smarty->assign('SUBJECT', $aData['subject']); $this->smarty->assign('DATA', $aData); - $headers = 'From: ' . $this->setting->getValue('website_name') . '<' . $this->setting->getValue('website_email') . ">\n"; - $headers .= "MIME-Version: 1.0\n"; - $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n"; - if (strlen(@$aData['senderName']) > 0 && @strlen($aData['senderEmail']) > 0 ) - $headers .= 'Reply-To: ' . $aData['senderName'] . ' <' . $aData['senderEmail'] . ">\n"; - if (mail($aData['email'], $this->smarty->fetch(BASEPATH . 'templates/mail/subject.tpl'), $this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'), $headers)) - return true; + + // Create new message for Swiftmailer + $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')) + ->setFrom(array( $senderEmail => $senderName)) + ->setTo($aData['email']) + ->setSender($senderEmail) + ->setReturnPath($senderEmail) + ->setBody($this->smarty->fetch(BASEPATH . 'templates/mail/' . $template . '.tpl'), 'text/html'); + if (isset($aData['senderName']) && + isset($aData['senderEmail']) && + strlen($aData['senderName']) > 0 && + strlen($aData['senderEmail']) > 0 && + filter_var($aData['senderEmail'], FILTER_VALIDATE_EMAIL)) + $message->setReplyTo(array($aData['senderEmail'] => $aData['senderName'])); + + // Send message out with configured transport + try { + if ($mailer->send($message)) return true; + } catch (Exception $e) { + $this->setErrorMessage($e->getMessage()); + return false; + } $this->setErrorMessage($this->sqlError('E0031')); return false; } diff --git a/public/include/classes/monitoring.class.php b/public/include/classes/monitoring.class.php index 46324086..f6f4e14d 100644 --- a/public/include/classes/monitoring.class.php +++ b/public/include/classes/monitoring.class.php @@ -16,8 +16,8 @@ class Monitoring extends Base { $aMonitors = explode(',', $api_keys); foreach ($aMonitors as $aData) { $temp = explode('|', $aData); - $aMonitor['api_key'] = $temp[0]; - $aMonitor['monitor_id'] = $temp[1]; + $aMonitor['api_key'] = trim($temp[0]); + $aMonitor['monitor_id'] = trim($temp[1]); $target = '/getMonitors?apiKey=' . $aMonitor['api_key'] . '&monitors=' . $aMonitor['monitor_id'] . '&format=json&noJsonCallback=1&customUptimeRatio=1-7-30&logs=1'; $aMonitorStatus = $this->tools->getApi($url, $target); if (!$aMonitorStatus || @$aMonitorStatus['stat'] == 'fail') { @@ -70,9 +70,8 @@ class Monitoring extends Base { if ($query && $query->bind_param('s', $name) && $query->execute() && $result = $query->get_result()) { return $result->fetch_assoc(); } else { - $this->sqlError(); + return $this->sqlError(); } - return $value; } /** diff --git a/public/include/classes/notification.class.php b/public/include/classes/notification.class.php old mode 100755 new mode 100644 index 41aa1d92..44860281 --- a/public/include/classes/notification.class.php +++ b/public/include/classes/notification.class.php @@ -58,10 +58,10 @@ class Notification extends Mail { * @param id int Account ID * @return array Notification data **/ - public function getNotifications($account_id) { + public function getNotifications($account_id,$limit=50) { $this->debug->append("STA " . __METHOD__, 4); - $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? ORDER BY time DESC"); - if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) + $stmt = $this->mysqli->prepare("SELECT * FROM $this->table WHERE account_id = ? ORDER BY time DESC LIMIT ?"); + if ($stmt && $stmt->bind_param('ii', $account_id, $limit) && $stmt->execute() && $result = $stmt->get_result()) return $result->fetch_all(MYSQLI_ASSOC); return $this->getError(); } @@ -72,13 +72,26 @@ class Notification extends Mail { * @return array Notification settings **/ public function getNotificationSettings($account_id) { + // Some defaults, we cover them here so we can avoid adding default settings on user creation + $aDefaults = array( 'newsletter' => 1 ); $this->debug->append("STA " . __METHOD__, 4); $stmt = $this->mysqli->prepare("SELECT * FROM $this->tableSettings WHERE account_id = ?"); if ($stmt && $stmt->bind_param('i', $account_id) && $stmt->execute() && $result = $stmt->get_result()) { if ($result->num_rows > 0) { + $aFound = array(); while ($row = $result->fetch_assoc()) { + if (array_key_exists($row['type'], $aDefaults)) $aFound[] = $row['type']; $aData[$row['type']] = $row['active']; } + // Check found types against our defaults, set if required + foreach ($aDefaults as $type => $value) { + if (!in_array($type, $aFound)) { + $aData[$type] = $value; + } + } + return $aData; + } else { + foreach ($aDefaults as $type => $value) $aData[$type] = $value; return $aData; } } diff --git a/public/include/classes/roundstats.class.php b/public/include/classes/roundstats.class.php index 81c8f1d1..8c3f0315 100644 --- a/public/include/classes/roundstats.class.php +++ b/public/include/classes/roundstats.class.php @@ -78,7 +78,7 @@ class RoundStats extends Base { SELECT b.id, height, blockhash, amount, confirmations, difficulty, FROM_UNIXTIME(time) as time, shares, IF(a.is_anonymous, 'anonymous', a.username) AS finder, - ROUND((difficulty * 65535) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares, + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares, (time - (SELECT time FROM $this->tableBlocks WHERE height < ? ORDER BY height DESC LIMIT 1)) AS round_time FROM " . $this->block->getTableName() . " as b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -288,3 +288,4 @@ $roundstats->setUser($user); $roundstats->setStatistics($statistics); $roundstats->setBlock($block); $roundstats->setTransaction($transaction); +$roundstats->setCoin($coin); diff --git a/public/include/classes/setting.class.php b/public/include/classes/setting.class.php index 3da3ccb9..bf88b9a5 100644 --- a/public/include/classes/setting.class.php +++ b/public/include/classes/setting.class.php @@ -3,6 +3,30 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; class Setting extends Base { protected $table = 'settings'; + private $cache = array(); + + /** + * Fetch all values available and cache them in this class + * That way we don't fetch them from DB for each call + */ + public function createCache() { + if ($aSettings = $this->getAllAssoc()) { + foreach ($aSettings as $key => $aData) { + $this->cache[$aData['name']] = $aData['value']; + } + return true; + } + return false; + } + + /** + * Flush our local cache, may be required for upgrades + * or other places where we need live data + **/ + public function flushCache() { + $this->cache = array(); + return true; + } /** * Fetch a value from our table @@ -10,6 +34,8 @@ class Setting extends Base { * @return value string Value **/ public function getValue($name, $default="") { + // Try our class cache first + if (isset($this->cache[$name])) return $this->cache[$name]; $stmt = $this->mysqli->prepare("SELECT value FROM $this->table WHERE name = ? LIMIT 1"); if ($this->checkStmt($stmt) && $stmt->bind_param('s', $name) && $stmt->execute() && $result = $stmt->get_result()) { if ($result->num_rows > 0) { @@ -30,6 +56,8 @@ class Setting extends Base { * @return bool **/ public function setValue($name, $value) { + // Update local cache too + $this->cache[$name] = $value; $stmt = $this->mysqli->prepare(" INSERT INTO $this->table (name, value) VALUES (?, ?) @@ -44,3 +72,5 @@ $setting = new Setting($debug, $mysqli); $setting->setDebug($debug); $setting->setMysql($mysqli); $setting->setErrorCodes($aErrorCodes); +// Fill our class cache with data so we don't have to run SQL queries all the time +$setting->createCache(); diff --git a/public/include/classes/share.class.php b/public/include/classes/share.class.php index 0d11c4d5..47c67813 100644 --- a/public/include/classes/share.class.php +++ b/public/include/classes/share.class.php @@ -75,7 +75,7 @@ class Share Extends Base { **/ public function getRoundShares($previous_upstream=0, $current_upstream) { $stmt = $this->mysqli->prepare("SELECT - ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 8) AS total + IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0) AS total FROM $this->table AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON a.username = SUBSTRING_INDEX( s.username , '.', 1 ) @@ -99,8 +99,8 @@ class Share Extends Base { a.id, SUBSTRING_INDEX( s.username , '.', 1 ) as username, a.no_fees AS no_fees, - ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 8) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 8) 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 FROM $this->table AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON a.username = SUBSTRING_INDEX( s.username , '.', 1 ) @@ -112,16 +112,6 @@ class Share Extends Base { return $this->sqlError(); } - /** - * Fetch the highest available share ID - **/ - function getMaxShareId() { - $stmt = $this->mysqli->prepare("SELECT MAX(id) AS id FROM $this->table"); - if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) - return $result->fetch_object()->id; - return $this->sqlError(); - } - /** * Fetch the highest available share ID from archive **/ @@ -146,8 +136,8 @@ class Share Extends Base { a.id, SUBSTRING_INDEX( s.username , '.', 1 ) as account, a.no_fees AS no_fees, - ROUND(IFNULL(SUM(IF(our_result='Y', IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 8) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 8) 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 FROM $this->tableArchive AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON a.username = SUBSTRING_INDEX( s.username , '.', 1 ) @@ -360,8 +350,6 @@ class Share Extends Base { * Fetch the lowest needed share ID from shares **/ function getMinimumShareId($iCount, $current_upstream) { - // We don't use baseline here to be more accurate - $iCount = $iCount * pow(2, ($this->config['difficulty'] - 16)); $stmt = $this->mysqli->prepare(" SELECT MIN(b.id) AS id FROM ( @@ -381,8 +369,6 @@ class Share Extends Base { * Fetch the lowest needed share ID from archive **/ function getMinArchiveShareId($iCount) { - // We don't use baseline here to be more accurate - $iCount = $iCount * pow(2, ($this->config['difficulty'] - 16)); $stmt = $this->mysqli->prepare(" SELECT MIN(b.share_id) AS share_id FROM ( diff --git a/public/include/classes/statistics.class.php b/public/include/classes/statistics.class.php index 5b2eeacf..22f45c23 100644 --- a/public/include/classes/statistics.class.php +++ b/public/include/classes/statistics.class.php @@ -46,46 +46,48 @@ class Statistics extends Base { 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(ROUND(SUM(IF(confirmations > -1, POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS TotalEstimatedShares, 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(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 3600 SECOND), POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS 1HourEstimatedShares, 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(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 86400 SECOND), POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS 24HourEstimatedShares, 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(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 604800 SECOND), POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS 7DaysEstimatedShares, 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(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 2419200 SECOND), POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS 4WeeksEstimatedShares, 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(ROUND(SUM(IF(confirmations > -1 AND FROM_UNIXTIME(time) >= DATE_SUB(now(), INTERVAL 29030400 SECOND), POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty / POW(2, (" . $this->config['difficulty'] . " -16)), 0))), 0) AS 12MonthEstimatedShares, 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()) - return $this->memcache->setCache(__FUNCTION__, $result->fetch_assoc()); + if ($this->checkStmt($stmt) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = $result->fetch_assoc(); + $aData['TotalEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['TotalDifficulty']); + $aData['1HourEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['1HourDifficulty']); + $aData['24HourEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['24HourDifficulty']); + $aData['7DaysEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['7DaysDifficulty']); + $aData['4WeeksEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['4WeeksDifficulty']); + $aData['12MonthEstimatedShares'] = $this->coin->calcEstaimtedShares($aData['12MonthDifficulty']); + return $this->memcache->setCache(__FUNCTION__, $aData); + } return $this->sqlError(); } @@ -102,7 +104,7 @@ class Statistics extends Base { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND((difficulty * POW(2, 32 - " . $this->config['target_bits'] . ")) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -125,7 +127,7 @@ class Statistics extends Base { b.*, a.username AS finder, a.is_anonymous AS is_anonymous, - ROUND((difficulty * POW(2, 32 - " . $this->config['target_bits'] . ")) / POW(2, (" . $this->config['difficulty'] . " -16)), 0) AS estshares + ROUND(difficulty * POW(2, 32 - " . $this->coin->getTargetBits() . "), 0) AS estshares FROM " . $this->block->getTableName() . " AS b LEFT JOIN " . $this->user->getTableName() . " AS a ON b.account_id = a.id @@ -221,19 +223,22 @@ class Statistics extends Base { SELECT ( ( - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(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)) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000), 0) AS hashrate + SELECT IFNULL(ROUND(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' ) - ) AS hashrate + ) AS shares FROM DUAL"); - if ($this->checkStmt($stmt) && $stmt->bind_param('iiii', $interval, $interval, $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) return $this->memcache->setStaticCache(__FUNCTION__, $result->fetch_object()->hashrate); + if ($this->checkStmt($stmt) && $stmt->bind_param('ii', $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) { + $hashrate = $this->coin->calcHashrate($result->fetch_object()->shares, $interval); + return $this->memcache->setStaticCache(__FUNCTION__, $hashrate); + } return $this->sqlError(); } @@ -288,8 +293,8 @@ class Statistics extends Base { } $stmt = $this->mysqli->prepare(" SELECT - ROUND(IFNULL(SUM(IF(our_result='Y', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS invalid + 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 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() ) @@ -311,8 +316,8 @@ class Statistics extends Base { } $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) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS invalid, + 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, u.id AS id, u.donate_percent AS donate_percent, u.is_anonymous AS is_anonymous, @@ -339,7 +344,7 @@ class Statistics extends Base { $data['data'][$row['id']]['is_anonymous'] = $row['is_anonymous']; } } - $data['share_id'] = $this->share->getMaxShareId(); + $data['share_id'] = $this->share->getLastInsertedShareId(); return $this->memcache->setCache(STATISTICS_ALL_USER_SHARES, $data); } return $this->sqlError(); @@ -363,8 +368,8 @@ class Statistics extends Base { 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) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS valid, - ROUND(IFNULL(SUM(IF(our_result='N', IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0)), 0) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS invalid + 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 FROM " . $this->share->getTableName() . " WHERE username LIKE ? AND UNIX_TIMESTAMP(time) >IFNULL((SELECT MAX(b.time) FROM " . $this->block->getTableName() . " AS b),0)"); @@ -446,7 +451,7 @@ class Statistics extends Base { /** * Fetch all user hashrates based on shares and archived shares - * @return data integer Current Hashrate in khash/s + * @return data array Set of all user stats **/ public function getAllUserMiningStats($interval=180) { $this->debug->append("STA " . __METHOD__, 4); @@ -454,7 +459,7 @@ class Statistics extends Base { SELECT a.id AS id, a.username AS account, - IFNULL(ROUND(SUM(t1.difficulty) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000, 2), 0) AS hashrate, + IFNULL(SUM(t1.difficulty), 0) AS shares, ROUND(COUNT(t1.id) / ?, 2) AS sharerate, IFNULL(AVG(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0) AS avgsharediff FROM ( @@ -462,26 +467,27 @@ class Statistics extends Base { id, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty, username - FROM shares + FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' UNION SELECT share_id, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty, username - FROM shares_archive + FROM " . $this->share->getArchiveTableName() . " WHERE time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) AS t1 LEFT JOIN " . $this->user->getTableName() . " AS a ON SUBSTRING_INDEX( t1.username, '.', 1 ) = a.username WHERE a.id IS NOT NULL GROUP BY account - ORDER BY hashrate DESC + ORDER BY shares DESC "); - if ($this->checkStmt($stmt) && $stmt->bind_param("iiii", $interval, $interval, $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) { + if ($this->checkStmt($stmt) && $stmt->bind_param("iii", $interval, $interval, $interval) && $stmt->execute() && $result = $stmt->get_result() ) { $aData = array(); while ($row = $result->fetch_assoc()) { $aData['data'][$row['id']] = $row; + $aData['data'][$row['id']]['hashrate'] = $this->coin->calcHashrate($row['shares'], $interval); } return $this->memcache->setStaticCache(STATISTICS_ALL_USER_HASHRATES, $aData, 600); } else { @@ -494,7 +500,7 @@ class Statistics extends Base { 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) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS total + ROUND(IFNULL(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)), 0), 0) AS total FROM " . $this->share->getTableName() . " WHERE username LIKE ? AND id > ? @@ -527,13 +533,13 @@ class Statistics extends Base { $stmt = $this->mysqli->prepare(" SELECT IFNULL(COUNT(*) / ?, 0) AS sharerate, - IFNULL(ROUND(SUM(difficulty) * POW(2, " . $this->config['target_bits'] . ") / ? / 1000, 2), 0) AS hashrate, + IFNULL(SUM(difficulty), 0) AS shares, IFNULL(AVG(difficulty), 0) AS avgsharediff FROM ( SELECT id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty FROM - shares + " . $this->share->getTableName() . " WHERE username LIKE ? AND time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' @@ -541,33 +547,17 @@ class Statistics extends Base { SELECT share_id, our_result, IF(difficulty = 0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty) AS difficulty FROM - shares_archive + " . $this->share->getArchiveTableName() . " WHERE username LIKE ? AND time > DATE_SUB(now(), INTERVAL ? SECOND) AND our_result = 'Y' ) AS temp"); $username = $username . ".%"; - if ($this->checkStmt($stmt) && $stmt->bind_param("iisisi", $interval, $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() ) - return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc()); - return $this->sqlError(); - } - - /** - * Get hashrate for a specific worker - * @param username string username - * @return data int Current hashrate in khash/s - **/ - public function getWorkerHashrate($workername, $worker_id=NULL, $interval=180) { - $this->debug->append("STA " . __METHOD__, 4); - if ($data = $this->memcache->get(__FUNCTION__ . $worker_id)) return $data; - $stmt = $this->mysqli->prepare(" - SELECT IFNULL(ROUND(SUM(IF(difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 600 / 1000), 0) AS hashrate - FROM " . $this->share->getTableName() . " AS - WHERE username = '?' - AND our_result = 'Y' - AND time > DATE_SUB(now(), INTERVAL ? SECOND)"); - if ($this->checkStmt($stmt) && $stmt->bind_param("si", $workername, $interval) && $stmt->execute() && $result = $stmt->get_result()) - return $this->memcache->setCache(__FUNCTION__ . $worker_id, (float)$result->fetch_object()->hashrate); + if ($this->checkStmt($stmt) && $stmt->bind_param("isisi", $interval, $username, $interval, $username, $interval) && $stmt->execute() && $result = $stmt->get_result() ) { + $aData = $result->fetch_assoc(); + $aData['hashrate'] = $this->coin->calcHashrate($aData['shares'], $interval); + return $this->memcache->setCache(__FUNCTION__ . $account_id, $aData); + } return $this->sqlError(); } @@ -613,7 +603,7 @@ class Statistics extends Base { 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) / POW(2, (" . $this->config['difficulty'] . " - 16)), 0) AS shares + ROUND(IFNULL(SUM(IF(s.difficulty=0, POW(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)), 0), 0) AS shares FROM " . $this->share->getTableName() . " AS s LEFT JOIN " . $this->user->getTableName() . " AS a ON SUBSTRING_INDEX( s.username, '.', 1 ) = a.username @@ -633,7 +623,7 @@ class Statistics extends Base { a.username AS account, a.donate_percent AS donate_percent, a.is_anonymous AS is_anonymous, - IFNULL(ROUND(SUM(t1.difficulty) * POW(2, " . $this->config['target_bits'] . ") / 600 / 1000, 2), 0) AS hashrate + IFNULL(SUM(t1.difficulty), 0) AS shares FROM ( SELECT id, IFNULL(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty), 0) AS difficulty, username FROM " . $this->share->getTableName() . " WHERE time > DATE_SUB(now(), INTERVAL 10 MINUTE) AND our_result = 'Y' @@ -643,9 +633,17 @@ class Statistics extends Base { LEFT JOIN " . $this->user->getTableName() . " AS a ON SUBSTRING_INDEX( t1.username, '.', 1 ) = a.username GROUP BY account - ORDER BY hashrate DESC LIMIT ?"); - if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result()) - return $this->memcache->setStaticCache(__FUNCTION__ . $type . $limit, $result->fetch_all(MYSQLI_ASSOC)); + ORDER BY shares DESC LIMIT ?"); + if ($this->checkStmt($stmt) && $stmt->bind_param("i", $limit) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = array(); + $count = 0; + while ($row = $result->fetch_assoc()) { + $aData[$count] = $row; + $aData[$count]['hashrate'] = $this->coin->calcHashrate($row['shares'], 600); + $count++; + } + return $this->memcache->setStaticCache(__FUNCTION__ . $type . $limit, $aData); + } return $this->sqlError(); break; } @@ -663,7 +661,7 @@ class Statistics extends Base { $stmt = $this->mysqli->prepare(" SELECT id, - IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, + 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)) @@ -674,7 +672,7 @@ class Statistics extends Base { UNION SELECT share_id, - IFNULL(ROUND(SUM(IF(difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, + 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)) @@ -688,7 +686,7 @@ class Statistics extends Base { // Initilize array for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += $row['hashrate']; + 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(); @@ -705,7 +703,7 @@ class Statistics extends Base { $stmt = $this->mysqli->prepare(" SELECT id, - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, + 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)) @@ -715,7 +713,7 @@ class Statistics extends Base { UNION SELECT share_id, - IFNULL(ROUND(SUM(IF(s.difficulty=0, pow(2, (" . $this->config['difficulty'] . " - 16)), s.difficulty)) * POW(2, " . $this->config['target_bits'] . ") / 3600 / 1000), 0) AS hashrate, + 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)) @@ -727,7 +725,7 @@ class Statistics extends Base { // Initilize array for ($i = 0; $i < 24; $i++) $aData[($iStartHour + $i) % 24] = 0; // Fill data - while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $row['hashrate']; + while ($row = $result->fetch_assoc()) $aData[$row['hour']] += (int) $this->coin->calcHashrate($row['shares'], 3600); return $this->memcache->setCache(__FUNCTION__, $aData); } return $this->sqlError(); @@ -788,17 +786,19 @@ class Statistics extends Base { $this->debug->append("STA " . __METHOD__, 4); if ($data = $this->memcache->get(__FUNCTION__ . $hour)) return $data; $stmt = $this->mysqli->prepare(" - SELECT - IFNULL(COUNT(id), 0) as count, + SELECT + IFNULL(COUNT(id), 0) as count, IFNULL(AVG(difficulty), 0) as average, - IFNULL(ROUND(SUM((POW(2, ( 32 - " . $this->config['target_bits'] . " )) * difficulty) / POW(2, (" . $this->config['difficulty'] . " -16))), 0), 0) AS expected, IFNULL(ROUND(SUM(shares)), 0) as shares, - IFNULL(SUM(amount), 0) as rewards + IFNULL(SUM(amount), 0) as rewards FROM " . $this->block->getTableName() . " WHERE FROM_UNIXTIME(time) > DATE_SUB(now(), INTERVAL ? HOUR) AND confirmations >= 1"); - if ($this->checkStmt($stmt) && $stmt->bind_param("i", $hour) && $stmt->execute() && $result = $stmt->get_result()) - return $this->memcache->setCache(__FUNCTION__ . $hour, $result->fetch_assoc()); + if ($this->checkStmt($stmt) && $stmt->bind_param("i", $hour) && $stmt->execute() && $result = $stmt->get_result()) { + $aData = $result->fetch_assoc(); + $aData['expected'] = $this->coin->calcEstaimtedShares($aData['average']); + return $this->memcache->setCache(__FUNCTION__ . $hour, $aData); + } return $this->sqlError(); } @@ -808,7 +808,7 @@ class Statistics extends Base { * @return shares integer Share count **/ public function getEstimatedShares($dDiff) { - return round((POW(2, (32 - $this->config['target_bits'])) * $dDiff) / pow(2, ($this->config['difficulty'] - 16))); + return $this->coin->calcEstaimtedShares($dDiff); } /** @@ -829,7 +829,7 @@ class Statistics extends Base { return $this->memcache->setCache(__FUNCTION__, $this->config['cointarget']); } - return $this->memcache->setCache(__FUNCTION__, pow(2, 32) * $dDifficulty / $dNetworkHashrate); + return $this->memcache->setCache(__FUNCTION__, $this->coin->calcNetworkExpectedTimePerBlock($dDifficulty, $dNetworkHashrate)); } /** @@ -841,11 +841,13 @@ class Statistics extends Base { if ($this->bitcoin->can_connect() === true) { $dDifficulty = $this->bitcoin->getdifficulty(); + $dNetworkHashrate = $this->bitcoin->getnetworkhashps(); } else { $dDifficulty = 1; + $dNetworkHashrate = 1; } - return $this->memcache->setCache(__FUNCTION__, round($dDifficulty * $this->config['cointarget'] / $this->getNetworkExpectedTimePerBlock(), 8)); + return $this->memcache->setCache(__FUNCTION__, $this->coin->calcExpectedNextDifficulty($dDifficulty, $dNetworkHashrate)); } /** @@ -890,7 +892,7 @@ class Statistics extends Base { $pps_reward = $this->config['pps']['reward']['default']; } } - return round($pps_reward / (pow(2, $this->config['target_bits']) * $dDifficulty), 12); + return round($this->coin->calcPPSValue($pps_reward, $dDifficulty), 12); } /** @@ -922,5 +924,5 @@ $statistics->setMemcache($memcache); $statistics->setConfig($config); $statistics->setBitcoin($bitcoin); $statistics->setErrorCodes($aErrorCodes); - +$statistics->setCoin($coin); ?> diff --git a/public/include/classes/template.class.php b/public/include/classes/template.class.php index b297c528..fd0eea58 100644 --- a/public/include/classes/template.class.php +++ b/public/include/classes/template.class.php @@ -31,6 +31,23 @@ class Template extends Base { return $aThemes; } + /** + * Get all available designs + * Read css files from css/design folder + * + * @return array - list of available designs + */ + public function getDesigns() { + $this->debug->append("STA " . __METHOD__, 4); + $aTmpDesigns = glob(BASEPATH . 'site_assets/' . THEME . '/css/design/*.css'); + $aDesigns = array(); + $aDesigns['default'] = 'default'; + foreach ($aTmpDesigns as $filename) { + if (basename($filename) != '.' && basename($filename) != '..') $aDesigns[basename($filename, ".css")] = basename($filename, ".css"); + } + return $aDesigns; + } + /** * Cached getActiveTemplates method * diff --git a/public/include/classes/tools.class.php b/public/include/classes/tools.class.php index 8778a200..210e27e0 100644 --- a/public/include/classes/tools.class.php +++ b/public/include/classes/tools.class.php @@ -55,6 +55,10 @@ class Tools extends Base { return 'btce'; } else if (preg_match('/cryptsy.com/', $url)) { return 'cryptsy'; + } else if (preg_match('/cryptorush.in/', $url)) { + return 'cryptorush'; + } else if (preg_match('/mintpal.com/', $url)) { + return 'mintpal'; } $this->setErrorMessage("API URL unknown"); return false; @@ -84,6 +88,12 @@ class Tools extends Base { case 'cryptsy': return @$aData['return']['markets'][$strCurrency]['lasttradeprice']; break; + case 'cryptorush': + return @$aData["$strCurrency/" . $this->config['price']['currency']]['last_trade']; + break; + case 'mintpal': + return @$aData['0']['last_price']; + break; } } else { $this->setErrorMessage("Got an invalid response from ticker API"); diff --git a/public/include/classes/transaction.class.php b/public/include/classes/transaction.class.php index fab7cf57..1999fd4b 100644 --- a/public/include/classes/transaction.class.php +++ b/public/include/classes/transaction.class.php @@ -70,8 +70,8 @@ class Transaction extends Base { $sql = " SELECT SUM(t.amount) AS total, t.type AS type - FROM transactions AS t - LEFT OUTER JOIN blocks AS b + FROM $this->table AS t + LEFT OUTER JOIN " . $this->block->getTableName() . " AS b ON b.id = t.block_id WHERE ( b.confirmations > 0 OR b.id IS NULL )"; if (!empty($account_id)) { @@ -100,6 +100,65 @@ class Transaction extends Base { return $this->sqlError(); } + + /** + * Fetch a transaction summary by user with total amounts + * @param account_id int Account ID, NULL for all + * @return data array type and total + **/ + public function getTransactionTypebyTime($account_id=NULL) { + $this->debug->append("STA " . __METHOD__, 4); + if ($data = $this->memcache->get(__FUNCTION__)) return $data; + $stmt = $this->mysqli->prepare(" + SELECT + IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourCredit, + IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourBonus, + IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitMP, + IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDebitAP, + IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourTXFee, + IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourFee, + IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 3600 SECOND), t.amount, 0)), 0) AS 1HourDonation, + + IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourCredit, + IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourBonus, + IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitMP, + IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDebitAP, + IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourTXFee, + IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourFee, + IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 86400 SECOND), t.amount, 0)), 0) AS 24HourDonation, + + IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekCredit, + IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekBonus, + IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitMP, + IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDebitAP, + IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekTXFee, + IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekFee, + IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 604800 SECOND), t.amount, 0)), 0) AS 1WeekDonation, + + IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthCredit, + IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthBonus, + IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitMP, + IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDebitAP, + IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthTXFee, + IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthFee, + IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 2419200 SECOND), t.amount, 0)), 0) AS 1MonthDonation, + + IFNULL(SUM(IF(t.type = 'Credit' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearCredit, + IFNULL(SUM(IF(t.type = 'Bonus' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearBonus, + IFNULL(SUM(IF(t.type = 'Debit_MP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitMP, + IFNULL(SUM(IF(t.type = 'Debit_AP' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDebitAP, + IFNULL(SUM(IF(t.type = 'TXFee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearTXFee, + IFNULL(SUM(IF(t.type = 'Fee' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearFee, + IFNULL(SUM(IF(t.type = 'Donation' AND timestamp >= DATE_SUB(now(), INTERVAL 31536000 SECOND), t.amount, 0)), 0) AS 1YearDonation + FROM $this->table AS t + LEFT OUTER JOIN " . $this->block->getTableName() . " AS b ON b.id = t.block_id + WHERE + t.account_id = ? AND (b.confirmations > 0 OR b.id IS NULL)"); + if ($this->checkStmt($stmt) && $stmt->bind_param("i", $account_id) && $stmt->execute() && $result = $stmt->get_result()) + return $this->memcache->setCache(__FUNCTION__ . $account_id, $result->fetch_assoc(), 60); + return $this->sqlError(); + } + /** * Get all transactions from start for account_id * @param start int Starting point, id of transaction @@ -211,7 +270,7 @@ class Transaction extends Base { FROM $this->table AS t LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id - LEFT JOIN blocks AS b + LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id WHERE ( @@ -306,9 +365,9 @@ class Transaction extends Base { ), 0 ) AS confirmed FROM $this->table AS t - LEFT JOIN blocks AS b + LEFT JOIN " . $this->block->getTableName() . " AS b ON t.block_id = b.id - LEFT JOIN accounts AS a + LEFT JOIN " . $this->user->getTableName() . " AS a ON t.account_id = a.id WHERE t.archived = 0 AND a.ap_threshold > 0 AND a.coin_address IS NOT NULL AND a.coin_address != '' GROUP BY t.account_id diff --git a/public/include/classes/user.class.php b/public/include/classes/user.class.php index 978d530d..68e77d3a 100644 --- a/public/include/classes/user.class.php +++ b/public/include/classes/user.class.php @@ -192,6 +192,11 @@ class User extends Base { return false; } if ($this->checkUserPassword($username, $password)) { + // delete notification cookies + setcookie("motd-box", "", time()-3600); + setcookie("lastlogin-box", "", time()-3600); + setcookie("backend-box", "", time()-3600); + // rest of login process $uid = $this->getUserId($username); $lastLoginTime = $this->getLastLogin($uid); $this->updateLoginTimestamp($uid); @@ -347,7 +352,7 @@ class User extends Base { **/ public function existsCoinAddress($address) { $this->debug->append("STA " . __METHOD__, 4); - return $this->getSingle($address, 'coin_address', 'coin_address') === $address; + return $this->getSingle($address, 'coin_address', 'coin_address', 's') === $address; } /** @@ -624,15 +629,12 @@ class User extends Base { // Unset all of the session variables $_SESSION = array(); // As we're killing the sesison, also kill the cookie! - if (ini_get("session.use_cookies")) { - $params = session_get_cookie_params(); - setcookie(session_name(), '', time() - 42000, $params["path"], $params["domain"], $params["secure"], $params["httponly"]); - } + setcookie(session_name(), '', time() - 42000); // Destroy the session. session_destroy(); // Enforce generation of a new Session ID and delete the old session_regenerate_id(true); - + // Enforce a page reload and point towards login with referrer included, if supplied $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]); $pushto = $_SERVER['SCRIPT_NAME'].'?page=login'; @@ -866,7 +868,7 @@ class User extends Base { $this->debug->append("STA " . __METHOD__, 4); // Fetch the users mail address if (empty($username)) { - $this->serErrorMessage("Username must not be empty"); + $this->setErrorMessage("Username must not be empty"); return false; } if (filter_var($username, FILTER_VALIDATE_EMAIL)) { @@ -926,23 +928,28 @@ public function isAuthenticated($logout=true) { /** * Convenience function to get IP address, no params is the same as REMOTE_ADDR - * @param trustremote bool must be FALSE to checkclient or checkforwarded + * @param trustremote bool must be FALSE to checkcloudflare, checkclient or checkforwarded + * @param checkcloudflare bool check HTTP_CF_CONNECTING_IP for a valid ip first * @param checkclient bool check HTTP_CLIENT_IP for a valid ip first * @param checkforwarded bool check HTTP_X_FORWARDED_FOR for a valid ip first * @return string IP address */ - public function getCurrentIP($trustremote=false, $checkclient=false, $checkforwarded=true) { + public function getCurrentIP($trustremote=false, $checkcloudflare=true, $checkclient=false, $checkforwarded=true) { + $cf = (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : false; $client = (isset($_SERVER['HTTP_CLIENT_IP'])) ? $_SERVER['HTTP_CLIENT_IP'] : false; $fwd = (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : false; $remote = (isset($_SERVER['REMOTE_ADDR'])) ? $_SERVER['REMOTE_ADDR'] : @$_SERVER['REMOTE_ADDR']; // shared internet - if (filter_var($client, FILTER_VALIDATE_IP) && !$trustremote && $checkclient) { + if (!$trustremote && $checkcloudflare && filter_var($cf, FILTER_VALIDATE_IP)) { + // cloudflare + return $cf; + } else if (!$trustremote && $checkclient && filter_var($client, FILTER_VALIDATE_IP)) { return $client; - } else if (strpos($fwd, ',') !== false && !$trustremote && $checkforwarded) { + } else if (!$trustremote && $checkforwarded && strpos($fwd, ',') !== false) { // multiple proxies $ips = explode(',', $fwd); return $ips[0]; - } else if (filter_var($fwd, FILTER_VALIDATE_IP) && !$trustremote && $checkforwarded) { + } else if (!$trustremote && $checkforwarded && filter_var($fwd, FILTER_VALIDATE_IP)) { // single return $fwd; } else { diff --git a/public/include/classes/worker.class.php b/public/include/classes/worker.class.php index b661bd22..9b7344ac 100644 --- a/public/include/classes/worker.class.php +++ b/public/include/classes/worker.class.php @@ -74,14 +74,14 @@ class Worker extends Base { ( 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username @@ -117,14 +117,14 @@ class Worker extends Base { ( 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username @@ -158,14 +158,14 @@ class Worker extends Base { 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 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->config['target_bits'] . ") / ? / 1000), 0), 0) AS hashrate + 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 FROM " . $this->share->getArchiveTableName() . " WHERE username = w.username @@ -272,5 +272,5 @@ $worker->setShare($share); $worker->setConfig($config); $worker->setUser($user); $worker->setErrorCodes($aErrorCodes); - +$worker->setCoin($coin); ?> diff --git a/public/include/config/admin_settings.inc.php b/public/include/config/admin_settings.inc.php index 593d03b8..e0adf7cb 100644 --- a/public/include/config/admin_settings.inc.php +++ b/public/include/config/admin_settings.inc.php @@ -2,6 +2,7 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; $aThemes = $template->getThemes(); +$aDesigns = $template->getDesigns(); // Load the settings available in this system $aSettings['website'][] = array( @@ -49,16 +50,30 @@ $aSettings['website'][] = array( $aSettings['website'][] = array( 'display' => 'Website theme', 'type' => 'select', 'options' => $aThemes, - 'default' => 'mpos', + 'default' => 'bootstrap', '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' => 'mobile', - 'name' => 'website_mobile_theme', 'value' => $setting->getValue('website_mobile_theme'), - 'tooltip' => 'The mobile theme used for your pool.' + 'display' => 'Website Design', 'type' => 'select', + 'options' => $aDesigns, + 'default' => 'default', + 'name' => 'website_design', 'value' => $setting->getValue('website_design'), + 'tooltip' => 'The default design used on your pool.' +); +$aSettings['website'][] = array( + 'display' => 'Website News Style', 'type' => 'select', + 'options' => array( 0 => 'Show all news in one Page', 1 => 'Show Responsive News Table' ), + 'default' => 0, + 'name' => 'website_news_style', 'value' => $setting->getValue('website_news_style'), + 'tooltip' => 'How News are displayed on Main Page.' +); +$aSettings['website'][] = array( + 'display' => 'Auto Hide Notifications', 'type' => 'select', + 'options' => array( 0 => 'Notifications always visible', 1 => 'Hide Notifications automatically' ), + 'default' => 0, + 'name' => 'website_notification_autohide', 'value' => $setting->getValue('website_notification_autohide'), + 'tooltip' => 'Hides Notifications after 5 seconds.' ); $aSettings['blockchain'][] = array( 'display' => 'Disable Blockexplorer', 'type' => 'select', @@ -257,6 +272,20 @@ $aSettings['acl'][] = array( 'name' => 'acl_chat_page', 'value' => $setting->getValue('acl_chat_page'), 'tooltip' => 'Make the chat page private (users only) or public.' ); +$aSettings['acl'][] = array( + 'display' => 'MOOT Forum Page', 'type' => 'select', + 'options' => array( 0 => 'Private', 1 => 'Public', 2 => 'Disabled' ), + 'default' => 2, + 'name' => 'acl_moot_forum', 'value' => $setting->getValue('acl_moot_forum'), + 'tooltip' => 'Make the forum page private (users only) or public.' +); +$aSettings['acl'][] = array( + 'display' => 'QRCode', 'type' => 'select', + 'options' => array( 0 => 'Enabled', 1 => 'Disabled' ), + 'default' => 0, + 'name' => 'acl_qrcode', 'value' => $setting->getValue('acl_qrcode'), + 'tooltip' => 'Hide or Show the QRCode Page.' +); $aSettings['system'][] = array( 'display' => 'E-mail address for system error notifications', 'type' => 'text', 'size' => 25, @@ -355,6 +384,13 @@ $aSettings['system'][] = array( 'name' => 'system_irc_chat', 'value' => $setting->getValue('system_irc_chat'), 'tooltip' => 'Your IRC support channel name.' ); +$aSettings['system'][] = array( + 'display' => 'Moot Forum Channel', 'type' => 'text', + 'size' => 25, + 'default' => 'lazypoolop', + 'name' => 'system_moot_forum', 'value' => $setting->getValue('system_moot_forum'), + 'tooltip' => 'Your MOOT support forum name.' +); $aSettings['recaptcha'][] = array( 'display' => 'Enable re-Captcha', 'type' => 'select', 'options' => array( 0 => 'No', 1 => 'Yes' ), @@ -425,3 +461,32 @@ $aSettings['notifications'][] = array( 'name' => 'notifications_disable_block', 'value' => $setting->getValue('notifications_disable_block'), 'tooltip' => 'Enable/Disable block notifications globally. Will remove the user option too.' ); +$aSettings['notifications'][] = array( + 'display' => 'Disable IDLE Worker Notifications', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes'), + 'default' => 0, + 'name' => 'notifications_disable_idle_worker', 'value' => $setting->getValue('notifications_disable_idle_worker'), + 'tooltip' => 'Enable/Disable IDLE worker notifications globally. Will remove the user option too.' +); +$aSettings['notifications'][] = array( + 'display' => 'Disable Pool Newsletter', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes'), + 'default' => 0, + 'name' => 'notifications_disable_pool_newsletter', 'value' => $setting->getValue('notifications_disable_pool_newsletter'), + 'tooltip' => 'Enable/Disable pool newsletter globally. Will remove the user option too.' +); +$aSettings['pools'][] = array( + 'display' => 'Enable Pool Navigation', 'type' => 'select', + 'options' => array( 0 => 'No', 1 => 'Yes' ), + 'default' => 0, + 'name' => 'poolnav_enabled', 'value' => $setting->getValue('poolnav_enabled'), + 'tooltip' => 'Enable or Disable Pool Navigation for multiple Pools in Header.' +); +$aSettings['pools'][] = array( + 'display' => 'Pools for Pool Navigation', 'type' => 'textarea', + 'size' => 20, + 'height' => 12, + 'default' => 'Pool Name|Pool URL', + 'name' => 'poolnav_pools', 'value' => $setting->getValue('poolnav_pools'), + 'tooltip' => '.' +); diff --git a/public/include/config/error_codes.inc.php b/public/include/config/error_codes.inc.php index b6e720ee..36a40b0f 100644 --- a/public/include/config/error_codes.inc.php +++ b/public/include/config/error_codes.inc.php @@ -35,7 +35,7 @@ $aErrorCodes['E0030'] = 'Unable to fetch a valid token for this invitation'; $aErrorCodes['E0031'] = 'Failed to send e-mail via mail() function'; $aErrorCodes['E0032'] = 'Failed to run API call: %s'; $aErrorCodes['E0033'] = 'Failed to store uptime status: %s'; -$aErrorCodes['E0034'] = 'Subjcet may only contain alphanumeric characters'; +$aErrorCodes['E0034'] = 'Subject may only contain alphanumeric characters'; $aErrorCodes['E0035'] = 'Failed to add news record'; $aErrorCodes['E0036'] = 'Failed to delete news record'; $aErrorCodes['E0037'] = 'Failed to update news record'; @@ -77,4 +77,5 @@ $aErrorCodes['E0078'] = 'RPC method did not return 200 OK'; $aErrorCodes['E0079'] = 'Wallet does not cover payouts total amount'; $aErrorCodes['E0080'] = 'No new unaccounted shares since last run'; $aErrorCodes['E0081'] = 'Failed to insert new block into database'; +$aErrorCodes['E0082'] = 'Block does not supply any usable confirmation information'; ?> diff --git a/public/include/config/global.inc.dist.php b/public/include/config/global.inc.dist.php index 06e67c82..c5fd9d74 100644 --- a/public/include/config/global.inc.dist.php +++ b/public/include/config/global.inc.dist.php @@ -29,6 +29,13 @@ $config['SALTY'] = 'THISSHOULDALSOBERRAANNDDOOM'; **/ $config['algorithm'] = 'scrypt'; +/** + * Getbalance API Calls + * System used for getting actual Balance from Wallet + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#getbalance-api-calls + **/ +$config['getbalancewithunconfirmed'] = true; + /** * Database configuration * MySQL database configuration @@ -50,6 +57,21 @@ $config['wallet']['host'] = 'localhost:19334'; $config['wallet']['username'] = 'testnet'; $config['wallet']['password'] = 'testnet'; +/** + * Swiftmailer configuration + * Configure your way to send mails + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-swiftmailer + **/ +$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; + /** * Getting Started Config * Shown to users in the 'Getting Started' section @@ -65,6 +87,7 @@ $config['gettingstarted']['stratumport'] = '3333'; * Fetch exchange rates via an API * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-ticker-api **/ +$config['price']['enabled'] = false; $config['price']['url'] = 'https://btc-e.com'; $config['price']['target'] = '/api/2/ltc_usd/ticker'; $config['price']['currency'] = 'USD'; @@ -77,6 +100,13 @@ $config['price']['currency'] = 'USD'; $config['ap_threshold']['min'] = 1; $config['ap_threshold']['max'] = 250; +/** + * Minimum manual Payout Threshold + * Minimum manual payout amount + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-manual-payout-threshold + **/ +$config['mp_threshold'] = 1; + /** * Donation thresholds * Minimum donation amount in percent @@ -121,12 +151,14 @@ $config['txfee_auto'] = 0.1; $config['txfee_manual'] = 0.1; /** - * Block Bonus - * Bonus in coins of block bonus + * Block & Pool Bonus + * Bonus coins for blockfinder or a pool bonus for everyone * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-block-bonus + * https://github.com/MPOS/php-mpos/wiki/Config-Setup#wiki-pool-bonus */ $config['block_bonus'] = 0; - +$config['pool_bonus'] = 0; +$config['pool_bonus_type'] = 'payout'; /** * Payout System diff --git a/public/include/config/monitor_crons.inc.php b/public/include/config/monitor_crons.inc.php index 98b8eb0f..732c1bdc 100644 --- a/public/include/config/monitor_crons.inc.php +++ b/public/include/config/monitor_crons.inc.php @@ -2,16 +2,16 @@ // Small helper array that may be used on some page controllers to // fetch the crons we wish to monitor -$aMonitorCrons = array('statistics','payouts','tables_cleanup','blockupdate','findblock','notifications','tickerupdate'); - switch ($config['payout_system']) { -case 'pplns': - $aMonitorCrons[] = $config['payout_system'] . '_payout'; - break; -case 'pps': - $aMonitorCrons[] = $config['payout_system'] . '_payout'; - break; -case 'prop': - $aMonitorCrons[] = 'proportional_payout'; - break; + case 'pplns': + $sPayoutSystem = $config['payout_system'] . '_payout'; + break; + case 'pps': + $sPayoutSystem = $config['payout_system'] . '_payout'; + break; + case 'prop': + $sPayoutSystem = 'proportional_payout'; + break; } + +$aMonitorCrons = array('statistics','tickerupdate','notifications','tables_cleanup','findblock',$sPayoutSystem,'blockupdate','payouts'); diff --git a/public/include/lib/Mobile_Detect.php b/public/include/lib/Mobile_Detect.php deleted file mode 100644 index 0d739d8b..00000000 --- a/public/include/lib/Mobile_Detect.php +++ /dev/null @@ -1,814 +0,0 @@ - - * Victor Stanciu (until v. 1.0) - * @license MIT License https://github.com/serbanghita/Mobile-Detect/blob/master/LICENSE.txt - * @link Official page: http://mobiledetect.net - * GitHub Repository: https://github.com/serbanghita/Mobile-Detect - * Google Code Old Page: http://code.google.com/p/php-mobile-detect/ - * @version 2.6.2 - */ - -class Mobile_Detect { - - protected $scriptVersion = '2.6.2'; - - // External info. - protected $userAgent = null; - protected $httpHeaders; - - // Arrays holding all detection rules. - protected $mobileDetectionRules = null; - protected $mobileDetectionRulesExtended = null; - // Type of detection to use. - protected $detectionType = 'mobile'; // mobile, extended @todo: refactor this. - - // List of mobile devices (phones) - protected $phoneDevices = array( - 'iPhone' => '\biPhone.*Mobile|\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|ADR6425|001HT|Inspire 4G|Android.*\bEVO\b', - '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|\bDroid\b.*Build|DROIDX|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|XT909|XT910|XT912|XT928', - '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-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-I9100|GT-I9103|GT-I9220|GT-I9250|GT-I9300|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-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-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|SCH-I535', - 'LG' => '\bLG\b;|(LG|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|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)', - 'Sony' => 'sony|SonyEricsson|SonyEricssonLT15iv|LT18i|E10i', - 'Asus' => 'Asus.*Galaxy', - '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', - // 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;|PPC;|SAGEM|mmp|pocket|psp|symbian|Smartphone|smartfon|treo|up.browser|up.link|vodafone|wap|nokia|Series40|Series60|S60|SonyEricsson|N900|MAUI.*WAP.*Browser|LG-P500' - ); - // List of tablet devices. - protected $tabletDevices = array( - 'iPad' => 'iPad|iPad.*Mobile', // @todo: check for mobile friendly emails topic. - 'NexusTablet' => '^.*Android.*Nexus(((?:(?!Mobile))|(?:(\s(7|10).+))).)*$', - '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-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', - // @reference: http://www.labnol.org/software/kindle-user-agent-string/20378/ - 'Kindle' => 'Kindle|Silk.*Accelerated', - // 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;', - 'AsusTablet' => 'Transformer|TF101', - '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|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) - '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)\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 - 'LGTablet' => '\bL-06C|LG-V900|LG-V909\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|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474', - 'YarvikTablet' => 'Android.*(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468)', - 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB', - 'ArnovaTablet' => 'AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT', - // @reference: http://wiki.archosfans.com/index.php?title=Main_Page - 'ArchosTablet' => 'Android.*ARCHOS|\b101G9\b|\b80G9\b', - // @reference: http://en.wikipedia.org/wiki/NOVO7 - 'AinolTablet' => 'NOVO7|Novo7Aurora|Novo7Basic|NOVO7PALADIN', - // @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|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT211|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201', - // @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|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010', - // @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.telstra.com.au/home-phone/thub-2/ - 'TelstraTablet' => 'T-Hub2', - // @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)', - // @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|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]', - // @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.galapad.net/product.html - 'GalapadTablet' => 'Android.*\bG1\b', - 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|ViewPad7|MID7015|BNTV250A|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|hp-tablet|rk30sdk', - ); - // List of mobile Operating Systems. - protected $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 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/|Java/|\bMIDP\b|\bCLDC\b', - 'webOS' => 'webOS|hpwOS', - 'badaOS' => '\bBada\b', - 'BREWOS' => 'BREW', - ); - // List of mobile User Agents. - protected $userAgents = 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.]+', - 'Skyfire' => 'Skyfire', - 'IE' => 'IEMobile|MSIEMobile', - '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' - ); - // Utilities. - protected $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' => 'SonyDTV115', // 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', - ); - // Properties list. - // @reference: http://user-agent-string.info/list-of-ua#Mobile Browser - const VER = '([\w._\+]+)'; - protected $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]'), - '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]' ), - 'UC Browser' => 'UC Browser[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];'), - - - ); - - function __construct(){ - - $this->setHttpHeaders(); - $this->setUserAgent(); - - $this->setMobileDetectionRules(); - $this->setMobileDetectionRulesExtended(); - - } - - - /** - * 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. - */ - public function getScriptVersion(){ - - return $this->scriptVersion; - - } - - public function setHttpHeaders($httpHeaders = null){ - - if(!empty($httpHeaders)){ - $this->httpHeaders = $httpHeaders; - } else { - foreach($_SERVER as $key => $value){ - if(substr($key,0,5)=='HTTP_'){ - $this->httpHeaders[$key] = $value; - } - } - } - - } - - public function getHttpHeaders(){ - - return $this->httpHeaders; - - } - - public function setUserAgent($userAgent = null){ - - if(!empty($userAgent)){ - $this->userAgent = $userAgent; - } else { - $this->userAgent = isset($this->httpHeaders['HTTP_USER_AGENT']) ? $this->httpHeaders['HTTP_USER_AGENT'] : null; - - if(empty($this->userAgent)){ - $this->userAgent = isset($this->httpHeaders['HTTP_X_DEVICE_USER_AGENT']) ? $this->httpHeaders['HTTP_X_DEVICE_USER_AGENT'] : null; - } - // Header can occur on devices using Opera Mini (can expose the real device type). Let's concatenate it (we need this extra info in the regexes). - if(!empty($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA'])){ - $this->userAgent .= ' '.$this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA']; - } - } - - } - - public function getUserAgent(){ - - return $this->userAgent; - - } - - function setDetectionType($type = null){ - - $this->detectionType = (!empty($type) ? $type : 'mobile'); - - } - - public function getPhoneDevices(){ - - return $this->phoneDevices; - - } - - public function getTabletDevices(){ - - return $this->tabletDevices; - - } - - /** - * Method sets the mobile detection rules. - * - * This method is used for the magic methods $detect->is*() - */ - public function setMobileDetectionRules(){ - // Merge all rules together. - $this->mobileDetectionRules = array_merge( - $this->phoneDevices, - $this->tabletDevices, - $this->operatingSystems, - $this->userAgents - ); - - } - - /** - * Method sets 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. - * - * @return bool - */ - public function setMobileDetectionRulesExtended(){ - - // Merge all rules together. - $this->mobileDetectionRulesExtended = array_merge( - $this->phoneDevices, - $this->tabletDevices, - $this->operatingSystems, - $this->userAgents, - $this->utilities - ); - - } - - /** - * @return array - */ - public function getRules() - { - - if($this->detectionType=='extended'){ - return $this->mobileDetectionRulesExtended; - } else { - return $this->mobileDetectionRules; - } - - } - -/** -* Check the HTTP headers for signs of mobile. -* This is the fastest mobile check possible; it's used -* inside isMobile() method. -* @return boolean -*/ - public function checkHttpHeadersForMobile(){ - - if( - isset($this->httpHeaders['HTTP_ACCEPT']) && - (strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/x-obml2d') !== false || // Opera Mini; @reference: http://dev.opera.com/articles/view/opera-binary-markup-language/ - strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.rim.html') !== false || // BlackBerry devices. - strpos($this->httpHeaders['HTTP_ACCEPT'], 'text/vnd.wap.wml') !== false || - strpos($this->httpHeaders['HTTP_ACCEPT'], 'application/vnd.wap.xhtml+xml') !== false) || - isset($this->httpHeaders['HTTP_X_WAP_PROFILE']) || // @todo: validate - isset($this->httpHeaders['HTTP_X_WAP_CLIENTID']) || - isset($this->httpHeaders['HTTP_WAP_CONNECTION']) || - isset($this->httpHeaders['HTTP_PROFILE']) || - isset($this->httpHeaders['HTTP_X_OPERAMINI_PHONE_UA']) || // Reported by Nokia devices (eg. C3) - isset($this->httpHeaders['HTTP_X_NOKIA_IPADDRESS']) || - isset($this->httpHeaders['HTTP_X_NOKIA_GATEWAY_ID']) || - isset($this->httpHeaders['HTTP_X_ORANGE_ID']) || - isset($this->httpHeaders['HTTP_X_VODAFONE_3GPDPCONTEXT']) || - isset($this->httpHeaders['HTTP_X_HUAWEI_USERID']) || - isset($this->httpHeaders['HTTP_UA_OS']) || // Reported by Windows Smartphones. - isset($this->httpHeaders['HTTP_X_MOBILE_GATEWAY']) || // Reported by Verizon, Vodafone proxy system. - isset($this->httpHeaders['HTTP_X_ATT_DEVICEID']) || // Seend this on HTC Sensation. @ref: SensationXE_Beats_Z715e - //HTTP_X_NETWORK_TYPE = WIFI - ( isset($this->httpHeaders['HTTP_UA_CPU']) && - $this->httpHeaders['HTTP_UA_CPU'] == 'ARM' // Seen this on a HTC. - ) - ){ - - return true; - - } - - return false; - - } - - /** - * Magic overloading method. - * - * @method boolean is[...]() - * @param string $name - * @param array $arguments - * @return mixed - */ - public function __call($name, $arguments) - { - - $this->setDetectionType('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 - */ - private function matchDetectionRulesAgainstUA($userAgent = null){ - - // Begin general search. - foreach($this->getRules() as $_regex){ - if(empty($_regex)){ continue; } - if( $this->match($_regex, $userAgent) ){ - //var_dump( $_regex ); - 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 - */ - private function matchUAAgainstKey($key, $userAgent = null){ - - // Make the keys lowercase so we can match: isIphone(), isiPhone(), isiphone(), etc. - $key = strtolower($key); - $_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('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 null $userAgent deprecated - * @param null $httpHeaders deprecated - * @return bool - */ - public function isTablet($userAgent = null, $httpHeaders = null) { - - $this->setDetectionType('mobile'); - - foreach($this->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 $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('extended'); - - return $this->matchUAAgainstKey($key); - - } - - public function getOperatingSystems(){ - - return $this->operatingSystems; - - } - - /** - * 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. - */ - 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 - */ - function getProperties(){ - - return $this->properties; - - } - - /** - * Prepare the version number. - * - * @param $ver - * @return int - */ - function prepareVersionNo($ver){ - - $ver = str_replace(array('_', ' ', '/'), array('.', '.', '.'), $ver); - $arrVer = explode('.', $ver, 2); - if(isset($arrVer[1])){ - $arrVer[1] = @str_replace('.', '', $arrVer[1]); // @todo: treat strings versions. - } - $ver = (float)implode('.', $arrVer); - - return $ver; - - } - - /** - * 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 - * @return mixed $version - */ - function version($propertyName, $type = 'text'){ - - if(empty($propertyName)){ return false; } - if( !in_array($type, array('text', 'float')) ){ $type = 'text'; } - - $properties = $this->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 == 'float' ? $this->prepareVersionNo($match[1]) : $match[1] ); - return $version; - } - - } - - } - - return false; - - } - - 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->version('iPad')>=4.3 || - $this->version('iPhone')>=3.1 || - $this->version('iPod')>=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')>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')>=7.0 || - - // Blackberry 7 - Tested on BlackBerry® Torch 9810 - // Blackberry 6.0 - Tested on the Torch 9800 and Style 9670 - $this->version('BlackBerry')>=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')>=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')>=12 ) || - - // Chrome for Android - Tested on Android 4.0, 4.1 device - ( $this->is('Chrome') && $this->is('AndroidOS') && $this->version('Android')>=4.0 ) || - - // Skyfire 4.1 - Tested on Android 2.3 device - ( $this->is('Skyfire') && $this->version('Skyfire')>=4.1 && $this->is('AndroidOS') && $this->version('Android')>=2.3 ) || - - // Opera Mobile 11.5-12: Tested on Android 2.3 - ( $this->is('Opera') && $this->version('Opera Mobi')>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')>=2.0 || - - // UC Browser - Tested on Android 2.3 device - ( ($this->is('UC Browser') || $this->is('Dolfin')) && $this->version('Android')>=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')>=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')>=11 && !$isMobile || - - // Safari Desktop 4-5 - Tested on OS X 10.7 and Windows 7 - $this->version('Safari')>=5.0 && !$isMobile || - - // Firefox Desktop 4-13 - Tested on OS X 10.7 and Windows 7 - $this->version('Firefox')>=4.0 && !$isMobile || - - // Internet Explorer 7-9 - Tested on Windows XP, Vista and 7 - $this->version('MSIE')>=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')>=10 && !$isMobile - - - ){ - return 'A'; - } - - if( - // Blackberry 5.0: Tested on the Storm 2 9550, Bold 9770 - $this->version('BlackBerry')>=5 && $this->version('BlackBerry')<6 || - - //Opera Mini (5.0-6.5) - Tested on iOS 3.2/4.3 and Android 2.3 - ( $this->version('Opera Mini')>=5.0 && $this->version('Opera Mini')<=6.5 && - ($this->version('Android')>=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')>=11 && $this->is('SymbianOS') - - ){ - return 'B'; - } - - if( - // Blackberry 4.x - Tested on the Curve 8330 - $this->version('BlackBerry')<5.0 || - // Windows Mobile - Tested on the HTC Leo (WinMo 5.2) - $this->match('MSIEMobile|Windows CE.*Mobile') || $this->version('Windows Mobile')<=5.2 - - - ){ - - return 'C'; - - } - - // All older smartphone platforms and featurephones - Any device that doesn't support media queries will receive the basic, C grade experience - return 'C'; - - - } - - -} - -$detect = new Mobile_Detect; diff --git a/public/include/lib/smarty_plugins/function.acl.php b/public/include/lib/smarty_plugins/function.acl.php index 78753375..6a358f15 100644 --- a/public/include/lib/smarty_plugins/function.acl.php +++ b/public/include/lib/smarty_plugins/function.acl.php @@ -5,9 +5,14 @@ function check_acl_access($params, $smarty) { $isAuthenticated = isset($_SESSION['AUTHENTICATED']) ? true : false; $iAclSetting = $params['acl']; - $sUrl = '
  • '.$params['name'].'
  • '; + // $params['icon'] is deprecated, only needed for mpos compatibility + if (isset($params['icon'])) { + $sUrl = '
  • '.$params['name'].'
  • '; + } else { + $sUrl = '
  • '.$params['name'].'
  • '; + } if (isset($params['fallback'])) - $sFallbackUrl = '
  • '.$params['name'].'
  • '; + $sFallbackUrl = '
  • '.$params['name'].'
  • '; switch($iAclSetting) { case '0': if ($isAuthenticated) { diff --git a/public/include/lib/swiftmailer/classes/Swift.php b/public/include/lib/swiftmailer/classes/Swift.php new file mode 100644 index 00000000..2e9af1ad --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift.php @@ -0,0 +1,81 @@ +createDependenciesFor('mime.attachment') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Attachment. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_Attachment + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new Attachment from a filesystem path. + * + * @param string $path + * @param string $contentType optional + * + * @return Swift_Mime_Attachment + */ + public static function fromPath($path, $contentType = null) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path), + $contentType + ); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/public/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php new file mode 100644 index 00000000..821fab8e --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ByteStream/AbstractFilterableInputStream.php @@ -0,0 +1,183 @@ +_filters[$key] = $filter; + } + + /** + * Remove an already present StreamFilter based on its $key. + * + * @param string $key + */ + public function removeFilter($key) + { + unset($this->_filters[$key]); + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * + * @return integer + * + * @throws Swift_IoException + */ + public function write($bytes) + { + $this->_writeBuffer .= $bytes; + foreach ($this->_filters as $filter) { + if ($filter->shouldBuffer($this->_writeBuffer)) { + return; + } + } + $this->_doWrite($this->_writeBuffer); + + return ++$this->_sequence; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + */ + public function commit() + { + $this->_doWrite($this->_writeBuffer); + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + if ($this->_writeBuffer !== '') { + $stream->write($this->_writeBuffer); + } + unset($this->_mirrors[$k]); + } + } + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + if ($this->_writeBuffer !== '') { + $this->_doWrite($this->_writeBuffer); + } + $this->_flush(); + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + // -- Private methods + + /** Run $bytes through all filters */ + private function _filter($bytes) + { + foreach ($this->_filters as $filter) { + $bytes = $filter->filter($bytes); + } + + return $bytes; + } + + /** Just write the bytes to the stream */ + private function _doWrite($bytes) + { + $this->_commit($this->_filter($bytes)); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + + $this->_writeBuffer = ''; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php b/public/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php new file mode 100644 index 00000000..5c162483 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ByteStream/ArrayByteStream.php @@ -0,0 +1,186 @@ +_array = $stack; + $this->_arraySize = count($stack); + } elseif (is_string($stack)) { + $this->write($stack); + } else { + $this->_array = array(); + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param integer $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_arraySize) { + return false; + } + + // Don't use array slice + $end = $length + $this->_offset; + $end = $this->_arraySize<$end + ?$this->_arraySize + :$end; + $ret = ''; + for (; $this->_offset < $end; ++$this->_offset) { + $ret .= $this->_array[$this->_offset]; + } + + return $ret; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + */ + public function write($bytes) + { + $to_add = str_split($bytes); + foreach ($to_add as $value) { + $this->_array[] = $value; + } + $this->_arraySize = count($this->_array); + + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param integer $byteOffset + * + * @return boolean + */ + public function setReadPointer($byteOffset) + { + if ($byteOffset > $this->_arraySize) { + $byteOffset = $this->_arraySize; + } elseif ($byteOffset < 0) { + $byteOffset = 0; + } + + $this->_offset = $byteOffset; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_offset = 0; + $this->_array = array(); + $this->_arraySize = 0; + + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php b/public/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php new file mode 100644 index 00000000..405f8b05 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ByteStream/FileByteStream.php @@ -0,0 +1,225 @@ +_path = $path; + $this->_mode = $writable ? 'w+b' : 'rb'; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Get the complete path to the file. + * + * @return string + */ + public function getPath() + { + return $this->_path; + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the + * remaining bytes are given instead. If no bytes are remaining at all, boolean + * false is returned. + * + * @param integer $length + * + * @return string + * + * @throws Swift_IoException + */ + public function read($length) + { + $fp = $this->_getReadHandle(); + if (!feof($fp)) { + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $bytes = fread($fp, $length); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_offset = ftell($fp); + + return $bytes; + } else { + $this->_resetReadHandle(); + + return false; + } + } + + /** + * Move the internal read pointer to $byteOffset in the stream. + * + * @param integer $byteOffset + * + * @return boolean + */ + public function setReadPointer($byteOffset) + { + if (isset($this->_reader)) { + $this->_seekReadStreamToPosition($byteOffset); + } + $this->_offset = $byteOffset; + } + + // -- Private methods + + /** Just write the bytes to the file */ + protected function _commit($bytes) + { + fwrite($this->_getWriteHandle(), $bytes); + $this->_resetReadHandle(); + } + + /** Not used */ + protected function _flush() + { + } + + /** Get the resource for reading */ + private function _getReadHandle() + { + if (!isset($this->_reader)) { + if (!$this->_reader = fopen($this->_path, 'rb')) { + throw new Swift_IoException( + 'Unable to open file for reading [' . $this->_path . ']' + ); + } + if ($this->_offset <> 0) { + $this->_getReadStreamSeekableStatus(); + $this->_seekReadStreamToPosition($this->_offset); + } + } + + return $this->_reader; + } + + /** Get the resource for writing */ + private function _getWriteHandle() + { + if (!isset($this->_writer)) { + if (!$this->_writer = fopen($this->_path, $this->_mode)) { + throw new Swift_IoException( + 'Unable to open file for writing [' . $this->_path . ']' + ); + } + } + + return $this->_writer; + } + + /** Force a reload of the resource for reading */ + private function _resetReadHandle() + { + if (isset($this->_reader)) { + fclose($this->_reader); + $this->_reader = null; + } + } + + /** Check if ReadOnly Stream is seekable */ + private function _getReadStreamSeekableStatus() + { + $metas = stream_get_meta_data($this->_reader); + $this->_seekable = $metas['seekable']; + } + + /** Streams in a readOnly stream ensuring copy if needed */ + private function _seekReadStreamToPosition($offset) + { + if ($this->_seekable===null) { + $this->_getReadStreamSeekableStatus(); + } + if ($this->_seekable === false) { + $currentPos = ftell($this->_reader); + if ($currentPos<$offset) { + $toDiscard = $offset-$currentPos; + fread($this->_reader, $toDiscard); + + return; + } + $this->_copyReadStream(); + } + fseek($this->_reader, $offset, SEEK_SET); + } + + /** Copy a readOnly Stream to ensure seekability */ + private function _copyReadStream() + { + if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) { + /* We have opened a php:// Stream Should work without problem */ + } elseif (function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) { + /* We have opened a tmpfile */ + } else { + throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available'); + } + $currentPos = ftell($this->_reader); + fclose($this->_reader); + $source = fopen($this->_path, 'rb'); + if (!$source) { + throw new Swift_IoException('Unable to open file for copying [' . $this->_path . ']'); + } + fseek($tmpFile, 0, SEEK_SET); + while (!feof($source)) { + fwrite($tmpFile, fread($source, 4096)); + } + fseek($tmpFile, $currentPos, SEEK_SET); + fclose($source); + $this->_reader = $tmpFile; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php b/public/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php new file mode 100644 index 00000000..f35f885e --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ByteStream/TemporaryFileByteStream.php @@ -0,0 +1,44 @@ +getPath())) === false) { + throw new Swift_IoException('Failed to get temporary file content.'); + } + + return $content; + } + + public function __destruct() + { + if (file_exists($this->getPath())) { + @unlink($this->getPath()); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader.php b/public/include/lib/swiftmailer/classes/Swift/CharacterReader.php new file mode 100644 index 00000000..df64d8a3 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterReader.php @@ -0,0 +1,69 @@ + + */ +interface Swift_CharacterReader +{ + const MAP_TYPE_INVALID = 0x01; + const MAP_TYPE_FIXED_LEN = 0x02; + const MAP_TYPE_POSITIONS = 0x03; + + /** + * Returns the complete character map + * + * @param string $string + * @param integer $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return integer + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars); + + /** + * Returns the mapType, see constants. + * + * @return integer + */ + public function getMapType(); + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param integer[] $bytes + * @param integer $size + * + * @return integer + */ + public function validateByteSequence($bytes, $size); + + /** + * Returns the number of bytes which should be read to start each character. + * + * For fixed width character sets this should be the number of octets-per-character. + * For multibyte character sets this will probably be 1. + * + * @return integer + */ + public function getInitialByteSize(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php new file mode 100644 index 00000000..49d7398c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/GenericFixedWidthReader.php @@ -0,0 +1,99 @@ + + */ +class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader +{ + /** + * The number of bytes in a single character. + * + * @var integer + */ + private $_width; + + /** + * Creates a new GenericFixedWidthReader using $width bytes per character. + * + * @param integer $width + */ + public function __construct($width) + { + $this->_width = $width; + } + + /** + * Returns the complete character map. + * + * @param string $string + * @param integer $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return integer + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + $strlen = strlen($string); + // % and / are CPU intensive, so, maybe find a better way + $ignored = $strlen % $this->_width; + $ignoredChars = substr($string, - $ignored); + $currentMap = $this->_width; + + return ($strlen - $ignored) / $this->_width; + } + + /** + * Returns the mapType. + * + * @return integer + */ + public function getMapType() + { + return self::MAP_TYPE_FIXED_LEN; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param integer $size + * + * @return integer + */ + public function validateByteSequence($bytes, $size) + { + $needed = $this->_width - $size; + + return ($needed > -1) ? $needed : -1; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return integer + */ + public function getInitialByteSize() + { + return $this->_width; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php new file mode 100644 index 00000000..18f3b04c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/UsAsciiReader.php @@ -0,0 +1,85 @@ +"\x07F") { // Invalid char + $currentMap[$i+$startOffset]=$string[$i]; + } + } + + return $strlen; + } + + /** + * Returns mapType + * + * @return integer mapType + */ + public function getMapType() + { + return self::MAP_TYPE_INVALID; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param integer $size + * + * @return integer + */ + public function validateByteSequence($bytes, $size) + { + $byte = reset($bytes); + if (1 == count($bytes) && $byte >= 0x00 && $byte <= 0x7F) { + return 0; + } else { + return -1; + } + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return integer + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php new file mode 100644 index 00000000..e3773c31 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterReader/Utf8Reader.php @@ -0,0 +1,181 @@ + + */ +class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader +{ + /** Pre-computed for optimization */ + private static $length_map=array( + // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x0N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x2N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x4N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x6N + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x8N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9N + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xAN + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBN + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xCN + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDN + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEN + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0 // 0xFN + ); + + private static $s_length_map=array( + "\x00"=>1, "\x01"=>1, "\x02"=>1, "\x03"=>1, "\x04"=>1, "\x05"=>1, "\x06"=>1, "\x07"=>1, + "\x08"=>1, "\x09"=>1, "\x0a"=>1, "\x0b"=>1, "\x0c"=>1, "\x0d"=>1, "\x0e"=>1, "\x0f"=>1, + "\x10"=>1, "\x11"=>1, "\x12"=>1, "\x13"=>1, "\x14"=>1, "\x15"=>1, "\x16"=>1, "\x17"=>1, + "\x18"=>1, "\x19"=>1, "\x1a"=>1, "\x1b"=>1, "\x1c"=>1, "\x1d"=>1, "\x1e"=>1, "\x1f"=>1, + "\x20"=>1, "\x21"=>1, "\x22"=>1, "\x23"=>1, "\x24"=>1, "\x25"=>1, "\x26"=>1, "\x27"=>1, + "\x28"=>1, "\x29"=>1, "\x2a"=>1, "\x2b"=>1, "\x2c"=>1, "\x2d"=>1, "\x2e"=>1, "\x2f"=>1, + "\x30"=>1, "\x31"=>1, "\x32"=>1, "\x33"=>1, "\x34"=>1, "\x35"=>1, "\x36"=>1, "\x37"=>1, + "\x38"=>1, "\x39"=>1, "\x3a"=>1, "\x3b"=>1, "\x3c"=>1, "\x3d"=>1, "\x3e"=>1, "\x3f"=>1, + "\x40"=>1, "\x41"=>1, "\x42"=>1, "\x43"=>1, "\x44"=>1, "\x45"=>1, "\x46"=>1, "\x47"=>1, + "\x48"=>1, "\x49"=>1, "\x4a"=>1, "\x4b"=>1, "\x4c"=>1, "\x4d"=>1, "\x4e"=>1, "\x4f"=>1, + "\x50"=>1, "\x51"=>1, "\x52"=>1, "\x53"=>1, "\x54"=>1, "\x55"=>1, "\x56"=>1, "\x57"=>1, + "\x58"=>1, "\x59"=>1, "\x5a"=>1, "\x5b"=>1, "\x5c"=>1, "\x5d"=>1, "\x5e"=>1, "\x5f"=>1, + "\x60"=>1, "\x61"=>1, "\x62"=>1, "\x63"=>1, "\x64"=>1, "\x65"=>1, "\x66"=>1, "\x67"=>1, + "\x68"=>1, "\x69"=>1, "\x6a"=>1, "\x6b"=>1, "\x6c"=>1, "\x6d"=>1, "\x6e"=>1, "\x6f"=>1, + "\x70"=>1, "\x71"=>1, "\x72"=>1, "\x73"=>1, "\x74"=>1, "\x75"=>1, "\x76"=>1, "\x77"=>1, + "\x78"=>1, "\x79"=>1, "\x7a"=>1, "\x7b"=>1, "\x7c"=>1, "\x7d"=>1, "\x7e"=>1, "\x7f"=>1, + "\x80"=>0, "\x81"=>0, "\x82"=>0, "\x83"=>0, "\x84"=>0, "\x85"=>0, "\x86"=>0, "\x87"=>0, + "\x88"=>0, "\x89"=>0, "\x8a"=>0, "\x8b"=>0, "\x8c"=>0, "\x8d"=>0, "\x8e"=>0, "\x8f"=>0, + "\x90"=>0, "\x91"=>0, "\x92"=>0, "\x93"=>0, "\x94"=>0, "\x95"=>0, "\x96"=>0, "\x97"=>0, + "\x98"=>0, "\x99"=>0, "\x9a"=>0, "\x9b"=>0, "\x9c"=>0, "\x9d"=>0, "\x9e"=>0, "\x9f"=>0, + "\xa0"=>0, "\xa1"=>0, "\xa2"=>0, "\xa3"=>0, "\xa4"=>0, "\xa5"=>0, "\xa6"=>0, "\xa7"=>0, + "\xa8"=>0, "\xa9"=>0, "\xaa"=>0, "\xab"=>0, "\xac"=>0, "\xad"=>0, "\xae"=>0, "\xaf"=>0, + "\xb0"=>0, "\xb1"=>0, "\xb2"=>0, "\xb3"=>0, "\xb4"=>0, "\xb5"=>0, "\xb6"=>0, "\xb7"=>0, + "\xb8"=>0, "\xb9"=>0, "\xba"=>0, "\xbb"=>0, "\xbc"=>0, "\xbd"=>0, "\xbe"=>0, "\xbf"=>0, + "\xc0"=>2, "\xc1"=>2, "\xc2"=>2, "\xc3"=>2, "\xc4"=>2, "\xc5"=>2, "\xc6"=>2, "\xc7"=>2, + "\xc8"=>2, "\xc9"=>2, "\xca"=>2, "\xcb"=>2, "\xcc"=>2, "\xcd"=>2, "\xce"=>2, "\xcf"=>2, + "\xd0"=>2, "\xd1"=>2, "\xd2"=>2, "\xd3"=>2, "\xd4"=>2, "\xd5"=>2, "\xd6"=>2, "\xd7"=>2, + "\xd8"=>2, "\xd9"=>2, "\xda"=>2, "\xdb"=>2, "\xdc"=>2, "\xdd"=>2, "\xde"=>2, "\xdf"=>2, + "\xe0"=>3, "\xe1"=>3, "\xe2"=>3, "\xe3"=>3, "\xe4"=>3, "\xe5"=>3, "\xe6"=>3, "\xe7"=>3, + "\xe8"=>3, "\xe9"=>3, "\xea"=>3, "\xeb"=>3, "\xec"=>3, "\xed"=>3, "\xee"=>3, "\xef"=>3, + "\xf0"=>4, "\xf1"=>4, "\xf2"=>4, "\xf3"=>4, "\xf4"=>4, "\xf5"=>4, "\xf6"=>4, "\xf7"=>4, + "\xf8"=>5, "\xf9"=>5, "\xfa"=>5, "\xfb"=>5, "\xfc"=>6, "\xfd"=>6, "\xfe"=>0, "\xff"=>0, + ); + + /** + * Returns the complete character map. + * + * @param string $string + * @param integer $startOffset + * @param array $currentMap + * @param mixed $ignoredChars + * + * @return integer + */ + public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars) + { + if (!isset($currentMap['i']) || ! isset($currentMap['p'])) { + $currentMap['p'] = $currentMap['i'] = array(); + } + + $strlen=strlen($string); + $charPos=count($currentMap['p']); + $foundChars=0; + $invalid=false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::$s_length_map[$char]; + if ($size == 0) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } else { + if ($invalid == true) { + /* We mark the chars as invalid and start a new char */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i; + $currentMap['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + } + + return $foundChars; + } + + /** + * Returns mapType. + * + * @return integer mapType + */ + public function getMapType() + { + return self::MAP_TYPE_POSITIONS; + } + + /** + * Returns an integer which specifies how many more bytes to read. + * + * A positive integer indicates the number of more bytes to fetch before invoking + * this method again. + * A value of zero means this is already a valid character. + * A value of -1 means this cannot possibly be a valid character. + * + * @param string $bytes + * @param integer $size + * + * @return integer + */ + public function validateByteSequence($bytes, $size) + { + if ($size<1) { + return -1; + } + $needed = self::$length_map[$bytes[0]] - $size; + + return ($needed > -1) + ? $needed + : -1 + ; + } + + /** + * Returns the number of bytes which should be read to start each character. + * + * @return integer + */ + public function getInitialByteSize() + { + return 1; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php b/public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php new file mode 100644 index 00000000..d653b813 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterReaderFactory.php @@ -0,0 +1,28 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + public function init() + { + if (count(self::$_map) > 0) { + return; + } + + $prefix = 'Swift_CharacterReader_'; + + $singleByte = array( + 'class' => $prefix . 'GenericFixedWidthReader', + 'constructor' => array(1) + ); + + $doubleByte = array( + 'class' => $prefix . 'GenericFixedWidthReader', + 'constructor' => array(2) + ); + + $fourBytes = array( + 'class' => $prefix . 'GenericFixedWidthReader', + 'constructor' => array(4) + ); + + // Utf-8 + self::$_map['utf-?8'] = array( + 'class' => $prefix . 'Utf8Reader', + 'constructor' => array() + ); + + //7-8 bit charsets + self::$_map['(us-)?ascii'] = $singleByte; + self::$_map['(iso|iec)-?8859-?[0-9]+'] = $singleByte; + self::$_map['windows-?125[0-9]'] = $singleByte; + self::$_map['cp-?[0-9]+'] = $singleByte; + self::$_map['ansi'] = $singleByte; + self::$_map['macintosh'] = $singleByte; + self::$_map['koi-?7'] = $singleByte; + self::$_map['koi-?8-?.+'] = $singleByte; + self::$_map['mik'] = $singleByte; + self::$_map['(cork|t1)'] = $singleByte; + self::$_map['v?iscii'] = $singleByte; + + //16 bits + self::$_map['(ucs-?2|utf-?16)'] = $doubleByte; + + //32 bits + self::$_map['(ucs-?4|utf-?32)'] = $fourBytes; + + // Fallback + self::$_map['.*'] = $singleByte; + } + + /** + * Returns a CharacterReader suitable for the charset applied. + * + * @param string $charset + * + * @return Swift_CharacterReader + */ + public function getReaderFor($charset) + { + $charset = trim(strtolower($charset)); + foreach (self::$_map as $pattern => $spec) { + $re = '/^' . $pattern . '$/D'; + if (preg_match($re, $charset)) { + if (!array_key_exists($pattern, self::$_loaded)) { + $reflector = new ReflectionClass($spec['class']); + if ($reflector->getConstructor()) { + $reader = $reflector->newInstanceArgs($spec['constructor']); + } else { + $reader = $reflector->newInstance(); + } + self::$_loaded[$pattern] = $reader; + } + + return self::$_loaded[$pattern]; + } + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterStream.php b/public/include/lib/swiftmailer/classes/Swift/CharacterStream.php new file mode 100644 index 00000000..29462001 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterStream.php @@ -0,0 +1,91 @@ +setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * Overwrite this character stream using the byte sequence in the byte stream. + * + * @param Swift_OutputByteStream $os output stream to read from + */ + public function importByteStream(Swift_OutputByteStream $os) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory + ->getReaderFor($this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + while (false !== $bytes = $os->read($startLength)) { + $c = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + $size = count($c); + $need = $this->_charReader + ->validateByteSequence($c, $size); + if ($need > 0 && + false !== $bytes = $os->read($need)) + { + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $c[] = self::$_byteMap[$bytes[$i]]; + } + } + $this->_array[] = $c; + ++$this->_array_size; + } + } + + /** + * Import a string a bytes into this CharacterStream, overwriting any existing + * data in the stream. + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * Read $length characters from the stream and move the internal pointer + * $length further into the stream. + * + * @param integer $length + * + * @return string + */ + public function read($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + + // Don't use array slice + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += $i - $this->_offset; // Limit function calls + $chars = false; + foreach ($arrays as $array) { + $chars .= implode('', array_map('chr', $array)); + } + + return $chars; + } + + /** + * Read $length characters from the stream and return a 1-dimensional array + * containing there octet values. + * + * @param integer $length + * + * @return integer[] + */ + public function readBytes($length) + { + if ($this->_offset == $this->_array_size) { + return false; + } + $arrays = array(); + $end = $length + $this->_offset; + for ($i = $this->_offset; $i < $end; ++$i) { + if (!isset($this->_array[$i])) { + break; + } + $arrays[] = $this->_array[$i]; + } + $this->_offset += ($i - $this->_offset); // Limit function calls + + return call_user_func_array('array_merge', $arrays); + } + + /** + * Write $chars to the end of the stream. + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + } + + $startLength = $this->_charReader->getInitialByteSize(); + + $fp = fopen('php://memory', 'w+b'); + fwrite($fp, $chars); + unset($chars); + fseek($fp, 0, SEEK_SET); + + $buffer = array(0); + $buf_pos = 1; + $buf_len = 1; + $has_datas = true; + do { + $bytes = array(); + // Buffer Filing + if ($buf_len - $buf_pos < $startLength) { + $buf = array_splice($buffer, $buf_pos); + $new = $this->_reloadBuffer($fp, 100); + if ($new) { + $buffer = array_merge($buf, $new); + $buf_len = count($buffer); + $buf_pos = 0; + } else { + $has_datas = false; + } + } + if ($buf_len - $buf_pos > 0) { + $size = 0; + for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) { + ++$size; + $bytes[] = $buffer[$buf_pos++]; + } + $need = $this->_charReader->validateByteSequence( + $bytes, $size); + if ($need > 0) { + if ($buf_len - $buf_pos < $need) { + $new = $this->_reloadBuffer($fp, $need); + + if ($new) { + $buffer = array_merge($buffer, $new); + $buf_len = count($buffer); + } + } + for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) { + $bytes[] = $buffer[$buf_pos++]; + } + } + $this->_array[] = $bytes; + ++$this->_array_size; + } + } while ($has_datas); + + fclose($fp); + } + + /** + * Move the internal pointer to $charOffset in the stream. + * + * @param integer $charOffset + */ + public function setPointer($charOffset) + { + if ($charOffset > $this->_array_size) { + $charOffset = $this->_array_size; + } elseif ($charOffset < 0) { + $charOffset = 0; + } + $this->_offset = $charOffset; + } + + /** + * Empty the stream and reset the internal pointer. + */ + public function flushContents() + { + $this->_offset = 0; + $this->_array = array(); + $this->_array_size = 0; + } + + private function _reloadBuffer($fp, $len) + { + if (!feof($fp) && ($bytes = fread($fp, $len)) !== false) { + $buf = array(); + for ($i = 0, $len = strlen($bytes); $i < $len; ++$i) { + $buf[] = self::$_byteMap[$bytes[$i]]; + } + + return $buf; + } + + return false; + } + + private static function _initializeMaps() + { + if (!isset(self::$_charMap)) { + self::$_charMap = array(); + for ($byte = 0; $byte < 256; ++$byte) { + self::$_charMap[$byte] = chr($byte); + } + self::$_byteMap = array_flip(self::$_charMap); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php b/public/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php new file mode 100644 index 00000000..98aabab7 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/CharacterStream/NgCharacterStream.php @@ -0,0 +1,277 @@ + + */ + +class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream +{ + /** + * The char reader (lazy-loaded) for the current charset. + * + * @var Swift_CharacterReader + */ + private $_charReader; + + /** + * A factory for creating CharacterReader instances. + * + * @var Swift_CharacterReaderFactory + */ + private $_charReaderFactory; + + /** + * The character set this stream is using. + * + * @var string + */ + private $_charset; + + /** + * The data's stored as-is. + * + * @var string + */ + private $_datas = ''; + + /** + * Number of bytes in the stream + * + * @var integer + */ + private $_datasSize = 0; + + /** + * Map. + * + * @var mixed + */ + private $_map; + + /** + * Map Type. + * + * @var integer + */ + private $_mapType = 0; + + /** + * Number of characters in the stream. + * + * @var integer + */ + private $_charCount = 0; + + /** + * Position in the stream. + * + * @var integer + */ + private $_currentPos = 0; + + /** + * Constructor. + * + * @param Swift_CharacterReaderFactory $factory + * @param string $charset + */ + public function __construct(Swift_CharacterReaderFactory $factory, $charset) + { + $this->setCharacterReaderFactory($factory); + $this->setCharacterSet($charset); + } + + /* -- Changing parameters of the stream -- */ + + /** + * Set the character set used in this CharacterStream. + * + * @param string $charset + */ + public function setCharacterSet($charset) + { + $this->_charset = $charset; + $this->_charReader = null; + $this->_mapType = 0; + } + + /** + * Set the CharacterReaderFactory for multi charset support. + * + * @param Swift_CharacterReaderFactory $factory + */ + public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) + { + $this->_charReaderFactory = $factory; + } + + /** + * @see Swift_CharacterStream::flushContents() + */ + public function flushContents() + { + $this->_datas = null; + $this->_map = null; + $this->_charCount = 0; + $this->_currentPos = 0; + $this->_datasSize = 0; + } + + /** + * @see Swift_CharacterStream::importByteStream() + * + * @param Swift_OutputByteStream $os + */ + public function importByteStream(Swift_OutputByteStream $os) + { + $this->flushContents(); + $blocks=512; + $os->setReadPointer(0); + while(false!==($read = $os->read($blocks))) + $this->write($read); + } + + /** + * @see Swift_CharacterStream::importString() + * + * @param string $string + */ + public function importString($string) + { + $this->flushContents(); + $this->write($string); + } + + /** + * @see Swift_CharacterStream::read() + * + * @param integer $length + * + * @return string + */ + public function read($length) + { + if ($this->_currentPos>=$this->_charCount) { + return false; + } + $ret=false; + $length = ($this->_currentPos+$length > $this->_charCount) + ? $this->_charCount - $this->_currentPos + : $length; + switch ($this->_mapType) { + case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: + $len = $length*$this->_map; + $ret = substr($this->_datas, + $this->_currentPos * $this->_map, + $len); + $this->_currentPos += $length; + break; + + case Swift_CharacterReader::MAP_TYPE_INVALID: + $end = $this->_currentPos + $length; + $end = $end > $this->_charCount + ?$this->_charCount + :$end; + $ret = ''; + for (; $this->_currentPos < $length; ++$this->_currentPos) { + if (isset ($this->_map[$this->_currentPos])) { + $ret .= '?'; + } else { + $ret .= $this->_datas[$this->_currentPos]; + } + } + break; + + case Swift_CharacterReader::MAP_TYPE_POSITIONS: + $end = $this->_currentPos + $length; + $end = $end > $this->_charCount + ?$this->_charCount + :$end; + $ret = ''; + $start = 0; + if ($this->_currentPos>0) { + $start = $this->_map['p'][$this->_currentPos-1]; + } + $to = $start; + for (; $this->_currentPos < $end; ++$this->_currentPos) { + if (isset($this->_map['i'][$this->_currentPos])) { + $ret .= substr($this->_datas, $start, $to - $start).'?'; + $start = $this->_map['p'][$this->_currentPos]; + } else { + $to = $this->_map['p'][$this->_currentPos]; + } + } + $ret .= substr($this->_datas, $start, $to - $start); + break; + } + + return $ret; + } + + /** + * @see Swift_CharacterStream::readBytes() + * + * @param integer $length + * + * @return integer[] + */ + public function readBytes($length) + { + $read=$this->read($length); + if ($read!==false) { + $ret = array_map('ord', str_split($read, 1)); + + return $ret; + } + + return false; + } + + /** + * @see Swift_CharacterStream::setPointer() + * + * @param integer $charOffset + */ + public function setPointer($charOffset) + { + if ($this->_charCount<$charOffset) { + $charOffset=$this->_charCount; + } + $this->_currentPos = $charOffset; + } + + /** + * @see Swift_CharacterStream::write() + * + * @param string $chars + */ + public function write($chars) + { + if (!isset($this->_charReader)) { + $this->_charReader = $this->_charReaderFactory->getReaderFor( + $this->_charset); + $this->_map = array(); + $this->_mapType = $this->_charReader->getMapType(); + } + $ignored=''; + $this->_datas .= $chars; + $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored); + if ($ignored!==false) { + $this->_datasSize=strlen($this->_datas)-strlen($ignored); + } else { + $this->_datasSize=strlen($this->_datas); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php b/public/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php new file mode 100644 index 00000000..58d52752 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ConfigurableSpool.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Base class for Spools (implements time and message limits). + * + * @package Swift + * @author Fabien Potencier + */ +abstract class Swift_ConfigurableSpool implements Swift_Spool +{ + /** The maximum number of messages to send per flush */ + private $_message_limit; + + /** The time limit per flush */ + private $_time_limit; + + /** + * Sets the maximum number of messages to send per flush. + * + * @param integer $limit + */ + public function setMessageLimit($limit) + { + $this->_message_limit = (int) $limit; + } + + /** + * Gets the maximum number of messages to send per flush. + * + * @return integer The limit + */ + public function getMessageLimit() + { + return $this->_message_limit; + } + + /** + * Sets the time limit (in seconds) per flush. + * + * @param integer $limit The limit + */ + public function setTimeLimit($limit) + { + $this->_time_limit = (int) $limit; + } + + /** + * Gets the time limit (in seconds) per flush. + * + * @return integer The limit + */ + public function getTimeLimit() + { + return $this->_time_limit; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/DependencyContainer.php b/public/include/lib/swiftmailer/classes/Swift/DependencyContainer.php new file mode 100644 index 00000000..b7178615 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/DependencyContainer.php @@ -0,0 +1,373 @@ +_store); + } + + /** + * Test if an item is registered in this container with the given name. + * + * @see register() + * + * @param string $itemName + * + * @return boolean + */ + public function has($itemName) + { + return array_key_exists($itemName, $this->_store) + && isset($this->_store[$itemName]['lookupType']); + } + + /** + * Lookup the item with the given $itemName. + * + * @see register() + * + * @param string $itemName + * + * @return mixed + * + * @throws Swift_DependencyException If the dependency is not found + */ + public function lookup($itemName) + { + if (!$this->has($itemName)) { + throw new Swift_DependencyException( + 'Cannot lookup dependency "' . $itemName . '" since it is not registered.' + ); + } + + switch ($this->_store[$itemName]['lookupType']) { + case self::TYPE_ALIAS: + return $this->_createAlias($itemName); + case self::TYPE_VALUE: + return $this->_getValue($itemName); + case self::TYPE_INSTANCE: + return $this->_createNewInstance($itemName); + case self::TYPE_SHARED: + return $this->_createSharedInstance($itemName); + } + } + + /** + * Create an array of arguments passed to the constructor of $itemName. + * + * @param string $itemName + * + * @return array + */ + public function createDependenciesFor($itemName) + { + $args = array(); + if (isset($this->_store[$itemName]['args'])) { + $args = $this->_resolveArgs($this->_store[$itemName]['args']); + } + + return $args; + } + + /** + * Register a new dependency with $itemName. + * + * This method returns the current DependencyContainer instance because it + * requires the use of the fluid interface to set the specific details for the + * dependency. + * @see asNewInstanceOf(), asSharedInstanceOf(), asValue() + * + * @param string $itemName + * + * @return Swift_DependencyContainer + */ + public function register($itemName) + { + $this->_store[$itemName] = array(); + $this->_endPoint =& $this->_store[$itemName]; + + return $this; + } + + /** + * Specify the previously registered item as a literal value. + * + * {@link register()} must be called before this will work. + * + * @param mixed $value + * + * @return Swift_DependencyContainer + */ + public function asValue($value) + { + $endPoint =& $this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_VALUE; + $endPoint['value'] = $value; + + return $this; + } + + /** + * Specify the previously registered item as an alias of another item. + * + * @param string $lookup + * + * @return Swift_DependencyContainer + */ + public function asAliasOf($lookup) + { + $endPoint =& $this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_ALIAS; + $endPoint['ref'] = $lookup; + + return $this; + } + + /** + * Specify the previously registered item as a new instance of $className. + * + * {@link register()} must be called before this will work. + * Any arguments can be set with {@link withDependencies()}, + * {@link addConstructorValue()} or {@link addConstructorLookup()}. + * + * @see withDependencies(), addConstructorValue(), addConstructorLookup() + * + * @param string $className + * + * @return Swift_DependencyContainer + */ + public function asNewInstanceOf($className) + { + $endPoint =& $this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_INSTANCE; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify the previously registered item as a shared instance of $className. + * + * {@link register()} must be called before this will work. + * + * @param string $className + * + * @return Swift_DependencyContainer + */ + public function asSharedInstanceOf($className) + { + $endPoint =& $this->_getEndPoint(); + $endPoint['lookupType'] = self::TYPE_SHARED; + $endPoint['className'] = $className; + + return $this; + } + + /** + * Specify a list of injected dependencies for the previously registered item. + * + * This method takes an array of lookup names. + * + * @see addConstructorValue(), addConstructorLookup() + * + * @param array $lookups + * + * @return Swift_DependencyContainer + */ + public function withDependencies(array $lookups) + { + $endPoint =& $this->_getEndPoint(); + $endPoint['args'] = array(); + foreach ($lookups as $lookup) { + $this->addConstructorLookup($lookup); + } + + return $this; + } + + /** + * Specify a literal (non looked up) value for the constructor of the + * previously registered item. + * + * @see withDependencies(), addConstructorLookup() + * + * @param mixed $value + * + * @return Swift_DependencyContainer + */ + public function addConstructorValue($value) + { + $endPoint =& $this->_getEndPoint(); + if (!isset($endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'value', 'item' => $value); + + return $this; + } + + /** + * Specify a dependency lookup for the constructor of the previously + * registered item. + * + * @see withDependencies(), addConstructorValue() + * + * @param string $lookup + * + * @return Swift_DependencyContainer + */ + public function addConstructorLookup($lookup) + { + $endPoint =& $this->_getEndPoint(); + if (!isset($this->_endPoint['args'])) { + $endPoint['args'] = array(); + } + $endPoint['args'][] = array('type' => 'lookup', 'item' => $lookup); + + return $this; + } + + // -- Private methods + + /** Get the literal value with $itemName */ + private function _getValue($itemName) + { + return $this->_store[$itemName]['value']; + } + + /** Resolve an alias to another item */ + private function _createAlias($itemName) + { + return $this->lookup($this->_store[$itemName]['ref']); + } + + /** Create a fresh instance of $itemName */ + private function _createNewInstance($itemName) + { + $reflector = new ReflectionClass($this->_store[$itemName]['className']); + if ($reflector->getConstructor()) { + return $reflector->newInstanceArgs( + $this->createDependenciesFor($itemName) + ); + } else { + return $reflector->newInstance(); + } + } + + /** Create and register a shared instance of $itemName */ + private function _createSharedInstance($itemName) + { + if (!isset($this->_store[$itemName]['instance'])) { + $this->_store[$itemName]['instance'] = $this->_createNewInstance($itemName); + } + + return $this->_store[$itemName]['instance']; + } + + /** Get the current endpoint in the store */ + private function &_getEndPoint() + { + if (!isset($this->_endPoint)) { + throw new BadMethodCallException( + 'Component must first be registered by calling register()' + ); + } + + return $this->_endPoint; + } + + /** Get an argument list with dependencies resolved */ + private function _resolveArgs(array $args) + { + $resolved = array(); + foreach ($args as $argDefinition) { + switch ($argDefinition['type']) { + case 'lookup': + $resolved[] = $this->_lookupRecursive($argDefinition['item']); + break; + case 'value': + $resolved[] = $argDefinition['item']; + break; + } + } + + return $resolved; + } + + /** Resolve a single dependency with an collections */ + private function _lookupRecursive($item) + { + if (is_array($item)) { + $collection = array(); + foreach ($item as $k => $v) { + $collection[$k] = $this->_lookupRecursive($v); + } + + return $collection; + } else { + return $this->lookup($item); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/DependencyException.php b/public/include/lib/swiftmailer/classes/Swift/DependencyException.php new file mode 100644 index 00000000..b3f01709 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/DependencyException.php @@ -0,0 +1,28 @@ +createDependenciesFor('mime.embeddedfile') + ); + + $this->setBody($data); + $this->setFilename($filename); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new EmbeddedFile. + * + * @param string|Swift_OutputByteStream $data + * @param string $filename + * @param string $contentType + * + * @return Swift_Mime_EmbeddedFile + */ + public static function newInstance($data = null, $filename = null, $contentType = null) + { + return new self($data, $filename, $contentType); + } + + /** + * Create a new EmbeddedFile from a filesystem path. + * + * @param string $path + * + * @return Swift_Mime_EmbeddedFile + */ + public static function fromPath($path) + { + return self::newInstance()->setFile( + new Swift_ByteStream_FileByteStream($path) + ); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder.php b/public/include/lib/swiftmailer/classes/Swift/Encoder.php new file mode 100644 index 00000000..53e88b8c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Encoder.php @@ -0,0 +1,29 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + + if (0 != $firstLineOffset) { + $firstLine = substr( + $encodedString, 0, $maxLineLength - $firstLineOffset + ) . "\r\n"; + $encodedString = substr( + $encodedString, $maxLineLength - $firstLineOffset + ); + } + + return $firstLine . trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } + + /** + * Does nothing. + */ + public function charsetChanged($charset) + { + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php b/public/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php new file mode 100644 index 00000000..e155bb99 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Encoder/QpEncoder.php @@ -0,0 +1,286 @@ + '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', + 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', + 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', + 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', + 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', + 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', + 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', + 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', + 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', + 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', + 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', + 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', + 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', + 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', + 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', + 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', + 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', + 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', + 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', + 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', + 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', + 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', + 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', + 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', + 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', + 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', + 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', + 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', + 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', + 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', + 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', + 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', + 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', + 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', + 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', + 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', + 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', + 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', + 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', + 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', + 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', + 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', + 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', + 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', + 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', + 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', + 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', + 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', + 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', + 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', + 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', + 255 => '=FF' + ); + + protected static $_safeMapShare = array(); + + /** + * A map of non-encoded ascii characters. + * + * @var string[] + */ + protected $_safeMap = array(); + + /** + * Creates a new QpEncoder for the given CharacterStream. + * + * @param Swift_CharacterStream $charStream to use for reading characters + * @param Swift_StreamFilter $filter if input should be canonicalized + */ + public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) + { + $this->_charStream = $charStream; + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + $this->_filter = $filter; + } + + public function __sleep() + { + return array('_charStream', '_filter'); + } + + public function __wakeup() + { + if (!isset(self::$_safeMapShare[$this->getSafeMapShareId()])) { + $this->initSafeMap(); + self::$_safeMapShare[$this->getSafeMapShareId()] = $this->_safeMap; + } else { + $this->_safeMap = self::$_safeMapShare[$this->getSafeMapShareId()]; + } + } + + protected function getSafeMapShareId() + { + return get_class($this); + } + + protected function initSafeMap() + { + foreach (array_merge( + array(0x09, 0x20), range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) + { + $this->_safeMap[$byte] = chr($byte); + } + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param string $string to encode + * @param integer $firstLineOffset, optional + * @param integer $maxLineLength, optional 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $lines = array(); + $lNo = 0; + $lines[$lNo] = ''; + $currentLine =& $lines[$lNo++]; + $size=$lineLen=0; + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + // Fetching more than 4 chars at one is slower, as is fetching fewer bytes + // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 + // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + if ($currentLine && $lineLen+$size >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine =& $lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen=0; + } + $lineLen+=$size; + $currentLine .= $enc; + } + + return $this->_standardize(implode("=\r\n", $lines)); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } + + // -- Protected methods + + /** + * Encode the given byte array into a verbatim QP form. + * + * @param integer[] $bytes + * @param integer $size + * + * @return string + */ + protected function _encodeByteSequence(array $bytes, &$size) + { + $ret = ''; + $size=0; + foreach ($bytes as $b) { + if (isset($this->_safeMap[$b])) { + $ret .= $this->_safeMap[$b]; + ++$size; + } else { + $ret .= self::$_qpMap[$b]; + $size+=3; + } + } + + return $ret; + } + + /** + * Get the next sequence of bytes to read from the char stream. + * + * @param integer $size number of bytes to read + * + * @return integer[] + */ + protected function _nextSequence($size = 4) + { + return $this->_charStream->readBytes($size); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + $string = str_replace(array("\t=0D=0A", " =0D=0A", "=0D=0A"), + array("=09\r\n", "=20\r\n", "\r\n"), $string + ); + switch ($end = ord(substr($string, -1))) { + case 0x09: + case 0x20: + $string = substr_replace($string, self::$_qpMap[$end], -1); + } + + return $string; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php b/public/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php new file mode 100644 index 00000000..37e30c1d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Encoder/Rfc2231Encoder.php @@ -0,0 +1,86 @@ +_charStream = $charStream; + } + + /** + * Takes an unencoded string and produces a string encoded according to + * RFC 2231 from it. + * + * @param string $string + * @param integer $firstLineOffset + * @param integer $maxLineLength optional, 0 indicates the default of 75 bytes + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + $lines = array(); $lineCount = 0; + $lines[] = ''; + $currentLine =& $lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $this->_charStream->flushContents(); + $this->_charStream->importString($string); + + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (false !== $char = $this->_charStream->read(4)) { + $encodedChar = rawurlencode($char); + if (0 != strlen($currentLine) + && strlen($currentLine . $encodedChar) > $thisLineLength) + { + $lines[] = ''; + $currentLine =& $lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } + + /** + * Updates the charset used. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charStream->setCharacterSet($charset); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Encoding.php b/public/include/lib/swiftmailer/classes/Swift/Encoding.php new file mode 100644 index 00000000..96391949 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Encoding.php @@ -0,0 +1,66 @@ +lookup($key); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php b/public/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php new file mode 100644 index 00000000..fa4f4447 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/CommandEvent.php @@ -0,0 +1,67 @@ +_command = $command; + $this->_successCodes = $successCodes; + } + + /** + * Get the command which was sent to the server. + * + * @return string + */ + public function getCommand() + { + return $this->_command; + } + + /** + * Get the numeric response codes which indicate success for this command. + * + * @return integer[] + */ + public function getSuccessCodes() + { + return $this->_successCodes; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php b/public/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php new file mode 100644 index 00000000..68009047 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/CommandListener.php @@ -0,0 +1,26 @@ +_source = $source; + } + + /** + * Get the source object of this event. + * + * @return object + */ + public function getSource() + { + return $this->_source; + } + + /** + * Prevent this Event from bubbling any further up the stack. + * + * @param boolean $cancel, optional + */ + public function cancelBubble($cancel = true) + { + $this->_bubbleCancelled = $cancel; + } + + /** + * Returns true if this Event will not bubble any further up the stack. + * + * @return boolean + */ + public function bubbleCancelled() + { + return $this->_bubbleCancelled; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php b/public/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php new file mode 100644 index 00000000..6b9117cb --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/ResponseEvent.php @@ -0,0 +1,68 @@ +_response = $response; + $this->_valid = $valid; + } + + /** + * Get the response which was received from the server. + * + * @return string + */ + public function getResponse() + { + return $this->_response; + } + + /** + * Get the success status of this Event. + * + * @return boolean + */ + public function isValid() + { + return $this->_valid; + } + +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php b/public/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php new file mode 100644 index 00000000..a39ba435 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/ResponseListener.php @@ -0,0 +1,26 @@ +_message = $message; + $this->_result = self::RESULT_PENDING; + } + + /** + * Get the Transport used to send the Message. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->getSource(); + } + + /** + * Get the Message being sent. + * + * @return Swift_Mime_Message + */ + public function getMessage() + { + return $this->_message; + } + + /** + * Set the array of addresses that failed in sending. + * + * @param array $recipients + */ + public function setFailedRecipients($recipients) + { + $this->_failedRecipients = $recipients; + } + + /** + * Get an recipient addresses which were not accepted for delivery. + * + * @return string[] + */ + public function getFailedRecipients() + { + return $this->_failedRecipients; + } + + /** + * Set the result of sending. + * + * @param integer $result + */ + public function setResult($result) + { + $this->_result = $result; + } + + /** + * Get the result of this Event. + * + * The return value is a bitmask from + * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED} + * + * @return integer + */ + public function getResult() + { + return $this->_result; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/SendListener.php b/public/include/lib/swiftmailer/classes/Swift/Events/SendListener.php new file mode 100644 index 00000000..bc914f54 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/SendListener.php @@ -0,0 +1,33 @@ +_eventMap = array( + 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener', + 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener', + 'Swift_Events_SendEvent' => 'Swift_Events_SendListener', + 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener', + 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener' + ); + } + + /** + * Create a new SendEvent for $source and $message. + * + * @param Swift_Transport $source + * @param Swift_Mime_Message + * + * @return Swift_Events_SendEvent + */ + public function createSendEvent(Swift_Transport $source, Swift_Mime_Message $message) + { + return new Swift_Events_SendEvent($source, $message); + } + + /** + * Create a new CommandEvent for $source and $command. + * + * @param Swift_Transport $source + * @param string $command That will be executed + * @param array $successCodes That are needed + * + * @return Swift_Events_CommandEvent + */ + public function createCommandEvent(Swift_Transport $source, $command, $successCodes = array()) + { + return new Swift_Events_CommandEvent($source, $command, $successCodes); + } + + /** + * Create a new ResponseEvent for $source and $response. + * + * @param Swift_Transport $source + * @param string $response + * @param boolean $valid If the response is valid + * + * @return Swift_Events_ResponseEvent + */ + public function createResponseEvent(Swift_Transport $source, $response, $valid) + { + return new Swift_Events_ResponseEvent($source, $response, $valid); + } + + /** + * Create a new TransportChangeEvent for $source. + * + * @param Swift_Transport $source + * + * @return Swift_Events_TransportChangeEvent + */ + public function createTransportChangeEvent(Swift_Transport $source) + { + return new Swift_Events_TransportChangeEvent($source); + } + + /** + * Create a new TransportExceptionEvent for $source. + * + * @param Swift_Transport $source + * @param Swift_TransportException $ex + * + * @return Swift_Events_TransportExceptionEvent + */ + public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex) + { + return new Swift_Events_TransportExceptionEvent($source, $ex); + } + + /** + * Bind an event listener to this dispatcher. + * + * @param Swift_Events_EventListener $listener + */ + public function bindEventListener(Swift_Events_EventListener $listener) + { + foreach ($this->_listeners as $l) { + // Already loaded + if ($l === $listener) { + return; + } + } + $this->_listeners[] = $listener; + } + + /** + * Dispatch the given Event to all suitable listeners. + * + * @param Swift_Events_EventObject $evt + * @param string $target method + */ + public function dispatchEvent(Swift_Events_EventObject $evt, $target) + { + $this->_prepareBubbleQueue($evt); + $this->_bubble($evt, $target); + } + + // -- Private methods + + /** Queue listeners on a stack ready for $evt to be bubbled up it */ + private function _prepareBubbleQueue(Swift_Events_EventObject $evt) + { + $this->_bubbleQueue = array(); + $evtClass = get_class($evt); + foreach ($this->_listeners as $listener) { + if (array_key_exists($evtClass, $this->_eventMap) + && ($listener instanceof $this->_eventMap[$evtClass])) + { + $this->_bubbleQueue[] = $listener; + } + } + } + + /** Bubble $evt up the stack calling $target() on each listener */ + private function _bubble(Swift_Events_EventObject $evt, $target) + { + if (!$evt->bubbleCancelled() && $listener = array_shift($this->_bubbleQueue)) { + $listener->$target($evt); + $this->_bubble($evt, $target); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php b/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php new file mode 100644 index 00000000..d8b5316b --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeEvent.php @@ -0,0 +1,29 @@ +getSource(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php b/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php new file mode 100644 index 00000000..15550370 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/TransportChangeListener.php @@ -0,0 +1,47 @@ +_exception = $ex; + } + + /** + * Get the TransportException thrown. + * + * @return Swift_TransportException + */ + public function getException() + { + return $this->_exception; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php b/public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php new file mode 100644 index 00000000..709abda3 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Events/TransportExceptionListener.php @@ -0,0 +1,26 @@ +createDependenciesFor('transport.failover') + ); + + $this->setTransports($transports); + } + + /** + * Create a new FailoverTransport instance. + * + * @param Swift_Transport[] $transports + * + * @return Swift_FailoverTransport + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/FileSpool.php b/public/include/lib/swiftmailer/classes/Swift/FileSpool.php new file mode 100644 index 00000000..0f01f40b --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/FileSpool.php @@ -0,0 +1,209 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages on the filesystem. + * + * @package Swift + * @author Fabien Potencier + * @author Xavier De Cock + */ +class Swift_FileSpool extends Swift_ConfigurableSpool +{ + /** The spool directory */ + private $_path; + + /** + * File WriteRetry Limit + * + * @var int + */ + private $_retryLimit=10; + + /** + * Create a new FileSpool. + * + * @param string $path + * + * @throws Swift_IoException + */ + public function __construct($path) + { + $this->_path = $path; + + if (!file_exists($this->_path)) { + if (!mkdir($this->_path, 0777, true)) { + throw new Swift_IoException('Unable to create Path ['.$this->_path.']'); + } + } + } + + /** + * Tests if this Spool mechanism has started. + * + * @return boolean + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Spool mechanism. + */ + public function start() + { + } + + /** + * Stops this Spool mechanism. + */ + public function stop() + { + } + + /** + * Allow to manage the enqueuing retry limit. + * + * Default, is ten and allows over 64^20 different fileNames + * + * @param integer $limit + */ + public function setRetryLimit($limit) + { + $this->_retryLimit=$limit; + } + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @return boolean + * + * @throws Swift_IoException + */ + public function queueMessage(Swift_Mime_Message $message) + { + $ser = serialize($message); + $fileName = $this->_path . '/' . $this->getRandomString(10); + for ($i = 0; $i < $this->_retryLimit; ++$i) { + /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */ + $fp = @fopen($fileName . '.message', 'x'); + if (false !== $fp) { + if (false === fwrite($fp, $ser)) { + return false; + } + + return fclose($fp); + } else { + /* The file already exists, we try a longer fileName */ + $fileName .= $this->getRandomString(1); + } + } + + throw new Swift_IoException('Unable to create a file for enqueuing Message'); + } + + /** + * Execute a recovery if for any reason a process is sending for too long. + * + * @param integer $timeout in second Defaults is for very slow smtp responses + */ + public function recover($timeout = 900) + { + foreach (new DirectoryIterator($this->_path) as $file) { + $file = $file->getRealPath(); + + if (substr($file, - 16) == '.message.sending') { + $lockedtime = filectime($file); + if ((time() - $lockedtime) > $timeout) { + rename($file, substr($file, 0, - 8)); + } + } + } + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return integer The number of sent e-mail's + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + $directoryIterator = new DirectoryIterator($this->_path); + + /* Start the transport only if there are queued files to send */ + if (!$transport->isStarted()) { + foreach ($directoryIterator as $file) { + if (substr($file->getRealPath(), -8) == '.message') { + $transport->start(); + break; + } + } + } + + $failedRecipients = (array) $failedRecipients; + $count = 0; + $time = time(); + foreach ($directoryIterator as $file) { + $file = $file->getRealPath(); + + if (substr($file, -8) != '.message') { + continue; + } + + /* We try a rename, it's an atomic operation, and avoid locking the file */ + if (rename($file, $file.'.sending')) { + $message = unserialize(file_get_contents($file.'.sending')); + + $count += $transport->send($message, $failedRecipients); + + unlink($file.'.sending'); + } else { + /* This message has just been catched by another process */ + continue; + } + + if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) { + break; + } + + if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) { + break; + } + } + + return $count; + } + + /** + * Returns a random string needed to generate a fileName for the queue. + * + * @param integer $count + * + * @return string + */ + protected function getRandomString($count) + { + // This string MUST stay FS safe, avoid special chars + $base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-."; + $ret = ''; + $strlen = strlen($base); + for ($i = 0; $i < $count; ++$i) { + $ret .= $base[((int) rand(0, $strlen - 1))]; + } + + return $ret; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/FileStream.php b/public/include/lib/swiftmailer/classes/Swift/FileStream.php new file mode 100644 index 00000000..567633ec --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/FileStream.php @@ -0,0 +1,26 @@ +setFile( + new Swift_ByteStream_FileByteStream($path) + ); + + return $image; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/InputByteStream.php b/public/include/lib/swiftmailer/classes/Swift/InputByteStream.php new file mode 100644 index 00000000..ae81e5d9 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/InputByteStream.php @@ -0,0 +1,77 @@ +_stream = $stream; + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param integer $mode + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->_contents[$nsKey][$itemKey] = $string; + break; + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + $this->_contents[$nsKey][$itemKey] .= $string; + break; + default: + throw new Swift_SwiftException( + 'Invalid mode [' . $mode . '] used to set nsKey='. + $nsKey . ', itemKey=' . $itemKey + ); + } + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param integer $mode + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $this->clearKey($nsKey, $itemKey); + case self::MODE_APPEND: + if (!$this->hasKey($nsKey, $itemKey)) { + $this->_contents[$nsKey][$itemKey] = ''; + } + while (false !== $bytes = $os->read(8192)) { + $this->_contents[$nsKey][$itemKey] .= $bytes; + } + break; + default: + throw new Swift_SwiftException( + 'Invalid mode [' . $mode . '] used to set nsKey='. + $nsKey . ', itemKey=' . $itemKey + ); + } + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @return string + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + return $this->_contents[$nsKey][$itemKey]; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + $this->_prepareCache($nsKey); + $is->write($this->getString($nsKey, $itemKey)); + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return boolean + */ + public function hasKey($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + + return array_key_exists($itemKey, $this->_contents[$nsKey]); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + unset($this->_contents[$nsKey][$itemKey]); + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + unset($this->_contents[$nsKey]); + } + + // -- Private methods + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + if (!array_key_exists($nsKey, $this->_contents)) { + $this->_contents[$nsKey] = array(); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php b/public/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php new file mode 100644 index 00000000..740897a5 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/KeyCache/DiskKeyCache.php @@ -0,0 +1,328 @@ +_stream = $stream; + $this->_path = $path; + + if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { + $this->_quotes = true; + } + } + + /** + * Set a string into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param string $string + * @param integer $mode + * + * @throws Swift_IoException + */ + public function setString($nsKey, $itemKey, $string, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode [' . $mode . '] used to set nsKey='. + $nsKey . ', itemKey=' . $itemKey + ); + break; + } + fwrite($fp, $string); + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Set a ByteStream into the cache under $itemKey for the namespace $nsKey. + * + * @see MODE_WRITE, MODE_APPEND + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_OutputByteStream $os + * @param integer $mode + * + * @throws Swift_IoException + */ + public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode) + { + $this->_prepareCache($nsKey); + switch ($mode) { + case self::MODE_WRITE: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + break; + case self::MODE_APPEND: + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_END); + break; + default: + throw new Swift_SwiftException( + 'Invalid mode [' . $mode . '] used to set nsKey='. + $nsKey . ', itemKey=' . $itemKey + ); + break; + } + while (false !== $bytes = $os->read(8192)) { + fwrite($fp, $bytes); + } + $this->_freeHandle($nsKey, $itemKey); + } + + /** + * Provides a ByteStream which when written to, writes data to $itemKey. + * + * NOTE: The stream will always write in append mode. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $writeThrough + * + * @return Swift_InputByteStream + */ + public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) + { + $is = clone $this->_stream; + $is->setKeyCache($this); + $is->setNsKey($nsKey); + $is->setItemKey($itemKey); + if (isset($writeThrough)) { + $is->setWriteThroughStream($writeThrough); + } + + return $is; + } + + /** + * Get data back out of the cache as a string. + * + * @param string $nsKey + * @param string $itemKey + * + * @return string + * + * @throws Swift_IoException + */ + public function getString($nsKey, $itemKey) + { + $this->_prepareCache($nsKey); + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + $str = ''; + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $str .= $bytes; + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + + return $str; + } + } + + /** + * Get data back out of the cache as a ByteStream. + * + * @param string $nsKey + * @param string $itemKey + * @param Swift_InputByteStream $is to write the data to + */ + public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is) + { + if ($this->hasKey($nsKey, $itemKey)) { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_START); + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 0); + } + while (!feof($fp) && false !== $bytes = fread($fp, 8192)) { + $is->write($bytes); + } + if ($this->_quotes) { + ini_set('magic_quotes_runtime', 1); + } + $this->_freeHandle($nsKey, $itemKey); + } + } + + /** + * Check if the given $itemKey exists in the namespace $nsKey. + * + * @param string $nsKey + * @param string $itemKey + * + * @return boolean + */ + public function hasKey($nsKey, $itemKey) + { + return is_file($this->_path . '/' . $nsKey . '/' . $itemKey); + } + + /** + * Clear data for $itemKey in the namespace $nsKey if it exists. + * + * @param string $nsKey + * @param string $itemKey + */ + public function clearKey($nsKey, $itemKey) + { + if ($this->hasKey($nsKey, $itemKey)) { + $this->_freeHandle($nsKey, $itemKey); + unlink($this->_path . '/' . $nsKey . '/' . $itemKey); + } + } + + /** + * Clear all data in the namespace $nsKey if it exists. + * + * @param string $nsKey + */ + public function clearAll($nsKey) + { + if (array_key_exists($nsKey, $this->_keys)) { + foreach ($this->_keys[$nsKey] as $itemKey=>$null) { + $this->clearKey($nsKey, $itemKey); + } + if (is_dir($this->_path . '/' . $nsKey)) { + rmdir($this->_path . '/' . $nsKey); + } + unset($this->_keys[$nsKey]); + } + } + + // -- Private methods + + /** + * Initialize the namespace of $nsKey if needed. + * + * @param string $nsKey + */ + private function _prepareCache($nsKey) + { + $cacheDir = $this->_path . '/' . $nsKey; + if (!is_dir($cacheDir)) { + if (!mkdir($cacheDir)) { + throw new Swift_IoException('Failed to create cache directory ' . $cacheDir); + } + $this->_keys[$nsKey] = array(); + } + } + + /** + * Get a file handle on the cache item. + * + * @param string $nsKey + * @param string $itemKey + * @param integer $position + * + * @return resource + */ + private function _getHandle($nsKey, $itemKey, $position) + { + if (!isset($this->_keys[$nsKey][$itemKey])) { + $openMode = $this->hasKey($nsKey, $itemKey) + ? 'r+b' + : 'w+b' + ; + $fp = fopen($this->_path . '/' . $nsKey . '/' . $itemKey, $openMode); + $this->_keys[$nsKey][$itemKey] = $fp; + } + if (self::POSITION_START == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_SET); + } elseif (self::POSITION_END == $position) { + fseek($this->_keys[$nsKey][$itemKey], 0, SEEK_END); + } + + return $this->_keys[$nsKey][$itemKey]; + } + + private function _freeHandle($nsKey, $itemKey) + { + $fp = $this->_getHandle($nsKey, $itemKey, self::POSITION_CURRENT); + fclose($fp); + $this->_keys[$nsKey][$itemKey] = null; + } + + /** + * Destructor. + */ + public function __destruct() + { + foreach ($this->_keys as $nsKey=>$null) { + $this->clearAll($nsKey); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php b/public/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php new file mode 100644 index 00000000..f4f8adb9 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/KeyCache/KeyCacheInputStream.php @@ -0,0 +1,53 @@ +_keyCache = $keyCache; + } + + /** + * Specify a stream to write through for each write(). + * + * @param Swift_InputByteStream $is + */ + public function setWriteThroughStream(Swift_InputByteStream $is) + { + $this->_writeThrough = $is; + } + + /** + * Writes $bytes to the end of the stream. + * + * @param string $bytes + * @param Swift_InputByteStream $is optional + */ + public function write($bytes, Swift_InputByteStream $is = null) + { + $this->_keyCache->setString( + $this->_nsKey, $this->_itemKey, $bytes, Swift_KeyCache::MODE_APPEND + ); + if (isset($is)) { + $is->write($bytes); + } + if (isset($this->_writeThrough)) { + $this->_writeThrough->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Not used. + */ + public function bind(Swift_InputByteStream $is) + { + } + + /** + * Not used. + */ + public function unbind(Swift_InputByteStream $is) + { + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + */ + public function flushBuffers() + { + $this->_keyCache->clearKey($this->_nsKey, $this->_itemKey); + } + + /** + * Set the nsKey which will be written to. + * + * @param string $nsKey + */ + public function setNsKey($nsKey) + { + $this->_nsKey = $nsKey; + } + + /** + * Set the itemKey which will be written to. + * + * @param string $itemKey + */ + public function setItemKey($itemKey) + { + $this->_itemKey = $itemKey; + } + + /** + * Any implementation should be cloneable, allowing the clone to access a + * separate $nsKey and $itemKey. + */ + public function __clone() + { + $this->_writeThrough = null; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php b/public/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php new file mode 100644 index 00000000..6eb3db70 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/LoadBalancedTransport.php @@ -0,0 +1,47 @@ +createDependenciesFor('transport.loadbalanced') + ); + + $this->setTransports($transports); + } + + /** + * Create a new LoadBalancedTransport instance. + * + * @param array $transports + * + * @return Swift_LoadBalancedTransport + */ + public static function newInstance($transports = array()) + { + return new self($transports); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/MailTransport.php b/public/include/lib/swiftmailer/classes/Swift/MailTransport.php new file mode 100644 index 00000000..6c579396 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/MailTransport.php @@ -0,0 +1,47 @@ +createDependenciesFor('transport.mail') + ); + + $this->setExtraParams($extraParams); + } + + /** + * Create a new MailTransport instance. + * + * @param string $extraParams To be passed to mail() + * + * @return Swift_MailTransport + */ + public static function newInstance($extraParams = '-f%s') + { + return new self($extraParams); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer.php b/public/include/lib/swiftmailer/classes/Swift/Mailer.php new file mode 100644 index 00000000..b6703dee --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mailer.php @@ -0,0 +1,115 @@ +_transport = $transport; + } + + /** + * Create a new Mailer instance. + * + * @param Swift_Transport $transport + * + * @return Swift_Mailer + */ + public static function newInstance(Swift_Transport $transport) + { + return new self($transport); + } + + /** + * Create a new class instance of one of the message services. + * + * For example 'mimepart' would create a 'message.mimepart' instance + * + * @param string $service + * + * @return object + */ + public function createMessage($service = 'message') + { + return Swift_DependencyContainer::getInstance() + ->lookup('message.'.$service); + } + + /** + * Send the given Message like it would be sent in a mail client. + * + * All recipients (with the exception of Bcc) will be able to see the other + * recipients this message was sent to. + * + * Recipient/sender data will be retrieved from the Message object. + * + * The return value is the number of recipients who were accepted for + * delivery. + * + * @param Swift_Mime_Message $message + * @param array $failedRecipients An array of failures by-reference + * + * @return integer + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if (!$this->_transport->isStarted()) { + $this->_transport->start(); + } + + $sent = 0; + + try { + $sent = $this->_transport->send($message, $failedRecipients); + } catch (Swift_RfcComplianceException $e) { + foreach ($message->getTo() as $address => $name) { + $failedRecipients[] = $address; + } + } + + return $sent; + } + + /** + * Register a plugin using a known unique key (e.g. myPlugin). + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_transport->registerPlugin($plugin); + } + + /** + * The Transport used to send messages. + * + * @return Swift_Transport + */ + public function getTransport() + { + return $this->_transport; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php b/public/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php new file mode 100644 index 00000000..37e98daf --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mailer/ArrayRecipientIterator.php @@ -0,0 +1,57 @@ +_recipients = $recipients; + } + + /** + * Returns true only if there are more recipients to send to. + * + * @return boolean + */ + public function hasNext() + { + return !empty($this->_recipients); + } + + /** + * Returns an array where the keys are the addresses of recipients and the + * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL) + * + * @return array + */ + public function nextRecipient() + { + return array_splice($this->_recipients, 0, 1); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php b/public/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php new file mode 100644 index 00000000..073bce15 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mailer/RecipientIterator.php @@ -0,0 +1,34 @@ + 'Foo') or ('foo@bar' => NULL) + * + * @return array + */ + public function nextRecipient(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/MemorySpool.php b/public/include/lib/swiftmailer/classes/Swift/MemorySpool.php new file mode 100644 index 00000000..764b5aa2 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/MemorySpool.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in memory. + * + * @package Swift + * @author Fabien Potencier + */ +class Swift_MemorySpool implements Swift_Spool +{ + protected $messages = array(); + + /** + * Tests if this Transport mechanism has started. + * + * @return boolean + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Stores a message in the queue. + * + * @param Swift_Mime_Message $message The message to store + * + * @return boolean Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message) + { + $this->messages[] = $message; + + return true; + } + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return integer The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null) + { + if (!$this->messages) { + return 0; + } + + if (!$transport->isStarted()) { + $transport->start(); + } + + $count = 0; + while ($message = array_pop($this->messages)) { + $count += $transport->send($message, $failedRecipients); + } + + return $count; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Message.php b/public/include/lib/swiftmailer/classes/Swift/Message.php new file mode 100644 index 00000000..a5aac9ea --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Message.php @@ -0,0 +1,273 @@ +createDependenciesFor('mime.message') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setSubject($subject); + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new Message. + * + * @param string $subject + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Message + */ + public static function newInstance($subject = null, $body = null, $contentType = null, $charset = null) + { + return new self($subject, $body, $contentType, $charset); + } + + /** + * Add a MimePart to this Message. + * + * @param string|Swift_OutputByteStream $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Mime_SimpleMessage + */ + public function addPart($body, $contentType = null, $charset = null) + { + return $this->attach(Swift_MimePart::newInstance( + $body, $contentType, $charset + )); + } + + /** + * Attach a new signature handler to the message. + * + * @param Swift_Signer $signer + * @return Swift_Message + */ + public function attachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + $this->headerSigners[] = $signer; + } elseif ($signer instanceof Swift_Signers_BodySigner) { + $this->bodySigners[] = $signer; + } + + return $this; + } + + /** + * Attach a new signature handler to the message. + * + * @param Swift_Signer $signer + * @return Swift_Message + */ + public function detachSigner(Swift_Signer $signer) + { + if ($signer instanceof Swift_Signers_HeaderSigner) { + foreach ($this->headerSigners as $k => $headerSigner) { + if ($headerSigner === $signer) { + unset($this->headerSigners[$k]); + return $this; + } + } + } elseif ($signer instanceof Swift_Signers_BodySigner) { + foreach ($this->bodySigners as $k => $bodySigner) { + if ($bodySigner === $signer) { + unset($this->bodySigners[$k]); + return $this; + } + } + } + + return $this; + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + return parent::toString(); + } + + $this->saveMessage(); + + $this->doSign(); + + $string = parent::toString(); + + $this->restoreMessage(); + + return $string; + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (empty($this->headerSigners) && empty($this->bodySigners)) { + parent::toByteStream($is); + return; + } + + $this->saveMessage(); + + $this->doSign(); + + parent::toByteStream($is); + + $this->restoreMessage(); + + } + + public function __wakeup() + { + Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message'); + } + + /* -- Protected Methods -- */ + + /** + * loops through signers and apply the signatures + */ + protected function doSign() + { + foreach ($this->bodySigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->signMessage($this); + } + + foreach ($this->headerSigners as $signer) { + $altered = $signer->getAlteredHeaders(); + $this->saveHeaders($altered); + $signer->reset(); + + $signer->setHeaders($this->getHeaders()); + + $signer->startBody(); + $this->_bodyToByteStream($signer); + $signer->endBody(); + + $signer->addSignature($this->getHeaders()); + } + } + + /** + * save the message before any signature is applied + */ + protected function saveMessage() + { + $this->savedMessage = array('headers'=> array()); + $this->savedMessage['body'] = $this->getBody(); + $this->savedMessage['children'] = $this->getChildren(); + if (count($this->savedMessage['children']) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $this->savedMessage['children'])); + $this->setBody(''); + } + } + + /** + * save the original headers + * @param array $altered + */ + protected function saveHeaders(array $altered) + { + foreach ($altered as $head) { + $lc = strtolower($head); + + if (!isset($this->savedMessage['headers'][$lc])) { + $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head); + } + } + } + + /** + * Remove or restore altered headers + */ + protected function restoreHeaders() + { + foreach ($this->savedMessage['headers'] as $name => $savedValue) { + $headers = $this->getHeaders()->getAll($name); + + foreach ($headers as $key => $value) { + if (!isset($savedValue[$key])) { + $this->getHeaders()->remove($name, $key); + } + } + } + } + + /** + * Restore message body + */ + protected function restoreMessage() + { + $this->setBody($this->savedMessage['body']); + $this->setChildren($this->savedMessage['children']); + + $this->restoreHeaders(); + $this->savedMessage = array(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php new file mode 100644 index 00000000..faf358fa --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Attachment.php @@ -0,0 +1,155 @@ +setDisposition('attachment'); + $this->setContentType('application/octet-stream'); + $this->_mimeTypes = $mimeTypes; + } + + /** + * Get the nesting level used for this attachment. + * + * Always returns {@link LEVEL_MIXED}. + * + * @return integer + */ + public function getNestingLevel() + { + return self::LEVEL_MIXED; + } + + /** + * Get the Content-Disposition of this attachment. + * + * By default attachments have a disposition of "attachment". + * + * @return string + */ + public function getDisposition() + { + return $this->_getHeaderFieldModel('Content-Disposition'); + } + + /** + * Set the Content-Disposition of this attachment. + * + * @param string $disposition + * + * @return Swift_Mime_Attachment + */ + public function setDisposition($disposition) + { + if (!$this->_setHeaderFieldModel('Content-Disposition', $disposition)) { + $this->getHeaders()->addParameterizedHeader( + 'Content-Disposition', $disposition + ); + } + + return $this; + } + + /** + * Get the filename of this attachment when downloaded. + * + * @return string + */ + public function getFilename() + { + return $this->_getHeaderParameter('Content-Disposition', 'filename'); + } + + /** + * Set the filename of this attachment. + * + * @param string $filename + * + * @return Swift_Mime_Attachment + */ + public function setFilename($filename) + { + $this->_setHeaderParameter('Content-Disposition', 'filename', $filename); + $this->_setHeaderParameter('Content-Type', 'name', $filename); + + return $this; + } + + /** + * Get the file size of this attachment. + * + * @return integer + */ + public function getSize() + { + return $this->_getHeaderParameter('Content-Disposition', 'size'); + } + + /** + * Set the file size of this attachment. + * + * @param integer $size + * + * @return Swift_Mime_Attachment + */ + public function setSize($size) + { + $this->_setHeaderParameter('Content-Disposition', 'size', $size); + + return $this; + } + + /** + * Set the file that this attachment is for. + * + * @param Swift_FileStream $file + * @param string $contentType optional + * + * @return Swift_Mime_Attachment + */ + public function setFile(Swift_FileStream $file, $contentType = null) + { + $this->setFilename(basename($file->getPath())); + $this->setBody($file, $contentType); + if (!isset($contentType)) { + $extension = strtolower(substr( + $file->getPath(), strrpos($file->getPath(), '.') + 1 + )); + + if (array_key_exists($extension, $this->_mimeTypes)) { + $this->setContentType($this->_mimeTypes[$extension]); + } + } + + return $this; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php b/public/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php new file mode 100644 index 00000000..bfd41edf --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/CharsetObserver.php @@ -0,0 +1,26 @@ += $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $remainder = 0; + + while (false !== $bytes = $os->read(8190)) { + $encoded = base64_encode($bytes); + $encodedTransformed = ''; + $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset; + + while ($thisMaxLineLength < strlen($encoded)) { + $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength) . "\r\n"; + $firstLineOffset = 0; + $encoded = substr($encoded, $thisMaxLineLength); + $thisMaxLineLength = $maxLineLength; + $remainder = 0; + } + + if (0 < $remainingLength = strlen($encoded)) { + $remainder += $remainingLength; + $encodedTransformed .= $encoded; + $encoded = null; + } + + $is->write($encodedTransformed); + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'base64'. + * + * @return string + */ + public function getName() + { + return 'base64'; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php new file mode 100644 index 00000000..f7dac216 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php @@ -0,0 +1,125 @@ +charset = $charset ? $charset : 'utf-8'; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + } + + /** + * Encode $in to $out. + * + * @param Swift_OutputByteStream $os to read from + * @param Swift_InputByteStream $is to write to + * @param integer $firstLineOffset + * @param integer $maxLineLength 0 indicates the default length for this encoding + * + * @throws RuntimeException + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + $string = ''; + + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + $is->write($this->encodeString($string)); + } + + /** + * Get the MIME name of this content encoding scheme. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param integer $firstLineOffset if first line needs to be shorter + * @param integer $maxLineLength 0 indicates the default length for this encoding + * + * @return string + * + * @throws RuntimeException + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->charset !== 'utf-8') { + throw new RuntimeException( + sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); + } + + return $this->_standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + * + * @param string $string + * + * @return string + */ + protected function _standardize($string) + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(?_name = $name; + $this->_canonical = $canonical; + } + + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param integer $firstLineOffset ignored + * @param integer $maxLineLength - 0 means no wrapping will occur + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($this->_canonical) { + $string = $this->_canonicalize($string); + } + + return $this->_safeWordWrap($string, $maxLineLength, "\r\n"); + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $os + * @param Swift_InputByteStream $is + * @param integer $firstLineOffset ignored + * @param integer $maxLineLength optional, 0 means no wrapping will occur + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $leftOver = ''; + while (false !== $bytes = $os->read(8192)) { + $toencode = $leftOver . $bytes; + if ($this->_canonical) { + $toencode = $this->_canonicalize($toencode); + } + $wrapped = $this->_safeWordWrap($toencode, $maxLineLength, "\r\n"); + $lastLinePos = strrpos($wrapped, "\r\n"); + $leftOver = substr($wrapped, $lastLinePos); + $wrapped = substr($wrapped, 0, $lastLinePos); + + $is->write($wrapped); + } + if (strlen($leftOver)) { + $is->write($leftOver); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } + + // -- Private methods + + /** + * A safer (but weaker) wordwrap for unicode. + * + * @param string $string + * @param integer $length + * @param string $le + * + * @return string + */ + private function _safeWordwrap($string, $length = 75, $le = "\r\n") + { + if (0 >= $length) { + return $string; + } + + $originalLines = explode($le, $string); + + $lines = array(); + $lineCount = 0; + + foreach ($originalLines as $originalLine) { + $lines[] = ''; + $currentLine =& $lines[$lineCount++]; + + //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine); + $chunks = preg_split('/(?<=\s)/', $originalLine); + + foreach ($chunks as $chunk) { + if (0 != strlen($currentLine) + && strlen($currentLine . $chunk) > $length) + { + $lines[] = ''; + $currentLine =& $lines[$lineCount++]; + } + $currentLine .= $chunk; + } + } + + return implode("\r\n", $lines); + } + + /** + * Canonicalize string input (fix CRLF). + * + * @param string $string + * + * @return string + */ + private function _canonicalize($string) + { + return str_replace( + array("\r\n", "\r", "\n"), + array("\n", "\n", "\r\n"), + $string + ); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php new file mode 100644 index 00000000..e3ee2026 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php @@ -0,0 +1,125 @@ +_dotEscape = $dotEscape; + parent::__construct($charStream, $filter); + } + + public function __sleep() + { + return array('_charStream', '_filter', '_dotEscape'); + } + + protected function getSafeMapShareId() + { + return get_class($this).($this->_dotEscape ? '.dotEscape' : ''); + } + + protected function initSafeMap() + { + parent::initSafeMap(); + if ($this->_dotEscape) { + /* Encode . as =2e for buggy remote servers */ + unset($this->_safeMap[0x2e]); + } + } + + /** + * Encode stream $in to stream $out. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + * + * @param Swift_OutputByteStream $os output stream + * @param Swift_InputByteStream $is input stream + * @param integer $firstLineOffset + * @param integer $maxLineLength + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $this->_charStream->flushContents(); + $this->_charStream->importByteStream($os); + + $currentLine = ''; + $prepend = ''; + $size=$lineLen=0; + + while (false !== $bytes = $this->_nextSequence()) { + // If we're filtering the input + if (isset($this->_filter)) { + // If we can't filter because we need more bytes + while ($this->_filter->shouldBuffer($bytes)) { + // Then collect bytes into the buffer + if (false === $moreBytes = $this->_nextSequence(1)) { + break; + } + + foreach ($moreBytes as $b) { + $bytes[] = $b; + } + } + // And filter them + $bytes = $this->_filter->filter($bytes); + } + + $enc = $this->_encodeByteSequence($bytes, $size); + if ($currentLine && $lineLen+$size >= $thisLineLength) { + $is->write($prepend . $this->_standardize($currentLine)); + $currentLine = ''; + $prepend = "=\r\n"; + $thisLineLength = $maxLineLength; + $lineLen=0; + } + $lineLen+=$size; + $currentLine .= $enc; + } + if (strlen($currentLine)) { + $is->write($prepend . $this->_standardize($currentLine)); + } + } + + /** + * Get the name of this encoding scheme. + * Returns the string 'quoted-printable'. + * + * @return string + */ + public function getName() + { + return 'quoted-printable'; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php new file mode 100644 index 00000000..491409ac --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php @@ -0,0 +1,90 @@ + + */ +class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder +{ + /** + * @var Swift_Mime_ContentEncoder_QpContentEncoder + */ + private $safeEncoder; + + /** + * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder + */ + private $nativeEncoder; + + /** + * @var null|string + */ + private $charset; + + /** + * Constructor. + * + * @param Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder + * @param Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder + * @param string|null $charset + */ + public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset) + { + $this->safeEncoder = $safeEncoder; + $this->nativeEncoder = $nativeEncoder; + $this->charset = $charset; + } + + /** + * {@inheritdoc} + */ + public function charsetChanged($charset) + { + $this->charset = $charset; + } + + /** + * {@inheritdoc} + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'quoted-printable'; + } + + /** + * {@inheritdoc} + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength); + } + + /** + * @return Swift_Mime_ContentEncoder + */ + private function getEncoder() + { + return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php new file mode 100644 index 00000000..8f1f9b57 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php @@ -0,0 +1,65 @@ + + */ +class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder +{ + /** + * Encode a given string to produce an encoded string. + * + * @param string $string + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return $string; + } + + /** + * Encode stream $in to stream $out. + * + * @param Swift_OutputByteStream $in + * @param Swift_InputByteStream $out + * @param int $firstLineOffset ignored + * @param int $maxLineLength ignored + */ + public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0) + { + while (false !== ($bytes = $os->read(8192))) { + $is->write($bytes); + } + } + + /** + * Get the name of this encoding scheme. + * + * @return string + */ + public function getName() + { + return 'raw'; + } + + /** + * Not used. + */ + public function charsetChanged($charset) + { + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php b/public/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php new file mode 100644 index 00000000..05e06e21 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/EmbeddedFile.php @@ -0,0 +1,47 @@ +setDisposition('inline'); + $this->setId($this->getId()); + } + + /** + * Get the nesting level of this EmbeddedFile. + * + * Returns {@see LEVEL_RELATED}. + * + * @return integer + */ + public function getNestingLevel() + { + return self::LEVEL_RELATED; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php b/public/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php new file mode 100644 index 00000000..e7e6f20d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/EncodingObserver.php @@ -0,0 +1,26 @@ +init(); + } + + public function __wakeup() + { + $this->init(); + } + + protected function init() + { + if (count(self::$_specials) > 0) { + return; + } + + self::$_specials = array( + '(', ')', '<', '>', '[', ']', + ':', ';', '@', ',', '.', '"' + ); + + /*** Refer to RFC 2822 for ABNF grammar ***/ + + // All basic building blocks + self::$_grammar['NO-WS-CTL'] = '[\x01-\x08\x0B\x0C\x0E-\x19\x7F]'; + self::$_grammar['WSP'] = '[ \t]'; + self::$_grammar['CRLF'] = '(?:\r\n)'; + self::$_grammar['FWS'] = '(?:(?:' . self::$_grammar['WSP'] . '*' . + self::$_grammar['CRLF'] . ')?' . self::$_grammar['WSP'] . ')'; + self::$_grammar['text'] = '[\x00-\x08\x0B\x0C\x0E-\x7F]'; + self::$_grammar['quoted-pair'] = '(?:\\\\' . self::$_grammar['text'] . ')'; + self::$_grammar['ctext'] = '(?:' . self::$_grammar['NO-WS-CTL'] . + '|[\x21-\x27\x2A-\x5B\x5D-\x7E])'; + // Uses recursive PCRE (?1) -- could be a weak point?? + self::$_grammar['ccontent'] = '(?:' . self::$_grammar['ctext'] . '|' . + self::$_grammar['quoted-pair'] . '|(?1))'; + self::$_grammar['comment'] = '(\((?:' . self::$_grammar['FWS'] . '|' . + self::$_grammar['ccontent']. ')*' . self::$_grammar['FWS'] . '?\))'; + self::$_grammar['CFWS'] = '(?:(?:' . self::$_grammar['FWS'] . '?' . + self::$_grammar['comment'] . ')*(?:(?:' . self::$_grammar['FWS'] . '?' . + self::$_grammar['comment'] . ')|' . self::$_grammar['FWS'] . '))'; + self::$_grammar['qtext'] = '(?:' . self::$_grammar['NO-WS-CTL'] . + '|[\x21\x23-\x5B\x5D-\x7E])'; + self::$_grammar['qcontent'] = '(?:' . self::$_grammar['qtext'] . '|' . + self::$_grammar['quoted-pair'] . ')'; + self::$_grammar['quoted-string'] = '(?:' . self::$_grammar['CFWS'] . '?"' . + '(' . self::$_grammar['FWS'] . '?' . self::$_grammar['qcontent'] . ')*' . + self::$_grammar['FWS'] . '?"' . self::$_grammar['CFWS'] . '?)'; + self::$_grammar['atext'] = '[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]'; + self::$_grammar['atom'] = '(?:' . self::$_grammar['CFWS'] . '?' . + self::$_grammar['atext'] . '+' . self::$_grammar['CFWS'] . '?)'; + self::$_grammar['dot-atom-text'] = '(?:' . self::$_grammar['atext'] . '+' . + '(\.' . self::$_grammar['atext'] . '+)*)'; + self::$_grammar['dot-atom'] = '(?:' . self::$_grammar['CFWS'] . '?' . + self::$_grammar['dot-atom-text'] . '+' . self::$_grammar['CFWS'] . '?)'; + self::$_grammar['word'] = '(?:' . self::$_grammar['atom'] . '|' . + self::$_grammar['quoted-string'] . ')'; + self::$_grammar['phrase'] = '(?:' . self::$_grammar['word'] . '+?)'; + self::$_grammar['no-fold-quote'] = '(?:"(?:' . self::$_grammar['qtext'] . + '|' . self::$_grammar['quoted-pair'] . ')*")'; + self::$_grammar['dtext'] = '(?:' . self::$_grammar['NO-WS-CTL'] . + '|[\x21-\x5A\x5E-\x7E])'; + self::$_grammar['no-fold-literal'] = '(?:\[(?:' . self::$_grammar['dtext'] . + '|' . self::$_grammar['quoted-pair'] . ')*\])'; + + // Message IDs + self::$_grammar['id-left'] = '(?:' . self::$_grammar['dot-atom-text'] . '|' . + self::$_grammar['no-fold-quote'] . ')'; + self::$_grammar['id-right'] = '(?:' . self::$_grammar['dot-atom-text'] . '|' . + self::$_grammar['no-fold-literal'] . ')'; + + // Addresses, mailboxes and paths + self::$_grammar['local-part'] = '(?:' . self::$_grammar['dot-atom'] . '|' . + self::$_grammar['quoted-string'] . ')'; + self::$_grammar['dcontent'] = '(?:' . self::$_grammar['dtext'] . '|' . + self::$_grammar['quoted-pair'] . ')'; + self::$_grammar['domain-literal'] = '(?:' . self::$_grammar['CFWS'] . '?\[(' . + self::$_grammar['FWS'] . '?' . self::$_grammar['dcontent'] . ')*?' . + self::$_grammar['FWS'] . '?\]' . self::$_grammar['CFWS'] . '?)'; + self::$_grammar['domain'] = '(?:' . self::$_grammar['dot-atom'] . '|' . + self::$_grammar['domain-literal'] . ')'; + self::$_grammar['addr-spec'] = '(?:' . self::$_grammar['local-part'] . '@' . + self::$_grammar['domain'] . ')'; + } + + /** + * Get the grammar defined for $name token. + * + * @param string $name exactly as written in the RFC + * + * @return string + */ + public function getDefinition($name) + { + if (array_key_exists($name, self::$_grammar)) { + return self::$_grammar[$name]; + } else { + throw new Swift_RfcComplianceException( + "No such grammar '" . $name . "' defined." + ); + } + } + + /** + * Returns the tokens defined in RFC 2822 (and some related RFCs). + * + * @return array + */ + public function getGrammarDefinitions() + { + return self::$_grammar; + } + + /** + * Returns the current special characters used in the syntax which need to be escaped. + * + * @return array + */ + public function getSpecials() + { + return self::$_specials; + } + + /** + * Escape special characters in a string (convert to quoted-pairs). + * + * @param string $token + * @param string[] $include additional chars to escape + * @param string[] $exclude chars from escaping + * + * @return string + */ + public function escapeSpecials($token, $include = array(), $exclude = array()) + { + foreach (array_merge(array('\\'), array_diff(self::$_specials, $exclude), $include) as $char) { + $token = str_replace($char, '\\' . $char, $token); + } + + return $token; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Header.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Header.php new file mode 100644 index 00000000..55d3ab8a --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Header.php @@ -0,0 +1,95 @@ +getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $firstLineOffset, $maxLineLength); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php new file mode 100644 index 00000000..c9bbe710 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php @@ -0,0 +1,67 @@ +_safeMap[$byte] = chr($byte); + } + } + + /** + * Get the name of this encoding scheme. + * + * Returns the string 'Q'. + * + * @return string + */ + public function getName() + { + return 'Q'; + } + + /** + * Takes an unencoded string and produces a QP encoded string from it. + * + * @param string $string string to encode + * @param integer $firstLineOffset optional + * @param integer $maxLineLength optional, 0 indicates the default of 76 chars + * + * @return string + */ + public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) + { + return str_replace(array(' ', '=20', "=\r\n"), array('_', '_', "\r\n"), + parent::encodeString($string, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php b/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php new file mode 100644 index 00000000..7cab133c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/HeaderFactory.php @@ -0,0 +1,80 @@ +setGrammar($grammar); + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->clearCachedValueIf($charset != $this->_charset); + $this->_charset = $charset; + if (isset($this->_encoder)) { + $this->_encoder->charsetChanged($charset); + } + } + + /** + * Get the character set used in this Header. + * + * @return string + */ + public function getCharset() + { + return $this->_charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + * This can be unspecified. + * + * @param string $lang + */ + public function setLanguage($lang) + { + $this->clearCachedValueIf($this->_lang != $lang); + $this->_lang = $lang; + } + + /** + * Get the language used in this Header. + * + * @return string + */ + public function getLanguage() + { + return $this->_lang; + } + + /** + * Set the encoder used for encoding the header. + * + * @param Swift_Mime_HeaderEncoder $encoder + */ + public function setEncoder(Swift_Mime_HeaderEncoder $encoder) + { + $this->_encoder = $encoder; + $this->setCachedValue(null); + } + + /** + * Get the encoder used for encoding this Header. + * + * @return Swift_Mime_HeaderEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the grammar used for the header. + * + * @param Swift_Mime_Grammar $grammar + */ + public function setGrammar(Swift_Mime_Grammar $grammar) + { + $this->_grammar = $grammar; + $this->setCachedValue(null); + } + + /** + * Get the grammar used for this Header. + * + * @return Swift_Mime_Grammar + */ + public function getGrammar() + { + return $this->_grammar; + } + + /** + * Get the name of this header (e.g. charset). + * + * @return string + */ + public function getFieldName() + { + return $this->_name; + } + + /** + * Set the maximum length of lines in the header (excluding EOL). + * + * @param integer $lineLength + */ + public function setMaxLineLength($lineLength) + { + $this->clearCachedValueIf($this->_lineLength != $lineLength); + $this->_lineLength = $lineLength; + } + + /** + * Get the maximum permitted length of lines in this Header. + * + * @return int + */ + public function getMaxLineLength() + { + return $this->_lineLength; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @return string + * + * @throws Swift_RfcComplianceException + */ + public function toString() + { + return $this->_tokensToString($this->toTokens()); + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + // -- Points of extension + + /** + * Set the name of this Header field. + * + * @param string $name + */ + protected function setFieldName($name) + { + $this->_name = $name; + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param Swift_Mime_Header $header + * @param string $string as displayed + * @param string $charset of the text + * @param Swift_Mime_HeaderEncoder $encoder + * @param boolean $shorten the first line to make remove for header name + * + * @return string + */ + protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) + { + // Treat token as exactly what was given + $phraseStr = $string; + // If it's not valid + if (!preg_match('/^' . $this->getGrammar()->getDefinition('phrase') . '$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^' . $this->getGrammar()->getDefinition('text') . '*$/D', $phraseStr)) { + $phraseStr = $this->getGrammar()->escapeSpecials( + $phraseStr, array('"'), $this->getGrammar()->getSpecials() + ); + $phraseStr = '"' . $phraseStr . '"'; + } else { // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = strlen($header->getFieldName() . ': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + * + * @param Swift_Mime_Header $header + * @param string $input + * @param string $usedLength optional + * + * @return string + */ + protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1) + { + $value = ''; + + $tokens = $this->getEncodableWordTokens($input); + + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = strlen($header->getFieldName() . ': ') + strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + + $header->setMaxLineLength(76); // Forcefully override + } else { + $value .= $token; + } + } + + return $value; + } + + /** + * Test if a token needs to be encoded or not. + * + * @param string $token + * + * @return boolean + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @param string $string + * + * @return string[] + */ + protected function getEncodableWordTokens($string) + { + $tokens = array(); + + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if (strlen($encodedToken) > 0) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if (strlen($encodedToken)) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + * + * @param string $token token to encode + * @param integer $firstLineOffset optional + * + * @return string + */ + protected function getTokenAsEncodedWord($token, $firstLineOffset = 0) + { + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->_charset; + if (isset($this->_lang)) { + $charsetDecl .= '*' . $this->_lang; + } + $encodingWrapperLength = strlen( + '=?' . $charsetDecl . '?' . $this->_encoder->getName() . '??=' + ); + + if ($firstLineOffset >= 75) { //Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + $this->_encoder->encodeString( + $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->_charset + ) + ); + + if (strtolower($this->_charset) !== 'iso-2022-jp') { // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?' . $charsetDecl . + '?' . $this->_encoder->getName() . + '?' . $line . '?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @param string $token + * + * @return string[] + */ + protected function generateTokenLines($token) + { + return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Set a value into the cache. + * + * @param string $value + */ + protected function setCachedValue($value) + { + $this->_cachedValue = $value; + } + + /** + * Get the value in the cache. + * + * @return string + */ + protected function getCachedValue() + { + return $this->_cachedValue; + } + + /** + * Clear the cached value if $condition is met. + * + * @param boolean $condition + */ + protected function clearCachedValueIf($condition) + { + if ($condition) { + $this->setCachedValue(null); + } + } + + // -- Private methods + + /** + * Generate a list of all tokens in the final header. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + if (is_null($string)) { + $string = $this->getFieldBody(); + } + + $tokens = array(); + + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + * + * @return string + */ + private function _tokensToString(array $tokens) + { + $lineCount = 0; + $headerLines = array(); + $headerLines[] = $this->_name . ': '; + $currentLine =& $headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" == $token) || + ($i > 0 && strlen($currentLine . $token) > $this->_lineLength) + && 0 < strlen($currentLine)) + { + $headerLines[] = ''; + $currentLine =& $headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" != $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines) . "\r\n"; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php new file mode 100644 index 00000000..9127cc22 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/DateHeader.php @@ -0,0 +1,127 @@ + + * + * + * + * @param string $name of Header + * @param Swift_Mime_Grammar $grammar + */ + public function __construct($name, Swift_Mime_Grammar $grammar) + { + $this->setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_DATE; + } + + /** + * Set the model for the field body. + * + * This method takes a UNIX timestamp. + * + * @param integer $model + */ + public function setFieldBodyModel($model) + { + $this->setTimestamp($model); + } + + /** + * Get the model for the field body. + * + * This method returns a UNIX timestamp. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getTimestamp(); + } + + /** + * Get the UNIX timestamp of the Date in this Header. + * + * @return int + */ + public function getTimestamp() + { + return $this->_timestamp; + } + + /** + * Set the UNIX timestamp of the Date in this Header. + * + * @param integer $timestamp + */ + public function setTimestamp($timestamp) + { + if (!is_null($timestamp)) { + $timestamp = (int) $timestamp; + } + $this->clearCachedValueIf($this->_timestamp != $timestamp); + $this->_timestamp = $timestamp; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_timestamp)) { + $this->setCachedValue(date('r', $this->_timestamp)); + } + } + + return $this->getCachedValue(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php new file mode 100644 index 00000000..1d00015e --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/IdentificationHeader.php @@ -0,0 +1,183 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_ID; + } + + /** + * Set the model for the field body. + * + * This method takes a string ID, or an array of IDs. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setId($model); + } + + /** + * Get the model for the field body. + * + * This method returns an array of IDs + * + * @return array + */ + public function getFieldBodyModel() + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws Swift_RfcComplianceException + */ + public function setId($id) + { + $this->setIds(is_array($id) ? $id : array($id)); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + * + * @return string + */ + public function getId() + { + if (count($this->_ids) > 0) { + return $this->_ids[0]; + } + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws Swift_RfcComplianceException + */ + public function setIds(array $ids) + { + $actualIds = array(); + + foreach ($ids as $id) { + $this->_assertValidId($id); + $actualIds[] = $id; + } + + $this->clearCachedValueIf($this->_ids != $actualIds); + $this->_ids = $actualIds; + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds() + { + return $this->_ids; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@see toString()} for that). + * + * @see toString() + * + * @return string + * + * @throws Swift_RfcComplianceException + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $angleAddrs = array(); + + foreach ($this->_ids as $id) { + $angleAddrs[] = '<' . $id . '>'; + } + + $this->setCachedValue(implode(' ', $angleAddrs)); + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match( + '/^' . $this->getGrammar()->getDefinition('id-left') . '@' . + $this->getGrammar()->getDefinition('id-right') . '$/D', + $id + )) + { + throw new Swift_RfcComplianceException( + 'Invalid ID given <' . $id . '>' + ); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php new file mode 100644 index 00000000..b8d08bd3 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/MailboxHeader.php @@ -0,0 +1,358 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_MAILBOX; + } + + /** + * Set the model for the field body. + * + * This method takes a string, or an array of addresses. + * + * @param mixed $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setNameAddresses($model); + } + + /** + * Get the model for the field body. + * + * This method returns an associative array like {@link getNameAddresses()} + * + * @return array + * + * @throws Swift_RfcComplianceException + */ + public function getFieldBodyModel() + { + return $this->getNameAddresses(); + } + + /** + * Set a list of mailboxes to be shown in this Header. + * + * The mailboxes can be a simple array of addresses, or an array of + * key=>value pairs where (email => personalName). + * Example: + * + * setNameAddresses(array( + * 'chris@swiftmailer.org' => 'Chris Corbyn', + * 'mark@swiftmailer.org' //No associated personal name + * )); + * ?> + * + * + * @see __construct() + * @see setAddresses() + * @see setValue() + * + * @param string|string[] $mailboxes + * + * @throws Swift_RfcComplianceException + */ + public function setNameAddresses($mailboxes) + { + $this->_mailboxes = $this->normalizeMailboxes((array) $mailboxes); + $this->setCachedValue(null); //Clear any cached value + } + + /** + * Get the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddressStrings()); + * // array ( + * // 0 => Chris Corbyn , + * // 1 => Mark Corbyn + * // ) + * ?> + * + * + * @see getNameAddresses() + * @see toString() + * + * @return string[] + * + * @throws Swift_RfcComplianceException + */ + public function getNameAddressStrings() + { + return $this->_createNameAddressStrings($this->getNameAddresses()); + } + + /** + * Get all mailboxes in this Header as key=>value pairs. + * + * The key is the address and the value is the name (or null if none set). + * Example: + * + * 'Chris Corbyn', + * 'mark@swiftmailer.org' => 'Mark Corbyn') + * ); + * print_r($header->getNameAddresses()); + * // array ( + * // chris@swiftmailer.org => Chris Corbyn, + * // mark@swiftmailer.org => Mark Corbyn + * // ) + * ?> + * + * + * @see getAddresses() + * @see getNameAddressStrings() + * + * @return string[] + */ + public function getNameAddresses() + { + return $this->_mailboxes; + } + + /** + * Makes this Header represent a list of plain email addresses with no names. + * + * Example: + * + * setAddresses( + * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld') + * ); + * ?> + * + * + * @see setNameAddresses() + * @see setValue() + * + * @param string[] $addresses + * + * @throws Swift_RfcComplianceException + */ + public function setAddresses($addresses) + { + $this->setNameAddresses(array_values((array) $addresses)); + } + + /** + * Get all email addresses in this Header. + * + * @see getNameAddresses() + * + * @return string[] + */ + public function getAddresses() + { + return array_keys($this->_mailboxes); + } + + /** + * Remove one or more addresses from this Header. + * + * @param string|string[] $addresses + */ + public function removeAddresses($addresses) + { + $this->setCachedValue(null); + foreach ((array) $addresses as $address) { + unset($this->_mailboxes[$address]); + } + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + * + * @throws Swift_RfcComplianceException + */ + public function getFieldBody() + { + // Compute the string value of the header only if needed + if (is_null($this->getCachedValue())) { + $this->setCachedValue($this->createMailboxListString($this->_mailboxes)); + } + + return $this->getCachedValue(); + } + + // -- Points of extension + + /** + * Normalizes a user-input list of mailboxes into consistent key=>value pairs. + * + * @param string[] $mailboxes + * + * @return string[] + */ + protected function normalizeMailboxes(array $mailboxes) + { + $actualMailboxes = array(); + + foreach ($mailboxes as $key => $value) { + if (is_string($key)) { //key is email addr + $address = $key; + $name = $value; + } else { + $address = $value; + $name = null; + } + $this->_assertValidAddress($address); + $actualMailboxes[$address] = $name; + } + + return $actualMailboxes; + } + + /** + * Produces a compliant, formatted display-name based on the string given. + * + * @param string $displayName as displayed + * @param boolean $shorten the first line to make remove for header name + * + * @return string + */ + protected function createDisplayNameString($displayName, $shorten = false) + { + return $this->createPhrase($this, $displayName, + $this->getCharset(), $this->getEncoder(), $shorten + ); + } + + /** + * Creates a string form of all the mailboxes in the passed array. + * + * @param string[] $mailboxes + * + * @return string + * + * @throws Swift_RfcComplianceException + */ + protected function createMailboxListString(array $mailboxes) + { + return implode(', ', $this->_createNameAddressStrings($mailboxes)); + } + + /** + * Redefine the encoding requirements for mailboxes. + * + * Commas and semicolons are used to separate + * multiple addresses, and should therefore be encoded + * + * @param string $token + * + * @return boolean + */ + protected function tokenNeedsEncoding($token) + { + return preg_match('/[,;]/', $token) || parent::tokenNeedsEncoding($token); + } + + // -- Private methods + + /** + * Return an array of strings conforming the the name-addr spec of RFC 2822. + * + * @param string[] $mailboxes + * + * @return string[] + */ + private function _createNameAddressStrings(array $mailboxes) + { + $strings = array(); + + foreach ($mailboxes as $email => $name) { + $mailboxStr = $email; + if (!is_null($name)) { + $nameStr = $this->createDisplayNameString($name, empty($strings)); + $mailboxStr = $nameStr . ' <' . $mailboxStr . '>'; + } + $strings[] = $mailboxStr; + } + + return $strings; + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If invalid. + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^' . $this->getGrammar()->getDefinition('addr-spec') . '$/D', + $address)) + { + throw new Swift_RfcComplianceException( + 'Address in mailbox given [' . $address . + '] does not comply with RFC 2822, 3.6.2.' + ); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php new file mode 100644 index 00000000..ecab7380 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/OpenDKIMHeader.php @@ -0,0 +1,139 @@ + + */ +class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header +{ + /** + * The value of this Header. + * + * @var string + */ + private $_value; + + /** + * The name of this Header + * @var string + */ + private $_fieldName; + + /** + * Creates a new SimpleHeader with $name. + * + * @param string $name + * @param Swift_Mime_HeaderEncoder $encoder + * @param Swift_Mime_Grammar $grammar + */ + public function __construct($name) + { + $this->_fieldName = $name; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + return $this->_value; + } + + /** + * Get this Header rendered as a RFC 2822 compliant string. + * + * @return string + */ + public function toString() + { + return $this->_fieldName.': '.$this->_value; + } + + /** + * Set the Header FieldName + * @see Swift_Mime_Header::getFieldName() + */ + public function getFieldName() + { + return $this->_fieldName; + } + + /** + * Ignored + */ + public function setCharset($charset) + { + + } + +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php new file mode 100644 index 00000000..0e4ac7d9 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/ParameterizedHeader.php @@ -0,0 +1,265 @@ +_paramEncoder = $paramEncoder; + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PARAMETERIZED; + } + + /** + * Set the character set used in this Header. + * + * @param string $charset + */ + public function setCharset($charset) + { + parent::setCharset($charset); + if (isset($this->_paramEncoder)) { + $this->_paramEncoder->charsetChanged($charset); + } + } + + /** + * Set the value of $parameter. + * + * @param string $parameter + * @param string $value + */ + public function setParameter($parameter, $value) + { + $this->setParameters(array_merge($this->getParameters(), array($parameter => $value))); + } + + /** + * Get the value of $parameter. + * + * @param string $parameter + * + * @return string + */ + public function getParameter($parameter) + { + $params = $this->getParameters(); + + return array_key_exists($parameter, $params) + ? $params[$parameter] + : null; + } + + /** + * Set an associative array of parameter names mapped to values. + * + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->clearCachedValueIf($this->_params != $parameters); + $this->_params = $parameters; + } + + /** + * Returns an associative array of parameter names mapped to values. + * + * @return string[] + */ + public function getParameters() + { + return $this->_params; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() //TODO: Check caching here + { + $body = parent::getFieldBody(); + foreach ($this->_params as $name => $value) { + if (!is_null($value)) { + // Add the parameter + $body .= '; ' . $this->_createParameter($name, $value); + } + } + + return $body; + } + + // -- Protected methods + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + * + * @param string $string The string to tokenize + * + * @return array An array of tokens as strings + */ + protected function toTokens($string = null) + { + $tokens = parent::toTokens(parent::getFieldBody()); + + // Try creating any parameters + foreach ($this->_params as $name => $value) { + if (!is_null($value)) { + // Add the semi-colon separator + $tokens[count($tokens)-1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines( + ' ' . $this->_createParameter($name, $value) + )); + } + } + + return $tokens; + } + + // -- Private methods + + /** + * Render a RFC 2047 compliant header parameter from the $name and $value. + * + * @param string $name + * @param string $value + * + * @return string + */ + private function _createParameter($name, $value) + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - strlen($name . '=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^' . self::TOKEN_REGEX . '$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^' . $this->getGrammar()->getDefinition('text') . '*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - strlen($name . '*N*="";') - 1; + $firstLineOffset = strlen( + $this->getCharset() . "'" . $this->getLanguage() . "'" + ); + } + } + + // Encode if we need to + if ($encoded || strlen($value) > $maxValueLength) { + if (isset($this->_paramEncoder)) { + $value = $this->_paramEncoder->encodeString( + $origValue, $firstLineOffset, $maxValueLength, $this->getCharset() + ); + } else { // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = isset($this->_paramEncoder) ? explode("\r\n", $value) : array($value); + + // Need to add indices + if (count($valueLines) > 1) { + $paramLines = array(); + foreach ($valueLines as $i => $line) { + $paramLines[] = $name . '*' . $i . + $this->_getEndOfParameterValue($line, true, $i == 0); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name . $this->_getEndOfParameterValue( + $valueLines[0], $encoded, true + ); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + * @param boolean $encoded + * @param boolean $firstLine + * + * @return string + */ + private function _getEndOfParameterValue($value, $encoded = false, $firstLine = false) + { + if (!preg_match('/^' . self::TOKEN_REGEX . '$/D', $value)) { + $value = '"' . $value . '"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*=' . $this->getCharset() . "'" . $this->getLanguage() . + "'"; + } + } + + return $prepend . $value; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php new file mode 100644 index 00000000..bfecf3f4 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/PathHeader.php @@ -0,0 +1,146 @@ +setFieldName($name); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_PATH; + } + + /** + * Set the model for the field body. + * This method takes a string for an address. + * + * @param string $model + * + * @throws Swift_RfcComplianceException + */ + public function setFieldBodyModel($model) + { + $this->setAddress($model); + } + + /** + * Get the model for the field body. + * This method returns a string email address. + * + * @return mixed + */ + public function getFieldBodyModel() + { + return $this->getAddress(); + } + + /** + * Set the Address which should appear in this Header. + * + * @param string $address + * + * @throws Swift_RfcComplianceException + */ + public function setAddress($address) + { + if (is_null($address)) { + $this->_address = null; + } elseif ('' == $address) { + $this->_address = ''; + } else { + $this->_assertValidAddress($address); + $this->_address = $address; + } + $this->setCachedValue(null); + } + + /** + * Get the address which is used in this Header (if any). + * + * Null is returned if no address is set. + * + * @return string + */ + public function getAddress() + { + return $this->_address; + } + + /** + * Get the string value of the body in this Header. + * + * This is not necessarily RFC 2822 compliant since folding white space will + * not be added at this stage (see {@link toString()} for that). + * + * @see toString() + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + if (isset($this->_address)) { + $this->setCachedValue('<' . $this->_address . '>'); + } + } + + return $this->getCachedValue(); + } + + /** + * Throws an Exception if the address passed does not comply with RFC 2822. + * + * @param string $address + * + * @throws Swift_RfcComplianceException If address is invalid + */ + private function _assertValidAddress($address) + { + if (!preg_match('/^' . $this->getGrammar()->getDefinition('addr-spec') . '$/D', + $address)) + { + throw new Swift_RfcComplianceException( + 'Address set in PathHeader does not comply with addr-spec of RFC 2822.' + ); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php new file mode 100644 index 00000000..2de49b4d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Headers/UnstructuredHeader.php @@ -0,0 +1,114 @@ +setFieldName($name); + $this->setEncoder($encoder); + parent::__construct($grammar); + } + + /** + * Get the type of Header that this instance represents. + * + * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX + * @see TYPE_DATE, TYPE_ID, TYPE_PATH + * + * @return int + */ + public function getFieldType() + { + return self::TYPE_TEXT; + } + + /** + * Set the model for the field body. + * + * This method takes a string for the field value. + * + * @param string $model + */ + public function setFieldBodyModel($model) + { + $this->setValue($model); + } + + /** + * Get the model for the field body. + * + * This method returns a string. + * + * @return string + */ + public function getFieldBodyModel() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + * + * @return string + */ + public function getValue() + { + return $this->_value; + } + + /** + * Set the (unencoded) value of this header. + * + * @param string $value + */ + public function setValue($value) + { + $this->clearCachedValueIf($this->_value != $value); + $this->_value = $value; + } + + /** + * Get the value of this header prepared for rendering. + * + * @return string + */ + public function getFieldBody() + { + if (!$this->getCachedValue()) { + $this->setCachedValue( + $this->encodeWords($this, $this->_value) + ); + } + + return $this->getCachedValue(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/Message.php b/public/include/lib/swiftmailer/classes/Swift/Mime/Message.php new file mode 100644 index 00000000..bce3af3c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/Message.php @@ -0,0 +1,225 @@ + 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $address + * @param string $name optional + */ + public function setSender($address, $name = null); + + /** + * Get the sender address for this message. + * + * This has a higher significance than the From address. + * + * @return string + */ + public function getSender(); + + /** + * Set the From address of this message. + * + * It is permissible for multiple From addresses to be set using an array. + * + * If multiple From addresses are used, you SHOULD set the Sender address and + * according to RFC 2822, MUST set the sender address. + * + * An array can be used if display names are to be provided: i.e. + * array('email@address.com' => 'Real Name'). + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setFrom($addresses, $name = null); + + /** + * Get the From address(es) of this message. + * + * This method always returns an associative array where the keys are the + * addresses. + * + * @return string[] + */ + public function getFrom(); + + /** + * Set the Reply-To address(es). + * + * Any replies from the receiver will be sent to this address. + * + * It is permissible for multiple reply-to addresses to be set using an array. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setReplyTo($addresses, $name = null); + + /** + * Get the Reply-To addresses for this message. + * + * This method always returns an associative array where the keys provide the + * email addresses. + * + * @return string[] + */ + public function getReplyTo(); + + /** + * Set the To address(es). + * + * Recipients set in this field will receive a copy of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setCc()}. + * + * If the second parameter is provided and the first is a string, then $name + * is associated with the address. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setTo($addresses, $name = null); + + /** + * Get the To addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getTo(); + + /** + * Set the Cc address(es). + * + * Recipients set in this field will receive a 'carbon-copy' of this message. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setCc($addresses, $name = null); + + /** + * Get the Cc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getCc(); + + /** + * Set the Bcc address(es). + * + * Recipients set in this field will receive a 'blind-carbon-copy' of this + * message. + * + * In other words, they will get the message, but any other recipients of the + * message will have no such knowledge of their receipt of it. + * + * This method has the same synopsis as {@link setFrom()} and {@link setTo()}. + * + * @param mixed $addresses + * @param string $name optional + */ + public function setBcc($addresses, $name = null); + + /** + * Get the Bcc addresses for this message. + * + * This method always returns an associative array, whereby the keys provide + * the actual email addresses. + * + * @return string[] + */ + public function getBcc(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php b/public/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php new file mode 100644 index 00000000..bc9f2ad3 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/MimeEntity.php @@ -0,0 +1,117 @@ +setContentType('text/plain'); + if (!is_null($charset)) { + $this->setCharset($charset); + } + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * @param string $charset optional + * + * @return Swift_Mime_MimePart + */ + public function setBody($body, $contentType = null, $charset = null) + { + if (isset($charset)) { + $this->setCharset($charset); + } + $body = $this->_convertString($body); + + parent::setBody($body, $contentType); + + return $this; + } + + /** + * Get the character set of this entity. + * + * @return string + */ + public function getCharset() + { + return $this->_getHeaderParameter('Content-Type', 'charset'); + } + + /** + * Set the character set of this entity. + * + * @param string $charset + * + * @return Swift_Mime_MimePart + */ + public function setCharset($charset) + { + $this->_setHeaderParameter('Content-Type', 'charset', $charset); + if ($charset !== $this->_userCharset) { + $this->_clearCache(); + } + $this->_userCharset = $charset; + parent::charsetChanged($charset); + + return $this; + } + + /** + * Get the format of this entity (i.e. flowed or fixed). + * + * @return string + */ + public function getFormat() + { + return $this->_getHeaderParameter('Content-Type', 'format'); + } + + /** + * Set the format of this entity (flowed or fixed). + * + * @param string $format + * + * @return Swift_Mime_MimePart + */ + public function setFormat($format) + { + $this->_setHeaderParameter('Content-Type', 'format', $format); + $this->_userFormat = $format; + + return $this; + } + + /** + * Test if delsp is being used for this entity. + * + * @return boolean + */ + public function getDelSp() + { + return ($this->_getHeaderParameter('Content-Type', 'delsp') == 'yes') + ? true + : false; + } + + /** + * Turn delsp on or off for this entity. + * + * @param boolean $delsp + * + * @return Swift_Mime_MimePart + */ + public function setDelSp($delsp = true) + { + $this->_setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null); + $this->_userDelSp = $delsp; + + return $this; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED + * + * @return int + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Receive notification that the charset has changed on this document, or a + * parent document. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + // -- Protected methods + + /** Fix the content-type and encoding of this entity */ + protected function _fixHeaders() + { + parent::_fixHeaders(); + if (count($this->getChildren())) { + $this->_setHeaderParameter('Content-Type', 'charset', null); + $this->_setHeaderParameter('Content-Type', 'format', null); + $this->_setHeaderParameter('Content-Type', 'delsp', null); + } else { + $this->setCharset($this->_userCharset); + $this->setFormat($this->_userFormat); + $this->setDelSp($this->_userDelSp); + } + } + + /** Set the nesting level of this entity */ + protected function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + /** Encode charset when charset is not utf-8 */ + protected function _convertString($string) + { + $charset = strtolower($this->getCharset()); + if (!in_array($charset, array('utf-8', 'iso-8859-1', ''))) { + // mb_convert_encoding must be the first one to check, since iconv cannot convert some words. + if (function_exists('mb_convert_encoding')) { + $string = mb_convert_encoding($string, $charset, 'utf-8'); + } elseif (function_exists('iconv')) { + $string = iconv($charset, 'utf-8//TRANSLIT//IGNORE', $string); + } else { + throw new Swift_SwiftException('No suitable convert encoding function (use UTF-8 as your charset or install the mbstring or iconv extension).'); + } + + return $string; + } + + return $string; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php b/public/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php new file mode 100644 index 00000000..95172ec4 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/ParameterizedHeader.php @@ -0,0 +1,36 @@ +_encoder = $encoder; + $this->_paramEncoder = $paramEncoder; + $this->_grammar = $grammar; + $this->_charset = $charset; + } + + /** + * Create a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string|null $addresses + * + * @return Swift_Mime_Header + */ + public function createMailboxHeader($name, $addresses = null) + { + $header = new Swift_Mime_Headers_MailboxHeader($name, $this->_encoder, $this->_grammar); + if (isset($addresses)) { + $header->setFieldBodyModel($addresses); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Date header using $timestamp (UNIX time). + * @param string $name + * @param integer|null $timestamp + * + * @return Swift_Mime_Header + */ + public function createDateHeader($name, $timestamp = null) + { + $header = new Swift_Mime_Headers_DateHeader($name, $this->_grammar); + if (isset($timestamp)) { + $header->setFieldBodyModel($timestamp); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + * + * @return Swift_Mime_Header + */ + public function createTextHeader($name, $value = null) + { + $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->_encoder, $this->_grammar); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + * + * @return Swift_Mime_ParameterizedHeader + */ + public function createParameterizedHeader($name, $value = null, + $params = array()) + { + $header = new Swift_Mime_Headers_ParameterizedHeader($name, + $this->_encoder, (strtolower($name) == 'content-disposition') + ? $this->_paramEncoder + : null, + $this->_grammar + ); + if (isset($value)) { + $header->setFieldBodyModel($value); + } + foreach ($params as $k => $v) { + $header->setParameter($k, $v); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + * + * @return Swift_Mime_Header + */ + public function createIdHeader($name, $ids = null) + { + $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->_grammar); + if (isset($ids)) { + $header->setFieldBodyModel($ids); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Create a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + * + * @return Swift_Mime_Header + */ + public function createPathHeader($name, $path = null) + { + $header = new Swift_Mime_Headers_PathHeader($name, $this->_grammar); + if (isset($path)) { + $header->setFieldBodyModel($path); + } + $this->_setHeaderCharset($header); + + return $header; + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_charset = $charset; + $this->_encoder->charsetChanged($charset); + $this->_paramEncoder->charsetChanged($charset); + } + + // -- Private methods + + /** Apply the charset to the Header */ + private function _setHeaderCharset(Swift_Mime_Header $header) + { + if (isset($this->_charset)) { + $header->setCharset($this->_charset); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php new file mode 100644 index 00000000..e06f9360 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleHeaderSet.php @@ -0,0 +1,387 @@ +_factory = $factory; + if (isset($charset)) { + $this->setCharset($charset); + } + } + + /** + * Set the charset used by these headers. + * + * @param string $charset + */ + public function setCharset($charset) + { + $this->_charset = $charset; + $this->_factory->charsetChanged($charset); + $this->_notifyHeadersOfCharset($charset); + } + + /** + * Add a new Mailbox Header with a list of $addresses. + * + * @param string $name + * @param array|string $addresses + */ + public function addMailboxHeader($name, $addresses = null) + { + $this->_storeHeader($name, + $this->_factory->createMailboxHeader($name, $addresses)); + } + + /** + * Add a new Date header using $timestamp (UNIX time). + * + * @param string $name + * @param integer $timestamp + */ + public function addDateHeader($name, $timestamp = null) + { + $this->_storeHeader($name, + $this->_factory->createDateHeader($name, $timestamp)); + } + + /** + * Add a new basic text header with $name and $value. + * + * @param string $name + * @param string $value + */ + public function addTextHeader($name, $value = null) + { + $this->_storeHeader($name, + $this->_factory->createTextHeader($name, $value)); + } + + /** + * Add a new ParameterizedHeader with $name, $value and $params. + * + * @param string $name + * @param string $value + * @param array $params + */ + public function addParameterizedHeader($name, $value = null, $params = array()) + { + $this->_storeHeader($name, $this->_factory->createParameterizedHeader($name, $value, $params)); + } + + /** + * Add a new ID header for Message-ID or Content-ID. + * + * @param string $name + * @param string|array $ids + */ + public function addIdHeader($name, $ids = null) + { + $this->_storeHeader($name, $this->_factory->createIdHeader($name, $ids)); + } + + /** + * Add a new Path header with an address (path) in it. + * + * @param string $name + * @param string $path + */ + public function addPathHeader($name, $path = null) + { + $this->_storeHeader($name, $this->_factory->createPathHeader($name, $path)); + } + + /** + * Returns true if at least one header with the given $name exists. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param integer $index + * + * @return boolean + */ + public function has($name, $index = 0) + { + $lowerName = strtolower($name); + + return array_key_exists($lowerName, $this->_headers) && array_key_exists($index, $this->_headers[$lowerName]); + } + + /** + * Set a header in the HeaderSet. + * + * The header may be a previously fetched header via {@link get()} or it may + * be one that has been created separately. + * + * If $index is specified, the header will be inserted into the set at this + * offset. + * + * @param Swift_Mime_Header $header + * @param integer $index + */ + public function set(Swift_Mime_Header $header, $index = 0) + { + $this->_storeHeader($header->getFieldName(), $header, $index); + } + + /** + * Get the header with the given $name. + * + * If multiple headers match, the actual one may be specified by $index. + * Returns NULL if none present. + * + * @param string $name + * @param integer $index + * + * @return Swift_Mime_Header + */ + public function get($name, $index = 0) + { + if ($this->has($name, $index)) { + $lowerName = strtolower($name); + + return $this->_headers[$lowerName][$index]; + } + } + + /** + * Get all headers with the given $name. + * + * @param string $name + * + * @return array + */ + public function getAll($name = null) + { + if (!isset($name)) { + $headers = array(); + foreach ($this->_headers as $collection) { + $headers = array_merge($headers, $collection); + } + + return $headers; + } + + $lowerName = strtolower($name); + if (!array_key_exists($lowerName, $this->_headers)) { + return array(); + } + + return $this->_headers[$lowerName]; + } + + /** + * Return the name of all Headers + * + * @return array + */ + public function listAll() + { + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + + return array_keys($headers); + } + + /** + * Remove the header with the given $name if it's set. + * + * If multiple headers match, the actual one may be specified by $index. + * + * @param string $name + * @param integer $index + */ + public function remove($name, $index = 0) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName][$index]); + } + + /** + * Remove all headers with the given $name. + * + * @param string $name + */ + public function removeAll($name) + { + $lowerName = strtolower($name); + unset($this->_headers[$lowerName]); + } + + /** + * Create a new instance of this HeaderSet. + * + * @return Swift_Mime_HeaderSet + */ + public function newInstance() + { + return new self($this->_factory); + } + + /** + * Define a list of Header names as an array in the correct order. + * + * These Headers will be output in the given order where present. + * + * @param array $sequence + */ + public function defineOrdering(array $sequence) + { + $this->_order = array_flip(array_map('strtolower', $sequence)); + } + + /** + * Set a list of header names which must always be displayed when set. + * + * Usually headers without a field value won't be output unless set here. + * + * @param array $names + */ + public function setAlwaysDisplayed(array $names) + { + $this->_required = array_flip(array_map('strtolower', $names)); + } + + /** + * Notify this observer that the entity's charset has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->setCharset($charset); + } + + /** + * Returns a string with a representation of all headers. + * + * @return string + */ + public function toString() + { + $string = ''; + $headers = $this->_headers; + if ($this->_canSort()) { + uksort($headers, array($this, '_sortHeaders')); + } + foreach ($headers as $collection) { + foreach ($collection as $header) { + if ($this->_isDisplayed($header) || $header->getFieldBody() != '') { + $string .= $header->toString(); + } + } + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @return string + * + * @see toString() + */ + public function __toString() + { + return $this->toString(); + } + + // -- Private methods + + /** Save a Header to the internal collection */ + private function _storeHeader($name, Swift_Mime_Header $header, $offset = null) + { + if (!isset($this->_headers[strtolower($name)])) { + $this->_headers[strtolower($name)] = array(); + } + if (!isset($offset)) { + $this->_headers[strtolower($name)][] = $header; + } else { + $this->_headers[strtolower($name)][$offset] = $header; + } + } + + /** Test if the headers can be sorted */ + private function _canSort() + { + return count($this->_order) > 0; + } + + /** uksort() algorithm for Header ordering */ + private function _sortHeaders($a, $b) + { + $lowerA = strtolower($a); + $lowerB = strtolower($b); + $aPos = array_key_exists($lowerA, $this->_order) + ? $this->_order[$lowerA] + : -1; + $bPos = array_key_exists($lowerB, $this->_order) + ? $this->_order[$lowerB] + : -1; + + if ($aPos == -1) { + return 1; + } elseif ($bPos == -1) { + return -1; + } + + return ($aPos < $bPos) ? -1 : 1; + } + + /** Test if the given Header is always displayed */ + private function _isDisplayed(Swift_Mime_Header $header) + { + return array_key_exists(strtolower($header->getFieldName()), $this->_required); + } + + /** Notify all Headers of the new charset */ + private function _notifyHeadersOfCharset($charset) + { + foreach ($this->_headers as $headerGroup) { + foreach ($headerGroup as $header) { + $header->setCharset($charset); + } + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php new file mode 100644 index 00000000..652f928c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMessage.php @@ -0,0 +1,656 @@ +getHeaders()->defineOrdering(array( + 'Return-Path', + 'Received', + 'DKIM-Signature', + 'DomainKey-Signature', + 'Sender', + 'Message-ID', + 'Date', + 'Subject', + 'From', + 'Reply-To', + 'To', + 'Cc', + 'Bcc', + 'MIME-Version', + 'Content-Type', + 'Content-Transfer-Encoding' + )); + $this->getHeaders()->setAlwaysDisplayed(array('Date', 'Message-ID', 'From')); + $this->getHeaders()->addTextHeader('MIME-Version', '1.0'); + $this->setDate(time()); + $this->setId($this->getId()); + $this->getHeaders()->addMailboxHeader('From'); + } + + /** + * Always returns {@link LEVEL_TOP} for a message instance. + * + * @return int + */ + public function getNestingLevel() + { + return self::LEVEL_TOP; + } + + /** + * Set the subject of this message. + * + * @param string $subject + * + * @return Swift_Mime_SimpleMessage + */ + public function setSubject($subject) + { + if (!$this->_setHeaderFieldModel('Subject', $subject)) { + $this->getHeaders()->addTextHeader('Subject', $subject); + } + + return $this; + } + + /** + * Get the subject of this message. + * + * @return string + */ + public function getSubject() + { + return $this->_getHeaderFieldModel('Subject'); + } + + /** + * Set the date at which this message was created. + * + * @param integer $date + * + * @return Swift_Mime_SimpleMessage + */ + public function setDate($date) + { + if (!$this->_setHeaderFieldModel('Date', $date)) { + $this->getHeaders()->addDateHeader('Date', $date); + } + + return $this; + } + + /** + * Get the date at which this message was created. + * + * @return integer + */ + public function getDate() + { + return $this->_getHeaderFieldModel('Date'); + } + + /** + * Set the return-path (the bounce address) of this message. + * + * @param string $address + * + * @return Swift_Mime_SimpleMessage + */ + public function setReturnPath($address) + { + if (!$this->_setHeaderFieldModel('Return-Path', $address)) { + $this->getHeaders()->addPathHeader('Return-Path', $address); + } + + return $this; + } + + /** + * Get the return-path (bounce address) of this message. + * + * @return string + */ + public function getReturnPath() + { + return $this->_getHeaderFieldModel('Return-Path'); + } + + /** + * Set the sender of this message. + * + * This does not override the From field, but it has a higher significance. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setSender($address, $name = null) + { + if (!is_array($address) && isset($name)) { + $address = array($address => $name); + } + + if (!$this->_setHeaderFieldModel('Sender', (array) $address)) { + $this->getHeaders()->addMailboxHeader('Sender', (array) $address); + } + + return $this; + } + + /** + * Get the sender of this message. + * + * @return string + */ + public function getSender() + { + return $this->_getHeaderFieldModel('Sender'); + } + + /** + * Add a From: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addFrom($address, $name = null) + { + $current = $this->getFrom(); + $current[$address] = $name; + + return $this->setFrom($current); + } + + /** + * Set the from address of this message. + * + * You may pass an array of addresses if this message is from multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param string $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setFrom($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('From', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('From', (array) $addresses); + } + + return $this; + } + + /** + * Get the from address of this message. + * + * @return string + */ + public function getFrom() + { + return $this->_getHeaderFieldModel('From'); + } + + /** + * Add a Reply-To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addReplyTo($address, $name = null) + { + $current = $this->getReplyTo(); + $current[$address] = $name; + + return $this->setReplyTo($current); + } + + /** + * Set the reply-to address of this message. + * + * You may pass an array of addresses if replies will go to multiple people. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param string $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setReplyTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Reply-To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses); + } + + return $this; + } + + /** + * Get the reply-to address of this message. + * + * @return string + */ + public function getReplyTo() + { + return $this->_getHeaderFieldModel('Reply-To'); + } + + /** + * Add a To: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addTo($address, $name = null) + { + $current = $this->getTo(); + $current[$address] = $name; + + return $this->setTo($current); + } + + /** + * Set the to addresses of this message. + * + * If multiple recipients will receive the message an array should be used. + * Example: array('receiver@domain.org', 'other@domain.org' => 'A name') + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setTo($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('To', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('To', (array) $addresses); + } + + return $this; + } + + /** + * Get the To addresses of this message. + * + * @return array + */ + public function getTo() + { + return $this->_getHeaderFieldModel('To'); + } + + /** + * Add a Cc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addCc($address, $name = null) + { + $current = $this->getCc(); + $current[$address] = $name; + + return $this->setCc($current); + } + + /** + * Set the Cc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setCc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Cc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Cc address of this message. + * + * @return array + */ + public function getCc() + { + return $this->_getHeaderFieldModel('Cc'); + } + + /** + * Add a Bcc: address to this message. + * + * If $name is passed this name will be associated with the address. + * + * @param string $address + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function addBcc($address, $name = null) + { + $current = $this->getBcc(); + $current[$address] = $name; + + return $this->setBcc($current); + } + + /** + * Set the Bcc addresses of this message. + * + * If $name is passed and the first parameter is a string, this name will be + * associated with the address. + * + * @param mixed $addresses + * @param string $name optional + * + * @return Swift_Mime_SimpleMessage + */ + public function setBcc($addresses, $name = null) + { + if (!is_array($addresses) && isset($name)) { + $addresses = array($addresses => $name); + } + + if (!$this->_setHeaderFieldModel('Bcc', (array) $addresses)) { + $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses); + } + + return $this; + } + + /** + * Get the Bcc addresses of this message. + * + * @return array + */ + public function getBcc() + { + return $this->_getHeaderFieldModel('Bcc'); + } + + /** + * Set the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @param integer $priority + * + * @return Swift_Mime_SimpleMessage + */ + public function setPriority($priority) + { + $priorityMap = array( + 1 => 'Highest', + 2 => 'High', + 3 => 'Normal', + 4 => 'Low', + 5 => 'Lowest' + ); + $pMapKeys = array_keys($priorityMap); + if ($priority > max($pMapKeys)) { + $priority = max($pMapKeys); + } elseif ($priority < min($pMapKeys)) { + $priority = min($pMapKeys); + } + if (!$this->_setHeaderFieldModel('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority]))) + { + $this->getHeaders()->addTextHeader('X-Priority', + sprintf('%d (%s)', $priority, $priorityMap[$priority])); + } + + return $this; + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + * + * @return integer + */ + public function getPriority() + { + list($priority) = sscanf($this->_getHeaderFieldModel('X-Priority'), + '%[1-5]' + ); + + return isset($priority) ? $priority : 3; + } + + /** + * Ask for a delivery receipt from the recipient to be sent to $addresses + * + * @param array $addresses + * + * @return Swift_Mime_SimpleMessage + */ + public function setReadReceiptTo($addresses) + { + if (!$this->_setHeaderFieldModel('Disposition-Notification-To', $addresses)) { + $this->getHeaders() + ->addMailboxHeader('Disposition-Notification-To', $addresses); + } + + return $this; + } + + /** + * Get the addresses to which a read-receipt will be sent. + * + * @return string + */ + public function getReadReceiptTo() + { + return $this->_getHeaderFieldModel('Disposition-Notification-To'); + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} such as an Attachment or MimePart. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return Swift_Mime_SimpleMessage + */ + public function attach(Swift_Mime_MimeEntity $entity) + { + $this->setChildren(array_merge($this->getChildren(), array($entity))); + + return $this; + } + + /** + * Remove an already attached entity. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return Swift_Mime_SimpleMessage + */ + public function detach(Swift_Mime_MimeEntity $entity) + { + $newChildren = array(); + foreach ($this->getChildren() as $child) { + if ($entity !== $child) { + $newChildren[] = $child; + } + } + $this->setChildren($newChildren); + + return $this; + } + + /** + * Attach a {@link Swift_Mime_MimeEntity} and return it's CID source. + * This method should be used when embedding images or other data in a message. + * + * @param Swift_Mime_MimeEntity $entity + * + * @return string + */ + public function embed(Swift_Mime_MimeEntity $entity) + { + $this->attach($entity); + + return 'cid:' . $entity->getId(); + } + + /** + * Get this message as a complete string. + * + * @return string + */ + public function toString() + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + $string = parent::toString(); + $this->setChildren($children); + } else { + $string = parent::toString(); + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this message to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream $is + */ + public function toByteStream(Swift_InputByteStream $is) + { + if (count($children = $this->getChildren()) > 0 && $this->getBody() != '') { + $this->setChildren(array_merge(array($this->_becomeMimePart()), $children)); + parent::toByteStream($is); + $this->setChildren($children); + } else { + parent::toByteStream($is); + } + } + + // -- Protected methods + + /** @see Swift_Mime_SimpleMimeEntity::_getIdField() */ + protected function _getIdField() + { + return 'Message-ID'; + } + + /** Turn the body of this message into a child of itself if needed */ + protected function _becomeMimePart() + { + $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(), + $this->_getCache(), $this->_getGrammar(), $this->_userCharset + ); + $part->setContentType($this->_userContentType); + $part->setBody($this->getBody()); + $part->setFormat($this->_userFormat); + $part->setDelSp($this->_userDelSp); + $part->_setNestingLevel($this->_getTopNestingLevel()); + + return $part; + } + + // -- Private methods + + /** Get the highest nesting level nested inside this message */ + private function _getTopNestingLevel() + { + $highestLevel = $this->getNestingLevel(); + foreach ($this->getChildren() as $child) { + $childLevel = $child->getNestingLevel(); + if ($highestLevel < $childLevel) { + $highestLevel = $childLevel; + } + } + + return $highestLevel; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php new file mode 100644 index 00000000..96ac34b1 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Mime/SimpleMimeEntity.php @@ -0,0 +1,859 @@ + array(self::LEVEL_TOP, self::LEVEL_MIXED), + 'multipart/alternative' => array(self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE), + 'multipart/related' => array(self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED) + ); + + /** A set of filter rules to define what level an entity should be nested at */ + private $_compoundLevelFilters = array(); + + /** The nesting level of this entity */ + private $_nestingLevel = self::LEVEL_ALTERNATIVE; + + /** A KeyCache instance used during encoding and streaming */ + private $_cache; + + /** Direct descendants of this entity */ + private $_immediateChildren = array(); + + /** All descendants of this entity */ + private $_children = array(); + + /** The maximum line length of the body of this entity */ + private $_maxLineLength = 78; + + /** The order in which alternative mime types should appear */ + private $_alternativePartOrder = array( + 'text/plain' => 1, + 'text/html' => 2, + 'multipart/related' => 3 + ); + + /** The CID of this entity */ + private $_id; + + /** The key used for accessing the cache */ + private $_cacheKey; + + protected $_userContentType; + + /** + * Create a new SimpleMimeEntity with $headers, $encoder and $cache. + * + * @param Swift_Mime_HeaderSet $headers + * @param Swift_Mime_ContentEncoder $encoder + * @param Swift_KeyCache $cache + * @param Swift_Mime_Grammar $grammar + */ + public function __construct(Swift_Mime_HeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_Mime_Grammar $grammar) + { + $this->_cacheKey = md5(uniqid(getmypid().mt_rand(), true)); + $this->_cache = $cache; + $this->_headers = $headers; + $this->_grammar = $grammar; + $this->setEncoder($encoder); + $this->_headers->defineOrdering(array('Content-Type', 'Content-Transfer-Encoding')); + + // This array specifies that, when the entire MIME document contains + // $compoundLevel, then for each child within $level, if its Content-Type + // is $contentType then it should be treated as if it's level is + // $neededLevel instead. I tried to write that unambiguously! :-\ + // Data Structure: + // array ( + // $compoundLevel => array( + // $level => array( + // $contentType => $neededLevel + // ) + // ) + // ) + + $this->_compoundLevelFilters = array( + (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => array( + self::LEVEL_ALTERNATIVE => array( + 'text/plain' => self::LEVEL_ALTERNATIVE, + 'text/html' => self::LEVEL_RELATED + ) + ) + ); + + $this->_id = $this->getRandomId(); + } + + /** + * Generate a new Content-ID or Message-ID for this MIME entity. + * + * @return string + */ + public function generateId() + { + $this->setId($this->getRandomId()); + + return $this->_id; + } + + /** + * Get the {@link Swift_Mime_HeaderSet} for this entity. + * + * @return Swift_Mime_HeaderSet + */ + public function getHeaders() + { + return $this->_headers; + } + + /** + * Get the nesting level of this entity. + * + * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE + * + * @return integer + */ + public function getNestingLevel() + { + return $this->_nestingLevel; + } + + /** + * Get the Content-type of this entity. + * + * @return string + */ + public function getContentType() + { + return $this->_getHeaderFieldModel('Content-Type'); + } + + /** + * Set the Content-type of this entity. + * + * @param string $type + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setContentType($type) + { + $this->_setContentTypeInHeaders($type); + // Keep track of the value so that if the content-type changes automatically + // due to added child entities, it can be restored if they are later removed + $this->_userContentType = $type; + + return $this; + } + + /** + * Get the CID of this entity. + * + * The CID will only be present in headers if a Content-ID header is present. + * + * @return string + */ + public function getId() + { + $tmp = (array) $this->_getHeaderFieldModel($this->_getIdField()); + + return $this->_headers->has($this->_getIdField()) ? current($tmp) : $this->_id; + } + + /** + * Set the CID of this entity. + * + * @param string $id + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setId($id) + { + if (!$this->_setHeaderFieldModel($this->_getIdField(), $id)) { + $this->_headers->addIdHeader($this->_getIdField(), $id); + } + $this->_id = $id; + + return $this; + } + + /** + * Get the description of this entity. + * + * This value comes from the Content-Description header if set. + * + * @return string + */ + public function getDescription() + { + return $this->_getHeaderFieldModel('Content-Description'); + } + + /** + * Set the description of this entity. + * + * This method sets a value in the Content-ID header. + * + * @param string $description + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setDescription($description) + { + if (!$this->_setHeaderFieldModel('Content-Description', $description)) { + $this->_headers->addTextHeader('Content-Description', $description); + } + + return $this; + } + + /** + * Get the maximum line length of the body of this entity. + * + * @return integer + */ + public function getMaxLineLength() + { + return $this->_maxLineLength; + } + + /** + * Set the maximum line length of lines in this body. + * + * Though not enforced by the library, lines should not exceed 1000 chars. + * + * @param integer $length + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setMaxLineLength($length) + { + $this->_maxLineLength = $length; + + return $this; + } + + /** + * Get all children added to this entity. + * + * @return array of Swift_Mime_Entity + */ + public function getChildren() + { + return $this->_children; + } + + /** + * Set all children of this entity. + * + * @param array $children Swift_Mime_Entity instances + * @param integer $compoundLevel For internal use only + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setChildren(array $children, $compoundLevel = null) + { + // TODO: Try to refactor this logic + + $compoundLevel = isset($compoundLevel) + ? $compoundLevel + : $this->_getCompoundLevel($children) + ; + + $immediateChildren = array(); + $grandchildren = array(); + $newContentType = $this->_userContentType; + + foreach ($children as $child) { + $level = $this->_getNeededChildLevel($child, $compoundLevel); + if (empty($immediateChildren)) { //first iteration + $immediateChildren = array($child); + } else { + $nextLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + if ($nextLevel == $level) { + $immediateChildren[] = $child; + } elseif ($level < $nextLevel) { + // Re-assign immediateChildren to grandchildren + $grandchildren = array_merge($grandchildren, $immediateChildren); + // Set new children + $immediateChildren = array($child); + } else { + $grandchildren[] = $child; + } + } + } + + if (!empty($immediateChildren)) { + $lowestLevel = $this->_getNeededChildLevel($immediateChildren[0], $compoundLevel); + + // Determine which composite media type is needed to accommodate the + // immediate children + foreach ($this->_compositeRanges as $mediaType => $range) { + if ($lowestLevel > $range[0] + && $lowestLevel <= $range[1]) + { + $newContentType = $mediaType; + break; + } + } + + // Put any grandchildren in a subpart + if (!empty($grandchildren)) { + $subentity = $this->_createChild(); + $subentity->_setNestingLevel($lowestLevel); + $subentity->setChildren($grandchildren, $compoundLevel); + array_unshift($immediateChildren, $subentity); + } + } + + $this->_immediateChildren = $immediateChildren; + $this->_children = $children; + $this->_setContentTypeInHeaders($newContentType); + $this->_fixHeaders(); + $this->_sortChildren(); + + return $this; + } + + /** + * Get the body of this entity as a string. + * + * @return string + */ + public function getBody() + { + return ($this->_body instanceof Swift_OutputByteStream) + ? $this->_readStream($this->_body) + : $this->_body; + } + + /** + * Set the body of this entity, either as a string, or as an instance of + * {@link Swift_OutputByteStream}. + * + * @param mixed $body + * @param string $contentType optional + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setBody($body, $contentType = null) + { + if ($body !== $this->_body) { + $this->_clearCache(); + } + + $this->_body = $body; + if (isset($contentType)) { + $this->setContentType($contentType); + } + + return $this; + } + + /** + * Get the encoder used for the body of this entity. + * + * @return Swift_Mime_ContentEncoder + */ + public function getEncoder() + { + return $this->_encoder; + } + + /** + * Set the encoder used for the body of this entity. + * + * @param Swift_Mime_ContentEncoder $encoder + * + * @return Swift_Mime_SimpleMimeEntity + */ + public function setEncoder(Swift_Mime_ContentEncoder $encoder) + { + if ($encoder !== $this->_encoder) { + $this->_clearCache(); + } + + $this->_encoder = $encoder; + $this->_setEncoding($encoder->getName()); + $this->_notifyEncoderChanged($encoder); + + return $this; + } + + /** + * Get the boundary used to separate children in this entity. + * + * @return string + */ + public function getBoundary() + { + if (!isset($this->_boundary)) { + $this->_boundary = '_=_swift_v4_' . time() . '_' . md5(getmypid().mt_rand().uniqid('', true)) . '_=_'; + } + + return $this->_boundary; + } + + /** + * Set the boundary used to separate children in this entity. + * + * @param string $boundary + * + * @return Swift_Mime_SimpleMimeEntity + * + * @throws Swift_RfcComplianceException + */ + public function setBoundary($boundary) + { + $this->_assertValidBoundary($boundary); + $this->_boundary = $boundary; + + return $this; + } + + /** + * Receive notification that the charset of this entity, or a parent entity + * has changed. + * + * @param string $charset + */ + public function charsetChanged($charset) + { + $this->_notifyCharsetChanged($charset); + } + + /** + * Receive notification that the encoder of this entity or a parent entity + * has changed. + * + * @param Swift_Mime_ContentEncoder $encoder + */ + public function encoderChanged(Swift_Mime_ContentEncoder $encoder) + { + $this->_notifyEncoderChanged($encoder); + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + public function toString() + { + $string = $this->_headers->toString(); + $string .= $this->_bodyToString(); + + return $string; + } + + /** + * Get this entire entity as a string. + * + * @return string + */ + protected function _bodyToString() + { + $string = ''; + + if (isset($this->_body) && empty($this->_immediateChildren)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $body = $this->_cache->getString($this->_cacheKey, 'body'); + } else { + $body = "\r\n" . $this->_encoder->encodeString($this->getBody(), 0, + $this->getMaxLineLength() + ); + $this->_cache->setString($this->_cacheKey, 'body', $body, + Swift_KeyCache::MODE_WRITE + ); + } + $string .= $body; + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $string .= "\r\n\r\n--" . $this->getBoundary() . "\r\n"; + $string .= $child->toString(); + } + $string .= "\r\n\r\n--" . $this->getBoundary() . "--\r\n"; + } + + return $string; + } + + /** + * Returns a string representation of this object. + * + * @see toString() + * + * @return string + */ + public function __toString() + { + return $this->toString(); + } + + /** + * Write this entire entity to a {@see Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + public function toByteStream(Swift_InputByteStream $is) + { + $is->write($this->_headers->toString()); + $is->commit(); + + $this->_bodyToByteStream($is); + } + + /** + * Write this entire entity to a {@link Swift_InputByteStream}. + * + * @param Swift_InputByteStream + */ + protected function _bodyToByteStream(Swift_InputByteStream $is) + { + if (empty($this->_immediateChildren)) { + if (isset($this->_body)) { + if ($this->_cache->hasKey($this->_cacheKey, 'body')) { + $this->_cache->exportToByteStream($this->_cacheKey, 'body', $is); + } else { + $cacheIs = $this->_cache->getInputByteStream($this->_cacheKey, 'body'); + if ($cacheIs) { + $is->bind($cacheIs); + } + + $is->write("\r\n"); + + if ($this->_body instanceof Swift_OutputByteStream) { + $this->_body->setReadPointer(0); + + $this->_encoder->encodeByteStream($this->_body, $is, 0, $this->getMaxLineLength()); + } else { + $is->write($this->_encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength())); + } + + if ($cacheIs) { + $is->unbind($cacheIs); + } + } + } + } + + if (!empty($this->_immediateChildren)) { + foreach ($this->_immediateChildren as $child) { + $is->write("\r\n\r\n--" . $this->getBoundary() . "\r\n"); + $child->toByteStream($is); + } + $is->write("\r\n\r\n--" . $this->getBoundary() . "--\r\n"); + } + } + + // -- Protected methods + + /** + * Get the name of the header that provides the ID of this entity + */ + protected function _getIdField() + { + return 'Content-ID'; + } + + /** + * Get the model data (usually an array or a string) for $field. + */ + protected function _getHeaderFieldModel($field) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getFieldBodyModel(); + } + } + + /** + * Set the model data for $field. + */ + protected function _setHeaderFieldModel($field, $model) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setFieldBodyModel($model); + + return true; + } else { + return false; + } + } + + /** + * Get the parameter value of $parameter on $field header. + */ + protected function _getHeaderParameter($field, $parameter) + { + if ($this->_headers->has($field)) { + return $this->_headers->get($field)->getParameter($parameter); + } + } + + /** + * Set the parameter value of $parameter on $field header. + */ + protected function _setHeaderParameter($field, $parameter, $value) + { + if ($this->_headers->has($field)) { + $this->_headers->get($field)->setParameter($parameter, $value); + + return true; + } else { + return false; + } + } + + /** + * Re-evaluate what content type and encoding should be used on this entity. + */ + protected function _fixHeaders() + { + if (count($this->_immediateChildren)) { + $this->_setHeaderParameter('Content-Type', 'boundary', + $this->getBoundary() + ); + $this->_headers->remove('Content-Transfer-Encoding'); + } else { + $this->_setHeaderParameter('Content-Type', 'boundary', null); + $this->_setEncoding($this->_encoder->getName()); + } + } + + /** + * Get the KeyCache used in this entity. + * + * @return Swift_KeyCache + */ + protected function _getCache() + { + return $this->_cache; + } + + /** + * Get the grammar used for validation. + * + * @return Swift_Mime_Grammar + */ + protected function _getGrammar() + { + return $this->_grammar; + } + + /** + * Empty the KeyCache for this entity. + */ + protected function _clearCache() + { + $this->_cache->clearKey($this->_cacheKey, 'body'); + } + + /** + * Returns a random Content-ID or Message-ID. + * + * @return string + */ + protected function getRandomId() + { + $idLeft = md5(getmypid() . '.' . time() . '.' . uniqid(mt_rand(), true)); + $idRight = !empty($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated'; + $id = $idLeft . '@' . $idRight; + + try { + $this->_assertValidId($id); + } catch (Swift_RfcComplianceException $e) { + $id = $idLeft . '@swift.generated'; + } + + return $id; + } + + // -- Private methods + + private function _readStream(Swift_OutputByteStream $os) + { + $string = ''; + while (false !== $bytes = $os->read(8192)) { + $string .= $bytes; + } + + return $string; + } + + private function _setEncoding($encoding) + { + if (!$this->_setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) { + $this->_headers->addTextHeader('Content-Transfer-Encoding', $encoding); + } + } + + private function _assertValidBoundary($boundary) + { + if (!preg_match( + '/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', + $boundary)) + { + throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.'); + } + } + + private function _setContentTypeInHeaders($type) + { + if (!$this->_setHeaderFieldModel('Content-Type', $type)) { + $this->_headers->addParameterizedHeader('Content-Type', $type); + } + } + + private function _setNestingLevel($level) + { + $this->_nestingLevel = $level; + } + + private function _getCompoundLevel($children) + { + $level = 0; + foreach ($children as $child) { + $level |= $child->getNestingLevel(); + } + + return $level; + } + + private function _getNeededChildLevel($child, $compoundLevel) + { + $filter = array(); + foreach ($this->_compoundLevelFilters as $bitmask => $rules) { + if (($compoundLevel & $bitmask) === $bitmask) { + $filter = $rules + $filter; + } + } + + $realLevel = $child->getNestingLevel(); + $lowercaseType = strtolower($child->getContentType()); + + if (isset($filter[$realLevel]) + && isset($filter[$realLevel][$lowercaseType])) + { + return $filter[$realLevel][$lowercaseType]; + } else { + return $realLevel; + } + } + + private function _createChild() + { + return new self($this->_headers->newInstance(), + $this->_encoder, $this->_cache, $this->_grammar); + } + + private function _notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder) + { + foreach ($this->_immediateChildren as $child) { + $child->encoderChanged($encoder); + } + } + + private function _notifyCharsetChanged($charset) + { + $this->_encoder->charsetChanged($charset); + $this->_headers->charsetChanged($charset); + foreach ($this->_immediateChildren as $child) { + $child->charsetChanged($charset); + } + } + + private function _sortChildren() + { + $shouldSort = false; + foreach ($this->_immediateChildren as $child) { + // NOTE: This include alternative parts moved into a related part + if ($child->getNestingLevel() == self::LEVEL_ALTERNATIVE) { + $shouldSort = true; + break; + } + } + + // Sort in order of preference, if there is one + if ($shouldSort) { + usort($this->_immediateChildren, array($this, '_childSortAlgorithm')); + } + } + + private function _childSortAlgorithm($a, $b) + { + $typePrefs = array(); + $types = array( + strtolower($a->getContentType()), + strtolower($b->getContentType()) + ); + foreach ($types as $type) { + $typePrefs[] = (array_key_exists($type, $this->_alternativePartOrder)) + ? $this->_alternativePartOrder[$type] + : (max($this->_alternativePartOrder) + 1); + } + + return ($typePrefs[0] >= $typePrefs[1]) ? 1 : -1; + } + + // -- Destructor + + /** + * Empties it's own contents from the cache. + */ + public function __destruct() + { + $this->_cache->clearAll($this->_cacheKey); + } + + /** + * Throws an Exception if the id passed does not comply with RFC 2822. + * + * @param string $id + * + * @throws Swift_RfcComplianceException + */ + private function _assertValidId($id) + { + if (!preg_match( + '/^' . $this->_grammar->getDefinition('id-left') . '@' . + $this->_grammar->getDefinition('id-right') . '$/D', + $id + )) + { + throw new Swift_RfcComplianceException( + 'Invalid ID given <' . $id . '>' + ); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/MimePart.php b/public/include/lib/swiftmailer/classes/Swift/MimePart.php new file mode 100644 index 00000000..10a4f3c8 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/MimePart.php @@ -0,0 +1,61 @@ +createDependenciesFor('mime.part') + ); + + if (!isset($charset)) { + $charset = Swift_DependencyContainer::getInstance() + ->lookup('properties.charset'); + } + $this->setBody($body); + $this->setCharset($charset); + if ($contentType) { + $this->setContentType($contentType); + } + } + + /** + * Create a new MimePart. + * + * @param string $body + * @param string $contentType + * @param string $charset + * + * @return Swift_Mime_MimePart + */ + public static function newInstance($body = null, $contentType = null, $charset = null) + { + return new self($body, $contentType, $charset); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/NullTransport.php b/public/include/lib/swiftmailer/classes/Swift/NullTransport.php new file mode 100644 index 00000000..335c4793 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/NullTransport.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @package Swift + * @author Fabien Potencier + */ +class Swift_NullTransport extends Swift_Transport_NullTransport +{ + /** + * Create a new NullTransport. + */ + public function __construct() + { + call_user_func_array( + array($this, 'Swift_Transport_NullTransport::__construct'), + Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.null') + ); + } + + /** + * Create a new NullTransport instance. + * + * @return Swift_NullTransport + */ + public static function newInstance() + { + return new self(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/OutputByteStream.php b/public/include/lib/swiftmailer/classes/Swift/OutputByteStream.php new file mode 100644 index 00000000..2ff74491 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/OutputByteStream.php @@ -0,0 +1,48 @@ +setThreshold($threshold); + $this->setSleepTime($sleep); + $this->_sleeper = $sleeper; + } + + /** + * Set the number of emails to send before restarting. + * + * @param integer $threshold + */ + public function setThreshold($threshold) + { + $this->_threshold = $threshold; + } + + /** + * Get the number of emails to send before restarting. + * + * @return int + */ + public function getThreshold() + { + return $this->_threshold; + } + + /** + * Set the number of seconds to sleep for during a restart. + * + * @param integer $sleep time + */ + public function setSleepTime($sleep) + { + $this->_sleep = $sleep; + } + + /** + * Get the number of seconds to sleep for during a restart. + * + * @return int + */ + public function getSleepTime() + { + return $this->_sleep; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + ++$this->_counter; + if ($this->_counter >= $this->_threshold) { + $transport = $evt->getTransport(); + $transport->stop(); + if ($this->_sleep) { + $this->sleep($this->_sleep); + } + $transport->start(); + $this->_counter = 0; + } + } + + /** + * Sleep for $seconds. + * + * @param integer $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php new file mode 100644 index 00000000..8794aacf --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/BandwidthMonitorPlugin.php @@ -0,0 +1,166 @@ +getMessage(); + $message->toByteStream($this); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_out += strlen($command); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_in += strlen($response); + } + + /** + * Called when a message is sent so that the outgoing counter can be increased. + * + * @param string $bytes + */ + public function write($bytes) + { + $this->_out += strlen($bytes); + foreach ($this->_mirrors as $stream) { + $stream->write($bytes); + } + } + + /** + * Not used. + */ + public function commit() + { + } + + /** + * Attach $is to this stream. + * + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + $this->_mirrors[] = $is; + } + + /** + * Remove an already bound stream. + * + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + foreach ($this->_mirrors as $k => $stream) { + if ($is === $stream) { + unset($this->_mirrors[$k]); + } + } + } + + /** + * Not used. + */ + public function flushBuffers() + { + foreach ($this->_mirrors as $stream) { + $stream->flushBuffers(); + } + } + + /** + * Get the total number of bytes sent to the server. + * + * @return int + */ + public function getBytesOut() + { + return $this->_out; + } + + /** + * Get the total number of bytes received from the server. + * + * @return int + */ + public function getBytesIn() + { + return $this->_in; + } + + /** + * Reset the internal counters to zero. + */ + public function reset() + { + $this->_out = 0; + $this->_in = 0; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php new file mode 100644 index 00000000..3269c698 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Decorator/Replacements.php @@ -0,0 +1,33 @@ + + * $replacements = array( + * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"), + * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y") + * ) + * + * + * When using an instance of {@link Swift_Plugins_Decorator_Replacements}, + * the object should return just the array of replacements for the address + * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + */ + public function __construct($replacements) + { + $this->setReplacements($replacements); + } + + /** + * Sets replacements. + * + * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements + * + * @see __construct() + */ + public function setReplacements($replacements) + { + if (!($replacements instanceof \Swift_Plugins_Decorator_Replacements)) { + $this->_replacements = (array) $replacements; + } else { + $this->_replacements = $replacements; + } + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $this->_restoreMessage($message); + $to = array_keys($message->getTo()); + $address = array_shift($to); + if ($replacements = $this->getReplacementsFor($address)) { + $body = $message->getBody(); + $search = array_keys($replacements); + $replace = array_values($replacements); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $this->_originalBody = $body; + $message->setBody($bodyReplaced); + } + + foreach ($message->getHeaders()->getAll() as $header) { + $body = $header->getFieldBodyModel(); + $count = 0; + if (is_array($body)) { + $bodyReplaced = array(); + foreach ($body as $key => $value) { + $count1 = 0; + $count2 = 0; + $key = is_string($key) ? str_replace($search, $replace, $key, $count1) : $key; + $value = is_string($value) ? str_replace($search, $replace, $value, $count2) : $value; + $bodyReplaced[$key] = $value; + + if (!$count && ($count1 || $count2)) { + $count = 1; + } + } + } else { + $bodyReplaced = str_replace($search, $replace, $body, $count); + } + + if ($count) { + $this->_originalHeaders[$header->getFieldName()] = $body; + $header->setFieldBodyModel($bodyReplaced); + } + } + + $children = (array) $message->getChildren(); + foreach ($children as $child) { + list($type, ) = sscanf($child->getContentType(), '%[^/]/%s'); + if ('text' == $type) { + $body = $child->getBody(); + $bodyReplaced = str_replace( + $search, $replace, $body + ); + if ($body != $bodyReplaced) { + $child->setBody($bodyReplaced); + $this->_originalChildBodies[$child->getId()] = $body; + } + } + } + $this->_lastMessage = $message; + } + } + + /** + * Find a map of replacements for the address. + * + * If this plugin was provided with a delegate instance of + * {@link Swift_Plugins_Decorator_Replacements} then the call will be + * delegated to it. Otherwise, it will attempt to find the replacements + * from the array provided in the constructor. + * + * If no replacements can be found, an empty value (NULL) is returned. + * + * @param string $address + * + * @return array + */ + public function getReplacementsFor($address) + { + if ($this->_replacements instanceof Swift_Plugins_Decorator_Replacements) { + return $this->_replacements->getReplacementsFor($address); + } else { + return isset($this->_replacements[$address]) + ? $this->_replacements[$address] + : null + ; + } + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + // -- Private methods + + /** Restore a changed message back to its original state */ + private function _restoreMessage(Swift_Mime_Message $message) + { + if ($this->_lastMessage === $message) { + if (isset($this->_originalBody)) { + $message->setBody($this->_originalBody); + $this->_originalBody = null; + } + if (!empty($this->_originalHeaders)) { + foreach ($message->getHeaders()->getAll() as $header) { + if (array_key_exists($header->getFieldName(), $this->_originalHeaders)) { + $header->setFieldBodyModel($this->_originalHeaders[$header->getFieldName()]); + } + } + $this->_originalHeaders = array(); + } + if (!empty($this->_originalChildBodies)) { + $children = (array) $message->getChildren(); + foreach ($children as $child) { + $id = $child->getId(); + if (array_key_exists($id, $this->_originalChildBodies)) { + $child->setBody($this->_originalChildBodies[$id]); + } + } + $this->_originalChildBodies = array(); + } + $this->_lastMessage = null; + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php new file mode 100644 index 00000000..1f1e4430 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/ImpersonatePlugin.php @@ -0,0 +1,70 @@ +_sender = $sender; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // save current recipients + $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath()); + + // replace them with the one to send to + $message->setReturnPath($this->_sender); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-Return-Path')) { + $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress()); + $headers->removeAll('X-Swift-Return-Path'); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php new file mode 100644 index 00000000..81c1d9bb --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Logger.php @@ -0,0 +1,38 @@ +_logger = $logger; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_logger->add($entry); + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_logger->clear(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return $this->_logger->dump(); + } + + /** + * Invoked immediately following a command being sent. + * + * @param Swift_Events_CommandEvent $evt + */ + public function commandSent(Swift_Events_CommandEvent $evt) + { + $command = $evt->getCommand(); + $this->_logger->add(sprintf(">> %s", $command)); + } + + /** + * Invoked immediately following a response coming back. + * + * @param Swift_Events_ResponseEvent $evt + */ + public function responseReceived(Swift_Events_ResponseEvent $evt) + { + $response = $evt->getResponse(); + $this->_logger->add(sprintf("<< %s", $response)); + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf("++ Starting %s", $transportName)); + } + + /** + * Invoked immediately after the Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf("++ %s started", $transportName)); + } + + /** + * Invoked just before a Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf("++ Stopping %s", $transportName)); + } + + /** + * Invoked immediately after the Transport is stopped. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + $transportName = get_class($evt->getSource()); + $this->_logger->add(sprintf("++ %s stopped", $transportName)); + } + + /** + * Invoked as a TransportException is thrown in the Transport system. + * + * @param Swift_Events_TransportExceptionEvent $evt + */ + public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt) + { + $e = $evt->getException(); + $message = $e->getMessage(); + $this->_logger->add(sprintf("!! %s", $message)); + $message .= PHP_EOL; + $message .= 'Log data:' . PHP_EOL; + $message .= $this->_logger->dump(); + $evt->cancelBubble(); + throw new Swift_TransportException($message); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php new file mode 100644 index 00000000..eb362ef8 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/ArrayLogger.php @@ -0,0 +1,74 @@ +_size = $size; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + $this->_log[] = $entry; + while (count($this->_log) > $this->_size) { + array_shift($this->_log); + } + } + + /** + * Clear the log contents. + */ + public function clear() + { + $this->_log = array(); + } + + /** + * Get this log as a string. + * + * @return string + */ + public function dump() + { + return implode(PHP_EOL, $this->_log); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php new file mode 100644 index 00000000..c542169f --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Loggers/EchoLogger.php @@ -0,0 +1,60 @@ +_isHtml = $isHtml; + } + + /** + * Add a log entry. + * + * @param string $entry + */ + public function add($entry) + { + if ($this->_isHtml) { + printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
    ', PHP_EOL); + } else { + printf('%s%s', $entry, PHP_EOL); + } + } + + /** + * Not implemented. + */ + public function clear() + { + } + + /** + * Not implemented. + */ + public function dump() + { + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php new file mode 100644 index 00000000..35d5de53 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/MessageLogger.php @@ -0,0 +1,77 @@ +messages = array(); + } + + /** + * Get the message list + * + * @return array + */ + public function getMessages() + { + return $this->messages; + } + + /** + * Get the message count + * + * @return integer count + */ + public function countMessages() + { + return count($this->messages); + } + + /** + * Empty the message list + * + */ + public function clear() + { + $this->messages = array(); + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $this->messages[] = clone $evt->getMessage(); + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php new file mode 100644 index 00000000..d2417215 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Pop/Pop3Connection.php @@ -0,0 +1,33 @@ +_host = $host; + $this->_port = $port; + $this->_crypto = $crypto; + } + + /** + * Create a new PopBeforeSmtpPlugin for $host and $port. + * + * @param string $host + * @param integer $port + * @param string $crypto as "tls" or "ssl" + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public static function newInstance($host, $port = 110, $crypto = null) + { + return new self($host, $port, $crypto); + } + + /** + * Set a Pop3Connection to delegate to instead of connecting directly. + * + * @param Swift_Plugins_Pop_Pop3Connection $connection + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection) + { + $this->_connection = $connection; + + return $this; + } + + /** + * Bind this plugin to a specific SMTP transport instance. + * + * @param Swift_Transport + */ + public function bindSmtp(Swift_Transport $smtp) + { + $this->_transport = $smtp; + } + + /** + * Set the connection timeout in seconds (default 10). + * + * @param integer $timeout + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setTimeout($timeout) + { + $this->_timeout = (int) $timeout; + + return $this; + } + + /** + * Set the username to use when connecting (if needed). + * + * @param string $username + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setUsername($username) + { + $this->_username = $username; + + return $this; + } + + /** + * Set the password to use when connecting (if needed). + * + * @param string $password + * + * @return Swift_Plugins_PopBeforeSmtpPlugin + */ + public function setPassword($password) + { + $this->_password = $password; + + return $this; + } + + /** + * Connect to the POP3 host and authenticate. + * + * @throws Swift_Plugins_Pop_Pop3Exception if connection fails + */ + public function connect() + { + if (isset($this->_connection)) { + $this->_connection->connect(); + } else { + if (!isset($this->_socket)) { + if (!$socket = fsockopen( + $this->_getHostString(), $this->_port, $errno, $errstr, $this->_timeout)) + { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]: %s', $this->_host, $errstr) + ); + } + $this->_socket = $socket; + + if (false === $greeting = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to connect to POP3 host [%s]', trim($greeting)) + ); + } + + $this->_assertOk($greeting); + + if ($this->_username) { + $this->_command(sprintf("USER %s\r\n", $this->_username)); + $this->_command(sprintf("PASS %s\r\n", $this->_password)); + } + } + } + } + + /** + * Disconnect from the POP3 host. + */ + public function disconnect() + { + if (isset($this->_connection)) { + $this->_connection->disconnect(); + } else { + $this->_command("QUIT\r\n"); + if (!fclose($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 host [%s] connection could not be stopped', $this->_host) + ); + } + $this->_socket = null; + } + } + + /** + * Invoked just before a Transport is started. + * + * @param Swift_Events_TransportChangeEvent $evt + */ + public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt) + { + if (isset($this->_transport)) { + if ($this->_transport !== $evt->getTransport()) { + return; + } + } + + $this->connect(); + $this->disconnect(); + } + + /** + * Not used. + */ + public function transportStarted(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + /** + * Not used. + */ + public function transportStopped(Swift_Events_TransportChangeEvent $evt) + { + } + + // -- Private Methods + + private function _command($command) + { + if (!fwrite($this->_socket, $command)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to write command [%s] to POP3 host', trim($command)) + ); + } + + if (false === $response = fgets($this->_socket)) { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('Failed to read from POP3 host after command [%s]', trim($command)) + ); + } + + $this->_assertOk($response); + + return $response; + } + + private function _assertOk($response) + { + if (substr($response, 0, 3) != '+OK') { + throw new Swift_Plugins_Pop_Pop3Exception( + sprintf('POP3 command failed [%s]', trim($response)) + ); + } + } + + private function _getHostString() + { + $host = $this->_host; + switch (strtolower($this->_crypto)) { + case 'ssl': + $host = 'ssl://' . $host; + break; + + case 'tls': + $host = 'tls://' . $host; + break; + } + + return $host; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php new file mode 100644 index 00000000..3b006b67 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/RedirectingPlugin.php @@ -0,0 +1,209 @@ +_recipient = $recipient; + $this->_whitelist = $whitelist; + } + + /** + * Set the recipient of all messages. + * + * @param mixed $recipient + */ + public function setRecipient($recipient) + { + $this->_recipient = $recipient; + } + + /** + * Get the recipient of all messages. + * + * @return mixed + */ + public function getRecipient() + { + return $this->_recipient; + } + + /** + * Set a list of regular expressions to whitelist certain recipients + * + * @param array $whitelist + */ + public function setWhitelist(array $whitelist) + { + $this->_whitelist = $whitelist; + } + + /** + * Get the whitelist + * + * @return array + */ + public function getWhitelist() + { + return $this->_whitelist; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $headers = $message->getHeaders(); + + // conditionally save current recipients + + if ($headers->has('to')) { + $headers->addMailboxHeader('X-Swift-To', $message->getTo()); + } + + if ($headers->has('cc')) { + $headers->addMailboxHeader('X-Swift-Cc', $message->getCc()); + } + + if ($headers->has('bcc')) { + $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc()); + } + + // Filter remaining headers against whitelist + $this->_filterHeaderSet($headers, 'To'); + $this->_filterHeaderSet($headers, 'Cc'); + $this->_filterHeaderSet($headers, 'Bcc'); + + // Add each hard coded recipient + foreach ( (array) $this->_recipient as $recipient) { + if (!array_key_exists($recipient, $message->getTo())) { + $message->addTo($recipient); + } + } + + } + + /** + * Filter header set against a whitelist of regular expressions + * + * @param Swift_Mime_HeaderSet $headerSet + * @param string $type + */ + private function _filterHeaderSet(Swift_Mime_HeaderSet $headerSet, $type) + { + foreach ($headerSet->getAll($type) as $headers) { + $headers->setNameAddresses($this->_filterNameAddresses($headers->getNameAddresses())); + } + } + + /** + * Filtered list of addresses => name pairs + * + * @param array $recipients + * @return array + */ + private function _filterNameAddresses(array $recipients) + { + $filtered = array(); + + foreach ($recipients as $address => $name) { + if ($this->_isWhitelisted($address)) { + $filtered[$address] = $name; + } + } + + return $filtered; + } + + /** + * Matches address against whitelist of regular expressions + * + * @param $recipient + * @return bool + */ + protected function _isWhitelisted($recipient) + { + if (in_array($recipient, (array) $this->_recipient)) { + return true; + } + + foreach ($this->_whitelist as $pattern) { + if (preg_match($pattern, $recipient)) { + return true; + } + } + + return false; + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $this->_restoreMessage($evt->getMessage()); + } + + // -- Private methods + + private function _restoreMessage(Swift_Mime_Message $message) + { + // restore original headers + $headers = $message->getHeaders(); + + if ($headers->has('X-Swift-To')) { + $message->setTo($headers->get('X-Swift-To')->getNameAddresses()); + $headers->removeAll('X-Swift-To'); + } + + if ($headers->has('X-Swift-Cc')) { + $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses()); + $headers->removeAll('X-Swift-Cc'); + } + + if ($headers->has('X-Swift-Bcc')) { + $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses()); + $headers->removeAll('X-Swift-Bcc'); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php new file mode 100644 index 00000000..0dfa22d8 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporter.php @@ -0,0 +1,34 @@ +_reporter = $reporter; + } + + /** + * Not used. + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + } + + /** + * Invoked immediately after the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + $message = $evt->getMessage(); + $failures = array_flip($evt->getFailedRecipients()); + foreach ((array) $message->getTo() as $address => $null) { + $this->_reporter->notify( + $message, $address, (array_key_exists($address, $failures) + ? Swift_Plugins_Reporter::RESULT_FAIL + : Swift_Plugins_Reporter::RESULT_PASS) + ); + } + foreach ((array) $message->getCc() as $address => $null) { + $this->_reporter->notify( + $message, $address, (array_key_exists($address, $failures) + ? Swift_Plugins_Reporter::RESULT_FAIL + : Swift_Plugins_Reporter::RESULT_PASS) + ); + } + foreach ((array) $message->getBcc() as $address => $null) { + $this->_reporter->notify( + $message, $address, (array_key_exists($address, $failures) + ? Swift_Plugins_Reporter::RESULT_FAIL + : Swift_Plugins_Reporter::RESULT_PASS) + ); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php new file mode 100644 index 00000000..844e2a18 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HitReporter.php @@ -0,0 +1,61 @@ +_failures_cache[$address])) { + $this->_failures[] = $address; + $this->_failures_cache[$address] = true; + } + } + + /** + * Get an array of addresses for which delivery failed. + * + * @return array + */ + public function getFailedRecipients() + { + return $this->_failures; + } + + /** + * Clear the buffer (empty the list). + */ + public function clear() + { + $this->_failures = $this->_failures_cache = array(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php new file mode 100644 index 00000000..7b8c1889 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Reporters/HtmlReporter.php @@ -0,0 +1,41 @@ +" . PHP_EOL; + echo "PASS " . $address . PHP_EOL; + echo "" . PHP_EOL; + flush(); + } else { + echo "
    " . PHP_EOL; + echo "FAIL " . $address . PHP_EOL; + echo "
    " . PHP_EOL; + flush(); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php new file mode 100644 index 00000000..c491f63d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Sleeper.php @@ -0,0 +1,26 @@ +_rate = $rate; + $this->_mode = $mode; + $this->_sleeper = $sleeper; + $this->_timer = $timer; + } + + /** + * Invoked immediately before the Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function beforeSendPerformed(Swift_Events_SendEvent $evt) + { + $time = $this->getTimestamp(); + if (!isset($this->_start)) { + $this->_start = $time; + } + $duration = $time - $this->_start; + + switch($this->_mode) { + case self::BYTES_PER_MINUTE : + $sleep = $this->_throttleBytesPerMinute($duration); + break; + case self::MESSAGES_PER_SECOND : + $sleep = $this->_throttleMessagesPerSecond($duration); + break; + case self::MESSAGES_PER_MINUTE : + $sleep = $this->_throttleMessagesPerMinute($duration); + break; + default : + $sleep = 0; + break; + } + + if ($sleep > 0) { + $this->sleep($sleep); + } + } + + /** + * Invoked when a Message is sent. + * + * @param Swift_Events_SendEvent $evt + */ + public function sendPerformed(Swift_Events_SendEvent $evt) + { + parent::sendPerformed($evt); + ++$this->_messages; + } + + /** + * Sleep for $seconds. + * + * @param integer $seconds + */ + public function sleep($seconds) + { + if (isset($this->_sleeper)) { + $this->_sleeper->sleep($seconds); + } else { + sleep($seconds); + } + } + + /** + * Get the current UNIX timestamp. + * + * @return int + */ + public function getTimestamp() + { + if (isset($this->_timer)) { + return $this->_timer->getTimestamp(); + } else { + return time(); + } + } + + // -- Private methods + + /** + * Get a number of seconds to sleep for. + * + * @param integer $timePassed + * + * @return int + */ + private function _throttleBytesPerMinute($timePassed) + { + $expectedDuration = $this->getBytesOut() / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param int $timePassed + * + * @return int + */ + private function _throttleMessagesPerSecond($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate); + + return (int) ceil($expectedDuration - $timePassed); + } + + /** + * Get a number of seconds to sleep for. + * + * @param integer $timePassed + * + * @return int + */ + private function _throttleMessagesPerMinute($timePassed) + { + $expectedDuration = $this->_messages / ($this->_rate / 60); + + return (int) ceil($expectedDuration - $timePassed); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php b/public/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php new file mode 100644 index 00000000..12dd09b8 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Plugins/Timer.php @@ -0,0 +1,26 @@ +register('properties.charset')->asValue($charset); + + return $this; + } + + /** + * Set the directory where temporary files can be saved. + * + * @param string $dir + * + * @return Swift_Preferences + */ + public function setTempDir($dir) + { + Swift_DependencyContainer::getInstance() + ->register('tempdir')->asValue($dir); + + return $this; + } + + /** + * Set the type of cache to use (i.e. "disk" or "array"). + * + * @param string $type + * + * @return Swift_Preferences + */ + public function setCacheType($type) + { + Swift_DependencyContainer::getInstance() + ->register('cache')->asAliasOf(sprintf('cache.%s', $type)); + + return $this; + } + + /** + * Set the QuotedPrintable dot escaper preference. + * + * @param boolean $dotEscape + * + * @return Swift_Preferences + */ + public function setQPDotEscape($dotEscape) + { + $dotEscape = !empty($dotEscape); + Swift_DependencyContainer::getInstance() + ->register('mime.qpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + ->addConstructorValue($dotEscape); + + return $this; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php b/public/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php new file mode 100644 index 00000000..4b6eed58 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/ReplacementFilterFactory.php @@ -0,0 +1,28 @@ +createDependenciesFor('transport.sendmail') + ); + + $this->setCommand($command); + } + + /** + * Create a new SendmailTransport instance. + * + * @param string $command + * + * @return Swift_SendmailTransport + */ + public static function newInstance($command = '/usr/sbin/sendmail -bs') + { + return new self($command); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/SignedMessage.php b/public/include/lib/swiftmailer/classes/Swift/SignedMessage.php new file mode 100644 index 00000000..c4fb2c73 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/SignedMessage.php @@ -0,0 +1,25 @@ + + * @deprecated + */ +class Swift_SignedMessage extends Swift_Message +{ + +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signer.php b/public/include/lib/swiftmailer/classes/Swift/Signer.php new file mode 100644 index 00000000..865f557e --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signer.php @@ -0,0 +1,22 @@ + + */ +interface Swift_Signer +{ + public function reset(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php new file mode 100644 index 00000000..1d700fb1 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/BodySigner.php @@ -0,0 +1,35 @@ + + */ +interface Swift_Signers_BodySigner extends Swift_Signer +{ + /** + * Change the Swift_Signed_Message to apply the singing. + * + * @param Swift_Message $message + * + * @return Swift_Signers_BodySigner + */ + public function signMessage(Swift_Message $message); + + /** + * Return the list of header a signer might tamper + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php new file mode 100644 index 00000000..6a240c7f --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/DKIMSigner.php @@ -0,0 +1,686 @@ + + */ +class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName + * + * @var string + */ + protected $_domainName; + + /** + * Selector + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha1'; + + /** + * Body canon method + * + * @var string + */ + protected $_bodyCanon = 'simple'; + + /** + * Header canon method + * + * @var string + */ + protected $_headerCanon = 'simple'; + + /** + * Headers not being signed + * + * @var array + */ + protected $_ignoredHeaders = array(); + + /** + * Signer identity + * + * @var unknown_type + */ + protected $_signerIdentity; + + /** + * BodyLength + * + * @var int + */ + protected $_bodyLen = 0; + + /** + * Maximum signedLen + * + * @var int + */ + protected $_maxLen = PHP_INT_MAX; + + /** + * Embbed bodyLen in signature + * + * @var boolean + */ + protected $_showLen = false; + + /** + * When the signature has been applied (true means time()), false means not embedded + * + * @var mixed + */ + protected $_signatureTimestamp = true; + + /** + * When will the signature expires false means not embedded, if sigTimestamp is auto + * Expiration is relative, otherwhise it's absolute + * + * @var int + */ + protected $_signatureExpiration = false; + + /** + * Must we embed signed headers? + * + * @var boolean + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash + * + * @var array + */ + protected $_signedHeaders = array(); + + /** + * If debugHeaders is set store debugDatas here + * + * @var string + */ + private $_debugHeadersData = ''; + + /** + * Stores the bodyHash + * + * @var string + */ + private $_bodyHash = ''; + + /** + * Stores the signature header + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_dkimHeader; + + /** + * Hash Handler + * + * @var hash_ressource + */ + private $_headerHashHandler; + + private $_bodyHashHandler; + + private $_headerHash; + + private $_headerCanonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@' . $domainName; + $this->_selector = $selector; + } + + /** + * Instanciate DKIMSigner + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * @return Swift_Signers_DKIMSigner + */ + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + + /** + * Reset the Signer + * @see Swift_Signer::reset() + */ + public function reset() + { + $this->_headerHash = null; + $this->_signedHeaders = array(); + $this->_headerHashHandler = null; + $this->_bodyHash = null; + $this->_bodyHashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = NULL; + $this->_bodyCanonSpace = false; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * @return int + * @throws Swift_IoException + */ + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + */ + public function commit() + { + // Nothing to do + return; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + return; + } + } + + return; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + */ + public function flushBuffers() + { + $this->reset(); + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256 + * + * @param string $hash + * @return Swift_Signers_DKIMSigner + */ + public function setHashAlgorithm($hash) + { + // Unable to sign with rsa-sha256 + if ($hash == 'rsa-sha1') { + $this->_hashAlgorithm = 'rsa-sha1'; + } else { + $this->_hashAlgorithm = 'rsa-sha256'; + } + + return $this; + } + + /** + * Set the body canonicalization algorithm + * + * @param string $canon + * @return Swift_Signers_DKIMSigner + */ + public function setBodyCanon($canon) + { + if ($canon == 'relaxed') { + $this->_bodyCanon = 'relaxed'; + } else { + $this->_bodyCanon = 'simple'; + } + + return $this; + } + + /** + * Set the header canonicalization algorithm + * + * @param string $canon + * @return Swift_Signers_DKIMSigner + */ + public function setHeaderCanon($canon) + { + if ($canon == 'relaxed') { + $this->_headerCanon = 'relaxed'; + } else { + $this->_headerCanon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity + * + * @param string $identity + * @return Swift_Signers_DKIMSigner + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Set the length of the body to sign + * + * @param mixed $len (bool or int) + * @return Swift_Signers_DKIMSigner + */ + public function setBodySignedLen($len) + { + if ($len === true) { + $this->_showLen = true; + $this->_maxLen = PHP_INT_MAX; + } elseif ($len === false) { + $this->showLen = false; + $this->_maxLen = PHP_INT_MAX; + } else { + $this->_showLen = true; + $this->_maxLen = (int) $len; + } + + return $this; + } + + /** + * Set the signature timestamp + * + * @param timestamp $time + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + + return $this; + } + + /** + * Set the signature expiration timestamp + * + * @param timestamp $time + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders + * + * @param boolean $debug + * @return Swift_Signers_DKIMSigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body + * + */ + public function startBody() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha256' : + $this->_bodyHashHandler = hash_init('sha256'); + break; + case 'rsa-sha1' : + $this->_bodyHashHandler = hash_init('sha1'); + break; + } + $this->_bodyCanonLine = ''; + } + + /** + * End Body + * + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DKIM-Signature', 'X-DebugHash'); + } else { + return array('DKIM-Signature'); + } + } + + /** + * Adds an ignored Header + * + * @param string $header_name + * @return Swift_Signers_DKIMSigner + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign + * + * @param Swift_Mime_HeaderSet $headers + * @return Swift_Signers_DKIMSigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_headerCanonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (! isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + + return $this; + } + + /** + * Add the signature to the given Headers + * + * @param Swift_Mime_HeaderSet $headers + * @return Swift_Signers_DKIMSigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DKIM-Signature + $params = array('v' => '1', 'a' => $this->_hashAlgorithm, 'bh' => base64_encode($this->_bodyHash), 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'i' => $this->_signerIdentity, 's' => $this->_selector); + if ($this->_bodyCanon != 'simple') { + $params['c'] = $this->_headerCanon . '/' . $this->_bodyCanon; + } elseif ($this->_headerCanon != 'simple') { + $params['c'] = $this->_headerCanon; + } + if ($this->_showLen) { + $params['l'] = $this->_bodyLen; + } + if ($this->_signatureTimestamp === true) { + $params['t'] = time(); + if ($this->_signatureExpiration !== false) { + $params['x'] = $params['t'] + $this->_signatureExpiration; + } + } else { + if ($this->_signatureTimestamp !== false) { + $params['t'] = $this->_signatureTimestamp; + } + if ($this->_signatureExpiration !== false) { + $params['x'] = $this->_signatureExpiration; + } + } + if ($this->_debugHeaders) { + $params['z'] = implode('|', $this->_debugHeadersData); + } + $string = ''; + foreach ($params as $k => $v) { + $string .= $k . '=' . $v . '; '; + } + $string = trim($string); + $headers->addTextHeader('DKIM-Signature', $string); + // Add the last DKIM-Signature + $tmp = $headers->getAll('DKIM-Signature'); + $this->_dkimHeader = end($tmp); + $this->_addHeader(trim($this->_dkimHeader->toString()) . "\r\n b=", true); + $this->_endOfHeaders(); + if ($this->_debugHeaders) { + $headers->addTextHeader('X-DebugHash', base64_encode($this->_headerHash)); + } + $this->_dkimHeader->setValue($string . " b=" . trim(chunk_split(base64_encode($this->_getEncryptedHash()), 73, " "))); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header, $is_sig = false) + { + switch ($this->_headerCanon) { + case 'relaxed' : + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", "", $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", " ", $value); + $header = $name . ":" . trim($value) . ($is_sig ? '' : "\r\n"); + case 'simple' : + // Nothing to do + } + $this->_addToHeaderHash($header); + } + + protected function _endOfHeaders() + { + //$this->_headerHash=hash_final($this->_headerHashHandler, true); + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $method = ($this->_bodyCanon == "relaxed"); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r" : + $this->_bodyCanonLastChar = "\r"; + break; + case "\n" : + if ($this->_bodyCanonLastChar == "\r") { + if ($method) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + // todo handle it but should never happen + } + break; + case " " : + case "\t" : + if ($method) { + $this->_bodyCanonSpace = true; + break; + } + default : + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + if ($this->_bodyCanonSpace) { + $this->_bodyCanonLine .= ' '; + $canon .= ' '; + $this->_bodyCanonSpace = false; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToBodyHash($canon); + } + + protected function _endOfBody() + { + // Add trailing Line return if last line is non empty + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToBodyHash("\r\n"); + } + $this->_bodyHash = hash_final($this->_bodyHashHandler, true); + } + + private function _addToBodyHash($string) + { + $len = strlen($string); + if ($len > ($new_len = ($this->_maxLen - $this->_bodyLen))) { + $string = substr($string, 0, $new_len); + $len = $new_len; + } + hash_update($this->_bodyHashHandler, $string); + $this->_bodyLen += $len; + } + + private function _addToHeaderHash($header) + { + if ($this->_debugHeaders) { + $this->_debugHeadersData[] = trim($header); + } + $this->_headerCanonData .= $header; + } + + private function _getEncryptedHash() + { + $signature = ''; + switch ($this->_hashAlgorithm) { + case 'rsa-sha1': + $algorithm = OPENSSL_ALGO_SHA1; + break; + case 'rsa-sha256': + $algorithm = OPENSSL_ALGO_SHA256; + break; + } + $pkeyId=openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_headerCanonData, $signature, $this->_privateKey, $algorithm)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']'); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php new file mode 100644 index 00000000..037a8166 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/DomainKeySigner.php @@ -0,0 +1,516 @@ + + */ +class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner +{ + /** + * PrivateKey + * + * @var string + */ + protected $_privateKey; + + /** + * DomainName + * + * @var string + */ + protected $_domainName; + + /** + * Selector + * + * @var string + */ + protected $_selector; + + /** + * Hash algorithm used + * + * @var string + */ + protected $_hashAlgorithm = 'rsa-sha1'; + + /** + * Canonisation method + * + * @var string + */ + protected $_canon = 'simple'; + + /** + * Headers not being signed + * + * @var array + */ + protected $_ignoredHeaders = array(); + + /** + * Signer identity + * + * @var unknown_type + */ + protected $_signerIdentity; + + /** + * Must we embed signed headers? + * + * @var boolean + */ + protected $_debugHeaders = false; + + // work variables + /** + * Headers used to generate hash + * + * @var array + */ + private $_signedHeaders = array(); + + /** + * If debugHeaders is set store debugDatas here + * + * @var string + */ + private $_debugHeadersData = ''; + + /** + * Stores the signature header + * + * @var Swift_Mime_Headers_ParameterizedHeader + */ + protected $_domainKeyHeader; + + /** + * Hash Handler + * + * @var hash_ressource + */ + private $_hashHandler; + + private $_hash; + + private $_canonData = ''; + + private $_bodyCanonEmptyCounter = 0; + + private $_bodyCanonIgnoreStart = 2; + + private $_bodyCanonSpace = false; + + private $_bodyCanonLastChar = null; + + private $_bodyCanonLine = ''; + + private $_bound = array(); + + /** + * Constructor + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + */ + public function __construct($privateKey, $domainName, $selector) + { + $this->_privateKey = $privateKey; + $this->_domainName = $domainName; + $this->_signerIdentity = '@' . $domainName; + $this->_selector = $selector; + } + + /** + * Instanciate DomainKeySigner + * + * @param string $privateKey + * @param string $domainName + * @param string $selector + * @return Swift_Signers_DomainKeySigner + */ + public static function newInstance($privateKey, $domainName, $selector) { + return new static($privateKey, $domainName, $selector); + } + + /** + * Resets internal states + * + * @return Swift_Signers_DomainKeysSigner + */ + public function reset() + { + $this->_hash = null; + $this->_hashHandler = null; + $this->_bodyCanonIgnoreStart = 2; + $this->_bodyCanonEmptyCounter = 0; + $this->_bodyCanonLastChar = NULL; + $this->_bodyCanonSpace = false; + + return $this; + } + + /** + * Writes $bytes to the end of the stream. + * + * Writing may not happen immediately if the stream chooses to buffer. If + * you want to write these bytes with immediate effect, call {@link commit()} + * after calling write(). + * + * This method returns the sequence ID of the write (i.e. 1 for first, 2 for + * second, etc etc). + * + * @param string $bytes + * @return int + * @throws Swift_IoException + * @return Swift_Signers_DomainKeysSigner + */ + public function write($bytes) + { + $this->_canonicalizeBody($bytes); + foreach ($this->_bound as $is) { + $is->write($bytes); + } + + return $this; + } + + /** + * For any bytes that are currently buffered inside the stream, force them + * off the buffer. + * + * @throws Swift_IoException + * @return Swift_Signers_DomainKeysSigner + */ + public function commit() + { + // Nothing to do + return $this; + } + + /** + * Attach $is to this stream. + * The stream acts as an observer, receiving all data that is written. + * All {@link write()} and {@link flushBuffers()} operations will be mirrored. + * + * @param Swift_InputByteStream $is + * @return Swift_Signers_DomainKeysSigner + */ + public function bind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + $this->_bound[] = $is; + + return $this; + } + + /** + * Remove an already bound stream. + * If $is is not bound, no errors will be raised. + * If the stream currently has any buffered data it will be written to $is + * before unbinding occurs. + * + * @param Swift_InputByteStream $is + * @return Swift_Signers_DomainKeysSigner + */ + public function unbind(Swift_InputByteStream $is) + { + // Don't have to mirror anything + foreach ($this->_bound as $k => $stream) { + if ($stream === $is) { + unset($this->_bound[$k]); + + return; + } + } + + return $this; + } + + /** + * Flush the contents of the stream (empty it) and set the internal pointer + * to the beginning. + * + * @throws Swift_IoException + * @return Swift_Signers_DomainKeysSigner + */ + public function flushBuffers() + { + $this->reset(); + + return $this; + } + + /** + * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256 + * + * @param string $hash + * @return Swift_Signers_DomainKeysSigner + */ + public function setHashAlgorithm($hash) + { + $this->_hashAlgorithm = 'rsa-sha1'; + + return $this; + } + + /** + * Set the canonicalization algorithm + * + * @param string $canon simple | nofws defaults to simple + * @return Swift_Signers_DomainKeysSigner + */ + public function setCanon($canon) + { + if ($canon == 'nofws') { + $this->_canon = 'nofws'; + } else { + $this->_canon = 'simple'; + } + + return $this; + } + + /** + * Set the signer identity + * + * @param string $identity + * @return Swift_Signers_DomainKeySigner + */ + public function setSignerIdentity($identity) + { + $this->_signerIdentity = $identity; + + return $this; + } + + /** + * Enable / disable the DebugHeaders + * + * @param boolean $debug + * @return Swift_Signers_DomainKeySigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + /** + * Start Body + * + */ + public function startBody() + { + } + + /** + * End Body + * + */ + public function endBody() + { + $this->_endOfBody(); + } + + /** + * Returns the list of Headers Tampered by this plugin + * + * @return array + */ + public function getAlteredHeaders() + { + if ($this->_debugHeaders) { + return array('DomainKey-Signature', 'X-DebugHash'); + } else { + return array('DomainKey-Signature'); + } + } + + /** + * Adds an ignored Header + * + * @param string $header_name + * @return Swift_Signers_DomainKeySigner + */ + public function ignoreHeader($header_name) + { + $this->_ignoredHeaders[strtolower($header_name)] = true; + + return $this; + } + + /** + * Set the headers to sign + * + * @param Swift_Mime_HeaderSet $headers + * @return Swift_Signers_DomainKeySigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $this->_startHash(); + $this->_canonData = ''; + // Loop through Headers + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (! isset($this->_ignoredHeaders[strtolower($hName)])) { + if ($headers->has($hName)) { + $tmp = $headers->getAll($hName); + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $this->_addHeader($header->toString()); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + $this->_endOfHeaders(); + + return $this; + } + + /** + * Add the signature to the given Headers + * + * @param Swift_Mime_HeaderSet $headers + * @return Swift_Signers_DomainKeySigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers) + { + // Prepare the DomainKey-Signature Header + $params = array('a' => $this->_hashAlgorithm, 'b' => chunk_split(base64_encode($this->_getEncryptedHash()), 73, " "), 'c' => $this->_canon, 'd' => $this->_domainName, 'h' => implode(': ', $this->_signedHeaders), 'q' => 'dns', 's' => $this->_selector); + $string = ''; + foreach ($params as $k => $v) { + $string .= $k . '=' . $v . '; '; + } + $string = trim($string); + $headers->addTextHeader('DomainKey-Signature', $string); + + return $this; + } + + /* Private helpers */ + + protected function _addHeader($header) + { + switch ($this->_canon) { + case 'nofws' : + // Prepare Header and cascade + $exploded = explode(':', $header, 2); + $name = strtolower(trim($exploded[0])); + $value = str_replace("\r\n", "", $exploded[1]); + $value = preg_replace("/[ \t][ \t]+/", " ", $value); + $header = $name . ":" . trim($value) . "\r\n"; + case 'simple' : + // Nothing to do + } + $this->_addToHash($header); + } + + protected function _endOfHeaders() + { + $this->_bodyCanonEmptyCounter = 1; + } + + protected function _canonicalizeBody($string) + { + $len = strlen($string); + $canon = ''; + $nofws = ($this->_canon == "nofws"); + for ($i = 0; $i < $len; ++$i) { + if ($this->_bodyCanonIgnoreStart > 0) { + --$this->_bodyCanonIgnoreStart; + continue; + } + switch ($string[$i]) { + case "\r" : + $this->_bodyCanonLastChar = "\r"; + break; + case "\n" : + if ($this->_bodyCanonLastChar == "\r") { + if ($nofws) { + $this->_bodyCanonSpace = false; + } + if ($this->_bodyCanonLine == '') { + ++$this->_bodyCanonEmptyCounter; + } else { + $this->_bodyCanonLine = ''; + $canon .= "\r\n"; + } + } else { + // Wooops Error + throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r'); + } + break; + case " " : + case "\t" : + case "\x09": //HTAB + if ($nofws) { + $this->_bodyCanonSpace = true; + break; + } + default : + if ($this->_bodyCanonEmptyCounter > 0) { + $canon .= str_repeat("\r\n", $this->_bodyCanonEmptyCounter); + $this->_bodyCanonEmptyCounter = 0; + } + $this->_bodyCanonLine .= $string[$i]; + $canon .= $string[$i]; + } + } + $this->_addToHash($canon); + } + + protected function _endOfBody() + { + if (strlen($this->_bodyCanonLine) > 0) { + $this->_addToHash("\r\n"); + } + $this->_hash = hash_final($this->_hashHandler, true); + } + + private function _addToHash($string) + { + $this->_canonData .= $string; + hash_update($this->_hashHandler, $string); + } + + private function _startHash() + { + // Init + switch ($this->_hashAlgorithm) { + case 'rsa-sha1' : + $this->_hashHandler = hash_init('sha1'); + break; + } + $this->_canonLine = ''; + } + + private function _getEncryptedHash() + { + $signature = ''; + $pkeyId=openssl_get_privatekey($this->_privateKey); + if (!$pkeyId) { + throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']'); + } + if (openssl_sign($this->_canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) { + return $signature; + } + throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']'); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php new file mode 100644 index 00000000..944deac6 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/HeaderSigner.php @@ -0,0 +1,67 @@ + + */ +interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream +{ + /** + * Exclude an header from the signed headers + * + * @param string $header_name + * + * @return Swift_Signers_HeaderSigner + */ + public function ignoreHeader($header_name); + + /** + * Prepare the Signer to get a new Body + * + * @return Swift_Signers_HeaderSigner + */ + public function startBody(); + + /** + * Give the signal that the body has finished streaming + * + * @return Swift_Signers_HeaderSigner + */ + public function endBody(); + + /** + * Give the headers already given + * + * @param Swift_Mime_SimpleHeaderSet $headers + * + * @return Swift_Signers_HeaderSigner + */ + public function setHeaders(Swift_Mime_HeaderSet $headers); + + /** + * Add the header(s) to the headerSet + * + * @param Swift_Mime_HeaderSet $headers + * + * @return Swift_Signers_HeaderSigner + */ + public function addSignature(Swift_Mime_HeaderSet $headers); + + /** + * Return the list of header a signer might tamper + * + * @return array + */ + public function getAlteredHeaders(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php new file mode 100644 index 00000000..45c89ab9 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/OpenDKIMSigner.php @@ -0,0 +1,184 @@ + + */ +class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner +{ + private $_peclLoaded = false; + + private $_dkimHandler = null; + + private $dropFirstLF = true; + + const CANON_RELAXED = 1; + const CANON_SIMPLE = 2; + const SIG_RSA_SHA1 = 3; + const SIG_RSA_SHA256 = 4; + + public function __construct($privateKey, $domainName, $selector) + { + if (extension_loaded('opendkim')) { + $this->_peclLoaded = true; + } else { + throw new Swift_SwiftException('php-opendkim extension not found'); + } + parent::__construct($privateKey, $domainName, $selector); + } + + public static function newInstance($privateKey, $domainName, $selector) + { + return new static($privateKey, $domainName, $selector); + } + + public function addSignature(Swift_Mime_HeaderSet $headers) + { + $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature'); + $headerVal=$this->_dkimHandler->getSignatureHeader(); + if (!$headerVal) { + throw new Swift_SwiftException('OpenDKIM Error: '.$this->_dkimHandler->getError()); + } + $header->setValue($headerVal); + $headers->set($header); + + return $this; + } + + public function setHeaders(Swift_Mime_HeaderSet $headers) + { + $bodyLen = $this->_bodyLen; + if (is_bool($bodyLen)) { + $bodyLen = - 1; + } + $hash = ($this->_hashAlgorithm == 'rsa-sha1') ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256; + $bodyCanon = ($this->_bodyCanon == 'simple') ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $headerCanon = ($this->_headerCanon == 'simple') ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED; + $this->_dkimHandler = new OpenDKIMSign($this->_privateKey, $this->_selector, $this->_domainName, $headerCanon, $bodyCanon, $hash, $bodyLen); + // Hardcode signature Margin for now + $this->_dkimHandler->setMargin(78); + + if (!is_numeric($this->_signatureTimestamp)) { + OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time()); + } else { + if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->_signatureTimestamp)) { + throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']'); + } + } + if (isset($this->_signerIdentity)) { + $this->_dkimHandler->setSigner($this->_signerIdentity); + } + $listHeaders = $headers->listAll(); + foreach ($listHeaders as $hName) { + // Check if we need to ignore Header + if (! isset($this->_ignoredHeaders[strtolower($hName)])) { + $tmp = $headers->getAll($hName); + if ($headers->has($hName)) { + foreach ($tmp as $header) { + if ($header->getFieldBody() != '') { + $htosign = $header->toString(); + $this->_dkimHandler->header($htosign); + $this->_signedHeaders[] = $header->getFieldName(); + } + } + } + } + } + return $this; + } + + public function startBody() + { + if (! $this->_peclLoaded) { + return parent::startBody(); + } + $this->dropFirstLF = true; + $this->_dkimHandler->eoh(); + return $this; + } + + public function endBody() + { + if (! $this->_peclLoaded) { + return parent::endBody(); + } + $this->_dkimHandler->eom(); + return $this; + } + + public function reset() + { + $this->_dkimHandler = null; + parent::reset(); + return $this; + } + + /** + * Set the signature timestamp + * + * @param timestamp $time + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureTimestamp($time) + { + $this->_signatureTimestamp = $time; + return $this; + } + + /** + * Set the signature expiration timestamp + * + * @param timestamp $time + * @return Swift_Signers_DKIMSigner + */ + public function setSignatureExpiration($time) + { + $this->_signatureExpiration = $time; + + return $this; + } + + /** + * Enable / disable the DebugHeaders + * + * @param boolean $debug + * @return Swift_Signers_DKIMSigner + */ + public function setDebugHeaders($debug) + { + $this->_debugHeaders = (bool) $debug; + + return $this; + } + + // Protected + + protected function _canonicalizeBody($string) + { + if (! $this->_peclLoaded) { + return parent::_canonicalizeBody($string); + } + if (false && $this->dropFirstLF === true) { + if ($string[0]=="\r" && $string[1]=="\n") { + $string=substr($string, 2); + } + } + $this->dropFirstLF = false; + if (strlen($string)) { + $this->_dkimHandler->body($string); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php b/public/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php new file mode 100644 index 00000000..939faba2 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Signers/SMimeSigner.php @@ -0,0 +1,430 @@ + + */ +class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner +{ + protected $signCertificate; + protected $signPrivateKey; + protected $encryptCert; + protected $signThenEncrypt = true; + protected $signLevel; + protected $encryptLevel; + protected $signOptions; + protected $encryptOptions; + protected $encryptCipher; + + /** + * @var Swift_StreamFilters_StringReplacementFilterFactory + */ + protected $replacementFactory; + + /** + * @var Swift_Mime_HeaderFactory + */ + protected $headerFactory; + + /** + * Constructor. + * + * @param string $certificate + * @param string $privateKey + * @param string $encryptCertificate + */ + public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null) + { + if (null !== $signPrivateKey) { + $this->setSignCertificate($signCertificate, $signPrivateKey); + } + + if (null !== $encryptCertificate) { + $this->setEncryptCertificate($encryptCertificate); + } + + $this->replacementFactory = Swift_DependencyContainer::getInstance() + ->lookup('transport.replacementfactory'); + + $this->signOptions = PKCS7_DETACHED; + + // Supported since php5.4 + if (defined('OPENSSL_CIPHER_AES_128_CBC')) { + $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC; + } else { + $this->encryptCipher = OPENSSL_CIPHER_RC2_128; + } + } + + /** + * Returns an new Swift_Signers_SMimeSigner instance. + * + * @param string $certificate + * @param string $privateKey + * + * @return Swift_Signers_SMimeSigner + */ + public static function newInstance($certificate = null, $privateKey = null) + { + return new self($certificate, $privateKey); + } + + /** + * Set the certificate location to use for signing. + * + * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php + * + * @param string $certificate + * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead + * @param integer $signOptions Bitwise operator options for openssl_pkcs7_sign() + * + * @return Swift_Signers_SMimeSigner + */ + public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED) + { + $this->signCertificate = 'file://' . str_replace('\\', '/', realpath($certificate)); + + if (null !== $privateKey) { + if (is_array($privateKey)) { + $this->signPrivateKey = $privateKey; + $this->signPrivateKey[0] = 'file://' . str_replace('\\', '/', realpath($privateKey[0])); + } else { + $this->signPrivateKey = 'file://' . str_replace('\\', '/', realpath($privateKey)); + } + } + + $this->signOptions = $signOptions; + + return $this; + } + + /** + * Set the certificate location to use for encryption. + * + * @link http://www.php.net/manual/en/openssl.pkcs7.flags.php + * @link http://nl3.php.net/manual/en/openssl.ciphers.php + * + * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates. + * @param integer $cipher + * + * @return Swift_Signers_SMimeSigner + */ + public function setEncryptCertificate($recipientCerts, $cipher = null) + { + if (is_array($recipientCerts)) { + $this->encryptCert = array(); + + foreach ($recipientCerts as $cert) { + $this->encryptCert[] = 'file://' . str_replace('\\', '/', realpath($cert)); + } + } else { + $this->encryptCert = 'file://' . str_replace('\\', '/', realpath($recipientCerts)); + } + + if (null !== $cipher) { + $this->encryptCipher = $cipher; + } + + return $this; + } + + /** + * @return string + */ + public function getSignCertificate() + { + return $this->signCertificate; + } + + /** + * @return string + */ + public function getSignPrivateKey() + { + return $this->signPrivateKey; + } + + /** + * Set perform signing before encryption. + * + * The default is to first sign the message and then encrypt. + * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted. + * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients. + * + * @param string $signThenEncrypt + * + * @return Swift_Signers_SMimeSigner + */ + public function setSignThenEncrypt($signThenEncrypt = true) + { + $this->signThenEncrypt = $signThenEncrypt; + + return $this; + } + + /** + * @return Boolean + */ + public function isSignThenEncrypt() + { + return $this->signThenEncrypt; + } + + /** + * Resets internal states. + * + * @return Swift_Signers_SMimeSigner + */ + public function reset() + { + return $this; + } + + /** + * Change the Swift_Message to apply the signing. + * + * @param Swift_Message $message + * + * @return Swift_Signers_SMimeSigner + */ + public function signMessage(Swift_Message $message) + { + if (null === $this->signCertificate && null === $this->encryptCert) { + return $this; + } + + // Store the message using ByteStream to a file{1} + // Remove all Children + // Sign file{1}, parse the new MIME headers and set them on the primary MimeEntity + // Set the singed-body as the new body (without boundary) + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $this->toSMimeByteStream($messageStream, $message); + $message->setEncoder(Swift_DependencyContainer::getInstance()->lookup('mime.rawcontentencoder')); + + $message->setChildren(array()); + $this->streamToMime($messageStream, $message); + + } + + /** + * Return the list of header a signer might tamper. + * + * @return array + */ + public function getAlteredHeaders() + { + return array('Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition'); + } + + /** + * @param Swift_InputByteStream $inputStream + * @param Swift_Message $mimeEntity + */ + protected function toSMimeByteStream(Swift_InputByteStream $inputStream, Swift_Message $message) + { + $mimeEntity = $this->createMessage($message); + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + $mimeEntity->toByteStream($messageStream); + $messageStream->commit(); + + if (null !== $this->signCertificate && null !== $this->encryptCert) { + $temporaryStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if ($this->signThenEncrypt) { + $this->messageStreamToSignedByteStream($messageStream, $temporaryStream); + $this->messageStreamToEncryptedByteStream($temporaryStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $temporaryStream); + $this->messageStreamToSignedByteStream($temporaryStream, $inputStream); + } + } elseif ($this->signCertificate !== null) { + $this->messageStreamToSignedByteStream($messageStream, $inputStream); + } else { + $this->messageStreamToEncryptedByteStream($messageStream, $inputStream); + } + } + + /** + * @param Swift_Message $message + * + * @return Swift_Message + */ + protected function createMessage(Swift_Message $message) + { + $mimeEntity = new Swift_Message('', $message->getBody(), $message->getContentType(), $message->getCharset()); + $mimeEntity->setChildren($message->getChildren()); + + $messageHeaders = $mimeEntity->getHeaders(); + $messageHeaders->remove('Message-ID'); + $messageHeaders->remove('Date'); + $messageHeaders->remove('Subject'); + $messageHeaders->remove('MIME-Version'); + $messageHeaders->remove('To'); + $messageHeaders->remove('From'); + + return $mimeEntity; + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $inputStream + * + * @throws Swift_IoException + */ + protected function messageStreamToSignedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $inputStream) + { + $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_sign($outputStream->getPath(), $signedMessageStream->getPath(), $this->signCertificate, $this->signPrivateKey, array(), $this->signOptions)) { + throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($signedMessageStream, $inputStream); + } + + /** + * @param Swift_FileStream $outputStream + * @param Swift_InputByteStream $is + * + * @throws Swift_IoException + */ + protected function messageStreamToEncryptedByteStream(Swift_FileStream $outputStream, Swift_InputByteStream $is) + { + $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream(); + + if (!openssl_pkcs7_encrypt($outputStream->getPath(), $encryptedMessageStream->getPath(), $this->encryptCert, array(), 0, $this->encryptCipher)) { + throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string())); + } + + $this->copyFromOpenSSLOutput($encryptedMessageStream, $is); + } + + /** + * @param Swift_OutputByteStream $fromStream + * @param Swift_InputByteStream $toStream + */ + protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream) + { + $bufferLength = 4096; + $filteredStream = new Swift_ByteStream_TemporaryFileByteStream(); + $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $filteredStream->write($buffer); + } + + $filteredStream->flushBuffers(); + + while (false !== ($buffer = $filteredStream->read($bufferLength))) { + $toStream->write($buffer); + } + + $toStream->commit(); + } + + /** + * Merges an OutputByteStream to Swift_Message. + * + * @param Swift_OutputByteStream $fromStream + * @param Swift_Message $message + */ + protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message) + { + $bufferLength = 78; + $headerData = ''; + + $fromStream->setReadPointer(0); + + while (($buffer = $fromStream->read($bufferLength)) !== false) { + $headerData .= $buffer; + + if (false !== strpos($buffer, "\r\n\r\n")) { + break; + } + } + + $headersPosEnd = strpos($headerData, "\r\n\r\n"); + $headerData = trim($headerData); + $headerData = substr($headerData, 0, $headersPosEnd); + $headerLines = explode("\r\n", $headerData); + unset($headerData); + + $headers = array(); + $currentHeaderName = ''; + + foreach ($headerLines as $headerLine) { + // Line separated + if (ctype_space($headerLines[0]) || false === strpos($headerLine, ':')) { + $headers[$currentHeaderName] .= ' ' . trim($headerLine); + continue; + } + + $header = explode(':', $headerLine, 2); + $currentHeaderName = strtolower($header[0]); + $headers[$currentHeaderName] = trim($header[1]); + } + + $messageStream = new Swift_ByteStream_TemporaryFileByteStream(); + $messageStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF'); + $messageStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF'); + + $messageHeaders = $message->getHeaders(); + + // No need to check for 'application/pkcs7-mime', as this is always base64 + if ('multipart/signed;' === substr($headers['content-type'], 0, 17)) { + if (!preg_match('/boundary=("[^"]+"|(?:[^\s]+|$))/is', $headers['content-type'], $contentTypeData)) { + throw new Swift_SwiftException('Failed to find Boundary parameter'); + } + + $boundary = trim($contentTypeData['1'], '"'); + $boundaryLen = strlen($boundary); + + // Skip the header and CRLF CRLF + $fromStream->setReadPointer($headersPosEnd + 4); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + + $messageHeaders->remove('Content-Transfer-Encoding'); + $message->setContentType($headers['content-type']); + $message->setBoundary($boundary); + $message->setBody($messageStream); + } else { + $fromStream->setReadPointer($headersPosEnd + 4); + + if (null === $this->headerFactory) { + $this->headerFactory = Swift_DependencyContainer::getInstance()->lookup('mime.headerfactory'); + } + + $message->setContentType($headers['content-type']); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Transfer-Encoding', $headers['content-transfer-encoding'])); + $messageHeaders->set($this->headerFactory->createTextHeader('Content-Disposition', $headers['content-disposition'])); + + while (false !== ($buffer = $fromStream->read($bufferLength))) { + $messageStream->write($buffer); + } + + $messageStream->commit(); + $message->setBody($messageStream); + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/SmtpTransport.php b/public/include/lib/swiftmailer/classes/Swift/SmtpTransport.php new file mode 100644 index 00000000..0ed31005 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/SmtpTransport.php @@ -0,0 +1,59 @@ +createDependenciesFor('transport.smtp') + ); + + $this->setHost($host); + $this->setPort($port); + $this->setEncryption($security); + } + + /** + * Create a new SmtpTransport instance. + * + * @param string $host + * @param integer $port + * @param string $security + * + * @return Swift_SmtpTransport + */ + public static function newInstance($host = 'localhost', $port = 25, $security = null) + { + return new self($host, $port, $security); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Spool.php b/public/include/lib/swiftmailer/classes/Swift/Spool.php new file mode 100644 index 00000000..981c1781 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Spool.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Interface for spools. + * + * @package Swift + * @author Fabien Potencier + */ +interface Swift_Spool +{ + /** + * Starts this Spool mechanism. + */ + public function start(); + + /** + * Stops this Spool mechanism. + */ + public function stop(); + + /** + * Tests if this Spool mechanism has started. + * + * @return boolean + */ + public function isStarted(); + + /** + * Queues a message. + * + * @param Swift_Mime_Message $message The message to store + * + * @return boolean Whether the operation has succeeded + */ + public function queueMessage(Swift_Mime_Message $message); + + /** + * Sends messages using the given transport instance. + * + * @param Swift_Transport $transport A transport instance + * @param string[] $failedRecipients An array of failures by-reference + * + * @return integer The number of sent emails + */ + public function flushQueue(Swift_Transport $transport, &$failedRecipients = null); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/SpoolTransport.php b/public/include/lib/swiftmailer/classes/Swift/SpoolTransport.php new file mode 100644 index 00000000..8a135d4c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/SpoolTransport.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @package Swift + * @author Fabien Potencier + */ +class Swift_SpoolTransport extends Swift_Transport_SpoolTransport +{ + /** + * Create a new SpoolTransport. + * + * @param Swift_Spool $spool + */ + public function __construct(Swift_Spool $spool) + { + $arguments = Swift_DependencyContainer::getInstance() + ->createDependenciesFor('transport.spool'); + + $arguments[] = $spool; + + call_user_func_array( + array($this, 'Swift_Transport_SpoolTransport::__construct'), + $arguments + ); + } + + /** + * Create a new SpoolTransport instance. + * + * @param Swift_Spool $spool + * + * @return Swift_SpoolTransport + */ + public static function newInstance(Swift_Spool $spool) + { + return new self($spool); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilter.php b/public/include/lib/swiftmailer/classes/Swift/StreamFilter.php new file mode 100644 index 00000000..8b887bf6 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/StreamFilter.php @@ -0,0 +1,36 @@ +_search = $search; + $this->_index = array(); + $this->_tree = array(); + $this->_replace = array(); + $this->_repSize = array(); + + $tree = null; + $i = null; + $last_size = $size = 0; + foreach ($search as $i => $search_element) { + if ($tree !== null) { + $tree[-1] = min (count($replace) - 1, $i - 1); + $tree[-2] = $last_size; + } + $tree = &$this->_tree; + if (is_array ($search_element)) { + foreach ($search_element as $k => $char) { + $this->_index[$char] = true; + if (!isset($tree[$char])) { + $tree[$char] = array(); + } + $tree = &$tree[$char]; + } + $last_size = $k+1; + $size = max($size, $last_size); + } else { + $last_size = 1; + if (!isset($tree[$search_element])) { + $tree[$search_element] = array(); + } + $tree = &$tree[$search_element]; + $size = max($last_size, $size); + $this->_index[$search_element] = true; + } + } + if ($i !== null) { + $tree[-1] = min (count ($replace) - 1, $i); + $tree[-2] = $last_size; + $this->_treeMaxLen = $size; + } + foreach ($replace as $rep) { + if (!is_array($rep)) { + $rep = array ($rep); + } + $this->_replace[] = $rep; + } + for ($i = count($this->_replace) - 1; $i >= 0; --$i) { + $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i); + $this->_repSize[$i] = count($rep); + } + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param array $buffer + * + * @return boolean + */ + public function shouldBuffer($buffer) + { + $endOfBuffer = end($buffer); + + return isset ($this->_index[$endOfBuffer]); + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param array $buffer + * @param integer $_minReplaces + * + * @return array + */ + public function filter($buffer, $_minReplaces = -1) + { + if ($this->_treeMaxLen == 0) { + return $buffer; + } + + $newBuffer = array(); + $buf_size = count($buffer); + for ($i = 0; $i < $buf_size; ++$i) { + $search_pos = $this->_tree; + $last_found = PHP_INT_MAX; + // We try to find if the next byte is part of a search pattern + for ($j = 0; $j <= $this->_treeMaxLen; ++$j) { + // We have a new byte for a search pattern + if (isset ($buffer [$p = $i + $j]) && isset($search_pos[$buffer[$p]])) { + $search_pos = $search_pos[$buffer[$p]]; + // We have a complete pattern, save, in case we don't find a better match later + if (isset($search_pos[- 1]) && $search_pos[-1] < $last_found + && $search_pos[-1] > $_minReplaces) + { + $last_found = $search_pos[-1]; + $last_size = $search_pos[-2]; + } + } + // We got a complete pattern + elseif ($last_found !== PHP_INT_MAX) { + // Adding replacement datas to output buffer + $rep_size = $this->_repSize[$last_found]; + for ($j = 0; $j < $rep_size; ++$j) { + $newBuffer[] = $this->_replace[$last_found][$j]; + } + // We Move cursor forward + $i += $last_size - 1; + // Edge Case, last position in buffer + if ($i >= $buf_size) { + $newBuffer[] = $buffer[$i]; + } + + // We start the next loop + continue 2; + } else { + // this byte is not in a pattern and we haven't found another pattern + break; + } + } + // Normal byte, move it to output buffer + $newBuffer[] = $buffer[$i]; + } + + return $newBuffer; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php b/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php new file mode 100644 index 00000000..ca7454ee --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilter.php @@ -0,0 +1,67 @@ +_search = $search; + $this->_replace = $replace; + } + + /** + * Returns true if based on the buffer passed more bytes should be buffered. + * + * @param string $buffer + * + * @return boolean + */ + public function shouldBuffer($buffer) + { + $endOfBuffer = substr($buffer, -1); + foreach ((array) $this->_search as $needle) { + if (false !== strpos($needle, $endOfBuffer)) { + return true; + } + } + + return false; + } + + /** + * Perform the actual replacements on $buffer and return the result. + * + * @param string $buffer + * + * @return string + */ + public function filter($buffer) + { + return str_replace($this->_search, $this->_replace, $buffer); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php new file mode 100644 index 00000000..bb4af778 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/StreamFilters/StringReplacementFilterFactory.php @@ -0,0 +1,46 @@ +_filters[$search][$replace])) { + if (!isset($this->_filters[$search])) { + $this->_filters[$search] = array(); + } + + if (!isset($this->_filters[$search][$replace])) { + $this->_filters[$search][$replace] = array(); + } + + $this->_filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace); + } + + return $this->_filters[$search][$replace]; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/SwiftException.php b/public/include/lib/swiftmailer/classes/Swift/SwiftException.php new file mode 100644 index 00000000..f3bcbed9 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/SwiftException.php @@ -0,0 +1,28 @@ +_eventDispatcher = $dispatcher; + $this->_buffer = $buf; + $this->_lookupHostname(); + } + + /** + * Set the name of the local domain which Swift will identify itself as. + * + * This should be a fully-qualified domain name and should be truly the domain + * you're using. + * + * If your server doesn't have a domain name, use the IP in square + * brackets (i.e. [127.0.0.1]). + * + * @param string $domain + * + * @return Swift_Transport_AbstractSmtpTransport + */ + public function setLocalDomain($domain) + { + $this->_domain = $domain; + + return $this; + } + + /** + * Get the name of the domain Swift will identify as. + * + * @return string + */ + public function getLocalDomain() + { + return $this->_domain; + } + + /** + * Sets the source IP. + * + * @param string $source + */ + public function setSourceIp($source) + { + $this->_sourceIp=$source; + } + + /** + * Returns the IP used to connect to the destination + * + * @return string + */ + public function getSourceIp() + { + return $this->_sourceIp; + } + + /** + * Start the SMTP connection. + */ + public function start() + { + if (!$this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->_buffer->initialize($this->_getBufferParams()); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_readGreeting(); + $this->_doHeloCommand(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStarted'); + } + + $this->_started = true; + } + } + + /** + * Test if an SMTP connection has been established. + * + * @return boolean + */ + public function isStarted() + { + return $this->_started; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $sent = 0; + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (!$reversePath = $this->_getReversePath($message)) { + throw new Swift_TransportException( + 'Cannot send message without a sender address' + ); + } + + $to = (array) $message->getTo(); + $cc = (array) $message->getCc(); + $bcc = (array) $message->getBcc(); + + $message->setBcc(array()); + + try { + $sent += $this->_sendTo($message, $reversePath, $to, $failedRecipients); + $sent += $this->_sendCc($message, $reversePath, $cc, $failedRecipients); + $sent += $this->_sendBcc($message, $reversePath, $bcc, $failedRecipients); + } catch (Exception $e) { + $message->setBcc($bcc); + throw $e; + } + + $message->setBcc($bcc); + + if ($evt) { + if ($sent == count($to) + count($cc) + count($bcc)) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + } elseif ($sent > 0) { + $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE); + } else { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + } + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); //Make sure a new Message ID is used + + return $sent; + } + + /** + * Stop the SMTP connection. + */ + public function stop() + { + if ($this->_started) { + if ($evt = $this->_eventDispatcher->createTransportChangeEvent($this)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped'); + if ($evt->bubbleCancelled()) { + return; + } + } + + try { + $this->executeCommand("QUIT\r\n", array(221)); + } catch (Swift_TransportException $e) {} + + try { + $this->_buffer->terminate(); + + if ($evt) { + $this->_eventDispatcher->dispatchEvent($evt, 'transportStopped'); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + $this->_started = false; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + /** + * Reset the current mail transaction. + */ + public function reset() + { + $this->executeCommand("RSET\r\n", array(250)); + } + + /** + * Get the IoBuffer where read/writes are occurring. + * + * @return Swift_Transport_IoBuffer + */ + public function getBuffer() + { + return $this->_buffer; + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $seq = $this->_buffer->write($command); + $response = $this->_getFullResponse($seq); + if ($evt = $this->_eventDispatcher->createCommandEvent($this, $command, $codes)) { + $this->_eventDispatcher->dispatchEvent($evt, 'commandSent'); + } + $this->_assertResponseCode($response, $codes); + + return $response; + } + + // -- Protected methods + + /** Read the opening SMTP greeting */ + protected function _readGreeting() + { + $this->_assertResponseCode($this->_getFullResponse(0), array(220)); + } + + /** Send the HELO welcome */ + protected function _doHeloCommand() + { + $this->executeCommand( + sprintf("HELO %s\r\n", $this->_domain), array(250) + ); + } + + /** Send the MAIL FROM command */ + protected function _doMailFromCommand($address) + { + $this->executeCommand( + sprintf("MAIL FROM: <%s>\r\n", $address), array(250) + ); + } + + /** Send the RCPT TO command */ + protected function _doRcptToCommand($address) + { + $this->executeCommand( + sprintf("RCPT TO: <%s>\r\n", $address), array(250, 251, 252) + ); + } + + /** Send the DATA command */ + protected function _doDataCommand() + { + $this->executeCommand("DATA\r\n", array(354)); + } + + /** Stream the contents of the message over the buffer */ + protected function _streamMessage(Swift_Mime_Message $message) + { + $this->_buffer->setWriteTranslations(array("\r\n." => "\r\n..")); + try { + $message->toByteStream($this->_buffer); + $this->_buffer->flushBuffers(); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + $this->_buffer->setWriteTranslations(array()); + $this->executeCommand("\r\n.\r\n", array(250)); + } + + /** Determine the best-use reverse path for this message */ + protected function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + // Don't use array_keys + reset($sender); // Reset Pointer to first pos + $path = key($sender); // Get key + } elseif (!empty($from)) { + reset($from); // Reset Pointer to first pos + $path = key($from); // Get key + } + + return $path; + } + + /** Throw a TransportException, first sending it to any listeners */ + protected function _throwException(Swift_TransportException $e) + { + if ($evt = $this->_eventDispatcher->createTransportExceptionEvent($this, $e)) { + $this->_eventDispatcher->dispatchEvent($evt, 'exceptionThrown'); + if (!$evt->bubbleCancelled()) { + throw $e; + } + } else { + throw $e; + } + } + + /** Throws an Exception if a response code is incorrect */ + protected function _assertResponseCode($response, $wanted) + { + list($code) = sscanf($response, '%3d'); + $valid = (empty($wanted) || in_array($code, $wanted)); + + if ($evt = $this->_eventDispatcher->createResponseEvent($this, $response, + $valid)) + { + $this->_eventDispatcher->dispatchEvent($evt, 'responseReceived'); + } + + if (!$valid) { + $this->_throwException( + new Swift_TransportException( + 'Expected response code ' . implode('/', $wanted) . ' but got code ' . + '"' . $code . '", with message "' . $response . '"', + $code) + ); + } + } + + /** Get an entire multi-line response using its sequence number */ + protected function _getFullResponse($seq) + { + $response = ''; + try { + do { + $line = $this->_buffer->readLine($seq); + $response .= $line; + } while (null !== $line && false !== $line && ' ' != $line{3}); + } catch (Swift_IoException $e) { + $this->_throwException( + new Swift_TransportException( + $e->getMessage()) + ); + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + + return $response; + } + + // -- Private methods + + /** Send an email to the given recipients from the given reverse path */ + private function _doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients) + { + $sent = 0; + $this->_doMailFromCommand($reversePath); + foreach ($recipients as $forwardPath) { + try { + $this->_doRcptToCommand($forwardPath); + $sent++; + } catch (Swift_TransportException $e) { + $failedRecipients[] = $forwardPath; + } + } + + if ($sent != 0) { + $this->_doDataCommand(); + $this->_streamMessage($message); + } else { + $this->reset(); + } + + return $sent; + } + + /** Send a message to the given To: recipients */ + private function _sendTo(Swift_Mime_Message $message, $reversePath, array $to, array &$failedRecipients) + { + if (empty($to)) { + return 0; + } + + return $this->_doMailTransaction($message, $reversePath, array_keys($to), + $failedRecipients); + } + + /** Send a message to the given Cc: recipients */ + private function _sendCc(Swift_Mime_Message $message, $reversePath, array $cc, array &$failedRecipients) + { + if (empty($cc)) { + return 0; + } + + return $this->_doMailTransaction($message, $reversePath, array_keys($cc), + $failedRecipients); + } + + /** Send a message to all Bcc: recipients */ + private function _sendBcc(Swift_Mime_Message $message, $reversePath, array $bcc, array &$failedRecipients) + { + $sent = 0; + foreach ($bcc as $forwardPath => $name) { + $message->setBcc(array($forwardPath => $name)); + $sent += $this->_doMailTransaction( + $message, $reversePath, array($forwardPath), $failedRecipients + ); + } + + return $sent; + } + + /** Try to determine the hostname of the server this is run on */ + private function _lookupHostname() + { + if (!empty($_SERVER['SERVER_NAME']) + && $this->_isFqdn($_SERVER['SERVER_NAME'])) + { + $this->_domain = $_SERVER['SERVER_NAME']; + } elseif (!empty($_SERVER['SERVER_ADDR'])) { + $this->_domain = sprintf('[%s]', $_SERVER['SERVER_ADDR']); + } + } + + /** Determine is the $hostname is a fully-qualified name */ + private function _isFqdn($hostname) + { + // We could do a really thorough check, but there's really no point + if (false !== $dotPos = strpos($hostname, '.')) { + return ($dotPos > 0) && ($dotPos != strlen($hostname) - 1); + } else { + return false; + } + } + + /** + * Destructor. + */ + public function __destruct() + { + $this->stop(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php new file mode 100644 index 00000000..80b47127 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php @@ -0,0 +1,83 @@ +executeCommand("AUTH CRAM-MD5\r\n", array(334)); + $challenge = base64_decode(substr($challenge, 4)); + $message = base64_encode( + $username . ' ' . $this->_getResponse($password, $challenge) + ); + $agent->executeCommand(sprintf("%s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Generate a CRAM-MD5 response from a server challenge. + * + * @param string $secret + * @param string $challenge + * + * @return string + */ + private function _getResponse($secret, $challenge) + { + if (strlen($secret) > 64) { + $secret = pack('H32', md5($secret)); + } + + if (strlen($secret) < 64) { + $secret = str_pad($secret, 64, chr(0)); + } + + $k_ipad = substr($secret, 0, 64) ^ str_repeat(chr(0x36), 64); + $k_opad = substr($secret, 0, 64) ^ str_repeat(chr(0x5C), 64); + + $inner = pack('H32', md5($k_ipad . $challenge)); + $digest = md5($k_opad . $inner); + + return $digest; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php new file mode 100644 index 00000000..deca3a5d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php @@ -0,0 +1,53 @@ +executeCommand("AUTH LOGIN\r\n", array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), array(334)); + $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php new file mode 100644 index 00000000..fe53057b --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php @@ -0,0 +1,701 @@ + + */ +class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator +{ + const NTLMSIG = "NTLMSSP\x00"; + const DESCONST = "KGS!@#$%"; + + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'NTLM'; + } + + /** + * Try to authenticate the user with $username and $password. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $username + * @param string $password + * + * @return boolean + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password) + { + if (!function_exists('mcrypt_module_open')) { + throw new LogicException('The mcrypt functions need to be enabled to use the NTLM authenticator.'); + } + + if (!function_exists('openssl_random_pseudo_bytes')) { + throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.'); + } + + if (!function_exists('bcmul')) { + throw new LogicException('The BCMatch functions must be enabled to use the NTLM authenticator.'); + } + + try { + // execute AUTH command and filter out the code at the beginning + // AUTH NTLM xxxx + $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4)); + + // extra parameters for our unit cases + $timestamp = func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), "1000")); + $client = func_num_args() > 4 ? func_get_arg(4) : $this->getRandomBytes(8); + + // Message 3 response + $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + protected function si2bin($si, $bits = 32) + { + $bin = null; + if ($si >= -pow(2, $bits - 1) && ($si <= pow(2, $bits - 1))) { + // positive or zero + if ($si >= 0) { + $bin = base_convert($si, 10, 2); + // pad to $bits bit + $bin_length = strlen($bin); + if ($bin_length < $bits) { + $bin = str_repeat("0", $bits - $bin_length) . $bin; + } + } else { // negative + $si = -$si - pow(2, $bits); + $bin = base_convert($si, 10, 2); + $bin_length = strlen($bin); + if ($bin_length > $bits) { + $bin = str_repeat("1", $bits - $bin_length) . $bin; + } + } + } + + return $bin; + } + + /** + * Send our auth message and returns the response + * + * @param Swift_Transport_SmtpAgent $agent + * @return string SMTP Response + */ + protected function sendMessage1(Swift_Transport_SmtpAgent $agent) + { + $message = $this->createMessage1(); + + return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), array(334)); + } + + /** + * Fetch all details of our response (message 2) + * + * @param string $response + * @return array our response parsed + */ + protected function parseMessage2($response) + { + $responseHex = bin2hex($response); + $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2; + $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2; + $challenge = $this->hex2bin(substr($responseHex, 48, 16)); + $context = $this->hex2bin(substr($responseHex, 64, 16)); + $targetInfoH = $this->hex2bin(substr($responseHex, 80, 16)); + $targetName = $this->hex2bin(substr($responseHex, $offset, $length)); + $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2; + $targetInfoBlock = substr($responseHex, $offset); + list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock); + + return array( + $challenge, + $context, + $targetInfoH, + $targetName, + $domainName, + $serverName, + $DNSDomainName, + $DNSServerName, + $this->hex2bin($targetInfoBlock), + $terminatorByte + ); + } + + /** + * Read the blob information in from message2 + * + * @param $block + * @return array + */ + protected function readSubBlock($block) + { + // remove terminatorByte cause it's always the same + $block = substr($block, 0, -8); + + $length = strlen($block); + $offset = 0; + $data = array(); + while ($offset < $length) { + $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256; + $offset += 8; + $data[] = $this->hex2bin(substr($block, $offset, $blockLength * 2)); + $offset += $blockLength * 2; + } + + if (count($data) == 3) { + $data[] = $data[2]; + $data[2] = ''; + } + + $data[] = $this->createByte('00'); + + return $data; + } + + /** + * Send our final message with all our data + * + * @param string $response Message 1 response (message 2) + * @param string $username + * @param string $password + * @param string $timestamp + * @param string $client + * @param Swift_Transport_SmtpAgent $agent + * @param bool $v2 Use version2 of the protocol + * @return string + */ + protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true) + { + list($domain, $username) = $this->getDomainAndUsername($username); + //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter + list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response); + + if (!$v2) { + // LMv1 + $lmResponse = $this->createLMPassword($password, $challenge); + // NTLMv1 + $ntlmResponse = $this->createNTLMPassword($password, $challenge); + } else { + // LMv2 + $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client); + // NTLMv2 + $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client); + } + + $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse); + + return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), array(235)); + } + + /** + * Create our message 1 + * + * @return string + */ + protected function createMessage1() + { + return self::NTLMSIG + . $this->createByte('01') // Message 1 + . $this->createByte('0702'); // Flags + } + + /** + * Create our message 3 + * + * @param string $domain + * @param string $username + * @param string $workstation + * @param string $lmResponse + * @param string $ntlmResponse + * @return string + */ + protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse) + { + // Create security buffers + $domainSec = $this->createSecurityBuffer($domain, 64); + $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec)); + $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2); + $userInfo = $this->readSecurityBuffer(bin2hex($userSec)); + $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2); + $workInfo = $this->readSecurityBuffer(bin2hex($workSec)); + $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true); + $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec)); + $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true); + + return self::NTLMSIG + . $this->createByte('03') // TYPE 3 message + . $lmSec // LM response header + . $ntlmSec // NTLM response header + . $domainSec // Domain header + . $userSec // User header + . $workSec // Workstation header + . $this->createByte("000000009a", 8) // session key header (empty) + . $this->createByte('01020000') // FLAGS + . $this->convertTo16bit($domain) // domain name + . $this->convertTo16bit($username) // username + . $this->convertTo16bit($workstation) // workstation + . $lmResponse + . $ntlmResponse; + } + + /** + * @param string $timestamp Epoch timestamp in microseconds + * @param string $client Random bytes + * @param string $targetInfo + * @return string + */ + protected function createBlob($timestamp, $client, $targetInfo) + { + return $this->createByte('0101') + . $this->createByte('00') + . $timestamp + . $client + . $this->createByte('00') + . $targetInfo + . $this->createByte('00'); + } + + /** + * Get domain and username from our username + * + * @example DOMAIN\username + * + * @param string $name + * @return array + */ + protected function getDomainAndUsername($name) + { + if (strpos($name, '\\') !== false) { + return explode('\\', $name); + } + + list($user, $domain) = explode('@', $name); + + return array($domain, $user); + } + + /** + * Create LMv1 response + * + * @param string $password + * @param string $challenge + * @return string + */ + protected function createLMPassword($password, $challenge) + { + // FIRST PART + $password = $this->createByte(strtoupper($password), 14, false); + list($key1, $key2) = str_split($password, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + + $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1) . $this->desEncrypt(self::DESCONST, $desKey2), 21, false); + + // SECOND PART + list($key1, $key2, $key3) = str_split($constantDecrypt, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1) . $this->desEncrypt($challenge, $desKey2) . $this->desEncrypt($challenge, $desKey3); + } + + /** + * Create NTLMv1 response + * + * @param string $password + * @param string $challenge + * @return string + */ + protected function createNTLMPassword($password, $challenge) + { + // FIRST PART + $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false); + list($key1, $key2, $key3) = str_split($ntlmHash, 7); + + $desKey1 = $this->createDesKey($key1); + $desKey2 = $this->createDesKey($key2); + $desKey3 = $this->createDesKey($key3); + + return $this->desEncrypt($challenge, $desKey1) . $this->desEncrypt($challenge, $desKey2) . $this->desEncrypt($challenge, $desKey3); + } + + /** + * Convert a normal timestamp to a tenth of a microtime epoch time + * + * @param string $time + * @return string + */ + protected function getCorrectTimestamp($time) + { + // Get our timestamp (tricky!) + bcscale(0); + + $time = number_format($time, 0, '.', ''); // save microtime to string + $time = bcadd($time, "11644473600000"); // add epoch time + $time = bcmul($time, 10000); // tenths of a microsecond. + + $binary = $this->si2bin($time, 64); // create 64 bit binary string + $timestamp = ""; + for ($i = 0; $i < 8; $i++) { + $timestamp .= chr(bindec(substr($binary, -(($i + 1) * 8), 8))); + } + + return $timestamp; + } + + /** + * Create LMv2 response + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge NTLM Challenge + * @param string $client Random string + * @return string + */ + protected function createLMv2Password($password, $username, $domain, $challenge, $client) + { + $lmPass = '00'; // by default 00 + // if $password > 15 than we can't use this method + if (strlen($password) <= 15) { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username) . $domain)); + + $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge . $client) . $client); + } + + return $this->createByte($lmPass, 24); + } + + /** + * Create NTLMv2 response + * + * @param string $password + * @param string $username + * @param string $domain + * @param string $challenge Hex values + * @param string $targetInfo Hex values + * @param string $timestamp + * @param string $client Random bytes + * @return string + * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse + */ + protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client) + { + $ntlmHash = $this->md4Encrypt($password); + $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username) . $domain)); + + // create blob + $blob = $this->createBlob($timestamp, $client, $targetInfo); + + $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge . $blob); + + return $ntlmv2Response . $blob; + } + + protected function createDesKey($key) + { + $material = array(bin2hex($key[0])); + $len = strlen($key); + for ($i = 1; $i < $len; $i++) { + list($high, $low) = str_split(bin2hex($key[$i])); + $v = $this->castToByte(ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf) . dechex(hexdec($low) & 0xf)), $i)); + $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte + } + $material[] = str_pad(substr(dechex($this->castToByte(ord($key[6]) << 1)), -2), 2, '0'); + + // odd parity + foreach ($material as $k => $v) { + $b = $this->castToByte(hexdec($v)); + $needsParity = (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5) + ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2) + ^ $this->uRShift($b, 1)) & 0x01) == 0; + + list($high, $low) = str_split($v); + if ($needsParity) { + $material[$k] = dechex(hexdec($high) | 0x0) . dechex(hexdec($low) | 0x1); + } else { + $material[$k] = dechex(hexdec($high) & 0xf) . dechex(hexdec($low) & 0xe); + } + } + + return $this->hex2bin(implode('', $material)); + } + + /** HELPER FUNCTIONS */ + /** + * Create our security buffer depending on length and offset + * + * @param string $value Value we want to put in + * @param int $offset start of value + * @param bool $is16 Do we 16bit string or not? + * @return string + */ + protected function createSecurityBuffer($value, $offset, $is16 = false) + { + $length = strlen(bin2hex($value)); + $length = $is16 ? $length / 2 : $length; + $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2); + + return $length . $length . $this->createByte(dechex($offset), 4); + } + + /** + * Read our security buffer to fetch length and offset of our value + * + * @param string $value Securitybuffer in hex + * @return array array with length and offset + */ + protected function readSecurityBuffer($value) + { + $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2; + $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2; + + return array($length, $offset); + } + + /** + * Cast to byte java equivalent to (byte) + * + * @param int $v + * @return int + */ + protected function castToByte($v) + { + return (($v + 128) % 256) - 128; + } + + /** + * Java unsigned right bitwise + * $a >>> $b + * + * @param int $a + * @param int $b + * @return int + */ + protected function uRShift($a, $b) + { + if ($b == 0) { + return $a; + } + + return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1)); + } + + /** + * Right padding with 0 to certain length + * + * @param string $input + * @param int $bytes Length of bytes + * @param bool $isHex Did we provided hex value + * @return string + */ + protected function createByte($input, $bytes = 4, $isHex = true) + { + if ($isHex) { + $byte = $this->hex2bin(str_pad($input, $bytes * 2, '00')); + } else { + $byte = str_pad($input, $bytes, "\x00"); + } + + return $byte; + } + + /** + * Create random bytes + * + * @param $length + * @return string + */ + protected function getRandomBytes($length) + { + $bytes = openssl_random_pseudo_bytes($length, $strong); + + if (false !== $bytes && true === $strong) { + return $bytes; + } + + throw new RuntimeException('OpenSSL did not produce a secure random number.'); + } + + /** ENCRYPTION ALGORITHMS */ + /** + * DES Encryption + * + * @param string $value + * @param string $key + * @return string + */ + protected function desEncrypt($value, $key) + { + $cipher = mcrypt_module_open(MCRYPT_DES, '', 'ecb', ''); + mcrypt_generic_init($cipher, $key, mcrypt_create_iv(mcrypt_enc_get_iv_size($cipher), MCRYPT_DEV_RANDOM)); + + return mcrypt_generic($cipher, $value); + } + + /** + * MD5 Encryption + * + * @param string $key Encryption key + * @param string $msg Message to encrypt + * @return string + */ + protected function md5Encrypt($key, $msg) + { + $blocksize = 64; + if (strlen($key) > $blocksize) { + $key = pack('H*', md5($key)); + } + + $key = str_pad($key, $blocksize, "\0"); + $ipadk = $key ^ str_repeat("\x36", $blocksize); + $opadk = $key ^ str_repeat("\x5c", $blocksize); + + return pack('H*', md5($opadk . pack('H*', md5($ipadk . $msg)))); + } + + /** + * MD4 Encryption + * + * @param string $input + * @return string + * @see http://php.net/manual/en/ref.hash.php + */ + protected function md4Encrypt($input) + { + $input = $this->convertTo16bit($input); + + return function_exists('hash') ? $this->hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input); + } + + /** + * Convert UTF-8 to UTF-16 + * + * @param string $input + * @return string + */ + protected function convertTo16bit($input) + { + return iconv('UTF-8', 'UTF-16LE', $input); + } + + /** + * Hex2bin replacement for < PHP 5.4 + * @param string $hex + * @return string Binary + */ + protected function hex2bin($hex) + { + if (function_exists('hex2bin')) { + return hex2bin($hex); + } else { + return pack('H*', $hex); + } + } + + /** + * @param string $message + */ + protected function debug($message) + { + $message = bin2hex($message); + $messageId = substr($message, 16, 8); + echo substr($message, 0, 16) . " NTLMSSP Signature
    \n"; + echo $messageId . " Type Indicator
    \n"; + + if ($messageId == "02000000") { + $map = array( + 'Challenge', + 'Context', + 'Target Information Security Buffer', + 'Target Name Data', + 'NetBIOS Domain Name', + 'NetBIOS Server Name', + 'DNS Domain Name', + 'DNS Server Name', + 'BLOB', + 'Target Information Terminator', + ); + + $data = $this->parseMessage2($this->hex2bin($message)); + + foreach ($map as $key => $value) { + echo bin2hex($data[$key]) . ' - ' . $data[$key] . ' ||| ' . $value . "
    \n"; + } + } elseif ($messageId == "03000000") { + $i = 0; + $data[$i++] = substr($message, 24, 16); + list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 40, 16); + list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 56, 16); + list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 72, 16); + list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 88, 16); + list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]); + + $data[$i++] = substr($message, 104, 16); + $data[$i++] = substr($message, 120, 8); + $data[$i++] = substr($message, $targetOffset, $targetLength); + $data[$i++] = substr($message, $userOffset, $userLength); + $data[$i++] = substr($message, $workOffset, $workLength); + $data[$i++] = substr($message, $lmOffset, $lmLength); + $data[$i] = substr($message, $ntmlOffset, $ntmlLength); + + $map = array( + 'LM Response Security Buffer', + 'NTLM Response Security Buffer', + 'Target Name Security Buffer', + 'User Name Security Buffer', + 'Workstation Name Security Buffer', + 'Session Key Security Buffer', + 'Flags', + 'Target Name Data', + 'User Name Data', + 'Workstation Name Data', + 'LM Response Data', + 'NTLM Response Data', + ); + + foreach ($map as $key => $value) { + echo $data[$key] . ' - ' . $this->hex2bin($data[$key]) . ' ||| ' . $value . "
    \n"; + } + } + + echo "

    "; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php new file mode 100644 index 00000000..ffa9af3d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php @@ -0,0 +1,52 @@ +executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php new file mode 100644 index 00000000..2668fd2d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php @@ -0,0 +1,71 @@ + + * $transport = Swift_SmtpTransport::newInstance('smtp.gmail.com', 587, 'tls') + * ->setAuthMode('XOAUTH2') + * ->setUsername('YOUR_EMAIL_ADDRESS') + * ->setPassword('YOUR_ACCESS_TOKEN'); + * + * + * @package Swift + * @subpackage Transport + * @author xu.li + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol + */ +class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator +{ + /** + * Get the name of the AUTH mechanism this Authenticator handles. + * + * @return string + */ + public function getAuthKeyword() + { + return 'XOAUTH2'; + } + + /** + * Try to authenticate the user with $email and $token. + * + * @param Swift_Transport_SmtpAgent $agent + * @param string $email + * @param string $token + * + * @return boolean + */ + public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token) + { + try { + $param = $this->constructXOAuth2Params($email, $token); + $agent->executeCommand("AUTH XOAUTH2 " . $param . "\r\n", array(235)); + + return true; + } catch (Swift_TransportException $e) { + $agent->executeCommand("RSET\r\n", array(250)); + + return false; + } + } + + /** + * Construct the auth parameter + * + * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism + */ + protected function constructXOAuth2Params($email, $token) + { + return base64_encode("user=$email\1auth=Bearer $token\1\1"); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php new file mode 100644 index 00000000..40b0908c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/AuthHandler.php @@ -0,0 +1,268 @@ +setAuthenticators($authenticators); + } + + /** + * Set the Authenticators which can process a login request. + * + * @param Swift_Transport_Esmtp_Authenticator[] $authenticators + */ + public function setAuthenticators(array $authenticators) + { + $this->_authenticators = $authenticators; + } + + /** + * Get the Authenticators which can process a login request. + * + * @return Swift_Transport_Esmtp_Authenticator[] + */ + public function getAuthenticators() + { + return $this->_authenticators; + } + + /** + * Set the username to authenticate with. + * + * @param string $username + */ + public function setUsername($username) + { + $this->_username = $username; + } + + /** + * Get the username to authenticate with. + * + * @return string + */ + public function getUsername() + { + return $this->_username; + } + + /** + * Set the password to authenticate with. + * + * @param string $password + */ + public function setPassword($password) + { + $this->_password = $password; + } + + /** + * Get the password to authenticate with. + * + * @return string + */ + public function getPassword() + { + return $this->_password; + } + + /** + * Set the auth mode to use to authenticate. + * + * @param string $mode + */ + public function setAuthMode($mode) + { + $this->_auth_mode = $mode; + } + + /** + * Get the auth mode to use to authenticate. + * + * @return string + */ + public function getAuthMode() + { + return $this->_auth_mode; + } + + /** + * Get the name of the ESMTP extension this handles. + * + * @return boolean + */ + public function getHandledKeyword() + { + return 'AUTH'; + } + + /** + * Set the parameters which the EHLO greeting indicated. + * + * @param string[] $parameters + */ + public function setKeywordParams(array $parameters) + { + $this->_esmtpParams = $parameters; + } + + /** + * Runs immediately after a EHLO has been issued. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + */ + public function afterEhlo(Swift_Transport_SmtpAgent $agent) + { + if ($this->_username) { + $count = 0; + foreach ($this->_getAuthenticatorsForAgent() as $authenticator) { + if (in_array(strtolower($authenticator->getAuthKeyword()), + array_map('strtolower', $this->_esmtpParams))) + { + $count++; + if ($authenticator->authenticate($agent, $this->_username, $this->_password)) { + return; + } + } + } + throw new Swift_TransportException( + 'Failed to authenticate on SMTP server with username "' . + $this->_username . '" using ' . $count . ' possible authenticators' + ); + } + } + + /** + * Not used. + */ + public function getMailParams() + { + return array(); + } + + /** + * Not used. + */ + public function getRcptParams() + { + return array(); + } + + /** + * Not used. + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false) + { + } + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword) + { + return 0; + } + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods() + { + return array('setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'); + } + + /** + * Not used. + */ + public function resetState() + { + } + + // -- Protected methods + + /** + * Returns the authenticator list for the given agent. + * + * @param Swift_Transport_SmtpAgent $agent + * + * @return array + */ + protected function _getAuthenticatorsForAgent() + { + if (!$mode = strtolower($this->_auth_mode)) { + return $this->_authenticators; + } + + foreach ($this->_authenticators as $authenticator) { + if (strtolower($authenticator->getAuthKeyword()) == $mode) { + return array($authenticator); + } + } + + throw new Swift_TransportException('Auth mode '.$mode.' is invalid'); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php new file mode 100644 index 00000000..0c6dc2e4 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/Esmtp/Authenticator.php @@ -0,0 +1,37 @@ +. + * + * @return string[] + */ + public function getMailParams(); + + /** + * Get params which are appended to RCPT TO:<>. + * + * @return string[] + */ + public function getRcptParams(); + + /** + * Runs when a command is due to be sent. + * + * @param Swift_Transport_SmtpAgent $agent to read/write + * @param string $command to send + * @param int[] $codes expected in response + * @param string[] $failedRecipients to collect failures + * @param boolean $stop to be set true by-reference if the command is now sent + */ + public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = array(), &$failedRecipients = null, &$stop = false); + + /** + * Returns +1, -1 or 0 according to the rules for usort(). + * + * This method is called to ensure extensions can be execute in an appropriate order. + * + * @param string $esmtpKeyword to compare with + * + * @return int + */ + public function getPriorityOver($esmtpKeyword); + + /** + * Returns an array of method names which are exposed to the Esmtp class. + * + * @return string[] + */ + public function exposeMixinMethods(); + + /** + * Tells this handler to clear any buffers and reset its state. + */ + public function resetState(); +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php b/public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php new file mode 100644 index 00000000..744a1270 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/EsmtpTransport.php @@ -0,0 +1,393 @@ + 'tcp', + 'host' => 'localhost', + 'port' => 25, + 'timeout' => 30, + 'blocking' => 1, + 'tls' => false, + 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET + ); + + /** + * Creates a new EsmtpTransport using the given I/O buffer. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Transport_EsmtpHandler[] $extensionHandlers + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + $this->setExtensionHandlers($extensionHandlers); + } + + /** + * Set the host to connect to. + * + * @param string $host + * + * @return Swift_Transport_EsmtpTransport + */ + public function setHost($host) + { + $this->_params['host'] = $host; + + return $this; + } + + /** + * Get the host to connect to. + * + * @return string + */ + public function getHost() + { + return $this->_params['host']; + } + + /** + * Set the port to connect to. + * + * @param integer $port + * + * @return Swift_Transport_EsmtpTransport + */ + public function setPort($port) + { + $this->_params['port'] = (int) $port; + + return $this; + } + + /** + * Get the port to connect to. + * + * @return int + */ + public function getPort() + { + return $this->_params['port']; + } + + /** + * Set the connection timeout. + * + * @param integer $timeout seconds + * + * @return Swift_Transport_EsmtpTransport + */ + public function setTimeout($timeout) + { + $this->_params['timeout'] = (int) $timeout; + $this->_buffer->setParam('timeout', (int) $timeout); + + return $this; + } + + /** + * Get the connection timeout. + * + * @return int + */ + public function getTimeout() + { + return $this->_params['timeout']; + } + + /** + * Set the encryption type (tls or ssl) + * + * @param string $encryption + * + * @return Swift_Transport_EsmtpTransport + */ + public function setEncryption($encryption) + { + if ('tls' == $encryption) { + $this->_params['protocol'] = 'tcp'; + $this->_params['tls'] = true; + } else { + $this->_params['protocol'] = $encryption; + $this->_params['tls'] = false; + } + + return $this; + } + + /** + * Get the encryption type. + * + * @return string + */ + public function getEncryption() + { + return $this->_params['tls'] ? 'tls' : $this->_params['protocol']; + } + + /** + * Sets the source IP. + * + * @param string $source + * + * @return Swift_Transport_EsmtpTransport + */ + public function setSourceIp($source) + { + $this->_params['sourceIp']=$source; + + return $this; + } + + /** + * Returns the IP used to connect to the destination. + * + * @return string + */ + public function getSourceIp() + { + return $this->_params['sourceIp']; + } + + /** + * Set ESMTP extension handlers. + * + * @param Swift_Transport_EsmtpHandler[] $handlers + * + * @return Swift_Transport_EsmtpTransport + */ + public function setExtensionHandlers(array $handlers) + { + $assoc = array(); + foreach ($handlers as $handler) { + $assoc[$handler->getHandledKeyword()] = $handler; + } + uasort($assoc, array($this, '_sortHandlers')); + $this->_handlers = $assoc; + $this->_setHandlerParams(); + + return $this; + } + + /** + * Get ESMTP extension handlers. + * + * @return Swift_Transport_EsmtpHandler[] + */ + public function getExtensionHandlers() + { + return array_values($this->_handlers); + } + + /** + * Run a command against the buffer, expecting the given response codes. + * + * If no response codes are given, the response will not be validated. + * If codes are given, an exception will be thrown on an invalid response. + * + * @param string $command + * @param int[] $codes + * @param string[] $failures An array of failures by-reference + * + * @return string + */ + public function executeCommand($command, $codes = array(), &$failures = null) + { + $failures = (array) $failures; + $stopSignal = false; + $response = null; + foreach ($this->_getActiveHandlers() as $handler) { + $response = $handler->onCommand( + $this, $command, $codes, $failures, $stopSignal + ); + if ($stopSignal) { + return $response; + } + } + + return parent::executeCommand($command, $codes, $failures); + } + + // -- Mixin invocation code + + /** Mixin handling method for ESMTP handlers */ + public function __call($method, $args) + { + foreach ($this->_handlers as $handler) { + if (in_array(strtolower($method), + array_map('strtolower', (array) $handler->exposeMixinMethods()) + )) + { + $return = call_user_func_array(array($handler, $method), $args); + // Allow fluid method calls + if (is_null($return) && substr($method, 0, 3) == 'set') { + return $this; + } else { + return $return; + } + } + } + trigger_error('Call to undefined method ' . $method, E_USER_ERROR); + } + + // -- Protected methods + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } + + /** Overridden to perform EHLO instead */ + protected function _doHeloCommand() + { + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + + if ($this->_params['tls']) { + try { + $this->executeCommand("STARTTLS\r\n", array(220)); + + if (!$this->_buffer->startTLS()) { + throw new Swift_TransportException('Unable to connect with TLS encryption'); + } + + try { + $response = $this->executeCommand( + sprintf("EHLO %s\r\n", $this->_domain), array(250) + ); + } catch (Swift_TransportException $e) { + return parent::_doHeloCommand(); + } + } catch (Swift_TransportException $e) { + $this->_throwException($e); + } + } + + $this->_capabilities = $this->_getCapabilities($response); + $this->_setHandlerParams(); + foreach ($this->_getActiveHandlers() as $handler) { + $handler->afterEhlo($this); + } + } + + /** Overridden to add Extension support */ + protected function _doMailFromCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getMailParams()); + } + $paramStr = !empty($params) ? ' ' . implode(' ', $params) : ''; + $this->executeCommand( + sprintf("MAIL FROM: <%s>%s\r\n", $address, $paramStr), array(250) + ); + } + + /** Overridden to add Extension support */ + protected function _doRcptToCommand($address) + { + $handlers = $this->_getActiveHandlers(); + $params = array(); + foreach ($handlers as $handler) { + $params = array_merge($params, (array) $handler->getRcptParams()); + } + $paramStr = !empty($params) ? ' ' . implode(' ', $params) : ''; + $this->executeCommand( + sprintf("RCPT TO: <%s>%s\r\n", $address, $paramStr), array(250, 251, 252) + ); + } + + // -- Private methods + + /** Determine ESMTP capabilities by function group */ + private function _getCapabilities($ehloResponse) + { + $capabilities = array(); + $ehloResponse = trim($ehloResponse); + $lines = explode("\r\n", $ehloResponse); + array_shift($lines); + foreach ($lines as $line) { + if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) { + $keyword = strtoupper($matches[1]); + $paramStr = strtoupper(ltrim($matches[2], ' =')); + $params = !empty($paramStr) ? explode(' ', $paramStr) : array(); + $capabilities[$keyword] = $params; + } + } + + return $capabilities; + } + + /** Set parameters which are used by each extension handler */ + private function _setHandlerParams() + { + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handler->setKeywordParams($this->_capabilities[$keyword]); + } + } + } + + /** Get ESMTP handlers which are currently ok to use */ + private function _getActiveHandlers() + { + $handlers = array(); + foreach ($this->_handlers as $keyword => $handler) { + if (array_key_exists($keyword, $this->_capabilities)) { + $handlers[] = $handler; + } + } + + return $handlers; + } + + /** Custom sort for extension handler ordering */ + private function _sortHandlers($a, $b) + { + return $a->getPriorityOver($b->getHandledKeyword()); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php b/public/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php new file mode 100644 index 00000000..d0d3f69b --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/FailoverTransport.php @@ -0,0 +1,90 @@ +_transports); + $sent = 0; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) + { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + + return $transport->send($message, $failedRecipients); + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in FailoverTransport failed, or no Transports available' + ); + } + + return $sent; + } + + // -- Protected methods + + protected function _getNextTransport() + { + if (!isset($this->_currentTransport)) { + $this->_currentTransport = parent::_getNextTransport(); + } + + return $this->_currentTransport; + } + + protected function _killCurrentTransport() + { + $this->_currentTransport = null; + parent::_killCurrentTransport(); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php b/public/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php new file mode 100644 index 00000000..7559ebfd --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/IoBuffer.php @@ -0,0 +1,69 @@ +_transports = $transports; + $this->_deadTransports = array(); + } + + /** + * Get $transports to delegate to. + * + * @return Swift_Transport[] + */ + public function getTransports() + { + return array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Test if this Transport mechanism has started. + * + * @return boolean + */ + public function isStarted() + { + return count($this->_transports) > 0; + } + + /** + * Start this Transport mechanism. + */ + public function start() + { + $this->_transports = array_merge($this->_transports, $this->_deadTransports); + } + + /** + * Stop this Transport mechanism. + */ + public function stop() + { + foreach ($this->_transports as $transport) { + $transport->stop(); + } + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $maxTransports = count($this->_transports); + $sent = 0; + + for ($i = 0; $i < $maxTransports + && $transport = $this->_getNextTransport(); ++$i) + { + try { + if (!$transport->isStarted()) { + $transport->start(); + } + if ($sent = $transport->send($message, $failedRecipients)) { + break; + } + } catch (Swift_TransportException $e) { + $this->_killCurrentTransport(); + } + } + + if (count($this->_transports) == 0) { + throw new Swift_TransportException( + 'All Transports in LoadBalancedTransport failed, or no Transports available' + ); + } + + return $sent; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + foreach ($this->_transports as $transport) { + $transport->registerPlugin($plugin); + } + } + + // -- Protected methods + + /** + * Rotates the transport list around and returns the first instance. + * + * @return Swift_Transport + */ + protected function _getNextTransport() + { + if ($next = array_shift($this->_transports)) { + $this->_transports[] = $next; + } + + return $next; + } + + /** + * Tag the currently used (top of stack) transport as dead/useless. + */ + protected function _killCurrentTransport() + { + if ($transport = array_pop($this->_transports)) { + try { + $transport->stop(); + } catch (Exception $e) { + } + $this->_deadTransports[] = $transport; + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php b/public/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php new file mode 100644 index 00000000..a9bff690 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/MailInvoker.php @@ -0,0 +1,34 @@ +_invoker = $invoker; + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Not used. + */ + public function isStarted() + { + return false; + } + + /** + * Not used. + */ + public function start() + { + } + + /** + * Not used. + */ + public function stop() + { + } + + /** + * Set the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @param string $params + * + * @return Swift_Transport_MailTransport + */ + public function setExtraParams($params) + { + $this->_extraParams = $params; + + return $this; + } + + /** + * Get the additional parameters used on the mail() function. + * + * This string is formatted for sprintf() where %s is the sender address. + * + * @return string + */ + public function getExtraParams() + { + return $this->_extraParams; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * The return value is the number of recipients who were accepted for delivery. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $count = ( + count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ); + + $toHeader = $message->getHeaders()->get('To'); + $subjectHeader = $message->getHeaders()->get('Subject'); + + if (!$toHeader) { + throw new Swift_TransportException( + 'Cannot send message without a recipient' + ); + } + $to = $toHeader->getFieldBody(); + $subject = $subjectHeader ? $subjectHeader->getFieldBody() : ''; + + $reversePath = $this->_getReversePath($message); + + // Remove headers that would otherwise be duplicated + $message->getHeaders()->remove('To'); + $message->getHeaders()->remove('Subject'); + + $messageStr = $message->toString(); + + $message->getHeaders()->set($toHeader); + $message->getHeaders()->set($subjectHeader); + + // Separate headers from body + if (false !== $endHeaders = strpos($messageStr, "\r\n\r\n")) { + $headers = substr($messageStr, 0, $endHeaders) . "\r\n"; //Keep last EOL + $body = substr($messageStr, $endHeaders + 4); + } else { + $headers = $messageStr . "\r\n"; + $body = ''; + } + + unset($messageStr); + + if ("\r\n" != PHP_EOL) { + // Non-windows (not using SMTP) + $headers = str_replace("\r\n", PHP_EOL, $headers); + $body = str_replace("\r\n", PHP_EOL, $body); + } else { + // Windows, using SMTP + $headers = str_replace("\r\n.", "\r\n..", $headers); + $body = str_replace("\r\n.", "\r\n..", $body); + } + + if ($this->_invoker->mail($to, $subject, $body, $headers, + sprintf($this->_extraParams, $reversePath))) + { + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + } else { + $failedRecipients = array_merge( + $failedRecipients, + array_keys((array) $message->getTo()), + array_keys((array) $message->getCc()), + array_keys((array) $message->getBcc()) + ); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + + $count = 0; + } + + return $count; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } + + // -- Private methods + + /** Determine the best-use reverse path for this message */ + private function _getReversePath(Swift_Mime_Message $message) + { + $return = $message->getReturnPath(); + $sender = $message->getSender(); + $from = $message->getFrom(); + $path = null; + if (!empty($return)) { + $path = $return; + } elseif (!empty($sender)) { + $keys = array_keys($sender); + $path = array_shift($keys); + } elseif (!empty($from)) { + $keys = array_keys($from); + $path = array_shift($keys); + } + + return $path; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php b/public/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php new file mode 100644 index 00000000..ce136d3c --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/NullTransport.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Pretends messages have been sent, but just ignores them. + * + * @package Swift + * @author Fabien Potencier + */ +class Swift_Transport_NullTransport implements Swift_Transport +{ + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher) + { + $this->_eventDispatcher = $eventDispatcher; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return boolean + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return integer The number of sent emails + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + return 0; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php b/public/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php new file mode 100644 index 00000000..95c2e4a0 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/SendmailTransport.php @@ -0,0 +1,163 @@ + 30, + 'blocking' => 1, + 'command' => '/usr/sbin/sendmail -bs', + 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS + ); + + /** + * Create a new SendmailTransport with $buf for I/O. + * + * @param Swift_Transport_IoBuffer $buf + * @param Swift_Events_EventDispatcher $dispatcher + */ + public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher) + { + parent::__construct($buf, $dispatcher); + } + + /** + * Start the standalone SMTP session if running in -bs mode. + */ + public function start() + { + if (false !== strpos($this->getCommand(), ' -bs')) { + parent::start(); + } + } + + /** + * Set the command to invoke. + * + * If using -t mode you are strongly advised to include -oi or -i in the flags. + * For example: /usr/sbin/sendmail -oi -t + * Swift will append a -f flag if one is not present. + * + * The recommended mode is "-bs" since it is interactive and failure notifications + * are hence possible. + * + * @param string $command + * + * @return Swift_Transport_SendmailTransport + */ + public function setCommand($command) + { + $this->_params['command'] = $command; + + return $this; + } + + /** + * Get the sendmail command which will be invoked. + * + * @return string + */ + public function getCommand() + { + return $this->_params['command']; + } + + /** + * Send the given Message. + * + * Recipient/sender data will be retrieved from the Message API. + * + * The return value is the number of recipients who were accepted for delivery. + * NOTE: If using 'sendmail -t' you will not be aware of any failures until + * they bounce (i.e. send() will always return 100% success). + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return int + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + $failedRecipients = (array) $failedRecipients; + $command = $this->getCommand(); + $buffer = $this->getBuffer(); + + if (false !== strpos($command, ' -t')) { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + if (false === strpos($command, ' -f')) { + $command .= ' -f' . $this->_getReversePath($message); + } + + $buffer->initialize(array_merge($this->_params, array('command' => $command))); + + if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) { + $buffer->setWriteTranslations(array("\r\n" => "\n", "\n." => "\n..")); + } else { + $buffer->setWriteTranslations(array("\r\n"=>"\n")); + } + + $count = count((array) $message->getTo()) + + count((array) $message->getCc()) + + count((array) $message->getBcc()) + ; + $message->toByteStream($buffer); + $buffer->flushBuffers(); + $buffer->setWriteTranslations(array()); + $buffer->terminate(); + + if ($evt) { + $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS); + $evt->setFailedRecipients($failedRecipients); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + $message->generateId(); + } elseif (false !== strpos($command, ' -bs')) { + $count = parent::send($message, $failedRecipients); + } else { + $this->_throwException(new Swift_TransportException( + 'Unsupported sendmail command flags [' . $command . ']. ' . + 'Must be one of "-bs" or "-t" but can include additional flags.' + )); + } + + return $count; + } + + // -- Protected methods + + /** Get the params to initialize the buffer */ + protected function _getBufferParams() + { + return $this->_params; + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php b/public/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php new file mode 100644 index 00000000..91157e5e --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/SimpleMailInvoker.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Stores Messages in a queue. + * + * @package Swift + * @author Fabien Potencier + */ +class Swift_Transport_SpoolTransport implements Swift_Transport +{ + /** The spool instance */ + private $_spool; + + /** The event dispatcher from the plugin API */ + private $_eventDispatcher; + + /** + * Constructor. + */ + public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) + { + $this->_eventDispatcher = $eventDispatcher; + $this->_spool = $spool; + } + + /** + * Sets the spool object. + * + * @param Swift_Spool $spool + * + * @return Swift_Transport_SpoolTransport + */ + public function setSpool(Swift_Spool $spool) + { + $this->_spool = $spool; + + return $this; + } + + /** + * Get the spool object. + * + * @return Swift_Spool + */ + public function getSpool() + { + return $this->_spool; + } + + /** + * Tests if this Transport mechanism has started. + * + * @return boolean + */ + public function isStarted() + { + return true; + } + + /** + * Starts this Transport mechanism. + */ + public function start() + { + } + + /** + * Stops this Transport mechanism. + */ + public function stop() + { + } + + /** + * Sends the given message. + * + * @param Swift_Mime_Message $message + * @param string[] $failedRecipients An array of failures by-reference + * + * @return integer The number of sent e-mail's + */ + public function send(Swift_Mime_Message $message, &$failedRecipients = null) + { + if ($evt = $this->_eventDispatcher->createSendEvent($this, $message)) { + $this->_eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed'); + if ($evt->bubbleCancelled()) { + return 0; + } + } + + $success = $this->_spool->queueMessage($message); + + if ($evt) { + $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SUCCESS : Swift_Events_SendEvent::RESULT_FAILED); + $this->_eventDispatcher->dispatchEvent($evt, 'sendPerformed'); + } + + return 1; + } + + /** + * Register a plugin. + * + * @param Swift_Events_EventListener $plugin + */ + public function registerPlugin(Swift_Events_EventListener $plugin) + { + $this->_eventDispatcher->bindEventListener($plugin); + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php b/public/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php new file mode 100644 index 00000000..0818d85d --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/Transport/StreamBuffer.php @@ -0,0 +1,322 @@ +_replacementFactory = $replacementFactory; + } + + /** + * Perform any initialization needed, using the given $params. + * + * Parameters will vary depending upon the type of IoBuffer used. + * + * @param array $params + */ + public function initialize(array $params) + { + $this->_params = $params; + switch ($params['type']) { + case self::TYPE_PROCESS: + $this->_establishProcessConnection(); + break; + case self::TYPE_SOCKET: + default: + $this->_establishSocketConnection(); + break; + } + } + + /** + * Set an individual param on the buffer (e.g. switching to SSL). + * + * @param string $param + * @param mixed $value + */ + public function setParam($param, $value) + { + if (isset($this->_stream)) { + switch ($param) { + case 'timeout': + if ($this->_stream) { + stream_set_timeout($this->_stream, $value); + } + break; + + case 'blocking': + if ($this->_stream) { + stream_set_blocking($this->_stream, 1); + } + + } + } + $this->_params[$param] = $value; + } + + public function startTLS() + { + return stream_socket_enable_crypto($this->_stream, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); + } + + /** + * Perform any shutdown logic needed. + */ + public function terminate() + { + if (isset($this->_stream)) { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + fclose($this->_in); + fclose($this->_out); + proc_close($this->_stream); + break; + case self::TYPE_SOCKET: + default: + fclose($this->_stream); + break; + } + } + $this->_stream = null; + $this->_out = null; + $this->_in = null; + } + + /** + * Set an array of string replacements which should be made on data written + * to the buffer. + * + * This could replace LF with CRLF for example. + * + * @param string[] $replacements + */ + public function setWriteTranslations(array $replacements) + { + foreach ($this->_translations as $search => $replace) { + if (!isset($replacements[$search])) { + $this->removeFilter($search); + unset($this->_translations[$search]); + } + } + + foreach ($replacements as $search => $replace) { + if (!isset($this->_translations[$search])) { + $this->addFilter( + $this->_replacementFactory->createFilter($search, $replace), $search + ); + $this->_translations[$search] = true; + } + } + } + + /** + * Get a line of output (including any CRLF). + * + * The $sequence number comes from any writes and may or may not be used + * depending upon the implementation. + * + * @param integer $sequence of last write to scan from + * + * @return string + * + * @throws Swift_IoException + */ + public function readLine($sequence) + { + if (isset($this->_out) && !feof($this->_out)) { + $line = fgets($this->_out); + if (strlen($line)==0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to ' . + $this->_getReadConnectionDescription() . + ' Timed Out' + ); + } + } + + return $line; + } + } + + /** + * Reads $length bytes from the stream into a string and moves the pointer + * through the stream by $length. + * + * If less bytes exist than are requested the remaining bytes are given instead. + * If no bytes are remaining at all, boolean false is returned. + * + * @param integer $length + * + * @return string|boolean + * + * @throws Swift_IoException + */ + public function read($length) + { + if (isset($this->_out) && !feof($this->_out)) { + $ret = fread($this->_out, $length); + if (strlen($ret)==0) { + $metas = stream_get_meta_data($this->_out); + if ($metas['timed_out']) { + throw new Swift_IoException( + 'Connection to ' . + $this->_getReadConnectionDescription() . + ' Timed Out' + ); + } + } + + return $ret; + } + } + + /** Not implemented */ + public function setReadPointer($byteOffset) + { + } + + // -- Protected methods + + /** Flush the stream contents */ + protected function _flush() + { + if (isset($this->_in)) { + fflush($this->_in); + } + } + + /** Write this bytes to the stream */ + protected function _commit($bytes) + { + if (isset($this->_in)) { + $bytesToWrite = strlen($bytes); + $totalBytesWritten = 0; + + while ($totalBytesWritten < $bytesToWrite) { + $bytesWriten = fwrite($this->_in, substr($bytes, $totalBytesWritten)); + $totalBytesWritten += $bytesWriten; + } + if ($totalBytesWritten > 0) { + return ++$this->_sequence; + } + } + } + + // -- Private methods + + /** + * Establishes a connection to a remote server. + */ + private function _establishSocketConnection() + { + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'] . '://' . $host; + } + $timeout = 15; + if (!empty($this->_params['timeout'])) { + $timeout = $this->_params['timeout']; + } + $options = array(); + if (!empty($this->_params['sourceIp'])) { + $options['socket']['bindto']=$this->_params['sourceIp'].':0'; + } + $this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options)); + if (false === $this->_stream) { + throw new Swift_TransportException( + 'Connection could not be established with host ' . $this->_params['host'] . + ' [' . $errstr . ' #' . $errno . ']' + ); + } + if (!empty($this->_params['blocking'])) { + stream_set_blocking($this->_stream, 1); + } else { + stream_set_blocking($this->_stream, 0); + } + stream_set_timeout($this->_stream, $timeout); + $this->_in =& $this->_stream; + $this->_out =& $this->_stream; + } + + /** + * Opens a process for input/output. + */ + private function _establishProcessConnection() + { + $command = $this->_params['command']; + $descriptorSpec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ); + $this->_stream = proc_open($command, $descriptorSpec, $pipes); + stream_set_blocking($pipes[2], 0); + if ($err = stream_get_contents($pipes[2])) { + throw new Swift_TransportException( + 'Process could not be started [' . $err . ']' + ); + } + $this->_in =& $pipes[0]; + $this->_out =& $pipes[1]; + } + + private function _getReadConnectionDescription() + { + switch ($this->_params['type']) { + case self::TYPE_PROCESS: + return 'Process '.$this->_params['command']; + break; + + case self::TYPE_SOCKET: + default: + $host = $this->_params['host']; + if (!empty($this->_params['protocol'])) { + $host = $this->_params['protocol'] . '://' . $host; + } + $host.=':'.$this->_params['port']; + + return $host; + break; + } + } +} diff --git a/public/include/lib/swiftmailer/classes/Swift/TransportException.php b/public/include/lib/swiftmailer/classes/Swift/TransportException.php new file mode 100644 index 00000000..48e41d16 --- /dev/null +++ b/public/include/lib/swiftmailer/classes/Swift/TransportException.php @@ -0,0 +1,29 @@ + + */ +class Swift_Validate +{ + /** + * Grammar Object + * + * @var Swift_Mime_Grammar + */ + private static $grammar = null; + + /** + * Checks if an e-mail address matches the current grammars. + * + * @param string $email + * + * @return boolean + */ + public static function email($email) + { + if (self::$grammar===null) { + self::$grammar = Swift_DependencyContainer::getInstance() + ->lookup('mime.grammar'); + } + + return preg_match( + '/^' . self::$grammar->getDefinition('addr-spec') . '$/D', + $email + ); + } +} diff --git a/public/include/lib/swiftmailer/dependency_maps/cache_deps.php b/public/include/lib/swiftmailer/dependency_maps/cache_deps.php new file mode 100644 index 00000000..6023448e --- /dev/null +++ b/public/include/lib/swiftmailer/dependency_maps/cache_deps.php @@ -0,0 +1,23 @@ +register('cache') + ->asAliasOf('cache.array') + + ->register('tempdir') + ->asValue('/tmp') + + ->register('cache.null') + ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache') + + ->register('cache.array') + ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache') + ->withDependencies(array('cache.inputstream')) + + ->register('cache.disk') + ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache') + ->withDependencies(array('cache.inputstream', 'tempdir')) + + ->register('cache.inputstream') + ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream') +; diff --git a/public/include/lib/swiftmailer/dependency_maps/message_deps.php b/public/include/lib/swiftmailer/dependency_maps/message_deps.php new file mode 100644 index 00000000..64d69d21 --- /dev/null +++ b/public/include/lib/swiftmailer/dependency_maps/message_deps.php @@ -0,0 +1,9 @@ +register('message.message') + ->asNewInstanceOf('Swift_Message') + + ->register('message.mimepart') + ->asNewInstanceOf('Swift_MimePart') +; diff --git a/public/include/lib/swiftmailer/dependency_maps/mime_deps.php b/public/include/lib/swiftmailer/dependency_maps/mime_deps.php new file mode 100644 index 00000000..a13472e9 --- /dev/null +++ b/public/include/lib/swiftmailer/dependency_maps/mime_deps.php @@ -0,0 +1,123 @@ +register('properties.charset') + ->asValue('utf-8') + + ->register('mime.grammar') + ->asSharedInstanceOf('Swift_Mime_Grammar') + + ->register('mime.message') + ->asNewInstanceOf('Swift_Mime_SimpleMessage') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset' + )) + + ->register('mime.part') + ->asNewInstanceOf('Swift_Mime_MimePart') + ->withDependencies(array( + 'mime.headerset', + 'mime.qpcontentencoder', + 'cache', + 'mime.grammar', + 'properties.charset' + )) + + ->register('mime.attachment') + ->asNewInstanceOf('Swift_Mime_Attachment') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar' + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.embeddedfile') + ->asNewInstanceOf('Swift_Mime_EmbeddedFile') + ->withDependencies(array( + 'mime.headerset', + 'mime.base64contentencoder', + 'cache', + 'mime.grammar' + )) + ->addConstructorValue($swift_mime_types) + + ->register('mime.headerfactory') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory') + ->withDependencies(array( + 'mime.qpheaderencoder', + 'mime.rfc2231encoder', + 'mime.grammar', + 'properties.charset' + )) + + ->register('mime.headerset') + ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet') + ->withDependencies(array('mime.headerfactory', 'properties.charset')) + + ->register('mime.qpheaderencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.base64headerencoder') + ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder') + ->withDependencies(array('mime.charstream')) + + ->register('mime.charstream') + ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream') + ->withDependencies(array('mime.characterreaderfactory', 'properties.charset')) + + ->register('mime.bytecanonicalizer') + ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter') + ->addConstructorValue(array(array(0x0D, 0x0A), array(0x0D), array(0x0A))) + ->addConstructorValue(array(array(0x0A), array(0x0A), array(0x0D, 0x0A))) + + ->register('mime.characterreaderfactory') + ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory') + + ->register('mime.safeqpcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder') + ->withDependencies(array('mime.charstream', 'mime.bytecanonicalizer')) + + ->register('mime.rawcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder') + + ->register('mime.nativeqpcontentencoder') + ->withDependencies(array('properties.charset')) + ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder') + + ->register('mime.qpcontentencoderproxy') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy') + ->withDependencies(array('mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset')) + + ->register('mime.7bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('7bit') + ->addConstructorValue(true) + + ->register('mime.8bitcontentencoder') + ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder') + ->addConstructorValue('8bit') + ->addConstructorValue(true) + + ->register('mime.base64contentencoder') + ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder') + + ->register('mime.rfc2231encoder') + ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder') + ->withDependencies(array('mime.charstream')) + + // As of PHP 5.4.7, the quoted_printable_encode() function behaves correctly. + // see https://github.com/php/php-src/commit/18bb426587d62f93c54c40bf8535eb8416603629 + ->register('mime.qpcontentencoder') + ->asAliasOf(version_compare(phpversion(), '5.4.7', '>=') ? 'mime.qpcontentencoderproxy' : 'mime.safeqpcontentencoder') +; + +unset($swift_mime_types); diff --git a/public/include/lib/swiftmailer/dependency_maps/transport_deps.php b/public/include/lib/swiftmailer/dependency_maps/transport_deps.php new file mode 100644 index 00000000..56ca0590 --- /dev/null +++ b/public/include/lib/swiftmailer/dependency_maps/transport_deps.php @@ -0,0 +1,76 @@ +register('transport.smtp') + ->asNewInstanceOf('Swift_Transport_EsmtpTransport') + ->withDependencies(array( + 'transport.buffer', + array('transport.authhandler'), + 'transport.eventdispatcher' + )) + + ->register('transport.sendmail') + ->asNewInstanceOf('Swift_Transport_SendmailTransport') + ->withDependencies(array( + 'transport.buffer', + 'transport.eventdispatcher' + )) + + ->register('transport.mail') + ->asNewInstanceOf('Swift_Transport_MailTransport') + ->withDependencies(array('transport.mailinvoker', 'transport.eventdispatcher')) + + ->register('transport.loadbalanced') + ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport') + + ->register('transport.failover') + ->asNewInstanceOf('Swift_Transport_FailoverTransport') + + ->register('transport.spool') + ->asNewInstanceOf('Swift_Transport_SpoolTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.null') + ->asNewInstanceOf('Swift_Transport_NullTransport') + ->withDependencies(array('transport.eventdispatcher')) + + ->register('transport.mailinvoker') + ->asSharedInstanceOf('Swift_Transport_SimpleMailInvoker') + + ->register('transport.buffer') + ->asNewInstanceOf('Swift_Transport_StreamBuffer') + ->withDependencies(array('transport.replacementfactory')) + + ->register('transport.authhandler') + ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler') + ->withDependencies(array( + array( + 'transport.crammd5auth', + 'transport.loginauth', + 'transport.plainauth', + 'transport.ntlmauth', + 'transport.xoauth2auth', + ) + )) + + ->register('transport.crammd5auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator') + + ->register('transport.loginauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator') + + ->register('transport.plainauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator') + + ->register('transport.xoauth2auth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator') + + ->register('transport.ntlmauth') + ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator') + + ->register('transport.eventdispatcher') + ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher') + + ->register('transport.replacementfactory') + ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory') +; diff --git a/public/include/lib/swiftmailer/mime_types.php b/public/include/lib/swiftmailer/mime_types.php new file mode 100644 index 00000000..f31567d6 --- /dev/null +++ b/public/include/lib/swiftmailer/mime_types.php @@ -0,0 +1,1007 @@ + 'text/vnd.in3d.3dml', + '3ds' => 'image/x-3ds', + '3g2' => 'video/3gpp2', + '3gp' => 'video/3gpp', + '7z' => 'application/x-7z-compressed', + 'aab' => 'application/x-authorware-bin', + 'aac' => 'audio/x-aac', + 'aam' => 'application/x-authorware-map', + 'aas' => 'application/x-authorware-seg', + 'abw' => 'application/x-abiword', + 'ac' => 'application/pkix-attr-cert', + 'acc' => 'application/vnd.americandynamics.acc', + 'ace' => 'application/x-ace-compressed', + 'acu' => 'application/vnd.acucobol', + 'acutc' => 'application/vnd.acucorp', + 'adp' => 'audio/adpcm', + 'aep' => 'application/vnd.audiograph', + 'afm' => 'application/x-font-type1', + 'afp' => 'application/vnd.ibm.modcap', + 'ahead' => 'application/vnd.ahead.space', + 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'air' => 'application/vnd.adobe.air-application-installer-package+zip', + 'ait' => 'application/vnd.dvb.ait', + 'ami' => 'application/vnd.amiga.ami', + 'apk' => 'application/vnd.android.package-archive', + 'appcache' => 'text/cache-manifest', + 'apr' => 'application/vnd.lotus-approach', + 'aps' => 'application/postscript', + 'arc' => 'application/x-freearc', + 'asc' => 'application/pgp-signature', + 'asf' => 'video/x-ms-asf', + 'asm' => 'text/x-asm', + 'aso' => 'application/vnd.accpac.simply.aso', + 'asx' => 'video/x-ms-asf', + 'atc' => 'application/vnd.acucorp', + 'atom' => 'application/atom+xml', + 'atomcat' => 'application/atomcat+xml', + 'atomsvc' => 'application/atomsvc+xml', + 'atx' => 'application/vnd.antix.game-component', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', + 'aw' => 'application/applixware', + 'azf' => 'application/vnd.airzip.filesecure.azf', + 'azs' => 'application/vnd.airzip.filesecure.azs', + 'azw' => 'application/vnd.amazon.ebook', + 'bat' => 'application/x-msdownload', + 'bcpio' => 'application/x-bcpio', + 'bdf' => 'application/x-font-bdf', + 'bdm' => 'application/vnd.syncml.dm+wbxml', + 'bed' => 'application/vnd.realvnc.bed', + 'bh2' => 'application/vnd.fujitsu.oasysprs', + 'bin' => 'application/octet-stream', + 'blb' => 'application/x-blorb', + 'blorb' => 'application/x-blorb', + 'bmi' => 'application/vnd.bmi', + 'bmp' => 'image/bmp', + 'book' => 'application/vnd.framemaker', + 'box' => 'application/vnd.previewsystems.box', + 'boz' => 'application/x-bzip2', + 'bpk' => 'application/octet-stream', + 'btif' => 'image/prs.btif', + 'bz' => 'application/x-bzip', + 'bz2' => 'application/x-bzip2', + 'c' => 'text/x-c', + 'c11amc' => 'application/vnd.cluetrust.cartomobile-config', + 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg', + 'c4d' => 'application/vnd.clonk.c4group', + 'c4f' => 'application/vnd.clonk.c4group', + 'c4g' => 'application/vnd.clonk.c4group', + 'c4p' => 'application/vnd.clonk.c4group', + 'c4u' => 'application/vnd.clonk.c4group', + 'cab' => 'application/vnd.ms-cab-compressed', + 'caf' => 'audio/x-caf', + 'cap' => 'application/vnd.tcpdump.pcap', + 'car' => 'application/vnd.curl.car', + 'cat' => 'application/vnd.ms-pki.seccat', + 'cb7' => 'application/x-cbr', + 'cba' => 'application/x-cbr', + 'cbr' => 'application/x-cbr', + 'cbt' => 'application/x-cbr', + 'cbz' => 'application/x-cbr', + 'cc' => 'text/x-c', + 'cct' => 'application/x-director', + 'ccxml' => 'application/ccxml+xml', + 'cdbcmsg' => 'application/vnd.contact.cmsg', + 'cdf' => 'application/x-netcdf', + 'cdkey' => 'application/vnd.mediastation.cdkey', + 'cdmia' => 'application/cdmi-capability', + 'cdmic' => 'application/cdmi-container', + 'cdmid' => 'application/cdmi-domain', + 'cdmio' => 'application/cdmi-object', + 'cdmiq' => 'application/cdmi-queue', + 'cdx' => 'chemical/x-cdx', + 'cdxml' => 'application/vnd.chemdraw+xml', + 'cdy' => 'application/vnd.cinderella', + 'cer' => 'application/pkix-cert', + 'cfs' => 'application/x-cfs-compressed', + 'cgm' => 'image/cgm', + 'chat' => 'application/x-chat', + 'chm' => 'application/vnd.ms-htmlhelp', + 'chrt' => 'application/vnd.kde.kchart', + 'cif' => 'chemical/x-cif', + 'cii' => 'application/vnd.anser-web-certificate-issue-initiation', + 'cil' => 'application/vnd.ms-artgalry', + 'cla' => 'application/vnd.claymore', + 'class' => 'application/java-vm', + 'clkk' => 'application/vnd.crick.clicker.keyboard', + 'clkp' => 'application/vnd.crick.clicker.palette', + 'clkt' => 'application/vnd.crick.clicker.template', + 'clkw' => 'application/vnd.crick.clicker.wordbank', + 'clkx' => 'application/vnd.crick.clicker', + 'clp' => 'application/x-msclip', + 'cmc' => 'application/vnd.cosmocaller', + 'cmdf' => 'chemical/x-cmdf', + 'cml' => 'chemical/x-cml', + 'cmp' => 'application/vnd.yellowriver-custom-menu', + 'cmx' => 'image/x-cmx', + 'cod' => 'application/vnd.rim.cod', + 'com' => 'application/x-msdownload', + 'conf' => 'text/plain', + 'cpio' => 'application/x-cpio', + 'cpp' => 'text/x-c', + 'cpt' => 'application/mac-compactpro', + 'crd' => 'application/x-mscardfile', + 'crl' => 'application/pkix-crl', + 'crt' => 'application/x-x509-ca-cert', + 'csh' => 'application/x-csh', + 'csml' => 'chemical/x-csml', + 'csp' => 'application/vnd.commonspace', + 'css' => 'text/css', + 'cst' => 'application/x-director', + 'csv' => 'text/csv', + 'cu' => 'application/cu-seeme', + 'curl' => 'text/vnd.curl', + 'cww' => 'application/prs.cww', + 'cxt' => 'application/x-director', + 'cxx' => 'text/x-c', + 'dae' => 'model/vnd.collada+xml', + 'daf' => 'application/vnd.mobius.daf', + 'dart' => 'application/vnd.dart', + 'dataless' => 'application/vnd.fdsn.seed', + 'davmount' => 'application/davmount+xml', + 'dbk' => 'application/docbook+xml', + 'dcr' => 'application/x-director', + 'dcurl' => 'text/vnd.curl.dcurl', + 'dd2' => 'application/vnd.oma.dd2+xml', + 'ddd' => 'application/vnd.fujixerox.ddd', + 'deb' => 'application/x-debian-package', + 'def' => 'text/plain', + 'deploy' => 'application/octet-stream', + 'der' => 'application/x-x509-ca-cert', + 'dfac' => 'application/vnd.dreamfactory', + 'dgc' => 'application/x-dgc-compressed', + 'dic' => 'text/x-c', + 'dir' => 'application/x-director', + 'dis' => 'application/vnd.mobius.dis', + 'dist' => 'application/octet-stream', + 'distz' => 'application/octet-stream', + 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/x-msdownload', + 'dmg' => 'application/x-apple-diskimage', + 'dmp' => 'application/vnd.tcpdump.pcap', + 'dms' => 'application/octet-stream', + 'dna' => 'application/vnd.dna', + 'doc' => 'application/msword', + 'docm' => 'application/vnd.ms-word.document.macroenabled.12', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dot' => 'application/msword', + 'dotm' => 'application/vnd.ms-word.template.macroenabled.12', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'dp' => 'application/vnd.osgi.dp', + 'dpg' => 'application/vnd.dpgraph', + 'dra' => 'audio/vnd.dra', + 'dsc' => 'text/prs.lines.tag', + 'dssc' => 'application/dssc+der', + 'dtb' => 'application/x-dtbook+xml', + 'dtd' => 'application/xml-dtd', + 'dts' => 'audio/vnd.dts', + 'dtshd' => 'audio/vnd.dts.hd', + 'dump' => 'application/octet-stream', + 'dvb' => 'video/vnd.dvb.file', + 'dvi' => 'application/x-dvi', + 'dwf' => 'model/vnd.dwf', + 'dwg' => 'image/vnd.dwg', + 'dxf' => 'image/vnd.dxf', + 'dxp' => 'application/vnd.spotfire.dxp', + 'dxr' => 'application/x-director', + 'ecelp4800' => 'audio/vnd.nuera.ecelp4800', + 'ecelp7470' => 'audio/vnd.nuera.ecelp7470', + 'ecelp9600' => 'audio/vnd.nuera.ecelp9600', + 'ecma' => 'application/ecmascript', + 'edm' => 'application/vnd.novadigm.edm', + 'edx' => 'application/vnd.novadigm.edx', + 'efif' => 'application/vnd.picsel', + 'ei6' => 'application/vnd.pg.osasli', + 'elc' => 'application/octet-stream', + 'emf' => 'application/x-msmetafile', + 'eml' => 'message/rfc822', + 'emma' => 'application/emma+xml', + 'emz' => 'application/x-msmetafile', + 'eol' => 'audio/vnd.digital-winds', + 'eot' => 'application/vnd.ms-fontobject', + 'eps' => 'application/postscript', + 'epub' => 'application/epub+zip', + 'es3' => 'application/vnd.eszigno3+xml', + 'esa' => 'application/vnd.osgi.subsystem', + 'esf' => 'application/vnd.epson.esf', + 'et3' => 'application/vnd.eszigno3+xml', + 'etx' => 'text/x-setext', + 'eva' => 'application/x-eva', + 'evy' => 'application/x-envoy', + 'exe' => 'application/x-msdownload', + 'exi' => 'application/exi', + 'ext' => 'application/vnd.novadigm.ext', + 'ez' => 'application/andrew-inset', + 'ez2' => 'application/vnd.ezpix-album', + 'ez3' => 'application/vnd.ezpix-package', + 'f' => 'text/x-fortran', + 'f4v' => 'video/x-f4v', + 'f77' => 'text/x-fortran', + 'f90' => 'text/x-fortran', + 'fbs' => 'image/vnd.fastbidsheet', + 'fcdt' => 'application/vnd.adobe.formscentral.fcdt', + 'fcs' => 'application/vnd.isac.fcs', + 'fdf' => 'application/vnd.fdf', + 'fe_launch' => 'application/vnd.denovo.fcselayout-link', + 'fg5' => 'application/vnd.fujitsu.oasysgp', + 'fgd' => 'application/x-director', + 'fh' => 'image/x-freehand', + 'fh4' => 'image/x-freehand', + 'fh5' => 'image/x-freehand', + 'fh7' => 'image/x-freehand', + 'fhc' => 'image/x-freehand', + 'fig' => 'application/x-xfig', + 'flac' => 'audio/x-flac', + 'fli' => 'video/x-fli', + 'flo' => 'application/vnd.micrografx.flo', + 'flv' => 'video/x-flv', + 'flw' => 'application/vnd.kde.kivio', + 'flx' => 'text/vnd.fmi.flexstor', + 'fly' => 'text/vnd.fly', + 'fm' => 'application/vnd.framemaker', + 'fnc' => 'application/vnd.frogans.fnc', + 'for' => 'text/x-fortran', + 'fpx' => 'image/vnd.fpx', + 'frame' => 'application/vnd.framemaker', + 'fsc' => 'application/vnd.fsc.weblaunch', + 'fst' => 'image/vnd.fst', + 'ftc' => 'application/vnd.fluxtime.clip', + 'fti' => 'application/vnd.anser-web-funds-transfer-initiation', + 'fvt' => 'video/vnd.fvt', + 'fxp' => 'application/vnd.adobe.fxp', + 'fxpl' => 'application/vnd.adobe.fxp', + 'fzs' => 'application/vnd.fuzzysheet', + 'g2w' => 'application/vnd.geoplan', + 'g3' => 'image/g3fax', + 'g3w' => 'application/vnd.geospace', + 'gac' => 'application/vnd.groove-account', + 'gam' => 'application/x-tads', + 'gbr' => 'application/rpki-ghostbusters', + 'gca' => 'application/x-gca-compressed', + 'gdl' => 'model/vnd.gdl', + 'geo' => 'application/vnd.dynageo', + 'gex' => 'application/vnd.geometry-explorer', + 'ggb' => 'application/vnd.geogebra.file', + 'ggt' => 'application/vnd.geogebra.tool', + 'ghf' => 'application/vnd.groove-help', + 'gif' => 'image/gif', + 'gim' => 'application/vnd.groove-identity-message', + 'gml' => 'application/gml+xml', + 'gmx' => 'application/vnd.gmx', + 'gnumeric' => 'application/x-gnumeric', + 'gph' => 'application/vnd.flographit', + 'gpx' => 'application/gpx+xml', + 'gqf' => 'application/vnd.grafeq', + 'gqs' => 'application/vnd.grafeq', + 'gram' => 'application/srgs', + 'gramps' => 'application/x-gramps-xml', + 'gre' => 'application/vnd.geometry-explorer', + 'grv' => 'application/vnd.groove-injector', + 'grxml' => 'application/srgs+xml', + 'gsf' => 'application/x-font-ghostscript', + 'gtar' => 'application/x-gtar', + 'gtm' => 'application/vnd.groove-tool-message', + 'gtw' => 'model/vnd.gtw', + 'gv' => 'text/vnd.graphviz', + 'gxf' => 'application/gxf', + 'gxt' => 'application/vnd.geonext', + 'gz' => 'application/x-gzip', + 'h' => 'text/x-c', + 'h261' => 'video/h261', + 'h263' => 'video/h263', + 'h264' => 'video/h264', + 'hal' => 'application/vnd.hal+xml', + 'hbci' => 'application/vnd.hbci', + 'hdf' => 'application/x-hdf', + 'hh' => 'text/x-c', + 'hlp' => 'application/winhlp', + 'hpgl' => 'application/vnd.hp-hpgl', + 'hpid' => 'application/vnd.hp-hpid', + 'hps' => 'application/vnd.hp-hps', + 'hqx' => 'application/mac-binhex40', + 'htke' => 'application/vnd.kenameaapp', + 'htm' => 'text/html', + 'html' => 'text/html', + 'hvd' => 'application/vnd.yamaha.hv-dic', + 'hvp' => 'application/vnd.yamaha.hv-voice', + 'hvs' => 'application/vnd.yamaha.hv-script', + 'i2g' => 'application/vnd.intergeo', + 'icc' => 'application/vnd.iccprofile', + 'ice' => 'x-conference/x-cooltalk', + 'icm' => 'application/vnd.iccprofile', + 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'ifb' => 'text/calendar', + 'ifm' => 'application/vnd.shana.informed.formdata', + 'iges' => 'model/iges', + 'igl' => 'application/vnd.igloader', + 'igm' => 'application/vnd.insors.igm', + 'igs' => 'model/iges', + 'igx' => 'application/vnd.micrografx.igx', + 'iif' => 'application/vnd.shana.informed.interchange', + 'imp' => 'application/vnd.accpac.simply.imp', + 'ims' => 'application/vnd.ms-ims', + 'in' => 'text/plain', + 'ink' => 'application/inkml+xml', + 'inkml' => 'application/inkml+xml', + 'install' => 'application/x-install-instructions', + 'iota' => 'application/vnd.astraea-software.iota', + 'ipfix' => 'application/ipfix', + 'ipk' => 'application/vnd.shana.informed.package', + 'irm' => 'application/vnd.ibm.rights-management', + 'irp' => 'application/vnd.irepository.package+xml', + 'iso' => 'application/x-iso9660-image', + 'itp' => 'application/vnd.shana.informed.formtemplate', + 'ivp' => 'application/vnd.immervision-ivp', + 'ivu' => 'application/vnd.immervision-ivu', + 'jad' => 'text/vnd.sun.j2me.app-descriptor', + 'jam' => 'application/vnd.jam', + 'jar' => 'application/java-archive', + 'java' => 'text/x-java-source', + 'jisp' => 'application/vnd.jisp', + 'jlt' => 'application/vnd.hp-jlyt', + 'jnlp' => 'application/x-java-jnlp-file', + 'joda' => 'application/vnd.joost.joda-archive', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpgm' => 'video/jpm', + 'jpgv' => 'video/jpeg', + 'jpm' => 'video/jpm', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'jsonml' => 'application/jsonml+json', + 'kar' => 'audio/midi', + 'karbon' => 'application/vnd.kde.karbon', + 'kfo' => 'application/vnd.kde.kformula', + 'kia' => 'application/vnd.kidspiration', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'kne' => 'application/vnd.kinar', + 'knp' => 'application/vnd.kinar', + 'kon' => 'application/vnd.kde.kontour', + 'kpr' => 'application/vnd.kde.kpresenter', + 'kpt' => 'application/vnd.kde.kpresenter', + 'kpxx' => 'application/vnd.ds-keypoint', + 'ksp' => 'application/vnd.kde.kspread', + 'ktr' => 'application/vnd.kahootz', + 'ktx' => 'image/ktx', + 'ktz' => 'application/vnd.kahootz', + 'kwd' => 'application/vnd.kde.kword', + 'kwt' => 'application/vnd.kde.kword', + 'lasxml' => 'application/vnd.las.las+xml', + 'latex' => 'application/x-latex', + 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop', + 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml', + 'les' => 'application/vnd.hhe.lesson-player', + 'lha' => 'application/x-lzh-compressed', + 'link66' => 'application/vnd.route66.link66+xml', + 'list' => 'text/plain', + 'list3820' => 'application/vnd.ibm.modcap', + 'listafp' => 'application/vnd.ibm.modcap', + 'lnk' => 'application/x-ms-shortcut', + 'log' => 'text/plain', + 'lostxml' => 'application/lost+xml', + 'lrf' => 'application/octet-stream', + 'lrm' => 'application/vnd.ms-lrm', + 'ltf' => 'application/vnd.frogans.ltf', + 'lvp' => 'audio/vnd.lucent.voice', + 'lwp' => 'application/vnd.lotus-wordpro', + 'lzh' => 'application/x-lzh-compressed', + 'm13' => 'application/x-msmediaview', + 'm14' => 'application/x-msmediaview', + 'm1v' => 'video/mpeg', + 'm21' => 'application/mp21', + 'm2a' => 'audio/mpeg', + 'm2v' => 'video/mpeg', + 'm3a' => 'audio/mpeg', + 'm3u' => 'audio/x-mpegurl', + 'm3u8' => 'application/vnd.apple.mpegurl', + 'm4a' => 'audio/mp4', + 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', + 'ma' => 'application/mathematica', + 'mads' => 'application/mads+xml', + 'mag' => 'application/vnd.ecowin.chart', + 'maker' => 'application/vnd.framemaker', + 'man' => 'text/troff', + 'mar' => 'application/octet-stream', + 'mathml' => 'application/mathml+xml', + 'mb' => 'application/mathematica', + 'mbk' => 'application/vnd.mobius.mbk', + 'mbox' => 'application/mbox', + 'mc1' => 'application/vnd.medcalcdata', + 'mcd' => 'application/vnd.mcd', + 'mcurl' => 'text/vnd.curl.mcurl', + 'mdb' => 'application/x-msaccess', + 'mdi' => 'image/vnd.ms-modi', + 'me' => 'text/troff', + 'mesh' => 'model/mesh', + 'meta4' => 'application/metalink4+xml', + 'metalink' => 'application/metalink+xml', + 'mets' => 'application/mets+xml', + 'mfm' => 'application/vnd.mfmp', + 'mft' => 'application/rpki-manifest', + 'mgp' => 'application/vnd.osgeo.mapguide.package', + 'mgz' => 'application/vnd.proteus.magazine', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mie' => 'application/x-mie', + 'mif' => 'application/vnd.mif', + 'mime' => 'message/rfc822', + 'mj2' => 'video/mj2', + 'mjp2' => 'video/mj2', + 'mk3d' => 'video/x-matroska', + 'mka' => 'audio/x-matroska', + 'mks' => 'video/x-matroska', + 'mkv' => 'video/x-matroska', + 'mlp' => 'application/vnd.dolby.mlp', + 'mmd' => 'application/vnd.chipnuts.karaoke-mmd', + 'mmf' => 'application/vnd.smaf', + 'mmr' => 'image/vnd.fujixerox.edmics-mmr', + 'mng' => 'video/x-mng', + 'mny' => 'application/x-msmoney', + 'mobi' => 'application/x-mobipocket-ebook', + 'mods' => 'application/mods+xml', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp21' => 'application/mp21', + 'mp2a' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mp4a' => 'audio/mp4', + 'mp4s' => 'application/mp4', + 'mp4v' => 'video/mp4', + 'mpc' => 'application/vnd.mophun.certificate', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpg4' => 'video/mp4', + 'mpga' => 'audio/mpeg', + 'mpkg' => 'application/vnd.apple.installer+xml', + 'mpm' => 'application/vnd.blueice.multipass', + 'mpn' => 'application/vnd.mophun.application', + 'mpp' => 'application/vnd.ms-project', + 'mpt' => 'application/vnd.ms-project', + 'mpy' => 'application/vnd.ibm.minipay', + 'mqy' => 'application/vnd.mobius.mqy', + 'mrc' => 'application/marc', + 'mrcx' => 'application/marcxml+xml', + 'ms' => 'text/troff', + 'mscml' => 'application/mediaservercontrol+xml', + 'mseed' => 'application/vnd.fdsn.mseed', + 'mseq' => 'application/vnd.mseq', + 'msf' => 'application/vnd.epson.msf', + 'msh' => 'model/mesh', + 'msi' => 'application/x-msdownload', + 'msl' => 'application/vnd.mobius.msl', + 'msty' => 'application/vnd.muvee.style', + 'mts' => 'model/vnd.mts', + 'mus' => 'application/vnd.musician', + 'musicxml' => 'application/vnd.recordare.musicxml+xml', + 'mvb' => 'application/x-msmediaview', + 'mwf' => 'application/vnd.mfer', + 'mxf' => 'application/mxf', + 'mxl' => 'application/vnd.recordare.musicxml', + 'mxml' => 'application/xv+xml', + 'mxs' => 'application/vnd.triscape.mxs', + 'mxu' => 'video/vnd.mpegurl', + 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install', + 'n3' => 'text/n3', + 'nb' => 'application/mathematica', + 'nbp' => 'application/vnd.wolfram.player', + 'nc' => 'application/x-netcdf', + 'ncx' => 'application/x-dtbncx+xml', + 'nfo' => 'text/x-nfo', + 'ngdat' => 'application/vnd.nokia.n-gage.data', + 'nitf' => 'application/vnd.nitf', + 'nlu' => 'application/vnd.neurolanguage.nlu', + 'nml' => 'application/vnd.enliven', + 'nnd' => 'application/vnd.noblenet-directory', + 'nns' => 'application/vnd.noblenet-sealer', + 'nnw' => 'application/vnd.noblenet-web', + 'npx' => 'image/vnd.net-fpx', + 'nsc' => 'application/x-conference', + 'nsf' => 'application/vnd.lotus-notes', + 'ntf' => 'application/vnd.nitf', + 'nzb' => 'application/x-nzb', + 'oa2' => 'application/vnd.fujitsu.oasys2', + 'oa3' => 'application/vnd.fujitsu.oasys3', + 'oas' => 'application/vnd.fujitsu.oasys', + 'obd' => 'application/x-msbinder', + 'obj' => 'application/x-tgif', + 'oda' => 'application/oda', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odft' => 'application/vnd.oasis.opendocument.formula-template', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', + 'ogx' => 'application/ogg', + 'omdoc' => 'application/omdoc+xml', + 'onepkg' => 'application/onenote', + 'onetmp' => 'application/onenote', + 'onetoc' => 'application/onenote', + 'onetoc2' => 'application/onenote', + 'opf' => 'application/oebps-package+xml', + 'opml' => 'text/x-opml', + 'oprc' => 'application/vnd.palm', + 'org' => 'application/vnd.lotus-organizer', + 'osf' => 'application/vnd.yamaha.openscoreformat', + 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml', + 'otc' => 'application/vnd.oasis.opendocument.chart-template', + 'otf' => 'application/x-font-otf', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'oti' => 'application/vnd.oasis.opendocument.image-template', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oxps' => 'application/oxps', + 'oxt' => 'application/vnd.openofficeorg.extension', + 'p' => 'text/x-pascal', + 'p10' => 'application/pkcs10', + 'p12' => 'application/x-pkcs12', + 'p7b' => 'application/x-pkcs7-certificates', + 'p7c' => 'application/pkcs7-mime', + 'p7m' => 'application/pkcs7-mime', + 'p7r' => 'application/x-pkcs7-certreqresp', + 'p7s' => 'application/pkcs7-signature', + 'p8' => 'application/pkcs8', + 'pas' => 'text/x-pascal', + 'paw' => 'application/vnd.pawaafile', + 'pbd' => 'application/vnd.powerbuilder6', + 'pbm' => 'image/x-portable-bitmap', + 'pcap' => 'application/vnd.tcpdump.pcap', + 'pcf' => 'application/x-font-pcf', + 'pcl' => 'application/vnd.hp-pcl', + 'pclxl' => 'application/vnd.hp-pclxl', + 'pct' => 'image/x-pict', + 'pcurl' => 'application/vnd.curl.pcurl', + 'pcx' => 'image/x-pcx', + 'pdb' => 'application/vnd.palm', + 'pdf' => 'application/pdf', + 'pfa' => 'application/x-font-type1', + 'pfb' => 'application/x-font-type1', + 'pfm' => 'application/x-font-type1', + 'pfr' => 'application/font-tdpfr', + 'pfx' => 'application/x-pkcs12', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', + 'pgp' => 'application/pgp-encrypted', + 'php' => 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'pic' => 'image/x-pict', + 'pkg' => 'application/octet-stream', + 'pki' => 'application/pkixcmp', + 'pkipath' => 'application/pkix-pkipath', + 'plb' => 'application/vnd.3gpp.pic-bw-large', + 'plc' => 'application/vnd.mobius.plc', + 'plf' => 'application/vnd.pocketlearn', + 'pls' => 'application/pls+xml', + 'pml' => 'application/vnd.ctc-posml', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'portpkg' => 'application/vnd.macports.portpkg', + 'pot' => 'application/vnd.ms-powerpoint', + 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12', + 'ppd' => 'application/vnd.cups-ppd', + 'ppm' => 'image/x-portable-pixmap', + 'pps' => 'application/vnd.ms-powerpoint', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'pqa' => 'application/vnd.palm', + 'prc' => 'application/x-mobipocket-ebook', + 'pre' => 'application/vnd.lotus-freelance', + 'prf' => 'application/pics-rules', + 'ps' => 'application/postscript', + 'psb' => 'application/vnd.3gpp.pic-bw-small', + 'psd' => 'image/vnd.adobe.photoshop', + 'psf' => 'application/x-font-linux-psf', + 'pskcxml' => 'application/pskc+xml', + 'ptid' => 'application/vnd.pvi.ptid1', + 'pub' => 'application/x-mspublisher', + 'pvb' => 'application/vnd.3gpp.pic-bw-var', + 'pwn' => 'application/vnd.3m.post-it-notes', + 'pya' => 'audio/vnd.ms-playready.media.pya', + 'pyv' => 'video/vnd.ms-playready.media.pyv', + 'qam' => 'application/vnd.epson.quickanime', + 'qbo' => 'application/vnd.intu.qbo', + 'qfx' => 'application/vnd.intu.qfx', + 'qps' => 'application/vnd.publishare-delta-tree', + 'qt' => 'video/quicktime', + 'qwd' => 'application/vnd.quark.quarkxpress', + 'qwt' => 'application/vnd.quark.quarkxpress', + 'qxb' => 'application/vnd.quark.quarkxpress', + 'qxd' => 'application/vnd.quark.quarkxpress', + 'qxl' => 'application/vnd.quark.quarkxpress', + 'qxt' => 'application/vnd.quark.quarkxpress', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rar' => 'application/x-rar-compressed', + 'ras' => 'image/x-cmu-raster', + 'rcprofile' => 'application/vnd.ipunplugged.rcprofile', + 'rdf' => 'application/rdf+xml', + 'rdz' => 'application/vnd.data-vision.rdz', + 'rep' => 'application/vnd.businessobjects', + 'res' => 'application/x-dtbresource+xml', + 'rgb' => 'image/x-rgb', + 'rif' => 'application/reginfo+xml', + 'rip' => 'audio/vnd.rip', + 'ris' => 'application/x-research-info-systems', + 'rl' => 'application/resource-lists+xml', + 'rlc' => 'image/vnd.fujixerox.edmics-rlc', + 'rld' => 'application/resource-lists-diff+xml', + 'rm' => 'application/vnd.rn-realmedia', + 'rmi' => 'audio/midi', + 'rmp' => 'audio/x-pn-realaudio-plugin', + 'rms' => 'application/vnd.jcp.javame.midlet-rms', + 'rmvb' => 'application/vnd.rn-realmedia-vbr', + 'rnc' => 'application/relax-ng-compact-syntax', + 'roa' => 'application/rpki-roa', + 'roff' => 'text/troff', + 'rp9' => 'application/vnd.cloanto.rp9', + 'rpss' => 'application/vnd.nokia.radio-presets', + 'rpst' => 'application/vnd.nokia.radio-preset', + 'rq' => 'application/sparql-query', + 'rs' => 'application/rls-services+xml', + 'rsd' => 'application/rsd+xml', + 'rss' => 'application/rss+xml', + 'rtf' => 'application/rtf', + 'rtx' => 'text/richtext', + 's' => 'text/x-asm', + 's3m' => 'audio/s3m', + 'saf' => 'application/vnd.yamaha.smaf-audio', + 'sbml' => 'application/sbml+xml', + 'sc' => 'application/vnd.ibm.secure-container', + 'scd' => 'application/x-msschedule', + 'scm' => 'application/vnd.lotus-screencam', + 'scq' => 'application/scvp-cv-request', + 'scs' => 'application/scvp-cv-response', + 'scurl' => 'text/vnd.curl.scurl', + 'sda' => 'application/vnd.stardivision.draw', + 'sdc' => 'application/vnd.stardivision.calc', + 'sdd' => 'application/vnd.stardivision.impress', + 'sdkd' => 'application/vnd.solent.sdkm+xml', + 'sdkm' => 'application/vnd.solent.sdkm+xml', + 'sdp' => 'application/sdp', + 'sdw' => 'application/vnd.stardivision.writer', + 'see' => 'application/vnd.seemail', + 'seed' => 'application/vnd.fdsn.seed', + 'sema' => 'application/vnd.sema', + 'semd' => 'application/vnd.semd', + 'semf' => 'application/vnd.semf', + 'ser' => 'application/java-serialized-object', + 'setpay' => 'application/set-payment-initiation', + 'setreg' => 'application/set-registration-initiation', + 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data', + 'sfs' => 'application/vnd.spotfire.sfs', + 'sfv' => 'text/x-sfv', + 'sgi' => 'image/sgi', + 'sgl' => 'application/vnd.stardivision.writer-global', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'shf' => 'application/shf+xml', + 'sid' => 'image/x-mrsid-image', + 'sig' => 'application/pgp-signature', + 'sil' => 'audio/silk', + 'silo' => 'model/mesh', + 'sis' => 'application/vnd.symbian.install', + 'sisx' => 'application/vnd.symbian.install', + 'sit' => 'application/x-stuffit', + 'sitx' => 'application/x-stuffitx', + 'skd' => 'application/vnd.koan', + 'skm' => 'application/vnd.koan', + 'skp' => 'application/vnd.koan', + 'skt' => 'application/vnd.koan', + 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12', + 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', + 'slt' => 'application/vnd.epson.salt', + 'sm' => 'application/vnd.stepmania.stepchart', + 'smf' => 'application/vnd.stardivision.math', + 'smi' => 'application/smil+xml', + 'smil' => 'application/smil+xml', + 'smv' => 'video/x-smv', + 'smzip' => 'application/vnd.stepmania.package', + 'snd' => 'audio/basic', + 'snf' => 'application/x-font-snf', + 'so' => 'application/octet-stream', + 'spc' => 'application/x-pkcs7-certificates', + 'spf' => 'application/vnd.yamaha.smaf-phrase', + 'spl' => 'application/x-futuresplash', + 'spot' => 'text/vnd.in3d.spot', + 'spp' => 'application/scvp-vp-response', + 'spq' => 'application/scvp-vp-request', + 'spx' => 'audio/ogg', + 'sql' => 'application/x-sql', + 'src' => 'application/x-wais-source', + 'srt' => 'application/x-subrip', + 'sru' => 'application/sru+xml', + 'srx' => 'application/sparql-results+xml', + 'ssdl' => 'application/ssdl+xml', + 'sse' => 'application/vnd.kodak-descriptor', + 'ssf' => 'application/vnd.epson.ssf', + 'ssml' => 'application/ssml+xml', + 'st' => 'application/vnd.sailingtracker.track', + 'stc' => 'application/vnd.sun.xml.calc.template', + 'std' => 'application/vnd.sun.xml.draw.template', + 'stf' => 'application/vnd.wt.stf', + 'sti' => 'application/vnd.sun.xml.impress.template', + 'stk' => 'application/hyperstudio', + 'stl' => 'application/vnd.ms-pki.stl', + 'str' => 'application/vnd.pg.format', + 'stw' => 'application/vnd.sun.xml.writer.template', + 'sub' => 'text/vnd.dvb.subtitle', + 'sus' => 'application/vnd.sus-calendar', + 'susp' => 'application/vnd.sus-calendar', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'svc' => 'application/vnd.dvb.service', + 'svd' => 'application/vnd.svd', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + 'swa' => 'application/x-director', + 'swf' => 'application/x-shockwave-flash', + 'swi' => 'application/vnd.aristanetworks.swi', + 'sxc' => 'application/vnd.sun.xml.calc', + 'sxd' => 'application/vnd.sun.xml.draw', + 'sxg' => 'application/vnd.sun.xml.writer.global', + 'sxi' => 'application/vnd.sun.xml.impress', + 'sxm' => 'application/vnd.sun.xml.math', + 'sxw' => 'application/vnd.sun.xml.writer', + 't' => 'text/troff', + 't3' => 'application/x-t3vm-image', + 'taglet' => 'application/vnd.mynfc', + 'tao' => 'application/vnd.tao.intent-module-archive', + 'tar' => 'application/x-tar', + 'tcap' => 'application/vnd.3gpp2.tcap', + 'tcl' => 'application/x-tcl', + 'teacher' => 'application/vnd.smart.teacher', + 'tei' => 'application/tei+xml', + 'teicorpus' => 'application/tei+xml', + 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tfi' => 'application/thraud+xml', + 'tfm' => 'application/x-tex-tfm', + 'tga' => 'image/x-tga', + 'thmx' => 'application/vnd.ms-officetheme', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tmo' => 'application/vnd.tmobile-livetv', + 'torrent' => 'application/x-bittorrent', + 'tpl' => 'application/vnd.groove-tool-template', + 'tpt' => 'application/vnd.trid.tpt', + 'tr' => 'text/troff', + 'tra' => 'application/vnd.trueapp', + 'trm' => 'application/x-msterminal', + 'tsd' => 'application/timestamped-data', + 'tsv' => 'text/tab-separated-values', + 'ttc' => 'application/x-font-ttf', + 'ttf' => 'application/x-font-ttf', + 'ttl' => 'text/turtle', + 'twd' => 'application/vnd.simtech-mindmapper', + 'twds' => 'application/vnd.simtech-mindmapper', + 'txd' => 'application/vnd.genomatix.tuxedo', + 'txf' => 'application/vnd.mobius.txf', + 'txt' => 'text/plain', + 'u32' => 'application/x-authorware-bin', + 'udeb' => 'application/x-debian-package', + 'ufd' => 'application/vnd.ufdl', + 'ufdl' => 'application/vnd.ufdl', + 'ulx' => 'application/x-glulx', + 'umj' => 'application/vnd.umajin', + 'unityweb' => 'application/vnd.unity', + 'uoml' => 'application/vnd.uoml+xml', + 'uri' => 'text/uri-list', + 'uris' => 'text/uri-list', + 'urls' => 'text/uri-list', + 'ustar' => 'application/x-ustar', + 'utz' => 'application/vnd.uiq.theme', + 'uu' => 'text/x-uuencode', + 'uva' => 'audio/vnd.dece.audio', + 'uvd' => 'application/vnd.dece.data', + 'uvf' => 'application/vnd.dece.data', + 'uvg' => 'image/vnd.dece.graphic', + 'uvh' => 'video/vnd.dece.hd', + 'uvi' => 'image/vnd.dece.graphic', + 'uvm' => 'video/vnd.dece.mobile', + 'uvp' => 'video/vnd.dece.pd', + 'uvs' => 'video/vnd.dece.sd', + 'uvt' => 'application/vnd.dece.ttml+xml', + 'uvu' => 'video/vnd.uvvu.mp4', + 'uvv' => 'video/vnd.dece.video', + 'uvva' => 'audio/vnd.dece.audio', + 'uvvd' => 'application/vnd.dece.data', + 'uvvf' => 'application/vnd.dece.data', + 'uvvg' => 'image/vnd.dece.graphic', + 'uvvh' => 'video/vnd.dece.hd', + 'uvvi' => 'image/vnd.dece.graphic', + 'uvvm' => 'video/vnd.dece.mobile', + 'uvvp' => 'video/vnd.dece.pd', + 'uvvs' => 'video/vnd.dece.sd', + 'uvvt' => 'application/vnd.dece.ttml+xml', + 'uvvu' => 'video/vnd.uvvu.mp4', + 'uvvv' => 'video/vnd.dece.video', + 'uvvx' => 'application/vnd.dece.unspecified', + 'uvvz' => 'application/vnd.dece.zip', + 'uvx' => 'application/vnd.dece.unspecified', + 'uvz' => 'application/vnd.dece.zip', + 'vcard' => 'text/vcard', + 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', + 'vcg' => 'application/vnd.groove-vcard', + 'vcs' => 'text/x-vcalendar', + 'vcx' => 'application/vnd.vcx', + 'vis' => 'application/vnd.visionary', + 'viv' => 'video/vnd.vivo', + 'vob' => 'video/x-ms-vob', + 'vor' => 'application/vnd.stardivision.writer', + 'vox' => 'application/x-authorware-bin', + 'vrml' => 'model/vrml', + 'vsd' => 'application/vnd.visio', + 'vsf' => 'application/vnd.vsf', + 'vss' => 'application/vnd.visio', + 'vst' => 'application/vnd.visio', + 'vsw' => 'application/vnd.visio', + 'vtu' => 'model/vnd.vtu', + 'vxml' => 'application/voicexml+xml', + 'w3d' => 'application/x-director', + 'wad' => 'application/x-doom', + 'wav' => 'audio/x-wav', + 'wax' => 'audio/x-ms-wax', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbs' => 'application/vnd.criticaltools.wbs+xml', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wcm' => 'application/vnd.ms-works', + 'wdb' => 'application/vnd.ms-works', + 'wdp' => 'image/vnd.ms-photo', + 'weba' => 'audio/webm', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wg' => 'application/vnd.pmi.widget', + 'wgt' => 'application/widget', + 'wks' => 'application/vnd.ms-works', + 'wm' => 'video/x-ms-wm', + 'wma' => 'audio/x-ms-wma', + 'wmd' => 'application/x-ms-wmd', + 'wmf' => 'application/x-msmetafile', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', + 'wmx' => 'video/x-ms-wmx', + 'wmz' => 'application/x-msmetafile', + 'woff' => 'application/font-woff', + 'wpd' => 'application/vnd.wordperfect', + 'wpl' => 'application/vnd.ms-wpl', + 'wps' => 'application/vnd.ms-works', + 'wqd' => 'application/vnd.wqd', + 'wri' => 'application/x-mswrite', + 'wrl' => 'model/vrml', + 'wsdl' => 'application/wsdl+xml', + 'wspolicy' => 'application/wspolicy+xml', + 'wtb' => 'application/vnd.webturbo', + 'wvx' => 'video/x-ms-wvx', + 'x32' => 'application/x-authorware-bin', + 'x3d' => 'model/x3d+xml', + 'x3db' => 'model/x3d+binary', + 'x3dbz' => 'model/x3d+binary', + 'x3dv' => 'model/x3d+vrml', + 'x3dvz' => 'model/x3d+vrml', + 'x3dz' => 'model/x3d+xml', + 'xaml' => 'application/xaml+xml', + 'xap' => 'application/x-silverlight-app', + 'xar' => 'application/vnd.xara', + 'xbap' => 'application/x-ms-xbap', + 'xbd' => 'application/vnd.fujixerox.docuworks.binder', + 'xbm' => 'image/x-xbitmap', + 'xdf' => 'application/xcap-diff+xml', + 'xdm' => 'application/vnd.syncml.dm+xml', + 'xdp' => 'application/vnd.adobe.xdp+xml', + 'xdssc' => 'application/dssc+xml', + 'xdw' => 'application/vnd.fujixerox.docuworks', + 'xenc' => 'application/xenc+xml', + 'xer' => 'application/patch-ops-error+xml', + 'xfdf' => 'application/vnd.adobe.xfdf', + 'xfdl' => 'application/vnd.xfdl', + 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xhvml' => 'application/xv+xml', + 'xif' => 'image/vnd.xiff', + 'xla' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12', + 'xlc' => 'application/vnd.ms-excel', + 'xlf' => 'application/x-xliff+xml', + 'xlm' => 'application/vnd.ms-excel', + 'xls' => 'application/vnd.ms-excel', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xlt' => 'application/vnd.ms-excel', + 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'xlw' => 'application/vnd.ms-excel', + 'xm' => 'audio/xm', + 'xml' => 'application/xml', + 'xo' => 'application/vnd.olpc-sugar', + 'xop' => 'application/xop+xml', + 'xpi' => 'application/x-xpinstall', + 'xpl' => 'application/xproc+xml', + 'xpm' => 'image/x-xpixmap', + 'xpr' => 'application/vnd.is-xpr', + 'xps' => 'application/vnd.ms-xpsdocument', + 'xpw' => 'application/vnd.intercon.formnet', + 'xpx' => 'application/vnd.intercon.formnet', + 'xsl' => 'application/xml', + 'xslt' => 'application/xslt+xml', + 'xsm' => 'application/vnd.syncml+xml', + 'xspf' => 'application/xspf+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xvm' => 'application/xv+xml', + 'xvml' => 'application/xv+xml', + 'xwd' => 'image/x-xwindowdump', + 'xyz' => 'chemical/x-xyz', + 'xz' => 'application/x-xz', + 'yang' => 'application/yang', + 'yin' => 'application/yin+xml', + 'z1' => 'application/x-zmachine', + 'z2' => 'application/x-zmachine', + 'z3' => 'application/x-zmachine', + 'z4' => 'application/x-zmachine', + 'z5' => 'application/x-zmachine', + 'z6' => 'application/x-zmachine', + 'z7' => 'application/x-zmachine', + 'z8' => 'application/x-zmachine', + 'zaz' => 'application/vnd.zzazz.deck+xml', + 'zip' => 'application/zip', + 'zir' => 'application/vnd.zul', + 'zirz' => 'application/vnd.zul', + 'zmm' => 'application/vnd.handheld-entertainment+xml', + '123' => 'application/vnd.lotus-1-2-3' +); diff --git a/public/include/lib/swiftmailer/preferences.php b/public/include/lib/swiftmailer/preferences.php new file mode 100644 index 00000000..42239437 --- /dev/null +++ b/public/include/lib/swiftmailer/preferences.php @@ -0,0 +1,35 @@ +setCharset('utf-8'); + +// Without these lines the default caching mechanism is "array" but this uses a lot of memory. +// If possible, use a disk cache to enable attaching large attachments etc. +// You can override the default temporary directory by setting the TMPDIR environment variable. + +// The @ operator in front of is_writable calls is to avoid PHP warnings +// when using open_basedir +$tmp = getenv('TMPDIR'); +if ($tmp && @is_writable($tmp)) { + $preferences + ->setTempDir($tmp) + ->setCacheType('disk'); +} elseif (function_exists('sys_get_temp_dir') && @is_writable(sys_get_temp_dir())) { + $preferences + ->setTempDir(sys_get_temp_dir()) + ->setCacheType('disk'); +} + +// this should only be done when Swiftmailer won't use the native QP content encoder +// see mime_deps.php +if (version_compare(phpversion(), '5.4.7', '<')) { + $preferences->setQPDotEscape(false); +} diff --git a/public/include/lib/swiftmailer/swift_init.php b/public/include/lib/swiftmailer/swift_init.php new file mode 100644 index 00000000..5c80b05c --- /dev/null +++ b/public/include/lib/swiftmailer/swift_init.php @@ -0,0 +1,28 @@ + 'application/x-php', + 'php3' => 'application/x-php', + 'php4' => 'application/x-php', + 'php5' => 'application/x-php', + 'pdf' => 'application/pdf', + 'zip' => 'application/zip', + 'gif' => 'image/gif', + 'jpg' => 'image/jpeg', + 'png' => 'image/png', + 'css' => 'text/css', + 'html' => 'text/html', + 'js' => 'text/javascript', + 'txt' => 'text/plain', + 'xml' => 'text/xml', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'avi' => 'video/avi', + 'bmp' => 'image/bmp', + 'bz2' => 'application/x-bz2', + 'csv' => 'text/csv', + 'dmg' => 'application/x-apple-diskimage', + 'doc' => 'application/msword', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'eml' => 'message/rfc822', + 'aps' => 'application/postscript', + 'exe' => 'application/x-ms-dos-executable', + 'flv' => 'video/x-flv', + 'gif' => 'image/gif', + 'gz' => 'application/x-gzip', + 'hqx' => 'application/stuffit', + 'htm' => 'text/html', + 'html' => 'text/html', + 'jar' => 'application/x-java-archive', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'm3u' => 'audio/x-mpegurl', + 'm4a' => 'audio/mp4', + 'mdb' => 'application/x-msaccess', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mov' => 'video/quicktime', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'odg' => 'vnd.oasis.opendocument.graphics', + 'odp' => 'vnd.oasis.opendocument.presentation', + 'odt' => 'vnd.oasis.opendocument.text', + 'ods' => 'vnd.oasis.opendocument.spreadsheet', + 'ogg' => 'audio/ogg', + 'pdf' => 'application/pdf', + 'png' => 'image/png', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'ps' => 'application/postscript', + 'rar' => 'application/x-rar-compressed', + 'rtf' => 'application/rtf', + 'tar' => 'application/x-tar', + 'sit' => 'application/x-stuffit', + 'svg' => 'image/svg+xml', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'ttf' => 'application/x-font-truetype', + 'txt' => 'text/plain', + 'vcf' => 'text/x-vcard', + 'wav' => 'audio/wav', + 'wma' => 'audio/x-ms-wma', + 'wmv' => 'audio/x-ms-wmv', + 'xls' => 'application/excel', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xml' => 'application/xml', + 'zip' => 'application/zip' + ]; + + // wrap array for generating file + foreach ($valid_mime_types_preset as $extension => $mime_type) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + + // collect extensions + $valid_extensions = []; + + // all extensions from second match + foreach ($matches[2] as $i => $extensions) { + // explode multiple extensions from string + $extensions = explode(" ", strtolower($extensions)); + + // force array for foreach + if (!is_array($extensions)) { + $extensions = array($extensions); + } + + foreach ($extensions as $extension) { + // get mime type + $mime_type = $matches[1][$i]; + + // check if string length lower than 10 + if (strlen($extension) < 10) { + // add extension + $valid_extensions[] = $extension; + + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + } + } + + $xml = simplexml_load_string($mime_xml); + + foreach ($xml as $node) { + // check if there is no pattern + if (!isset($node->glob["pattern"])) { + continue; + } + + // get all matching extensions from match + foreach ((array) $node->glob["pattern"] as $extension) { + // skip none glob extensions + if (strpos($extension, '.') === FALSE) { + continue; + } + + // remove get only last part + $extension = explode('.', strtolower($extension)); + $extension = end($extension); + + // maximum length in database column + if (strlen($extension) <= 9) { + $valid_extensions[] = $extension; + } + } + + if (isset($node->glob["pattern"][0])) { + // mime type + $mime_type = strtolower((string) $node["type"]); + + // get first extension + $extension = strtolower(trim($node->glob["ddpattern"][0], '*.')); + + // skip none glob extensions and check if string length between 1 and 10 + if (strpos($extension, '.') !== FALSE || strlen($extension) < 1 || strlen($extension) > 9) { + continue; + } + + // check if string length lower than 10 + if (!isset($valid_mime_types[$mime_type])) { + // generate array for mimetype to extension resolver (only first match) + $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'"; + } + } + } + + // full list of valid extensions only + $valid_mime_types = array_unique($valid_mime_types); + ksort($valid_mime_types); + + // combine mime types and extensions array + $output = "$preamble\$swift_mime_types = array(\n ".implode($valid_mime_types, ",\n ")."\n);"; + + // write mime_types.php config file + @file_put_contents('./mime_types.php', $output); +} + +generateUpToDateMimeArray(); diff --git a/public/include/pages/about/chat.inc.php b/public/include/pages/about/chat.inc.php index a5150163..db20159b 100644 --- a/public/include/pages/about/chat.inc.php +++ b/public/include/pages/about/chat.inc.php @@ -14,7 +14,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); break; } diff --git a/public/include/pages/about/moot.inc.php b/public/include/pages/about/moot.inc.php new file mode 100644 index 00000000..595c8f5e --- /dev/null +++ b/public/include/pages/about/moot.inc.php @@ -0,0 +1,20 @@ +getValue('acl_moot_forum', 2)) { +case '0': + if ($user->isAuthenticated()) { + $smarty->assign('CHATROOM', $setting->getValue('system_moot_forum', 'lazypoolop')); + $smarty->assign("CONTENT", "default.tpl"); + } + break; +case '1': + $smarty->assign('CHATROOM', $setting->getValue('system_moot_forum', 'lazypoolop')); + $smarty->assign("CONTENT", "default.tpl"); + break; +case '2': + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); + $smarty->assign("CONTENT", "disabled.tpl"); + break; +} diff --git a/public/include/pages/about/pool.inc.php b/public/include/pages/about/pool.inc.php index c6c54342..ef599375 100644 --- a/public/include/pages/about/pool.inc.php +++ b/public/include/pages/about/pool.inc.php @@ -12,7 +12,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); break; } diff --git a/public/include/pages/account/confirm.inc.php b/public/include/pages/account/confirm.inc.php index 6d175281..61d741e7 100644 --- a/public/include/pages/account/confirm.inc.php +++ b/public/include/pages/account/confirm.inc.php @@ -3,9 +3,9 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // Confirm an account by token if (!isset($_GET['token']) || empty($_GET['token'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Missing token', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Missing token', 'TYPE' => 'danger'); } else if (!$aToken = $oToken->getToken($_GET['token'], 'confirm_email')) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to activate your account. Invalid token.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to activate your account. Invalid token.', 'TYPE' => 'alert alert-danger'); } else { $user->setLocked($aToken['account_id'], 0); $oToken->deleteToken($aToken['token']); diff --git a/public/include/pages/account/earnings.inc.php b/public/include/pages/account/earnings.inc.php new file mode 100644 index 00000000..c4fe7015 --- /dev/null +++ b/public/include/pages/account/earnings.inc.php @@ -0,0 +1,21 @@ +isAuthenticated()) { + if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { + $iLimit = 30; + $debug->append('No cached version available, fetching from backend', 3); + if (!$setting->getValue('disable_transactionsummary')) { + $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'); +?> diff --git a/public/include/pages/account/edit.inc.php b/public/include/pages/account/edit.inc.php index cde09a77..951face4 100644 --- a/public/include/pages/account/edit.inc.php +++ b/public/include/pages/account/edit.inc.php @@ -12,68 +12,70 @@ $updating = (@$_POST['do']) ? 1 : 0; if ($user->isAuthenticated()) { if ($config['twofactor']['enabled']) { - $popupmsg = 'E-mail confirmations are required for '; - $popuptypes = array(); - if ($config['twofactor']['options']['details'] && $oldtoken_ea !== "") { - $popuptypes[] = 'editing your details'; - $ea_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $oldtoken_ea, 5); - $ea_sent = $user->token->doesTokenExist('account_edit', $_SESSION['USERDATA']['id']); - } - if ($config['twofactor']['options']['changepw'] && $oldtoken_cp !== "") { - $popuptypes[] = 'changing your password'; - $cp_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $oldtoken_cp, 6); - $cp_sent = $user->token->doesTokenExist('change_pw', $_SESSION['USERDATA']['id']); - } - if ($config['twofactor']['options']['withdraw'] && $oldtoken_wf !== "") { - $popuptypes[] = 'withdrawals'; - $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 '; - $messages_tokensent_status = array( - 'ea' => 'edit your account details', - 'wf' => 'withdraw funds', - 'cp' => 'change your password' - ); - // build the message we're going to show them for their token(s) - $eaprep_sent = ($ea_sent) ? $message_tokensent_valid.$messages_tokensent_status['ea'] : ""; - $eaprep_edit = ($ea_editable) ? $message_tokensent_invalid.$messages_tokensent_status['ea'] : ""; - $wfprep_sent = ($wf_sent) ? $message_tokensent_valid.$messages_tokensent_status['wf'] : ""; - $wfprep_edit = ($wf_editable) ? $message_tokensent_invalid.$messages_tokensent_status['wf'] : ""; - $cpprep_sent = ($cp_sent) ? $message_tokensent_valid.$messages_tokensent_status['cp'] : ""; - $cpprep_edit = ($cp_editable) ? $message_tokensent_invalid.$messages_tokensent_status['cp'] : ""; - $ptc = 0; - $ptcn = count($popuptypes); - foreach ($popuptypes as $pt) { - if ($ptcn == 1) { $popupmsg.= $popuptypes[$ptc]; continue; } - if ($ptc !== ($ptcn-1)) { - $popupmsg.= $popuptypes[$ptc].', '; - } else { - $popupmsg.= 'and '.$popuptypes[$ptc]; + if ($config['twofactor']['options']['details'] OR $config['twofactor']['options']['changepw'] OR $config['twofactor']['options']['withdraw']) { + $popupmsg = 'E-mail confirmations are required for '; + $popuptypes = array(); + if ($config['twofactor']['options']['details'] && $oldtoken_ea !== "") { + $popuptypes[] = 'editing your details'; + $ea_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $oldtoken_ea, 5); + $ea_sent = $user->token->doesTokenExist('account_edit', $_SESSION['USERDATA']['id']); } - $ptc++; + if ($config['twofactor']['options']['changepw'] && $oldtoken_cp !== "") { + $popuptypes[] = 'changing your password'; + $cp_editable = $user->token->isTokenValid($_SESSION['USERDATA']['id'], $oldtoken_cp, 6); + $cp_sent = $user->token->doesTokenExist('change_pw', $_SESSION['USERDATA']['id']); + } + if ($config['twofactor']['options']['withdraw'] && $oldtoken_wf !== "") { + $popuptypes[] = 'withdrawals'; + $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 '; + $messages_tokensent_status = array( + 'ea' => 'edit your account details', + 'wf' => 'withdraw funds', + 'cp' => 'change your password' + ); + // build the message we're going to show them for their token(s) + $eaprep_sent = ($ea_sent) ? $message_tokensent_valid.$messages_tokensent_status['ea'] : ""; + $eaprep_edit = ($ea_editable) ? $message_tokensent_invalid.$messages_tokensent_status['ea'] : ""; + $wfprep_sent = ($wf_sent) ? $message_tokensent_valid.$messages_tokensent_status['wf'] : ""; + $wfprep_edit = ($wf_editable) ? $message_tokensent_invalid.$messages_tokensent_status['wf'] : ""; + $cpprep_sent = ($cp_sent) ? $message_tokensent_valid.$messages_tokensent_status['cp'] : ""; + $cpprep_edit = ($cp_editable) ? $message_tokensent_invalid.$messages_tokensent_status['cp'] : ""; + $ptc = 0; + $ptcn = count($popuptypes); + foreach ($popuptypes as $pt) { + if ($ptcn == 1) { $popupmsg.= $popuptypes[$ptc]; continue; } + if ($ptc !== ($ptcn-1)) { + $popupmsg.= $popuptypes[$ptc].', '; + } else { + $popupmsg.= 'and '.$popuptypes[$ptc]; + } + $ptc++; + } + // display global notice about tokens being in use and for which bits they're active + $_SESSION['POPUP'][] = array('CONTENT' => $popupmsg, 'TYPE' => 'alert alert-warning'); } - // display global notice about tokens being in use and for which bits they're active - $_SESSION['POPUP'][] = array('CONTENT' => $popupmsg, 'TYPE' => 'info'); } if (isset($_POST['do']) && $_POST['do'] == 'genPin') { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($user->generatePin($_SESSION['USERDATA']['id'], $_POST['currentPassword'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Your PIN # has been sent to your email.', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Your PIN # has been sent to your email.', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } else { if ( @$_POST['do'] && !$user->checkPin($_SESSION['USERDATA']['id'], @$_POST['authPin'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN. ' . ($config['maxfailed']['pin'] - $user->getUserPinFailed($_SESSION['USERDATA']['id'])) . ' attempts remaining.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid PIN. ' . ($config['maxfailed']['pin'] - $user->getUserPinFailed($_SESSION['USERDATA']['id'])) . ' attempts remaining.', 'TYPE' => 'alert alert-danger'); } else { if (isset($_POST['unlock']) && isset($_POST['utype'])) { $validtypes = array('account_edit','change_pw','withdraw_funds'); @@ -83,24 +85,26 @@ if ($user->isAuthenticated()) { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { $send = $user->sendChangeConfigEmail($ctype, $_SESSION['USERDATA']['id']); if ($send) { - $_SESSION['POPUP'][] = array('CONTENT' => 'A confirmation was sent to your e-mail, follow that link to continue', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'A confirmation was sent to your e-mail, follow that link to continue', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } } else { switch (@$_POST['do']) { case 'cashOut': + $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']); + $dBalance = $aBalance['confirmed']; if ($setting->getValue('disable_payouts') == 1 || $setting->getValue('disable_manual_payouts') == 1) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Manual payouts are disabled.', 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Manual payouts are disabled.', 'TYPE' => 'alert alert-warning'); + } 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'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You have no payout address set.', 'TYPE' => 'alert alert-danger'); } else { - $aBalance = $transaction->getBalance($_SESSION['USERDATA']['id']); - $dBalance = $aBalance['confirmed']; $user->log->log("info", $_SESSION['USERDATA']['username']." requesting manual payout"); if ($dBalance > $config['txfee_manual']) { if (!$oPayout->isPayoutActive($_SESSION['USERDATA']['id'])) { @@ -108,16 +112,16 @@ if ($user->isAuthenticated()) { if ($iPayoutId = $oPayout->createPayout($_SESSION['USERDATA']['id'], $oldtoken_wf)) { $_SESSION['POPUP'][] = array('CONTENT' => 'Created new manual payout request with ID #' . $iPayoutId); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $iPayoutId->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $iPayoutId->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'You already have one active manual payout request.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You already have one active manual payout request.', 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee_manual'] . ' ' . $config['currency'] . ' to cover transaction fees', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Insufficient funds, you need more than ' . $config['txfee_manual'] . ' ' . $config['currency'] . ' to cover transaction fees', 'TYPE' => 'alert alert-danger'); } } break; @@ -125,24 +129,24 @@ if ($user->isAuthenticated()) { 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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Account details updated', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to update your account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } break; case 'updatePassword': 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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Password updated', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } break; } @@ -172,12 +176,12 @@ if ($config['twofactor']['enabled'] && $user->isAuthenticated()) { } // display token info per each - only when sent and editable or just sent, not by default - (!empty($eaprep_sent) && !empty($eaprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $eaprep_sent, 'TYPE' => 'success'):""; - (!empty($eaprep_sent) && empty($eaprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['ea'], 'TYPE' => 'success'):""; - (!empty($wfprep_sent) && !empty($wfprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $wfprep_sent, 'TYPE' => 'success'):""; - (!empty($wfprep_sent) && empty($wfprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['wf'], 'TYPE' => 'success'):""; - (!empty($cpprep_sent) && !empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $cpprep_sent, 'TYPE' => 'success'):""; - (!empty($cpprep_sent) && empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['cp'], 'TYPE' => 'success'):""; + (!empty($eaprep_sent) && !empty($eaprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $eaprep_sent, 'TYPE' => 'alert alert-success'):""; + (!empty($eaprep_sent) && empty($eaprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['ea'], 'TYPE' => 'alert alert-success'):""; + (!empty($wfprep_sent) && !empty($wfprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $wfprep_sent, 'TYPE' => 'alert alert-success'):""; + (!empty($wfprep_sent) && empty($wfprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['wf'], 'TYPE' => 'alert alert-success'):""; + (!empty($cpprep_sent) && !empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $cpprep_sent, 'TYPE' => 'alert alert-success'):""; + (!empty($cpprep_sent) && empty($cpprep_edit)) ? $_SESSION['POPUP'][] = array('CONTENT' => $message_tokensent_invalid.$messages_tokensent_status['cp'], 'TYPE' => 'alert alert-success'):""; // two-factor stuff $smarty->assign("CHANGEPASSUNLOCKED", $cp_editable); $smarty->assign("WITHDRAWUNLOCKED", $wf_editable); diff --git a/public/include/pages/account/invitations.inc.php b/public/include/pages/account/invitations.inc.php index 4020cfd1..627b4f46 100644 --- a/public/include/pages/account/invitations.inc.php +++ b/public/include/pages/account/invitations.inc.php @@ -4,23 +4,23 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($user->isAuthenticated()) { if (!$setting->getValue('disable_invitations')) { if ($invitation->getCountInvitations($_SESSION['USERDATA']['id']) >= $config['accounts']['invitations']['count']) { - $_SESSION['POPUP'][] = array('CONTENT' => 'You have exceeded the allowed invitations of ' . $config['accounts']['invitations']['count'], 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You have exceeded the allowed invitations of ' . $config['accounts']['invitations']['count'], 'TYPE' => 'alert alert-danger'); } else if (isset($_POST['do']) && $_POST['do'] == 'sendInvitation') { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($invitation->sendInvitation($_SESSION['USERDATA']['id'], $_POST['data'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Invitation sent', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Invitation sent', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to send invitation to recipient: ' . $invitation->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to send invitation to recipient: ' . $invitation->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } $aInvitations = $invitation->getInvitations($_SESSION['USERDATA']['id']); $smarty->assign('INVITATIONS', $aInvitations); } else { $aInvitations = array(); - $_SESSION['POPUP'][] = array('CONTENT' => 'Invitations are disabled', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Invitations are disabled', 'TYPE' => 'alert alert-danger'); } } $smarty->assign('CONTENT', 'default.tpl'); diff --git a/public/include/pages/account/notifications.inc.php b/public/include/pages/account/notifications.inc.php old mode 100755 new mode 100644 index 5fbf0355..f06c796a --- a/public/include/pages/account/notifications.inc.php +++ b/public/include/pages/account/notifications.inc.php @@ -3,27 +3,29 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($user->isAuthenticated()) { if ($setting->getValue('disable_notifications') == 1) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Notification system disabled by admin.', 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Notification system disabled by admin.', 'TYPE' => 'alert alert-warning'); $smarty->assign('CONTENT', 'empty'); } else { if (@$_REQUEST['do'] == 'save') { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($notification->updateSettings($_SESSION['USERDATA']['id'], $_REQUEST['data'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Updated notification settings', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $notification->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $notification->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } // Fetch notifications $aNotifications = $notification->getNotifications($_SESSION['USERDATA']['id']); - if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'errormsg'); + if (!$aNotifications) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any notifications', 'TYPE' => 'alert alert-danger'); // Fetch global settings $smarty->assign('DISABLE_BLOCKNOTIFICATIONS', $setting->getValue('notifications_disable_block')); + $smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); + $smarty->assign('DISABLE_POOLNEWSLETTER', $setting->getValue('notifications_disable_pool_newsletter')); // Fetch user notification settings $aSettings = $notification->getNotificationSettings($_SESSION['USERDATA']['id']); diff --git a/public/include/pages/account/qrcode.inc.php b/public/include/pages/account/qrcode.inc.php index 3171ded7..6e30b898 100644 --- a/public/include/pages/account/qrcode.inc.php +++ b/public/include/pages/account/qrcode.inc.php @@ -1,5 +1,15 @@ isAuthenticated()) $smarty->assign("CONTENT", "default.tpl"); +switch($setting->getValue('acl_qrcode')) { +case '0': + if ($user->isAuthenticated()) { + $smarty->assign("CONTENT", "default.tpl"); + } + break; +case '1': + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); + $smarty->assign("CONTENT", ""); + break; +} ?> diff --git a/public/include/pages/account/transactions.inc.php b/public/include/pages/account/transactions.inc.php index 4509b399..afe405ac 100644 --- a/public/include/pages/account/transactions.inc.php +++ b/public/include/pages/account/transactions.inc.php @@ -6,11 +6,8 @@ if ($user->isAuthenticated()) { empty($_REQUEST['start']) ? $start = 0 : $start = $_REQUEST['start']; $aTransactions = $transaction->getTransactions($start, @$_REQUEST['filter'], $iLimit, $_SESSION['USERDATA']['id']); $aTransactionTypes = $transaction->getTypes(); - if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg'); - if (!$setting->getValue('disable_transactionsummary')) { - $aTransactionSummary = $transaction->getTransactionSummary($_SESSION['USERDATA']['id']); - $smarty->assign('SUMMARY', $aTransactionSummary); - } + if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'alert alert-danger'); + $smarty->assign('LIMIT', $iLimit); $smarty->assign('TRANSACTIONS', $aTransactions); $smarty->assign('TRANSACTIONTYPES', $aTransactionTypes); diff --git a/public/include/pages/account/unlock.inc.php b/public/include/pages/account/unlock.inc.php index caeaa5b4..1aa83fca 100644 --- a/public/include/pages/account/unlock.inc.php +++ b/public/include/pages/account/unlock.inc.php @@ -3,15 +3,15 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // Confirm an account by token if (!isset($_GET['token']) || empty($_GET['token'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Missing token', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Missing token', 'TYPE' => 'alert alert-danger'); } else if (!$aToken = $oToken->getToken($_GET['token'], 'account_unlock')) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to re-activate your account. Invalid token.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to re-activate your account. Invalid token.', 'TYPE' => 'alert alert-danger'); } else { if ($user->setUserFailed($aToken['account_id'], 0) && $user->setUserPinFailed($aToken['account_id'], 0) && $user->setLocked($aToken['account_id'], 0)) { $oToken->deleteToken($aToken['token']); $_SESSION['POPUP'][] = array('CONTENT' => 'Account re-activated. Please login.'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to re-activate account. Contact site support.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to re-activate account. Contact site support.', 'TYPE' => 'alert alert-danger'); } } $smarty->assign('CONTENT', 'default.tpl'); diff --git a/public/include/pages/account/workers.inc.php b/public/include/pages/account/workers.inc.php index e85623f1..2284aa41 100644 --- a/public/include/pages/account/workers.inc.php +++ b/public/include/pages/account/workers.inc.php @@ -6,42 +6,43 @@ if ($user->isAuthenticated()) { 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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker removed', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker added', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Worker updated', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $worker->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_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' => 'errormsg'); + if (!$aWorkers) $_SESSION['POPUP'][] = array('CONTENT' => 'You have no workers configured', 'TYPE' => 'alert alert-danger'); $smarty->assign('WORKERS', $aWorkers); } diff --git a/public/include/pages/admin/dashboard.inc.php b/public/include/pages/admin/dashboard.inc.php index 5496c158..d5ab1bdc 100644 --- a/public/include/pages/admin/dashboard.inc.php +++ b/public/include/pages/admin/dashboard.inc.php @@ -11,7 +11,7 @@ if ($bitcoin->can_connect() === true){ $aGetInfo = $bitcoin->getinfo(); } else { $aGetInfo = array('errors' => 'Unable to connect'); - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'alert alert-danger'); } // Fetch version information diff --git a/public/include/pages/admin/news.inc.php b/public/include/pages/admin/news.inc.php index 36734294..197bdba5 100644 --- a/public/include/pages/admin/news.inc.php +++ b/public/include/pages/admin/news.inc.php @@ -12,21 +12,21 @@ use \Michelf\Markdown; if (@$_REQUEST['do'] == 'toggle_active') if ($news->toggleActive($_REQUEST['id'])) - $_SESSION['POPUP'][] = array('CONTENT' => 'News entry changed', 'TYPE' => 'success'); + $_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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'News entry added', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to add new entry: ' . $news->getError(), 'TYPE' => 'errormsg'); + $_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' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Succesfully removed news entry', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to delete entry: ' . $news->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to delete entry: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); } } diff --git a/public/include/pages/admin/news_edit.inc.php b/public/include/pages/admin/news_edit.inc.php index 8549533b..8b21c0e5 100644 --- a/public/include/pages/admin/news_edit.inc.php +++ b/public/include/pages/admin/news_edit.inc.php @@ -14,7 +14,7 @@ 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' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'News update failed: ' . $news->getError(), 'TYPE' => 'alert alert-danger'); } } diff --git a/public/include/pages/admin/newsletter.inc.php b/public/include/pages/admin/newsletter.inc.php new file mode 100644 index 00000000..69204b01 --- /dev/null +++ b/public/include/pages/admin/newsletter.inc.php @@ -0,0 +1,41 @@ +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 ($setting->getValue('notifications_disable_pool_newsletter', 0) == 1) { + $_SESSION['POPUP'][] = array('CONTENT' => 'Pool newsletters are disabled.', 'TYPE' => 'alert alert-info'); + $smarty->assign("CONTENT", ""); +} else { + if (@$_REQUEST['do'] == 'send') { + if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { + $iFailed = 0; + $iSuccess = 0; + foreach ($user->getAllAssoc() as $aData) { + $aUserNotificationSettings = $notification->getNotificationSettings($aData['id']); + if ($aData['is_locked'] != 0 || $aUserNotificationSettings['newsletter'] != 1) continue; + $aData['subject'] = $_REQUEST['data']['subject']; + $aData['CONTENT'] = $_REQUEST['data']['content']; + if (!$mail->sendMail('newsletter/body', $aData, true)) { + $iFailed++; + } else { + $iSuccess++; + } + } + $_SESSION['POPUP'][] = array('CONTENT' => 'Newsletter sent to ' . $iSuccess . ' users.', 'TYPE' => 'alert alert-success'); + if ($iFailed > 0) + $_SESSION['POPUP'][] = array('CONTENT' => 'Failed to send e-mail to ' . $iFailed . ' users. ', 'TYPE' => 'alert alert-info'); + } else { + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); + } + } + $smarty->assign("CONTENT", "default.tpl"); +} +?> diff --git a/public/include/pages/admin/poolworkers.inc.php b/public/include/pages/admin/poolworkers.inc.php index 24cb675c..8d80314a 100644 --- a/public/include/pages/admin/poolworkers.inc.php +++ b/public/include/pages/admin/poolworkers.inc.php @@ -15,6 +15,7 @@ empty($_REQUEST['start']) ? $start = 0 : $start = $_REQUEST['start']; $aWorkers = $worker->getAllWorkers($iLimit, $interval, $start); +$smarty->assign('DISABLE_IDLEWORKERNOTIFICATIONS', $setting->getValue('notifications_disable_idle_worker')); $smarty->assign('LIMIT', $iLimit); $smarty->assign('WORKERS', $aWorkers); $smarty->assign('CONTENT', 'default.tpl'); diff --git a/public/include/pages/admin/reports.inc.php b/public/include/pages/admin/reports.inc.php index 3139234c..1723fd2f 100644 --- a/public/include/pages/admin/reports.inc.php +++ b/public/include/pages/admin/reports.inc.php @@ -28,24 +28,24 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $iLimit = 1000; } - if (@$_REQUEST['next'] && !empty($_REQUEST['height'])) { - $iHeight = @$roundstats->getNextBlockForStats($_REQUEST['height'], $iLimit); - if (!$iHeight) { - $aBlock = $block->getLast(); - $iHeight = $aBlock['height']; - } - } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height'])) { - $iHeight = $_REQUEST['height']; - } else if (!empty($_REQUEST['height']) && is_numeric($_REQUEST['height'])) { - $iHeight = $_REQUEST['height']; - } else { - $aBlock = $block->getLast(); - $iHeight = $aBlock['height']; - } - if (@$_REQUEST['search']) { $iHeight = $roundstats->searchForBlockHeight($_REQUEST['search']); } + if (@$_REQUEST['next'] && !empty($_REQUEST['height'])) { + $iHeight = @$roundstats->getNextBlock($_REQUEST['height']); + if (!$iHeight) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } + } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height'])) { + $iHeight = $roundstats->getPreviousBlock($_REQUEST['height']); + } else if (empty($_REQUEST['height'])) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } else { + $iHeight = $_REQUEST['height']; + } + $_REQUEST['height'] = $iHeight; if (@$_REQUEST['filter']) { $filter = $_REQUEST['filter']; @@ -65,13 +65,13 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { } } - $smarty->assign('REPORTDATA', $aBlocksData); - $smarty->assign("USERLIST", $aUserList); - $smarty->assign("USERNAME", $userName); - $smarty->assign("USERID", $iUserId); - $smarty->assign("BLOCKLIMIT", $iLimit); - $smarty->assign("HEIGHT", $iHeight); - $smarty->assign("FILTER", $filter); + $smarty->assign('REPORTDATA', $aBlocksData); + $smarty->assign("USERLIST", $aUserList); + $smarty->assign("USERNAME", $userName); + $smarty->assign("USERID", $iUserId); + $smarty->assign("BLOCKLIMIT", $iLimit); + $smarty->assign("HEIGHT", $iHeight); + $smarty->assign("FILTER", $filter); } else { $debug->append('Using cached page', 3); } diff --git a/public/include/pages/admin/settings.inc.php b/public/include/pages/admin/settings.inc.php index e36b0f6a..9412f69c 100644 --- a/public/include/pages/admin/settings.inc.php +++ b/public/include/pages/admin/settings.inc.php @@ -12,7 +12,7 @@ if (@$_REQUEST['do'] == 'save' && !empty($_REQUEST['data'])) { foreach($_REQUEST['data'] as $var => $value) { $setting->setValue($var, $value); } - $_SESSION['POPUP'][] = array('CONTENT' => 'Settings updated', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Settings updated', 'TYPE' => 'alert alert-success'); } // Load our available settings from configuration diff --git a/public/include/pages/admin/templates.inc.php b/public/include/pages/admin/templates.inc.php index 8f67611d..00af9281 100644 --- a/public/include/pages/admin/templates.inc.php +++ b/public/include/pages/admin/templates.inc.php @@ -27,16 +27,16 @@ $sOriginalTemplate = $template->getTemplateContent($sTemplate); if (@$_REQUEST['do'] == 'save') { if ($template->updateEntry(@$_REQUEST['template'], @$_REQUEST['content'], @$_REQUEST['active'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Page updated', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page updated', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Page update failed: ' . $template->getError(), 'TYPE' => 'errormsg'); + $_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' => 'errormsg'); + $_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); diff --git a/public/include/pages/admin/transactions.inc.php b/public/include/pages/admin/transactions.inc.php index 37afac7b..3ff3b626 100644 --- a/public/include/pages/admin/transactions.inc.php +++ b/public/include/pages/admin/transactions.inc.php @@ -13,7 +13,7 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { empty($_REQUEST['start']) ? $start = 0 : $start = $_REQUEST['start']; $aTransactions = $transaction->getTransactions($start, @$_REQUEST['filter'], $iLimit); $aTransactionTypes = $transaction->getTypes(); - if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'errormsg'); + if (!$aTransactions) $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any transaction', 'TYPE' => 'alert alert-danger'); if (!$setting->getValue('disable_transactionsummary')) { $aTransactionSummary = $transaction->getTransactionSummary(); $smarty->assign('SUMMARY', $aTransactionSummary); diff --git a/public/include/pages/admin/user.inc.php b/public/include/pages/admin/user.inc.php index 5795bd50..dfc9de05 100644 --- a/public/include/pages/admin/user.inc.php +++ b/public/include/pages/admin/user.inc.php @@ -8,7 +8,7 @@ if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { } // Some defaults -$iLimit = 30; +$iLimit = 100; $smarty->assign('LIMIT', $iLimit); empty($_REQUEST['start']) ? $start = 0 : $start = $_REQUEST['start']; $smarty->assign('ADMIN', array('' => '', '0' => 'No', '1' => 'Yes')); @@ -74,7 +74,7 @@ if (isset($_REQUEST['filter'])) { // Assign our variables $smarty->assign("USERS", $aUsers); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any users', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Could not find any users', 'TYPE' => 'alert alert-danger'); } } diff --git a/public/include/pages/admin/wallet.inc.php b/public/include/pages/admin/wallet.inc.php index 216f489c..fc423bb6 100644 --- a/public/include/pages/admin/wallet.inc.php +++ b/public/include/pages/admin/wallet.inc.php @@ -9,7 +9,7 @@ if (!$user->isAuthenticated() || !$user->isAdmin($_SESSION['USERDATA']['id'])) { if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $debug->append('No cached version available, fetching from backend', 3); - if ($bitcoin->can_connect() === true){ + if ($bitcoin->can_connect() === true) { $dBalance = $bitcoin->getrealbalance(); $dWalletAccounts = $bitcoin->listaccounts(); @@ -18,9 +18,9 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $dAccountAddresses = array(); foreach($dWalletAccounts as $key => $value) { - $dAccountAddresses[$key] = $bitcoin->getaddressesbyaccount($key); + $dAccountAddresses[$key] = $bitcoin->getaddressesbyaccount((string)$key); } - + $aGetInfo = $bitcoin->getinfo(); if (is_array($aGetInfo) && array_key_exists('newmint', $aGetInfo)) { $dNewmint = $aGetInfo['newmint']; @@ -28,10 +28,13 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $dNewmint = -1; } } else { + $dWalletAccounts = array(); + $dAddressCount = 0; + $dAccountAddresses = array(); $aGetInfo = array('errors' => 'Unable to connect'); $dBalance = 0; $dNewmint = -1; - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'alert alert-danger'); } // Fetch unconfirmed amount from blocks table empty($config['network_confirmations']) ? $confirmations = 120 : $confirmations = $config['network_confirmations']; diff --git a/public/include/pages/api/getdashboarddata.inc.php b/public/include/pages/api/getdashboarddata.inc.php index db70772a..b4b3575b 100644 --- a/public/include/pages/api/getdashboarddata.inc.php +++ b/public/include/pages/api/getdashboarddata.inc.php @@ -98,7 +98,7 @@ $data = array( 'shares' => array( 'valid' => $aRoundShares['valid'], 'invalid' => $aRoundShares['invalid'], 'invalid_percent' => $dPoolInvalidPercent, 'estimated' => $iEstShares, 'progress' => $dEstPercent ), 'price' => $aPrice, 'difficulty' => pow(2, $config['difficulty'] - 16), - 'target_bits' => $config['difficulty'] + 'target_bits' => $coin->getTargetBits() ), 'system' => array( 'load' => sys_getloadavg() ), 'network' => array( 'hashrate' => $dNetworkHashrateAdjusted, 'difficulty' => $dDifficulty, 'block' => $iBlock, 'esttimeperblock' => round($dExpectedTimePerBlock ,2), 'nextdifficulty' => $dEstNextDifficulty, 'blocksuntildiffchange' => $iBlocksUntilDiffChange ), diff --git a/public/include/pages/api/getnavbardata.inc.php b/public/include/pages/api/getnavbardata.inc.php index aa83986e..24ab357e 100644 --- a/public/include/pages/api/getnavbardata.inc.php +++ b/public/include/pages/api/getnavbardata.inc.php @@ -66,8 +66,8 @@ if ($iEstShares > 0 && $aRoundShares['valid'] > 0) { // Output JSON format $data = array( 'raw' => array( 'workers' => $worker->getCountAllActiveWorkers(), 'pool' => array( 'hashrate' => $dPoolHashrate ) ), - 'pool' => array( 'hashratemodifiername' => $aHashunits[$dPoolHashrateModifier], 'hashratemodifier' => $dPoolHashrateModifier, 'workers' => $worker->getCountAllActiveWorkers(), 'hashrate' => $dPoolHashrateAdjusted, 'estimated' => $iEstShares, 'progress' => $dEstPercent ), - 'network' => array( 'hashratemodifiername' => $aHashunits[$dNetworkHashrateModifier], 'hashratemodifier' => $dNetworkHashrateModifier, 'hashrate' => $dNetworkHashrateAdjusted, 'difficulty' => $dDifficulty, 'block' => $iBlock ), + 'pool' => array( 'workers' => $worker->getCountAllActiveWorkers(), 'hashrate' => $dPoolHashrateAdjusted, 'estimated' => $iEstShares, 'progress' => $dEstPercent ), + 'network' => array( 'hashrate' => $dNetworkHashrateAdjusted, 'difficulty' => $dDifficulty, 'block' => $iBlock ) ); echo $api->get_json($data); diff --git a/public/include/pages/api/getpoolstatus.inc.php b/public/include/pages/api/getpoolstatus.inc.php index a364a45b..26abc851 100644 --- a/public/include/pages/api/getpoolstatus.inc.php +++ b/public/include/pages/api/getpoolstatus.inc.php @@ -33,7 +33,9 @@ if ($iCurrentPoolHashrate > $dNetworkHashrate) $dNetworkHashrate = $iCurrentPool // Time in seconds, not hours, using modifier in smarty to translate $iCurrentPoolHashrate > 0 ? $iEstTime = $dDifficulty * pow(2,32) / ($iCurrentPoolHashrate * 1000) : $iEstTime = 0; -$iEstShares = (pow(2, 32 - $config['difficulty']) * $dDifficulty); +$iEstShares = $statistics->getEstimatedShares($dDifficulty); +// For mpos-bot PoolLuck +$iEstShares > 0 && $aShares['valid'] > 0 ? $dEstPercent = round(100 / $iEstShares * $aShares['valid'], 2) : $dEstPercent = 0; // Time since last $now = new DateTime( "now" ); @@ -48,6 +50,7 @@ $data = array( 'pool_name' => $setting->getValue('website_name'), 'hashrate' => $iCurrentPoolHashrate, 'efficiency' => $dEfficiency, + 'progress' => $dEstPercent, 'workers' => $worker->getCountAllActiveWorkers(), 'currentnetworkblock' => $iBlock, 'nextnetworkblock' => $iBlock + 1, diff --git a/public/include/pages/api/getusertransactions.inc.php b/public/include/pages/api/getusertransactions.inc.php index 403ff929..3903deba 100644 --- a/public/include/pages/api/getusertransactions.inc.php +++ b/public/include/pages/api/getusertransactions.inc.php @@ -8,13 +8,13 @@ $api->isActive(); $user_id = $api->checkAccess($user->checkApiKey($_REQUEST['api_key']), @$_REQUEST['id']); // Fetch transactions -if (isset($_REQUEST['limit']) && $_REQUEST['limit'] < 30) { +if (isset($_REQUEST['limit']) && $_REQUEST['limit'] <= 100) { $limit = $_REQUEST['limit']; } else { // Force limit - $limit = 5; + $limit = 100; } -$data['transactions'] = $transaction->getTransactions(0, NULL, 30, $user_id); +$data['transactions'] = $transaction->getTransactions(0, NULL, $limit, $user_id); // Fetch summary if enabled if (!$setting->getValue('disable_transactionsummary')) { diff --git a/public/include/pages/contactform.inc.php b/public/include/pages/contactform.inc.php index 379047f5..7cf7c021 100644 --- a/public/include/pages/contactform.inc.php +++ b/public/include/pages/contactform.inc.php @@ -2,10 +2,10 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($setting->getValue('acl_contactform') == 2) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "empty"); } else if ($setting->getValue('acl_contactform') == 0 && !$user->isAuthenticated(false)) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is disabled for guests.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is disabled for guests.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); } else { if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_contactform')) { diff --git a/public/include/pages/contactform/contactform.inc.php b/public/include/pages/contactform/contactform.inc.php index f83e89f2..9c273803 100644 --- a/public/include/pages/contactform/contactform.inc.php +++ b/public/include/pages/contactform/contactform.inc.php @@ -12,20 +12,20 @@ if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_ena ( (isset($_POST["recaptcha_response_field"])) ? $_POST["recaptcha_response_field"] : null ) ); $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), $rsp->error, true)); - if (!$rsp->is_valid) $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'errormsg'); + if (!$rsp->is_valid) $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); } if ($setting->getValue('acl_contactform') == 2) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); } else if ($setting->getValue('acl_contactform') == 0 && !$user->isAuthenticated(false)) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is disabled for guests.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Contactform is disabled for guests.', 'TYPE' => 'alert alert-danger'); } else { // Check if recaptcha is enabled, process form data if valid if ($setting->getValue('recaptcha_enabled') != 1 || $setting->getValue('recaptcha_enabled_contactform') != 1 || $rsp->is_valid) { if ($mail->contactform($_POST['senderName'], $_POST['senderEmail'], $_POST['senderSubject'], $_POST['senderMessage'])) { $_SESSION['POPUP'][] = array('CONTENT' => 'Thanks for sending your message! We will get back to you shortly'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'There was a problem sending your message. Please try again. ' . $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'There was a problem sending your message. Please try again. ' . $user->getError(), 'TYPE' => 'alert alert-danger'); } } } diff --git a/public/include/pages/login.inc.php b/public/include/pages/login.inc.php index a8f7cd0e..d58f9213 100644 --- a/public/include/pages/login.inc.php +++ b/public/include/pages/login.inc.php @@ -33,13 +33,13 @@ if ($setting->getValue('maintenance') && !$user->isAdmin($user->getUserIdByEmail if (!headers_sent()) header('Location: ' . $location); exit(''); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to login: '.$user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); } } // Load login template diff --git a/public/include/pages/password/change.inc.php b/public/include/pages/password/change.inc.php index 96fd1d40..1fefc6a2 100644 --- a/public/include/pages/password/change.inc.php +++ b/public/include/pages/password/change.inc.php @@ -4,12 +4,12 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if (isset($_POST['do']) && $_POST['do'] == 'resetPassword') { if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($user->resetPassword($_POST['token'], $_POST['newPassword'], $_POST['newPassword2'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Password reset complete! Please login.', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Password reset complete! Please login.', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => $user->getError(), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } diff --git a/public/include/pages/password/reset.inc.php b/public/include/pages/password/reset.inc.php index c06c21b6..71478ae8 100644 --- a/public/include/pages/password/reset.inc.php +++ b/public/include/pages/password/reset.inc.php @@ -4,12 +4,12 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; // Process password reset request if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { if ($user->initResetPassword($_POST['username'], $smarty)) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Please check your mail account to finish your password reset', 'TYPE' => 'success'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Please check your mail account to finish your password reset', 'TYPE' => 'alert alert-success'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => htmlentities($user->getError(), ENT_QUOTES), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => htmlentities($user->getError(), ENT_QUOTES), 'TYPE' => 'alert alert-danger'); } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } // Tempalte specifics, user default template by parent page diff --git a/public/include/pages/register.inc.php b/public/include/pages/register.inc.php index da9ec064..2dc4516d 100644 --- a/public/include/pages/register.inc.php +++ b/public/include/pages/register.inc.php @@ -2,10 +2,10 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; if ($setting->getValue('lock_registration') && $setting->getValue('disable_invitations')) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); } else if ($setting->getValue('lock_registration') && !$setting->getValue('disable_invitations') && !isset($_GET['token'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Only invited users are allowed to register.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Only invited users are allowed to register.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); } else { if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_enabled_registrations')) { diff --git a/public/include/pages/register/register.inc.php b/public/include/pages/register/register.inc.php index 31afe78d..e2dcd75f 100644 --- a/public/include/pages/register/register.inc.php +++ b/public/include/pages/register/register.inc.php @@ -12,14 +12,14 @@ if ($setting->getValue('recaptcha_enabled') && $setting->getValue('recaptcha_ena ( (isset($_POST["recaptcha_response_field"])) ? $_POST["recaptcha_response_field"] : null ) ); $smarty->assign("RECAPTCHA", recaptcha_get_html($setting->getValue('recaptcha_public_key'), $rsp->error, true)); - if (!$rsp->is_valid) $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'errormsg'); + if (!$rsp->is_valid) $_SESSION['POPUP'][] = array('CONTENT' => 'Invalid Captcha, please try again.', 'TYPE' => 'alert alert-danger'); $recaptcha = ($rsp->is_valid) ? 1 : 0; } if ($setting->getValue('disable_invitations') && $setting->getValue('lock_registration')) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Account registration is currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); } else if ($setting->getValue('lock_registration') && !$setting->getValue('disable_invitations') && !isset($_POST['token'])) { - $_SESSION['POPUP'][] = array('CONTENT' => 'Only invited users are allowed to register.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Only invited users are allowed to register.', 'TYPE' => 'alert alert-danger'); } else { // Check if csrf is enabled and fail if token is invalid if (!$config['csrf']['enabled'] || $config['csrf']['enabled'] && $csrftoken->valid) { @@ -29,11 +29,11 @@ if ($setting->getValue('disable_invitations') && $setting->getValue('lock_regist 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'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to create account: ' . $user->getError(), 'TYPE' => 'alert alert-danger'); } } } else { - $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $csrftoken->getErrorWithDescriptionHTML(), 'TYPE' => 'alert alert-warning'); } } diff --git a/public/include/pages/statistics.inc.php b/public/include/pages/statistics.inc.php index ca100ea4..50125993 100644 --- a/public/include/pages/statistics.inc.php +++ b/public/include/pages/statistics.inc.php @@ -9,7 +9,7 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { } else { $dDifficulty = 1; $iBlock = 0; - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to litecoind RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'alert alert-danger'); } $smarty->assign("CURRENTBLOCK", $iBlock); $smarty->assign("DIFFICULTY", $dDifficulty); diff --git a/public/include/pages/statistics/blockfinder.inc.php b/public/include/pages/statistics/blockfinder.inc.php index c746e958..eb818bf8 100644 --- a/public/include/pages/statistics/blockfinder.inc.php +++ b/public/include/pages/statistics/blockfinder.inc.php @@ -25,7 +25,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/pages/statistics/blocks.inc.php b/public/include/pages/statistics/blocks.inc.php index 61a24c7e..90ea8425 100644 --- a/public/include/pages/statistics/blocks.inc.php +++ b/public/include/pages/statistics/blocks.inc.php @@ -13,18 +13,21 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { } $iHeight = 0; - if (@$_REQUEST['next'] && !empty($_REQUEST['height']) && is_numeric($_REQUEST['height'])) { - $iHeight = @$roundstats->getNextBlockForStats($_REQUEST['height'], $iLimit); - if (!$iHeight) { - $iBlock = $block->getLast(); - $iHeight = $iBlock['height']; - } - } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height']) && is_numeric($_REQUEST['height'])) { - $iHeight = $_REQUEST['height']; + if (@$_REQUEST['next'] && !empty($_REQUEST['height'])) { + $iHeight = @$roundstats->getNextBlock($_REQUEST['height']); + if (!$iHeight) { + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } + } else if (@$_REQUEST['prev'] && !empty($_REQUEST['height'])) { + $iHeight = $roundstats->getPreviousBlock($_REQUEST['height']); } else if (empty($_REQUEST['height'])) { - $aBlock = $block->getLast(); - $iHeight = $aBlock['height']; + $iBlock = $block->getLast(); + $iHeight = $iBlock['height']; + } else { + $iHeight = $_REQUEST['height']; } + $_REQUEST['height'] = $iHeight; $test = false; if (@$_REQUEST['test'] && $user->isAdmin($_SESSION['USERDATA']['id'])) { @@ -48,8 +51,8 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { } } } else if ($config['payout_system'] == 'prop' || $config['payout_system'] == 'pps') { - if ($setting->getValue('statistics_show_block_average') && !$test) { - foreach($aBlocksFoundData as $key => $aData) { + 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; } @@ -98,7 +101,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/pages/about/donors.inc.php b/public/include/pages/statistics/donors.inc.php similarity index 90% rename from public/include/pages/about/donors.inc.php rename to public/include/pages/statistics/donors.inc.php index 9828ca10..9017bbb7 100644 --- a/public/include/pages/about/donors.inc.php +++ b/public/include/pages/statistics/donors.inc.php @@ -16,7 +16,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", "disabled.tpl"); break; } diff --git a/public/include/pages/statistics/graphs.inc.php b/public/include/pages/statistics/graphs.inc.php index 517532a3..0a19492d 100644 --- a/public/include/pages/statistics/graphs.inc.php +++ b/public/include/pages/statistics/graphs.inc.php @@ -23,7 +23,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/pages/statistics/pool.inc.php b/public/include/pages/statistics/pool.inc.php index bc85f91b..47ba55c4 100644 --- a/public/include/pages/statistics/pool.inc.php +++ b/public/include/pages/statistics/pool.inc.php @@ -11,7 +11,7 @@ if ($bitcoin->can_connect() === true){ $dDifficulty = 1; $dNetworkHashrate = 1; $iBlock = 0; - $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Unable to connect to wallet RPC service: ' . $bitcoin->can_connect(), 'TYPE' => 'alert alert-danger'); } if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { @@ -24,7 +24,7 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { $aContributorsHashes = $statistics->getTopContributors('hashes', 15); // Grab the last 5 blocks found as a quick overview - $iLimit = 5; + $iLimit = 10; $aBlocksFoundData = $statistics->getBlocksFound($iLimit); count($aBlocksFoundData) > 0 ? $aBlockData = $aBlocksFoundData[0] : $aBlockData = array(); @@ -91,7 +91,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/pages/statistics/round.inc.php b/public/include/pages/statistics/round.inc.php index e4529deb..da1fcd60 100644 --- a/public/include/pages/statistics/round.inc.php +++ b/public/include/pages/statistics/round.inc.php @@ -58,7 +58,7 @@ case '1': $smarty->assign("CONTENT", "default.tpl"); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/pages/statistics/uptime.inc.php b/public/include/pages/statistics/uptime.inc.php index e0418323..7eea6e14 100644 --- a/public/include/pages/statistics/uptime.inc.php +++ b/public/include/pages/statistics/uptime.inc.php @@ -15,7 +15,7 @@ if (!$smarty->isCached('master.tpl', $smarty_cache_key)) { )); $content = 'default.tpl'; } else { - $_SESSION['POPUP'][] = array('CONTENT' => 'UptimeRobot API Key not configured.', 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => 'UptimeRobot API Key not configured.', 'TYPE' => 'alert alert-warning'); $content = ''; } } else { @@ -32,7 +32,7 @@ case '1': $smarty->assign("CONTENT", $content); break; case '2': - $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Page currently disabled. Please try again later.', 'TYPE' => 'alert alert-danger'); $smarty->assign("CONTENT", ""); break; } diff --git a/public/include/smarty/libs/plugins/modifier.relative_date.php b/public/include/smarty/libs/plugins/modifier.relative_date.php new file mode 100644 index 00000000..96186266 --- /dev/null +++ b/public/include/smarty/libs/plugins/modifier.relative_date.php @@ -0,0 +1,79 @@ + +* Purpose: Output dates relative to the current time +* Input: timestamp = UNIX timestamp or a date which can be converted by strtotime() +* days = use date only and ignore the time +* format = (optional) a php date format (for dates over 1 year) +* ------------------------------------------------------------- +*/ + +function smarty_modifier_relative_date($timestamp, $days = false, $format = "M j, Y") { + + if (!is_numeric($timestamp)) { + // It's not a time stamp, so try to convert it... + $timestamp = strtotime($timestamp); + } + + if (!is_numeric($timestamp)) { + // If its still not numeric, the format is not valid + return false; + } + + // Calculate the difference in seconds + $difference = time() - $timestamp; + + // Check if we only want to calculate based on the day + if ($days && $difference < (60*60*24)) { + return "Today"; + } + if ($difference < 3) { + return "Just now"; + } + if ($difference < 60) { + return $difference . " seconds ago"; + } + if ($difference < (60*2)) { + return "1 minute ago"; + } + if ($difference < (60*60)) { + return intval($difference / 60) . " minutes ago"; + } + if ($difference < (60*60*2)) { + return "1 hour ago"; + } + if ($difference < (60*60*24)) { + return intval($difference / (60*60)) . " hours ago"; + } + if ($difference < (60*60*24*2)) { + return "1 day ago"; + } + if ($difference < (60*60*24*7)) { + return intval($difference / (60*60*24)) . " days ago"; + } + if ($difference < (60*60*24*7*2)) { + return "1 week ago"; + } + if ($difference < (60*60*24*7*(52/12))) { + return intval($difference / (60*60*24*7)) . " weeks ago"; + } + if ($difference < (60*60*24*7*(52/12)*2)) { + return "1 month ago"; + } + if ($difference < (60*60*24*364)) { + return intval($difference / (60*60*24*7*(52/12))) . " months ago"; + } + + // More than a year ago, just return the formatted date + return @date($format, $timestamp); + +} + +?> \ No newline at end of file diff --git a/public/include/smarty_globals.inc.php b/public/include/smarty_globals.inc.php index 61d350f4..d19fd00b 100644 --- a/public/include/smarty_globals.inc.php +++ b/public/include/smarty_globals.inc.php @@ -65,6 +65,9 @@ $aGlobal = array( 'twofactor' => $config['twofactor'], 'csrf' => $config['csrf'], 'config' => array( + 'website_design' => $setting->getValue('website_design'), + 'poolnav_enabled' => $setting->getValue('poolnav_enabled'), + 'poolnav_pools' => $setting->getValue('poolnav_pools'), 'recaptcha_enabled' => $setting->getValue('recaptcha_enabled'), 'recaptcha_enabled_logins' => $setting->getValue('recaptcha_enabled_logins'), 'disable_navbar' => $setting->getValue('disable_navbar'), @@ -75,19 +78,22 @@ $aGlobal = array( 'disable_contactform' => $setting->getValue('disable_contactform'), 'disable_contactform_guest' => $setting->getValue('disable_contactform_guest'), 'algorithm' => $config['algorithm'], - 'target_bits' => $config['target_bits'], + 'getbalancewithunconfirmed' => $config['getbalancewithunconfirmed'], + 'target_bits' => $coin->getTargetBits(), 'accounts' => $config['accounts'], 'disable_invitations' => $setting->getValue('disable_invitations'), 'disable_notifications' => $setting->getValue('disable_notifications'), 'monitoring_uptimerobot_api_keys' => $setting->getValue('monitoring_uptimerobot_api_keys'), 'statistics_ajax_refresh_interval' => $statistics_ajax_refresh_interval, 'statistics_ajax_long_refresh_interval' => $statistics_ajax_long_refresh_interval, - 'price' => array( 'currency' => $config['price']['currency'] ), + 'price' => $config['price'], 'targetdiff' => $config['difficulty'], 'currency' => $config['currency'], + 'exchangeurl' => $config['price']['url'], 'txfee_manual' => $config['txfee_manual'], 'txfee_auto' => $config['txfee_auto'], 'payout_system' => $config['payout_system'], + 'mp_threshold' => $config['mp_threshold'], 'ap_threshold' => array( 'min' => $config['ap_threshold']['min'], 'max' => $config['ap_threshold']['max'] @@ -100,6 +106,8 @@ $aGlobal['website']['name'] = $setting->getValue('website_name'); $aGlobal['website']['title'] = $setting->getValue('website_title'); $aGlobal['website']['slogan'] = $setting->getValue('website_slogan'); $aGlobal['website']['email'] = $setting->getValue('website_email'); +$aGlobal['website']['newsstyle'] = $setting->getValue('website_news_style'); +$aGlobal['website']['notificationshide'] = $setting->getValue('website_notification_autohide'); $aGlobal['website']['api']['disabled'] = $setting->getValue('disable_api'); $aGlobal['website']['blockexplorer']['disabled'] = $setting->getValue('website_blockexplorer_disabled'); $aGlobal['website']['transactionexplorer']['disabled'] = $setting->getValue('website_transactionexplorer_disabled'); @@ -125,12 +133,18 @@ $aGlobal['acl']['donors']['page'] = $setting->getValue('acl_donors_page'); $aGlobal['acl']['about']['page'] = $setting->getValue('acl_about_page'); $aGlobal['acl']['contactform'] = $setting->getValue('acl_contactform'); $aGlobal['acl']['chat']['page'] = $setting->getValue('acl_chat_page', 2); +$aGlobal['acl']['moot']['forum'] = $setting->getValue('acl_moot_forum', 2); +$aGlobal['acl']['qrcode'] = $setting->getValue('acl_qrcode'); // We don't want these session infos cached if (@$_SESSION['USERDATA']['id']) { $aGlobal['userdata'] = $_SESSION['USERDATA']['id'] ? $user->getUserData($_SESSION['USERDATA']['id']) : array(); $aGlobal['userdata']['balance'] = $transaction->getBalance($_SESSION['USERDATA']['id']); + // Fetch Last 5 notifications + $aLastNotifications = $notification->getNotifications($_SESSION['USERDATA']['id'], 5); + $aGlobal['userdata']['lastnotifications'] = $aLastNotifications; + // Other userdata that we can cache savely $aGlobal['userdata']['shares'] = $statistics->getUserShares($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); $aUserMiningStats = $statistics->getUserMiningStats($_SESSION['USERDATA']['username'], $_SESSION['USERDATA']['id']); @@ -165,15 +179,19 @@ if (@$_SESSION['USERDATA']['id']) { // Site-wide notifications, based on user events if ($aGlobal['userdata']['balance']['confirmed'] >= $config['ap_threshold']['max']) - $_SESSION['POPUP'][] = array('CONTENT' => 'You have exceeded the pools configured ' . $config['currency'] . ' warning threshold. Please initiate a transfer!', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You have exceeded the pools configured ' . $config['currency'] . ' warning threshold. Please initiate a transfer!', 'TYPE' => 'alert alert-danger'); if ($user->getUserFailed($_SESSION['USERDATA']['id']) > 0) - $_SESSION['POPUP'][] = array('CONTENT' => 'You have ' . $user->getUserFailed($_SESSION['USERDATA']['id']) . ' failed login attempts! Reset Counter', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'You have ' . $user->getUserFailed($_SESSION['USERDATA']['id']) . ' failed login attempts! Reset Counter', 'TYPE' => 'alert alert-danger'); } if ($setting->getValue('maintenance')) - $_SESSION['POPUP'][] = array('CONTENT' => 'This pool is currently in maintenance mode.', 'TYPE' => 'warning'); + $_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, 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => $motd, 'DISMISS' => 'yes', 'ID' => 'motd', 'TYPE' => 'alert alert-info'); + +// check for deprecated theme +if ($setting->getValue('website_theme') == "mpos") + $_SESSION['POPUP'][] = array('CONTENT' => 'You are using an old Theme that will not be maintained in the future.', 'TYPE' => 'alert alert-warning'); // So we can display additional info $smarty->assign('DEBUG', $config['DEBUG']); @@ -208,7 +226,7 @@ foreach ($aMonitorCrons as $strCron) { } } if ($bMessage) - $_SESSION['POPUP'][] = array('CONTENT' => implode($aCronMessage, '')); + $_SESSION['POPUP'][] = array('CONTENT' => implode($aCronMessage, ''), 'DISMISS' => 'yes', 'ID' => 'backend', 'TYPE' => 'alert alert-warning'); // Make it available in Smarty $smarty->assign('PATH', 'site_assets/' . THEME); diff --git a/public/include/version.inc.php b/public/include/version.inc.php index e39b701f..e9968618 100644 --- a/public/include/version.inc.php +++ b/public/include/version.inc.php @@ -2,16 +2,16 @@ $defflip = (!cfip()) ? exit(header('HTTP/1.1 401 Unauthorized')) : 1; define('MPOS_VERSION', '0.0.4'); -define('DB_VERSION', '0.0.6'); +define('DB_VERSION', '0.0.8'); define('CONFIG_VERSION', '0.0.7'); // Fetch installed database version $db_version = $setting->getValue('DB_VERSION'); if ($db_version != DB_VERSION) { // Notify admins via error popup - $_SESSION['POPUP'][] = array('CONTENT' => 'Database version mismatch (Installed: ' . $db_version . ', Current: ' . DB_VERSION . '). Database update required, please import any new SQL files. Cronjobs have been halted.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Database version mismatch (Installed: ' . $db_version . ', Current: ' . DB_VERSION . '). Database update required, please import any new SQL files. Cronjobs have been halted.', 'TYPE' => 'alert alert-danger'); } if (@$config['version'] !== CONFIG_VERSION) { // Notify admins via error popup - $_SESSION['POPUP'][] = array('CONTENT' => 'Configuration file version mismatch (Installed: ' . @$config['version'] . ', Current: ' . CONFIG_VERSION . '). Configuration update required, please check dist config for changes. Cronjobs have been halted.', 'TYPE' => 'errormsg'); + $_SESSION['POPUP'][] = array('CONTENT' => 'Configuration file version mismatch (Installed: ' . @$config['version'] . ', Current: ' . CONFIG_VERSION . '). Configuration update required, please check dist config for changes. Cronjobs have been halted.', 'TYPE' => 'alert alert-danger'); } diff --git a/public/index.php b/public/index.php index 8f312174..b1d1d60a 100644 --- a/public/index.php +++ b/public/index.php @@ -46,7 +46,7 @@ $hts = ($config['https_only'] && (!empty($_SERVER['QUERY_STRING']))) ? "https:// // Rate limiting if ($config['memcache']['enabled'] && $config['mc_antidos']['enabled']) { if (PHP_OS == 'WINNT') { - require_once(CLASS_DIR . 'memcached.class.php'); + require_once(CLASS_DIR . '/memcached.class.php'); } // memcache antidos needs a memcache handle $memcache = new Memcached(); @@ -98,11 +98,10 @@ if (count(@$_SESSION['last_ip_pop']) == 2) { $data = $_SESSION['last_ip_pop']; $ip = filter_var($data[0], FILTER_VALIDATE_IP); $time = date("l, F jS \a\\t g:i a", $data[1]); - $closelink = "Close"; if (@$_SESSION['AUTHENTICATED'] && $_SESSION['last_ip_pop'][0] !== $user->getCurrentIP()) { - $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time $closelink", 'TYPE' => 'warning'); + $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time", 'DISMISS' => 'yes', 'ID' => 'lastlogin', 'TYPE' => 'alert alert-warning'); } else { - $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time $closelink", 'TYPE' => 'info'); + $_SESSION['POPUP'][] = array('CONTENT' => "You last logged in from $ip on $time", 'DISMISS' => 'yes', 'ID' => 'lastlogin', 'TYPE' => 'alert alert-info'); } } diff --git a/public/site_assets/bootstrap/css/bootstrap-switch.css b/public/site_assets/bootstrap/css/bootstrap-switch.css new file mode 100644 index 00000000..7bc3c529 --- /dev/null +++ b/public/site_assets/bootstrap/css/bootstrap-switch.css @@ -0,0 +1,194 @@ +/* ======================================================================== + * bootstrap-switch - v3.0.0 + * http://www.bootstrap-switch.org + * ======================================================================== + * Copyright 2012-2013 Mattia Larentis + * + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== + */ + +.bootstrap-switch { + display: inline-block; + cursor: pointer; + border-radius: 4px; + border: 1px solid; + border-color: #cccccc; + position: relative; + text-align: left; + overflow: hidden; + line-height: 8px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + min-width: 100px; + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.bootstrap-switch.bootstrap-switch-mini { + min-width: 71px; +} +.bootstrap-switch.bootstrap-switch-mini > div > span, +.bootstrap-switch.bootstrap-switch-mini > div > label { + padding-bottom: 4px; + padding-top: 4px; + font-size: 10px; + line-height: 9px; +} +.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-mini-icons { + height: 1.20em; + line-height: 9px; + vertical-align: text-top; + text-align: center; + transform: scale(0.6); + margin-top: -1px; + margin-bottom: -1px; +} +.bootstrap-switch.bootstrap-switch-small { + min-width: 79px; +} +.bootstrap-switch.bootstrap-switch-small > div > span, +.bootstrap-switch.bootstrap-switch-small > div > label { + padding-bottom: 3px; + padding-top: 3px; + font-size: 12px; + line-height: 18px; +} +.bootstrap-switch.bootstrap-switch-large { + min-width: 120px; +} +.bootstrap-switch.bootstrap-switch-large > div > span, +.bootstrap-switch.bootstrap-switch-large > div > label { + padding-bottom: 9px; + padding-top: 9px; + font-size: 16px; + line-height: normal; +} +.bootstrap-switch.bootstrap-switch-animate > div { + -webkit-transition: margin-left 0.5s; + transition: margin-left 0.5s; +} +.bootstrap-switch.bootstrap-switch-on > div { + margin-left: 0%; +} +.bootstrap-switch.bootstrap-switch-on > div > label { + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.bootstrap-switch.bootstrap-switch-off > div { + margin-left: -50%; +} +.bootstrap-switch.bootstrap-switch-off > div > label { + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.bootstrap-switch.bootstrap-switch-disabled, +.bootstrap-switch.bootstrap-switch-readonly { + opacity: 0.5; + filter: alpha(opacity=50); + cursor: default !important; +} +.bootstrap-switch.bootstrap-switch-disabled > div > span, +.bootstrap-switch.bootstrap-switch-readonly > div > span, +.bootstrap-switch.bootstrap-switch-disabled > div > label, +.bootstrap-switch.bootstrap-switch-readonly > div > label { + cursor: default !important; +} +.bootstrap-switch.bootstrap-switch-focused { + border-color: #66afe9; + outline: 0; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); +} +.bootstrap-switch > div { + display: inline-block; + width: 150%; + top: 0; + border-radius: 4px; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +.bootstrap-switch > div > span, +.bootstrap-switch > div > label { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + cursor: pointer; + display: inline-block !important; + height: 100%; + padding-bottom: 4px; + padding-top: 4px; + font-size: 14px; + line-height: 20px; +} +.bootstrap-switch > div > span { + text-align: center; + z-index: 1; + width: 33.333333333%; +} +.bootstrap-switch > div > span.bootstrap-switch-handle-on { + color: #f00; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; +} +.bootstrap-switch > div > span.bootstrap-switch-handle-off { + color: #000; + background: #eeeeee; + border-bottom-right-radius: 3px; + border-top-right-radius: 3px; +} +.bootstrap-switch > div > span.bootstrap-switch-primary { + color: #fff; + background: #428bca; +} +.bootstrap-switch > div > span.bootstrap-switch-info { + color: #fff; + background: #5bc0de; +} +.bootstrap-switch > div > span.bootstrap-switch-success { + color: #fff; + background: #5cb85c; +} +.bootstrap-switch > div > span.bootstrap-switch-warning { + background: #f0ad4e; + color: #fff; +} +.bootstrap-switch > div > span.bootstrap-switch-danger { + color: #fff; + background: #d9534f; +} +.bootstrap-switch > div > span.bootstrap-switch-default { + color: #000; + background: #eeeeee; +} +.bootstrap-switch > div > label { + text-align: center; + margin-top: -1px; + margin-bottom: -1px; + z-index: 100; + width: 33.333333333%; + color: #333333; + background: #ffffff; +} +.bootstrap-switch input[type='radio'], +.bootstrap-switch input[type='checkbox'] { + position: absolute !important; + top: 0; + left: 0; + opacity: 0; + filter: alpha(opacity=0); + z-index: -1; +} diff --git a/public/site_assets/bootstrap/css/bootstrap-switch.min.css b/public/site_assets/bootstrap/css/bootstrap-switch.min.css new file mode 100644 index 00000000..7e579b98 --- /dev/null +++ b/public/site_assets/bootstrap/css/bootstrap-switch.min.css @@ -0,0 +1,22 @@ +/* ======================================================================== + * bootstrap-switch - v3.0.0 + * http://www.bootstrap-switch.org + * ======================================================================== + * Copyright 2012-2013 Mattia Larentis + * + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== + */ + +.bootstrap-switch{display:inline-block;cursor:pointer;border-radius:4px;border:1px solid;border-color:#ccc;position:relative;text-align:left;overflow:hidden;line-height:8px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;min-width:100px;-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.bootstrap-switch.bootstrap-switch-mini{min-width:71px}.bootstrap-switch.bootstrap-switch-mini>div>span,.bootstrap-switch.bootstrap-switch-mini>div>label{padding-bottom:4px;padding-top:4px;font-size:10px;line-height:9px}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-mini-icons{height:1.2em;line-height:9px;vertical-align:text-top;text-align:center;transform:scale(.6);margin-top:-1px;margin-bottom:-1px}.bootstrap-switch.bootstrap-switch-small{min-width:79px}.bootstrap-switch.bootstrap-switch-small>div>span,.bootstrap-switch.bootstrap-switch-small>div>label{padding-bottom:3px;padding-top:3px;font-size:12px;line-height:18px}.bootstrap-switch.bootstrap-switch-large{min-width:120px}.bootstrap-switch.bootstrap-switch-large>div>span,.bootstrap-switch.bootstrap-switch-large>div>label{padding-bottom:9px;padding-top:9px;font-size:16px;line-height:normal}.bootstrap-switch.bootstrap-switch-animate>div{-webkit-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-on>div{margin-left:0}.bootstrap-switch.bootstrap-switch-on>div>label{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch.bootstrap-switch-off>div{margin-left:-50%}.bootstrap-switch.bootstrap-switch-off>div>label{border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-readonly{opacity:.5;filter:alpha(opacity=50);cursor:default!important}.bootstrap-switch.bootstrap-switch-disabled>div>span,.bootstrap-switch.bootstrap-switch-readonly>div>span,.bootstrap-switch.bootstrap-switch-disabled>div>label,.bootstrap-switch.bootstrap-switch-readonly>div>label{cursor:default!important}.bootstrap-switch.bootstrap-switch-focused{border-color:#66afe9;outline:0;-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)}.bootstrap-switch>div{display:inline-block;width:150%;top:0;border-radius:4px;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.bootstrap-switch>div>span,.bootstrap-switch>div>label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:inline-block!important;height:100%;padding-bottom:4px;padding-top:4px;font-size:14px;line-height:20px}.bootstrap-switch>div>span{text-align:center;z-index:1;width:33.33333333%}.bootstrap-switch>div>span.bootstrap-switch-handle-on{color:red;border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch>div>span.bootstrap-switch-handle-off{color:#000;background:#eee;border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch>div>span.bootstrap-switch-primary{color:#fff;background:#428bca}.bootstrap-switch>div>span.bootstrap-switch-info{color:#fff;background:#5bc0de}.bootstrap-switch>div>span.bootstrap-switch-success{color:#fff;background:#5cb85c}.bootstrap-switch>div>span.bootstrap-switch-warning{background:#f0ad4e;color:#fff}.bootstrap-switch>div>span.bootstrap-switch-danger{color:#fff;background:#d9534f}.bootstrap-switch>div>span.bootstrap-switch-default{color:#000;background:#eee}.bootstrap-switch>div>label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;width:33.33333333%;color:#333;background:#fff}.bootstrap-switch input[type=radio],.bootstrap-switch input[type=checkbox]{position:absolute!important;top:0;left:0;opacity:0;filter:alpha(opacity=0);z-index:-1} \ No newline at end of file diff --git a/public/site_assets/bootstrap/css/bootstrap.css b/public/site_assets/bootstrap/css/bootstrap.css new file mode 100644 index 00000000..25d47e1d --- /dev/null +++ b/public/site_assets/bootstrap/css/bootstrap.css @@ -0,0 +1,5831 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.0 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; + vertical-align: baseline; +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + margin: .67em 0; + font-size: 2em; +} +mark { + color: #000; + background: #ff0; +} +small { + font-size: 80%; +} +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} +sup { + top: -.5em; +} +sub { + bottom: -.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + height: 0; + -moz-box-sizing: content-box; + box-sizing: content-box; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + margin: 0; + font: inherit; + color: inherit; +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; + cursor: pointer; +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; + padding: 0; +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + padding: .35em .625em .75em; + margin: 0 2px; + border: 1px solid #c0c0c0; +} +legend { + padding: 0; + border: 0; +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-spacing: 0; + border-collapse: collapse; +} +td, +th { + padding: 0; +} +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } + select { + background: #fff !important; + } + .navbar { + display: none; + } + .table td, + .table th { + background-color: #fff !important; + } + .btn > .caret, + .dropup > .btn > .caret { + border-top-color: #000 !important; + } + .label { + border: 1px solid #000; + } + .table { + border-collapse: collapse !important; + } + .table-bordered th, + .table-bordered td { + border: 1px solid #ddd !important; + } +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +*:before, +*:after { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +html { + font-size: 62.5%; + + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.428571429; + color: #333; + background-color: #fff; +} +input, +button, +select, +textarea { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} +a { + color: #428bca; + text-decoration: none; +} +a:hover, +a:focus { + color: #2a6496; + text-decoration: underline; +} +a:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +figure { + margin: 0; +} +img { + vertical-align: middle; +} +.img-responsive { + display: block; + max-width: 100%; + height: auto; +} +.img-rounded { + border-radius: 6px; +} +.img-thumbnail { + display: inline-block; + max-width: 100%; + height: auto; + padding: 4px; + line-height: 1.428571429; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.img-circle { + border-radius: 50%; +} +hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eee; +} +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; +} +h1, +h2, +h3, +h4, +h5, +h6, +.h1, +.h2, +.h3, +.h4, +.h5, +.h6 { + font-family: inherit; + font-weight: 500; + line-height: 1.1; + color: inherit; +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small, +.h1 small, +.h2 small, +.h3 small, +.h4 small, +.h5 small, +.h6 small, +h1 .small, +h2 .small, +h3 .small, +h4 .small, +h5 .small, +h6 .small, +.h1 .small, +.h2 .small, +.h3 .small, +.h4 .small, +.h5 .small, +.h6 .small { + font-weight: normal; + line-height: 1; + color: #999; +} +h1, +.h1, +h2, +.h2, +h3, +.h3 { + margin-top: 20px; + margin-bottom: 10px; +} +h1 small, +.h1 small, +h2 small, +.h2 small, +h3 small, +.h3 small, +h1 .small, +.h1 .small, +h2 .small, +.h2 .small, +h3 .small, +.h3 .small { + font-size: 65%; +} +h4, +.h4, +h5, +.h5, +h6, +.h6 { + margin-top: 10px; + margin-bottom: 10px; +} +h4 small, +.h4 small, +h5 small, +.h5 small, +h6 small, +.h6 small, +h4 .small, +.h4 .small, +h5 .small, +.h5 .small, +h6 .small, +.h6 .small { + font-size: 75%; +} +h1, +.h1 { + font-size: 36px; +} +h2, +.h2 { + font-size: 30px; +} +h3, +.h3 { + font-size: 24px; +} +h4, +.h4 { + font-size: 18px; +} +h5, +.h5 { + font-size: 14px; +} +h6, +.h6 { + font-size: 12px; +} +p { + margin: 0 0 10px; +} +.lead { + margin-bottom: 20px; + font-size: 16px; + font-weight: 200; + line-height: 1.4; +} +@media (min-width: 768px) { + .lead { + font-size: 21px; + } +} +small, +.small { + font-size: 85%; +} +cite { + font-style: normal; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} +.text-justify { + text-align: justify; +} +.text-muted { + color: #999; +} +.text-primary { + color: #428bca; +} +a.text-primary:hover { + color: #3071a9; +} +.text-success { + color: #3c763d; +} +a.text-success:hover { + color: #2b542c; +} +.text-info { + color: #31708f; +} +a.text-info:hover { + color: #245269; +} +.text-warning { + color: #8a6d3b; +} +a.text-warning:hover { + color: #66512c; +} +.text-danger { + color: #a94442; +} +a.text-danger:hover { + color: #843534; +} +.bg-primary { + color: #fff; + background-color: #428bca; +} +a.bg-primary:hover { + background-color: #3071a9; +} +.bg-success { + background-color: #dff0d8; +} +a.bg-success:hover { + background-color: #c1e2b3; +} +.bg-info { + background-color: #d9edf7; +} +a.bg-info:hover { + background-color: #afd9ee; +} +.bg-warning { + background-color: #fcf8e3; +} +a.bg-warning:hover { + background-color: #f7ecb5; +} +.bg-danger { + background-color: #f2dede; +} +a.bg-danger:hover { + background-color: #e4b9b9; +} +.page-header { + padding-bottom: 9px; + margin: 40px 0 20px; + border-bottom: 1px solid #eee; +} +ul, +ol { + margin-top: 0; + margin-bottom: 10px; +} +ul ul, +ol ul, +ul ol, +ol ol { + margin-bottom: 0; +} +.list-unstyled { + padding-left: 0; + list-style: none; +} +.list-inline { + padding-left: 0; + list-style: none; +} +.list-inline > li { + display: inline-block; + 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; +} +dt { + font-weight: bold; +} +dd { + margin-left: 0; +} +@media (min-width: 768px) { + .dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; + } + .dl-horizontal dd { + margin-left: 180px; + } +} +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999; +} +.initialism { + font-size: 90%; + text-transform: uppercase; +} +blockquote { + padding: 10px 20px; + margin: 0 0 20px; + font-size: 17.5px; + border-left: 5px solid #eee; +} +blockquote p:last-child, +blockquote ul:last-child, +blockquote ol:last-child { + margin-bottom: 0; +} +blockquote footer, +blockquote small, +blockquote .small { + display: block; + font-size: 80%; + line-height: 1.428571429; + color: #999; +} +blockquote footer:before, +blockquote small:before, +blockquote .small:before { + content: '\2014 \00A0'; +} +.blockquote-reverse, +blockquote.pull-right { + padding-right: 15px; + padding-left: 0; + text-align: right; + border-right: 5px solid #eee; + border-left: 0; +} +.blockquote-reverse footer:before, +blockquote.pull-right footer:before, +.blockquote-reverse small:before, +blockquote.pull-right small:before, +.blockquote-reverse .small:before, +blockquote.pull-right .small:before { + content: ''; +} +.blockquote-reverse footer:after, +blockquote.pull-right footer:after, +.blockquote-reverse small:after, +blockquote.pull-right small:after, +.blockquote-reverse .small:after, +blockquote.pull-right .small:after { + content: '\00A0 \2014'; +} +blockquote:before, +blockquote:after { + content: ""; +} +address { + margin-bottom: 20px; + font-style: normal; + line-height: 1.428571429; +} +code, +kbd, +pre, +samp { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; +} +code { + padding: 2px 4px; + font-size: 90%; + color: #c7254e; + white-space: nowrap; + background-color: #f9f2f4; + border-radius: 4px; +} +kbd { + padding: 2px 4px; + font-size: 90%; + color: #fff; + background-color: #333; + border-radius: 3px; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .25); +} +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 1.428571429; + color: #333; + word-break: break-all; + word-wrap: break-word; + background-color: #f5f5f5; + border: 1px solid #ccc; + border-radius: 4px; +} +pre code { + padding: 0; + font-size: inherit; + color: inherit; + white-space: pre-wrap; + background-color: transparent; + border-radius: 0; +} +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} +.container { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +@media (min-width: 768px) { + .container { + width: 750px; + } +} +@media (min-width: 992px) { + .container { + width: 970px; + } +} +@media (min-width: 1200px) { + .container { + width: 1170px; + } +} +.container-fluid { + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-left: auto; +} +.row { + margin-right: -15px; + margin-left: -15px; +} +.col-xs-1, .col-sm-1, .col-md-1, .col-lg-1, .col-xs-2, .col-sm-2, .col-md-2, .col-lg-2, .col-xs-3, .col-sm-3, .col-md-3, .col-lg-3, .col-xs-4, .col-sm-4, .col-md-4, .col-lg-4, .col-xs-5, .col-sm-5, .col-md-5, .col-lg-5, .col-xs-6, .col-sm-6, .col-md-6, .col-lg-6, .col-xs-7, .col-sm-7, .col-md-7, .col-lg-7, .col-xs-8, .col-sm-8, .col-md-8, .col-lg-8, .col-xs-9, .col-sm-9, .col-md-9, .col-lg-9, .col-xs-10, .col-sm-10, .col-md-10, .col-lg-10, .col-xs-11, .col-sm-11, .col-md-11, .col-lg-11, .col-xs-12, .col-sm-12, .col-md-12, .col-lg-12 { + position: relative; + min-height: 1px; + padding-right: 15px; + padding-left: 15px; +} +.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 { + float: left; +} +.col-xs-12 { + width: 100%; +} +.col-xs-11 { + width: 91.66666666666666%; +} +.col-xs-10 { + width: 83.33333333333334%; +} +.col-xs-9 { + width: 75%; +} +.col-xs-8 { + width: 66.66666666666666%; +} +.col-xs-7 { + width: 58.333333333333336%; +} +.col-xs-6 { + width: 50%; +} +.col-xs-5 { + width: 41.66666666666667%; +} +.col-xs-4 { + width: 33.33333333333333%; +} +.col-xs-3 { + width: 25%; +} +.col-xs-2 { + width: 16.666666666666664%; +} +.col-xs-1 { + width: 8.333333333333332%; +} +.col-xs-pull-12 { + right: 100%; +} +.col-xs-pull-11 { + right: 91.66666666666666%; +} +.col-xs-pull-10 { + right: 83.33333333333334%; +} +.col-xs-pull-9 { + right: 75%; +} +.col-xs-pull-8 { + right: 66.66666666666666%; +} +.col-xs-pull-7 { + right: 58.333333333333336%; +} +.col-xs-pull-6 { + right: 50%; +} +.col-xs-pull-5 { + right: 41.66666666666667%; +} +.col-xs-pull-4 { + right: 33.33333333333333%; +} +.col-xs-pull-3 { + right: 25%; +} +.col-xs-pull-2 { + right: 16.666666666666664%; +} +.col-xs-pull-1 { + right: 8.333333333333332%; +} +.col-xs-pull-0 { + right: 0; +} +.col-xs-push-12 { + left: 100%; +} +.col-xs-push-11 { + left: 91.66666666666666%; +} +.col-xs-push-10 { + left: 83.33333333333334%; +} +.col-xs-push-9 { + left: 75%; +} +.col-xs-push-8 { + left: 66.66666666666666%; +} +.col-xs-push-7 { + left: 58.333333333333336%; +} +.col-xs-push-6 { + left: 50%; +} +.col-xs-push-5 { + left: 41.66666666666667%; +} +.col-xs-push-4 { + left: 33.33333333333333%; +} +.col-xs-push-3 { + left: 25%; +} +.col-xs-push-2 { + left: 16.666666666666664%; +} +.col-xs-push-1 { + left: 8.333333333333332%; +} +.col-xs-push-0 { + left: 0; +} +.col-xs-offset-12 { + margin-left: 100%; +} +.col-xs-offset-11 { + margin-left: 91.66666666666666%; +} +.col-xs-offset-10 { + margin-left: 83.33333333333334%; +} +.col-xs-offset-9 { + margin-left: 75%; +} +.col-xs-offset-8 { + margin-left: 66.66666666666666%; +} +.col-xs-offset-7 { + margin-left: 58.333333333333336%; +} +.col-xs-offset-6 { + margin-left: 50%; +} +.col-xs-offset-5 { + margin-left: 41.66666666666667%; +} +.col-xs-offset-4 { + margin-left: 33.33333333333333%; +} +.col-xs-offset-3 { + margin-left: 25%; +} +.col-xs-offset-2 { + margin-left: 16.666666666666664%; +} +.col-xs-offset-1 { + margin-left: 8.333333333333332%; +} +.col-xs-offset-0 { + margin-left: 0; +} +@media (min-width: 768px) { + .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 { + float: left; + } + .col-sm-12 { + width: 100%; + } + .col-sm-11 { + width: 91.66666666666666%; + } + .col-sm-10 { + width: 83.33333333333334%; + } + .col-sm-9 { + width: 75%; + } + .col-sm-8 { + width: 66.66666666666666%; + } + .col-sm-7 { + width: 58.333333333333336%; + } + .col-sm-6 { + width: 50%; + } + .col-sm-5 { + width: 41.66666666666667%; + } + .col-sm-4 { + width: 33.33333333333333%; + } + .col-sm-3 { + width: 25%; + } + .col-sm-2 { + width: 16.666666666666664%; + } + .col-sm-1 { + width: 8.333333333333332%; + } + .col-sm-pull-12 { + right: 100%; + } + .col-sm-pull-11 { + right: 91.66666666666666%; + } + .col-sm-pull-10 { + right: 83.33333333333334%; + } + .col-sm-pull-9 { + right: 75%; + } + .col-sm-pull-8 { + right: 66.66666666666666%; + } + .col-sm-pull-7 { + right: 58.333333333333336%; + } + .col-sm-pull-6 { + right: 50%; + } + .col-sm-pull-5 { + right: 41.66666666666667%; + } + .col-sm-pull-4 { + right: 33.33333333333333%; + } + .col-sm-pull-3 { + right: 25%; + } + .col-sm-pull-2 { + right: 16.666666666666664%; + } + .col-sm-pull-1 { + right: 8.333333333333332%; + } + .col-sm-pull-0 { + right: 0; + } + .col-sm-push-12 { + left: 100%; + } + .col-sm-push-11 { + left: 91.66666666666666%; + } + .col-sm-push-10 { + left: 83.33333333333334%; + } + .col-sm-push-9 { + left: 75%; + } + .col-sm-push-8 { + left: 66.66666666666666%; + } + .col-sm-push-7 { + left: 58.333333333333336%; + } + .col-sm-push-6 { + left: 50%; + } + .col-sm-push-5 { + left: 41.66666666666667%; + } + .col-sm-push-4 { + left: 33.33333333333333%; + } + .col-sm-push-3 { + left: 25%; + } + .col-sm-push-2 { + left: 16.666666666666664%; + } + .col-sm-push-1 { + left: 8.333333333333332%; + } + .col-sm-push-0 { + left: 0; + } + .col-sm-offset-12 { + margin-left: 100%; + } + .col-sm-offset-11 { + margin-left: 91.66666666666666%; + } + .col-sm-offset-10 { + margin-left: 83.33333333333334%; + } + .col-sm-offset-9 { + margin-left: 75%; + } + .col-sm-offset-8 { + margin-left: 66.66666666666666%; + } + .col-sm-offset-7 { + margin-left: 58.333333333333336%; + } + .col-sm-offset-6 { + margin-left: 50%; + } + .col-sm-offset-5 { + margin-left: 41.66666666666667%; + } + .col-sm-offset-4 { + margin-left: 33.33333333333333%; + } + .col-sm-offset-3 { + margin-left: 25%; + } + .col-sm-offset-2 { + margin-left: 16.666666666666664%; + } + .col-sm-offset-1 { + margin-left: 8.333333333333332%; + } + .col-sm-offset-0 { + margin-left: 0; + } +} +@media (min-width: 992px) { + .col-md-1, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-10, .col-md-11, .col-md-12 { + float: left; + } + .col-md-12 { + width: 100%; + } + .col-md-11 { + width: 91.66666666666666%; + } + .col-md-10 { + width: 83.33333333333334%; + } + .col-md-9 { + width: 75%; + } + .col-md-8 { + width: 66.66666666666666%; + } + .col-md-7 { + width: 58.333333333333336%; + } + .col-md-6 { + width: 50%; + } + .col-md-5 { + width: 41.66666666666667%; + } + .col-md-4 { + width: 33.33333333333333%; + } + .col-md-3 { + width: 25%; + } + .col-md-2 { + width: 16.666666666666664%; + } + .col-md-1 { + width: 8.333333333333332%; + } + .col-md-pull-12 { + right: 100%; + } + .col-md-pull-11 { + right: 91.66666666666666%; + } + .col-md-pull-10 { + right: 83.33333333333334%; + } + .col-md-pull-9 { + right: 75%; + } + .col-md-pull-8 { + right: 66.66666666666666%; + } + .col-md-pull-7 { + right: 58.333333333333336%; + } + .col-md-pull-6 { + right: 50%; + } + .col-md-pull-5 { + right: 41.66666666666667%; + } + .col-md-pull-4 { + right: 33.33333333333333%; + } + .col-md-pull-3 { + right: 25%; + } + .col-md-pull-2 { + right: 16.666666666666664%; + } + .col-md-pull-1 { + right: 8.333333333333332%; + } + .col-md-pull-0 { + right: 0; + } + .col-md-push-12 { + left: 100%; + } + .col-md-push-11 { + left: 91.66666666666666%; + } + .col-md-push-10 { + left: 83.33333333333334%; + } + .col-md-push-9 { + left: 75%; + } + .col-md-push-8 { + left: 66.66666666666666%; + } + .col-md-push-7 { + left: 58.333333333333336%; + } + .col-md-push-6 { + left: 50%; + } + .col-md-push-5 { + left: 41.66666666666667%; + } + .col-md-push-4 { + left: 33.33333333333333%; + } + .col-md-push-3 { + left: 25%; + } + .col-md-push-2 { + left: 16.666666666666664%; + } + .col-md-push-1 { + left: 8.333333333333332%; + } + .col-md-push-0 { + left: 0; + } + .col-md-offset-12 { + margin-left: 100%; + } + .col-md-offset-11 { + margin-left: 91.66666666666666%; + } + .col-md-offset-10 { + margin-left: 83.33333333333334%; + } + .col-md-offset-9 { + margin-left: 75%; + } + .col-md-offset-8 { + margin-left: 66.66666666666666%; + } + .col-md-offset-7 { + margin-left: 58.333333333333336%; + } + .col-md-offset-6 { + margin-left: 50%; + } + .col-md-offset-5 { + margin-left: 41.66666666666667%; + } + .col-md-offset-4 { + margin-left: 33.33333333333333%; + } + .col-md-offset-3 { + margin-left: 25%; + } + .col-md-offset-2 { + margin-left: 16.666666666666664%; + } + .col-md-offset-1 { + margin-left: 8.333333333333332%; + } + .col-md-offset-0 { + margin-left: 0; + } +} +@media (min-width: 1200px) { + .col-lg-1, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-10, .col-lg-11, .col-lg-12 { + float: left; + } + .col-lg-12 { + width: 100%; + } + .col-lg-11 { + width: 91.66666666666666%; + } + .col-lg-10 { + width: 83.33333333333334%; + } + .col-lg-9 { + width: 75%; + } + .col-lg-8 { + width: 66.66666666666666%; + } + .col-lg-7 { + width: 58.333333333333336%; + } + .col-lg-6 { + width: 50%; + } + .col-lg-5 { + width: 41.66666666666667%; + } + .col-lg-4 { + width: 33.33333333333333%; + } + .col-lg-3 { + width: 25%; + } + .col-lg-2 { + width: 16.666666666666664%; + } + .col-lg-1 { + width: 8.333333333333332%; + } + .col-lg-pull-12 { + right: 100%; + } + .col-lg-pull-11 { + right: 91.66666666666666%; + } + .col-lg-pull-10 { + right: 83.33333333333334%; + } + .col-lg-pull-9 { + right: 75%; + } + .col-lg-pull-8 { + right: 66.66666666666666%; + } + .col-lg-pull-7 { + right: 58.333333333333336%; + } + .col-lg-pull-6 { + right: 50%; + } + .col-lg-pull-5 { + right: 41.66666666666667%; + } + .col-lg-pull-4 { + right: 33.33333333333333%; + } + .col-lg-pull-3 { + right: 25%; + } + .col-lg-pull-2 { + right: 16.666666666666664%; + } + .col-lg-pull-1 { + right: 8.333333333333332%; + } + .col-lg-pull-0 { + right: 0; + } + .col-lg-push-12 { + left: 100%; + } + .col-lg-push-11 { + left: 91.66666666666666%; + } + .col-lg-push-10 { + left: 83.33333333333334%; + } + .col-lg-push-9 { + left: 75%; + } + .col-lg-push-8 { + left: 66.66666666666666%; + } + .col-lg-push-7 { + left: 58.333333333333336%; + } + .col-lg-push-6 { + left: 50%; + } + .col-lg-push-5 { + left: 41.66666666666667%; + } + .col-lg-push-4 { + left: 33.33333333333333%; + } + .col-lg-push-3 { + left: 25%; + } + .col-lg-push-2 { + left: 16.666666666666664%; + } + .col-lg-push-1 { + left: 8.333333333333332%; + } + .col-lg-push-0 { + left: 0; + } + .col-lg-offset-12 { + margin-left: 100%; + } + .col-lg-offset-11 { + margin-left: 91.66666666666666%; + } + .col-lg-offset-10 { + margin-left: 83.33333333333334%; + } + .col-lg-offset-9 { + margin-left: 75%; + } + .col-lg-offset-8 { + margin-left: 66.66666666666666%; + } + .col-lg-offset-7 { + margin-left: 58.333333333333336%; + } + .col-lg-offset-6 { + margin-left: 50%; + } + .col-lg-offset-5 { + margin-left: 41.66666666666667%; + } + .col-lg-offset-4 { + margin-left: 33.33333333333333%; + } + .col-lg-offset-3 { + margin-left: 25%; + } + .col-lg-offset-2 { + margin-left: 16.666666666666664%; + } + .col-lg-offset-1 { + margin-left: 8.333333333333332%; + } + .col-lg-offset-0 { + margin-left: 0; + } +} +table { + max-width: 100%; + background-color: transparent; +} +th { + text-align: left; +} +.table { + width: 100%; + margin-bottom: 20px; +} +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + padding: 8px; + line-height: 1.428571429; + vertical-align: top; + border-top: 1px solid #ddd; +} +.table > thead > tr > th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; +} +.table > caption + thead > tr:first-child > th, +.table > colgroup + thead > tr:first-child > th, +.table > thead:first-child > tr:first-child > th, +.table > caption + thead > tr:first-child > td, +.table > colgroup + thead > tr:first-child > td, +.table > thead:first-child > tr:first-child > td { + border-top: 0; +} +.table > tbody + tbody { + border-top: 2px solid #ddd; +} +.table .table { + background-color: #fff; +} +.table-condensed > thead > tr > th, +.table-condensed > tbody > tr > th, +.table-condensed > tfoot > tr > th, +.table-condensed > thead > tr > td, +.table-condensed > tbody > tr > td, +.table-condensed > tfoot > tr > td { + padding: 5px; +} +.table-bordered { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border: 1px solid #ddd; +} +.table-bordered > thead > tr > th, +.table-bordered > thead > tr > td { + border-bottom-width: 2px; +} +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #f5f5f5; +} +table col[class*="col-"] { + position: static; + display: table-column; + float: none; +} +table td[class*="col-"], +table th[class*="col-"] { + position: static; + display: table-cell; + float: none; +} +.table > thead > tr > td.active, +.table > tbody > tr > td.active, +.table > tfoot > tr > td.active, +.table > thead > tr > th.active, +.table > tbody > tr > th.active, +.table > tfoot > tr > th.active, +.table > thead > tr.active > td, +.table > tbody > tr.active > td, +.table > tfoot > tr.active > td, +.table > thead > tr.active > th, +.table > tbody > tr.active > th, +.table > tfoot > tr.active > th { + background-color: #f5f5f5; +} +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr.active:hover > th { + background-color: #e8e8e8; +} +.table > thead > tr > td.success, +.table > tbody > tr > td.success, +.table > tfoot > tr > td.success, +.table > thead > tr > th.success, +.table > tbody > tr > th.success, +.table > tfoot > tr > th.success, +.table > thead > tr.success > td, +.table > tbody > tr.success > td, +.table > tfoot > tr.success > td, +.table > thead > tr.success > th, +.table > tbody > tr.success > th, +.table > tfoot > tr.success > th { + background-color: #dff0d8; +} +.table-hover > tbody > tr > td.success:hover, +.table-hover > tbody > tr > th.success:hover, +.table-hover > tbody > tr.success:hover > td, +.table-hover > tbody > tr.success:hover > th { + background-color: #d0e9c6; +} +.table > thead > tr > td.info, +.table > tbody > tr > td.info, +.table > tfoot > tr > td.info, +.table > thead > tr > th.info, +.table > tbody > tr > th.info, +.table > tfoot > tr > th.info, +.table > thead > tr.info > td, +.table > tbody > tr.info > td, +.table > tfoot > tr.info > td, +.table > thead > tr.info > th, +.table > tbody > tr.info > th, +.table > tfoot > tr.info > th { + background-color: #d9edf7; +} +.table-hover > tbody > tr > td.info:hover, +.table-hover > tbody > tr > th.info:hover, +.table-hover > tbody > tr.info:hover > td, +.table-hover > tbody > tr.info:hover > th { + background-color: #c4e3f3; +} +.table > thead > tr > td.warning, +.table > tbody > tr > td.warning, +.table > tfoot > tr > td.warning, +.table > thead > tr > th.warning, +.table > tbody > tr > th.warning, +.table > tfoot > tr > th.warning, +.table > thead > tr.warning > td, +.table > tbody > tr.warning > td, +.table > tfoot > tr.warning > td, +.table > thead > tr.warning > th, +.table > tbody > tr.warning > th, +.table > tfoot > tr.warning > th { + background-color: #fcf8e3; +} +.table-hover > tbody > tr > td.warning:hover, +.table-hover > tbody > tr > th.warning:hover, +.table-hover > tbody > tr.warning:hover > td, +.table-hover > tbody > tr.warning:hover > th { + background-color: #faf2cc; +} +.table > thead > tr > td.danger, +.table > tbody > tr > td.danger, +.table > tfoot > tr > td.danger, +.table > thead > tr > th.danger, +.table > tbody > tr > th.danger, +.table > tfoot > tr > th.danger, +.table > thead > tr.danger > td, +.table > tbody > tr.danger > td, +.table > tfoot > tr.danger > td, +.table > thead > tr.danger > th, +.table > tbody > tr.danger > th, +.table > tfoot > tr.danger > th { + background-color: #f2dede; +} +.table-hover > tbody > tr > td.danger:hover, +.table-hover > tbody > tr > th.danger:hover, +.table-hover > tbody > tr.danger:hover > td, +.table-hover > tbody > tr.danger:hover > th { + background-color: #ebcccc; +} +@media (max-width: 767px) { + .table-responsive { + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; + border: 1px solid #ddd; + } + .table-responsive > .table { + margin-bottom: 0; + } + .table-responsive > .table > thead > tr > th, + .table-responsive > .table > tbody > tr > th, + .table-responsive > .table > tfoot > tr > th, + .table-responsive > .table > thead > tr > td, + .table-responsive > .table > tbody > tr > td, + .table-responsive > .table > tfoot > tr > td { + white-space: nowrap; + } + .table-responsive > .table-bordered { + border: 0; + } + .table-responsive > .table-bordered > thead > tr > th:first-child, + .table-responsive > .table-bordered > tbody > tr > th:first-child, + .table-responsive > .table-bordered > tfoot > tr > th:first-child, + .table-responsive > .table-bordered > thead > tr > td:first-child, + .table-responsive > .table-bordered > tbody > tr > td:first-child, + .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; + } + .table-responsive > .table-bordered > thead > tr > th:last-child, + .table-responsive > .table-bordered > tbody > tr > th:last-child, + .table-responsive > .table-bordered > tfoot > tr > th:last-child, + .table-responsive > .table-bordered > thead > tr > td:last-child, + .table-responsive > .table-bordered > tbody > tr > td:last-child, + .table-responsive > .table-bordered > tfoot > tr > td:last-child { + border-right: 0; + } + .table-responsive > .table-bordered > tbody > tr:last-child > th, + .table-responsive > .table-bordered > tfoot > tr:last-child > th, + .table-responsive > .table-bordered > tbody > tr:last-child > td, + .table-responsive > .table-bordered > tfoot > tr:last-child > td { + border-bottom: 0; + } +} +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: inherit; + color: #333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} +label { + display: inline-block; + margin-bottom: 5px; + font-weight: bold; +} +input[type="search"] { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + /* IE8-9 */ + line-height: normal; +} +input[type="file"] { + display: block; +} +input[type="range"] { + display: block; + width: 100%; +} +select[multiple], +select[size] { + height: auto; +} +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +output { + display: block; + padding-top: 7px; + font-size: 14px; + line-height: 1.428571429; + color: #555; +} +.form-control { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.428571429; + color: #555; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; +} +.form-control:focus { + border-color: #66afe9; + outline: 0; + -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; +} +.form-control:-ms-input-placeholder { + color: #999; +} +.form-control::-webkit-input-placeholder { + color: #999; +} +.form-control[disabled], +.form-control[readonly], +fieldset[disabled] .form-control { + cursor: not-allowed; + background-color: #eee; + opacity: 1; +} +textarea.form-control { + height: auto; +} +input[type="date"] { + line-height: 34px; +} +.form-group { + margin-bottom: 15px; +} +.radio, +.checkbox { + display: block; + min-height: 20px; + padding-left: 20px; + margin-top: 10px; + margin-bottom: 10px; +} +.radio label, +.checkbox label { + display: inline; + font-weight: normal; + cursor: pointer; +} +.radio input[type="radio"], +.radio-inline input[type="radio"], +.checkbox input[type="checkbox"], +.checkbox-inline input[type="checkbox"] { + float: left; + margin-left: -20px; +} +.radio + .radio, +.checkbox + .checkbox { + margin-top: -5px; +} +.radio-inline, +.checkbox-inline { + display: inline-block; + padding-left: 20px; + margin-bottom: 0; + font-weight: normal; + vertical-align: middle; + cursor: pointer; +} +.radio-inline + .radio-inline, +.checkbox-inline + .checkbox-inline { + margin-top: 0; + margin-left: 10px; +} +input[type="radio"][disabled], +input[type="checkbox"][disabled], +.radio[disabled], +.radio-inline[disabled], +.checkbox[disabled], +.checkbox-inline[disabled], +fieldset[disabled] input[type="radio"], +fieldset[disabled] input[type="checkbox"], +fieldset[disabled] .radio, +fieldset[disabled] .radio-inline, +fieldset[disabled] .checkbox, +fieldset[disabled] .checkbox-inline { + cursor: not-allowed; +} +.input-sm { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-sm { + height: 30px; + line-height: 30px; +} +textarea.input-sm, +select[multiple].input-sm { + height: auto; +} +.input-lg { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-lg { + height: 46px; + line-height: 46px; +} +textarea.input-lg, +select[multiple].input-lg { + height: auto; +} +.has-feedback { + position: relative; +} +.has-feedback .form-control { + padding-right: 42.5px; +} +.has-feedback .form-control-feedback { + position: absolute; + top: 25px; + right: 0; + display: block; + width: 34px; + height: 34px; + line-height: 34px; + text-align: center; +} +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #3c763d; +} +.has-success .form-control { + border-color: #3c763d; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-success .form-control:focus { + border-color: #2b542c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #67b168; +} +.has-success .input-group-addon { + color: #3c763d; + background-color: #dff0d8; + border-color: #3c763d; +} +.has-success .form-control-feedback { + color: #3c763d; +} +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #8a6d3b; +} +.has-warning .form-control { + border-color: #8a6d3b; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-warning .form-control:focus { + border-color: #66512c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #c0a16b; +} +.has-warning .input-group-addon { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #8a6d3b; +} +.has-warning .form-control-feedback { + color: #8a6d3b; +} +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #a94442; +} +.has-error .form-control { + border-color: #a94442; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); +} +.has-error .form-control:focus { + border-color: #843534; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075), 0 0 6px #ce8483; +} +.has-error .input-group-addon { + color: #a94442; + background-color: #f2dede; + border-color: #a94442; +} +.has-error .form-control-feedback { + color: #a94442; +} +.form-control-static { + margin-bottom: 0; +} +.help-block { + display: block; + margin-top: 5px; + margin-bottom: 10px; + color: #737373; +} +@media (min-width: 768px) { + .form-inline .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .form-inline .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio, + .form-inline .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .form-inline .radio input[type="radio"], + .form-inline .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } + .form-inline .has-feedback .form-control-feedback { + top: 0; + } +} +.form-horizontal .control-label, +.form-horizontal .radio, +.form-horizontal .checkbox, +.form-horizontal .radio-inline, +.form-horizontal .checkbox-inline { + padding-top: 7px; + margin-top: 0; + margin-bottom: 0; +} +.form-horizontal .radio, +.form-horizontal .checkbox { + min-height: 27px; +} +.form-horizontal .form-group { + margin-right: -15px; + margin-left: -15px; +} +.form-horizontal .form-control-static { + padding-top: 7px; +} +@media (min-width: 768px) { + .form-horizontal .control-label { + text-align: right; + } +} +.form-horizontal .has-feedback .form-control-feedback { + top: 0; + right: 15px; +} +.btn { + display: inline-block; + padding: 6px 12px; + margin-bottom: 0; + font-size: 14px; + font-weight: normal; + line-height: 1.428571429; + text-align: center; + white-space: nowrap; + vertical-align: middle; + cursor: pointer; + -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 { + outline: thin dotted; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} +.btn:hover, +.btn:focus { + color: #333; + text-decoration: none; +} +.btn:active, +.btn.active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn.disabled, +.btn[disabled], +fieldset[disabled] .btn { + pointer-events: none; + cursor: not-allowed; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; + opacity: .65; +} +.btn-default { + color: #333; + background-color: #fff; + border-color: #ccc; +} +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #333; + background-color: #ebebeb; + border-color: #adadad; +} +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + background-image: none; +} +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #fff; + border-color: #ccc; +} +.btn-default .badge { + color: #fff; + background-color: #333; +} +.btn-primary { + color: #fff; + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #fff; + background-color: #3276b1; + border-color: #285e8e; +} +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #428bca; + border-color: #357ebd; +} +.btn-primary .badge { + color: #428bca; + background-color: #fff; +} +.btn-success { + color: #fff; + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #fff; + background-color: #47a447; + border-color: #398439; +} +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + background-image: none; +} +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #5cb85c; + border-color: #4cae4c; +} +.btn-success .badge { + color: #5cb85c; + background-color: #fff; +} +.btn-info { + color: #fff; + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #fff; + background-color: #39b3d7; + border-color: #269abc; +} +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + background-image: none; +} +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #5bc0de; + border-color: #46b8da; +} +.btn-info .badge { + color: #5bc0de; + background-color: #fff; +} +.btn-warning { + color: #fff; + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #fff; + background-color: #ed9c28; + border-color: #d58512; +} +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + background-image: none; +} +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #f0ad4e; + border-color: #eea236; +} +.btn-warning .badge { + color: #f0ad4e; + background-color: #fff; +} +.btn-danger { + color: #fff; + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #fff; + background-color: #d2322d; + border-color: #ac2925; +} +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + background-image: none; +} +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #d9534f; + border-color: #d43f3a; +} +.btn-danger .badge { + color: #d9534f; + background-color: #fff; +} +.btn-link { + font-weight: normal; + color: #428bca; + cursor: pointer; + border-radius: 0; +} +.btn-link, +.btn-link:active, +.btn-link[disabled], +fieldset[disabled] .btn-link { + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.btn-link, +.btn-link:hover, +.btn-link:focus, +.btn-link:active { + border-color: transparent; +} +.btn-link:hover, +.btn-link:focus { + color: #2a6496; + text-decoration: underline; + background-color: transparent; +} +.btn-link[disabled]:hover, +fieldset[disabled] .btn-link:hover, +.btn-link[disabled]:focus, +fieldset[disabled] .btn-link:focus { + color: #999; + text-decoration: none; +} +.btn-lg { + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +.btn-sm { + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-xs { + padding: 1px 5px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; +} +.btn-block + .btn-block { + margin-top: 5px; +} +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} +.fade { + opacity: 0; + -webkit-transition: opacity .15s linear; + transition: opacity .15s linear; +} +.fade.in { + opacity: 1; +} +.collapse { + display: none; +} +.collapse.in { + display: block; +} +.collapsing { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height .35s ease; + transition: height .35s ease; +} +@font-face { + font-family: 'Glyphicons Halflings'; + + src: url('../fonts/glyphicons-halflings-regular.eot'); + src: url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'), url('../fonts/glyphicons-halflings-regular.woff') format('woff'), url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'), url('../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular') format('svg'); +} +.glyphicon { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: normal; + line-height: 1; + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.glyphicon-asterisk:before { + content: "\2a"; +} +.glyphicon-plus:before { + content: "\2b"; +} +.glyphicon-euro:before { + content: "\20ac"; +} +.glyphicon-minus:before { + content: "\2212"; +} +.glyphicon-cloud:before { + content: "\2601"; +} +.glyphicon-envelope:before { + content: "\2709"; +} +.glyphicon-pencil:before { + content: "\270f"; +} +.glyphicon-glass:before { + content: "\e001"; +} +.glyphicon-music:before { + content: "\e002"; +} +.glyphicon-search:before { + content: "\e003"; +} +.glyphicon-heart:before { + content: "\e005"; +} +.glyphicon-star:before { + content: "\e006"; +} +.glyphicon-star-empty:before { + content: "\e007"; +} +.glyphicon-user:before { + content: "\e008"; +} +.glyphicon-film:before { + content: "\e009"; +} +.glyphicon-th-large:before { + content: "\e010"; +} +.glyphicon-th:before { + content: "\e011"; +} +.glyphicon-th-list:before { + content: "\e012"; +} +.glyphicon-ok:before { + content: "\e013"; +} +.glyphicon-remove:before { + content: "\e014"; +} +.glyphicon-zoom-in:before { + content: "\e015"; +} +.glyphicon-zoom-out:before { + content: "\e016"; +} +.glyphicon-off:before { + content: "\e017"; +} +.glyphicon-signal:before { + content: "\e018"; +} +.glyphicon-cog:before { + content: "\e019"; +} +.glyphicon-trash:before { + content: "\e020"; +} +.glyphicon-home:before { + content: "\e021"; +} +.glyphicon-file:before { + content: "\e022"; +} +.glyphicon-time:before { + content: "\e023"; +} +.glyphicon-road:before { + content: "\e024"; +} +.glyphicon-download-alt:before { + content: "\e025"; +} +.glyphicon-download:before { + content: "\e026"; +} +.glyphicon-upload:before { + content: "\e027"; +} +.glyphicon-inbox:before { + content: "\e028"; +} +.glyphicon-play-circle:before { + content: "\e029"; +} +.glyphicon-repeat:before { + content: "\e030"; +} +.glyphicon-refresh:before { + content: "\e031"; +} +.glyphicon-list-alt:before { + content: "\e032"; +} +.glyphicon-lock:before { + content: "\e033"; +} +.glyphicon-flag:before { + content: "\e034"; +} +.glyphicon-headphones:before { + content: "\e035"; +} +.glyphicon-volume-off:before { + content: "\e036"; +} +.glyphicon-volume-down:before { + content: "\e037"; +} +.glyphicon-volume-up:before { + content: "\e038"; +} +.glyphicon-qrcode:before { + content: "\e039"; +} +.glyphicon-barcode:before { + content: "\e040"; +} +.glyphicon-tag:before { + content: "\e041"; +} +.glyphicon-tags:before { + content: "\e042"; +} +.glyphicon-book:before { + content: "\e043"; +} +.glyphicon-bookmark:before { + content: "\e044"; +} +.glyphicon-print:before { + content: "\e045"; +} +.glyphicon-camera:before { + content: "\e046"; +} +.glyphicon-font:before { + content: "\e047"; +} +.glyphicon-bold:before { + content: "\e048"; +} +.glyphicon-italic:before { + content: "\e049"; +} +.glyphicon-text-height:before { + content: "\e050"; +} +.glyphicon-text-width:before { + content: "\e051"; +} +.glyphicon-align-left:before { + content: "\e052"; +} +.glyphicon-align-center:before { + content: "\e053"; +} +.glyphicon-align-right:before { + content: "\e054"; +} +.glyphicon-align-justify:before { + content: "\e055"; +} +.glyphicon-list:before { + content: "\e056"; +} +.glyphicon-indent-left:before { + content: "\e057"; +} +.glyphicon-indent-right:before { + content: "\e058"; +} +.glyphicon-facetime-video:before { + content: "\e059"; +} +.glyphicon-picture:before { + content: "\e060"; +} +.glyphicon-map-marker:before { + content: "\e062"; +} +.glyphicon-adjust:before { + content: "\e063"; +} +.glyphicon-tint:before { + content: "\e064"; +} +.glyphicon-edit:before { + content: "\e065"; +} +.glyphicon-share:before { + content: "\e066"; +} +.glyphicon-check:before { + content: "\e067"; +} +.glyphicon-move:before { + content: "\e068"; +} +.glyphicon-step-backward:before { + content: "\e069"; +} +.glyphicon-fast-backward:before { + content: "\e070"; +} +.glyphicon-backward:before { + content: "\e071"; +} +.glyphicon-play:before { + content: "\e072"; +} +.glyphicon-pause:before { + content: "\e073"; +} +.glyphicon-stop:before { + content: "\e074"; +} +.glyphicon-forward:before { + content: "\e075"; +} +.glyphicon-fast-forward:before { + content: "\e076"; +} +.glyphicon-step-forward:before { + content: "\e077"; +} +.glyphicon-eject:before { + content: "\e078"; +} +.glyphicon-chevron-left:before { + content: "\e079"; +} +.glyphicon-chevron-right:before { + content: "\e080"; +} +.glyphicon-plus-sign:before { + content: "\e081"; +} +.glyphicon-minus-sign:before { + content: "\e082"; +} +.glyphicon-remove-sign:before { + content: "\e083"; +} +.glyphicon-ok-sign:before { + content: "\e084"; +} +.glyphicon-question-sign:before { + content: "\e085"; +} +.glyphicon-info-sign:before { + content: "\e086"; +} +.glyphicon-screenshot:before { + content: "\e087"; +} +.glyphicon-remove-circle:before { + content: "\e088"; +} +.glyphicon-ok-circle:before { + content: "\e089"; +} +.glyphicon-ban-circle:before { + content: "\e090"; +} +.glyphicon-arrow-left:before { + content: "\e091"; +} +.glyphicon-arrow-right:before { + content: "\e092"; +} +.glyphicon-arrow-up:before { + content: "\e093"; +} +.glyphicon-arrow-down:before { + content: "\e094"; +} +.glyphicon-share-alt:before { + content: "\e095"; +} +.glyphicon-resize-full:before { + content: "\e096"; +} +.glyphicon-resize-small:before { + content: "\e097"; +} +.glyphicon-exclamation-sign:before { + content: "\e101"; +} +.glyphicon-gift:before { + content: "\e102"; +} +.glyphicon-leaf:before { + content: "\e103"; +} +.glyphicon-fire:before { + content: "\e104"; +} +.glyphicon-eye-open:before { + content: "\e105"; +} +.glyphicon-eye-close:before { + content: "\e106"; +} +.glyphicon-warning-sign:before { + content: "\e107"; +} +.glyphicon-plane:before { + content: "\e108"; +} +.glyphicon-calendar:before { + content: "\e109"; +} +.glyphicon-random:before { + content: "\e110"; +} +.glyphicon-comment:before { + content: "\e111"; +} +.glyphicon-magnet:before { + content: "\e112"; +} +.glyphicon-chevron-up:before { + content: "\e113"; +} +.glyphicon-chevron-down:before { + content: "\e114"; +} +.glyphicon-retweet:before { + content: "\e115"; +} +.glyphicon-shopping-cart:before { + content: "\e116"; +} +.glyphicon-folder-close:before { + content: "\e117"; +} +.glyphicon-folder-open:before { + content: "\e118"; +} +.glyphicon-resize-vertical:before { + content: "\e119"; +} +.glyphicon-resize-horizontal:before { + content: "\e120"; +} +.glyphicon-hdd:before { + content: "\e121"; +} +.glyphicon-bullhorn:before { + content: "\e122"; +} +.glyphicon-bell:before { + content: "\e123"; +} +.glyphicon-certificate:before { + content: "\e124"; +} +.glyphicon-thumbs-up:before { + content: "\e125"; +} +.glyphicon-thumbs-down:before { + content: "\e126"; +} +.glyphicon-hand-right:before { + content: "\e127"; +} +.glyphicon-hand-left:before { + content: "\e128"; +} +.glyphicon-hand-up:before { + content: "\e129"; +} +.glyphicon-hand-down:before { + content: "\e130"; +} +.glyphicon-circle-arrow-right:before { + content: "\e131"; +} +.glyphicon-circle-arrow-left:before { + content: "\e132"; +} +.glyphicon-circle-arrow-up:before { + content: "\e133"; +} +.glyphicon-circle-arrow-down:before { + content: "\e134"; +} +.glyphicon-globe:before { + content: "\e135"; +} +.glyphicon-wrench:before { + content: "\e136"; +} +.glyphicon-tasks:before { + content: "\e137"; +} +.glyphicon-filter:before { + content: "\e138"; +} +.glyphicon-briefcase:before { + content: "\e139"; +} +.glyphicon-fullscreen:before { + content: "\e140"; +} +.glyphicon-dashboard:before { + content: "\e141"; +} +.glyphicon-paperclip:before { + content: "\e142"; +} +.glyphicon-heart-empty:before { + content: "\e143"; +} +.glyphicon-link:before { + content: "\e144"; +} +.glyphicon-phone:before { + content: "\e145"; +} +.glyphicon-pushpin:before { + content: "\e146"; +} +.glyphicon-usd:before { + content: "\e148"; +} +.glyphicon-gbp:before { + content: "\e149"; +} +.glyphicon-sort:before { + content: "\e150"; +} +.glyphicon-sort-by-alphabet:before { + content: "\e151"; +} +.glyphicon-sort-by-alphabet-alt:before { + content: "\e152"; +} +.glyphicon-sort-by-order:before { + content: "\e153"; +} +.glyphicon-sort-by-order-alt:before { + content: "\e154"; +} +.glyphicon-sort-by-attributes:before { + content: "\e155"; +} +.glyphicon-sort-by-attributes-alt:before { + content: "\e156"; +} +.glyphicon-unchecked:before { + content: "\e157"; +} +.glyphicon-expand:before { + content: "\e158"; +} +.glyphicon-collapse-down:before { + content: "\e159"; +} +.glyphicon-collapse-up:before { + content: "\e160"; +} +.glyphicon-log-in:before { + content: "\e161"; +} +.glyphicon-flash:before { + content: "\e162"; +} +.glyphicon-log-out:before { + content: "\e163"; +} +.glyphicon-new-window:before { + content: "\e164"; +} +.glyphicon-record:before { + content: "\e165"; +} +.glyphicon-save:before { + content: "\e166"; +} +.glyphicon-open:before { + content: "\e167"; +} +.glyphicon-saved:before { + content: "\e168"; +} +.glyphicon-import:before { + content: "\e169"; +} +.glyphicon-export:before { + content: "\e170"; +} +.glyphicon-send:before { + content: "\e171"; +} +.glyphicon-floppy-disk:before { + content: "\e172"; +} +.glyphicon-floppy-saved:before { + content: "\e173"; +} +.glyphicon-floppy-remove:before { + content: "\e174"; +} +.glyphicon-floppy-save:before { + content: "\e175"; +} +.glyphicon-floppy-open:before { + content: "\e176"; +} +.glyphicon-credit-card:before { + content: "\e177"; +} +.glyphicon-transfer:before { + content: "\e178"; +} +.glyphicon-cutlery:before { + content: "\e179"; +} +.glyphicon-header:before { + content: "\e180"; +} +.glyphicon-compressed:before { + content: "\e181"; +} +.glyphicon-earphone:before { + content: "\e182"; +} +.glyphicon-phone-alt:before { + content: "\e183"; +} +.glyphicon-tower:before { + content: "\e184"; +} +.glyphicon-stats:before { + content: "\e185"; +} +.glyphicon-sd-video:before { + content: "\e186"; +} +.glyphicon-hd-video:before { + content: "\e187"; +} +.glyphicon-subtitles:before { + content: "\e188"; +} +.glyphicon-sound-stereo:before { + content: "\e189"; +} +.glyphicon-sound-dolby:before { + content: "\e190"; +} +.glyphicon-sound-5-1:before { + content: "\e191"; +} +.glyphicon-sound-6-1:before { + content: "\e192"; +} +.glyphicon-sound-7-1:before { + content: "\e193"; +} +.glyphicon-copyright-mark:before { + content: "\e194"; +} +.glyphicon-registration-mark:before { + content: "\e195"; +} +.glyphicon-cloud-download:before { + content: "\e197"; +} +.glyphicon-cloud-upload:before { + content: "\e198"; +} +.glyphicon-tree-conifer:before { + content: "\e199"; +} +.glyphicon-tree-deciduous:before { + content: "\e200"; +} +.caret { + display: inline-block; + width: 0; + height: 0; + margin-left: 2px; + vertical-align: middle; + border-top: 4px solid; + border-right: 4px solid transparent; + border-left: 4px solid transparent; +} +.dropdown { + position: relative; +} +.dropdown-toggle:focus { + outline: 0; +} +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + font-size: 14px; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .15); + border-radius: 4px; + -webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175); + box-shadow: 0 6px 12px rgba(0, 0, 0, .175); +} +.dropdown-menu.pull-right { + right: 0; + left: auto; +} +.dropdown-menu .divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 1.428571429; + color: #333; + white-space: nowrap; +} +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #f5f5f5; +} +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #fff; + text-decoration: none; + background-color: #428bca; + outline: 0; +} +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999; +} +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: not-allowed; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); +} +.open > .dropdown-menu { + display: block; +} +.open > a { + outline: 0; +} +.dropdown-menu-right { + right: 0; + left: auto; +} +.dropdown-menu-left { + right: auto; + left: 0; +} +.dropdown-header { + display: block; + padding: 3px 20px; + font-size: 12px; + line-height: 1.428571429; + color: #999; +} +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + content: ""; + border-top: 0; + border-bottom: 4px solid; +} +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} +@media (min-width: 768px) { + .navbar-right .dropdown-menu { + right: 0; + left: auto; + } + .navbar-right .dropdown-menu-left { + right: auto; + left: 0; + } +} +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-block; + vertical-align: middle; +} +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + float: left; +} +.btn-group > .btn:hover, +.btn-group-vertical > .btn:hover, +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus, +.btn-group > .btn:active, +.btn-group-vertical > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn.active { + z-index: 2; +} +.btn-group > .btn:focus, +.btn-group-vertical > .btn:focus { + outline: none; +} +.btn-group .btn + .btn, +.btn-group .btn + .btn-group, +.btn-group .btn-group + .btn, +.btn-group .btn-group + .btn-group { + margin-left: -1px; +} +.btn-toolbar { + margin-left: -5px; +} +.btn-toolbar .btn-group, +.btn-toolbar .input-group { + float: left; +} +.btn-toolbar > .btn, +.btn-toolbar > .btn-group, +.btn-toolbar > .input-group { + margin-left: 5px; +} +.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) { + border-radius: 0; +} +.btn-group > .btn:first-child { + margin-left: 0; +} +.btn-group > .btn:first-child:not(:last-child):not(.dropdown-toggle) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn:last-child:not(:first-child), +.btn-group > .dropdown-toggle:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group > .btn-group { + float: left; +} +.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group > .btn-group:first-child > .btn:last-child, +.btn-group > .btn-group:first-child > .dropdown-toggle { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.btn-group > .btn-group:last-child > .btn:first-child { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group .dropdown-toggle:active, +.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; +} +.btn-group > .btn-lg + .dropdown-toggle { + padding-right: 12px; + padding-left: 12px; +} +.btn-group.open .dropdown-toggle { + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); +} +.btn-group.open .dropdown-toggle.btn-link { + -webkit-box-shadow: none; + box-shadow: none; +} +.btn .caret { + margin-left: 0; +} +.btn-lg .caret { + border-width: 5px 5px 0; + border-bottom-width: 0; +} +.dropup .btn-lg .caret { + border-width: 0 5px 5px; +} +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group, +.btn-group-vertical > .btn-group > .btn { + display: block; + float: none; + width: 100%; + max-width: 100%; +} +.btn-group-vertical > .btn-group > .btn { + float: none; +} +.btn-group-vertical > .btn + .btn, +.btn-group-vertical > .btn + .btn-group, +.btn-group-vertical > .btn-group + .btn, +.btn-group-vertical > .btn-group + .btn-group { + margin-top: -1px; + margin-left: 0; +} +.btn-group-vertical > .btn:not(:first-child):not(:last-child) { + border-radius: 0; +} +.btn-group-vertical > .btn:first-child:not(:last-child) { + border-top-right-radius: 4px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn:last-child:not(:first-child) { + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 4px; +} +.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn { + border-radius: 0; +} +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .btn:last-child, +.btn-group-vertical > .btn-group:first-child:not(:last-child) > .dropdown-toggle { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child { + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.btn-group-justified { + display: table; + width: 100%; + table-layout: fixed; + border-collapse: separate; +} +.btn-group-justified > .btn, +.btn-group-justified > .btn-group { + display: table-cell; + float: none; + width: 1%; +} +.btn-group-justified > .btn-group .btn { + width: 100%; +} +[data-toggle="buttons"] > .btn > input[type="radio"], +[data-toggle="buttons"] > .btn > input[type="checkbox"] { + display: none; +} +.input-group { + position: relative; + display: table; + border-collapse: separate; +} +.input-group[class*="col-"] { + float: none; + padding-right: 0; + padding-left: 0; +} +.input-group .form-control { + float: left; + width: 100%; + margin-bottom: 0; +} +.input-group-lg > .form-control, +.input-group-lg > .input-group-addon, +.input-group-lg > .input-group-btn > .btn { + height: 46px; + padding: 10px 16px; + font-size: 18px; + line-height: 1.33; + border-radius: 6px; +} +select.input-group-lg > .form-control, +select.input-group-lg > .input-group-addon, +select.input-group-lg > .input-group-btn > .btn { + height: 46px; + line-height: 46px; +} +textarea.input-group-lg > .form-control, +textarea.input-group-lg > .input-group-addon, +textarea.input-group-lg > .input-group-btn > .btn, +select[multiple].input-group-lg > .form-control, +select[multiple].input-group-lg > .input-group-addon, +select[multiple].input-group-lg > .input-group-btn > .btn { + height: auto; +} +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 30px; + padding: 5px 10px; + font-size: 12px; + line-height: 1.5; + border-radius: 3px; +} +select.input-group-sm > .form-control, +select.input-group-sm > .input-group-addon, +select.input-group-sm > .input-group-btn > .btn { + height: 30px; + line-height: 30px; +} +textarea.input-group-sm > .form-control, +textarea.input-group-sm > .input-group-addon, +textarea.input-group-sm > .input-group-btn > .btn, +select[multiple].input-group-sm > .form-control, +select[multiple].input-group-sm > .input-group-addon, +select[multiple].input-group-sm > .input-group-btn > .btn { + height: auto; +} +.input-group-addon, +.input-group-btn, +.input-group .form-control { + display: table-cell; +} +.input-group-addon:not(:first-child):not(:last-child), +.input-group-btn:not(:first-child):not(:last-child), +.input-group .form-control:not(:first-child):not(:last-child) { + border-radius: 0; +} +.input-group-addon, +.input-group-btn { + width: 1%; + white-space: nowrap; + vertical-align: middle; +} +.input-group-addon { + padding: 6px 12px; + font-size: 14px; + font-weight: normal; + line-height: 1; + color: #555; + text-align: center; + background-color: #eee; + border: 1px solid #ccc; + border-radius: 4px; +} +.input-group-addon.input-sm { + padding: 5px 10px; + font-size: 12px; + border-radius: 3px; +} +.input-group-addon.input-lg { + padding: 10px 16px; + font-size: 18px; + border-radius: 6px; +} +.input-group-addon input[type="radio"], +.input-group-addon input[type="checkbox"] { + margin-top: 0; +} +.input-group .form-control:first-child, +.input-group-addon:first-child, +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group > .btn, +.input-group-btn:first-child > .dropdown-toggle, +.input-group-btn:last-child > .btn:not(:last-child):not(.dropdown-toggle), +.input-group-btn:last-child > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} +.input-group-addon:first-child { + border-right: 0; +} +.input-group .form-control:last-child, +.input-group-addon:last-child, +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group > .btn, +.input-group-btn:last-child > .dropdown-toggle, +.input-group-btn:first-child > .btn:not(:first-child), +.input-group-btn:first-child > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} +.input-group-addon:last-child { + border-left: 0; +} +.input-group-btn { + position: relative; + font-size: 0; + white-space: nowrap; +} +.input-group-btn > .btn { + position: relative; +} +.input-group-btn > .btn + .btn { + margin-left: -1px; +} +.input-group-btn > .btn:hover, +.input-group-btn > .btn:focus, +.input-group-btn > .btn:active { + z-index: 2; +} +.input-group-btn:first-child > .btn, +.input-group-btn:first-child > .btn-group { + margin-right: -1px; +} +.input-group-btn:last-child > .btn, +.input-group-btn:last-child > .btn-group { + margin-left: -1px; +} +.nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} +.nav > li { + position: relative; + display: block; +} +.nav > li > a { + position: relative; + display: block; + padding: 10px 15px; +} +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #999; +} +.nav > li.disabled > a:hover, +.nav > li.disabled > a:focus { + color: #999; + text-decoration: none; + cursor: not-allowed; + background-color: transparent; +} +.nav .open > a, +.nav .open > a:hover, +.nav .open > a:focus { + background-color: #eee; + border-color: #428bca; +} +.nav .nav-divider { + height: 1px; + margin: 9px 0; + overflow: hidden; + background-color: #e5e5e5; +} +.nav > li > a > img { + max-width: none; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eee #eee #ddd; +} +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #555; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.nav-tabs.nav-justified { + width: 100%; + border-bottom: 0; +} +.nav-tabs.nav-justified > li { + float: none; +} +.nav-tabs.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-tabs.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-tabs.nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs.nav-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs.nav-justified > .active > a, +.nav-tabs.nav-justified > .active > a:hover, +.nav-tabs.nav-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs.nav-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs.nav-justified > .active > a, + .nav-tabs.nav-justified > .active > a:hover, + .nav-tabs.nav-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #428bca; +} +.nav-stacked > li { + float: none; +} +.nav-stacked > li + li { + margin-top: 2px; + margin-left: 0; +} +.nav-justified { + width: 100%; +} +.nav-justified > li { + float: none; +} +.nav-justified > li > a { + margin-bottom: 5px; + text-align: center; +} +.nav-justified > .dropdown .dropdown-menu { + top: auto; + left: auto; +} +@media (min-width: 768px) { + .nav-justified > li { + display: table-cell; + width: 1%; + } + .nav-justified > li > a { + margin-bottom: 0; + } +} +.nav-tabs-justified { + border-bottom: 0; +} +.nav-tabs-justified > li > a { + margin-right: 0; + border-radius: 4px; +} +.nav-tabs-justified > .active > a, +.nav-tabs-justified > .active > a:hover, +.nav-tabs-justified > .active > a:focus { + border: 1px solid #ddd; +} +@media (min-width: 768px) { + .nav-tabs-justified > li > a { + border-bottom: 1px solid #ddd; + border-radius: 4px 4px 0 0; + } + .nav-tabs-justified > .active > a, + .nav-tabs-justified > .active > a:hover, + .nav-tabs-justified > .active > a:focus { + border-bottom-color: #fff; + } +} +.tab-content > .tab-pane { + display: none; +} +.tab-content > .active { + display: block; +} +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar { + position: relative; + min-height: 50px; + margin-bottom: 20px; + border: 1px solid transparent; +} +@media (min-width: 768px) { + .navbar { + border-radius: 4px; + } +} +@media (min-width: 768px) { + .navbar-header { + float: left; + } +} +.navbar-collapse { + max-height: 340px; + padding-right: 15px; + padding-left: 15px; + overflow-x: visible; + -webkit-overflow-scrolling: touch; + border-top: 1px solid transparent; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1); +} +.navbar-collapse.in { + overflow-y: auto; +} +@media (min-width: 768px) { + .navbar-collapse { + width: auto; + border-top: 0; + box-shadow: none; + } + .navbar-collapse.collapse { + display: block !important; + height: auto !important; + padding-bottom: 0; + overflow: visible !important; + } + .navbar-collapse.in { + overflow-y: visible; + } + .navbar-fixed-top .navbar-collapse, + .navbar-static-top .navbar-collapse, + .navbar-fixed-bottom .navbar-collapse { + padding-right: 0; + padding-left: 0; + } +} +.container > .navbar-header, +.container-fluid > .navbar-header, +.container > .navbar-collapse, +.container-fluid > .navbar-collapse { + margin-right: -15px; + margin-left: -15px; +} +@media (min-width: 768px) { + .container > .navbar-header, + .container-fluid > .navbar-header, + .container > .navbar-collapse, + .container-fluid > .navbar-collapse { + margin-right: 0; + margin-left: 0; + } +} +.navbar-static-top { + z-index: 1000; + border-width: 0 0 1px; +} +@media (min-width: 768px) { + .navbar-static-top { + border-radius: 0; + } +} +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; +} +@media (min-width: 768px) { + .navbar-fixed-top, + .navbar-fixed-bottom { + border-radius: 0; + } +} +.navbar-fixed-top { + top: 0; + border-width: 0 0 1px; +} +.navbar-fixed-bottom { + bottom: 0; + margin-bottom: 0; + border-width: 1px 0 0; +} +.navbar-brand { + float: left; + height: 20px; + padding: 15px 15px; + font-size: 18px; + line-height: 20px; +} +.navbar-brand:hover, +.navbar-brand:focus { + text-decoration: none; +} +@media (min-width: 768px) { + .navbar > .container .navbar-brand, + .navbar > .container-fluid .navbar-brand { + margin-left: -15px; + } +} +.navbar-toggle { + position: relative; + float: right; + padding: 9px 10px; + margin-top: 8px; + margin-right: 15px; + margin-bottom: 8px; + background-color: transparent; + background-image: none; + border: 1px solid transparent; + border-radius: 4px; +} +.navbar-toggle:focus { + outline: none; +} +.navbar-toggle .icon-bar { + display: block; + width: 22px; + height: 2px; + border-radius: 1px; +} +.navbar-toggle .icon-bar + .icon-bar { + margin-top: 4px; +} +@media (min-width: 768px) { + .navbar-toggle { + display: none; + } +} +.navbar-nav { + margin: 7.5px -15px; +} +.navbar-nav > li > a { + padding-top: 10px; + padding-bottom: 10px; + line-height: 20px; +} +@media (max-width: 767px) { + .navbar-nav .open .dropdown-menu { + position: static; + float: none; + width: auto; + margin-top: 0; + background-color: transparent; + border: 0; + box-shadow: none; + } + .navbar-nav .open .dropdown-menu > li > a, + .navbar-nav .open .dropdown-menu .dropdown-header { + padding: 5px 15px 5px 25px; + } + .navbar-nav .open .dropdown-menu > li > a { + line-height: 20px; + } + .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-nav .open .dropdown-menu > li > a:focus { + background-image: none; + } +} +@media (min-width: 768px) { + .navbar-nav { + float: left; + margin: 0; + } + .navbar-nav > li { + float: left; + } + .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + } + .navbar-nav.navbar-right:last-child { + margin-right: -15px; + } +} +@media (min-width: 768px) { + .navbar-left { + float: left !important; + } + .navbar-right { + float: right !important; + } +} +.navbar-form { + padding: 10px 15px; + margin-top: 8px; + margin-right: -15px; + margin-bottom: 8px; + margin-left: -15px; + border-top: 1px solid transparent; + border-bottom: 1px solid transparent; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, .1), 0 1px 0 rgba(255, 255, 255, .1); +} +@media (min-width: 768px) { + .navbar-form .form-group { + display: inline-block; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .form-control { + display: inline-block; + width: auto; + vertical-align: middle; + } + .navbar-form .control-label { + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio, + .navbar-form .checkbox { + display: inline-block; + padding-left: 0; + margin-top: 0; + margin-bottom: 0; + vertical-align: middle; + } + .navbar-form .radio input[type="radio"], + .navbar-form .checkbox input[type="checkbox"] { + float: none; + margin-left: 0; + } + .navbar-form .has-feedback .form-control-feedback { + top: 0; + } +} +@media (max-width: 767px) { + .navbar-form .form-group { + margin-bottom: 5px; + } +} +@media (min-width: 768px) { + .navbar-form { + width: auto; + padding-top: 0; + padding-bottom: 0; + margin-right: 0; + margin-left: 0; + border: 0; + -webkit-box-shadow: none; + box-shadow: none; + } + .navbar-form.navbar-right:last-child { + margin-right: -15px; + } +} +.navbar-nav > li > .dropdown-menu { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +.navbar-fixed-bottom .navbar-nav > li > .dropdown-menu { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} +.navbar-btn { + margin-top: 8px; + margin-bottom: 8px; +} +.navbar-btn.btn-sm { + margin-top: 10px; + margin-bottom: 10px; +} +.navbar-btn.btn-xs { + margin-top: 14px; + margin-bottom: 14px; +} +.navbar-text { + margin-top: 15px; + margin-bottom: 15px; +} +@media (min-width: 768px) { + .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; + } + .navbar-text.navbar-right:last-child { + margin-right: 0; + } +} +.navbar-default { + background-color: #f8f8f8; + border-color: #e7e7e7; +} +.navbar-default .navbar-brand { + color: #777; +} +.navbar-default .navbar-brand:hover, +.navbar-default .navbar-brand:focus { + color: #5e5e5e; + background-color: transparent; +} +.navbar-default .navbar-text { + color: #777; +} +.navbar-default .navbar-nav > li > a { + color: #777; +} +.navbar-default .navbar-nav > li > a:hover, +.navbar-default .navbar-nav > li > a:focus { + color: #333; + background-color: transparent; +} +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + color: #555; + background-color: #e7e7e7; +} +.navbar-default .navbar-nav > .disabled > a, +.navbar-default .navbar-nav > .disabled > a:hover, +.navbar-default .navbar-nav > .disabled > a:focus { + color: #ccc; + background-color: transparent; +} +.navbar-default .navbar-toggle { + border-color: #ddd; +} +.navbar-default .navbar-toggle:hover, +.navbar-default .navbar-toggle:focus { + background-color: #ddd; +} +.navbar-default .navbar-toggle .icon-bar { + background-color: #888; +} +.navbar-default .navbar-collapse, +.navbar-default .navbar-form { + border-color: #e7e7e7; +} +.navbar-default .navbar-nav > .open > a, +.navbar-default .navbar-nav > .open > a:hover, +.navbar-default .navbar-nav > .open > a:focus { + color: #555; + background-color: #e7e7e7; +} +@media (max-width: 767px) { + .navbar-default .navbar-nav .open .dropdown-menu > li > a { + color: #777; + } + .navbar-default .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > li > a:focus { + color: #333; + background-color: transparent; + } + .navbar-default .navbar-nav .open .dropdown-menu > .active > a, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #555; + background-color: #e7e7e7; + } + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #ccc; + background-color: transparent; + } +} +.navbar-default .navbar-link { + color: #777; +} +.navbar-default .navbar-link:hover { + color: #333; +} +.navbar-inverse { + background-color: #222; + border-color: #080808; +} +.navbar-inverse .navbar-brand { + color: #999; +} +.navbar-inverse .navbar-brand:hover, +.navbar-inverse .navbar-brand:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-text { + color: #999; +} +.navbar-inverse .navbar-nav > li > a { + color: #999; +} +.navbar-inverse .navbar-nav > li > a:hover, +.navbar-inverse .navbar-nav > li > a:focus { + color: #fff; + background-color: transparent; +} +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #080808; +} +.navbar-inverse .navbar-nav > .disabled > a, +.navbar-inverse .navbar-nav > .disabled > a:hover, +.navbar-inverse .navbar-nav > .disabled > a:focus { + color: #444; + background-color: transparent; +} +.navbar-inverse .navbar-toggle { + border-color: #333; +} +.navbar-inverse .navbar-toggle:hover, +.navbar-inverse .navbar-toggle:focus { + background-color: #333; +} +.navbar-inverse .navbar-toggle .icon-bar { + background-color: #fff; +} +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #101010; +} +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus { + color: #fff; + background-color: #080808; +} +@media (max-width: 767px) { + .navbar-inverse .navbar-nav .open .dropdown-menu > .dropdown-header { + border-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #999; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a:focus { + color: #fff; + background-color: transparent; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .active > a:focus { + color: #fff; + background-color: #080808; + } + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:hover, + .navbar-inverse .navbar-nav .open .dropdown-menu > .disabled > a:focus { + color: #444; + background-color: transparent; + } +} +.navbar-inverse .navbar-link { + color: #999; +} +.navbar-inverse .navbar-link:hover { + color: #fff; +} +.breadcrumb { + padding: 8px 15px; + margin-bottom: 20px; + list-style: none; + background-color: #f5f5f5; + border-radius: 4px; +} +.breadcrumb > li { + display: inline-block; +} +.breadcrumb > li + li:before { + padding: 0 5px; + color: #ccc; + content: "/\00a0"; +} +.breadcrumb > .active { + color: #999; +} +.pagination { + display: inline-block; + padding-left: 0; + margin: 20px 0; + border-radius: 4px; +} +.pagination > li { + display: inline; +} +.pagination > li > a, +.pagination > li > span { + position: relative; + float: left; + padding: 6px 12px; + margin-left: -1px; + line-height: 1.428571429; + color: #428bca; + text-decoration: none; + background-color: #fff; + border: 1px solid #ddd; +} +.pagination > li:first-child > a, +.pagination > li:first-child > span { + margin-left: 0; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} +.pagination > li > a:hover, +.pagination > li > span:hover, +.pagination > li > a:focus, +.pagination > li > span:focus { + color: #2a6496; + background-color: #eee; + border-color: #ddd; +} +.pagination > .active > a, +.pagination > .active > span, +.pagination > .active > a:hover, +.pagination > .active > span:hover, +.pagination > .active > a:focus, +.pagination > .active > span:focus { + z-index: 2; + color: #fff; + cursor: default; + background-color: #428bca; + border-color: #428bca; +} +.pagination > .disabled > span, +.pagination > .disabled > span:hover, +.pagination > .disabled > span:focus, +.pagination > .disabled > a, +.pagination > .disabled > a:hover, +.pagination > .disabled > a:focus { + color: #999; + cursor: not-allowed; + background-color: #fff; + border-color: #ddd; +} +.pagination-lg > li > a, +.pagination-lg > li > span { + padding: 10px 16px; + font-size: 18px; +} +.pagination-lg > li:first-child > a, +.pagination-lg > li:first-child > span { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; +} +.pagination-lg > li:last-child > a, +.pagination-lg > li:last-child > span { + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; +} +.pagination-sm > li > a, +.pagination-sm > li > span { + padding: 5px 10px; + font-size: 12px; +} +.pagination-sm > li:first-child > a, +.pagination-sm > li:first-child > span { + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; +} +.pagination-sm > li:last-child > a, +.pagination-sm > li:last-child > span { + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; +} +.pager { + padding-left: 0; + margin: 20px 0; + text-align: center; + list-style: none; +} +.pager li { + display: inline; +} +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 15px; +} +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #eee; +} +.pager .next > a, +.pager .next > span { + float: right; +} +.pager .previous > a, +.pager .previous > span { + float: left; +} +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999; + cursor: not-allowed; + background-color: #fff; +} +.label { + display: inline; + padding: .2em .6em .3em; + font-size: 75%; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25em; +} +.label[href]:hover, +.label[href]:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +.label:empty { + display: none; +} +.btn .label { + position: relative; + top: -1px; +} +.label-default { + background-color: #999; +} +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #808080; +} +.label-primary { + background-color: #428bca; +} +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #3071a9; +} +.label-success { + background-color: #5cb85c; +} +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #449d44; +} +.label-info { + background-color: #5bc0de; +} +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #31b0d5; +} +.label-warning { + background-color: #f0ad4e; +} +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ec971f; +} +.label-danger { + background-color: #d9534f; +} +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #c9302c; +} +.badge { + display: inline-block; + min-width: 10px; + padding: 3px 7px; + font-size: 12px; + font-weight: bold; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + background-color: #999; + border-radius: 10px; +} +.badge:empty { + display: none; +} +.btn .badge { + position: relative; + top: -1px; +} +.btn-xs .badge { + top: 0; + padding: 1px 5px; +} +a.badge:hover, +a.badge:focus { + color: #fff; + text-decoration: none; + cursor: pointer; +} +a.list-group-item.active > .badge, +.nav-pills > .active > a > .badge { + color: #428bca; + background-color: #fff; +} +.nav-pills > li > a > .badge { + margin-left: 3px; +} +.jumbotron { + padding: 30px; + margin-bottom: 30px; + color: inherit; + background-color: #eee; +} +.jumbotron h1, +.jumbotron .h1 { + color: inherit; +} +.jumbotron p { + margin-bottom: 15px; + font-size: 21px; + font-weight: 200; +} +.container .jumbotron { + border-radius: 6px; +} +.jumbotron .container { + max-width: 100%; +} +@media screen and (min-width: 768px) { + .jumbotron { + padding-top: 48px; + padding-bottom: 48px; + } + .container .jumbotron { + padding-right: 60px; + padding-left: 60px; + } + .jumbotron h1, + .jumbotron .h1 { + font-size: 63px; + } +} +.thumbnail { + display: block; + padding: 4px; + margin-bottom: 20px; + line-height: 1.428571429; + background-color: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -webkit-transition: all .2s ease-in-out; + transition: all .2s ease-in-out; +} +.thumbnail > img, +.thumbnail a > img { + display: block; + max-width: 100%; + height: auto; + margin-right: auto; + margin-left: auto; +} +a.thumbnail:hover, +a.thumbnail:focus, +a.thumbnail.active { + border-color: #428bca; +} +.thumbnail .caption { + padding: 9px; + color: #333; +} +.alert { + padding: 15px; + margin-bottom: 20px; + border: 1px solid transparent; + border-radius: 4px; +} +.alert h4 { + margin-top: 0; + color: inherit; +} +.alert .alert-link { + font-weight: bold; +} +.alert > p, +.alert > ul { + margin-bottom: 0; +} +.alert > p + p { + margin-top: 5px; +} +.alert-dismissable { + padding-right: 35px; +} +.alert-dismissable .close { + position: relative; + top: -2px; + right: -21px; + color: inherit; +} +.alert-success { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.alert-success hr { + border-top-color: #c9e2b3; +} +.alert-success .alert-link { + color: #2b542c; +} +.alert-info { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.alert-info hr { + border-top-color: #a6e1ec; +} +.alert-info .alert-link { + color: #245269; +} +.alert-warning { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.alert-warning hr { + border-top-color: #f7e1b5; +} +.alert-warning .alert-link { + color: #66512c; +} +.alert-danger { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.alert-danger hr { + border-top-color: #e4b9c0; +} +.alert-danger .alert-link { + color: #843534; +} +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f5f5f5; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, .1); +} +.progress-bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + line-height: 20px; + color: #fff; + text-align: center; + background-color: #428bca; + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .15); + -webkit-transition: width .6s ease; + transition: width .6s ease; +} +.progress-striped .progress-bar { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} +.progress.active .progress-bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} +.progress-bar-success { + background-color: #5cb85c; +} +.progress-striped .progress-bar-success { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-info { + background-color: #5bc0de; +} +.progress-striped .progress-bar-info { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-warning { + background-color: #f0ad4e; +} +.progress-striped .progress-bar-warning { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.progress-bar-danger { + background-color: #d9534f; +} +.progress-striped .progress-bar-danger { + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); +} +.media, +.media-body { + overflow: hidden; + zoom: 1; +} +.media, +.media .media { + margin-top: 15px; +} +.media:first-child { + margin-top: 0; +} +.media-object { + display: block; +} +.media-heading { + margin: 0 0 5px; +} +.media > .pull-left { + margin-right: 10px; +} +.media > .pull-right { + margin-left: 10px; +} +.media-list { + padding-left: 0; + list-style: none; +} +.list-group { + padding-left: 0; + margin-bottom: 20px; +} +.list-group-item { + position: relative; + display: block; + padding: 10px 15px; + margin-bottom: -1px; + background-color: #fff; + border: 1px solid #ddd; +} +.list-group-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; +} +.list-group-item:last-child { + margin-bottom: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; +} +.list-group-item > .badge { + float: right; +} +.list-group-item > .badge + .badge { + margin-right: 5px; +} +a.list-group-item { + color: #555; +} +a.list-group-item .list-group-item-heading { + color: #333; +} +a.list-group-item:hover, +a.list-group-item:focus { + text-decoration: none; + background-color: #f5f5f5; +} +a.list-group-item.active, +a.list-group-item.active:hover, +a.list-group-item.active:focus { + z-index: 2; + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +a.list-group-item.active .list-group-item-heading, +a.list-group-item.active:hover .list-group-item-heading, +a.list-group-item.active:focus .list-group-item-heading { + color: inherit; +} +a.list-group-item.active .list-group-item-text, +a.list-group-item.active:hover .list-group-item-text, +a.list-group-item.active:focus .list-group-item-text { + color: #e1edf7; +} +.list-group-item-success { + color: #3c763d; + background-color: #dff0d8; +} +a.list-group-item-success { + color: #3c763d; +} +a.list-group-item-success .list-group-item-heading { + color: inherit; +} +a.list-group-item-success:hover, +a.list-group-item-success:focus { + color: #3c763d; + background-color: #d0e9c6; +} +a.list-group-item-success.active, +a.list-group-item-success.active:hover, +a.list-group-item-success.active:focus { + color: #fff; + background-color: #3c763d; + border-color: #3c763d; +} +.list-group-item-info { + color: #31708f; + background-color: #d9edf7; +} +a.list-group-item-info { + color: #31708f; +} +a.list-group-item-info .list-group-item-heading { + color: inherit; +} +a.list-group-item-info:hover, +a.list-group-item-info:focus { + color: #31708f; + background-color: #c4e3f3; +} +a.list-group-item-info.active, +a.list-group-item-info.active:hover, +a.list-group-item-info.active:focus { + color: #fff; + background-color: #31708f; + border-color: #31708f; +} +.list-group-item-warning { + color: #8a6d3b; + background-color: #fcf8e3; +} +a.list-group-item-warning { + color: #8a6d3b; +} +a.list-group-item-warning .list-group-item-heading { + color: inherit; +} +a.list-group-item-warning:hover, +a.list-group-item-warning:focus { + color: #8a6d3b; + background-color: #faf2cc; +} +a.list-group-item-warning.active, +a.list-group-item-warning.active:hover, +a.list-group-item-warning.active:focus { + color: #fff; + background-color: #8a6d3b; + border-color: #8a6d3b; +} +.list-group-item-danger { + color: #a94442; + background-color: #f2dede; +} +a.list-group-item-danger { + color: #a94442; +} +a.list-group-item-danger .list-group-item-heading { + color: inherit; +} +a.list-group-item-danger:hover, +a.list-group-item-danger:focus { + color: #a94442; + background-color: #ebcccc; +} +a.list-group-item-danger.active, +a.list-group-item-danger.active:hover, +a.list-group-item-danger.active:focus { + color: #fff; + background-color: #a94442; + border-color: #a94442; +} +.list-group-item-heading { + margin-top: 0; + margin-bottom: 5px; +} +.list-group-item-text { + margin-bottom: 0; + line-height: 1.3; +} +.panel { + margin-bottom: 20px; + background-color: #fff; + border: 1px solid transparent; + border-radius: 4px; + -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: 0 1px 1px rgba(0, 0, 0, .05); +} +.panel-body { + padding: 20px 10px 0px 10px; +} +.panel > .list-group { + margin-bottom: 0; +} +.panel > .list-group .list-group-item { + 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-left-radius: 3px; + border-top-right-radius: 3px; +} +.panel > .list-group:last-child .list-group-item:last-child { + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} +.panel-heading + .list-group .list-group-item:first-child { + border-top-width: 0; +} +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} +.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, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:first-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:first-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:first-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child th:first-child { + border-top-left-radius: 3px; +} +.panel > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child td:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table-responsive:first-child > .table:first-child > tbody:first-child > tr:first-child td:last-child, +.panel > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table-responsive:first-child > .table:first-child > thead:first-child > tr:first-child th:last-child, +.panel > .table:first-child > tbody:first-child > tr:first-child th:last-child, +.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 > 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, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:first-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:first-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:first-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:first-child { + border-bottom-left-radius: 3px; +} +.panel > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child td:last-child, +.panel > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tbody:last-child > tr:last-child th:last-child, +.panel > .table:last-child > tfoot:last-child > tr:last-child th:last-child, +.panel > .table-responsive:last-child > .table:last-child > tfoot:last-child > tr:last-child th:last-child { + border-bottom-right-radius: 3px; +} +.panel > .panel-body + .table, +.panel > .panel-body + .table-responsive { + border-top: 1px solid #ddd; +} +.panel > .table > tbody:first-child > tr:first-child th, +.panel > .table > tbody:first-child > tr:first-child td { + border-top: 0; +} +.panel > .table-bordered, +.panel > .table-responsive > .table-bordered { + border: 0; +} +.panel > .table-bordered > thead > tr > th:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:first-child, +.panel > .table-bordered > tbody > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:first-child, +.panel > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:first-child, +.panel > .table-bordered > thead > tr > td:first-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:first-child, +.panel > .table-bordered > tbody > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:first-child, +.panel > .table-bordered > tfoot > tr > td:first-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} +.panel > .table-bordered > thead > tr > th:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > th:last-child, +.panel > .table-bordered > tbody > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > th:last-child, +.panel > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-responsive > .table-bordered > tfoot > tr > th:last-child, +.panel > .table-bordered > thead > tr > td:last-child, +.panel > .table-responsive > .table-bordered > thead > tr > td:last-child, +.panel > .table-bordered > tbody > tr > td:last-child, +.panel > .table-responsive > .table-bordered > tbody > tr > td:last-child, +.panel > .table-bordered > tfoot > tr > td:last-child, +.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: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 { + 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; +} +.panel-group .panel { + margin-bottom: 0; + overflow: hidden; + border-radius: 4px; +} +.panel-group .panel + .panel { + margin-top: 5px; +} +.panel-group .panel-heading { + border-bottom: 0; +} +.panel-group .panel-heading + .panel-collapse .panel-body { + border-top: 1px solid #ddd; +} +.panel-group .panel-footer { + border-top: 0; +} +.panel-group .panel-footer + .panel-collapse .panel-body { + border-bottom: 1px solid #ddd; +} +.panel-default { + border-color: #ddd; +} +.panel-default > .panel-heading { + color: #333; + background-color: #f5f5f5; + border-color: #ddd; +} +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ddd; +} +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ddd; +} +.panel-primary { + border-color: #428bca; +} +.panel-primary > .panel-heading { + color: #fff; + background-color: #428bca; + border-color: #428bca; +} +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #428bca; +} +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #428bca; +} +.panel-success { + border-color: #d6e9c6; +} +.panel-success > .panel-heading { + color: #3c763d; + background-color: #dff0d8; + border-color: #d6e9c6; +} +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #d6e9c6; +} +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #d6e9c6; +} +.panel-info { + border-color: #bce8f1; +} +.panel-info > .panel-heading { + color: #31708f; + background-color: #d9edf7; + border-color: #bce8f1; +} +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #bce8f1; +} +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #bce8f1; +} +.panel-warning { + border-color: #faebcc; +} +.panel-warning > .panel-heading { + color: #8a6d3b; + background-color: #fcf8e3; + border-color: #faebcc; +} +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #faebcc; +} +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #faebcc; +} +.panel-danger { + border-color: #ebccd1; +} +.panel-danger > .panel-heading { + color: #a94442; + background-color: #f2dede; + border-color: #ebccd1; +} +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #ebccd1; +} +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #ebccd1; +} +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, .05); +} +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, .15); +} +.well-lg { + padding: 24px; + border-radius: 6px; +} +.well-sm { + padding: 9px; + border-radius: 3px; +} +.close { + float: right; + font-size: 21px; + font-weight: bold; + line-height: 1; + color: #000; + text-shadow: 0 1px 0 #fff; + filter: alpha(opacity=20); + opacity: .2; +} +.close:hover, +.close:focus { + color: #000; + text-decoration: none; + cursor: pointer; + filter: alpha(opacity=50); + opacity: .5; +} +button.close { + -webkit-appearance: none; + padding: 0; + cursor: pointer; + background: transparent; + border: 0; +} +.modal-open { + overflow: hidden; +} +.modal { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1050; + display: none; + overflow: auto; + overflow-y: scroll; + -webkit-overflow-scrolling: touch; + outline: 0; +} +.modal.fade .modal-dialog { + -webkit-transition: -webkit-transform .3s ease-out; + -moz-transition: -moz-transform .3s ease-out; + -o-transition: -o-transform .3s ease-out; + transition: transform .3s ease-out; + -webkit-transform: translate(0, -25%); + -ms-transform: translate(0, -25%); + transform: translate(0, -25%); +} +.modal.in .modal-dialog { + -webkit-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +.modal-dialog { + position: relative; + width: auto; + margin: 10px; +} +.modal-content { + position: relative; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, .5); + box-shadow: 0 3px 9px rgba(0, 0, 0, .5); +} +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000; +} +.modal-backdrop.fade { + filter: alpha(opacity=0); + opacity: 0; +} +.modal-backdrop.in { + filter: alpha(opacity=50); + opacity: .5; +} +.modal-header { + min-height: 16.428571429px; + padding: 15px; + border-bottom: 1px solid #e5e5e5; +} +.modal-header .close { + margin-top: -2px; +} +.modal-title { + margin: 0; + line-height: 1.428571429; +} +.modal-body { + position: relative; + padding: 20px; +} +.modal-footer { + padding: 19px 20px 20px; + margin-top: 15px; + text-align: right; + border-top: 1px solid #e5e5e5; +} +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} +@media (min-width: 768px) { + .modal-dialog { + width: 600px; + margin: 30px auto; + } + .modal-content { + -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + } + .modal-sm { + width: 300px; + } + .modal-lg { + width: 900px; + } +} +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 12px; + line-height: 1.4; + visibility: visible; + filter: alpha(opacity=0); + opacity: 0; +} +.tooltip.in { + filter: alpha(opacity=90); + opacity: .9; +} +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} +.tooltip-inner { + max-width: 200px; + padding: 3px 8px; + color: #fff; + text-align: center; + text-decoration: none; + background-color: #000; + border-radius: 4px; +} +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-left .tooltip-arrow { + bottom: 0; + left: 5px; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.top-right .tooltip-arrow { + right: 5px; + bottom: 0; + border-width: 5px 5px 0; + border-top-color: #000; +} +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-width: 5px 5px 5px 0; + border-right-color: #000; +} +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-width: 5px 0 5px 5px; + border-left-color: #000; +} +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-left .tooltip-arrow { + top: 0; + left: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.tooltip.bottom-right .tooltip-arrow { + top: 0; + right: 5px; + border-width: 0 5px 5px; + border-bottom-color: #000; +} +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, .2); + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2); + box-shadow: 0 5px 10px rgba(0, 0, 0, .2); +} +.popover.top { + margin-top: -10px; +} +.popover.right { + margin-left: 10px; +} +.popover.bottom { + margin-top: 10px; +} +.popover.left { + margin-left: -10px; +} +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + border-radius: 5px 5px 0 0; +} +.popover-content { + padding: 9px 14px; +} +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} +.popover .arrow { + border-width: 11px; +} +.popover .arrow:after { + content: ""; + border-width: 10px; +} +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, .25); + border-bottom-width: 0; +} +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + content: " "; + border-top-color: #fff; + border-bottom-width: 0; +} +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, .25); + border-left-width: 0; +} +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + content: " "; + border-right-color: #fff; + border-left-width: 0; +} +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-top-width: 0; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, .25); +} +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + content: " "; + border-top-width: 0; + border-bottom-color: #fff; +} +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-right-width: 0; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, .25); +} +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + content: " "; + border-right-width: 0; + border-left-color: #fff; +} +.carousel { + position: relative; +} +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: .6s ease-in-out left; + transition: .6s ease-in-out left; +} +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + max-width: 100%; + height: auto; + line-height: 1; +} +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} +.carousel-inner > .active { + left: 0; +} +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} +.carousel-inner > .next { + left: 100%; +} +.carousel-inner > .prev { + left: -100%; +} +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} +.carousel-inner > .active.left { + left: -100%; +} +.carousel-inner > .active.right { + left: 100%; +} +.carousel-control { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 15%; + font-size: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); + filter: alpha(opacity=50); + opacity: .5; +} +.carousel-control.left { + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .5) 0%), color-stop(rgba(0, 0, 0, .0001) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, .5) 0%, rgba(0, 0, 0, .0001) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control.right { + right: 0; + left: auto; + background-image: -webkit-linear-gradient(left, color-stop(rgba(0, 0, 0, .0001) 0%), color-stop(rgba(0, 0, 0, .5) 100%)); + background-image: linear-gradient(to right, rgba(0, 0, 0, .0001) 0%, rgba(0, 0, 0, .5) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1); + background-repeat: repeat-x; +} +.carousel-control:hover, +.carousel-control:focus { + color: #fff; + text-decoration: none; + filter: alpha(opacity=90); + outline: none; + opacity: .9; +} +.carousel-control .icon-prev, +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-left, +.carousel-control .glyphicon-chevron-right { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; +} +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} +.carousel-control .icon-next, +.carousel-control .glyphicon-chevron-right { + right: 50%; +} +.carousel-control .icon-prev, +.carousel-control .icon-next { + width: 20px; + height: 20px; + margin-top: -10px; + margin-left: -10px; + font-family: serif; +} +.carousel-control .icon-prev:before { + content: '\2039'; +} +.carousel-control .icon-next:before { + content: '\203a'; +} +.carousel-indicators { + position: absolute; + bottom: 10px; + left: 50%; + z-index: 15; + width: 60%; + padding-left: 0; + margin-left: -30%; + text-align: center; + list-style: none; +} +.carousel-indicators li { + display: inline-block; + width: 10px; + height: 10px; + margin: 1px; + text-indent: -999px; + cursor: pointer; + background-color: #000 \9; + background-color: rgba(0, 0, 0, 0); + border: 1px solid #fff; + border-radius: 10px; +} +.carousel-indicators .active { + width: 12px; + height: 12px; + margin: 0; + background-color: #fff; +} +.carousel-caption { + position: absolute; + right: 15%; + bottom: 20px; + left: 15%; + z-index: 10; + padding-top: 20px; + padding-bottom: 20px; + color: #fff; + text-align: center; + text-shadow: 0 1px 2px rgba(0, 0, 0, .6); +} +.carousel-caption .btn { + text-shadow: none; +} +@media screen and (min-width: 768px) { + .carousel-control .glyphicons-chevron-left, + .carousel-control .glyphicons-chevron-right, + .carousel-control .icon-prev, + .carousel-control .icon-next { + width: 30px; + height: 30px; + margin-top: -15px; + margin-left: -15px; + font-size: 30px; + } + .carousel-caption { + right: 20%; + left: 20%; + padding-bottom: 30px; + } + .carousel-indicators { + bottom: 20px; + } +} +.clearfix:before, +.clearfix:after, +.container:before, +.container:after, +.container-fluid:before, +.container-fluid:after, +.row:before, +.row:after, +.form-horizontal .form-group:before, +.form-horizontal .form-group:after, +.btn-toolbar:before, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:before, +.btn-group-vertical > .btn-group:after, +.nav:before, +.nav:after, +.navbar:before, +.navbar:after, +.navbar-header:before, +.navbar-header:after, +.navbar-collapse:before, +.navbar-collapse:after, +.pager:before, +.pager:after, +.panel-body:before, +.panel-body:after, +.modal-footer:before, +.modal-footer:after { + display: table; + content: " "; +} +.clearfix:after, +.container:after, +.container-fluid:after, +.row:after, +.form-horizontal .form-group:after, +.btn-toolbar:after, +.btn-group-vertical > .btn-group:after, +.nav:after, +.navbar:after, +.navbar-header:after, +.navbar-collapse:after, +.pager:after, +.panel-body:after, +.modal-footer:after { + clear: both; +} +.center-block { + display: block; + margin-right: auto; + margin-left: auto; +} +.pull-right { + float: right !important; +} +.pull-left { + float: left !important; +} +.hide { + display: none !important; +} +.show { + display: block !important; +} +.invisible { + visibility: hidden; +} +.text-hide { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} +.hidden { + display: none !important; + visibility: hidden !important; +} +.affix { + position: fixed; +} +@-ms-viewport { + width: device-width; +} +.visible-xs, +tr.visible-xs, +th.visible-xs, +td.visible-xs { + display: none !important; +} +@media (max-width: 767px) { + .visible-xs { + display: block !important; + } + table.visible-xs { + display: table; + } + tr.visible-xs { + display: table-row !important; + } + th.visible-xs, + 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; + } + table.visible-sm { + display: table; + } + tr.visible-sm { + display: table-row !important; + } + th.visible-sm, + 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; + } + table.visible-md { + display: table; + } + tr.visible-md { + display: table-row !important; + } + th.visible-md, + 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; + } + table.visible-lg { + display: table; + } + tr.visible-lg { + display: table-row !important; + } + th.visible-lg, + td.visible-lg { + display: table-cell !important; + } +} +@media (max-width: 767px) { + .hidden-xs, + tr.hidden-xs, + th.hidden-xs, + td.hidden-xs { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .hidden-sm, + tr.hidden-sm, + th.hidden-sm, + td.hidden-sm { + display: none !important; + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .hidden-md, + tr.hidden-md, + th.hidden-md, + td.hidden-md { + display: none !important; + } +} +@media (min-width: 1200px) { + .hidden-lg, + tr.hidden-lg, + th.hidden-lg, + td.hidden-lg { + display: none !important; + } +} +.visible-print, +tr.visible-print, +th.visible-print, +td.visible-print { + display: none !important; +} +@media print { + .visible-print { + display: block !important; + } + table.visible-print { + display: table; + } + tr.visible-print { + display: table-row !important; + } + th.visible-print, + td.visible-print { + display: table-cell !important; + } +} +@media print { + .hidden-print, + tr.hidden-print, + th.hidden-print, + td.hidden-print { + display: none !important; + } +} +/*# sourceMappingURL=bootstrap.css.map */ diff --git a/public/site_assets/bootstrap/css/bootstrap.min.css b/public/site_assets/bootstrap/css/bootstrap.min.css new file mode 100644 index 00000000..4f9cd67c --- /dev/null +++ b/public/site_assets/bootstrap/css/bootstrap.min.css @@ -0,0 +1,7 @@ +/*! + * Bootstrap v3.1.0 (http://getbootstrap.com) + * Copyright 2011-2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/*! normalize.css v3.0.0 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:0 0}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}@media print{*{text-shadow:none!important;color:#000!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}:before,:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#333;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#428bca;text-decoration:none}a:hover,a:focus{color:#2a6496;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}figure{margin:0}img{vertical-align:middle}.img-responsive{display:block;max-width:100%;height:auto}.img-rounded{border-radius:6px}.img-thumbnail{padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out;display:inline-block;max-width:100%;height:auto}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:inherit;font-weight:500;line-height:1.1;color:inherit}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:400;line-height:1;color:#999}h1,.h1,h2,.h2,h3,.h3{margin-top:20px;margin-bottom:10px}h1 small,.h1 small,h2 small,.h2 small,h3 small,.h3 small,h1 .small,.h1 .small,h2 .small,.h2 .small,h3 .small,.h3 .small{font-size:65%}h4,.h4,h5,.h5,h6,.h6{margin-top:10px;margin-bottom:10px}h4 small,.h4 small,h5 small,.h5 small,h6 small,.h6 small,h4 .small,.h4 .small,h5 .small,.h5 .small,h6 .small,.h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media (min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.text-justify{text-align:justify}.text-muted{color:#999}.text-primary{color:#428bca}a.text-primary:hover{color:#3071a9}.text-success{color:#3c763d}a.text-success:hover{color:#2b542c}.text-info{color:#31708f}a.text-info:hover{color:#245269}.text-warning{color:#8a6d3b}a.text-warning:hover{color:#66512c}.text-danger{color:#a94442}a.text-danger:hover{color:#843534}.bg-primary{color:#fff;background-color:#428bca}a.bg-primary:hover{background-color:#3071a9}.bg-success{background-color:#dff0d8}a.bg-success:hover{background-color:#c1e2b3}.bg-info{background-color:#d9edf7}a.bg-info:hover{background-color:#afd9ee}.bg-warning{background-color:#fcf8e3}a.bg-warning:hover{background-color:#f7ecb5}.bg-danger{background-color:#f2dede}a.bg-danger:hover{background-color:#e4b9b9}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-left:5px;padding-right:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:700}dd{margin-left:0}@media (min-width:768px){.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;font-size:17.5px;border-left:5px solid #eee}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}blockquote footer,blockquote small,blockquote .small{display:block;font-size:80%;line-height:1.428571429;color:#999}blockquote footer:before,blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}.blockquote-reverse,blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0;text-align:right}.blockquote-reverse footer:before,blockquote.pull-right footer:before,.blockquote-reverse small:before,blockquote.pull-right small:before,.blockquote-reverse .small:before,blockquote.pull-right .small:before{content:''}.blockquote-reverse footer:after,blockquote.pull-right footer:after,.blockquote-reverse small:after,blockquote.pull-right small:after,.blockquote-reverse .small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;background-color:#f9f2f4;white-space:nowrap;border-radius:4px}kbd{padding:2px 4px;font-size:90%;color:#fff;background-color:#333;border-radius:3px;box-shadow:inset 0 -1px 0 rgba(0,0,0,.25)}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;word-break:break-all;word-wrap:break-word;color:#333;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}@media (min-width:768px){.container{width:750px}}@media (min-width:992px){.container{width:970px}}@media (min-width:1200px){.container{width:1170px}}.container-fluid{margin-right:auto;margin-left:auto;padding-left:15px;padding-right:15px}.row{margin-left:-15px;margin-right:-15px}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-left:15px;padding-right:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media (min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media (min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media (min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*=col-]{position:static;float:none;display:table-column}table td[class*=col-],table th[class*=col-]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>tbody>tr>td.active,.table>tfoot>tr>td.active,.table>thead>tr>th.active,.table>tbody>tr>th.active,.table>tfoot>tr>th.active,.table>thead>tr.active>td,.table>tbody>tr.active>td,.table>tfoot>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr.active>th,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>tbody>tr>td.success,.table>tfoot>tr>td.success,.table>thead>tr>th.success,.table>tbody>tr>th.success,.table>tfoot>tr>th.success,.table>thead>tr.success>td,.table>tbody>tr.success>td,.table>tfoot>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr.success>th,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>tbody>tr>td.info,.table>tfoot>tr>td.info,.table>thead>tr>th.info,.table>tbody>tr>th.info,.table>tfoot>tr>th.info,.table>thead>tr.info>td,.table>tbody>tr.info>td,.table>tfoot>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr.info>th,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>tbody>tr>td.warning,.table>tfoot>tr>td.warning,.table>thead>tr>th.warning,.table>tbody>tr>th.warning,.table>tfoot>tr>th.warning,.table>thead>tr.warning>td,.table>tbody>tr.warning>td,.table>tfoot>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr.warning>th,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>tbody>tr>td.danger,.table>tfoot>tr>td.danger,.table>thead>tr>th.danger,.table>tbody>tr>th.danger,.table>tfoot>tr>th.danger,.table>thead>tr.danger>td,.table>tbody>tr.danger>td,.table>tfoot>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr.danger>th,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}@media (max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;overflow-x:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #ddd;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0;min-width:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#333;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:700}input[type=search]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type=radio],input[type=checkbox]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type=file]{display:block}input[type=range]{display:block;width:100%}select[multiple],select[size]{height:auto}input[type=file]:focus,input[type=radio]:focus,input[type=checkbox]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}output{display:block;padding-top:7px;font-size:14px;line-height:1.428571429;color:#555}.form-control{display:block;width:100%;height:34px;padding:6px 12px;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-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}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee;opacity:1}textarea.form-control{height:auto}input[type=date]{line-height:34px}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;margin-top:10px;margin-bottom:10px;padding-left:20px}.radio label,.checkbox label{display:inline;font-weight:400;cursor:pointer}.radio input[type=radio],.radio-inline input[type=radio],.checkbox input[type=checkbox],.checkbox-inline input[type=checkbox]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;vertical-align:middle;font-weight:400;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type=radio][disabled],input[type=checkbox][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type=radio],fieldset[disabled] input[type=checkbox],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm,select[multiple].input-sm{height:auto}.input-lg{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:46px;line-height:46px}textarea.input-lg,select[multiple].input-lg{height:auto}.has-feedback{position:relative}.has-feedback .form-control{padding-right:42.5px}.has-feedback .form-control-feedback{position:absolute;top:25px;right:0;display:block;width:34px;height:34px;line-height:34px;text-align:center}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#3c763d}.has-success .form-control{border-color:#3c763d;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-success .form-control:focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.has-success .input-group-addon{color:#3c763d;border-color:#3c763d;background-color:#dff0d8}.has-success .form-control-feedback{color:#3c763d}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#8a6d3b}.has-warning .form-control{border-color:#8a6d3b;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-warning .form-control:focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-warning .input-group-addon{color:#8a6d3b;border-color:#8a6d3b;background-color:#fcf8e3}.has-warning .form-control-feedback{color:#8a6d3b}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#a94442}.has-error .form-control{border-color:#a94442;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 1px rgba(0,0,0,.075)}.has-error .form-control:focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-error .input-group-addon{color:#a94442;border-color:#a94442;background-color:#f2dede}.has-error .form-control-feedback{color:#a94442}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#737373}@media (min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .control-label{margin-bottom:0;vertical-align:middle}.form-inline .radio,.form-inline .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.form-inline .radio input[type=radio],.form-inline .checkbox input[type=checkbox]{float:none;margin-left:0}.form-inline .has-feedback .form-control-feedback{top:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{margin-top:0;margin-bottom:0;padding-top:7px}.form-horizontal .radio,.form-horizontal .checkbox{min-height:27px}.form-horizontal .form-group{margin-left:-15px;margin-right:-15px}.form-horizontal .form-control-static{padding-top:7px}@media (min-width:768px){.form-horizontal .control-label{text-align:right}}.form-horizontal .has-feedback .form-control-feedback{top:0;right:15px}.btn{display:inline-block;margin-bottom:0;font-weight:400;text-align:center;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;white-space:nowrap;padding:6px 12px;font-size:14px;line-height:1.428571429;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#333;text-decoration:none}.btn:active,.btn.active{outline:0;background-image:none;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{cursor:not-allowed;pointer-events:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#333;background-color:#fff;border-color:#ccc}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#333;background-color:#ebebeb;border-color:#adadad}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:#ccc}.btn-default .badge{color:#fff;background-color:#333}.btn-primary{color:#fff;background-color:#428bca;border-color:#357ebd}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#3276b1;border-color:#285e8e}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#428bca;border-color:#357ebd}.btn-primary .badge{color:#428bca;background-color:#fff}.btn-success{color:#fff;background-color:#5cb85c;border-color:#4cae4c}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#47a447;border-color:#398439}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#5cb85c;border-color:#4cae4c}.btn-success .badge{color:#5cb85c;background-color:#fff}.btn-info{color:#fff;background-color:#5bc0de;border-color:#46b8da}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#39b3d7;border-color:#269abc}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#5bc0de;border-color:#46b8da}.btn-info .badge{color:#5bc0de;background-color:#fff}.btn-warning{color:#fff;background-color:#f0ad4e;border-color:#eea236}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#ed9c28;border-color:#d58512}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#f0ad4e;border-color:#eea236}.btn-warning .badge{color:#f0ad4e;background-color:#fff}.btn-danger{color:#fff;background-color:#d9534f;border-color:#d43f3a}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#d2322d;border-color:#ac2925}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#d9534f;border-color:#d43f3a}.btn-danger .badge{color:#d9534f;background-color:#fff}.btn-link{color:#428bca;font-weight:400;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#2a6496;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-left:0;padding-right:0}.btn-block+.btn-block{margin-top:5px}input[type=submit].btn-block,input[type=reset].btn-block,input[type=button].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url(../fonts/glyphicons-halflings-regular.eot);src:url(../fonts/glyphicons-halflings-regular.eot?#iefix) format('embedded-opentype'),url(../fonts/glyphicons-halflings-regular.woff) format('woff'),url(../fonts/glyphicons-halflings-regular.ttf) format('truetype'),url(../fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular) format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';font-style:normal;font-weight:400;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:14px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:400;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{text-decoration:none;color:#262626;background-color:#f5f5f5}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;outline:0;background-color:#428bca}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);cursor:not-allowed}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-menu-right{left:auto;right:0}.dropdown-menu-left{left:0;right:auto}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media (min-width:768px){.navbar-right .dropdown-menu{left:auto;right:0}.navbar-right .dropdown-menu-left{left:0;right:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{margin-left:-5px}.btn-toolbar .btn-group,.btn-toolbar .input-group{float:left}.btn-toolbar>.btn,.btn-toolbar>.btn-group,.btn-toolbar>.input-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.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-left:8px;padding-right:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-left:12px;padding-right:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-bottom-left-radius:4px;border-top-right-radius:0;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child:not(:last-child)>.btn:last-child,.btn-group-vertical>.btn-group:first-child:not(:last-child)>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child:not(:first-child)>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;table-layout:fixed;border-collapse:separate}.btn-group-justified>.btn,.btn-group-justified>.btn-group{float:none;display:table-cell;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle=buttons]>.btn>input[type=radio],[data-toggle=buttons]>.btn>input[type=checkbox]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*=col-]{float:none;padding-left:0;padding-right:0}.input-group .form-control{float:left;width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:46px;padding:10px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:46px;line-height:46px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn,select[multiple].input-group-lg>.form-control,select[multiple].input-group-lg>.input-group-addon,select[multiple].input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn,select[multiple].input-group-sm>.form-control,select[multiple].input-group-sm>.input-group-addon,select[multiple].input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:6px 12px;font-size:14px;font-weight:400;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:10px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type=radio],.input-group-addon input[type=checkbox]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group-btn:last-child>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-top-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child),.input-group-btn:first-child>.btn-group:not(:first-child)>.btn{border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;font-size:0;white-space:nowrap}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-1px}.input-group-btn>.btn:hover,.input-group-btn>.btn:focus,.input-group-btn>.btn:active{z-index:2}.input-group-btn:first-child>.btn,.input-group-btn:first-child>.btn-group{margin-right:-1px}.input-group-btn:last-child>.btn,.input-group-btn:last-child>.btn-group{margin-left:-1px}.nav{margin-bottom:0;padding-left:0;list-style:none}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#428bca}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#428bca}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{text-align:center;margin-bottom:5px}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media (min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media (min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}@media (min-width:768px){.navbar{border-radius:4px}}@media (min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;overflow-x:visible;padding-right:15px;padding-left:15px;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,.1);-webkit-overflow-scrolling:touch}.navbar-collapse.in{overflow-y:auto}@media (min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-left:0;padding-right:0}}.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media (min-width:768px){.container>.navbar-header,.container-fluid>.navbar-header,.container>.navbar-collapse,.container-fluid>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media (min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media (min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px;font-size:18px;line-height:20px;height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media (min-width:768px){.navbar>.container .navbar-brand,.navbar>.container-fluid .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;margin-right:15px;padding:9px 10px;margin-top:8px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle:focus{outline:0}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media (min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media (max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media (min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media (min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{margin-left:-15px;margin-right:-15px;padding:10px 15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1);margin-top:8px;margin-bottom:8px}@media (min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block;width:auto;vertical-align:middle}.navbar-form .control-label{margin-bottom:0;vertical-align:middle}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;margin-top:0;margin-bottom:0;padding-left:0;vertical-align:middle}.navbar-form .radio input[type=radio],.navbar-form .checkbox input[type=checkbox]{float:none;margin-left:0}.navbar-form .has-feedback .form-control-feedback{top:0}}@media (max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media (min-width:768px){.navbar-form{width:auto;border:0;margin-left:0;margin-right:0;padding-top:0;padding-bottom:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-btn{margin-top:8px;margin-bottom:8px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media (min-width:768px){.navbar-text{float:left;margin-left:15px;margin-right:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav>li>a{color:#777}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-inverse{background-color:#222;border-color:#080808}.navbar-inverse .navbar-brand{color:#999}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .navbar-nav>li>a{color:#999}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#444;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#333}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#333}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#101010}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{background-color:#080808;color:#fff}@media (max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#999}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:transparent}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#080808}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#444;background-color:transparent}}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{content:"/\00a0";padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:6px 12px;line-height:1.428571429;text-decoration:none;color:#428bca;background-color:#fff;border:1px solid #ddd;margin-left:-1px}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-bottom-right-radius:4px;border-top-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{color:#2a6496;background-color:#eee;border-color:#ddd}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca;cursor:default}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;background-color:#fff;border-color:#ddd;cursor:not-allowed}.pagination-lg>li>a,.pagination-lg>li>span{padding:10px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-bottom-right-radius:6px;border-top-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-bottom-right-radius:3px;border-top-right-radius:3px}.pager{padding-left:0;margin:20px 0;list-style:none;text-align:center}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;background-color:#fff;cursor:not-allowed}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:gray}.label-primary{background-color:#428bca}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#3071a9}.label-success{background-color:#5cb85c}.label-success[href]:hover,.label-success[href]:focus{background-color:#449d44}.label-info{background-color:#5bc0de}.label-info[href]:hover,.label-info[href]:focus{background-color:#31b0d5}.label-warning{background-color:#f0ad4e}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#ec971f}.label-danger{background-color:#d9534f}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#c9302c}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:700;color:#fff;line-height:1;vertical-align:baseline;white-space:nowrap;text-align:center;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.btn-xs .badge{top:0;padding:1px 5px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#428bca;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{color:inherit}.jumbotron p{margin-bottom:15px;font-size:21px;font-weight:200}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-left:60px;padding-right:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;max-width:100%;height:auto;margin-left:auto;margin-right:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#428bca}.thumbnail .caption{padding:9px;color:#333}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:700}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#3c763d}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#2b542c}.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#31708f}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#245269}.alert-warning{background-color:#fcf8e3;border-color:#faebcc;color:#8a6d3b}.alert-warning hr{border-top-color:#f7e1b5}.alert-warning .alert-link{color:#66512c}.alert-danger{background-color:#f2dede;border-color:#ebccd1;color:#a94442}.alert-danger hr{border-top-color:#e4b9c0}.alert-danger .alert-link{color:#843534}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1);box-shadow:inset 0 1px 2px rgba(0,0,0,.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#428bca;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#5cb85c}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#5bc0de}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#f0ad4e}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#d9534f}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{margin-bottom:20px;padding-left:0}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#428bca;border-color:#428bca}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e1edf7}.list-group-item-success{color:#3c763d;background-color:#dff0d8}a.list-group-item-success{color:#3c763d}a.list-group-item-success .list-group-item-heading{color:inherit}a.list-group-item-success:hover,a.list-group-item-success:focus{color:#3c763d;background-color:#d0e9c6}a.list-group-item-success.active,a.list-group-item-success.active:hover,a.list-group-item-success.active:focus{color:#fff;background-color:#3c763d;border-color:#3c763d}.list-group-item-info{color:#31708f;background-color:#d9edf7}a.list-group-item-info{color:#31708f}a.list-group-item-info .list-group-item-heading{color:inherit}a.list-group-item-info:hover,a.list-group-item-info:focus{color:#31708f;background-color:#c4e3f3}a.list-group-item-info.active,a.list-group-item-info.active:hover,a.list-group-item-info.active:focus{color:#fff;background-color:#31708f;border-color:#31708f}.list-group-item-warning{color:#8a6d3b;background-color:#fcf8e3}a.list-group-item-warning{color:#8a6d3b}a.list-group-item-warning .list-group-item-heading{color:inherit}a.list-group-item-warning:hover,a.list-group-item-warning:focus{color:#8a6d3b;background-color:#faf2cc}a.list-group-item-warning.active,a.list-group-item-warning.active:hover,a.list-group-item-warning.active:focus{color:#fff;background-color:#8a6d3b;border-color:#8a6d3b}.list-group-item-danger{color:#a94442;background-color:#f2dede}a.list-group-item-danger{color:#a94442}a.list-group-item-danger .list-group-item-heading{color:inherit}a.list-group-item-danger:hover,a.list-group-item-danger:focus{color:#a94442;background-color:#ebcccc}a.list-group-item-danger.active,a.list-group-item-danger.active:hover,a.list-group-item-danger.active:focus{color:#fff;background-color:#a94442;border-color:#a94442}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,.05);box-shadow:0 1px 1px rgba(0,0,0,.05)}.panel-body{padding:20px 10px 0px 10px}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{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-right-radius:3px;border-top-left-radius:3px}.panel>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.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,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:first-child,.panel>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:first-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:first-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child th:first-child{border-top-left-radius:3px}.panel>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child td:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table-responsive:first-child>.table:first-child>tbody:first-child>tr:first-child td:last-child,.panel>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table-responsive:first-child>.table:first-child>thead:first-child>tr:first-child th:last-child,.panel>.table:first-child>tbody:first-child>tr:first-child th:last-child,.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>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,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:first-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:first-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:first-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:first-child{border-bottom-left-radius:3px}.panel>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child td:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child td:last-child,.panel>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tbody:last-child>tr:last-child th:last-child,.panel>.table:last-child>tfoot:last-child>tr:last-child th:last-child,.panel>.table-responsive:last-child>.table:last-child>tfoot:last-child>tr:last-child th:last-child{border-bottom-right-radius:3px}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child>tr:first-child th,.panel>.table>tbody:first-child>tr:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.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: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{border-bottom:0}.panel>.table-responsive{border:0;margin-bottom:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-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}.panel-group .panel{margin-bottom:0;border-radius:4px;overflow:hidden}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#333;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#428bca}.panel-primary>.panel-heading{color:#fff;background-color:#428bca;border-color:#428bca}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#428bca}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#428bca}.panel-success{border-color:#d6e9c6}.panel-success>.panel-heading{color:#3c763d;background-color:#dff0d8;border-color:#d6e9c6}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#d6e9c6}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#d6e9c6}.panel-info{border-color:#bce8f1}.panel-info>.panel-heading{color:#31708f;background-color:#d9edf7;border-color:#bce8f1}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#bce8f1}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#bce8f1}.panel-warning{border-color:#faebcc}.panel-warning>.panel-heading{color:#8a6d3b;background-color:#fcf8e3;border-color:#faebcc}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#faebcc}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#faebcc}.panel-danger{border-color:#ebccd1}.panel-danger>.panel-heading{color:#a94442;background-color:#f2dede;border-color:#ebccd1}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ebccd1}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ebccd1}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.05);box-shadow:inset 0 1px 1px rgba(0,0,0,.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:700;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:0 0;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{display:none;overflow:auto;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;-webkit-overflow-scrolling:touch;outline:0}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid #e5e5e5;min-height:16.428571429px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}.modal-sm{width:300px}.modal-lg{width:900px}}.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:3px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-3px;padding:0 5px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.top-right .tooltip-arrow{bottom:0;right:5px;border-width:5px 5px 0;border-top-color:#000}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-width:0 5px 5px;border-bottom-color:#000}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-width:0 5px 5px;border-bottom-color:#000}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#fff;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);white-space:normal}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0,0,0,.25);bottom:-11px}.popover.top .arrow:after{content:" ";bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#fff}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0,0,0,.25)}.popover.right .arrow:after{content:" ";left:1px;bottom:-10px;border-left-width:0;border-right-color:#fff}.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,.25);top:-11px}.popover.bottom .arrow:after{content:" ";top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#fff}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0,0,0,.25)}.popover.left .arrow:after{content:" ";right:1px;border-right-width:0;border-left-color:#fff;bottom:-10px}.carousel{position:relative}.carousel-inner{position:relative;overflow:hidden;width:100%}.carousel-inner>.item{display:none;position:relative;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;max-width:100%;height:auto;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;left:0;bottom:0;width:15%;opacity:.5;filter:alpha(opacity=50);font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.5) 0),color-stop(rgba(0,0,0,.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000', endColorstr='#00000000', GradientType=1)}.carousel-control.right{left:auto;right:0;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,.0001) 0),color-stop(rgba(0,0,0,.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#80000000', GradientType=1)}.carousel-control:hover,.carousel-control:focus{outline:0;color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;margin-left:-30%;padding-left:0;list-style:none;text-align:center}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;border:1px solid #fff;border-radius:10px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0)}.carousel-indicators .active{margin:0;width:12px;height:12px;background-color:#fff}.carousel-caption{position:absolute;left:15%;right:15%;bottom:20px;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{left:20%;right:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after,.container:before,.container:after,.container-fluid:before,.container-fluid:after,.row:before,.row:after,.form-horizontal .form-group:before,.form-horizontal .form-group:after,.btn-toolbar:before,.btn-toolbar:after,.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after,.nav:before,.nav:after,.navbar:before,.navbar:after,.navbar-header:before,.navbar-header:after,.navbar-collapse:before,.navbar-collapse:after,.pager:before,.pager:after,.panel-body:before,.panel-body:after,.modal-footer:before,.modal-footer:after{content:" ";display:table}.clearfix:after,.container:after,.container-fluid:after,.row:after,.form-horizontal .form-group:after,.btn-toolbar:after,.btn-group-vertical>.btn-group:after,.nav:after,.navbar:after,.navbar-header:after,.navbar-collapse:after,.pager:after,.panel-body:after,.modal-footer:after{clear:both}.center-block{display:block;margin-left:auto;margin-right:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media (max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,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}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,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}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,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}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}@media (max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media (min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media (min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media (min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}}@media print{.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}} diff --git a/public/site_assets/bootstrap/css/design/blue.css b/public/site_assets/bootstrap/css/design/blue.css new file mode 100644 index 00000000..284b7617 --- /dev/null +++ b/public/site_assets/bootstrap/css/design/blue.css @@ -0,0 +1,140 @@ +/* overwrite style infos */ + +/* ------------------------------- */ + +body { + background-color: #A2BCF5; + font-size: 12px; +} + +p { + font-size: 12px; +} + +#page-wrapper { + background-color: #A2BCF5; +} + +@media(min-width:768px) { + #page-wrapper { + border-left: 1px solid #A2BCF5; + } +} + +.navbar-static-side ul li { + border-bottom: 1px solid #A2BCF5; +} + +.navbar, .navbar-static-side, .navbar-default { + background-color: #A2BCF5; +} + +a { + color: #0e0af2; +} +a:hover, +a:focus { + color: #FFFFFF; +} + +.panel-body { + color: #000000; + background-color: #8CABED; + border-color: #A2BCF5; +} + +.panel .panel-default { + background-color: #3E6CCF; +} + +.lightblue { + background-color: #3065D9; +} + +.footer { + color: #FFFFFF; +} + +.navbar .brand, .navbar .nav > li > a { + color: #0e0af2; +} + +.navbar .brand, .navbar .nav > li > a:hover { + color: #8CABED; + background-color: #0e0af2; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + background-color: #0e0af2; + color: #FFFFFF; +} + +.table tbody tr:hover a, +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #0e0af2; + color: #FFFFFF; +} + +.nav > li > a:hover, +.nav > li > a:focus { + background-color: #0e0af2; + color: #FFFFFF; +} + +.nav .nav-second-level > li > a:hover, +.nav .nav-second-level > li > a:focus { + background-color: #0e0af2; + color: #FFFFFF; +} + +.navbar .nav > li.dropdown.open > .dropdown-toggle, +.navbar .nav > li.dropdown.active > .dropdown-toggle, +.navbar .nav > li.dropdown.open.active > .dropdown-toggle { + color: #FFFFFF; + background-color: #0e0af2; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li > a, +.navbar-default .navbar-nav .open .dropdown-menu { + color: #FFFFFF; + background-color: #0e0af2; + font-size: 12px; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li a:hover { + background-color: #0e0af2; + color: #3E6CCF; + font-size: 12px; +} + +/* Tables */ + +.panel-footer { + color: #000; + background-color: #3065D9; + border-top: 1px solid #3065D9; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-body { + color: #000000; + background-color: #3E6CCF; +} + +.panel-info > .panel-heading { + background-color: #6F94E3; + border-color: #2c28ed; + color: #D3D3D3; +} + +.panel-info { + border-color: #2c28ed; +} + +.dropdown-menu { + background-color: #6090F7; +} diff --git a/public/site_assets/bootstrap/css/design/dark.css b/public/site_assets/bootstrap/css/design/dark.css new file mode 100644 index 00000000..7cf1e85b --- /dev/null +++ b/public/site_assets/bootstrap/css/design/dark.css @@ -0,0 +1,144 @@ +/* overwrite style infos */ + +/* ------------------------------- */ + +body { + background-color: #222222; + font-size: 12px; +} + +p { + font-size: 12px; +} + +#page-wrapper { + background-color: #999999; +} + +@media(min-width:768px) { + #page-wrapper { + border-left: 1px solid #222222; + } +} + +.navbar-static-side ul li { + border-bottom: 1px solid #222222; +} + +.navbar, .navbar-static-side, .navbar-default { + background-color: #222222; +} + +a { + color: #999999; +} +a:hover, +a:focus { + color: #FFFFFF; +} + +.panel-body { + color: #333; + background-color: #FFFFFF; + border-color: #222222; +} + +.panel .panel-default { + background-color: #D3D3D3; +} + +.lightblue { + background-color: #222222; +} + +.footer { + color: #FFFFFF; +} + +.navbar .brand, .navbar .nav > li > a { + color: #999999; +} + +.navbar .brand, .navbar .nav > li > a:hover { + color: #FFFFFF; + background-color: #000000; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + background-color: #FF0000; + color: #FFFFFF; +} + +.table tbody tr:hover a, +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #999999; + color: #FFFFFF; +} + +.nav > li > a:hover, +.nav > li > a:focus { + background-color: #000000; + color: #FFFFFF; +} + +.nav .nav-second-level > li > a:hover, +.nav .nav-second-level > li > a:focus { + background-color: #000000; + color: #FFFFFF; +} + +.navbar .nav > li.dropdown.open > .dropdown-toggle, +.navbar .nav > li.dropdown.active > .dropdown-toggle, +.navbar .nav > li.dropdown.open.active > .dropdown-toggle { + color: #FFFFFF; + background-color: #000000; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li > a, +.navbar-default .navbar-nav .open .dropdown-menu { + color: #FFFFFF; + background-color: #000000; + font-size: 12px; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li a:hover { + background-color: #000000; + color: #999999; + font-size: 12px; +} + +/* Tables */ + +.panel-footer { + color: #000000; + background-color: #BDBFBF; + border-top: 1px solid #808080; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-body { + color: #000000; + background-color: #D3D3D3; +} + +.panel-info > .panel-heading { + background-color: #808080; + border-color: #808080; + color: #D3D3D3; +} + +.panel-info { + border-color: #808080; +} + +.dropdown-menu { + background-color: #D3D3D3; +} + +.confirmations { + color: #F3FF12; +} diff --git a/public/site_assets/bootstrap/css/design/green.css b/public/site_assets/bootstrap/css/design/green.css new file mode 100644 index 00000000..c9f5230f --- /dev/null +++ b/public/site_assets/bootstrap/css/design/green.css @@ -0,0 +1,140 @@ +/* overwrite style infos */ + +/* ------------------------------- */ + +body { + background-color: #167A1D; + font-size: 12px; +} + +p { + font-size: 12px; +} + +#page-wrapper { + background-color: #00A80B; +} + +@media(min-width:768px) { + #page-wrapper { + border-left: 1px solid #167A1D; + } +} + +.navbar-static-side ul li { + border-bottom: 1px solid #167A1D; +} + +.navbar, .navbar-static-side, .navbar-default { + background-color: #167A1D; +} + +a { + color: #05F215; +} +a:hover, +a:focus { + color: #FFFFFF; +} + +.panel-body { + color: #188518; + background-color: #FFFFFF; + border-color: #167A1D; +} + +.panel .panel-default { + background-color: #65B058; +} + +.lightblue { + background-color: #167A1D; +} + +.footer { + color: #FFFFFF; +} + +.navbar .brand, .navbar .nav > li > a { + color: #05F215; +} + +.navbar .brand, .navbar .nav > li > a:hover { + color: #FFFFFF; + background-color: #2AAD13; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:hover, +.navbar-default .navbar-nav > .active > a:focus { + background-color: #FF0000; + color: #FFFFFF; +} + +.table tbody tr:hover a, +.table tbody tr:hover td, +.table tbody tr:hover th { + background-color: #00A80B; + color: #FFFFFF; +} + +.nav > li > a:hover, +.nav > li > a:focus { + background-color: #2AAD13; + color: #FFFFFF; +} + +.nav .nav-second-level > li > a:hover, +.nav .nav-second-level > li > a:focus { + background-color: #2AAD13; + color: #FFFFFF; +} + +.navbar .nav > li.dropdown.open > .dropdown-toggle, +.navbar .nav > li.dropdown.active > .dropdown-toggle, +.navbar .nav > li.dropdown.open.active > .dropdown-toggle { + color: #FFFFFF; + background-color: #2AAD13; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li > a, +.navbar-default .navbar-nav .open .dropdown-menu { + color: #FFFFFF; + background-color: #2AAD13; + font-size: 12px; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li a:hover { + background-color: #2AAD13; + color: #000000; + font-size: 12px; +} + +/* Tables */ + +.panel-footer { + color: #000000; + background-color: #1EA106; + border-top: 1px solid #04CC11; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; +} + +.panel-body { + color: #000000; + background-color: #65B058; +} + +.panel-info > .panel-heading { + background-color: #65B058; + border-color: #04CC11; + color: #24E002; +} + +.panel-info { + border-color: #FFFFFF; +} + +.dropdown-menu { + background-color: #24E002; +} diff --git a/public/site_assets/mpos/css/ie.css b/public/site_assets/bootstrap/css/ie.css similarity index 100% rename from public/site_assets/mpos/css/ie.css rename to public/site_assets/bootstrap/css/ie.css diff --git a/public/site_assets/bootstrap/css/mpos.css b/public/site_assets/bootstrap/css/mpos.css new file mode 100644 index 00000000..d8cd9220 --- /dev/null +++ b/public/site_assets/bootstrap/css/mpos.css @@ -0,0 +1,623 @@ +/* Global Styles */ + +/* ------------------------------- */ + +body { + background-color: #f8f8f8; + min-width: 350px; + font-size: 12px; + /* Design constraint */ +} + +p { + font-size: 12px; +} + +/* Wrappers */ + +/* ------------------------------- */ + + #wrapper { + width: 100%; +} + +#page-wrapper { + padding: 0 15px; + min-height: 568px; + background-color: #fff; + font-size: 12px; +} + +@media(min-width:768px) { + #page-wrapper { + position: inherit; + margin: 0 0 0 250px; + padding: 0 30px; + min-height: 900px; + border-left: 1px solid #e7e7e7; + font-size: 12px; + } +} + +.navbar-static-side ul li { + border-bottom: 1px solid #e7e7e7; +} + + +/* Input fields */ + +/* ------------------------------- */ + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + padding: 4px 4px 4px 4px; + font-size: 11px; + color: #555555; + border: 1px solid #ccc; + height: 25px; + line-height: 25px; +} + +.input-group-sm > .form-control, +.input-group-sm > .input-group-addon, +.input-group-sm > .input-group-btn > .btn { + height: 25px; + font-size: 12px; +} + +.form-control { + font-size: 12px; +} + +.input-group .input-group-addon { + line-height: 1!important; + } + +.glyphicon{ + line-height: 1em; +} + +.select-mini, .input-group { + font-size: 11px; + height: 25px; + padding: 3px; +} + +/* Navigation */ + +/* ------------------------------- */ + +/* Top Right Navigation Dropdown Styles */ + +.navbar-top-links li { + display: inline-block; +} + +.navbar-top-links li:last-child { + margin-right: 15px; +} + +.navbar-top-links li a { + padding: 15px; + min-height: 50px; +} + +.dropdown-user { + min-width:100px; +} + +.navbar-top-links .dropdown-menu li { + display: block; +} + +.navbar-top-links .dropdown-menu li:last-child { + margin-right: 0; +} + +.navbar-top-links .dropdown-menu li a { + padding: 3px 20px; + min-height: 0; +} + +.navbar-top-links .dropdown-menu li a div { + white-space: normal; +} + +.navbar-top-links .dropdown-messages, +.navbar-top-links .dropdown-tasks, +.navbar-top-links .dropdown-alerts { + width: 310px; + min-width: 0; +} + +.navbar-top-links .dropdown-messages { + margin-left: 5px; +} + +.navbar-top-links .dropdown-tasks { + margin-left: -59px; +} + +.navbar-top-links .dropdown-alerts { + /*#margin-left: -123px; */ +} + +.navbar-top-links .dropdown-user { + right: 0; + left: auto; +} + +/* Sidebar Menu Styles */ + +.sidebar-search { + padding: 15px; +} + +.arrow { + float: right; +} + +.fa.arrow:before { + content: "\f104"; +} + +.active > a > .fa.arrow:before { + content: "\f107"; +} + +.nav-second-level li, +.nav-third-level li { + border-bottom: none !important; +} + +.nav-second-level li a { + padding-left: 37px; +} + +.nav-third-level li a { + padding-left: 52px; +} + +@media(min-width:768px) { + .navbar-static-side { + z-index: 1; + position: absolute; + width: 250px; + } + + .navbar-top-links .dropdown-messages, + .navbar-top-links .dropdown-tasks, + .navbar-top-links .dropdown-alerts { + margin-left: auto; + } + .col-md-spark, .col-md-spark-2 { + float: left; + } + .col-md-spark { + width:16.65% + } + .col-md-spark-2 { + width:20% + } +} + +.navbar-default .navbar-nav .open .dropdown-menu > li > a, +.navbar-default .navbar-nav .open .dropdown-menu { + font-size: 12px; +} + +.navbar-default .navbar-nav .open .dropdown-menu > li a:hover { + font-size: 12px; +} + +/* Buttons */ + +/* ------------------------------- */ + +.btn-outline { + color: inherit; + background-color: transparent; + transition: all .5s; +} + +.btn-primary.btn-outline { + color: #428bca; +} + +.btn-success.btn-outline { + color: #5cb85c; +} + +.btn-info.btn-outline { + color: #5bc0de; +} + +.btn-warning.btn-outline { + color: #f0ad4e; +} + +.btn-danger.btn-outline { + color: #d9534f; +} + +.btn-primary.btn-outline:hover, +.btn-success.btn-outline:hover, +.btn-info.btn-outline:hover, +.btn-warning.btn-outline:hover, +.btn-danger.btn-outline:hover { + color: #fff; +} + +/* Pages */ + +/* ------------------------------- */ + +/* Dashboard Chat */ + +.chat { + margin: 0; + padding: 0; + list-style: none; +} + +.chat li { + margin-bottom: 10px; + padding-bottom: 5px; + border-bottom: 1px dotted #B3A9A9; +} + +.chat li.left .chat-body { + margin-left: 60px; +} + +.chat li.right .chat-body { + margin-right: 60px; +} + +.chat li .chat-body p { + margin: 0; + color: #777777; +} + +.panel .slidedown .glyphicon, +.chat .glyphicon { + margin-right: 5px; +} + +.chat-panel .panel-body { + height: 350px; + overflow-y: scroll; +} + +/* Login Page */ + +.login-panel { + margin-top: 25%; +} + +/* Flot Chart Containers */ + +.flot-chart { + display: block; + height: 400px; +} + +.flot-chart-content { + width: 100%; + height: 100%; +} + +/* DataTables Overrides */ + +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc:after, +table.dataTable thead .sorting_desc, +table.dataTable thead .sorting_asc_disabled, +table.dataTable thead .sorting_desc_disabled { + background: transparent; +} + +table.dataTable thead .sorting_asc:after { + content: "\f0de"; + float: right; + font-family: fontawesome; +} + +table.dataTable thead .sorting_desc:after { + content: "\f0dd"; + float: right; + font-family: fontawesome; +} + +table.dataTable thead .sorting:after { + content: "\f0dc"; + float: right; + font-family: fontawesome; + color: rgba(50,50,50,.5); +} + +div.dataTables_length select { + font-size: 11px; + height: 25px; +} + +div.dataTables_filter input { + font-size: 11px; + height: 25px; +} + +div.dataTables_paginate { + font-size: 11px; +} + +div.dataTables_paginate ul.pagination { + font-size: 11px; + +} + +/* Circle Buttons */ + + .btn-circle { + width: 30px; + height: 30px; + padding: 6px 0; + border-radius: 15px; + text-align: center; + font-size: 12px; + line-height: 1.428571429; +} + +.btn-circle.btn-lg { + width: 50px; + height: 50px; + padding: 10px 16px; + border-radius: 25px; + font-size: 18px; + line-height: 1.33; +} + +.btn-circle.btn-xl { + width: 70px; + height: 70px; + padding: 10px 16px; + border-radius: 35px; + font-size: 24px; + line-height: 1.33; +} + +.show-grid [class^="col-"] { + padding-top: 10px; + padding-bottom: 10px; + border: 1px solid #ddd; + background-color: #eee !important; +} + +.show-grid { + margin: 15px 0; +} + +/* No Padding for Tables */ + +.no-padding { + padding:0 +} + +.no-padding table { + margin: 0 +} + +.no-padding .table-bordered { + border: 0; +} + +.borderless > tbody > tr > td { + border: none; + padding: 5px; +} + +.borderless > thead > tr > th { + border: none; +} + +.margin-bottom-sm { + margin-bottom: 5px !important; +} + +p.overview { + font-family: 'Open Sans',sans-serif; + font-weight: 600; + font-size: 11px; + text-transform: uppercase; + display: block; + margin-bottom: 4px; +} + +span.overview { + font-size: 14px; + font-weight: bold; +} + +div.overview { + margin: 20px 0px 0px; +} + +span.bigfont { + font-size: 100%; +} + +th.smallwidth { + width: 250px; +} + +.col-md-spark, .col-md-spark-2 { + position:relative; + min-height:1px; + padding-left:15px; + padding-right:15px +} + +span.overview-mhs { + font-size: 11px; + font-weight: bold; +} + +div.black { + color: black; +} + +div.progress-fix { + margin: 0px 0px 5px 0px; +} + +span.spark-18 { + margin: -20%; +} + +span.spark-25 { + margin: -25%; +} + +/* Test Edit */ + +.circle-tile { + margin-bottom: 30px; +} + +.circle-tile { + margin-bottom: 15px; + text-align: center; +} + +.circle-tile-content { + padding-top: 50px; + border-radius: 8px; + border: 3px solid rgba(255, 255, 255, 0.3); +} + +.circle-tile-description { + font-weight: bold; + font-size: 16px; +} + +.circle-tile-number { + padding: 0px 1px 4px; +} + +.circle-tile-heading { + position: relative; + width: 80px; + height: 80px; + margin: 0px auto -40px; + border: 3px solid rgba(255, 255, 255, 0.3); + border-radius: 100%; + color: #FFF; + transition: all 0.3s ease-in-out 0s; +} + +.circle-tile-heading .fa { + line-height: 80px; +} + +.lightblue { + background-color: #2FAACE; +} + +.text-faded { + color: rgba(255, 255, 255, 0.7); +} + +.text-link { + color: #FFFFFF; +} + +p.up { + margin: -5px 0px -8px; + font-weight: 600; +} + +div.up { + margin: -10px 0px 6px 0px; +} + +p.up-more { + margin: -6px 0px 10px; + font-weight: 600; +} + +p.up-more2 { + margin: -6px 0px 0px; +} + +div.fade { + opacity: 0.8; +} + +/* End Test */ + +/* Tables */ + +.table>tbody>tr>th +{ + padding-left:3px; + padding-bottom:3px; + border: 1px solid #ddd; + background-color: #f9f9f9; + padding-right:1px; +} + +.table > tbody > tr > td +{ + padding:4px; +} + +.panel > .table, +.panel > .table-responsive > .table { + margin-bottom: 0; +} + +.table-responsive +{ + white-space: nowrap; + width: 100%; + margin-bottom: 15px; + overflow-x: scroll; + overflow-y: hidden; + -webkit-overflow-scrolling: touch; + -ms-overflow-style: -ms-autohiding-scrollbar; +} + +/* End Tables */ + +/* Footer */ + + +.footer { + clear: both; + text-align: center; + padding: 4px 0px 0px; + font-size: 11px; + width: 100%; + margin-bottom: 5px !important; +} + +.confirmations { + color: #F79D00; +} + +/* End Footer */ diff --git a/public/site_assets/bootstrap/css/plugins/dataTables/dataTables.bootstrap.css b/public/site_assets/bootstrap/css/plugins/dataTables/dataTables.bootstrap.css new file mode 100644 index 00000000..192b2f2a --- /dev/null +++ b/public/site_assets/bootstrap/css/plugins/dataTables/dataTables.bootstrap.css @@ -0,0 +1,235 @@ +div.dataTables_length label { + float: left; + text-align: left; + font-weight: normal; +} + +div.dataTables_length select { + width: 75px; +} + +div.dataTables_filter label { + float: right; + font-weight: normal; +} + +div.dataTables_filter input { + width: 16em; +} + +div.dataTables_info { + padding-top: 8px; +} + +div.dataTables_paginate { + float: right; + margin: 0; +} + +div.dataTables_paginate ul.pagination { + margin: 2px 0; + white-space: nowrap; +} + +table.dataTable, +table.dataTable td, +table.dataTable th { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; +} + +table.dataTable { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; +} + +table.dataTable thead .sorting, +table.dataTable thead .sorting_asc, +table.dataTable thead .sorting_desc, +table.dataTable thead .sorting_asc_disabled, +table.dataTable thead .sorting_desc_disabled { + cursor: pointer; +} + +/* +table.dataTable thead .sorting { + background: url('../../../images/sort_both.png') no-repeat center right; +} + +table.dataTable thead .sorting_asc { + background: url('../../../images/sort_asc.png') no-repeat center right; +} + +table.dataTable thead .sorting_desc { + background: url('../../../images/sort_desc.png') no-repeat center right; +} + +table.dataTable thead .sorting_asc_disabled { + background: url('../../../images/sort_asc_disabled.png') no-repeat center right; +} + +table.dataTable thead .sorting_desc_disabled { + background: url('../../../images/sort_desc_disabled.png') no-repeat center right; +} +*/ + +table.dataTable th:active { + outline: none; +} + +/* Scrolling */ + +div.dataTables_scrollHead table { + margin-bottom: 0 !important; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +div.dataTables_scrollHead table thead tr:last-child th:first-child, +div.dataTables_scrollHead table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.dataTables_scrollBody table { + margin-top: 0 !important; + margin-bottom: 0 !important; + border-top: none; +} + +div.dataTables_scrollBody tbody tr:first-child th, +div.dataTables_scrollBody tbody tr:first-child td { + border-top: none; +} + +div.dataTables_scrollFoot table { + margin-top: 0 !important; + border-top: none; +} + +/* + * TableTools styles + */ + +.table tbody tr.active td, +.table tbody tr.active th { + color: white; + background-color: #08C; +} + +.table tbody tr.active:hover td, +.table tbody tr.active:hover th { + background-color: #0075b0 !important; +} + +.table tbody tr.active a { + color: white; +} + +.table-striped tbody tr.active:nth-child(odd) td, +.table-striped tbody tr.active:nth-child(odd) th { + background-color: #017ebc; +} + +table.DTTT_selectable tbody tr { + cursor: pointer; +} + +div.DTTT .btn { + font-size: 12px; + color: #333 !important; +} + +div.DTTT .btn:hover { + text-decoration: none !important; +} + +ul.DTTT_dropdown.dropdown-menu { + z-index: 2003; +} + +ul.DTTT_dropdown.dropdown-menu a { + color: #333 !important; /* needed only when demo_page.css is included */ +} + +ul.DTTT_dropdown.dropdown-menu li { + position: relative; +} + +ul.DTTT_dropdown.dropdown-menu li:hover a { + color: white !important; + background-color: #0088cc; +} + +div.DTTT_collection_background { + z-index: 2002; +} + +/* TableTools information display */ + +div.DTTT_print_info.modal { + height: 150px; + margin-top: -75px; + text-align: center; +} + +div.DTTT_print_info h6 { + margin: 1em; + font-size: 28px; + font-weight: normal; + line-height: 28px; +} + +div.DTTT_print_info p { + font-size: 14px; + line-height: 20px; +} + +/* + * FixedColumns styles + */ + +div.DTFC_LeftHeadWrapper table, +div.DTFC_LeftFootWrapper table, +div.DTFC_RightHeadWrapper table, +div.DTFC_RightFootWrapper table, +table.DTFC_Cloned tr.even { + background-color: white; +} + +div.DTFC_RightHeadWrapper table, +div.DTFC_LeftHeadWrapper table { + margin-bottom: 0 !important; + border-top-right-radius: 0 !important; + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child, +div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child { + border-bottom-left-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + +div.DTFC_RightBodyWrapper table, +div.DTFC_LeftBodyWrapper table { + margin-bottom: 0 !important; + border-top: none; +} + +div.DTFC_RightBodyWrapper tbody tr:first-child th, +div.DTFC_RightBodyWrapper tbody tr:first-child td, +div.DTFC_LeftBodyWrapper tbody tr:first-child th, +div.DTFC_LeftBodyWrapper tbody tr:first-child td { + border-top: none; +} + +div.DTFC_RightFootWrapper table, +div.DTFC_LeftFootWrapper table { + border-top: none; +} \ No newline at end of file diff --git a/public/site_assets/bootstrap/css/plugins/morris/morris-0.4.3.min.css b/public/site_assets/bootstrap/css/plugins/morris/morris-0.4.3.min.css new file mode 100644 index 00000000..7cbb3c10 --- /dev/null +++ b/public/site_assets/bootstrap/css/plugins/morris/morris-0.4.3.min.css @@ -0,0 +1,2 @@ +.morris-hover{position:absolute;z-index:1000;}.morris-hover.morris-default-style{border-radius:10px;padding:6px;color:#666;background:rgba(255, 255, 255, 0.8);border:solid 2px rgba(230, 230, 230, 0.8);font-family:sans-serif;font-size:12px;text-align:center;}.morris-hover.morris-default-style .morris-hover-row-label{font-weight:bold;margin:0.25em 0;} +.morris-hover.morris-default-style .morris-hover-point{white-space:nowrap;margin:0.1em 0;} \ No newline at end of file diff --git a/public/site_assets/bootstrap/css/plugins/social-buttons/social-buttons.css b/public/site_assets/bootstrap/css/plugins/social-buttons/social-buttons.css new file mode 100644 index 00000000..fb3b7871 --- /dev/null +++ b/public/site_assets/bootstrap/css/plugins/social-buttons/social-buttons.css @@ -0,0 +1,68 @@ +@import url(//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css); +/* + * Social Buttons for Bootstrap + * + * Copyright 2013 Panayiotis Lipiridis + * Licensed under the MIT License + * + * https://github.com/lipis/bootstrap-social + */ + +.btn-social{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.btn-social :first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)} +.btn-social.btn-lg{padding-left:61px}.btn-social.btn-lg :first-child{line-height:45px;width:45px;font-size:1.8em} +.btn-social.btn-sm{padding-left:38px}.btn-social.btn-sm :first-child{line-height:28px;width:28px;font-size:1.4em} +.btn-social.btn-xs{padding-left:30px}.btn-social.btn-xs :first-child{line-height:20px;width:20px;font-size:1.2em} +.btn-social-icon{position:relative;padding-left:44px;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:34px;width:34px;padding-left:0;padding-right:0}.btn-social-icon :first-child{position:absolute;left:0;top:0;bottom:0;width:32px;line-height:34px;font-size:1.6em;text-align:center;border-right:1px solid rgba(0,0,0,0.2)} +.btn-social-icon.btn-lg{padding-left:61px}.btn-social-icon.btn-lg :first-child{line-height:45px;width:45px;font-size:1.8em} +.btn-social-icon.btn-sm{padding-left:38px}.btn-social-icon.btn-sm :first-child{line-height:28px;width:28px;font-size:1.4em} +.btn-social-icon.btn-xs{padding-left:30px}.btn-social-icon.btn-xs :first-child{line-height:20px;width:20px;font-size:1.2em} +.btn-social-icon :first-child{border:none;text-align:center;width:100% !important} +.btn-social-icon.btn-lg{height:45px;width:45px;padding-left:0;padding-right:0} +.btn-social-icon.btn-sm{height:30px;width:30px;padding-left:0;padding-right:0} +.btn-social-icon.btn-xs{height:22px;width:22px;padding-left:0;padding-right:0} +.btn-bitbucket{color:#fff;background-color:#205081;border-color:rgba(0,0,0,0.2)}.btn-bitbucket:hover,.btn-bitbucket:focus,.btn-bitbucket:active,.btn-bitbucket.active,.open .dropdown-toggle.btn-bitbucket{color:#fff;background-color:#183c60;border-color:rgba(0,0,0,0.2)} +.btn-bitbucket:active,.btn-bitbucket.active,.open .dropdown-toggle.btn-bitbucket{background-image:none} +.btn-bitbucket.disabled,.btn-bitbucket[disabled],fieldset[disabled] .btn-bitbucket,.btn-bitbucket.disabled:hover,.btn-bitbucket[disabled]:hover,fieldset[disabled] .btn-bitbucket:hover,.btn-bitbucket.disabled:focus,.btn-bitbucket[disabled]:focus,fieldset[disabled] .btn-bitbucket:focus,.btn-bitbucket.disabled:active,.btn-bitbucket[disabled]:active,fieldset[disabled] .btn-bitbucket:active,.btn-bitbucket.disabled.active,.btn-bitbucket[disabled].active,fieldset[disabled] .btn-bitbucket.active{background-color:#205081;border-color:rgba(0,0,0,0.2)} +.btn-dropbox{color:#fff;background-color:#1087dd;border-color:rgba(0,0,0,0.2)}.btn-dropbox:hover,.btn-dropbox:focus,.btn-dropbox:active,.btn-dropbox.active,.open .dropdown-toggle.btn-dropbox{color:#fff;background-color:#0d70b7;border-color:rgba(0,0,0,0.2)} +.btn-dropbox:active,.btn-dropbox.active,.open .dropdown-toggle.btn-dropbox{background-image:none} +.btn-dropbox.disabled,.btn-dropbox[disabled],fieldset[disabled] .btn-dropbox,.btn-dropbox.disabled:hover,.btn-dropbox[disabled]:hover,fieldset[disabled] .btn-dropbox:hover,.btn-dropbox.disabled:focus,.btn-dropbox[disabled]:focus,fieldset[disabled] .btn-dropbox:focus,.btn-dropbox.disabled:active,.btn-dropbox[disabled]:active,fieldset[disabled] .btn-dropbox:active,.btn-dropbox.disabled.active,.btn-dropbox[disabled].active,fieldset[disabled] .btn-dropbox.active{background-color:#1087dd;border-color:rgba(0,0,0,0.2)} +.btn-facebook{color:#fff;background-color:#3b5998;border-color:rgba(0,0,0,0.2)}.btn-facebook:hover,.btn-facebook:focus,.btn-facebook:active,.btn-facebook.active,.open .dropdown-toggle.btn-facebook{color:#fff;background-color:#30487b;border-color:rgba(0,0,0,0.2)} +.btn-facebook:active,.btn-facebook.active,.open .dropdown-toggle.btn-facebook{background-image:none} +.btn-facebook.disabled,.btn-facebook[disabled],fieldset[disabled] .btn-facebook,.btn-facebook.disabled:hover,.btn-facebook[disabled]:hover,fieldset[disabled] .btn-facebook:hover,.btn-facebook.disabled:focus,.btn-facebook[disabled]:focus,fieldset[disabled] .btn-facebook:focus,.btn-facebook.disabled:active,.btn-facebook[disabled]:active,fieldset[disabled] .btn-facebook:active,.btn-facebook.disabled.active,.btn-facebook[disabled].active,fieldset[disabled] .btn-facebook.active{background-color:#3b5998;border-color:rgba(0,0,0,0.2)} +.btn-flickr{color:#fff;background-color:#ff0084;border-color:rgba(0,0,0,0.2)}.btn-flickr:hover,.btn-flickr:focus,.btn-flickr:active,.btn-flickr.active,.open .dropdown-toggle.btn-flickr{color:#fff;background-color:#d6006f;border-color:rgba(0,0,0,0.2)} +.btn-flickr:active,.btn-flickr.active,.open .dropdown-toggle.btn-flickr{background-image:none} +.btn-flickr.disabled,.btn-flickr[disabled],fieldset[disabled] .btn-flickr,.btn-flickr.disabled:hover,.btn-flickr[disabled]:hover,fieldset[disabled] .btn-flickr:hover,.btn-flickr.disabled:focus,.btn-flickr[disabled]:focus,fieldset[disabled] .btn-flickr:focus,.btn-flickr.disabled:active,.btn-flickr[disabled]:active,fieldset[disabled] .btn-flickr:active,.btn-flickr.disabled.active,.btn-flickr[disabled].active,fieldset[disabled] .btn-flickr.active{background-color:#ff0084;border-color:rgba(0,0,0,0.2)} +.btn-github{color:#fff;background-color:#444;border-color:rgba(0,0,0,0.2)}.btn-github:hover,.btn-github:focus,.btn-github:active,.btn-github.active,.open .dropdown-toggle.btn-github{color:#fff;background-color:#303030;border-color:rgba(0,0,0,0.2)} +.btn-github:active,.btn-github.active,.open .dropdown-toggle.btn-github{background-image:none} +.btn-github.disabled,.btn-github[disabled],fieldset[disabled] .btn-github,.btn-github.disabled:hover,.btn-github[disabled]:hover,fieldset[disabled] .btn-github:hover,.btn-github.disabled:focus,.btn-github[disabled]:focus,fieldset[disabled] .btn-github:focus,.btn-github.disabled:active,.btn-github[disabled]:active,fieldset[disabled] .btn-github:active,.btn-github.disabled.active,.btn-github[disabled].active,fieldset[disabled] .btn-github.active{background-color:#444;border-color:rgba(0,0,0,0.2)} +.btn-google-plus{color:#fff;background-color:#dd4b39;border-color:rgba(0,0,0,0.2)}.btn-google-plus:hover,.btn-google-plus:focus,.btn-google-plus:active,.btn-google-plus.active,.open .dropdown-toggle.btn-google-plus{color:#fff;background-color:#ca3523;border-color:rgba(0,0,0,0.2)} +.btn-google-plus:active,.btn-google-plus.active,.open .dropdown-toggle.btn-google-plus{background-image:none} +.btn-google-plus.disabled,.btn-google-plus[disabled],fieldset[disabled] .btn-google-plus,.btn-google-plus.disabled:hover,.btn-google-plus[disabled]:hover,fieldset[disabled] .btn-google-plus:hover,.btn-google-plus.disabled:focus,.btn-google-plus[disabled]:focus,fieldset[disabled] .btn-google-plus:focus,.btn-google-plus.disabled:active,.btn-google-plus[disabled]:active,fieldset[disabled] .btn-google-plus:active,.btn-google-plus.disabled.active,.btn-google-plus[disabled].active,fieldset[disabled] .btn-google-plus.active{background-color:#dd4b39;border-color:rgba(0,0,0,0.2)} +.btn-instagram{color:#fff;background-color:#517fa4;border-color:rgba(0,0,0,0.2)}.btn-instagram:hover,.btn-instagram:focus,.btn-instagram:active,.btn-instagram.active,.open .dropdown-toggle.btn-instagram{color:#fff;background-color:#446a89;border-color:rgba(0,0,0,0.2)} +.btn-instagram:active,.btn-instagram.active,.open .dropdown-toggle.btn-instagram{background-image:none} +.btn-instagram.disabled,.btn-instagram[disabled],fieldset[disabled] .btn-instagram,.btn-instagram.disabled:hover,.btn-instagram[disabled]:hover,fieldset[disabled] .btn-instagram:hover,.btn-instagram.disabled:focus,.btn-instagram[disabled]:focus,fieldset[disabled] .btn-instagram:focus,.btn-instagram.disabled:active,.btn-instagram[disabled]:active,fieldset[disabled] .btn-instagram:active,.btn-instagram.disabled.active,.btn-instagram[disabled].active,fieldset[disabled] .btn-instagram.active{background-color:#517fa4;border-color:rgba(0,0,0,0.2)} +.btn-linkedin{color:#fff;background-color:#007bb6;border-color:rgba(0,0,0,0.2)}.btn-linkedin:hover,.btn-linkedin:focus,.btn-linkedin:active,.btn-linkedin.active,.open .dropdown-toggle.btn-linkedin{color:#fff;background-color:#005f8d;border-color:rgba(0,0,0,0.2)} +.btn-linkedin:active,.btn-linkedin.active,.open .dropdown-toggle.btn-linkedin{background-image:none} +.btn-linkedin.disabled,.btn-linkedin[disabled],fieldset[disabled] .btn-linkedin,.btn-linkedin.disabled:hover,.btn-linkedin[disabled]:hover,fieldset[disabled] .btn-linkedin:hover,.btn-linkedin.disabled:focus,.btn-linkedin[disabled]:focus,fieldset[disabled] .btn-linkedin:focus,.btn-linkedin.disabled:active,.btn-linkedin[disabled]:active,fieldset[disabled] .btn-linkedin:active,.btn-linkedin.disabled.active,.btn-linkedin[disabled].active,fieldset[disabled] .btn-linkedin.active{background-color:#007bb6;border-color:rgba(0,0,0,0.2)} +.btn-pinterest{color:#fff;background-color:#cb2027;border-color:rgba(0,0,0,0.2)}.btn-pinterest:hover,.btn-pinterest:focus,.btn-pinterest:active,.btn-pinterest.active,.open .dropdown-toggle.btn-pinterest{color:#fff;background-color:#a81a20;border-color:rgba(0,0,0,0.2)} +.btn-pinterest:active,.btn-pinterest.active,.open .dropdown-toggle.btn-pinterest{background-image:none} +.btn-pinterest.disabled,.btn-pinterest[disabled],fieldset[disabled] .btn-pinterest,.btn-pinterest.disabled:hover,.btn-pinterest[disabled]:hover,fieldset[disabled] .btn-pinterest:hover,.btn-pinterest.disabled:focus,.btn-pinterest[disabled]:focus,fieldset[disabled] .btn-pinterest:focus,.btn-pinterest.disabled:active,.btn-pinterest[disabled]:active,fieldset[disabled] .btn-pinterest:active,.btn-pinterest.disabled.active,.btn-pinterest[disabled].active,fieldset[disabled] .btn-pinterest.active{background-color:#cb2027;border-color:rgba(0,0,0,0.2)} +.btn-tumblr{color:#fff;background-color:#2c4762;border-color:rgba(0,0,0,0.2)}.btn-tumblr:hover,.btn-tumblr:focus,.btn-tumblr:active,.btn-tumblr.active,.open .dropdown-toggle.btn-tumblr{color:#fff;background-color:#1f3346;border-color:rgba(0,0,0,0.2)} +.btn-tumblr:active,.btn-tumblr.active,.open .dropdown-toggle.btn-tumblr{background-image:none} +.btn-tumblr.disabled,.btn-tumblr[disabled],fieldset[disabled] .btn-tumblr,.btn-tumblr.disabled:hover,.btn-tumblr[disabled]:hover,fieldset[disabled] .btn-tumblr:hover,.btn-tumblr.disabled:focus,.btn-tumblr[disabled]:focus,fieldset[disabled] .btn-tumblr:focus,.btn-tumblr.disabled:active,.btn-tumblr[disabled]:active,fieldset[disabled] .btn-tumblr:active,.btn-tumblr.disabled.active,.btn-tumblr[disabled].active,fieldset[disabled] .btn-tumblr.active{background-color:#2c4762;border-color:rgba(0,0,0,0.2)} +.btn-twitter{color:#fff;background-color:#2ba9e1;border-color:rgba(0,0,0,0.2)}.btn-twitter:hover,.btn-twitter:focus,.btn-twitter:active,.btn-twitter.active,.open .dropdown-toggle.btn-twitter{color:#fff;background-color:#1c92c7;border-color:rgba(0,0,0,0.2)} +.btn-twitter:active,.btn-twitter.active,.open .dropdown-toggle.btn-twitter{background-image:none} +.btn-twitter.disabled,.btn-twitter[disabled],fieldset[disabled] .btn-twitter,.btn-twitter.disabled:hover,.btn-twitter[disabled]:hover,fieldset[disabled] .btn-twitter:hover,.btn-twitter.disabled:focus,.btn-twitter[disabled]:focus,fieldset[disabled] .btn-twitter:focus,.btn-twitter.disabled:active,.btn-twitter[disabled]:active,fieldset[disabled] .btn-twitter:active,.btn-twitter.disabled.active,.btn-twitter[disabled].active,fieldset[disabled] .btn-twitter.active{background-color:#2ba9e1;border-color:rgba(0,0,0,0.2)} +.btn-vk{color:#fff;background-color:#587ea3;border-color:rgba(0,0,0,0.2)}.btn-vk:hover,.btn-vk:focus,.btn-vk:active,.btn-vk.active,.open .dropdown-toggle.btn-vk{color:#fff;background-color:#4a6a89;border-color:rgba(0,0,0,0.2)} +.btn-vk:active,.btn-vk.active,.open .dropdown-toggle.btn-vk{background-image:none} +.btn-vk.disabled,.btn-vk[disabled],fieldset[disabled] .btn-vk,.btn-vk.disabled:hover,.btn-vk[disabled]:hover,fieldset[disabled] .btn-vk:hover,.btn-vk.disabled:focus,.btn-vk[disabled]:focus,fieldset[disabled] .btn-vk:focus,.btn-vk.disabled:active,.btn-vk[disabled]:active,fieldset[disabled] .btn-vk:active,.btn-vk.disabled.active,.btn-vk[disabled].active,fieldset[disabled] .btn-vk.active{background-color:#587ea3;border-color:rgba(0,0,0,0.2)} + + +/* + * Only for this example - not needed for the buttons + * ----------------------------------------------------- */ +.btn-social-icon {margin-bottom: 4px;} +.social-class .social-hex{font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:10px;opacity:.3;float:right} +.social-class li{margin-bottom:4px}.social-class li:hover .social-hex{opacity:1} +.social-class li:hover code{background-color:#e8e8ee} +.social-class code{cursor:default} \ No newline at end of file diff --git a/public/site_assets/bootstrap/css/plugins/timeline/timeline.css b/public/site_assets/bootstrap/css/plugins/timeline/timeline.css new file mode 100644 index 00000000..4ce0623a --- /dev/null +++ b/public/site_assets/bootstrap/css/plugins/timeline/timeline.css @@ -0,0 +1,144 @@ +.timeline { + position: relative; + padding: 20px 0 20px; + list-style: none; +} + +.timeline:before { + content: " "; + position: absolute; + top: 0; + bottom: 0; + left: 50%; + width: 3px; + margin-left: -1.5px; + background-color: #eeeeee; +} + +.timeline > li { + position: relative; + margin-bottom: 20px; +} + +.timeline > li:before, +.timeline > li:after { + content: " "; + display: table; +} + +.timeline > li:after { + clear: both; +} + +.timeline > li:before, +.timeline > li:after { + content: " "; + display: table; +} + +.timeline > li:after { + clear: both; +} + +.timeline > li > .timeline-panel { + float: left; + position: relative; + width: 46%; + padding: 20px; + border: 1px solid #d4d4d4; + border-radius: 2px; + -webkit-box-shadow: 0 1px 6px rgba(0,0,0,0.175); + box-shadow: 0 1px 6px rgba(0,0,0,0.175); +} + +.timeline > li > .timeline-panel:before { + content: " "; + display: inline-block; + position: absolute; + top: 26px; + right: -15px; + border-top: 15px solid transparent; + border-right: 0 solid #ccc; + border-bottom: 15px solid transparent; + border-left: 15px solid #ccc; +} + +.timeline > li > .timeline-panel:after { + content: " "; + display: inline-block; + position: absolute; + top: 27px; + right: -14px; + border-top: 14px solid transparent; + border-right: 0 solid #fff; + border-bottom: 14px solid transparent; + border-left: 14px solid #fff; +} + +.timeline > li > .timeline-badge { + z-index: 100; + position: absolute; + top: 16px; + left: 50%; + width: 50px; + height: 50px; + margin-left: -25px; + border-radius: 50% 50% 50% 50%; + text-align: center; + font-size: 1.4em; + line-height: 50px; + color: #fff; + background-color: #999999; +} + +.timeline > li.timeline-inverted > .timeline-panel { + float: right; +} + +.timeline > li.timeline-inverted > .timeline-panel:before { + right: auto; + left: -15px; + border-right-width: 15px; + border-left-width: 0; +} + +.timeline > li.timeline-inverted > .timeline-panel:after { + right: auto; + left: -14px; + border-right-width: 14px; + border-left-width: 0; +} + +.timeline-badge.primary { + background-color: #2e6da4 !important; +} + +.timeline-badge.success { + background-color: #3f903f !important; +} + +.timeline-badge.warning { + background-color: #f0ad4e !important; +} + +.timeline-badge.danger { + background-color: #d9534f !important; +} + +.timeline-badge.info { + background-color: #5bc0de !important; +} + +.timeline-title { + margin-top: 0; + color: inherit; +} + +.timeline-body > p, +.timeline-body > ul { + margin-bottom: 0; +} + +.timeline-body > p + p { + margin-top: 5px; +} \ No newline at end of file diff --git a/public/site_assets/bootstrap/css/sparklines.css b/public/site_assets/bootstrap/css/sparklines.css new file mode 100644 index 00000000..b43df68b --- /dev/null +++ b/public/site_assets/bootstrap/css/sparklines.css @@ -0,0 +1,45 @@ +.sparklines-stats li:first-child { + border-radius: 2px 0 0 2px; + -webkit-border-radius: 2px 0 0 2px; + -moz-border-radius: 2px 0 0 2px; +} +.sparklines-stats li.bg-default { + background-color: #fafafa; + border: 1px solid #e5e5e5; +} +ul.list-justified li { + float: none; + width: 1%; + display: table-cell; +} +.sparklines-stats li { + padding: 12px 18px; + border-left: 1px solid #e5e5e5; + display: inline-block; +} +.sparklines-stats { + margin-left: 0; + padding: 0; + list-style: none; + margin-bottom: 20px; +} +.chart { + float: right; + margin-top: 4px; +} +.sparklines-stats-showcase { + float: left; + margin-right: 18px; +} +.sparklines-stats-showcase span { + font-weight: 600; + font-size: 11px; + text-transform: uppercase; + display: block; + margin-bottom: 4px; +} +.sparklines-stats-showcase h2 { + margin: 0; + font-size: 20px; + line-height: 20px; +} diff --git a/public/site_assets/bootstrap/font-awesome/css/font-awesome.css b/public/site_assets/bootstrap/font-awesome/css/font-awesome.css new file mode 100644 index 00000000..048cff97 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/css/font-awesome.css @@ -0,0 +1,1338 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url('../fonts/fontawesome-webfont.eot?v=4.0.3'); + src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg'); + font-weight: normal; + font-style: normal; +} +.fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.3333333333333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.2857142857142858em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.142857142857143em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.142857142857143em; + width: 2.142857142857143em; + top: 0.14285714285714285em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.8571428571428572em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} +@-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(359deg); + } +} +@-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + } +} +@-o-keyframes spin { + 0% { + -o-transform: rotate(0deg); + } + 100% { + -o-transform: rotate(359deg); + } +} +@-ms-keyframes spin { + 0% { + -ms-transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(359deg); + } +} +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: "\f000"; +} +.fa-music:before { + content: "\f001"; +} +.fa-search:before { + content: "\f002"; +} +.fa-envelope-o:before { + content: "\f003"; +} +.fa-heart:before { + content: "\f004"; +} +.fa-star:before { + content: "\f005"; +} +.fa-star-o:before { + content: "\f006"; +} +.fa-user:before { + content: "\f007"; +} +.fa-film:before { + content: "\f008"; +} +.fa-th-large:before { + content: "\f009"; +} +.fa-th:before { + content: "\f00a"; +} +.fa-th-list:before { + content: "\f00b"; +} +.fa-check:before { + content: "\f00c"; +} +.fa-times:before { + content: "\f00d"; +} +.fa-search-plus:before { + content: "\f00e"; +} +.fa-search-minus:before { + content: "\f010"; +} +.fa-power-off:before { + content: "\f011"; +} +.fa-signal:before { + content: "\f012"; +} +.fa-gear:before, +.fa-cog:before { + content: "\f013"; +} +.fa-trash-o:before { + content: "\f014"; +} +.fa-home:before { + content: "\f015"; +} +.fa-file-o:before { + content: "\f016"; +} +.fa-clock-o:before { + content: "\f017"; +} +.fa-road:before { + content: "\f018"; +} +.fa-download:before { + content: "\f019"; +} +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} +.fa-inbox:before { + content: "\f01c"; +} +.fa-play-circle-o:before { + content: "\f01d"; +} +.fa-rotate-right:before, +.fa-repeat:before { + content: "\f01e"; +} +.fa-refresh:before { + content: "\f021"; +} +.fa-list-alt:before { + content: "\f022"; +} +.fa-lock:before { + content: "\f023"; +} +.fa-flag:before { + content: "\f024"; +} +.fa-headphones:before { + content: "\f025"; +} +.fa-volume-off:before { + content: "\f026"; +} +.fa-volume-down:before { + content: "\f027"; +} +.fa-volume-up:before { + content: "\f028"; +} +.fa-qrcode:before { + content: "\f029"; +} +.fa-barcode:before { + content: "\f02a"; +} +.fa-tag:before { + content: "\f02b"; +} +.fa-tags:before { + content: "\f02c"; +} +.fa-book:before { + content: "\f02d"; +} +.fa-bookmark:before { + content: "\f02e"; +} +.fa-print:before { + content: "\f02f"; +} +.fa-camera:before { + content: "\f030"; +} +.fa-font:before { + content: "\f031"; +} +.fa-bold:before { + content: "\f032"; +} +.fa-italic:before { + content: "\f033"; +} +.fa-text-height:before { + content: "\f034"; +} +.fa-text-width:before { + content: "\f035"; +} +.fa-align-left:before { + content: "\f036"; +} +.fa-align-center:before { + content: "\f037"; +} +.fa-align-right:before { + content: "\f038"; +} +.fa-align-justify:before { + content: "\f039"; +} +.fa-list:before { + content: "\f03a"; +} +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} +.fa-indent:before { + content: "\f03c"; +} +.fa-video-camera:before { + content: "\f03d"; +} +.fa-picture-o:before { + content: "\f03e"; +} +.fa-pencil:before { + content: "\f040"; +} +.fa-map-marker:before { + content: "\f041"; +} +.fa-adjust:before { + content: "\f042"; +} +.fa-tint:before { + content: "\f043"; +} +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} +.fa-share-square-o:before { + content: "\f045"; +} +.fa-check-square-o:before { + content: "\f046"; +} +.fa-arrows:before { + content: "\f047"; +} +.fa-step-backward:before { + content: "\f048"; +} +.fa-fast-backward:before { + content: "\f049"; +} +.fa-backward:before { + content: "\f04a"; +} +.fa-play:before { + content: "\f04b"; +} +.fa-pause:before { + content: "\f04c"; +} +.fa-stop:before { + content: "\f04d"; +} +.fa-forward:before { + content: "\f04e"; +} +.fa-fast-forward:before { + content: "\f050"; +} +.fa-step-forward:before { + content: "\f051"; +} +.fa-eject:before { + content: "\f052"; +} +.fa-chevron-left:before { + content: "\f053"; +} +.fa-chevron-right:before { + content: "\f054"; +} +.fa-plus-circle:before { + content: "\f055"; +} +.fa-minus-circle:before { + content: "\f056"; +} +.fa-times-circle:before { + content: "\f057"; +} +.fa-check-circle:before { + content: "\f058"; +} +.fa-question-circle:before { + content: "\f059"; +} +.fa-info-circle:before { + content: "\f05a"; +} +.fa-crosshairs:before { + content: "\f05b"; +} +.fa-times-circle-o:before { + content: "\f05c"; +} +.fa-check-circle-o:before { + content: "\f05d"; +} +.fa-ban:before { + content: "\f05e"; +} +.fa-arrow-left:before { + content: "\f060"; +} +.fa-arrow-right:before { + content: "\f061"; +} +.fa-arrow-up:before { + content: "\f062"; +} +.fa-arrow-down:before { + content: "\f063"; +} +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} +.fa-expand:before { + content: "\f065"; +} +.fa-compress:before { + content: "\f066"; +} +.fa-plus:before { + content: "\f067"; +} +.fa-minus:before { + content: "\f068"; +} +.fa-asterisk:before { + content: "\f069"; +} +.fa-exclamation-circle:before { + content: "\f06a"; +} +.fa-gift:before { + content: "\f06b"; +} +.fa-leaf:before { + content: "\f06c"; +} +.fa-fire:before { + content: "\f06d"; +} +.fa-eye:before { + content: "\f06e"; +} +.fa-eye-slash:before { + content: "\f070"; +} +.fa-warning:before, +.fa-exclamation-triangle:before { + content: "\f071"; +} +.fa-plane:before { + content: "\f072"; +} +.fa-calendar:before { + content: "\f073"; +} +.fa-random:before { + content: "\f074"; +} +.fa-comment:before { + content: "\f075"; +} +.fa-magnet:before { + content: "\f076"; +} +.fa-chevron-up:before { + content: "\f077"; +} +.fa-chevron-down:before { + content: "\f078"; +} +.fa-retweet:before { + content: "\f079"; +} +.fa-shopping-cart:before { + content: "\f07a"; +} +.fa-folder:before { + content: "\f07b"; +} +.fa-folder-open:before { + content: "\f07c"; +} +.fa-arrows-v:before { + content: "\f07d"; +} +.fa-arrows-h:before { + content: "\f07e"; +} +.fa-bar-chart-o:before { + content: "\f080"; +} +.fa-twitter-square:before { + content: "\f081"; +} +.fa-facebook-square:before { + content: "\f082"; +} +.fa-camera-retro:before { + content: "\f083"; +} +.fa-key:before { + content: "\f084"; +} +.fa-gears:before, +.fa-cogs:before { + content: "\f085"; +} +.fa-comments:before { + content: "\f086"; +} +.fa-thumbs-o-up:before { + content: "\f087"; +} +.fa-thumbs-o-down:before { + content: "\f088"; +} +.fa-star-half:before { + content: "\f089"; +} +.fa-heart-o:before { + content: "\f08a"; +} +.fa-sign-out:before { + content: "\f08b"; +} +.fa-linkedin-square:before { + content: "\f08c"; +} +.fa-thumb-tack:before { + content: "\f08d"; +} +.fa-external-link:before { + content: "\f08e"; +} +.fa-sign-in:before { + content: "\f090"; +} +.fa-trophy:before { + content: "\f091"; +} +.fa-github-square:before { + content: "\f092"; +} +.fa-upload:before { + content: "\f093"; +} +.fa-lemon-o:before { + content: "\f094"; +} +.fa-phone:before { + content: "\f095"; +} +.fa-square-o:before { + content: "\f096"; +} +.fa-bookmark-o:before { + content: "\f097"; +} +.fa-phone-square:before { + content: "\f098"; +} +.fa-twitter:before { + content: "\f099"; +} +.fa-facebook:before { + content: "\f09a"; +} +.fa-github:before { + content: "\f09b"; +} +.fa-unlock:before { + content: "\f09c"; +} +.fa-credit-card:before { + content: "\f09d"; +} +.fa-rss:before { + content: "\f09e"; +} +.fa-hdd-o:before { + content: "\f0a0"; +} +.fa-bullhorn:before { + content: "\f0a1"; +} +.fa-bell:before { + content: "\f0f3"; +} +.fa-certificate:before { + content: "\f0a3"; +} +.fa-hand-o-right:before { + content: "\f0a4"; +} +.fa-hand-o-left:before { + content: "\f0a5"; +} +.fa-hand-o-up:before { + content: "\f0a6"; +} +.fa-hand-o-down:before { + content: "\f0a7"; +} +.fa-arrow-circle-left:before { + content: "\f0a8"; +} +.fa-arrow-circle-right:before { + content: "\f0a9"; +} +.fa-arrow-circle-up:before { + content: "\f0aa"; +} +.fa-arrow-circle-down:before { + content: "\f0ab"; +} +.fa-globe:before { + content: "\f0ac"; +} +.fa-wrench:before { + content: "\f0ad"; +} +.fa-tasks:before { + content: "\f0ae"; +} +.fa-filter:before { + content: "\f0b0"; +} +.fa-briefcase:before { + content: "\f0b1"; +} +.fa-arrows-alt:before { + content: "\f0b2"; +} +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} +.fa-cloud:before { + content: "\f0c2"; +} +.fa-flask:before { + content: "\f0c3"; +} +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} +.fa-paperclip:before { + content: "\f0c6"; +} +.fa-save:before, +.fa-floppy-o:before { + content: "\f0c7"; +} +.fa-square:before { + content: "\f0c8"; +} +.fa-bars:before { + content: "\f0c9"; +} +.fa-list-ul:before { + content: "\f0ca"; +} +.fa-list-ol:before { + content: "\f0cb"; +} +.fa-strikethrough:before { + content: "\f0cc"; +} +.fa-underline:before { + content: "\f0cd"; +} +.fa-table:before { + content: "\f0ce"; +} +.fa-magic:before { + content: "\f0d0"; +} +.fa-truck:before { + content: "\f0d1"; +} +.fa-pinterest:before { + content: "\f0d2"; +} +.fa-pinterest-square:before { + content: "\f0d3"; +} +.fa-google-plus-square:before { + content: "\f0d4"; +} +.fa-google-plus:before { + content: "\f0d5"; +} +.fa-money:before { + content: "\f0d6"; +} +.fa-caret-down:before { + content: "\f0d7"; +} +.fa-caret-up:before { + content: "\f0d8"; +} +.fa-caret-left:before { + content: "\f0d9"; +} +.fa-caret-right:before { + content: "\f0da"; +} +.fa-columns:before { + content: "\f0db"; +} +.fa-unsorted:before, +.fa-sort:before { + content: "\f0dc"; +} +.fa-sort-down:before, +.fa-sort-asc:before { + content: "\f0dd"; +} +.fa-sort-up:before, +.fa-sort-desc:before { + content: "\f0de"; +} +.fa-envelope:before { + content: "\f0e0"; +} +.fa-linkedin:before { + content: "\f0e1"; +} +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} +.fa-legal:before, +.fa-gavel:before { + content: "\f0e3"; +} +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} +.fa-comment-o:before { + content: "\f0e5"; +} +.fa-comments-o:before { + content: "\f0e6"; +} +.fa-flash:before, +.fa-bolt:before { + content: "\f0e7"; +} +.fa-sitemap:before { + content: "\f0e8"; +} +.fa-umbrella:before { + content: "\f0e9"; +} +.fa-paste:before, +.fa-clipboard:before { + content: "\f0ea"; +} +.fa-lightbulb-o:before { + content: "\f0eb"; +} +.fa-exchange:before { + content: "\f0ec"; +} +.fa-cloud-download:before { + content: "\f0ed"; +} +.fa-cloud-upload:before { + content: "\f0ee"; +} +.fa-user-md:before { + content: "\f0f0"; +} +.fa-stethoscope:before { + content: "\f0f1"; +} +.fa-suitcase:before { + content: "\f0f2"; +} +.fa-bell-o:before { + content: "\f0a2"; +} +.fa-coffee:before { + content: "\f0f4"; +} +.fa-cutlery:before { + content: "\f0f5"; +} +.fa-file-text-o:before { + content: "\f0f6"; +} +.fa-building-o:before { + content: "\f0f7"; +} +.fa-hospital-o:before { + content: "\f0f8"; +} +.fa-ambulance:before { + content: "\f0f9"; +} +.fa-medkit:before { + content: "\f0fa"; +} +.fa-fighter-jet:before { + content: "\f0fb"; +} +.fa-beer:before { + content: "\f0fc"; +} +.fa-h-square:before { + content: "\f0fd"; +} +.fa-plus-square:before { + content: "\f0fe"; +} +.fa-angle-double-left:before { + content: "\f100"; +} +.fa-angle-double-right:before { + content: "\f101"; +} +.fa-angle-double-up:before { + content: "\f102"; +} +.fa-angle-double-down:before { + content: "\f103"; +} +.fa-angle-left:before { + content: "\f104"; +} +.fa-angle-right:before { + content: "\f105"; +} +.fa-angle-up:before { + content: "\f106"; +} +.fa-angle-down:before { + content: "\f107"; +} +.fa-desktop:before { + content: "\f108"; +} +.fa-laptop:before { + content: "\f109"; +} +.fa-tablet:before { + content: "\f10a"; +} +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} +.fa-circle-o:before { + content: "\f10c"; +} +.fa-quote-left:before { + content: "\f10d"; +} +.fa-quote-right:before { + content: "\f10e"; +} +.fa-spinner:before { + content: "\f110"; +} +.fa-circle:before { + content: "\f111"; +} +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} +.fa-github-alt:before { + content: "\f113"; +} +.fa-folder-o:before { + content: "\f114"; +} +.fa-folder-open-o:before { + content: "\f115"; +} +.fa-smile-o:before { + content: "\f118"; +} +.fa-frown-o:before { + content: "\f119"; +} +.fa-meh-o:before { + content: "\f11a"; +} +.fa-gamepad:before { + content: "\f11b"; +} +.fa-keyboard-o:before { + content: "\f11c"; +} +.fa-flag-o:before { + content: "\f11d"; +} +.fa-flag-checkered:before { + content: "\f11e"; +} +.fa-terminal:before { + content: "\f120"; +} +.fa-code:before { + content: "\f121"; +} +.fa-reply-all:before { + content: "\f122"; +} +.fa-mail-reply-all:before { + content: "\f122"; +} +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} +.fa-location-arrow:before { + content: "\f124"; +} +.fa-crop:before { + content: "\f125"; +} +.fa-code-fork:before { + content: "\f126"; +} +.fa-unlink:before, +.fa-chain-broken:before { + content: "\f127"; +} +.fa-question:before { + content: "\f128"; +} +.fa-info:before { + content: "\f129"; +} +.fa-exclamation:before { + content: "\f12a"; +} +.fa-superscript:before { + content: "\f12b"; +} +.fa-subscript:before { + content: "\f12c"; +} +.fa-eraser:before { + content: "\f12d"; +} +.fa-puzzle-piece:before { + content: "\f12e"; +} +.fa-microphone:before { + content: "\f130"; +} +.fa-microphone-slash:before { + content: "\f131"; +} +.fa-shield:before { + content: "\f132"; +} +.fa-calendar-o:before { + content: "\f133"; +} +.fa-fire-extinguisher:before { + content: "\f134"; +} +.fa-rocket:before { + content: "\f135"; +} +.fa-maxcdn:before { + content: "\f136"; +} +.fa-chevron-circle-left:before { + content: "\f137"; +} +.fa-chevron-circle-right:before { + content: "\f138"; +} +.fa-chevron-circle-up:before { + content: "\f139"; +} +.fa-chevron-circle-down:before { + content: "\f13a"; +} +.fa-html5:before { + content: "\f13b"; +} +.fa-css3:before { + content: "\f13c"; +} +.fa-anchor:before { + content: "\f13d"; +} +.fa-unlock-alt:before { + content: "\f13e"; +} +.fa-bullseye:before { + content: "\f140"; +} +.fa-ellipsis-h:before { + content: "\f141"; +} +.fa-ellipsis-v:before { + content: "\f142"; +} +.fa-rss-square:before { + content: "\f143"; +} +.fa-play-circle:before { + content: "\f144"; +} +.fa-ticket:before { + content: "\f145"; +} +.fa-minus-square:before { + content: "\f146"; +} +.fa-minus-square-o:before { + content: "\f147"; +} +.fa-level-up:before { + content: "\f148"; +} +.fa-level-down:before { + content: "\f149"; +} +.fa-check-square:before { + content: "\f14a"; +} +.fa-pencil-square:before { + content: "\f14b"; +} +.fa-external-link-square:before { + content: "\f14c"; +} +.fa-share-square:before { + content: "\f14d"; +} +.fa-compass:before { + content: "\f14e"; +} +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: "\f150"; +} +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: "\f151"; +} +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: "\f152"; +} +.fa-euro:before, +.fa-eur:before { + content: "\f153"; +} +.fa-gbp:before { + content: "\f154"; +} +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} +.fa-rupee:before, +.fa-inr:before { + content: "\f156"; +} +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: "\f157"; +} +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: "\f158"; +} +.fa-won:before, +.fa-krw:before { + content: "\f159"; +} +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} +.fa-file:before { + content: "\f15b"; +} +.fa-file-text:before { + content: "\f15c"; +} +.fa-sort-alpha-asc:before { + content: "\f15d"; +} +.fa-sort-alpha-desc:before { + content: "\f15e"; +} +.fa-sort-amount-asc:before { + content: "\f160"; +} +.fa-sort-amount-desc:before { + content: "\f161"; +} +.fa-sort-numeric-asc:before { + content: "\f162"; +} +.fa-sort-numeric-desc:before { + content: "\f163"; +} +.fa-thumbs-up:before { + content: "\f164"; +} +.fa-thumbs-down:before { + content: "\f165"; +} +.fa-youtube-square:before { + content: "\f166"; +} +.fa-youtube:before { + content: "\f167"; +} +.fa-xing:before { + content: "\f168"; +} +.fa-xing-square:before { + content: "\f169"; +} +.fa-youtube-play:before { + content: "\f16a"; +} +.fa-dropbox:before { + content: "\f16b"; +} +.fa-stack-overflow:before { + content: "\f16c"; +} +.fa-instagram:before { + content: "\f16d"; +} +.fa-flickr:before { + content: "\f16e"; +} +.fa-adn:before { + content: "\f170"; +} +.fa-bitbucket:before { + content: "\f171"; +} +.fa-bitbucket-square:before { + content: "\f172"; +} +.fa-tumblr:before { + content: "\f173"; +} +.fa-tumblr-square:before { + content: "\f174"; +} +.fa-long-arrow-down:before { + content: "\f175"; +} +.fa-long-arrow-up:before { + content: "\f176"; +} +.fa-long-arrow-left:before { + content: "\f177"; +} +.fa-long-arrow-right:before { + content: "\f178"; +} +.fa-apple:before { + content: "\f179"; +} +.fa-windows:before { + content: "\f17a"; +} +.fa-android:before { + content: "\f17b"; +} +.fa-linux:before { + content: "\f17c"; +} +.fa-dribbble:before { + content: "\f17d"; +} +.fa-skype:before { + content: "\f17e"; +} +.fa-foursquare:before { + content: "\f180"; +} +.fa-trello:before { + content: "\f181"; +} +.fa-female:before { + content: "\f182"; +} +.fa-male:before { + content: "\f183"; +} +.fa-gittip:before { + content: "\f184"; +} +.fa-sun-o:before { + content: "\f185"; +} +.fa-moon-o:before { + content: "\f186"; +} +.fa-archive:before { + content: "\f187"; +} +.fa-bug:before { + content: "\f188"; +} +.fa-vk:before { + content: "\f189"; +} +.fa-weibo:before { + content: "\f18a"; +} +.fa-renren:before { + content: "\f18b"; +} +.fa-pagelines:before { + content: "\f18c"; +} +.fa-stack-exchange:before { + content: "\f18d"; +} +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} +.fa-arrow-circle-o-left:before { + content: "\f190"; +} +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: "\f191"; +} +.fa-dot-circle-o:before { + content: "\f192"; +} +.fa-wheelchair:before { + content: "\f193"; +} +.fa-vimeo-square:before { + content: "\f194"; +} +.fa-turkish-lira:before, +.fa-try:before { + content: "\f195"; +} +.fa-plus-square-o:before { + content: "\f196"; +} diff --git a/public/site_assets/bootstrap/font-awesome/css/font-awesome.min.css b/public/site_assets/bootstrap/font-awesome/css/font-awesome.min.css new file mode 100644 index 00000000..449d6ac5 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/css/font-awesome.min.css @@ -0,0 +1,4 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.0.3');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font-family:FontAwesome;font-style:normal;font-weight:normal;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.3333333333333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.2857142857142858em;text-align:center}.fa-ul{padding-left:0;margin-left:2.142857142857143em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;top:.14285714285714285em;text-align:center}.fa-li.fa-lg{left:-1.8571428571428572em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0,mirror=1);-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2,mirror=1);-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-asc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-desc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-reply-all:before{content:"\f122"}.fa-mail-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"} \ No newline at end of file diff --git a/public/site_assets/bootstrap/font-awesome/fonts/FontAwesome.otf b/public/site_assets/bootstrap/font-awesome/fonts/FontAwesome.otf new file mode 100644 index 00000000..8b0f54e4 Binary files /dev/null and b/public/site_assets/bootstrap/font-awesome/fonts/FontAwesome.otf differ diff --git a/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.eot b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.eot new file mode 100644 index 00000000..7c79c6a6 Binary files /dev/null and b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.eot differ diff --git a/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.svg b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.svg new file mode 100644 index 00000000..45fdf338 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.svg @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.ttf b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.ttf new file mode 100644 index 00000000..e89738de Binary files /dev/null and b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.ttf differ diff --git a/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.woff b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.woff new file mode 100644 index 00000000..8c1748aa Binary files /dev/null and b/public/site_assets/bootstrap/font-awesome/fonts/fontawesome-webfont.woff differ diff --git a/public/site_assets/bootstrap/font-awesome/less/bordered-pulled.less b/public/site_assets/bootstrap/font-awesome/less/bordered-pulled.less new file mode 100644 index 00000000..0c90eb56 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/bordered-pulled.less @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.@{fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em @fa-border-color; + border-radius: .1em; +} + +.pull-right { float: right; } +.pull-left { float: left; } + +.@{fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/public/site_assets/bootstrap/font-awesome/less/core.less b/public/site_assets/bootstrap/font-awesome/less/core.less new file mode 100644 index 00000000..6d223bc2 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/core.less @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.@{fa-css-prefix} { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/public/site_assets/bootstrap/font-awesome/less/fixed-width.less b/public/site_assets/bootstrap/font-awesome/less/fixed-width.less new file mode 100644 index 00000000..110289f2 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/fixed-width.less @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.@{fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/public/site_assets/bootstrap/font-awesome/less/font-awesome.less b/public/site_assets/bootstrap/font-awesome/less/font-awesome.less new file mode 100644 index 00000000..96d2f222 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/font-awesome.less @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "spinning"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; diff --git a/public/site_assets/bootstrap/font-awesome/less/icons.less b/public/site_assets/bootstrap/font-awesome/less/icons.less new file mode 100644 index 00000000..bf0f856f --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/icons.less @@ -0,0 +1,412 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.@{fa-css-prefix}-glass:before { content: @fa-var-glass; } +.@{fa-css-prefix}-music:before { content: @fa-var-music; } +.@{fa-css-prefix}-search:before { content: @fa-var-search; } +.@{fa-css-prefix}-envelope-o:before { content: @fa-var-envelope-o; } +.@{fa-css-prefix}-heart:before { content: @fa-var-heart; } +.@{fa-css-prefix}-star:before { content: @fa-var-star; } +.@{fa-css-prefix}-star-o:before { content: @fa-var-star-o; } +.@{fa-css-prefix}-user:before { content: @fa-var-user; } +.@{fa-css-prefix}-film:before { content: @fa-var-film; } +.@{fa-css-prefix}-th-large:before { content: @fa-var-th-large; } +.@{fa-css-prefix}-th:before { content: @fa-var-th; } +.@{fa-css-prefix}-th-list:before { content: @fa-var-th-list; } +.@{fa-css-prefix}-check:before { content: @fa-var-check; } +.@{fa-css-prefix}-times:before { content: @fa-var-times; } +.@{fa-css-prefix}-search-plus:before { content: @fa-var-search-plus; } +.@{fa-css-prefix}-search-minus:before { content: @fa-var-search-minus; } +.@{fa-css-prefix}-power-off:before { content: @fa-var-power-off; } +.@{fa-css-prefix}-signal:before { content: @fa-var-signal; } +.@{fa-css-prefix}-gear:before, +.@{fa-css-prefix}-cog:before { content: @fa-var-cog; } +.@{fa-css-prefix}-trash-o:before { content: @fa-var-trash-o; } +.@{fa-css-prefix}-home:before { content: @fa-var-home; } +.@{fa-css-prefix}-file-o:before { content: @fa-var-file-o; } +.@{fa-css-prefix}-clock-o:before { content: @fa-var-clock-o; } +.@{fa-css-prefix}-road:before { content: @fa-var-road; } +.@{fa-css-prefix}-download:before { content: @fa-var-download; } +.@{fa-css-prefix}-arrow-circle-o-down:before { content: @fa-var-arrow-circle-o-down; } +.@{fa-css-prefix}-arrow-circle-o-up:before { content: @fa-var-arrow-circle-o-up; } +.@{fa-css-prefix}-inbox:before { content: @fa-var-inbox; } +.@{fa-css-prefix}-play-circle-o:before { content: @fa-var-play-circle-o; } +.@{fa-css-prefix}-rotate-right:before, +.@{fa-css-prefix}-repeat:before { content: @fa-var-repeat; } +.@{fa-css-prefix}-refresh:before { content: @fa-var-refresh; } +.@{fa-css-prefix}-list-alt:before { content: @fa-var-list-alt; } +.@{fa-css-prefix}-lock:before { content: @fa-var-lock; } +.@{fa-css-prefix}-flag:before { content: @fa-var-flag; } +.@{fa-css-prefix}-headphones:before { content: @fa-var-headphones; } +.@{fa-css-prefix}-volume-off:before { content: @fa-var-volume-off; } +.@{fa-css-prefix}-volume-down:before { content: @fa-var-volume-down; } +.@{fa-css-prefix}-volume-up:before { content: @fa-var-volume-up; } +.@{fa-css-prefix}-qrcode:before { content: @fa-var-qrcode; } +.@{fa-css-prefix}-barcode:before { content: @fa-var-barcode; } +.@{fa-css-prefix}-tag:before { content: @fa-var-tag; } +.@{fa-css-prefix}-tags:before { content: @fa-var-tags; } +.@{fa-css-prefix}-book:before { content: @fa-var-book; } +.@{fa-css-prefix}-bookmark:before { content: @fa-var-bookmark; } +.@{fa-css-prefix}-print:before { content: @fa-var-print; } +.@{fa-css-prefix}-camera:before { content: @fa-var-camera; } +.@{fa-css-prefix}-font:before { content: @fa-var-font; } +.@{fa-css-prefix}-bold:before { content: @fa-var-bold; } +.@{fa-css-prefix}-italic:before { content: @fa-var-italic; } +.@{fa-css-prefix}-text-height:before { content: @fa-var-text-height; } +.@{fa-css-prefix}-text-width:before { content: @fa-var-text-width; } +.@{fa-css-prefix}-align-left:before { content: @fa-var-align-left; } +.@{fa-css-prefix}-align-center:before { content: @fa-var-align-center; } +.@{fa-css-prefix}-align-right:before { content: @fa-var-align-right; } +.@{fa-css-prefix}-align-justify:before { content: @fa-var-align-justify; } +.@{fa-css-prefix}-list:before { content: @fa-var-list; } +.@{fa-css-prefix}-dedent:before, +.@{fa-css-prefix}-outdent:before { content: @fa-var-outdent; } +.@{fa-css-prefix}-indent:before { content: @fa-var-indent; } +.@{fa-css-prefix}-video-camera:before { content: @fa-var-video-camera; } +.@{fa-css-prefix}-picture-o:before { content: @fa-var-picture-o; } +.@{fa-css-prefix}-pencil:before { content: @fa-var-pencil; } +.@{fa-css-prefix}-map-marker:before { content: @fa-var-map-marker; } +.@{fa-css-prefix}-adjust:before { content: @fa-var-adjust; } +.@{fa-css-prefix}-tint:before { content: @fa-var-tint; } +.@{fa-css-prefix}-edit:before, +.@{fa-css-prefix}-pencil-square-o:before { content: @fa-var-pencil-square-o; } +.@{fa-css-prefix}-share-square-o:before { content: @fa-var-share-square-o; } +.@{fa-css-prefix}-check-square-o:before { content: @fa-var-check-square-o; } +.@{fa-css-prefix}-arrows:before { content: @fa-var-arrows; } +.@{fa-css-prefix}-step-backward:before { content: @fa-var-step-backward; } +.@{fa-css-prefix}-fast-backward:before { content: @fa-var-fast-backward; } +.@{fa-css-prefix}-backward:before { content: @fa-var-backward; } +.@{fa-css-prefix}-play:before { content: @fa-var-play; } +.@{fa-css-prefix}-pause:before { content: @fa-var-pause; } +.@{fa-css-prefix}-stop:before { content: @fa-var-stop; } +.@{fa-css-prefix}-forward:before { content: @fa-var-forward; } +.@{fa-css-prefix}-fast-forward:before { content: @fa-var-fast-forward; } +.@{fa-css-prefix}-step-forward:before { content: @fa-var-step-forward; } +.@{fa-css-prefix}-eject:before { content: @fa-var-eject; } +.@{fa-css-prefix}-chevron-left:before { content: @fa-var-chevron-left; } +.@{fa-css-prefix}-chevron-right:before { content: @fa-var-chevron-right; } +.@{fa-css-prefix}-plus-circle:before { content: @fa-var-plus-circle; } +.@{fa-css-prefix}-minus-circle:before { content: @fa-var-minus-circle; } +.@{fa-css-prefix}-times-circle:before { content: @fa-var-times-circle; } +.@{fa-css-prefix}-check-circle:before { content: @fa-var-check-circle; } +.@{fa-css-prefix}-question-circle:before { content: @fa-var-question-circle; } +.@{fa-css-prefix}-info-circle:before { content: @fa-var-info-circle; } +.@{fa-css-prefix}-crosshairs:before { content: @fa-var-crosshairs; } +.@{fa-css-prefix}-times-circle-o:before { content: @fa-var-times-circle-o; } +.@{fa-css-prefix}-check-circle-o:before { content: @fa-var-check-circle-o; } +.@{fa-css-prefix}-ban:before { content: @fa-var-ban; } +.@{fa-css-prefix}-arrow-left:before { content: @fa-var-arrow-left; } +.@{fa-css-prefix}-arrow-right:before { content: @fa-var-arrow-right; } +.@{fa-css-prefix}-arrow-up:before { content: @fa-var-arrow-up; } +.@{fa-css-prefix}-arrow-down:before { content: @fa-var-arrow-down; } +.@{fa-css-prefix}-mail-forward:before, +.@{fa-css-prefix}-share:before { content: @fa-var-share; } +.@{fa-css-prefix}-expand:before { content: @fa-var-expand; } +.@{fa-css-prefix}-compress:before { content: @fa-var-compress; } +.@{fa-css-prefix}-plus:before { content: @fa-var-plus; } +.@{fa-css-prefix}-minus:before { content: @fa-var-minus; } +.@{fa-css-prefix}-asterisk:before { content: @fa-var-asterisk; } +.@{fa-css-prefix}-exclamation-circle:before { content: @fa-var-exclamation-circle; } +.@{fa-css-prefix}-gift:before { content: @fa-var-gift; } +.@{fa-css-prefix}-leaf:before { content: @fa-var-leaf; } +.@{fa-css-prefix}-fire:before { content: @fa-var-fire; } +.@{fa-css-prefix}-eye:before { content: @fa-var-eye; } +.@{fa-css-prefix}-eye-slash:before { content: @fa-var-eye-slash; } +.@{fa-css-prefix}-warning:before, +.@{fa-css-prefix}-exclamation-triangle:before { content: @fa-var-exclamation-triangle; } +.@{fa-css-prefix}-plane:before { content: @fa-var-plane; } +.@{fa-css-prefix}-calendar:before { content: @fa-var-calendar; } +.@{fa-css-prefix}-random:before { content: @fa-var-random; } +.@{fa-css-prefix}-comment:before { content: @fa-var-comment; } +.@{fa-css-prefix}-magnet:before { content: @fa-var-magnet; } +.@{fa-css-prefix}-chevron-up:before { content: @fa-var-chevron-up; } +.@{fa-css-prefix}-chevron-down:before { content: @fa-var-chevron-down; } +.@{fa-css-prefix}-retweet:before { content: @fa-var-retweet; } +.@{fa-css-prefix}-shopping-cart:before { content: @fa-var-shopping-cart; } +.@{fa-css-prefix}-folder:before { content: @fa-var-folder; } +.@{fa-css-prefix}-folder-open:before { content: @fa-var-folder-open; } +.@{fa-css-prefix}-arrows-v:before { content: @fa-var-arrows-v; } +.@{fa-css-prefix}-arrows-h:before { content: @fa-var-arrows-h; } +.@{fa-css-prefix}-bar-chart-o:before { content: @fa-var-bar-chart-o; } +.@{fa-css-prefix}-twitter-square:before { content: @fa-var-twitter-square; } +.@{fa-css-prefix}-facebook-square:before { content: @fa-var-facebook-square; } +.@{fa-css-prefix}-camera-retro:before { content: @fa-var-camera-retro; } +.@{fa-css-prefix}-key:before { content: @fa-var-key; } +.@{fa-css-prefix}-gears:before, +.@{fa-css-prefix}-cogs:before { content: @fa-var-cogs; } +.@{fa-css-prefix}-comments:before { content: @fa-var-comments; } +.@{fa-css-prefix}-thumbs-o-up:before { content: @fa-var-thumbs-o-up; } +.@{fa-css-prefix}-thumbs-o-down:before { content: @fa-var-thumbs-o-down; } +.@{fa-css-prefix}-star-half:before { content: @fa-var-star-half; } +.@{fa-css-prefix}-heart-o:before { content: @fa-var-heart-o; } +.@{fa-css-prefix}-sign-out:before { content: @fa-var-sign-out; } +.@{fa-css-prefix}-linkedin-square:before { content: @fa-var-linkedin-square; } +.@{fa-css-prefix}-thumb-tack:before { content: @fa-var-thumb-tack; } +.@{fa-css-prefix}-external-link:before { content: @fa-var-external-link; } +.@{fa-css-prefix}-sign-in:before { content: @fa-var-sign-in; } +.@{fa-css-prefix}-trophy:before { content: @fa-var-trophy; } +.@{fa-css-prefix}-github-square:before { content: @fa-var-github-square; } +.@{fa-css-prefix}-upload:before { content: @fa-var-upload; } +.@{fa-css-prefix}-lemon-o:before { content: @fa-var-lemon-o; } +.@{fa-css-prefix}-phone:before { content: @fa-var-phone; } +.@{fa-css-prefix}-square-o:before { content: @fa-var-square-o; } +.@{fa-css-prefix}-bookmark-o:before { content: @fa-var-bookmark-o; } +.@{fa-css-prefix}-phone-square:before { content: @fa-var-phone-square; } +.@{fa-css-prefix}-twitter:before { content: @fa-var-twitter; } +.@{fa-css-prefix}-facebook:before { content: @fa-var-facebook; } +.@{fa-css-prefix}-github:before { content: @fa-var-github; } +.@{fa-css-prefix}-unlock:before { content: @fa-var-unlock; } +.@{fa-css-prefix}-credit-card:before { content: @fa-var-credit-card; } +.@{fa-css-prefix}-rss:before { content: @fa-var-rss; } +.@{fa-css-prefix}-hdd-o:before { content: @fa-var-hdd-o; } +.@{fa-css-prefix}-bullhorn:before { content: @fa-var-bullhorn; } +.@{fa-css-prefix}-bell:before { content: @fa-var-bell; } +.@{fa-css-prefix}-certificate:before { content: @fa-var-certificate; } +.@{fa-css-prefix}-hand-o-right:before { content: @fa-var-hand-o-right; } +.@{fa-css-prefix}-hand-o-left:before { content: @fa-var-hand-o-left; } +.@{fa-css-prefix}-hand-o-up:before { content: @fa-var-hand-o-up; } +.@{fa-css-prefix}-hand-o-down:before { content: @fa-var-hand-o-down; } +.@{fa-css-prefix}-arrow-circle-left:before { content: @fa-var-arrow-circle-left; } +.@{fa-css-prefix}-arrow-circle-right:before { content: @fa-var-arrow-circle-right; } +.@{fa-css-prefix}-arrow-circle-up:before { content: @fa-var-arrow-circle-up; } +.@{fa-css-prefix}-arrow-circle-down:before { content: @fa-var-arrow-circle-down; } +.@{fa-css-prefix}-globe:before { content: @fa-var-globe; } +.@{fa-css-prefix}-wrench:before { content: @fa-var-wrench; } +.@{fa-css-prefix}-tasks:before { content: @fa-var-tasks; } +.@{fa-css-prefix}-filter:before { content: @fa-var-filter; } +.@{fa-css-prefix}-briefcase:before { content: @fa-var-briefcase; } +.@{fa-css-prefix}-arrows-alt:before { content: @fa-var-arrows-alt; } +.@{fa-css-prefix}-group:before, +.@{fa-css-prefix}-users:before { content: @fa-var-users; } +.@{fa-css-prefix}-chain:before, +.@{fa-css-prefix}-link:before { content: @fa-var-link; } +.@{fa-css-prefix}-cloud:before { content: @fa-var-cloud; } +.@{fa-css-prefix}-flask:before { content: @fa-var-flask; } +.@{fa-css-prefix}-cut:before, +.@{fa-css-prefix}-scissors:before { content: @fa-var-scissors; } +.@{fa-css-prefix}-copy:before, +.@{fa-css-prefix}-files-o:before { content: @fa-var-files-o; } +.@{fa-css-prefix}-paperclip:before { content: @fa-var-paperclip; } +.@{fa-css-prefix}-save:before, +.@{fa-css-prefix}-floppy-o:before { content: @fa-var-floppy-o; } +.@{fa-css-prefix}-square:before { content: @fa-var-square; } +.@{fa-css-prefix}-bars:before { content: @fa-var-bars; } +.@{fa-css-prefix}-list-ul:before { content: @fa-var-list-ul; } +.@{fa-css-prefix}-list-ol:before { content: @fa-var-list-ol; } +.@{fa-css-prefix}-strikethrough:before { content: @fa-var-strikethrough; } +.@{fa-css-prefix}-underline:before { content: @fa-var-underline; } +.@{fa-css-prefix}-table:before { content: @fa-var-table; } +.@{fa-css-prefix}-magic:before { content: @fa-var-magic; } +.@{fa-css-prefix}-truck:before { content: @fa-var-truck; } +.@{fa-css-prefix}-pinterest:before { content: @fa-var-pinterest; } +.@{fa-css-prefix}-pinterest-square:before { content: @fa-var-pinterest-square; } +.@{fa-css-prefix}-google-plus-square:before { content: @fa-var-google-plus-square; } +.@{fa-css-prefix}-google-plus:before { content: @fa-var-google-plus; } +.@{fa-css-prefix}-money:before { content: @fa-var-money; } +.@{fa-css-prefix}-caret-down:before { content: @fa-var-caret-down; } +.@{fa-css-prefix}-caret-up:before { content: @fa-var-caret-up; } +.@{fa-css-prefix}-caret-left:before { content: @fa-var-caret-left; } +.@{fa-css-prefix}-caret-right:before { content: @fa-var-caret-right; } +.@{fa-css-prefix}-columns:before { content: @fa-var-columns; } +.@{fa-css-prefix}-unsorted:before, +.@{fa-css-prefix}-sort:before { content: @fa-var-sort; } +.@{fa-css-prefix}-sort-down:before, +.@{fa-css-prefix}-sort-asc:before { content: @fa-var-sort-asc; } +.@{fa-css-prefix}-sort-up:before, +.@{fa-css-prefix}-sort-desc:before { content: @fa-var-sort-desc; } +.@{fa-css-prefix}-envelope:before { content: @fa-var-envelope; } +.@{fa-css-prefix}-linkedin:before { content: @fa-var-linkedin; } +.@{fa-css-prefix}-rotate-left:before, +.@{fa-css-prefix}-undo:before { content: @fa-var-undo; } +.@{fa-css-prefix}-legal:before, +.@{fa-css-prefix}-gavel:before { content: @fa-var-gavel; } +.@{fa-css-prefix}-dashboard:before, +.@{fa-css-prefix}-tachometer:before { content: @fa-var-tachometer; } +.@{fa-css-prefix}-comment-o:before { content: @fa-var-comment-o; } +.@{fa-css-prefix}-comments-o:before { content: @fa-var-comments-o; } +.@{fa-css-prefix}-flash:before, +.@{fa-css-prefix}-bolt:before { content: @fa-var-bolt; } +.@{fa-css-prefix}-sitemap:before { content: @fa-var-sitemap; } +.@{fa-css-prefix}-umbrella:before { content: @fa-var-umbrella; } +.@{fa-css-prefix}-paste:before, +.@{fa-css-prefix}-clipboard:before { content: @fa-var-clipboard; } +.@{fa-css-prefix}-lightbulb-o:before { content: @fa-var-lightbulb-o; } +.@{fa-css-prefix}-exchange:before { content: @fa-var-exchange; } +.@{fa-css-prefix}-cloud-download:before { content: @fa-var-cloud-download; } +.@{fa-css-prefix}-cloud-upload:before { content: @fa-var-cloud-upload; } +.@{fa-css-prefix}-user-md:before { content: @fa-var-user-md; } +.@{fa-css-prefix}-stethoscope:before { content: @fa-var-stethoscope; } +.@{fa-css-prefix}-suitcase:before { content: @fa-var-suitcase; } +.@{fa-css-prefix}-bell-o:before { content: @fa-var-bell-o; } +.@{fa-css-prefix}-coffee:before { content: @fa-var-coffee; } +.@{fa-css-prefix}-cutlery:before { content: @fa-var-cutlery; } +.@{fa-css-prefix}-file-text-o:before { content: @fa-var-file-text-o; } +.@{fa-css-prefix}-building-o:before { content: @fa-var-building-o; } +.@{fa-css-prefix}-hospital-o:before { content: @fa-var-hospital-o; } +.@{fa-css-prefix}-ambulance:before { content: @fa-var-ambulance; } +.@{fa-css-prefix}-medkit:before { content: @fa-var-medkit; } +.@{fa-css-prefix}-fighter-jet:before { content: @fa-var-fighter-jet; } +.@{fa-css-prefix}-beer:before { content: @fa-var-beer; } +.@{fa-css-prefix}-h-square:before { content: @fa-var-h-square; } +.@{fa-css-prefix}-plus-square:before { content: @fa-var-plus-square; } +.@{fa-css-prefix}-angle-double-left:before { content: @fa-var-angle-double-left; } +.@{fa-css-prefix}-angle-double-right:before { content: @fa-var-angle-double-right; } +.@{fa-css-prefix}-angle-double-up:before { content: @fa-var-angle-double-up; } +.@{fa-css-prefix}-angle-double-down:before { content: @fa-var-angle-double-down; } +.@{fa-css-prefix}-angle-left:before { content: @fa-var-angle-left; } +.@{fa-css-prefix}-angle-right:before { content: @fa-var-angle-right; } +.@{fa-css-prefix}-angle-up:before { content: @fa-var-angle-up; } +.@{fa-css-prefix}-angle-down:before { content: @fa-var-angle-down; } +.@{fa-css-prefix}-desktop:before { content: @fa-var-desktop; } +.@{fa-css-prefix}-laptop:before { content: @fa-var-laptop; } +.@{fa-css-prefix}-tablet:before { content: @fa-var-tablet; } +.@{fa-css-prefix}-mobile-phone:before, +.@{fa-css-prefix}-mobile:before { content: @fa-var-mobile; } +.@{fa-css-prefix}-circle-o:before { content: @fa-var-circle-o; } +.@{fa-css-prefix}-quote-left:before { content: @fa-var-quote-left; } +.@{fa-css-prefix}-quote-right:before { content: @fa-var-quote-right; } +.@{fa-css-prefix}-spinner:before { content: @fa-var-spinner; } +.@{fa-css-prefix}-circle:before { content: @fa-var-circle; } +.@{fa-css-prefix}-mail-reply:before, +.@{fa-css-prefix}-reply:before { content: @fa-var-reply; } +.@{fa-css-prefix}-github-alt:before { content: @fa-var-github-alt; } +.@{fa-css-prefix}-folder-o:before { content: @fa-var-folder-o; } +.@{fa-css-prefix}-folder-open-o:before { content: @fa-var-folder-open-o; } +.@{fa-css-prefix}-smile-o:before { content: @fa-var-smile-o; } +.@{fa-css-prefix}-frown-o:before { content: @fa-var-frown-o; } +.@{fa-css-prefix}-meh-o:before { content: @fa-var-meh-o; } +.@{fa-css-prefix}-gamepad:before { content: @fa-var-gamepad; } +.@{fa-css-prefix}-keyboard-o:before { content: @fa-var-keyboard-o; } +.@{fa-css-prefix}-flag-o:before { content: @fa-var-flag-o; } +.@{fa-css-prefix}-flag-checkered:before { content: @fa-var-flag-checkered; } +.@{fa-css-prefix}-terminal:before { content: @fa-var-terminal; } +.@{fa-css-prefix}-code:before { content: @fa-var-code; } +.@{fa-css-prefix}-reply-all:before { content: @fa-var-reply-all; } +.@{fa-css-prefix}-mail-reply-all:before { content: @fa-var-mail-reply-all; } +.@{fa-css-prefix}-star-half-empty:before, +.@{fa-css-prefix}-star-half-full:before, +.@{fa-css-prefix}-star-half-o:before { content: @fa-var-star-half-o; } +.@{fa-css-prefix}-location-arrow:before { content: @fa-var-location-arrow; } +.@{fa-css-prefix}-crop:before { content: @fa-var-crop; } +.@{fa-css-prefix}-code-fork:before { content: @fa-var-code-fork; } +.@{fa-css-prefix}-unlink:before, +.@{fa-css-prefix}-chain-broken:before { content: @fa-var-chain-broken; } +.@{fa-css-prefix}-question:before { content: @fa-var-question; } +.@{fa-css-prefix}-info:before { content: @fa-var-info; } +.@{fa-css-prefix}-exclamation:before { content: @fa-var-exclamation; } +.@{fa-css-prefix}-superscript:before { content: @fa-var-superscript; } +.@{fa-css-prefix}-subscript:before { content: @fa-var-subscript; } +.@{fa-css-prefix}-eraser:before { content: @fa-var-eraser; } +.@{fa-css-prefix}-puzzle-piece:before { content: @fa-var-puzzle-piece; } +.@{fa-css-prefix}-microphone:before { content: @fa-var-microphone; } +.@{fa-css-prefix}-microphone-slash:before { content: @fa-var-microphone-slash; } +.@{fa-css-prefix}-shield:before { content: @fa-var-shield; } +.@{fa-css-prefix}-calendar-o:before { content: @fa-var-calendar-o; } +.@{fa-css-prefix}-fire-extinguisher:before { content: @fa-var-fire-extinguisher; } +.@{fa-css-prefix}-rocket:before { content: @fa-var-rocket; } +.@{fa-css-prefix}-maxcdn:before { content: @fa-var-maxcdn; } +.@{fa-css-prefix}-chevron-circle-left:before { content: @fa-var-chevron-circle-left; } +.@{fa-css-prefix}-chevron-circle-right:before { content: @fa-var-chevron-circle-right; } +.@{fa-css-prefix}-chevron-circle-up:before { content: @fa-var-chevron-circle-up; } +.@{fa-css-prefix}-chevron-circle-down:before { content: @fa-var-chevron-circle-down; } +.@{fa-css-prefix}-html5:before { content: @fa-var-html5; } +.@{fa-css-prefix}-css3:before { content: @fa-var-css3; } +.@{fa-css-prefix}-anchor:before { content: @fa-var-anchor; } +.@{fa-css-prefix}-unlock-alt:before { content: @fa-var-unlock-alt; } +.@{fa-css-prefix}-bullseye:before { content: @fa-var-bullseye; } +.@{fa-css-prefix}-ellipsis-h:before { content: @fa-var-ellipsis-h; } +.@{fa-css-prefix}-ellipsis-v:before { content: @fa-var-ellipsis-v; } +.@{fa-css-prefix}-rss-square:before { content: @fa-var-rss-square; } +.@{fa-css-prefix}-play-circle:before { content: @fa-var-play-circle; } +.@{fa-css-prefix}-ticket:before { content: @fa-var-ticket; } +.@{fa-css-prefix}-minus-square:before { content: @fa-var-minus-square; } +.@{fa-css-prefix}-minus-square-o:before { content: @fa-var-minus-square-o; } +.@{fa-css-prefix}-level-up:before { content: @fa-var-level-up; } +.@{fa-css-prefix}-level-down:before { content: @fa-var-level-down; } +.@{fa-css-prefix}-check-square:before { content: @fa-var-check-square; } +.@{fa-css-prefix}-pencil-square:before { content: @fa-var-pencil-square; } +.@{fa-css-prefix}-external-link-square:before { content: @fa-var-external-link-square; } +.@{fa-css-prefix}-share-square:before { content: @fa-var-share-square; } +.@{fa-css-prefix}-compass:before { content: @fa-var-compass; } +.@{fa-css-prefix}-toggle-down:before, +.@{fa-css-prefix}-caret-square-o-down:before { content: @fa-var-caret-square-o-down; } +.@{fa-css-prefix}-toggle-up:before, +.@{fa-css-prefix}-caret-square-o-up:before { content: @fa-var-caret-square-o-up; } +.@{fa-css-prefix}-toggle-right:before, +.@{fa-css-prefix}-caret-square-o-right:before { content: @fa-var-caret-square-o-right; } +.@{fa-css-prefix}-euro:before, +.@{fa-css-prefix}-eur:before { content: @fa-var-eur; } +.@{fa-css-prefix}-gbp:before { content: @fa-var-gbp; } +.@{fa-css-prefix}-dollar:before, +.@{fa-css-prefix}-usd:before { content: @fa-var-usd; } +.@{fa-css-prefix}-rupee:before, +.@{fa-css-prefix}-inr:before { content: @fa-var-inr; } +.@{fa-css-prefix}-cny:before, +.@{fa-css-prefix}-rmb:before, +.@{fa-css-prefix}-yen:before, +.@{fa-css-prefix}-jpy:before { content: @fa-var-jpy; } +.@{fa-css-prefix}-ruble:before, +.@{fa-css-prefix}-rouble:before, +.@{fa-css-prefix}-rub:before { content: @fa-var-rub; } +.@{fa-css-prefix}-won:before, +.@{fa-css-prefix}-krw:before { content: @fa-var-krw; } +.@{fa-css-prefix}-bitcoin:before, +.@{fa-css-prefix}-btc:before { content: @fa-var-btc; } +.@{fa-css-prefix}-file:before { content: @fa-var-file; } +.@{fa-css-prefix}-file-text:before { content: @fa-var-file-text; } +.@{fa-css-prefix}-sort-alpha-asc:before { content: @fa-var-sort-alpha-asc; } +.@{fa-css-prefix}-sort-alpha-desc:before { content: @fa-var-sort-alpha-desc; } +.@{fa-css-prefix}-sort-amount-asc:before { content: @fa-var-sort-amount-asc; } +.@{fa-css-prefix}-sort-amount-desc:before { content: @fa-var-sort-amount-desc; } +.@{fa-css-prefix}-sort-numeric-asc:before { content: @fa-var-sort-numeric-asc; } +.@{fa-css-prefix}-sort-numeric-desc:before { content: @fa-var-sort-numeric-desc; } +.@{fa-css-prefix}-thumbs-up:before { content: @fa-var-thumbs-up; } +.@{fa-css-prefix}-thumbs-down:before { content: @fa-var-thumbs-down; } +.@{fa-css-prefix}-youtube-square:before { content: @fa-var-youtube-square; } +.@{fa-css-prefix}-youtube:before { content: @fa-var-youtube; } +.@{fa-css-prefix}-xing:before { content: @fa-var-xing; } +.@{fa-css-prefix}-xing-square:before { content: @fa-var-xing-square; } +.@{fa-css-prefix}-youtube-play:before { content: @fa-var-youtube-play; } +.@{fa-css-prefix}-dropbox:before { content: @fa-var-dropbox; } +.@{fa-css-prefix}-stack-overflow:before { content: @fa-var-stack-overflow; } +.@{fa-css-prefix}-instagram:before { content: @fa-var-instagram; } +.@{fa-css-prefix}-flickr:before { content: @fa-var-flickr; } +.@{fa-css-prefix}-adn:before { content: @fa-var-adn; } +.@{fa-css-prefix}-bitbucket:before { content: @fa-var-bitbucket; } +.@{fa-css-prefix}-bitbucket-square:before { content: @fa-var-bitbucket-square; } +.@{fa-css-prefix}-tumblr:before { content: @fa-var-tumblr; } +.@{fa-css-prefix}-tumblr-square:before { content: @fa-var-tumblr-square; } +.@{fa-css-prefix}-long-arrow-down:before { content: @fa-var-long-arrow-down; } +.@{fa-css-prefix}-long-arrow-up:before { content: @fa-var-long-arrow-up; } +.@{fa-css-prefix}-long-arrow-left:before { content: @fa-var-long-arrow-left; } +.@{fa-css-prefix}-long-arrow-right:before { content: @fa-var-long-arrow-right; } +.@{fa-css-prefix}-apple:before { content: @fa-var-apple; } +.@{fa-css-prefix}-windows:before { content: @fa-var-windows; } +.@{fa-css-prefix}-android:before { content: @fa-var-android; } +.@{fa-css-prefix}-linux:before { content: @fa-var-linux; } +.@{fa-css-prefix}-dribbble:before { content: @fa-var-dribbble; } +.@{fa-css-prefix}-skype:before { content: @fa-var-skype; } +.@{fa-css-prefix}-foursquare:before { content: @fa-var-foursquare; } +.@{fa-css-prefix}-trello:before { content: @fa-var-trello; } +.@{fa-css-prefix}-female:before { content: @fa-var-female; } +.@{fa-css-prefix}-male:before { content: @fa-var-male; } +.@{fa-css-prefix}-gittip:before { content: @fa-var-gittip; } +.@{fa-css-prefix}-sun-o:before { content: @fa-var-sun-o; } +.@{fa-css-prefix}-moon-o:before { content: @fa-var-moon-o; } +.@{fa-css-prefix}-archive:before { content: @fa-var-archive; } +.@{fa-css-prefix}-bug:before { content: @fa-var-bug; } +.@{fa-css-prefix}-vk:before { content: @fa-var-vk; } +.@{fa-css-prefix}-weibo:before { content: @fa-var-weibo; } +.@{fa-css-prefix}-renren:before { content: @fa-var-renren; } +.@{fa-css-prefix}-pagelines:before { content: @fa-var-pagelines; } +.@{fa-css-prefix}-stack-exchange:before { content: @fa-var-stack-exchange; } +.@{fa-css-prefix}-arrow-circle-o-right:before { content: @fa-var-arrow-circle-o-right; } +.@{fa-css-prefix}-arrow-circle-o-left:before { content: @fa-var-arrow-circle-o-left; } +.@{fa-css-prefix}-toggle-left:before, +.@{fa-css-prefix}-caret-square-o-left:before { content: @fa-var-caret-square-o-left; } +.@{fa-css-prefix}-dot-circle-o:before { content: @fa-var-dot-circle-o; } +.@{fa-css-prefix}-wheelchair:before { content: @fa-var-wheelchair; } +.@{fa-css-prefix}-vimeo-square:before { content: @fa-var-vimeo-square; } +.@{fa-css-prefix}-turkish-lira:before, +.@{fa-css-prefix}-try:before { content: @fa-var-try; } +.@{fa-css-prefix}-plus-square-o:before { content: @fa-var-plus-square-o; } diff --git a/public/site_assets/bootstrap/font-awesome/less/larger.less b/public/site_assets/bootstrap/font-awesome/less/larger.less new file mode 100644 index 00000000..c9d64677 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/larger.less @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.@{fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.@{fa-css-prefix}-2x { font-size: 2em; } +.@{fa-css-prefix}-3x { font-size: 3em; } +.@{fa-css-prefix}-4x { font-size: 4em; } +.@{fa-css-prefix}-5x { font-size: 5em; } diff --git a/public/site_assets/bootstrap/font-awesome/less/list.less b/public/site_assets/bootstrap/font-awesome/less/list.less new file mode 100644 index 00000000..eed93405 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/list.less @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.@{fa-css-prefix}-ul { + padding-left: 0; + margin-left: @fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.@{fa-css-prefix}-li { + position: absolute; + left: -@fa-li-width; + width: @fa-li-width; + top: (2em / 14); + text-align: center; + &.@{fa-css-prefix}-lg { + left: -@fa-li-width + (4em / 14); + } +} diff --git a/public/site_assets/bootstrap/font-awesome/less/mixins.less b/public/site_assets/bootstrap/font-awesome/less/mixins.less new file mode 100644 index 00000000..19e5a645 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/mixins.less @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +.fa-icon-rotate(@degrees, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation); + -webkit-transform: rotate(@degrees); + -moz-transform: rotate(@degrees); + -ms-transform: rotate(@degrees); + -o-transform: rotate(@degrees); + transform: rotate(@degrees); +} + +.fa-icon-flip(@horiz, @vert, @rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=@rotation, mirror=1); + -webkit-transform: scale(@horiz, @vert); + -moz-transform: scale(@horiz, @vert); + -ms-transform: scale(@horiz, @vert); + -o-transform: scale(@horiz, @vert); + transform: scale(@horiz, @vert); +} diff --git a/public/site_assets/bootstrap/font-awesome/less/path.less b/public/site_assets/bootstrap/font-awesome/less/path.less new file mode 100644 index 00000000..c5a69124 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/path.less @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); + src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), + url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), + url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), + url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); +// src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/public/site_assets/bootstrap/font-awesome/less/rotated-flipped.less b/public/site_assets/bootstrap/font-awesome/less/rotated-flipped.less new file mode 100644 index 00000000..8fff3a6c --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/rotated-flipped.less @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } +.@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } +.@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } + +.@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } +.@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } diff --git a/public/site_assets/bootstrap/font-awesome/less/spinning.less b/public/site_assets/bootstrap/font-awesome/less/spinning.less new file mode 100644 index 00000000..60828fe5 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/spinning.less @@ -0,0 +1,30 @@ +// Spinning Icons +// -------------------------- + +.@{fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@-ms-keyframes spin { + 0% { -ms-transform: rotate(0deg); } + 100% { -ms-transform: rotate(359deg); } +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} diff --git a/public/site_assets/bootstrap/font-awesome/less/stacked.less b/public/site_assets/bootstrap/font-awesome/less/stacked.less new file mode 100644 index 00000000..fc53fb0e --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/stacked.less @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.@{fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.@{fa-css-prefix}-stack-1x { line-height: inherit; } +.@{fa-css-prefix}-stack-2x { font-size: 2em; } +.@{fa-css-prefix}-inverse { color: @fa-inverse; } diff --git a/public/site_assets/bootstrap/font-awesome/less/variables.less b/public/site_assets/bootstrap/font-awesome/less/variables.less new file mode 100644 index 00000000..f40a555f --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/less/variables.less @@ -0,0 +1,381 @@ +// Variables +// -------------------------- + +@fa-font-path: "../fonts"; +//@fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts"; // for referencing Bootstrap CDN font files directly +@fa-css-prefix: fa; +@fa-version: "4.0.3"; +@fa-border-color: #eee; +@fa-inverse: #fff; +@fa-li-width: (30em / 14); + +@fa-var-glass: "\f000"; +@fa-var-music: "\f001"; +@fa-var-search: "\f002"; +@fa-var-envelope-o: "\f003"; +@fa-var-heart: "\f004"; +@fa-var-star: "\f005"; +@fa-var-star-o: "\f006"; +@fa-var-user: "\f007"; +@fa-var-film: "\f008"; +@fa-var-th-large: "\f009"; +@fa-var-th: "\f00a"; +@fa-var-th-list: "\f00b"; +@fa-var-check: "\f00c"; +@fa-var-times: "\f00d"; +@fa-var-search-plus: "\f00e"; +@fa-var-search-minus: "\f010"; +@fa-var-power-off: "\f011"; +@fa-var-signal: "\f012"; +@fa-var-cog: "\f013"; +@fa-var-trash-o: "\f014"; +@fa-var-home: "\f015"; +@fa-var-file-o: "\f016"; +@fa-var-clock-o: "\f017"; +@fa-var-road: "\f018"; +@fa-var-download: "\f019"; +@fa-var-arrow-circle-o-down: "\f01a"; +@fa-var-arrow-circle-o-up: "\f01b"; +@fa-var-inbox: "\f01c"; +@fa-var-play-circle-o: "\f01d"; +@fa-var-repeat: "\f01e"; +@fa-var-refresh: "\f021"; +@fa-var-list-alt: "\f022"; +@fa-var-lock: "\f023"; +@fa-var-flag: "\f024"; +@fa-var-headphones: "\f025"; +@fa-var-volume-off: "\f026"; +@fa-var-volume-down: "\f027"; +@fa-var-volume-up: "\f028"; +@fa-var-qrcode: "\f029"; +@fa-var-barcode: "\f02a"; +@fa-var-tag: "\f02b"; +@fa-var-tags: "\f02c"; +@fa-var-book: "\f02d"; +@fa-var-bookmark: "\f02e"; +@fa-var-print: "\f02f"; +@fa-var-camera: "\f030"; +@fa-var-font: "\f031"; +@fa-var-bold: "\f032"; +@fa-var-italic: "\f033"; +@fa-var-text-height: "\f034"; +@fa-var-text-width: "\f035"; +@fa-var-align-left: "\f036"; +@fa-var-align-center: "\f037"; +@fa-var-align-right: "\f038"; +@fa-var-align-justify: "\f039"; +@fa-var-list: "\f03a"; +@fa-var-outdent: "\f03b"; +@fa-var-indent: "\f03c"; +@fa-var-video-camera: "\f03d"; +@fa-var-picture-o: "\f03e"; +@fa-var-pencil: "\f040"; +@fa-var-map-marker: "\f041"; +@fa-var-adjust: "\f042"; +@fa-var-tint: "\f043"; +@fa-var-pencil-square-o: "\f044"; +@fa-var-share-square-o: "\f045"; +@fa-var-check-square-o: "\f046"; +@fa-var-arrows: "\f047"; +@fa-var-step-backward: "\f048"; +@fa-var-fast-backward: "\f049"; +@fa-var-backward: "\f04a"; +@fa-var-play: "\f04b"; +@fa-var-pause: "\f04c"; +@fa-var-stop: "\f04d"; +@fa-var-forward: "\f04e"; +@fa-var-fast-forward: "\f050"; +@fa-var-step-forward: "\f051"; +@fa-var-eject: "\f052"; +@fa-var-chevron-left: "\f053"; +@fa-var-chevron-right: "\f054"; +@fa-var-plus-circle: "\f055"; +@fa-var-minus-circle: "\f056"; +@fa-var-times-circle: "\f057"; +@fa-var-check-circle: "\f058"; +@fa-var-question-circle: "\f059"; +@fa-var-info-circle: "\f05a"; +@fa-var-crosshairs: "\f05b"; +@fa-var-times-circle-o: "\f05c"; +@fa-var-check-circle-o: "\f05d"; +@fa-var-ban: "\f05e"; +@fa-var-arrow-left: "\f060"; +@fa-var-arrow-right: "\f061"; +@fa-var-arrow-up: "\f062"; +@fa-var-arrow-down: "\f063"; +@fa-var-share: "\f064"; +@fa-var-expand: "\f065"; +@fa-var-compress: "\f066"; +@fa-var-plus: "\f067"; +@fa-var-minus: "\f068"; +@fa-var-asterisk: "\f069"; +@fa-var-exclamation-circle: "\f06a"; +@fa-var-gift: "\f06b"; +@fa-var-leaf: "\f06c"; +@fa-var-fire: "\f06d"; +@fa-var-eye: "\f06e"; +@fa-var-eye-slash: "\f070"; +@fa-var-exclamation-triangle: "\f071"; +@fa-var-plane: "\f072"; +@fa-var-calendar: "\f073"; +@fa-var-random: "\f074"; +@fa-var-comment: "\f075"; +@fa-var-magnet: "\f076"; +@fa-var-chevron-up: "\f077"; +@fa-var-chevron-down: "\f078"; +@fa-var-retweet: "\f079"; +@fa-var-shopping-cart: "\f07a"; +@fa-var-folder: "\f07b"; +@fa-var-folder-open: "\f07c"; +@fa-var-arrows-v: "\f07d"; +@fa-var-arrows-h: "\f07e"; +@fa-var-bar-chart-o: "\f080"; +@fa-var-twitter-square: "\f081"; +@fa-var-facebook-square: "\f082"; +@fa-var-camera-retro: "\f083"; +@fa-var-key: "\f084"; +@fa-var-cogs: "\f085"; +@fa-var-comments: "\f086"; +@fa-var-thumbs-o-up: "\f087"; +@fa-var-thumbs-o-down: "\f088"; +@fa-var-star-half: "\f089"; +@fa-var-heart-o: "\f08a"; +@fa-var-sign-out: "\f08b"; +@fa-var-linkedin-square: "\f08c"; +@fa-var-thumb-tack: "\f08d"; +@fa-var-external-link: "\f08e"; +@fa-var-sign-in: "\f090"; +@fa-var-trophy: "\f091"; +@fa-var-github-square: "\f092"; +@fa-var-upload: "\f093"; +@fa-var-lemon-o: "\f094"; +@fa-var-phone: "\f095"; +@fa-var-square-o: "\f096"; +@fa-var-bookmark-o: "\f097"; +@fa-var-phone-square: "\f098"; +@fa-var-twitter: "\f099"; +@fa-var-facebook: "\f09a"; +@fa-var-github: "\f09b"; +@fa-var-unlock: "\f09c"; +@fa-var-credit-card: "\f09d"; +@fa-var-rss: "\f09e"; +@fa-var-hdd-o: "\f0a0"; +@fa-var-bullhorn: "\f0a1"; +@fa-var-bell: "\f0f3"; +@fa-var-certificate: "\f0a3"; +@fa-var-hand-o-right: "\f0a4"; +@fa-var-hand-o-left: "\f0a5"; +@fa-var-hand-o-up: "\f0a6"; +@fa-var-hand-o-down: "\f0a7"; +@fa-var-arrow-circle-left: "\f0a8"; +@fa-var-arrow-circle-right: "\f0a9"; +@fa-var-arrow-circle-up: "\f0aa"; +@fa-var-arrow-circle-down: "\f0ab"; +@fa-var-globe: "\f0ac"; +@fa-var-wrench: "\f0ad"; +@fa-var-tasks: "\f0ae"; +@fa-var-filter: "\f0b0"; +@fa-var-briefcase: "\f0b1"; +@fa-var-arrows-alt: "\f0b2"; +@fa-var-users: "\f0c0"; +@fa-var-link: "\f0c1"; +@fa-var-cloud: "\f0c2"; +@fa-var-flask: "\f0c3"; +@fa-var-scissors: "\f0c4"; +@fa-var-files-o: "\f0c5"; +@fa-var-paperclip: "\f0c6"; +@fa-var-floppy-o: "\f0c7"; +@fa-var-square: "\f0c8"; +@fa-var-bars: "\f0c9"; +@fa-var-list-ul: "\f0ca"; +@fa-var-list-ol: "\f0cb"; +@fa-var-strikethrough: "\f0cc"; +@fa-var-underline: "\f0cd"; +@fa-var-table: "\f0ce"; +@fa-var-magic: "\f0d0"; +@fa-var-truck: "\f0d1"; +@fa-var-pinterest: "\f0d2"; +@fa-var-pinterest-square: "\f0d3"; +@fa-var-google-plus-square: "\f0d4"; +@fa-var-google-plus: "\f0d5"; +@fa-var-money: "\f0d6"; +@fa-var-caret-down: "\f0d7"; +@fa-var-caret-up: "\f0d8"; +@fa-var-caret-left: "\f0d9"; +@fa-var-caret-right: "\f0da"; +@fa-var-columns: "\f0db"; +@fa-var-sort: "\f0dc"; +@fa-var-sort-asc: "\f0dd"; +@fa-var-sort-desc: "\f0de"; +@fa-var-envelope: "\f0e0"; +@fa-var-linkedin: "\f0e1"; +@fa-var-undo: "\f0e2"; +@fa-var-gavel: "\f0e3"; +@fa-var-tachometer: "\f0e4"; +@fa-var-comment-o: "\f0e5"; +@fa-var-comments-o: "\f0e6"; +@fa-var-bolt: "\f0e7"; +@fa-var-sitemap: "\f0e8"; +@fa-var-umbrella: "\f0e9"; +@fa-var-clipboard: "\f0ea"; +@fa-var-lightbulb-o: "\f0eb"; +@fa-var-exchange: "\f0ec"; +@fa-var-cloud-download: "\f0ed"; +@fa-var-cloud-upload: "\f0ee"; +@fa-var-user-md: "\f0f0"; +@fa-var-stethoscope: "\f0f1"; +@fa-var-suitcase: "\f0f2"; +@fa-var-bell-o: "\f0a2"; +@fa-var-coffee: "\f0f4"; +@fa-var-cutlery: "\f0f5"; +@fa-var-file-text-o: "\f0f6"; +@fa-var-building-o: "\f0f7"; +@fa-var-hospital-o: "\f0f8"; +@fa-var-ambulance: "\f0f9"; +@fa-var-medkit: "\f0fa"; +@fa-var-fighter-jet: "\f0fb"; +@fa-var-beer: "\f0fc"; +@fa-var-h-square: "\f0fd"; +@fa-var-plus-square: "\f0fe"; +@fa-var-angle-double-left: "\f100"; +@fa-var-angle-double-right: "\f101"; +@fa-var-angle-double-up: "\f102"; +@fa-var-angle-double-down: "\f103"; +@fa-var-angle-left: "\f104"; +@fa-var-angle-right: "\f105"; +@fa-var-angle-up: "\f106"; +@fa-var-angle-down: "\f107"; +@fa-var-desktop: "\f108"; +@fa-var-laptop: "\f109"; +@fa-var-tablet: "\f10a"; +@fa-var-mobile: "\f10b"; +@fa-var-circle-o: "\f10c"; +@fa-var-quote-left: "\f10d"; +@fa-var-quote-right: "\f10e"; +@fa-var-spinner: "\f110"; +@fa-var-circle: "\f111"; +@fa-var-reply: "\f112"; +@fa-var-github-alt: "\f113"; +@fa-var-folder-o: "\f114"; +@fa-var-folder-open-o: "\f115"; +@fa-var-smile-o: "\f118"; +@fa-var-frown-o: "\f119"; +@fa-var-meh-o: "\f11a"; +@fa-var-gamepad: "\f11b"; +@fa-var-keyboard-o: "\f11c"; +@fa-var-flag-o: "\f11d"; +@fa-var-flag-checkered: "\f11e"; +@fa-var-terminal: "\f120"; +@fa-var-code: "\f121"; +@fa-var-reply-all: "\f122"; +@fa-var-mail-reply-all: "\f122"; +@fa-var-star-half-o: "\f123"; +@fa-var-location-arrow: "\f124"; +@fa-var-crop: "\f125"; +@fa-var-code-fork: "\f126"; +@fa-var-chain-broken: "\f127"; +@fa-var-question: "\f128"; +@fa-var-info: "\f129"; +@fa-var-exclamation: "\f12a"; +@fa-var-superscript: "\f12b"; +@fa-var-subscript: "\f12c"; +@fa-var-eraser: "\f12d"; +@fa-var-puzzle-piece: "\f12e"; +@fa-var-microphone: "\f130"; +@fa-var-microphone-slash: "\f131"; +@fa-var-shield: "\f132"; +@fa-var-calendar-o: "\f133"; +@fa-var-fire-extinguisher: "\f134"; +@fa-var-rocket: "\f135"; +@fa-var-maxcdn: "\f136"; +@fa-var-chevron-circle-left: "\f137"; +@fa-var-chevron-circle-right: "\f138"; +@fa-var-chevron-circle-up: "\f139"; +@fa-var-chevron-circle-down: "\f13a"; +@fa-var-html5: "\f13b"; +@fa-var-css3: "\f13c"; +@fa-var-anchor: "\f13d"; +@fa-var-unlock-alt: "\f13e"; +@fa-var-bullseye: "\f140"; +@fa-var-ellipsis-h: "\f141"; +@fa-var-ellipsis-v: "\f142"; +@fa-var-rss-square: "\f143"; +@fa-var-play-circle: "\f144"; +@fa-var-ticket: "\f145"; +@fa-var-minus-square: "\f146"; +@fa-var-minus-square-o: "\f147"; +@fa-var-level-up: "\f148"; +@fa-var-level-down: "\f149"; +@fa-var-check-square: "\f14a"; +@fa-var-pencil-square: "\f14b"; +@fa-var-external-link-square: "\f14c"; +@fa-var-share-square: "\f14d"; +@fa-var-compass: "\f14e"; +@fa-var-caret-square-o-down: "\f150"; +@fa-var-caret-square-o-up: "\f151"; +@fa-var-caret-square-o-right: "\f152"; +@fa-var-eur: "\f153"; +@fa-var-gbp: "\f154"; +@fa-var-usd: "\f155"; +@fa-var-inr: "\f156"; +@fa-var-jpy: "\f157"; +@fa-var-rub: "\f158"; +@fa-var-krw: "\f159"; +@fa-var-btc: "\f15a"; +@fa-var-file: "\f15b"; +@fa-var-file-text: "\f15c"; +@fa-var-sort-alpha-asc: "\f15d"; +@fa-var-sort-alpha-desc: "\f15e"; +@fa-var-sort-amount-asc: "\f160"; +@fa-var-sort-amount-desc: "\f161"; +@fa-var-sort-numeric-asc: "\f162"; +@fa-var-sort-numeric-desc: "\f163"; +@fa-var-thumbs-up: "\f164"; +@fa-var-thumbs-down: "\f165"; +@fa-var-youtube-square: "\f166"; +@fa-var-youtube: "\f167"; +@fa-var-xing: "\f168"; +@fa-var-xing-square: "\f169"; +@fa-var-youtube-play: "\f16a"; +@fa-var-dropbox: "\f16b"; +@fa-var-stack-overflow: "\f16c"; +@fa-var-instagram: "\f16d"; +@fa-var-flickr: "\f16e"; +@fa-var-adn: "\f170"; +@fa-var-bitbucket: "\f171"; +@fa-var-bitbucket-square: "\f172"; +@fa-var-tumblr: "\f173"; +@fa-var-tumblr-square: "\f174"; +@fa-var-long-arrow-down: "\f175"; +@fa-var-long-arrow-up: "\f176"; +@fa-var-long-arrow-left: "\f177"; +@fa-var-long-arrow-right: "\f178"; +@fa-var-apple: "\f179"; +@fa-var-windows: "\f17a"; +@fa-var-android: "\f17b"; +@fa-var-linux: "\f17c"; +@fa-var-dribbble: "\f17d"; +@fa-var-skype: "\f17e"; +@fa-var-foursquare: "\f180"; +@fa-var-trello: "\f181"; +@fa-var-female: "\f182"; +@fa-var-male: "\f183"; +@fa-var-gittip: "\f184"; +@fa-var-sun-o: "\f185"; +@fa-var-moon-o: "\f186"; +@fa-var-archive: "\f187"; +@fa-var-bug: "\f188"; +@fa-var-vk: "\f189"; +@fa-var-weibo: "\f18a"; +@fa-var-renren: "\f18b"; +@fa-var-pagelines: "\f18c"; +@fa-var-stack-exchange: "\f18d"; +@fa-var-arrow-circle-o-right: "\f18e"; +@fa-var-arrow-circle-o-left: "\f190"; +@fa-var-caret-square-o-left: "\f191"; +@fa-var-dot-circle-o: "\f192"; +@fa-var-wheelchair: "\f193"; +@fa-var-vimeo-square: "\f194"; +@fa-var-try: "\f195"; +@fa-var-plus-square-o: "\f196"; + diff --git a/public/site_assets/bootstrap/font-awesome/scss/_bordered-pulled.scss b/public/site_assets/bootstrap/font-awesome/scss/_bordered-pulled.scss new file mode 100644 index 00000000..9d3fdf3a --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_bordered-pulled.scss @@ -0,0 +1,16 @@ +// Bordered & Pulled +// ------------------------- + +.#{$fa-css-prefix}-border { + padding: .2em .25em .15em; + border: solid .08em $fa-border-color; + border-radius: .1em; +} + +.pull-right { float: right; } +.pull-left { float: left; } + +.#{$fa-css-prefix} { + &.pull-left { margin-right: .3em; } + &.pull-right { margin-left: .3em; } +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_core.scss b/public/site_assets/bootstrap/font-awesome/scss/_core.scss new file mode 100644 index 00000000..861ccd9d --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_core.scss @@ -0,0 +1,12 @@ +// Base Class Definition +// ------------------------- + +.#{$fa-css-prefix} { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_fixed-width.scss b/public/site_assets/bootstrap/font-awesome/scss/_fixed-width.scss new file mode 100644 index 00000000..b221c981 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_fixed-width.scss @@ -0,0 +1,6 @@ +// Fixed Width Icons +// ------------------------- +.#{$fa-css-prefix}-fw { + width: (18em / 14); + text-align: center; +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_icons.scss b/public/site_assets/bootstrap/font-awesome/scss/_icons.scss new file mode 100644 index 00000000..7490cf36 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_icons.scss @@ -0,0 +1,412 @@ +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ + +.#{$fa-css-prefix}-glass:before { content: $fa-var-glass; } +.#{$fa-css-prefix}-music:before { content: $fa-var-music; } +.#{$fa-css-prefix}-search:before { content: $fa-var-search; } +.#{$fa-css-prefix}-envelope-o:before { content: $fa-var-envelope-o; } +.#{$fa-css-prefix}-heart:before { content: $fa-var-heart; } +.#{$fa-css-prefix}-star:before { content: $fa-var-star; } +.#{$fa-css-prefix}-star-o:before { content: $fa-var-star-o; } +.#{$fa-css-prefix}-user:before { content: $fa-var-user; } +.#{$fa-css-prefix}-film:before { content: $fa-var-film; } +.#{$fa-css-prefix}-th-large:before { content: $fa-var-th-large; } +.#{$fa-css-prefix}-th:before { content: $fa-var-th; } +.#{$fa-css-prefix}-th-list:before { content: $fa-var-th-list; } +.#{$fa-css-prefix}-check:before { content: $fa-var-check; } +.#{$fa-css-prefix}-times:before { content: $fa-var-times; } +.#{$fa-css-prefix}-search-plus:before { content: $fa-var-search-plus; } +.#{$fa-css-prefix}-search-minus:before { content: $fa-var-search-minus; } +.#{$fa-css-prefix}-power-off:before { content: $fa-var-power-off; } +.#{$fa-css-prefix}-signal:before { content: $fa-var-signal; } +.#{$fa-css-prefix}-gear:before, +.#{$fa-css-prefix}-cog:before { content: $fa-var-cog; } +.#{$fa-css-prefix}-trash-o:before { content: $fa-var-trash-o; } +.#{$fa-css-prefix}-home:before { content: $fa-var-home; } +.#{$fa-css-prefix}-file-o:before { content: $fa-var-file-o; } +.#{$fa-css-prefix}-clock-o:before { content: $fa-var-clock-o; } +.#{$fa-css-prefix}-road:before { content: $fa-var-road; } +.#{$fa-css-prefix}-download:before { content: $fa-var-download; } +.#{$fa-css-prefix}-arrow-circle-o-down:before { content: $fa-var-arrow-circle-o-down; } +.#{$fa-css-prefix}-arrow-circle-o-up:before { content: $fa-var-arrow-circle-o-up; } +.#{$fa-css-prefix}-inbox:before { content: $fa-var-inbox; } +.#{$fa-css-prefix}-play-circle-o:before { content: $fa-var-play-circle-o; } +.#{$fa-css-prefix}-rotate-right:before, +.#{$fa-css-prefix}-repeat:before { content: $fa-var-repeat; } +.#{$fa-css-prefix}-refresh:before { content: $fa-var-refresh; } +.#{$fa-css-prefix}-list-alt:before { content: $fa-var-list-alt; } +.#{$fa-css-prefix}-lock:before { content: $fa-var-lock; } +.#{$fa-css-prefix}-flag:before { content: $fa-var-flag; } +.#{$fa-css-prefix}-headphones:before { content: $fa-var-headphones; } +.#{$fa-css-prefix}-volume-off:before { content: $fa-var-volume-off; } +.#{$fa-css-prefix}-volume-down:before { content: $fa-var-volume-down; } +.#{$fa-css-prefix}-volume-up:before { content: $fa-var-volume-up; } +.#{$fa-css-prefix}-qrcode:before { content: $fa-var-qrcode; } +.#{$fa-css-prefix}-barcode:before { content: $fa-var-barcode; } +.#{$fa-css-prefix}-tag:before { content: $fa-var-tag; } +.#{$fa-css-prefix}-tags:before { content: $fa-var-tags; } +.#{$fa-css-prefix}-book:before { content: $fa-var-book; } +.#{$fa-css-prefix}-bookmark:before { content: $fa-var-bookmark; } +.#{$fa-css-prefix}-print:before { content: $fa-var-print; } +.#{$fa-css-prefix}-camera:before { content: $fa-var-camera; } +.#{$fa-css-prefix}-font:before { content: $fa-var-font; } +.#{$fa-css-prefix}-bold:before { content: $fa-var-bold; } +.#{$fa-css-prefix}-italic:before { content: $fa-var-italic; } +.#{$fa-css-prefix}-text-height:before { content: $fa-var-text-height; } +.#{$fa-css-prefix}-text-width:before { content: $fa-var-text-width; } +.#{$fa-css-prefix}-align-left:before { content: $fa-var-align-left; } +.#{$fa-css-prefix}-align-center:before { content: $fa-var-align-center; } +.#{$fa-css-prefix}-align-right:before { content: $fa-var-align-right; } +.#{$fa-css-prefix}-align-justify:before { content: $fa-var-align-justify; } +.#{$fa-css-prefix}-list:before { content: $fa-var-list; } +.#{$fa-css-prefix}-dedent:before, +.#{$fa-css-prefix}-outdent:before { content: $fa-var-outdent; } +.#{$fa-css-prefix}-indent:before { content: $fa-var-indent; } +.#{$fa-css-prefix}-video-camera:before { content: $fa-var-video-camera; } +.#{$fa-css-prefix}-picture-o:before { content: $fa-var-picture-o; } +.#{$fa-css-prefix}-pencil:before { content: $fa-var-pencil; } +.#{$fa-css-prefix}-map-marker:before { content: $fa-var-map-marker; } +.#{$fa-css-prefix}-adjust:before { content: $fa-var-adjust; } +.#{$fa-css-prefix}-tint:before { content: $fa-var-tint; } +.#{$fa-css-prefix}-edit:before, +.#{$fa-css-prefix}-pencil-square-o:before { content: $fa-var-pencil-square-o; } +.#{$fa-css-prefix}-share-square-o:before { content: $fa-var-share-square-o; } +.#{$fa-css-prefix}-check-square-o:before { content: $fa-var-check-square-o; } +.#{$fa-css-prefix}-arrows:before { content: $fa-var-arrows; } +.#{$fa-css-prefix}-step-backward:before { content: $fa-var-step-backward; } +.#{$fa-css-prefix}-fast-backward:before { content: $fa-var-fast-backward; } +.#{$fa-css-prefix}-backward:before { content: $fa-var-backward; } +.#{$fa-css-prefix}-play:before { content: $fa-var-play; } +.#{$fa-css-prefix}-pause:before { content: $fa-var-pause; } +.#{$fa-css-prefix}-stop:before { content: $fa-var-stop; } +.#{$fa-css-prefix}-forward:before { content: $fa-var-forward; } +.#{$fa-css-prefix}-fast-forward:before { content: $fa-var-fast-forward; } +.#{$fa-css-prefix}-step-forward:before { content: $fa-var-step-forward; } +.#{$fa-css-prefix}-eject:before { content: $fa-var-eject; } +.#{$fa-css-prefix}-chevron-left:before { content: $fa-var-chevron-left; } +.#{$fa-css-prefix}-chevron-right:before { content: $fa-var-chevron-right; } +.#{$fa-css-prefix}-plus-circle:before { content: $fa-var-plus-circle; } +.#{$fa-css-prefix}-minus-circle:before { content: $fa-var-minus-circle; } +.#{$fa-css-prefix}-times-circle:before { content: $fa-var-times-circle; } +.#{$fa-css-prefix}-check-circle:before { content: $fa-var-check-circle; } +.#{$fa-css-prefix}-question-circle:before { content: $fa-var-question-circle; } +.#{$fa-css-prefix}-info-circle:before { content: $fa-var-info-circle; } +.#{$fa-css-prefix}-crosshairs:before { content: $fa-var-crosshairs; } +.#{$fa-css-prefix}-times-circle-o:before { content: $fa-var-times-circle-o; } +.#{$fa-css-prefix}-check-circle-o:before { content: $fa-var-check-circle-o; } +.#{$fa-css-prefix}-ban:before { content: $fa-var-ban; } +.#{$fa-css-prefix}-arrow-left:before { content: $fa-var-arrow-left; } +.#{$fa-css-prefix}-arrow-right:before { content: $fa-var-arrow-right; } +.#{$fa-css-prefix}-arrow-up:before { content: $fa-var-arrow-up; } +.#{$fa-css-prefix}-arrow-down:before { content: $fa-var-arrow-down; } +.#{$fa-css-prefix}-mail-forward:before, +.#{$fa-css-prefix}-share:before { content: $fa-var-share; } +.#{$fa-css-prefix}-expand:before { content: $fa-var-expand; } +.#{$fa-css-prefix}-compress:before { content: $fa-var-compress; } +.#{$fa-css-prefix}-plus:before { content: $fa-var-plus; } +.#{$fa-css-prefix}-minus:before { content: $fa-var-minus; } +.#{$fa-css-prefix}-asterisk:before { content: $fa-var-asterisk; } +.#{$fa-css-prefix}-exclamation-circle:before { content: $fa-var-exclamation-circle; } +.#{$fa-css-prefix}-gift:before { content: $fa-var-gift; } +.#{$fa-css-prefix}-leaf:before { content: $fa-var-leaf; } +.#{$fa-css-prefix}-fire:before { content: $fa-var-fire; } +.#{$fa-css-prefix}-eye:before { content: $fa-var-eye; } +.#{$fa-css-prefix}-eye-slash:before { content: $fa-var-eye-slash; } +.#{$fa-css-prefix}-warning:before, +.#{$fa-css-prefix}-exclamation-triangle:before { content: $fa-var-exclamation-triangle; } +.#{$fa-css-prefix}-plane:before { content: $fa-var-plane; } +.#{$fa-css-prefix}-calendar:before { content: $fa-var-calendar; } +.#{$fa-css-prefix}-random:before { content: $fa-var-random; } +.#{$fa-css-prefix}-comment:before { content: $fa-var-comment; } +.#{$fa-css-prefix}-magnet:before { content: $fa-var-magnet; } +.#{$fa-css-prefix}-chevron-up:before { content: $fa-var-chevron-up; } +.#{$fa-css-prefix}-chevron-down:before { content: $fa-var-chevron-down; } +.#{$fa-css-prefix}-retweet:before { content: $fa-var-retweet; } +.#{$fa-css-prefix}-shopping-cart:before { content: $fa-var-shopping-cart; } +.#{$fa-css-prefix}-folder:before { content: $fa-var-folder; } +.#{$fa-css-prefix}-folder-open:before { content: $fa-var-folder-open; } +.#{$fa-css-prefix}-arrows-v:before { content: $fa-var-arrows-v; } +.#{$fa-css-prefix}-arrows-h:before { content: $fa-var-arrows-h; } +.#{$fa-css-prefix}-bar-chart-o:before { content: $fa-var-bar-chart-o; } +.#{$fa-css-prefix}-twitter-square:before { content: $fa-var-twitter-square; } +.#{$fa-css-prefix}-facebook-square:before { content: $fa-var-facebook-square; } +.#{$fa-css-prefix}-camera-retro:before { content: $fa-var-camera-retro; } +.#{$fa-css-prefix}-key:before { content: $fa-var-key; } +.#{$fa-css-prefix}-gears:before, +.#{$fa-css-prefix}-cogs:before { content: $fa-var-cogs; } +.#{$fa-css-prefix}-comments:before { content: $fa-var-comments; } +.#{$fa-css-prefix}-thumbs-o-up:before { content: $fa-var-thumbs-o-up; } +.#{$fa-css-prefix}-thumbs-o-down:before { content: $fa-var-thumbs-o-down; } +.#{$fa-css-prefix}-star-half:before { content: $fa-var-star-half; } +.#{$fa-css-prefix}-heart-o:before { content: $fa-var-heart-o; } +.#{$fa-css-prefix}-sign-out:before { content: $fa-var-sign-out; } +.#{$fa-css-prefix}-linkedin-square:before { content: $fa-var-linkedin-square; } +.#{$fa-css-prefix}-thumb-tack:before { content: $fa-var-thumb-tack; } +.#{$fa-css-prefix}-external-link:before { content: $fa-var-external-link; } +.#{$fa-css-prefix}-sign-in:before { content: $fa-var-sign-in; } +.#{$fa-css-prefix}-trophy:before { content: $fa-var-trophy; } +.#{$fa-css-prefix}-github-square:before { content: $fa-var-github-square; } +.#{$fa-css-prefix}-upload:before { content: $fa-var-upload; } +.#{$fa-css-prefix}-lemon-o:before { content: $fa-var-lemon-o; } +.#{$fa-css-prefix}-phone:before { content: $fa-var-phone; } +.#{$fa-css-prefix}-square-o:before { content: $fa-var-square-o; } +.#{$fa-css-prefix}-bookmark-o:before { content: $fa-var-bookmark-o; } +.#{$fa-css-prefix}-phone-square:before { content: $fa-var-phone-square; } +.#{$fa-css-prefix}-twitter:before { content: $fa-var-twitter; } +.#{$fa-css-prefix}-facebook:before { content: $fa-var-facebook; } +.#{$fa-css-prefix}-github:before { content: $fa-var-github; } +.#{$fa-css-prefix}-unlock:before { content: $fa-var-unlock; } +.#{$fa-css-prefix}-credit-card:before { content: $fa-var-credit-card; } +.#{$fa-css-prefix}-rss:before { content: $fa-var-rss; } +.#{$fa-css-prefix}-hdd-o:before { content: $fa-var-hdd-o; } +.#{$fa-css-prefix}-bullhorn:before { content: $fa-var-bullhorn; } +.#{$fa-css-prefix}-bell:before { content: $fa-var-bell; } +.#{$fa-css-prefix}-certificate:before { content: $fa-var-certificate; } +.#{$fa-css-prefix}-hand-o-right:before { content: $fa-var-hand-o-right; } +.#{$fa-css-prefix}-hand-o-left:before { content: $fa-var-hand-o-left; } +.#{$fa-css-prefix}-hand-o-up:before { content: $fa-var-hand-o-up; } +.#{$fa-css-prefix}-hand-o-down:before { content: $fa-var-hand-o-down; } +.#{$fa-css-prefix}-arrow-circle-left:before { content: $fa-var-arrow-circle-left; } +.#{$fa-css-prefix}-arrow-circle-right:before { content: $fa-var-arrow-circle-right; } +.#{$fa-css-prefix}-arrow-circle-up:before { content: $fa-var-arrow-circle-up; } +.#{$fa-css-prefix}-arrow-circle-down:before { content: $fa-var-arrow-circle-down; } +.#{$fa-css-prefix}-globe:before { content: $fa-var-globe; } +.#{$fa-css-prefix}-wrench:before { content: $fa-var-wrench; } +.#{$fa-css-prefix}-tasks:before { content: $fa-var-tasks; } +.#{$fa-css-prefix}-filter:before { content: $fa-var-filter; } +.#{$fa-css-prefix}-briefcase:before { content: $fa-var-briefcase; } +.#{$fa-css-prefix}-arrows-alt:before { content: $fa-var-arrows-alt; } +.#{$fa-css-prefix}-group:before, +.#{$fa-css-prefix}-users:before { content: $fa-var-users; } +.#{$fa-css-prefix}-chain:before, +.#{$fa-css-prefix}-link:before { content: $fa-var-link; } +.#{$fa-css-prefix}-cloud:before { content: $fa-var-cloud; } +.#{$fa-css-prefix}-flask:before { content: $fa-var-flask; } +.#{$fa-css-prefix}-cut:before, +.#{$fa-css-prefix}-scissors:before { content: $fa-var-scissors; } +.#{$fa-css-prefix}-copy:before, +.#{$fa-css-prefix}-files-o:before { content: $fa-var-files-o; } +.#{$fa-css-prefix}-paperclip:before { content: $fa-var-paperclip; } +.#{$fa-css-prefix}-save:before, +.#{$fa-css-prefix}-floppy-o:before { content: $fa-var-floppy-o; } +.#{$fa-css-prefix}-square:before { content: $fa-var-square; } +.#{$fa-css-prefix}-bars:before { content: $fa-var-bars; } +.#{$fa-css-prefix}-list-ul:before { content: $fa-var-list-ul; } +.#{$fa-css-prefix}-list-ol:before { content: $fa-var-list-ol; } +.#{$fa-css-prefix}-strikethrough:before { content: $fa-var-strikethrough; } +.#{$fa-css-prefix}-underline:before { content: $fa-var-underline; } +.#{$fa-css-prefix}-table:before { content: $fa-var-table; } +.#{$fa-css-prefix}-magic:before { content: $fa-var-magic; } +.#{$fa-css-prefix}-truck:before { content: $fa-var-truck; } +.#{$fa-css-prefix}-pinterest:before { content: $fa-var-pinterest; } +.#{$fa-css-prefix}-pinterest-square:before { content: $fa-var-pinterest-square; } +.#{$fa-css-prefix}-google-plus-square:before { content: $fa-var-google-plus-square; } +.#{$fa-css-prefix}-google-plus:before { content: $fa-var-google-plus; } +.#{$fa-css-prefix}-money:before { content: $fa-var-money; } +.#{$fa-css-prefix}-caret-down:before { content: $fa-var-caret-down; } +.#{$fa-css-prefix}-caret-up:before { content: $fa-var-caret-up; } +.#{$fa-css-prefix}-caret-left:before { content: $fa-var-caret-left; } +.#{$fa-css-prefix}-caret-right:before { content: $fa-var-caret-right; } +.#{$fa-css-prefix}-columns:before { content: $fa-var-columns; } +.#{$fa-css-prefix}-unsorted:before, +.#{$fa-css-prefix}-sort:before { content: $fa-var-sort; } +.#{$fa-css-prefix}-sort-down:before, +.#{$fa-css-prefix}-sort-asc:before { content: $fa-var-sort-asc; } +.#{$fa-css-prefix}-sort-up:before, +.#{$fa-css-prefix}-sort-desc:before { content: $fa-var-sort-desc; } +.#{$fa-css-prefix}-envelope:before { content: $fa-var-envelope; } +.#{$fa-css-prefix}-linkedin:before { content: $fa-var-linkedin; } +.#{$fa-css-prefix}-rotate-left:before, +.#{$fa-css-prefix}-undo:before { content: $fa-var-undo; } +.#{$fa-css-prefix}-legal:before, +.#{$fa-css-prefix}-gavel:before { content: $fa-var-gavel; } +.#{$fa-css-prefix}-dashboard:before, +.#{$fa-css-prefix}-tachometer:before { content: $fa-var-tachometer; } +.#{$fa-css-prefix}-comment-o:before { content: $fa-var-comment-o; } +.#{$fa-css-prefix}-comments-o:before { content: $fa-var-comments-o; } +.#{$fa-css-prefix}-flash:before, +.#{$fa-css-prefix}-bolt:before { content: $fa-var-bolt; } +.#{$fa-css-prefix}-sitemap:before { content: $fa-var-sitemap; } +.#{$fa-css-prefix}-umbrella:before { content: $fa-var-umbrella; } +.#{$fa-css-prefix}-paste:before, +.#{$fa-css-prefix}-clipboard:before { content: $fa-var-clipboard; } +.#{$fa-css-prefix}-lightbulb-o:before { content: $fa-var-lightbulb-o; } +.#{$fa-css-prefix}-exchange:before { content: $fa-var-exchange; } +.#{$fa-css-prefix}-cloud-download:before { content: $fa-var-cloud-download; } +.#{$fa-css-prefix}-cloud-upload:before { content: $fa-var-cloud-upload; } +.#{$fa-css-prefix}-user-md:before { content: $fa-var-user-md; } +.#{$fa-css-prefix}-stethoscope:before { content: $fa-var-stethoscope; } +.#{$fa-css-prefix}-suitcase:before { content: $fa-var-suitcase; } +.#{$fa-css-prefix}-bell-o:before { content: $fa-var-bell-o; } +.#{$fa-css-prefix}-coffee:before { content: $fa-var-coffee; } +.#{$fa-css-prefix}-cutlery:before { content: $fa-var-cutlery; } +.#{$fa-css-prefix}-file-text-o:before { content: $fa-var-file-text-o; } +.#{$fa-css-prefix}-building-o:before { content: $fa-var-building-o; } +.#{$fa-css-prefix}-hospital-o:before { content: $fa-var-hospital-o; } +.#{$fa-css-prefix}-ambulance:before { content: $fa-var-ambulance; } +.#{$fa-css-prefix}-medkit:before { content: $fa-var-medkit; } +.#{$fa-css-prefix}-fighter-jet:before { content: $fa-var-fighter-jet; } +.#{$fa-css-prefix}-beer:before { content: $fa-var-beer; } +.#{$fa-css-prefix}-h-square:before { content: $fa-var-h-square; } +.#{$fa-css-prefix}-plus-square:before { content: $fa-var-plus-square; } +.#{$fa-css-prefix}-angle-double-left:before { content: $fa-var-angle-double-left; } +.#{$fa-css-prefix}-angle-double-right:before { content: $fa-var-angle-double-right; } +.#{$fa-css-prefix}-angle-double-up:before { content: $fa-var-angle-double-up; } +.#{$fa-css-prefix}-angle-double-down:before { content: $fa-var-angle-double-down; } +.#{$fa-css-prefix}-angle-left:before { content: $fa-var-angle-left; } +.#{$fa-css-prefix}-angle-right:before { content: $fa-var-angle-right; } +.#{$fa-css-prefix}-angle-up:before { content: $fa-var-angle-up; } +.#{$fa-css-prefix}-angle-down:before { content: $fa-var-angle-down; } +.#{$fa-css-prefix}-desktop:before { content: $fa-var-desktop; } +.#{$fa-css-prefix}-laptop:before { content: $fa-var-laptop; } +.#{$fa-css-prefix}-tablet:before { content: $fa-var-tablet; } +.#{$fa-css-prefix}-mobile-phone:before, +.#{$fa-css-prefix}-mobile:before { content: $fa-var-mobile; } +.#{$fa-css-prefix}-circle-o:before { content: $fa-var-circle-o; } +.#{$fa-css-prefix}-quote-left:before { content: $fa-var-quote-left; } +.#{$fa-css-prefix}-quote-right:before { content: $fa-var-quote-right; } +.#{$fa-css-prefix}-spinner:before { content: $fa-var-spinner; } +.#{$fa-css-prefix}-circle:before { content: $fa-var-circle; } +.#{$fa-css-prefix}-mail-reply:before, +.#{$fa-css-prefix}-reply:before { content: $fa-var-reply; } +.#{$fa-css-prefix}-github-alt:before { content: $fa-var-github-alt; } +.#{$fa-css-prefix}-folder-o:before { content: $fa-var-folder-o; } +.#{$fa-css-prefix}-folder-open-o:before { content: $fa-var-folder-open-o; } +.#{$fa-css-prefix}-smile-o:before { content: $fa-var-smile-o; } +.#{$fa-css-prefix}-frown-o:before { content: $fa-var-frown-o; } +.#{$fa-css-prefix}-meh-o:before { content: $fa-var-meh-o; } +.#{$fa-css-prefix}-gamepad:before { content: $fa-var-gamepad; } +.#{$fa-css-prefix}-keyboard-o:before { content: $fa-var-keyboard-o; } +.#{$fa-css-prefix}-flag-o:before { content: $fa-var-flag-o; } +.#{$fa-css-prefix}-flag-checkered:before { content: $fa-var-flag-checkered; } +.#{$fa-css-prefix}-terminal:before { content: $fa-var-terminal; } +.#{$fa-css-prefix}-code:before { content: $fa-var-code; } +.#{$fa-css-prefix}-reply-all:before { content: $fa-var-reply-all; } +.#{$fa-css-prefix}-mail-reply-all:before { content: $fa-var-mail-reply-all; } +.#{$fa-css-prefix}-star-half-empty:before, +.#{$fa-css-prefix}-star-half-full:before, +.#{$fa-css-prefix}-star-half-o:before { content: $fa-var-star-half-o; } +.#{$fa-css-prefix}-location-arrow:before { content: $fa-var-location-arrow; } +.#{$fa-css-prefix}-crop:before { content: $fa-var-crop; } +.#{$fa-css-prefix}-code-fork:before { content: $fa-var-code-fork; } +.#{$fa-css-prefix}-unlink:before, +.#{$fa-css-prefix}-chain-broken:before { content: $fa-var-chain-broken; } +.#{$fa-css-prefix}-question:before { content: $fa-var-question; } +.#{$fa-css-prefix}-info:before { content: $fa-var-info; } +.#{$fa-css-prefix}-exclamation:before { content: $fa-var-exclamation; } +.#{$fa-css-prefix}-superscript:before { content: $fa-var-superscript; } +.#{$fa-css-prefix}-subscript:before { content: $fa-var-subscript; } +.#{$fa-css-prefix}-eraser:before { content: $fa-var-eraser; } +.#{$fa-css-prefix}-puzzle-piece:before { content: $fa-var-puzzle-piece; } +.#{$fa-css-prefix}-microphone:before { content: $fa-var-microphone; } +.#{$fa-css-prefix}-microphone-slash:before { content: $fa-var-microphone-slash; } +.#{$fa-css-prefix}-shield:before { content: $fa-var-shield; } +.#{$fa-css-prefix}-calendar-o:before { content: $fa-var-calendar-o; } +.#{$fa-css-prefix}-fire-extinguisher:before { content: $fa-var-fire-extinguisher; } +.#{$fa-css-prefix}-rocket:before { content: $fa-var-rocket; } +.#{$fa-css-prefix}-maxcdn:before { content: $fa-var-maxcdn; } +.#{$fa-css-prefix}-chevron-circle-left:before { content: $fa-var-chevron-circle-left; } +.#{$fa-css-prefix}-chevron-circle-right:before { content: $fa-var-chevron-circle-right; } +.#{$fa-css-prefix}-chevron-circle-up:before { content: $fa-var-chevron-circle-up; } +.#{$fa-css-prefix}-chevron-circle-down:before { content: $fa-var-chevron-circle-down; } +.#{$fa-css-prefix}-html5:before { content: $fa-var-html5; } +.#{$fa-css-prefix}-css3:before { content: $fa-var-css3; } +.#{$fa-css-prefix}-anchor:before { content: $fa-var-anchor; } +.#{$fa-css-prefix}-unlock-alt:before { content: $fa-var-unlock-alt; } +.#{$fa-css-prefix}-bullseye:before { content: $fa-var-bullseye; } +.#{$fa-css-prefix}-ellipsis-h:before { content: $fa-var-ellipsis-h; } +.#{$fa-css-prefix}-ellipsis-v:before { content: $fa-var-ellipsis-v; } +.#{$fa-css-prefix}-rss-square:before { content: $fa-var-rss-square; } +.#{$fa-css-prefix}-play-circle:before { content: $fa-var-play-circle; } +.#{$fa-css-prefix}-ticket:before { content: $fa-var-ticket; } +.#{$fa-css-prefix}-minus-square:before { content: $fa-var-minus-square; } +.#{$fa-css-prefix}-minus-square-o:before { content: $fa-var-minus-square-o; } +.#{$fa-css-prefix}-level-up:before { content: $fa-var-level-up; } +.#{$fa-css-prefix}-level-down:before { content: $fa-var-level-down; } +.#{$fa-css-prefix}-check-square:before { content: $fa-var-check-square; } +.#{$fa-css-prefix}-pencil-square:before { content: $fa-var-pencil-square; } +.#{$fa-css-prefix}-external-link-square:before { content: $fa-var-external-link-square; } +.#{$fa-css-prefix}-share-square:before { content: $fa-var-share-square; } +.#{$fa-css-prefix}-compass:before { content: $fa-var-compass; } +.#{$fa-css-prefix}-toggle-down:before, +.#{$fa-css-prefix}-caret-square-o-down:before { content: $fa-var-caret-square-o-down; } +.#{$fa-css-prefix}-toggle-up:before, +.#{$fa-css-prefix}-caret-square-o-up:before { content: $fa-var-caret-square-o-up; } +.#{$fa-css-prefix}-toggle-right:before, +.#{$fa-css-prefix}-caret-square-o-right:before { content: $fa-var-caret-square-o-right; } +.#{$fa-css-prefix}-euro:before, +.#{$fa-css-prefix}-eur:before { content: $fa-var-eur; } +.#{$fa-css-prefix}-gbp:before { content: $fa-var-gbp; } +.#{$fa-css-prefix}-dollar:before, +.#{$fa-css-prefix}-usd:before { content: $fa-var-usd; } +.#{$fa-css-prefix}-rupee:before, +.#{$fa-css-prefix}-inr:before { content: $fa-var-inr; } +.#{$fa-css-prefix}-cny:before, +.#{$fa-css-prefix}-rmb:before, +.#{$fa-css-prefix}-yen:before, +.#{$fa-css-prefix}-jpy:before { content: $fa-var-jpy; } +.#{$fa-css-prefix}-ruble:before, +.#{$fa-css-prefix}-rouble:before, +.#{$fa-css-prefix}-rub:before { content: $fa-var-rub; } +.#{$fa-css-prefix}-won:before, +.#{$fa-css-prefix}-krw:before { content: $fa-var-krw; } +.#{$fa-css-prefix}-bitcoin:before, +.#{$fa-css-prefix}-btc:before { content: $fa-var-btc; } +.#{$fa-css-prefix}-file:before { content: $fa-var-file; } +.#{$fa-css-prefix}-file-text:before { content: $fa-var-file-text; } +.#{$fa-css-prefix}-sort-alpha-asc:before { content: $fa-var-sort-alpha-asc; } +.#{$fa-css-prefix}-sort-alpha-desc:before { content: $fa-var-sort-alpha-desc; } +.#{$fa-css-prefix}-sort-amount-asc:before { content: $fa-var-sort-amount-asc; } +.#{$fa-css-prefix}-sort-amount-desc:before { content: $fa-var-sort-amount-desc; } +.#{$fa-css-prefix}-sort-numeric-asc:before { content: $fa-var-sort-numeric-asc; } +.#{$fa-css-prefix}-sort-numeric-desc:before { content: $fa-var-sort-numeric-desc; } +.#{$fa-css-prefix}-thumbs-up:before { content: $fa-var-thumbs-up; } +.#{$fa-css-prefix}-thumbs-down:before { content: $fa-var-thumbs-down; } +.#{$fa-css-prefix}-youtube-square:before { content: $fa-var-youtube-square; } +.#{$fa-css-prefix}-youtube:before { content: $fa-var-youtube; } +.#{$fa-css-prefix}-xing:before { content: $fa-var-xing; } +.#{$fa-css-prefix}-xing-square:before { content: $fa-var-xing-square; } +.#{$fa-css-prefix}-youtube-play:before { content: $fa-var-youtube-play; } +.#{$fa-css-prefix}-dropbox:before { content: $fa-var-dropbox; } +.#{$fa-css-prefix}-stack-overflow:before { content: $fa-var-stack-overflow; } +.#{$fa-css-prefix}-instagram:before { content: $fa-var-instagram; } +.#{$fa-css-prefix}-flickr:before { content: $fa-var-flickr; } +.#{$fa-css-prefix}-adn:before { content: $fa-var-adn; } +.#{$fa-css-prefix}-bitbucket:before { content: $fa-var-bitbucket; } +.#{$fa-css-prefix}-bitbucket-square:before { content: $fa-var-bitbucket-square; } +.#{$fa-css-prefix}-tumblr:before { content: $fa-var-tumblr; } +.#{$fa-css-prefix}-tumblr-square:before { content: $fa-var-tumblr-square; } +.#{$fa-css-prefix}-long-arrow-down:before { content: $fa-var-long-arrow-down; } +.#{$fa-css-prefix}-long-arrow-up:before { content: $fa-var-long-arrow-up; } +.#{$fa-css-prefix}-long-arrow-left:before { content: $fa-var-long-arrow-left; } +.#{$fa-css-prefix}-long-arrow-right:before { content: $fa-var-long-arrow-right; } +.#{$fa-css-prefix}-apple:before { content: $fa-var-apple; } +.#{$fa-css-prefix}-windows:before { content: $fa-var-windows; } +.#{$fa-css-prefix}-android:before { content: $fa-var-android; } +.#{$fa-css-prefix}-linux:before { content: $fa-var-linux; } +.#{$fa-css-prefix}-dribbble:before { content: $fa-var-dribbble; } +.#{$fa-css-prefix}-skype:before { content: $fa-var-skype; } +.#{$fa-css-prefix}-foursquare:before { content: $fa-var-foursquare; } +.#{$fa-css-prefix}-trello:before { content: $fa-var-trello; } +.#{$fa-css-prefix}-female:before { content: $fa-var-female; } +.#{$fa-css-prefix}-male:before { content: $fa-var-male; } +.#{$fa-css-prefix}-gittip:before { content: $fa-var-gittip; } +.#{$fa-css-prefix}-sun-o:before { content: $fa-var-sun-o; } +.#{$fa-css-prefix}-moon-o:before { content: $fa-var-moon-o; } +.#{$fa-css-prefix}-archive:before { content: $fa-var-archive; } +.#{$fa-css-prefix}-bug:before { content: $fa-var-bug; } +.#{$fa-css-prefix}-vk:before { content: $fa-var-vk; } +.#{$fa-css-prefix}-weibo:before { content: $fa-var-weibo; } +.#{$fa-css-prefix}-renren:before { content: $fa-var-renren; } +.#{$fa-css-prefix}-pagelines:before { content: $fa-var-pagelines; } +.#{$fa-css-prefix}-stack-exchange:before { content: $fa-var-stack-exchange; } +.#{$fa-css-prefix}-arrow-circle-o-right:before { content: $fa-var-arrow-circle-o-right; } +.#{$fa-css-prefix}-arrow-circle-o-left:before { content: $fa-var-arrow-circle-o-left; } +.#{$fa-css-prefix}-toggle-left:before, +.#{$fa-css-prefix}-caret-square-o-left:before { content: $fa-var-caret-square-o-left; } +.#{$fa-css-prefix}-dot-circle-o:before { content: $fa-var-dot-circle-o; } +.#{$fa-css-prefix}-wheelchair:before { content: $fa-var-wheelchair; } +.#{$fa-css-prefix}-vimeo-square:before { content: $fa-var-vimeo-square; } +.#{$fa-css-prefix}-turkish-lira:before, +.#{$fa-css-prefix}-try:before { content: $fa-var-try; } +.#{$fa-css-prefix}-plus-square-o:before { content: $fa-var-plus-square-o; } diff --git a/public/site_assets/bootstrap/font-awesome/scss/_larger.scss b/public/site_assets/bootstrap/font-awesome/scss/_larger.scss new file mode 100644 index 00000000..41e9a818 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_larger.scss @@ -0,0 +1,13 @@ +// Icon Sizes +// ------------------------- + +/* makes the font 33% larger relative to the icon container */ +.#{$fa-css-prefix}-lg { + font-size: (4em / 3); + line-height: (3em / 4); + vertical-align: -15%; +} +.#{$fa-css-prefix}-2x { font-size: 2em; } +.#{$fa-css-prefix}-3x { font-size: 3em; } +.#{$fa-css-prefix}-4x { font-size: 4em; } +.#{$fa-css-prefix}-5x { font-size: 5em; } diff --git a/public/site_assets/bootstrap/font-awesome/scss/_list.scss b/public/site_assets/bootstrap/font-awesome/scss/_list.scss new file mode 100644 index 00000000..7d1e4d54 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_list.scss @@ -0,0 +1,19 @@ +// List Icons +// ------------------------- + +.#{$fa-css-prefix}-ul { + padding-left: 0; + margin-left: $fa-li-width; + list-style-type: none; + > li { position: relative; } +} +.#{$fa-css-prefix}-li { + position: absolute; + left: -$fa-li-width; + width: $fa-li-width; + top: (2em / 14); + text-align: center; + &.#{$fa-css-prefix}-lg { + left: -$fa-li-width + (4em / 14); + } +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_mixins.scss b/public/site_assets/bootstrap/font-awesome/scss/_mixins.scss new file mode 100644 index 00000000..9f555963 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_mixins.scss @@ -0,0 +1,20 @@ +// Mixins +// -------------------------- + +@mixin fa-icon-rotate($degrees, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation); + -webkit-transform: rotate($degrees); + -moz-transform: rotate($degrees); + -ms-transform: rotate($degrees); + -o-transform: rotate($degrees); + transform: rotate($degrees); +} + +@mixin fa-icon-flip($horiz, $vert, $rotation) { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=$rotation); + -webkit-transform: scale($horiz, $vert); + -moz-transform: scale($horiz, $vert); + -ms-transform: scale($horiz, $vert); + -o-transform: scale($horiz, $vert); + transform: scale($horiz, $vert); +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_path.scss b/public/site_assets/bootstrap/font-awesome/scss/_path.scss new file mode 100644 index 00000000..fd21c351 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_path.scss @@ -0,0 +1,14 @@ +/* FONT PATH + * -------------------------- */ + +@font-face { + font-family: 'FontAwesome'; + src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); + src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), + url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), + url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), + url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); + //src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts + font-weight: normal; + font-style: normal; +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_rotated-flipped.scss b/public/site_assets/bootstrap/font-awesome/scss/_rotated-flipped.scss new file mode 100644 index 00000000..343fa550 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_rotated-flipped.scss @@ -0,0 +1,9 @@ +// Rotated & Flipped Icons +// ------------------------- + +.#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } +.#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } +.#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } + +.#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } +.#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } diff --git a/public/site_assets/bootstrap/font-awesome/scss/_spinning.scss b/public/site_assets/bootstrap/font-awesome/scss/_spinning.scss new file mode 100644 index 00000000..ba1e4f16 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_spinning.scss @@ -0,0 +1,30 @@ +// Spinning Icons +// -------------------------- + +.#{$fa-css-prefix}-spin { + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} +@-ms-keyframes spin { + 0% { -ms-transform: rotate(0deg); } + 100% { -ms-transform: rotate(359deg); } +} +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(359deg); } +} diff --git a/public/site_assets/bootstrap/font-awesome/scss/_stacked.scss b/public/site_assets/bootstrap/font-awesome/scss/_stacked.scss new file mode 100644 index 00000000..aef74036 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_stacked.scss @@ -0,0 +1,20 @@ +// Stacked Icons +// ------------------------- + +.#{$fa-css-prefix}-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.#{$fa-css-prefix}-stack-1x { line-height: inherit; } +.#{$fa-css-prefix}-stack-2x { font-size: 2em; } +.#{$fa-css-prefix}-inverse { color: $fa-inverse; } diff --git a/public/site_assets/bootstrap/font-awesome/scss/_variables.scss b/public/site_assets/bootstrap/font-awesome/scss/_variables.scss new file mode 100644 index 00000000..2d6e076a --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/_variables.scss @@ -0,0 +1,381 @@ +// Variables +// -------------------------- + +$fa-font-path: "../fonts" !default; +//$fa-font-path: "//netdna.bootstrapcdn.com/font-awesome/4.0.3/fonts" !default; // for referencing Bootstrap CDN font files directly +$fa-css-prefix: fa !default; +$fa-version: "4.0.3" !default; +$fa-border-color: #eee !default; +$fa-inverse: #fff !default; +$fa-li-width: (30em / 14) !default; + +$fa-var-glass: "\f000"; +$fa-var-music: "\f001"; +$fa-var-search: "\f002"; +$fa-var-envelope-o: "\f003"; +$fa-var-heart: "\f004"; +$fa-var-star: "\f005"; +$fa-var-star-o: "\f006"; +$fa-var-user: "\f007"; +$fa-var-film: "\f008"; +$fa-var-th-large: "\f009"; +$fa-var-th: "\f00a"; +$fa-var-th-list: "\f00b"; +$fa-var-check: "\f00c"; +$fa-var-times: "\f00d"; +$fa-var-search-plus: "\f00e"; +$fa-var-search-minus: "\f010"; +$fa-var-power-off: "\f011"; +$fa-var-signal: "\f012"; +$fa-var-cog: "\f013"; +$fa-var-trash-o: "\f014"; +$fa-var-home: "\f015"; +$fa-var-file-o: "\f016"; +$fa-var-clock-o: "\f017"; +$fa-var-road: "\f018"; +$fa-var-download: "\f019"; +$fa-var-arrow-circle-o-down: "\f01a"; +$fa-var-arrow-circle-o-up: "\f01b"; +$fa-var-inbox: "\f01c"; +$fa-var-play-circle-o: "\f01d"; +$fa-var-repeat: "\f01e"; +$fa-var-refresh: "\f021"; +$fa-var-list-alt: "\f022"; +$fa-var-lock: "\f023"; +$fa-var-flag: "\f024"; +$fa-var-headphones: "\f025"; +$fa-var-volume-off: "\f026"; +$fa-var-volume-down: "\f027"; +$fa-var-volume-up: "\f028"; +$fa-var-qrcode: "\f029"; +$fa-var-barcode: "\f02a"; +$fa-var-tag: "\f02b"; +$fa-var-tags: "\f02c"; +$fa-var-book: "\f02d"; +$fa-var-bookmark: "\f02e"; +$fa-var-print: "\f02f"; +$fa-var-camera: "\f030"; +$fa-var-font: "\f031"; +$fa-var-bold: "\f032"; +$fa-var-italic: "\f033"; +$fa-var-text-height: "\f034"; +$fa-var-text-width: "\f035"; +$fa-var-align-left: "\f036"; +$fa-var-align-center: "\f037"; +$fa-var-align-right: "\f038"; +$fa-var-align-justify: "\f039"; +$fa-var-list: "\f03a"; +$fa-var-outdent: "\f03b"; +$fa-var-indent: "\f03c"; +$fa-var-video-camera: "\f03d"; +$fa-var-picture-o: "\f03e"; +$fa-var-pencil: "\f040"; +$fa-var-map-marker: "\f041"; +$fa-var-adjust: "\f042"; +$fa-var-tint: "\f043"; +$fa-var-pencil-square-o: "\f044"; +$fa-var-share-square-o: "\f045"; +$fa-var-check-square-o: "\f046"; +$fa-var-arrows: "\f047"; +$fa-var-step-backward: "\f048"; +$fa-var-fast-backward: "\f049"; +$fa-var-backward: "\f04a"; +$fa-var-play: "\f04b"; +$fa-var-pause: "\f04c"; +$fa-var-stop: "\f04d"; +$fa-var-forward: "\f04e"; +$fa-var-fast-forward: "\f050"; +$fa-var-step-forward: "\f051"; +$fa-var-eject: "\f052"; +$fa-var-chevron-left: "\f053"; +$fa-var-chevron-right: "\f054"; +$fa-var-plus-circle: "\f055"; +$fa-var-minus-circle: "\f056"; +$fa-var-times-circle: "\f057"; +$fa-var-check-circle: "\f058"; +$fa-var-question-circle: "\f059"; +$fa-var-info-circle: "\f05a"; +$fa-var-crosshairs: "\f05b"; +$fa-var-times-circle-o: "\f05c"; +$fa-var-check-circle-o: "\f05d"; +$fa-var-ban: "\f05e"; +$fa-var-arrow-left: "\f060"; +$fa-var-arrow-right: "\f061"; +$fa-var-arrow-up: "\f062"; +$fa-var-arrow-down: "\f063"; +$fa-var-share: "\f064"; +$fa-var-expand: "\f065"; +$fa-var-compress: "\f066"; +$fa-var-plus: "\f067"; +$fa-var-minus: "\f068"; +$fa-var-asterisk: "\f069"; +$fa-var-exclamation-circle: "\f06a"; +$fa-var-gift: "\f06b"; +$fa-var-leaf: "\f06c"; +$fa-var-fire: "\f06d"; +$fa-var-eye: "\f06e"; +$fa-var-eye-slash: "\f070"; +$fa-var-exclamation-triangle: "\f071"; +$fa-var-plane: "\f072"; +$fa-var-calendar: "\f073"; +$fa-var-random: "\f074"; +$fa-var-comment: "\f075"; +$fa-var-magnet: "\f076"; +$fa-var-chevron-up: "\f077"; +$fa-var-chevron-down: "\f078"; +$fa-var-retweet: "\f079"; +$fa-var-shopping-cart: "\f07a"; +$fa-var-folder: "\f07b"; +$fa-var-folder-open: "\f07c"; +$fa-var-arrows-v: "\f07d"; +$fa-var-arrows-h: "\f07e"; +$fa-var-bar-chart-o: "\f080"; +$fa-var-twitter-square: "\f081"; +$fa-var-facebook-square: "\f082"; +$fa-var-camera-retro: "\f083"; +$fa-var-key: "\f084"; +$fa-var-cogs: "\f085"; +$fa-var-comments: "\f086"; +$fa-var-thumbs-o-up: "\f087"; +$fa-var-thumbs-o-down: "\f088"; +$fa-var-star-half: "\f089"; +$fa-var-heart-o: "\f08a"; +$fa-var-sign-out: "\f08b"; +$fa-var-linkedin-square: "\f08c"; +$fa-var-thumb-tack: "\f08d"; +$fa-var-external-link: "\f08e"; +$fa-var-sign-in: "\f090"; +$fa-var-trophy: "\f091"; +$fa-var-github-square: "\f092"; +$fa-var-upload: "\f093"; +$fa-var-lemon-o: "\f094"; +$fa-var-phone: "\f095"; +$fa-var-square-o: "\f096"; +$fa-var-bookmark-o: "\f097"; +$fa-var-phone-square: "\f098"; +$fa-var-twitter: "\f099"; +$fa-var-facebook: "\f09a"; +$fa-var-github: "\f09b"; +$fa-var-unlock: "\f09c"; +$fa-var-credit-card: "\f09d"; +$fa-var-rss: "\f09e"; +$fa-var-hdd-o: "\f0a0"; +$fa-var-bullhorn: "\f0a1"; +$fa-var-bell: "\f0f3"; +$fa-var-certificate: "\f0a3"; +$fa-var-hand-o-right: "\f0a4"; +$fa-var-hand-o-left: "\f0a5"; +$fa-var-hand-o-up: "\f0a6"; +$fa-var-hand-o-down: "\f0a7"; +$fa-var-arrow-circle-left: "\f0a8"; +$fa-var-arrow-circle-right: "\f0a9"; +$fa-var-arrow-circle-up: "\f0aa"; +$fa-var-arrow-circle-down: "\f0ab"; +$fa-var-globe: "\f0ac"; +$fa-var-wrench: "\f0ad"; +$fa-var-tasks: "\f0ae"; +$fa-var-filter: "\f0b0"; +$fa-var-briefcase: "\f0b1"; +$fa-var-arrows-alt: "\f0b2"; +$fa-var-users: "\f0c0"; +$fa-var-link: "\f0c1"; +$fa-var-cloud: "\f0c2"; +$fa-var-flask: "\f0c3"; +$fa-var-scissors: "\f0c4"; +$fa-var-files-o: "\f0c5"; +$fa-var-paperclip: "\f0c6"; +$fa-var-floppy-o: "\f0c7"; +$fa-var-square: "\f0c8"; +$fa-var-bars: "\f0c9"; +$fa-var-list-ul: "\f0ca"; +$fa-var-list-ol: "\f0cb"; +$fa-var-strikethrough: "\f0cc"; +$fa-var-underline: "\f0cd"; +$fa-var-table: "\f0ce"; +$fa-var-magic: "\f0d0"; +$fa-var-truck: "\f0d1"; +$fa-var-pinterest: "\f0d2"; +$fa-var-pinterest-square: "\f0d3"; +$fa-var-google-plus-square: "\f0d4"; +$fa-var-google-plus: "\f0d5"; +$fa-var-money: "\f0d6"; +$fa-var-caret-down: "\f0d7"; +$fa-var-caret-up: "\f0d8"; +$fa-var-caret-left: "\f0d9"; +$fa-var-caret-right: "\f0da"; +$fa-var-columns: "\f0db"; +$fa-var-sort: "\f0dc"; +$fa-var-sort-asc: "\f0dd"; +$fa-var-sort-desc: "\f0de"; +$fa-var-envelope: "\f0e0"; +$fa-var-linkedin: "\f0e1"; +$fa-var-undo: "\f0e2"; +$fa-var-gavel: "\f0e3"; +$fa-var-tachometer: "\f0e4"; +$fa-var-comment-o: "\f0e5"; +$fa-var-comments-o: "\f0e6"; +$fa-var-bolt: "\f0e7"; +$fa-var-sitemap: "\f0e8"; +$fa-var-umbrella: "\f0e9"; +$fa-var-clipboard: "\f0ea"; +$fa-var-lightbulb-o: "\f0eb"; +$fa-var-exchange: "\f0ec"; +$fa-var-cloud-download: "\f0ed"; +$fa-var-cloud-upload: "\f0ee"; +$fa-var-user-md: "\f0f0"; +$fa-var-stethoscope: "\f0f1"; +$fa-var-suitcase: "\f0f2"; +$fa-var-bell-o: "\f0a2"; +$fa-var-coffee: "\f0f4"; +$fa-var-cutlery: "\f0f5"; +$fa-var-file-text-o: "\f0f6"; +$fa-var-building-o: "\f0f7"; +$fa-var-hospital-o: "\f0f8"; +$fa-var-ambulance: "\f0f9"; +$fa-var-medkit: "\f0fa"; +$fa-var-fighter-jet: "\f0fb"; +$fa-var-beer: "\f0fc"; +$fa-var-h-square: "\f0fd"; +$fa-var-plus-square: "\f0fe"; +$fa-var-angle-double-left: "\f100"; +$fa-var-angle-double-right: "\f101"; +$fa-var-angle-double-up: "\f102"; +$fa-var-angle-double-down: "\f103"; +$fa-var-angle-left: "\f104"; +$fa-var-angle-right: "\f105"; +$fa-var-angle-up: "\f106"; +$fa-var-angle-down: "\f107"; +$fa-var-desktop: "\f108"; +$fa-var-laptop: "\f109"; +$fa-var-tablet: "\f10a"; +$fa-var-mobile: "\f10b"; +$fa-var-circle-o: "\f10c"; +$fa-var-quote-left: "\f10d"; +$fa-var-quote-right: "\f10e"; +$fa-var-spinner: "\f110"; +$fa-var-circle: "\f111"; +$fa-var-reply: "\f112"; +$fa-var-github-alt: "\f113"; +$fa-var-folder-o: "\f114"; +$fa-var-folder-open-o: "\f115"; +$fa-var-smile-o: "\f118"; +$fa-var-frown-o: "\f119"; +$fa-var-meh-o: "\f11a"; +$fa-var-gamepad: "\f11b"; +$fa-var-keyboard-o: "\f11c"; +$fa-var-flag-o: "\f11d"; +$fa-var-flag-checkered: "\f11e"; +$fa-var-terminal: "\f120"; +$fa-var-code: "\f121"; +$fa-var-reply-all: "\f122"; +$fa-var-mail-reply-all: "\f122"; +$fa-var-star-half-o: "\f123"; +$fa-var-location-arrow: "\f124"; +$fa-var-crop: "\f125"; +$fa-var-code-fork: "\f126"; +$fa-var-chain-broken: "\f127"; +$fa-var-question: "\f128"; +$fa-var-info: "\f129"; +$fa-var-exclamation: "\f12a"; +$fa-var-superscript: "\f12b"; +$fa-var-subscript: "\f12c"; +$fa-var-eraser: "\f12d"; +$fa-var-puzzle-piece: "\f12e"; +$fa-var-microphone: "\f130"; +$fa-var-microphone-slash: "\f131"; +$fa-var-shield: "\f132"; +$fa-var-calendar-o: "\f133"; +$fa-var-fire-extinguisher: "\f134"; +$fa-var-rocket: "\f135"; +$fa-var-maxcdn: "\f136"; +$fa-var-chevron-circle-left: "\f137"; +$fa-var-chevron-circle-right: "\f138"; +$fa-var-chevron-circle-up: "\f139"; +$fa-var-chevron-circle-down: "\f13a"; +$fa-var-html5: "\f13b"; +$fa-var-css3: "\f13c"; +$fa-var-anchor: "\f13d"; +$fa-var-unlock-alt: "\f13e"; +$fa-var-bullseye: "\f140"; +$fa-var-ellipsis-h: "\f141"; +$fa-var-ellipsis-v: "\f142"; +$fa-var-rss-square: "\f143"; +$fa-var-play-circle: "\f144"; +$fa-var-ticket: "\f145"; +$fa-var-minus-square: "\f146"; +$fa-var-minus-square-o: "\f147"; +$fa-var-level-up: "\f148"; +$fa-var-level-down: "\f149"; +$fa-var-check-square: "\f14a"; +$fa-var-pencil-square: "\f14b"; +$fa-var-external-link-square: "\f14c"; +$fa-var-share-square: "\f14d"; +$fa-var-compass: "\f14e"; +$fa-var-caret-square-o-down: "\f150"; +$fa-var-caret-square-o-up: "\f151"; +$fa-var-caret-square-o-right: "\f152"; +$fa-var-eur: "\f153"; +$fa-var-gbp: "\f154"; +$fa-var-usd: "\f155"; +$fa-var-inr: "\f156"; +$fa-var-jpy: "\f157"; +$fa-var-rub: "\f158"; +$fa-var-krw: "\f159"; +$fa-var-btc: "\f15a"; +$fa-var-file: "\f15b"; +$fa-var-file-text: "\f15c"; +$fa-var-sort-alpha-asc: "\f15d"; +$fa-var-sort-alpha-desc: "\f15e"; +$fa-var-sort-amount-asc: "\f160"; +$fa-var-sort-amount-desc: "\f161"; +$fa-var-sort-numeric-asc: "\f162"; +$fa-var-sort-numeric-desc: "\f163"; +$fa-var-thumbs-up: "\f164"; +$fa-var-thumbs-down: "\f165"; +$fa-var-youtube-square: "\f166"; +$fa-var-youtube: "\f167"; +$fa-var-xing: "\f168"; +$fa-var-xing-square: "\f169"; +$fa-var-youtube-play: "\f16a"; +$fa-var-dropbox: "\f16b"; +$fa-var-stack-overflow: "\f16c"; +$fa-var-instagram: "\f16d"; +$fa-var-flickr: "\f16e"; +$fa-var-adn: "\f170"; +$fa-var-bitbucket: "\f171"; +$fa-var-bitbucket-square: "\f172"; +$fa-var-tumblr: "\f173"; +$fa-var-tumblr-square: "\f174"; +$fa-var-long-arrow-down: "\f175"; +$fa-var-long-arrow-up: "\f176"; +$fa-var-long-arrow-left: "\f177"; +$fa-var-long-arrow-right: "\f178"; +$fa-var-apple: "\f179"; +$fa-var-windows: "\f17a"; +$fa-var-android: "\f17b"; +$fa-var-linux: "\f17c"; +$fa-var-dribbble: "\f17d"; +$fa-var-skype: "\f17e"; +$fa-var-foursquare: "\f180"; +$fa-var-trello: "\f181"; +$fa-var-female: "\f182"; +$fa-var-male: "\f183"; +$fa-var-gittip: "\f184"; +$fa-var-sun-o: "\f185"; +$fa-var-moon-o: "\f186"; +$fa-var-archive: "\f187"; +$fa-var-bug: "\f188"; +$fa-var-vk: "\f189"; +$fa-var-weibo: "\f18a"; +$fa-var-renren: "\f18b"; +$fa-var-pagelines: "\f18c"; +$fa-var-stack-exchange: "\f18d"; +$fa-var-arrow-circle-o-right: "\f18e"; +$fa-var-arrow-circle-o-left: "\f190"; +$fa-var-caret-square-o-left: "\f191"; +$fa-var-dot-circle-o: "\f192"; +$fa-var-wheelchair: "\f193"; +$fa-var-vimeo-square: "\f194"; +$fa-var-try: "\f195"; +$fa-var-plus-square-o: "\f196"; + diff --git a/public/site_assets/bootstrap/font-awesome/scss/font-awesome.scss b/public/site_assets/bootstrap/font-awesome/scss/font-awesome.scss new file mode 100644 index 00000000..96d2f222 --- /dev/null +++ b/public/site_assets/bootstrap/font-awesome/scss/font-awesome.scss @@ -0,0 +1,17 @@ +/*! + * Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ + +@import "variables"; +@import "mixins"; +@import "path"; +@import "core"; +@import "larger"; +@import "fixed-width"; +@import "list"; +@import "bordered-pulled"; +@import "spinning"; +@import "rotated-flipped"; +@import "stacked"; +@import "icons"; diff --git a/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.eot b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.eot new file mode 100644 index 00000000..423bd5d3 Binary files /dev/null and b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.eot differ diff --git a/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.svg b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.svg new file mode 100644 index 00000000..44694887 --- /dev/null +++ b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.ttf b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.ttf new file mode 100644 index 00000000..a498ef4e Binary files /dev/null and b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.ttf differ diff --git a/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.woff b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.woff new file mode 100644 index 00000000..d83c539b Binary files /dev/null and b/public/site_assets/bootstrap/fonts/glyphicons-halflings-regular.woff differ diff --git a/public/site_assets/mpos/images/breadcrumb_divider.png b/public/site_assets/bootstrap/images/breadcrumb_divider.png similarity index 100% rename from public/site_assets/mpos/images/breadcrumb_divider.png rename to public/site_assets/bootstrap/images/breadcrumb_divider.png diff --git a/public/site_assets/mpos/images/btn_submit.png b/public/site_assets/bootstrap/images/btn_submit.png similarity index 100% rename from public/site_assets/mpos/images/btn_submit.png rename to public/site_assets/bootstrap/images/btn_submit.png diff --git a/public/site_assets/mpos/images/btn_submit_2.png b/public/site_assets/bootstrap/images/btn_submit_2.png similarity index 100% rename from public/site_assets/mpos/images/btn_submit_2.png rename to public/site_assets/bootstrap/images/btn_submit_2.png diff --git a/public/site_assets/mpos/images/btn_view_site.png b/public/site_assets/bootstrap/images/btn_view_site.png similarity index 100% rename from public/site_assets/mpos/images/btn_view_site.png rename to public/site_assets/bootstrap/images/btn_view_site.png diff --git a/public/site_assets/mpos/images/chartbg-vanilla.png b/public/site_assets/bootstrap/images/chartbg-vanilla.png similarity index 100% rename from public/site_assets/mpos/images/chartbg-vanilla.png rename to public/site_assets/bootstrap/images/chartbg-vanilla.png diff --git a/public/site_assets/mpos/images/chartbg.png b/public/site_assets/bootstrap/images/chartbg.png similarity index 100% rename from public/site_assets/mpos/images/chartbg.png rename to public/site_assets/bootstrap/images/chartbg.png diff --git a/public/site_assets/mpos/images/close.png b/public/site_assets/bootstrap/images/close.png similarity index 100% rename from public/site_assets/mpos/images/close.png rename to public/site_assets/bootstrap/images/close.png diff --git a/public/site_assets/mpos/images/header_bg.png b/public/site_assets/bootstrap/images/header_bg.png similarity index 100% rename from public/site_assets/mpos/images/header_bg.png rename to public/site_assets/bootstrap/images/header_bg.png diff --git a/public/site_assets/mpos/images/header_shadow.png b/public/site_assets/bootstrap/images/header_shadow.png similarity index 100% rename from public/site_assets/mpos/images/header_shadow.png rename to public/site_assets/bootstrap/images/header_shadow.png diff --git a/public/site_assets/mpos/images/icn_alert_error.png b/public/site_assets/bootstrap/images/icn_alert_error.png similarity index 100% rename from public/site_assets/mpos/images/icn_alert_error.png rename to public/site_assets/bootstrap/images/icn_alert_error.png diff --git a/public/site_assets/mpos/images/icn_alert_info.png b/public/site_assets/bootstrap/images/icn_alert_info.png similarity index 100% rename from public/site_assets/mpos/images/icn_alert_info.png rename to public/site_assets/bootstrap/images/icn_alert_info.png diff --git a/public/site_assets/mpos/images/icn_alert_success.png b/public/site_assets/bootstrap/images/icn_alert_success.png similarity index 100% rename from public/site_assets/mpos/images/icn_alert_success.png rename to public/site_assets/bootstrap/images/icn_alert_success.png diff --git a/public/site_assets/mpos/images/icn_alert_warning.png b/public/site_assets/bootstrap/images/icn_alert_warning.png similarity index 100% rename from public/site_assets/mpos/images/icn_alert_warning.png rename to public/site_assets/bootstrap/images/icn_alert_warning.png diff --git a/public/site_assets/mpos/images/module_footer_bg.png b/public/site_assets/bootstrap/images/module_footer_bg.png similarity index 100% rename from public/site_assets/mpos/images/module_footer_bg.png rename to public/site_assets/bootstrap/images/module_footer_bg.png diff --git a/public/site_assets/mpos/images/post_message.png b/public/site_assets/bootstrap/images/post_message.png similarity index 100% rename from public/site_assets/mpos/images/post_message.png rename to public/site_assets/bootstrap/images/post_message.png diff --git a/public/site_assets/mobile/images/questionmark.png b/public/site_assets/bootstrap/images/questionmark.png similarity index 100% rename from public/site_assets/mobile/images/questionmark.png rename to public/site_assets/bootstrap/images/questionmark.png diff --git a/public/site_assets/mpos/images/secondary_bar.png b/public/site_assets/bootstrap/images/secondary_bar.png similarity index 100% rename from public/site_assets/mpos/images/secondary_bar.png rename to public/site_assets/bootstrap/images/secondary_bar.png diff --git a/public/site_assets/mpos/images/secondary_bar_shadow.png b/public/site_assets/bootstrap/images/secondary_bar_shadow.png similarity index 100% rename from public/site_assets/mpos/images/secondary_bar_shadow.png rename to public/site_assets/bootstrap/images/secondary_bar_shadow.png diff --git a/public/site_assets/mpos/images/sidebar.png b/public/site_assets/bootstrap/images/sidebar.png similarity index 100% rename from public/site_assets/mpos/images/sidebar.png rename to public/site_assets/bootstrap/images/sidebar.png diff --git a/public/site_assets/mpos/images/sidebar_divider.png b/public/site_assets/bootstrap/images/sidebar_divider.png similarity index 100% rename from public/site_assets/mpos/images/sidebar_divider.png rename to public/site_assets/bootstrap/images/sidebar_divider.png diff --git a/public/site_assets/mpos/images/sidebar_shadow.png b/public/site_assets/bootstrap/images/sidebar_shadow.png similarity index 100% rename from public/site_assets/mpos/images/sidebar_shadow.png rename to public/site_assets/bootstrap/images/sidebar_shadow.png diff --git a/public/site_assets/bootstrap/images/sort_asc.png b/public/site_assets/bootstrap/images/sort_asc.png new file mode 100644 index 00000000..a56d0e21 Binary files /dev/null and b/public/site_assets/bootstrap/images/sort_asc.png differ diff --git a/public/site_assets/bootstrap/images/sort_asc_disabled.png b/public/site_assets/bootstrap/images/sort_asc_disabled.png new file mode 100644 index 00000000..b7e621ef Binary files /dev/null and b/public/site_assets/bootstrap/images/sort_asc_disabled.png differ diff --git a/public/site_assets/bootstrap/images/sort_both.png b/public/site_assets/bootstrap/images/sort_both.png new file mode 100644 index 00000000..839ac4bb Binary files /dev/null and b/public/site_assets/bootstrap/images/sort_both.png differ diff --git a/public/site_assets/bootstrap/images/sort_desc.png b/public/site_assets/bootstrap/images/sort_desc.png new file mode 100644 index 00000000..90b29515 Binary files /dev/null and b/public/site_assets/bootstrap/images/sort_desc.png differ diff --git a/public/site_assets/bootstrap/images/sort_desc_disabled.png b/public/site_assets/bootstrap/images/sort_desc_disabled.png new file mode 100644 index 00000000..2409653d Binary files /dev/null and b/public/site_assets/bootstrap/images/sort_desc_disabled.png differ diff --git a/public/site_assets/mpos/images/table_sorter_header.png b/public/site_assets/bootstrap/images/table_sorter_header.png similarity index 100% rename from public/site_assets/mpos/images/table_sorter_header.png rename to public/site_assets/bootstrap/images/table_sorter_header.png diff --git a/public/site_assets/bootstrap/js/bootstrap-switch.min.js b/public/site_assets/bootstrap/js/bootstrap-switch.min.js new file mode 100644 index 00000000..1db601b2 --- /dev/null +++ b/public/site_assets/bootstrap/js/bootstrap-switch.min.js @@ -0,0 +1,22 @@ +/* ======================================================================== + * bootstrap-switch - v3.0.0 + * http://www.bootstrap-switch.org + * ======================================================================== + * Copyright 2012-2013 Mattia Larentis + * + * ======================================================================== + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ======================================================================== + */ + +(function(){var t=[].slice;!function(e,o){"use strict";var n;return n=function(){function t(t,o){null==o&&(o={}),this.$element=e(t),this.options=e.extend({},e.fn.bootstrapSwitch.defaults,o,{state:this.$element.is(":checked"),size:this.$element.data("size"),animate:this.$element.data("animate"),disabled:this.$element.is(":disabled"),readonly:this.$element.is("[readonly]"),onColor:this.$element.data("on-color"),offColor:this.$element.data("off-color"),onText:this.$element.data("on-text"),offText:this.$element.data("off-text"),labelText:this.$element.data("label-text")}),this.$on=e("",{"class":""+this.name+"-handle-on "+this.name+"-"+this.options.onColor,html:this.options.onText}),this.$off=e("",{"class":""+this.name+"-handle-off "+this.name+"-"+this.options.offColor,html:this.options.offText}),this.$label=e("