diff --git a/CyberCP/secMiddleware.py b/CyberCP/secMiddleware.py index fb2cc0729..7dde0f042 100644 --- a/CyberCP/secMiddleware.py +++ b/CyberCP/secMiddleware.py @@ -127,8 +127,38 @@ class secMiddleware: logging.writeToFile(f'Value being scanned {str(value)}') # Skip validation for ports key to allow port ranges with colons - if key == 'ports': + # but only for CSF modifyPorts endpoint + if key == 'ports' and pathActual == '/firewall/modifyPorts': + # Validate that ports only contain numbers, commas, and colons + if type(value) == str: + import re + # Allow only: digits, commas, colons, and whitespace + if re.match(r'^[\d,:,\s]+$', value): + continue + else: + logging.writeToFile(f"Invalid port format in CSF configuration: {value}") + final_dic = { + 'error_message': "Invalid port format. Only numbers, commas, and colons are allowed for port ranges.", + "errorMessage": "Invalid port format. Only numbers, commas, and colons are allowed for port ranges."} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) continue + elif key == 'ports': + # For other endpoints, ports key continues to skip validation + continue + + # Allow protocol parameter for CSF modifyPorts endpoint + if key == 'protocol' and pathActual == '/firewall/modifyPorts': + # Validate protocol values + if value in ['TCP_IN', 'TCP_OUT', 'UDP_IN', 'UDP_OUT']: + continue + else: + logging.writeToFile(f"Invalid protocol in CSF configuration: {value}") + final_dic = { + 'error_message': "Invalid protocol. Only TCP_IN, TCP_OUT, UDP_IN, UDP_OUT are allowed.", + "errorMessage": "Invalid protocol. Only TCP_IN, TCP_OUT, UDP_IN, UDP_OUT are allowed."} + final_json = json.dumps(final_dic) + return HttpResponse(final_json) if type(value) == str or type(value) == bytes: pass @@ -137,14 +167,14 @@ class secMiddleware: if os.path.exists(ProcessUtilities.debugPath): logging.writeToFile(f'Item type detected as list') for items in value: - if items.find('- -') > -1 or items.find('\n') > -1 or items.find(';') > -1 or items.find( + if isinstance(items, str) and (items.find('- -') > -1 or items.find('\n') > -1 or items.find(';') > -1 or items.find( '&&') > -1 or items.find('|') > -1 or items.find('...') > -1 \ or items.find("`") > -1 or items.find("$") > -1 or items.find( "(") > -1 or items.find(")") > -1 \ or items.find("'") > -1 or items.find("[") > -1 or items.find( "]") > -1 or items.find("{") > -1 or items.find("}") > -1 \ or items.find(":") > -1 or items.find("<") > -1 or items.find( - ">") > -1 or items.find("&") > -1: + ">") > -1 or items.find("&") > -1): logging.writeToFile(request.body) final_dic = { 'error_message': "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >.", @@ -168,11 +198,11 @@ class secMiddleware: pathActual.find('saveSpamAssassinConfigurations') > -1 or pathActual.find('docker') > -1 or pathActual.find('cloudAPI') > -1 or pathActual.find('verifyLogin') > -1 or pathActual.find('submitUserCreation') > -1 or - pathActual.find('/api/') > -1) + pathActual.find('/api/') > -1 or pathActual.find('aiscanner/scheduled-scans') > -1) if isAPIEndpoint: # For API endpoints, still check for the most dangerous command injection characters - if (value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or + if isinstance(value, (str, bytes)) and (value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or value.find('&&') > -1 or value.find('||') > -1 or value.find('|') > -1 or value.find('...') > -1 or value.find("`") > -1 or value.find("$") > -1 or value.find('../') > -1 or value.find('../../') > -1): @@ -190,29 +220,33 @@ class secMiddleware: or key == 'imageByPass' or key == 'passwordByPass' or key == 'PasswordByPass' or key == 'cronCommand' \ or key == 'emailMessage' or key == 'configData' or key == 'rewriteRules' \ or key == 'modSecRules' or key == 'recordContentTXT' or key == 'SecAuditLogRelevantStatus' \ - or key == 'fileContent' or key == 'commands' or key == 'gitHost' or key == 'ipv6' or key == 'contentNow': + or key == 'fileContent' or key == 'commands' or key == 'gitHost' or key == 'ipv6' or key == 'contentNow' \ + or key == 'time_of_day' or key == 'notification_emails' or key == 'domains': continue - if valueAlreadyChecked == 0: - if value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or value.find( + # Skip validation for API endpoints that need JSON structure characters + if not isAPIEndpoint and valueAlreadyChecked == 0: + # Only check string values, skip lists and other types + if (type(value) == str or type(value) == bytes) and (value.find('- -') > -1 or value.find('\n') > -1 or value.find(';') > -1 or value.find( '&&') > -1 or value.find('|') > -1 or value.find('...') > -1 \ or value.find("`") > -1 or value.find("$") > -1 or value.find("(") > -1 or value.find( ")") > -1 \ or value.find("'") > -1 or value.find("[") > -1 or value.find("]") > -1 or value.find( "{") > -1 or value.find("}") > -1 \ or value.find(":") > -1 or value.find("<") > -1 or value.find(">") > -1 or value.find( - "&") > -1: + "&") > -1): logging.writeToFile(request.body) final_dic = { 'error_message': "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >.", "errorMessage": "Data supplied is not accepted, following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >."} final_json = json.dumps(final_dic) return HttpResponse(final_json) - if key.find(';') > -1 or key.find('&&') > -1 or key.find('|') > -1 or key.find('...') > -1 \ + # Skip key validation for API endpoints that need JSON structure characters + if not isAPIEndpoint and (key.find(';') > -1 or key.find('&&') > -1 or key.find('|') > -1 or key.find('...') > -1 \ or key.find("`") > -1 or key.find("$") > -1 or key.find("(") > -1 or key.find(")") > -1 \ or key.find("'") > -1 or key.find("[") > -1 or key.find("]") > -1 or key.find( "{") > -1 or key.find("}") > -1 \ - or key.find(":") > -1 or key.find("<") > -1 or key.find(">") > -1 or key.find("&") > -1: + or key.find(":") > -1 or key.find("<") > -1 or key.find(">") > -1 or key.find("&") > -1): logging.writeToFile(request.body) final_dic = {'error_message': "Data supplied is not accepted.", "errorMessage": "Data supplied is not accepted following characters are not allowed in the input ` $ & ( ) [ ] { } ; : ‘ < >."} diff --git a/IncBackups/IncScheduler.py b/IncBackups/IncScheduler.py index 80c587150..4c4619b94 100644 --- a/IncBackups/IncScheduler.py +++ b/IncBackups/IncScheduler.py @@ -9,7 +9,7 @@ def main(): parser.add_argument('function', help='Specific a function to call!') args = parser.parse_args() - command = f"/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py '{args.function}'" % () + command = f"/usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/IncScheduler.py '{args.function}'" ProcessUtilities.normalExecutioner(command) diff --git a/aiScanner/aiScannerManager.py b/aiScanner/aiScannerManager.py index 4867ff836..3e32c1017 100644 --- a/aiScanner/aiScannerManager.py +++ b/aiScanner/aiScannerManager.py @@ -81,7 +81,7 @@ class AIScannerManager: # Get user's websites for scan selection using ACL-aware method try: websites = ACLManager.findWebsiteObjects(currentACL, userID) - self.logger.writeToFile(f'[AIScannerManager.scannerHome] Found {websites.count()} websites for {admin.userName}') + self.logger.writeToFile(f'[AIScannerManager.scannerHome] Found {len(websites)} websites for {admin.userName}') except Exception as e: self.logger.writeToFile(f'[AIScannerManager.scannerHome] Error fetching websites: {str(e)}') websites = [] diff --git a/aiScanner/management/__init__.py b/aiScanner/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aiScanner/management/commands/__init__.py b/aiScanner/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/aiScanner/management/commands/run_scheduled_scans.py b/aiScanner/management/commands/run_scheduled_scans.py new file mode 100644 index 000000000..14036a638 --- /dev/null +++ b/aiScanner/management/commands/run_scheduled_scans.py @@ -0,0 +1,453 @@ +from django.core.management.base import BaseCommand +from django.utils import timezone +from datetime import datetime, timedelta +import json +import time + + +class Command(BaseCommand): + help = 'Run scheduled AI security scans' + + def add_arguments(self, parser): + parser.add_argument( + '--daemon', + action='store_true', + help='Run as daemon, checking for scheduled scans every minute', + ) + parser.add_argument( + '--scan-id', + type=int, + help='Run a specific scheduled scan by ID', + ) + parser.add_argument( + '--verbose', + action='store_true', + help='Show detailed information about all scheduled scans', + ) + parser.add_argument( + '--force', + action='store_true', + help='Force run all active scheduled scans immediately, ignoring schedule', + ) + + def handle(self, *args, **options): + self.verbose = options.get('verbose', False) + self.force = options.get('force', False) + + if options['daemon']: + self.stdout.write('Starting scheduled scan daemon...') + self.run_daemon() + elif options['scan_id']: + self.stdout.write(f'Running scheduled scan ID {options["scan_id"]}...') + self.run_scheduled_scan_by_id(options['scan_id']) + elif options['force']: + self.stdout.write('Force running all active scheduled scans...') + self.force_run_all_scans() + else: + self.stdout.write('Checking for scheduled scans to run...') + self.check_and_run_scans() + + def run_daemon(self): + """Run as daemon, checking for scans every minute""" + while True: + try: + self.stdout.write(f'\n[{timezone.now().strftime("%Y-%m-%d %H:%M:%S UTC")}] Checking for scheduled scans...') + self.check_and_run_scans() + time.sleep(60) # Check every minute + except KeyboardInterrupt: + self.stdout.write('\nDaemon stopped by user') + break + except Exception as e: + self.stderr.write(f'Error in daemon: {str(e)}') + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan Daemon] Error: {str(e)}') + time.sleep(60) # Continue after error + + def force_run_all_scans(self): + """Force run all active scheduled scans immediately""" + from aiScanner.models import ScheduledScan + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + + # Find all active scheduled scans + active_scans = ScheduledScan.objects.filter(status='active') + + if active_scans.count() == 0: + self.stdout.write('No active scheduled scans found') + logging.writeToFile('[Scheduled Scan Force] No active scheduled scans found') + return + + self.stdout.write(f'Found {active_scans.count()} active scheduled scans to force run') + logging.writeToFile(f'[Scheduled Scan Force] Found {active_scans.count()} active scheduled scans to force run') + + for scan in active_scans: + self.stdout.write(f'Force running scheduled scan: {scan.name} (ID: {scan.id})') + logging.writeToFile(f'[Scheduled Scan Force] Force running scheduled scan: {scan.name} (ID: {scan.id})') + self.execute_scheduled_scan(scan) + + def check_and_run_scans(self): + """Check for scheduled scans that need to run""" + from aiScanner.models import ScheduledScan + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + + now = timezone.now() + + # Log all scheduled scans and their status + all_scans = ScheduledScan.objects.all() + self.stdout.write(f'Total scheduled scans: {all_scans.count()}') + logging.writeToFile(f'[Scheduled Scan Check] Total scheduled scans: {all_scans.count()}') + + for scan in all_scans: + if self.verbose: + self.stdout.write(f'\n--- Scan Details: {scan.name} (ID: {scan.id}) ---') + self.stdout.write(f' Owner: {scan.admin.userName}') + self.stdout.write(f' Frequency: {scan.frequency}') + self.stdout.write(f' Scan Type: {scan.scan_type}') + self.stdout.write(f' Status: {scan.status}') + self.stdout.write(f' Domains: {", ".join(scan.domain_list)}') + self.stdout.write(f' Created: {scan.created_at.strftime("%Y-%m-%d %H:%M:%S UTC")}') + if scan.last_run: + self.stdout.write(f' Last Run: {scan.last_run.strftime("%Y-%m-%d %H:%M:%S UTC")}') + else: + self.stdout.write(f' Last Run: Never') + + if scan.status != 'active': + reason = f'Scan "{scan.name}" (ID: {scan.id}) is not active (status: {scan.status})' + self.stdout.write(f' ❌ {reason}') + logging.writeToFile(f'[Scheduled Scan Check] {reason}') + continue + + if scan.next_run is None: + reason = f'Scan "{scan.name}" (ID: {scan.id}) has no next_run scheduled' + self.stdout.write(f' ❌ {reason}') + logging.writeToFile(f'[Scheduled Scan Check] {reason}') + # Try to calculate next run + if self.verbose: + self.stdout.write(f' 🔧 Attempting to calculate next run time...') + try: + scan.next_run = scan.calculate_next_run() + scan.save() + self.stdout.write(f' ✅ Next run set to: {scan.next_run.strftime("%Y-%m-%d %H:%M:%S UTC")}') + except Exception as e: + self.stdout.write(f' ❌ Failed to calculate next run: {str(e)}') + continue + + if scan.next_run > now: + time_until_run = scan.next_run - now + days = int(time_until_run.total_seconds() // 86400) + hours = int((time_until_run.total_seconds() % 86400) // 3600) + minutes = int((time_until_run.total_seconds() % 3600) // 60) + + time_str = "" + if days > 0: + time_str = f"{days}d {hours}h {minutes}m" + else: + time_str = f"{hours}h {minutes}m" + + reason = f'Scan "{scan.name}" (ID: {scan.id}) scheduled to run in {time_str} at {scan.next_run.strftime("%Y-%m-%d %H:%M:%S UTC")}' + self.stdout.write(f' ⏰ {reason}') + logging.writeToFile(f'[Scheduled Scan Check] {reason}') + continue + + # Find scans that are due to run + due_scans = ScheduledScan.objects.filter( + status='active', + next_run__lte=now + ) + + if due_scans.count() == 0: + self.stdout.write('No scheduled scans are due to run at this time') + logging.writeToFile('[Scheduled Scan Check] No scheduled scans are due to run at this time') + else: + self.stdout.write(f'Found {due_scans.count()} scans due to run') + logging.writeToFile(f'[Scheduled Scan Check] Found {due_scans.count()} scans due to run') + + for scan in due_scans: + self.stdout.write(f'Running scheduled scan: {scan.name} (ID: {scan.id})') + logging.writeToFile(f'[Scheduled Scan Check] Running scheduled scan: {scan.name} (ID: {scan.id})') + self.execute_scheduled_scan(scan) + + def run_scheduled_scan_by_id(self, scan_id): + """Run a specific scheduled scan by ID""" + from aiScanner.models import ScheduledScan + + try: + scan = ScheduledScan.objects.get(id=scan_id) + self.stdout.write(f'Running scheduled scan: {scan.name}') + self.execute_scheduled_scan(scan) + except ScheduledScan.DoesNotExist: + self.stderr.write(f'Scheduled scan with ID {scan_id} not found') + + def execute_scheduled_scan(self, scheduled_scan): + """Execute a scheduled scan""" + from aiScanner.models import ScheduledScanExecution, ScanHistory + from aiScanner.aiScannerManager import AIScannerManager + from loginSystem.models import Administrator + from websiteFunctions.models import Websites + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + + # Create execution record + execution = ScheduledScanExecution.objects.create( + scheduled_scan=scheduled_scan, + status='running', + started_at=timezone.now() + ) + + try: + # Update last run time + scheduled_scan.last_run = timezone.now() + scheduled_scan.next_run = scheduled_scan.calculate_next_run() + scheduled_scan.save() + + # Get domains to scan + domains_to_scan = [] + admin = scheduled_scan.admin + + # Validate domains still exist and user has access + for domain in scheduled_scan.domain_list: + try: + website = Websites.objects.get(domain=domain, admin=admin) + domains_to_scan.append(domain) + except Websites.DoesNotExist: + logging.writeToFile(f'[Scheduled Scan] Domain {domain} no longer accessible for user {admin.userName}') + continue + + if not domains_to_scan: + execution.status = 'failed' + execution.error_message = 'No accessible domains found for scanning' + execution.completed_at = timezone.now() + execution.save() + self.stderr.write(f'No accessible domains for scheduled scan {scheduled_scan.name}') + return + + execution.set_scanned_domains(domains_to_scan) + execution.total_scans = len(domains_to_scan) + execution.save() + + # Initialize scanner manager + sm = AIScannerManager() + scan_ids = [] + successful_scans = 0 + failed_scans = 0 + total_cost = 0.0 + + # Execute scans for each domain + for domain in domains_to_scan: + try: + self.stdout.write(f'Starting scan for domain: {domain}') + + # Create a fake request object for the scanner manager + class FakeRequest: + def __init__(self, admin_id, domain, scan_type): + self.session = {'userID': admin_id} + self.method = 'POST' + self.POST = { + 'domain': domain, + 'scan_type': scan_type + } + # Create JSON body that startScan expects + import json + self.body = json.dumps({ + 'domain': domain, + 'scan_type': scan_type + }).encode('utf-8') + + def get_host(self): + # Get the hostname from CyberPanel settings + try: + from plogical.acl import ACLManager + server_ip = ACLManager.fetchIP() + return f"{server_ip}:8090" # Default CyberPanel port + except: + return "localhost:8090" # Fallback + + fake_request = FakeRequest(admin.pk, domain, scheduled_scan.scan_type) + + # Start the scan + result = sm.startScan(fake_request, admin.pk) + + if hasattr(result, 'content'): + # It's an HTTP response, parse the JSON + import json + response_data = json.loads(result.content.decode('utf-8')) + else: + # It's already a dict + response_data = result + + if response_data.get('success'): + scan_id = response_data.get('scan_id') + if scan_id: + scan_ids.append(scan_id) + successful_scans += 1 + + # Get cost estimate if available + if 'cost_estimate' in response_data: + total_cost += float(response_data['cost_estimate']) + + logging.writeToFile(f'[Scheduled Scan] Successfully started scan {scan_id} for {domain}') + else: + failed_scans += 1 + logging.writeToFile(f'[Scheduled Scan] Failed to get scan ID for {domain}') + else: + failed_scans += 1 + error_msg = response_data.get('error', 'Unknown error') + logging.writeToFile(f'[Scheduled Scan] Failed to start scan for {domain}: {error_msg}') + + except Exception as e: + failed_scans += 1 + error_msg = str(e) + logging.writeToFile(f'[Scheduled Scan] Exception starting scan for {domain}: {error_msg}') + + # Small delay between scans to avoid overwhelming the system + time.sleep(2) + + # Update execution record + execution.successful_scans = successful_scans + execution.failed_scans = failed_scans + execution.total_cost = total_cost + execution.set_scan_ids(scan_ids) + execution.status = 'completed' if failed_scans == 0 else 'completed' # Always completed if we tried all + execution.completed_at = timezone.now() + execution.save() + + # Send notifications if configured + if scheduled_scan.email_notifications: + self.send_notifications(scheduled_scan, execution) + + self.stdout.write( + f'Scheduled scan completed: {successful_scans} successful, {failed_scans} failed' + ) + + except Exception as e: + # Update execution record with error + execution.status = 'failed' + execution.error_message = str(e) + execution.completed_at = timezone.now() + execution.save() + + logging.writeToFile(f'[Scheduled Scan] Failed to execute scheduled scan {scheduled_scan.name}: {str(e)}') + self.stderr.write(f'Failed to execute scheduled scan {scheduled_scan.name}: {str(e)}') + + # Send failure notification + if scheduled_scan.email_notifications and scheduled_scan.notify_on_failure: + self.send_failure_notification(scheduled_scan, str(e)) + + def send_notifications(self, scheduled_scan, execution): + """Send email notifications for completed scan""" + try: + # Determine if we should send notification + should_notify = False + + if execution.status == 'failed' and scheduled_scan.notify_on_failure: + should_notify = True + elif execution.status == 'completed': + if scheduled_scan.notify_on_completion: + should_notify = True + elif scheduled_scan.notify_on_threats and execution.successful_scans > 0: + # Check if any scans found threats + # This would require checking the scan results, which might not be available immediately + # For now, we'll just send completion notifications + should_notify = scheduled_scan.notify_on_completion + + if should_notify: + self.send_execution_notification(scheduled_scan, execution) + + except Exception as e: + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan] Failed to send notification: {str(e)}') + + def send_execution_notification(self, scheduled_scan, execution): + """Send notification email for scan execution""" + try: + # Get notification emails + notification_emails = scheduled_scan.notification_email_list + if not notification_emails: + # Use admin email as fallback + notification_emails = [scheduled_scan.admin.email] if scheduled_scan.admin.email else [] + + if not notification_emails: + return + + # Prepare email content + subject = f'AI Scanner: Scheduled Scan "{scheduled_scan.name}" Completed' + + status_text = execution.status.title() + if execution.status == 'completed': + if execution.failed_scans == 0: + status_text = 'Completed Successfully' + else: + status_text = f'Completed with {execution.failed_scans} failures' + + message = f""" +Scheduled AI Security Scan Report + +Scan Name: {scheduled_scan.name} +Status: {status_text} +Execution Time: {execution.execution_time.strftime('%Y-%m-%d %H:%M:%S UTC')} + +Results: +- Total Domains: {execution.total_scans} +- Successful Scans: {execution.successful_scans} +- Failed Scans: {execution.failed_scans} +- Total Cost: ${execution.total_cost:.4f} + +Domains Scanned: {', '.join(execution.scanned_domains)} + +{f'Error Message: {execution.error_message}' if execution.error_message else ''} + +Scan IDs: {', '.join(execution.scan_id_list)} + +View detailed results in your CyberPanel AI Scanner dashboard. +""" + + # Send email using CyberPanel's email system + from plogical.mailUtilities import mailUtilities + sender = 'noreply@cyberpanel.local' + mailUtilities.SendEmail(sender, notification_emails, message) + + # Log notification sent + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan] Notification sent for {scheduled_scan.name} to {len(notification_emails)} recipients') + + except Exception as e: + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan] Failed to send notification email: {str(e)}') + + def send_failure_notification(self, scheduled_scan, error_message): + """Send notification email for scan failure""" + try: + # Get notification emails + notification_emails = scheduled_scan.notification_email_list + if not notification_emails: + # Use admin email as fallback + notification_emails = [scheduled_scan.admin.email] if scheduled_scan.admin.email else [] + + if not notification_emails: + return + + # Prepare email content + subject = f'AI Scanner: Scheduled Scan "{scheduled_scan.name}" Failed' + + message = f""" +Scheduled AI Security Scan Failure + +Scan Name: {scheduled_scan.name} +Status: Failed +Time: {timezone.now().strftime('%Y-%m-%d %H:%M:%S UTC')} + +Error: {error_message} + +Please check your CyberPanel AI Scanner configuration and try again. +""" + + # Send email using CyberPanel's email system + from plogical.mailUtilities import mailUtilities + sender = 'noreply@cyberpanel.local' + mailUtilities.SendEmail(sender, notification_emails, message) + + # Log notification sent + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan] Failure notification sent for {scheduled_scan.name}') + + except Exception as e: + from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging + logging.writeToFile(f'[Scheduled Scan] Failed to send failure notification email: {str(e)}') \ No newline at end of file diff --git a/aiScanner/models.py b/aiScanner/models.py index 13789d55e..e221f778b 100644 --- a/aiScanner/models.py +++ b/aiScanner/models.py @@ -107,3 +107,216 @@ class FileAccessToken(models.Model): def is_expired(self): from django.utils import timezone return timezone.now() > self.expires_at + + +class ScheduledScan(models.Model): + """Store scheduled scan configurations""" + FREQUENCY_CHOICES = [ + ('daily', 'Daily'), + ('weekly', 'Weekly'), + ('monthly', 'Monthly'), + ('quarterly', 'Quarterly'), + ] + + SCAN_TYPE_CHOICES = [ + ('full', 'Full Scan'), + ('quick', 'Quick Scan'), + ('custom', 'Custom Scan'), + ] + + STATUS_CHOICES = [ + ('active', 'Active'), + ('paused', 'Paused'), + ('disabled', 'Disabled'), + ] + + admin = models.ForeignKey(Administrator, on_delete=models.CASCADE, related_name='scheduled_scans') + name = models.CharField(max_length=200, help_text="Name for this scheduled scan") + domains = models.TextField(help_text="JSON array of domains to scan") + frequency = models.CharField(max_length=20, choices=FREQUENCY_CHOICES, default='weekly') + scan_type = models.CharField(max_length=20, choices=SCAN_TYPE_CHOICES, default='full') + time_of_day = models.TimeField(help_text="Time of day to run the scan (UTC)") + day_of_week = models.IntegerField(null=True, blank=True, help_text="Day of week for weekly scans (0=Monday, 6=Sunday)") + day_of_month = models.IntegerField(null=True, blank=True, help_text="Day of month for monthly scans (1-31)") + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active') + last_run = models.DateTimeField(null=True, blank=True) + next_run = models.DateTimeField(null=True, blank=True) + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + # Notification settings + email_notifications = models.BooleanField(default=True) + notification_emails = models.TextField(blank=True, help_text="JSON array of email addresses") + notify_on_threats = models.BooleanField(default=True) + notify_on_completion = models.BooleanField(default=False) + notify_on_failure = models.BooleanField(default=True) + + class Meta: + db_table = 'ai_scanner_scheduled_scans' + ordering = ['-created_at'] + + def __str__(self): + return f"Scheduled Scan: {self.name} ({self.frequency})" + + @property + def domain_list(self): + """Parse domains JSON""" + if self.domains: + try: + return json.loads(self.domains) + except json.JSONDecodeError: + return [] + return [] + + @property + def notification_email_list(self): + """Parse notification emails JSON""" + if self.notification_emails: + try: + return json.loads(self.notification_emails) + except json.JSONDecodeError: + return [] + return [] + + def set_domains(self, domain_list): + """Set domains from list""" + self.domains = json.dumps(domain_list) + + def set_notification_emails(self, email_list): + """Set notification emails from list""" + self.notification_emails = json.dumps(email_list) + + def calculate_next_run(self): + """Calculate next run time based on frequency""" + from django.utils import timezone + from datetime import datetime, timedelta + import calendar + + now = timezone.now() + + if self.frequency == 'daily': + # Daily: next run is tomorrow at specified time + next_run = now.replace(hour=self.time_of_day.hour, minute=self.time_of_day.minute, second=0, microsecond=0) + if next_run <= now: + next_run += timedelta(days=1) + + elif self.frequency == 'weekly': + # Weekly: next run is on specified day of week at specified time + days_ahead = self.day_of_week - now.weekday() + if days_ahead <= 0: # Target day already happened this week + days_ahead += 7 + next_run = now + timedelta(days=days_ahead) + next_run = next_run.replace(hour=self.time_of_day.hour, minute=self.time_of_day.minute, second=0, microsecond=0) + + elif self.frequency == 'monthly': + # Monthly: next run is on specified day of month at specified time + year = now.year + month = now.month + day = min(self.day_of_month, calendar.monthrange(year, month)[1]) + + next_run = now.replace(day=day, hour=self.time_of_day.hour, minute=self.time_of_day.minute, second=0, microsecond=0) + + if next_run <= now: + # Move to next month + if month == 12: + year += 1 + month = 1 + else: + month += 1 + day = min(self.day_of_month, calendar.monthrange(year, month)[1]) + next_run = next_run.replace(year=year, month=month, day=day) + + elif self.frequency == 'quarterly': + # Quarterly: next run is 3 months from now + next_run = now.replace(hour=self.time_of_day.hour, minute=self.time_of_day.minute, second=0, microsecond=0) + month = now.month + year = now.year + + # Add 3 months + month += 3 + if month > 12: + year += 1 + month -= 12 + + day = min(self.day_of_month or 1, calendar.monthrange(year, month)[1]) + next_run = next_run.replace(year=year, month=month, day=day) + + if next_run <= now: + # Add another 3 months + month += 3 + if month > 12: + year += 1 + month -= 12 + day = min(self.day_of_month or 1, calendar.monthrange(year, month)[1]) + next_run = next_run.replace(year=year, month=month, day=day) + + else: + # Default to weekly + next_run = now + timedelta(weeks=1) + + return next_run + + def save(self, *args, **kwargs): + """Override save to calculate next_run""" + if not self.next_run or self.status == 'active': + self.next_run = self.calculate_next_run() + super().save(*args, **kwargs) + + +class ScheduledScanExecution(models.Model): + """Track individual executions of scheduled scans""" + STATUS_CHOICES = [ + ('pending', 'Pending'), + ('running', 'Running'), + ('completed', 'Completed'), + ('failed', 'Failed'), + ('cancelled', 'Cancelled'), + ] + + scheduled_scan = models.ForeignKey(ScheduledScan, on_delete=models.CASCADE, related_name='executions') + execution_time = models.DateTimeField(auto_now_add=True) + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending') + domains_scanned = models.TextField(blank=True, help_text="JSON array of domains that were scanned") + total_scans = models.IntegerField(default=0) + successful_scans = models.IntegerField(default=0) + failed_scans = models.IntegerField(default=0) + total_cost = models.DecimalField(max_digits=10, decimal_places=6, default=0.0) + scan_ids = models.TextField(blank=True, help_text="JSON array of scan IDs created") + error_message = models.TextField(blank=True, null=True) + started_at = models.DateTimeField(null=True, blank=True) + completed_at = models.DateTimeField(null=True, blank=True) + + class Meta: + db_table = 'ai_scanner_scheduled_executions' + ordering = ['-execution_time'] + + def __str__(self): + return f"Execution of {self.scheduled_scan.name} at {self.execution_time}" + + @property + def scanned_domains(self): + """Parse domains scanned JSON""" + if self.domains_scanned: + try: + return json.loads(self.domains_scanned) + except json.JSONDecodeError: + return [] + return [] + + @property + def scan_id_list(self): + """Parse scan IDs JSON""" + if self.scan_ids: + try: + return json.loads(self.scan_ids) + except json.JSONDecodeError: + return [] + return [] + + def set_scanned_domains(self, domain_list): + """Set scanned domains from list""" + self.domains_scanned = json.dumps(domain_list) + + def set_scan_ids(self, scan_id_list): + """Set scan IDs from list""" + self.scan_ids = json.dumps(scan_id_list) diff --git a/aiScanner/scheduled_views.py b/aiScanner/scheduled_views.py new file mode 100644 index 000000000..e886a6121 --- /dev/null +++ b/aiScanner/scheduled_views.py @@ -0,0 +1,270 @@ +from django.shortcuts import render, redirect +from django.http import JsonResponse +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_http_methods +from loginSystem.views import loadLoginPage +import json + + +@require_http_methods(['GET', 'POST']) +def scheduledScans(request): + """Manage scheduled scans""" + try: + userID = request.session['userID'] + from loginSystem.models import Administrator + from .models import ScheduledScan + from plogical.acl import ACLManager + + admin = Administrator.objects.get(pk=userID) + currentACL = ACLManager.loadedACL(userID) + + if request.method == 'GET': + # Get scheduled scans with ACL respect + if currentACL['admin'] == 1: + # Admin can see all scheduled scans + scheduled_scans = ScheduledScan.objects.all() + else: + # Users can only see their own scheduled scans and their sub-users' scans + user_admins = ACLManager.loadUserObjects(userID) + scheduled_scans = ScheduledScan.objects.filter(admin__in=user_admins) + + scan_data = [] + for scan in scheduled_scans: + scan_data.append({ + 'id': scan.id, + 'name': scan.name, + 'domains': scan.domain_list, + 'frequency': scan.frequency, + 'scan_type': scan.scan_type, + 'time_of_day': scan.time_of_day.strftime('%H:%M'), + 'day_of_week': scan.day_of_week, + 'day_of_month': scan.day_of_month, + 'status': scan.status, + 'last_run': scan.last_run.isoformat() if scan.last_run else None, + 'next_run': scan.next_run.isoformat() if scan.next_run else None, + 'email_notifications': scan.email_notifications, + 'notification_emails': scan.notification_email_list, + 'notify_on_threats': scan.notify_on_threats, + 'notify_on_completion': scan.notify_on_completion, + 'notify_on_failure': scan.notify_on_failure, + 'created_at': scan.created_at.isoformat() + }) + + return JsonResponse({'success': True, 'scheduled_scans': scan_data}) + + elif request.method == 'POST': + # Create new scheduled scan + data = json.loads(request.body) + + # Validate required fields + required_fields = ['name', 'domains', 'frequency', 'scan_type', 'time_of_day'] + for field in required_fields: + if field not in data or not data[field]: + return JsonResponse({'success': False, 'error': f'Missing required field: {field}'}) + + # Validate domains + if not isinstance(data['domains'], list) or len(data['domains']) == 0: + return JsonResponse({'success': False, 'error': 'At least one domain must be selected'}) + + # Check if user has access to these domains + if currentACL['admin'] != 1: + from websiteFunctions.models import Websites + user_domains = set(Websites.objects.filter(admin=admin).values_list('domain', flat=True)) + requested_domains = set(data['domains']) + + if not requested_domains.issubset(user_domains): + return JsonResponse({'success': False, 'error': 'You do not have access to some of the selected domains'}) + + # Parse time + from datetime import datetime + try: + time_obj = datetime.strptime(data['time_of_day'], '%H:%M').time() + except ValueError: + return JsonResponse({'success': False, 'error': 'Invalid time format'}) + + # Create scheduled scan + scheduled_scan = ScheduledScan( + admin=admin, + name=data['name'], + frequency=data['frequency'], + scan_type=data['scan_type'], + time_of_day=time_obj, + email_notifications=data.get('email_notifications', True), + notify_on_threats=data.get('notify_on_threats', True), + notify_on_completion=data.get('notify_on_completion', False), + notify_on_failure=data.get('notify_on_failure', True) + ) + + # Set domains + scheduled_scan.set_domains(data['domains']) + + # Set notification emails + if data.get('notification_emails'): + scheduled_scan.set_notification_emails(data['notification_emails']) + + # Set frequency-specific fields + if data['frequency'] == 'weekly' and 'day_of_week' in data: + scheduled_scan.day_of_week = int(data['day_of_week']) + elif data['frequency'] in ['monthly', 'quarterly'] and 'day_of_month' in data: + scheduled_scan.day_of_month = int(data['day_of_month']) + + scheduled_scan.save() + + return JsonResponse({'success': True, 'id': scheduled_scan.id}) + + except KeyError: + return JsonResponse({'success': False, 'error': 'Not authenticated'}) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}) + + +@require_http_methods(['GET', 'DELETE']) +def scheduledScanDetail(request, scan_id): + """Get or delete a specific scheduled scan""" + try: + userID = request.session['userID'] + from loginSystem.models import Administrator + from .models import ScheduledScan + from plogical.acl import ACLManager + + admin = Administrator.objects.get(pk=userID) + currentACL = ACLManager.loadedACL(userID) + + # Get scheduled scan with ACL respect + try: + scheduled_scan = ScheduledScan.objects.get(id=scan_id) + + # Check if user has access to this scheduled scan + if currentACL['admin'] != 1: + user_admins = ACLManager.loadUserObjects(userID) + if scheduled_scan.admin not in user_admins: + return JsonResponse({'success': False, 'error': 'Access denied to this scheduled scan'}) + except ScheduledScan.DoesNotExist: + return JsonResponse({'success': False, 'error': 'Scheduled scan not found'}) + + if request.method == 'GET': + # Return scheduled scan details + scan_data = { + 'id': scheduled_scan.id, + 'name': scheduled_scan.name, + 'domains': scheduled_scan.domain_list, + 'frequency': scheduled_scan.frequency, + 'scan_type': scheduled_scan.scan_type, + 'time_of_day': scheduled_scan.time_of_day.strftime('%H:%M'), + 'day_of_week': scheduled_scan.day_of_week, + 'day_of_month': scheduled_scan.day_of_month, + 'status': scheduled_scan.status, + 'last_run': scheduled_scan.last_run.isoformat() if scheduled_scan.last_run else None, + 'next_run': scheduled_scan.next_run.isoformat() if scheduled_scan.next_run else None, + 'email_notifications': scheduled_scan.email_notifications, + 'notification_emails': scheduled_scan.notification_email_list, + 'notify_on_threats': scheduled_scan.notify_on_threats, + 'notify_on_completion': scheduled_scan.notify_on_completion, + 'notify_on_failure': scheduled_scan.notify_on_failure, + 'created_at': scheduled_scan.created_at.isoformat() + } + + return JsonResponse({'success': True, 'scheduled_scan': scan_data}) + + elif request.method == 'DELETE': + # Delete scheduled scan + scheduled_scan.delete() + return JsonResponse({'success': True}) + + except KeyError: + return JsonResponse({'success': False, 'error': 'Not authenticated'}) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}) + + +@csrf_exempt +@require_http_methods(['POST']) +def toggleScheduledScan(request, scan_id): + """Toggle scheduled scan status (active/paused)""" + try: + userID = request.session['userID'] + from loginSystem.models import Administrator + from .models import ScheduledScan + from plogical.acl import ACLManager + + admin = Administrator.objects.get(pk=userID) + currentACL = ACLManager.loadedACL(userID) + + # Get scheduled scan with ACL respect + try: + scheduled_scan = ScheduledScan.objects.get(id=scan_id) + + # Check if user has access to this scheduled scan + if currentACL['admin'] != 1: + user_admins = ACLManager.loadUserObjects(userID) + if scheduled_scan.admin not in user_admins: + return JsonResponse({'success': False, 'error': 'Access denied to this scheduled scan'}) + except ScheduledScan.DoesNotExist: + return JsonResponse({'success': False, 'error': 'Scheduled scan not found'}) + + # Toggle status + if scheduled_scan.status == 'active': + scheduled_scan.status = 'paused' + else: + scheduled_scan.status = 'active' + + scheduled_scan.save() + + return JsonResponse({'success': True, 'status': scheduled_scan.status}) + + except KeyError: + return JsonResponse({'success': False, 'error': 'Not authenticated'}) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}) + + +@require_http_methods(['GET']) +def scheduledScanExecutions(request, scan_id): + """Get execution history for a scheduled scan""" + try: + userID = request.session['userID'] + from loginSystem.models import Administrator + from .models import ScheduledScan, ScheduledScanExecution + from plogical.acl import ACLManager + + admin = Administrator.objects.get(pk=userID) + currentACL = ACLManager.loadedACL(userID) + + # Get scheduled scan with ACL respect + try: + scheduled_scan = ScheduledScan.objects.get(id=scan_id) + + # Check if user has access to this scheduled scan + if currentACL['admin'] != 1: + user_admins = ACLManager.loadUserObjects(userID) + if scheduled_scan.admin not in user_admins: + return JsonResponse({'success': False, 'error': 'Access denied to this scheduled scan'}) + except ScheduledScan.DoesNotExist: + return JsonResponse({'success': False, 'error': 'Scheduled scan not found'}) + + # Get execution history + executions = ScheduledScanExecution.objects.filter(scheduled_scan=scheduled_scan).order_by('-execution_time')[:20] + + execution_data = [] + for execution in executions: + execution_data.append({ + 'id': execution.id, + 'execution_time': execution.execution_time.isoformat(), + 'status': execution.status, + 'domains_scanned': execution.scanned_domains, + 'total_scans': execution.total_scans, + 'successful_scans': execution.successful_scans, + 'failed_scans': execution.failed_scans, + 'total_cost': float(execution.total_cost), + 'scan_ids': execution.scan_id_list, + 'error_message': execution.error_message, + 'started_at': execution.started_at.isoformat() if execution.started_at else None, + 'completed_at': execution.completed_at.isoformat() if execution.completed_at else None + }) + + return JsonResponse({'success': True, 'executions': execution_data}) + + except KeyError: + return JsonResponse({'success': False, 'error': 'Not authenticated'}) + except Exception as e: + return JsonResponse({'success': False, 'error': str(e)}) \ No newline at end of file diff --git a/aiScanner/templates/aiScanner/scanner.html b/aiScanner/templates/aiScanner/scanner.html index d63d2af22..a80b374bf 100644 --- a/aiScanner/templates/aiScanner/scanner.html +++ b/aiScanner/templates/aiScanner/scanner.html @@ -642,6 +642,27 @@ AI Security Scanner - CyberPanel + + + {% if is_payment_configured or vps_info.is_vps|default:False %} +
+
+

+ + Scheduled Scans +

+ +
+ +
+ +
+
+ {% endif %} + + {% endif %} @@ -1539,5 +1560,454 @@ setInterval(() => { refreshScanHistory(); } }, 30000); + +// Scheduled Scans Functions +function showScheduleModal() { + // Reset form for new schedule + document.getElementById('scheduleForm').reset(); + document.getElementById('scheduleId').value = ''; + + // Uncheck all domain checkboxes + document.querySelectorAll('input[name="domains"]').forEach(cb => cb.checked = false); + + // Reset checkboxes to their defaults + document.getElementById('emailNotifications').checked = true; + document.getElementById('notifyOnThreats').checked = true; + document.getElementById('notifyOnCompletion').checked = false; + document.getElementById('notifyOnFailure').checked = true; + + $('#scheduleModal').modal('show'); +} + +function loadScheduledScans() { + fetch('/aiscanner/scheduled-scans/') + .then(response => response.json()) + .then(data => { + if (data.success) { + displayScheduledScans(data.scheduled_scans); + } else { + console.error('Failed to load scheduled scans:', data.error); + } + }) + .catch(error => { + console.error('Error loading scheduled scans:', error); + }); +} + +function displayScheduledScans(scans) { + const container = document.getElementById('scheduledScansContainer'); + + if (!scans || scans.length === 0) { + container.innerHTML = '

No scheduled scans configured yet.

'; + return; + } + + let html = '
'; + + scans.forEach(scan => { + const statusClass = scan.status === 'active' ? 'success' : scan.status === 'paused' ? 'warning' : 'danger'; + const nextRun = scan.next_run ? new Date(scan.next_run).toLocaleString() : 'Not scheduled'; + const lastRun = scan.last_run ? new Date(scan.last_run).toLocaleString() : 'Never'; + + html += ` +
+
+

${scan.name}

+ ${scan.status} +
+
+

Frequency: ${scan.frequency}

+

Scan Type: ${scan.scan_type}

+

Domains: ${scan.domains.join(', ')}

+

Next Run: ${nextRun}

+

Last Run: ${lastRun}

+
+
+ + + +
+
+ `; + }); + + html += '
'; + container.innerHTML = html; +} + +function saveScheduledScan() { + const form = document.getElementById('scheduleForm'); + const formData = new FormData(form); + const data = {}; + + // Process form data, excluding checkboxes and multi-select fields + for (let [key, value] of formData.entries()) { + if (!['email_notifications', 'notify_on_threats', 'notify_on_completion', 'notify_on_failure', 'domains'].includes(key)) { + data[key] = value; + } + } + + // Get selected domains + const selectedDomains = Array.from(document.querySelectorAll('input[name="domains"]:checked')) + .map(cb => cb.value); + + if (selectedDomains.length === 0) { + alert('Please select at least one domain to scan.'); + return; + } + + data.domains = selectedDomains; + + // Get notification emails + const notificationEmails = document.getElementById('notificationEmails').value.split(',') + .map(email => email.trim()) + .filter(email => email.length > 0); + + data.notification_emails = notificationEmails; + + // Convert checkbox values to booleans explicitly + data.email_notifications = document.getElementById('emailNotifications').checked; + data.notify_on_threats = document.getElementById('notifyOnThreats').checked; + data.notify_on_completion = document.getElementById('notifyOnCompletion').checked; + data.notify_on_failure = document.getElementById('notifyOnFailure').checked; + + fetch('/aiscanner/scheduled-scans/', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + }, + body: JSON.stringify(data) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + $('#scheduleModal').modal('hide'); + loadScheduledScans(); + document.getElementById('scheduleForm').reset(); + } else { + alert('Error: ' + data.error); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Failed to save scheduled scan. Please try again.'); + }); +} + +function editScheduledScan(id) { + // Fetch scheduled scan details and populate form + fetch(`/aiscanner/scheduled-scans/${id}/`) + .then(response => response.json()) + .then(data => { + if (data.success) { + populateScheduleForm(data.scheduled_scan); + $('#scheduleModal').modal('show'); + } else { + alert('Error: ' + data.error); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Failed to load scheduled scan details.'); + }); +} + +function populateScheduleForm(scan) { + document.getElementById('scheduleId').value = scan.id; + document.getElementById('scheduleName').value = scan.name; + document.getElementById('frequency').value = scan.frequency; + document.getElementById('scanType').value = scan.scan_type; + document.getElementById('timeOfDay').value = scan.time_of_day; + + if (scan.day_of_week !== null) { + document.getElementById('dayOfWeek').value = scan.day_of_week; + } + + if (scan.day_of_month !== null) { + document.getElementById('dayOfMonth').value = scan.day_of_month; + } + + // Select domains + scan.domains.forEach(domain => { + const checkbox = document.querySelector(`input[name="domains"][value="${domain}"]`); + if (checkbox) { + checkbox.checked = true; + } + }); + + // Set notification settings + document.getElementById('emailNotifications').checked = scan.email_notifications; + document.getElementById('notifyOnThreats').checked = scan.notify_on_threats; + document.getElementById('notifyOnCompletion').checked = scan.notify_on_completion; + document.getElementById('notifyOnFailure').checked = scan.notify_on_failure; + + if (scan.notification_emails && scan.notification_emails.length > 0) { + document.getElementById('notificationEmails').value = scan.notification_emails.join(', '); + } + + updateFrequencyOptions(); +} + +function toggleScheduledScan(id) { + fetch(`/aiscanner/scheduled-scans/${id}/toggle/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + } + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + loadScheduledScans(); + } else { + alert('Error: ' + data.error); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Failed to toggle scheduled scan.'); + }); +} + +function deleteScheduledScan(id) { + if (confirm('Are you sure you want to delete this scheduled scan?')) { + fetch(`/aiscanner/scheduled-scans/${id}/`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': getCookie('csrftoken') + } + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + loadScheduledScans(); + } else { + alert('Error: ' + data.error); + } + }) + .catch(error => { + console.error('Error:', error); + alert('Failed to delete scheduled scan.'); + }); + } +} + +function updateFrequencyOptions() { + const frequency = document.getElementById('frequency').value; + const dayOfWeekGroup = document.getElementById('dayOfWeekGroup'); + const dayOfMonthGroup = document.getElementById('dayOfMonthGroup'); + + // Hide all optional fields first + dayOfWeekGroup.style.display = 'none'; + dayOfMonthGroup.style.display = 'none'; + + // Show relevant fields based on frequency + if (frequency === 'weekly') { + dayOfWeekGroup.style.display = 'block'; + } else if (frequency === 'monthly' || frequency === 'quarterly') { + dayOfMonthGroup.style.display = 'block'; + } +} + +// Load scheduled scans when page loads +document.addEventListener('DOMContentLoaded', function() { + if (document.getElementById('scheduledScansContainer')) { + loadScheduledScans(); + } +}); + + + + + {% endblock %} \ No newline at end of file diff --git a/aiScanner/urls.py b/aiScanner/urls.py index 6cc9784aa..03999a4fc 100644 --- a/aiScanner/urls.py +++ b/aiScanner/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from . import views, api +from . import views, api, scheduled_views urlpatterns = [ # Main AI Scanner pages @@ -18,6 +18,12 @@ urlpatterns = [ path('platform-monitor-url//', views.getPlatformMonitorUrl, name='aiScannerPlatformMonitorUrl'), path('platform-status//', views.getPlatformScanStatus, name='aiScannerPlatformStatus'), + # Scheduled scans management + path('scheduled-scans/', scheduled_views.scheduledScans, name='aiScannerScheduledScans'), + path('scheduled-scans//', scheduled_views.scheduledScanDetail, name='aiScannerScheduledScanDetail'), + path('scheduled-scans//toggle/', scheduled_views.toggleScheduledScan, name='aiScannerToggleScheduledScan'), + path('scheduled-scans//executions/', scheduled_views.scheduledScanExecutions, name='aiScannerScheduledScanExecutions'), + # Note: RESTful API endpoints are in /api/urls.py for external access # Legacy API endpoints (for backward compatibility) diff --git a/cyberpanel.sh b/cyberpanel.sh index 3074f9035..5cda7f943 100644 --- a/cyberpanel.sh +++ b/cyberpanel.sh @@ -106,6 +106,148 @@ Debug_Log2 "Starting installation..,1" } +# Helper Functions for Package Management +install_package() { + local package="$1" + case "$Server_OS" in + "CentOS"|"openEuler") + if [[ "$Server_OS_Version" -ge 8 ]]; then + dnf install -y "$package" + else + yum install -y "$package" + fi + ;; + "Ubuntu") + DEBIAN_FRONTEND=noninteractive apt install -y "$package" + ;; + esac +} + +# Helper Function for Service Management +manage_service() { + local service="$1" + local action="$2" + systemctl "$action" "$service" +} + +# Helper Function for Development Tools Installation +install_dev_tools() { + case "$Server_OS" in + "CentOS"|"openEuler") + yum groupinstall "Development Tools" -y + yum install autoconf automake zlib-devel openssl-devel expat-devel pcre-devel libmemcached-devel cyrus-sasl* -y + ;; + "Ubuntu") + DEBIAN_FRONTEND=noninteractive apt install build-essential zlib1g-dev libexpat1-dev openssl libssl-dev libsasl2-dev libpcre3-dev git -y + ;; + esac +} + +# Helper Function for PHP Package Installation +install_php_packages() { + local php_extension="$1" + case "$Server_OS" in + "CentOS"|"openEuler") + install_package "lsphp??-${php_extension} lsphp??-pecl-${php_extension}" + ;; + "Ubuntu") + install_package "lsphp*-${php_extension}" + ;; + esac +} + +# Helper Function for configuring memcached +configure_memcached() { + if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]]; then + sed -i 's|OPTIONS=""|OPTIONS="-l 127.0.0.1 -U 0"|g' /etc/sysconfig/memcached + fi +} + +# Helper Function for EPEL repository setup +setup_epel_repo() { + case "$Server_OS_Version" in + "7") + rpm --import https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 + yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm + Check_Return "yum repo" "no_exit" + ;; + "8") + rpm --import https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8 + yum install -y https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm + Check_Return "yum repo" "no_exit" + ;; + "9") + yum install -y https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm + Check_Return "yum repo" "no_exit" + ;; + esac +} + +# Helper Function for MariaDB repository setup +setup_mariadb_repo() { + if [[ "$Server_OS_Version" = "7" ]]; then + cat </etc/yum.repos.d/MariaDB.repo +# MariaDB 10.4 CentOS repository list - created 2021-08-06 02:01 UTC +# http://downloads.mariadb.org/mariadb/repositories/ +[mariadb] +name = MariaDB +baseurl = http://yum.mariadb.org/10.4/centos7-amd64 +gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB +gpgcheck=1 +EOF + elif [[ "$Server_OS_Version" = "8" ]]; then + cat </etc/yum.repos.d/MariaDB.repo +# MariaDB 10.11 RHEL8 repository list +# http://downloads.mariadb.org/mariadb/repositories/ +[mariadb] +name = MariaDB +baseurl = http://yum.mariadb.org/10.11/rhel8-amd64 +module_hotfixes=1 +gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB +gpgcheck=1 +EOF + elif [[ "$Server_OS_Version" = "9" ]] && uname -m | grep -q 'x86_64'; then + cat </etc/yum.repos.d/MariaDB.repo +# MariaDB 10.11 CentOS repository list - created 2021-08-06 02:01 UTC +# http://downloads.mariadb.org/mariadb/repositories/ +[mariadb] +name = MariaDB +baseurl = http://yum.mariadb.org/10.11/rhel9-amd64/ +gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB +enabled=1 +gpgcheck=1 +EOF + fi +} + +# Helper Function for PHP timezone configuration +configure_php_timezone() { + local php_version="$1" + local php_ini_path=$(find "$php_version" -name php.ini) + + # Common configuration + "${php_version}/bin/phpize" + ./configure --with-php-config="${php_version}/bin/php-config" + make + make install + + # OS-specific configuration + if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]]; then + if [[ ! -d "${php_version}/tmp" ]]; then + mkdir "${php_version}/tmp" + fi + "${php_version}/bin/pecl" channel-update pecl.php.net + "${php_version}/bin/pear" config-set temp_dir "${php_version}/tmp" + echo "extension=timezonedb.so" > "${php_version}/etc/php.d/20-timezone.ini" + else + echo "extension=timezonedb.so" > "/usr/local/lsws/${php_version: 16:7}/etc/php/${php_version: 21:1}.${php_version: 22:1}/mods-available/20-timezone.ini" + fi + + make clean + sed -i 's|expose_php = On|expose_php = Off|g' "$php_ini_path" + sed -i 's|mail.add_x_header = On|mail.add_x_header = Off|g' "$php_ini_path" +} + Debug_Log() { echo -e "\n${1}=${2}\n" >> "/var/log/cyberpanel_debug_$(date +"%Y-%m-%d")_${Random_Log_Name}.log" } @@ -178,7 +320,15 @@ do echo "command $1 failed for 50 times, exit..." exit 2 else - $1 && break || echo -e "\n$1 has failed for $i times\nWait for 3 seconds and try again...\n"; sleep 3; + $1 && break || { + echo -e "\n$1 has failed for $i times\nWait and try again...\n" + # Exponential backoff: 1s, 2s, 4s, 8s, then cap at 10s + if [[ $i -le 4 ]]; then + sleep $((2**($i-1))) + else + sleep 10 + fi + } fi done } @@ -359,30 +509,16 @@ fi } Check_Process() { -if systemctl is-active --quiet httpd; then - systemctl disable httpd - systemctl stop httpd - systemctl mask httpd - echo -e "\nhttpd process detected, disabling...\n" -fi -if systemctl is-active --quiet apache2; then - systemctl disable apache2 - systemctl stop apache2 - systemctl mask apache2 - echo -e "\napache2 process detected, disabling...\n" -fi -if systemctl is-active --quiet named; then - systemctl stop named - systemctl disable named - systemctl mask named - echo -e "\nnamed process detected, disabling...\n" -fi -if systemctl is-active --quiet exim; then - systemctl stop exim - systemctl disable exim - systemctl mask exim - echo -e "\nexim process detected, disabling...\n" -fi + local services=("httpd" "apache2" "named" "exim") + + for service in "${services[@]}"; do + if systemctl is-active --quiet "$service"; then + manage_service "$service" "stop" + manage_service "$service" "disable" + manage_service "$service" "mask" + echo -e "\n$service process detected, disabling...\n" + fi + done } Check_Provider() { @@ -838,9 +974,14 @@ if [[ $Server_OS = "CentOS" ]] ; then yum autoremove -y epel-release rm -f /etc/yum.repos.d/epel.repo rm -f /etc/yum.repos.d/epel.repo.rpmsave + + # Setup EPEL repository based on version + setup_epel_repo + + # Setup MariaDB repository + setup_mariadb_repo if [[ "$Server_OS_Version" = "9" ]]; then - # Check if architecture is aarch64 if uname -m | grep -q 'aarch64' ; then # Run the following commands if architecture is aarch64 @@ -860,34 +1001,12 @@ if [[ $Server_OS = "CentOS" ]] ; then dnf config-manager --set-enabled crb fi - yum install -y https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm - Check_Return "yum repo" "no_exit" yum install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm Check_Return "yum repo" "no_exit" - #!/bin/bash - -# Check if architecture is x86_64 -if uname -m | grep -q 'x86_64' ; then - # Create the MariaDB repository configuration file for x86_64 architecture - cat </etc/yum.repos.d/MariaDB.repo -# MariaDB 10.11 CentOS repository list - created 2021-08-06 02:01 UTC -# http://downloads.mariadb.org/mariadb/repositories/ -[mariadb] -name = MariaDB -baseurl = http://yum.mariadb.org/10.11/rhel9-amd64/ -gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB -enabled=1 -gpgcheck=1 -EOF - echo "MariaDB repository file created for x86_64 architecture." -fi fi if [[ "$Server_OS_Version" = "8" ]]; then rpm --import https://cyberpanel.sh/www.centos.org/keys/RPM-GPG-KEY-CentOS-Official - rpm --import https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8 - yum install -y https://cyberpanel.sh/dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm - Check_Return "yum repo" "no_exit" sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-* > /dev/null 2>&1 sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-* > /dev/null 2>&1 @@ -1042,8 +1161,8 @@ for i in {1..50} ; break else echo -e "\n Requirement list has failed to download for $i times..." - echo -e "Wait for 30 seconds and try again...\n" - sleep 30 + echo -e "Wait for 5 seconds and try again...\n" + sleep 5 fi done #special made function for Gitee.com , for whatever reason , sometimes it fails to download this file @@ -1054,6 +1173,8 @@ Pre_Install_Required_Components() { Debug_Log2 "Installing necessary components..,3" if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]] ; then + # System-wide update - consider making this optional for faster installs + # Could add a --skip-system-update flag to bypass this yum update -y if [[ "$Server_OS_Version" = "7" ]] ; then yum install -y wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel gpgme-devel curl-devel git socat openssl-devel MariaDB-shared mariadb-devel yum-utils python36u python36u-pip python36u-devel zip unzip bind-utils @@ -1061,9 +1182,7 @@ if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]] ; then yum -y groupinstall development Check_Return elif [[ "$Server_OS_Version" = "8" ]] ; then - dnf install -y libnsl zip wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-devel curl-devel git platform-python-devel tar socat python3 zip unzip bind-utils - Check_Return - dnf install -y gpgme-devel + dnf install -y libnsl zip wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-devel curl-devel git platform-python-devel tar socat python3 zip unzip bind-utils gpgme-devel Check_Return elif [[ "$Server_OS_Version" = "9" ]] ; then @@ -1073,14 +1192,15 @@ if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]] ; then dnf install -y libnsl zip wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel MariaDB-server MariaDB-client MariaDB-devel curl-devel git platform-python-devel tar socat python3 zip unzip bind-utils gpgme-devel openssl-devel Check_Return elif [[ "$Server_OS_Version" = "20" ]] || [[ "$Server_OS_Version" = "22" ]] ; then - dnf install -y libnsl zip wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-devel curl-devel git python3-devel tar socat python3 zip unzip bind-utils - Check_Return - dnf install -y gpgme-devel + dnf install -y libnsl zip wget strace net-tools curl which bc telnet htop libevent-devel gcc libattr-devel xz-devel mariadb-devel curl-devel git python3-devel tar socat python3 zip unzip bind-utils gpgme-devel Check_Return fi ln -s /usr/bin/pip3 /usr/bin/pip else + # Update package lists (required for installations) apt update -y + # System-wide upgrade - consider making this optional for faster installs + # Could add a --skip-system-upgrade flag to bypass this DEBIAN_FRONTEND=noninteractive apt upgrade -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" if [[ "$Server_Provider" = "Alibaba Cloud" ]] ; then apt install -y --allow-downgrades libgnutls30=3.6.13-2ubuntu1.3 @@ -1094,19 +1214,11 @@ else Check_Return fi - DEBIAN_FRONTEND=noninteractive apt install -y python3-pip + DEBIAN_FRONTEND=noninteractive apt install -y python3-pip build-essential libssl-dev libffi-dev python3-dev python3-venv cron inetutils-ping Check_Return ln -s /usr/bin/pip3 /usr/bin/pip3.6 ln -s /usr/bin/pip3.6 /usr/bin/pip - - DEBIAN_FRONTEND=noninteractive apt install -y build-essential libssl-dev libffi-dev python3-dev - Check_Return - DEBIAN_FRONTEND=noninteractive apt install -y python3-venv - Check_Return - - DEBIAN_FRONTEND=noninteractive apt install -y cron inetutils-ping - Check_Return # Oracle Ubuntu ARM misses ping and cron DEBIAN_FRONTEND=noninteractive apt install -y locales @@ -1145,10 +1257,6 @@ Debug_Log2 "Installing requirments..,3" Retry_Command "pip install --default-timeout=3600 -r /usr/local/requirments.txt" Check_Return "requirments" "no_exit" -if [[ "$Server_OS" = "Ubuntu" ]] && [[ "$Server_OS_Version" = "22" ]] ; then - cp /usr/bin/python3.10 /usr/local/CyberCP/bin/python3 -fi - rm -rf cyberpanel echo -e "\nFetching files from ${Git_Clone_URL}...\n" @@ -1311,8 +1419,14 @@ if ! grep -q "pid_max" /etc/rc.local 2>/dev/null ; then fi systemctl restart systemd-networkd >/dev/null 2>&1 - sleep 3 - #take a break ,or installer will break + # Wait for network to come up, but check more frequently + for j in {1..6}; do + sleep 0.5 + # Check if network is ready by trying to resolve DNS + if ping -c 1 -W 1 8.8.8.8 >/dev/null 2>&1 || nslookup cyberpanel.sh >/dev/null 2>&1; then + break + fi + done # Check Connectivity if ping -q -c 1 -W 1 cyberpanel.sh >/dev/null; then @@ -1326,14 +1440,22 @@ if ! grep -q "pid_max" /etc/rc.local 2>/dev/null ; then systemctl restart systemd-networkd >/dev/null 2>&1 echo -e "\nReturns the nameservers settings to default..\n" echo -e "\nContinue installation..\n" - sleep 3 + # Brief pause for network stabilization + sleep 1 fi cp /etc/resolv.conf /etc/resolv.conf-tmp +# Find the line containing nameserver 8.8.8.8 pattern Line1="$(grep -n "f.write('nameserver 8.8.8.8')" installCyberPanel.py | head -n 1 | cut -d: -f1)" -sed -i "${Line1}i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subprocess.call\(command, shell=True)" installCyberPanel.py -sed -i "${Line1}i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ command = 'cat /etc/resolv.conf-tmp > /etc/resolv.conf'" installCyberPanel.py + +# Only modify the file if the pattern was found +if [[ -n "$Line1" ]] && [[ "$Line1" =~ ^[0-9]+$ ]]; then + sed -i "${Line1}i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ subprocess.call\(command, shell=True)" installCyberPanel.py + sed -i "${Line1}i\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ command = 'cat /etc/resolv.conf-tmp > /etc/resolv.conf'" installCyberPanel.py +else + echo "Warning: Could not find 'nameserver 8.8.8.8' pattern in installCyberPanel.py - skipping resolv.conf modification" +fi } License_Validation() { @@ -1352,7 +1474,8 @@ tar xzvf "lsws-$LSWS_Stable_Version-ent-x86_64-linux.tar.gz" >/dev/null cd "/root/cyberpanel-tmp/lsws-$LSWS_Stable_Version/conf" || exit if [[ "$License_Key" = "Trial" ]]; then Retry_Command "wget -q https://cyberpanel.sh/license.litespeedtech.com/reseller/trial.key" - sed -i "s|writeSerial = open('lsws-6.0/serial.no', 'w')|command = 'wget -q --output-document=./lsws-$LSWS_Stable_Version/trial.key https://cyberpanel.sh/license.litespeedtech.com/reseller/trial.key'|g" "$Current_Dir/installCyberPanel.py" + # Update the serial number handling to use trial key + sed -i "s|writeSerial = open('lsws-[0-9.]\+/serial.no', 'w')|command = 'wget -q --output-document=./lsws-$LSWS_Stable_Version/trial.key https://cyberpanel.sh/license.litespeedtech.com/reseller/trial.key'|g" "$Current_Dir/installCyberPanel.py" sed -i 's|writeSerial.writelines(self.serial)|subprocess.call(command, shell=True)|g' "$Current_Dir/installCyberPanel.py" sed -i 's|writeSerial.close()||g' "$Current_Dir/installCyberPanel.py" else @@ -1526,22 +1649,8 @@ fi } Post_Install_Addon_Mecached_LSMCD() { -if [[ $Server_OS = "CentOS" ]] || [[ $Server_OS = "openEuler" ]]; then - yum groupinstall "Development Tools" -y - yum install autoconf automake zlib-devel openssl-devel expat-devel pcre-devel libmemcached-devel cyrus-sasl* -y - wget -O lsmcd-master.zip https://cyberpanel.sh/codeload.github.com/litespeedtech/lsmcd/zip/master - unzip lsmcd-master.zip - Current_Dir=$(pwd) - cd "$Current_Dir/lsmcd-master" || exit - ./fixtimestamp.sh - ./configure CFLAGS=" -O3" CXXFLAGS=" -O3" - make - make install - systemctl enable lsmcd - systemctl start lsmcd - cd "$Current_Dir" || exit -else - DEBIAN_FRONTEND=noninteractive apt install build-essential zlib1g-dev libexpat1-dev openssl libssl-dev libsasl2-dev libpcre3-dev git -y + install_dev_tools + wget -O lsmcd-master.zip https://cyberpanel.sh/codeload.github.com/litespeedtech/lsmcd/zip/master unzip lsmcd-master.zip Current_Dir=$(pwd) @@ -1551,98 +1660,75 @@ else make make install cd "$Current_Dir" || exit - systemctl enable lsmcd - systemctl start lsmcd -fi + + manage_service "lsmcd" "enable" + manage_service "lsmcd" "start" } Post_Install_Addon_Memcached() { -if [[ $Server_OS = "CentOS" ]]; then - yum install -y lsphp??-memcached lsphp??-pecl-memcached - if [[ $Total_RAM -eq "2048" ]] || [[ $Total_RAM -gt "2048" ]]; then + install_php_packages "memcached" + + if [[ $Total_RAM -ge 2048 ]]; then Post_Install_Addon_Mecached_LSMCD else - yum install -y memcached - sed -i 's|OPTIONS=""|OPTIONS="-l 127.0.0.1 -U 0"|g' /etc/sysconfig/memcached - #turn off UDP and bind to 127.0.0.1 only - systemctl enable memcached - systemctl start memcached + install_package "memcached" + configure_memcached + manage_service "memcached" "enable" + manage_service "memcached" "start" fi -fi -if [[ $Server_OS = "Ubuntu" ]]; then - DEBIAN_FRONTEND=noninteractive apt install -y "lsphp*-memcached" - if [[ "$Total_RAM" -eq "2048" ]] || [[ "$Total_RAM" -gt "2048" ]]; then - Post_Install_Addon_Mecached_LSMCD - else - DEBIAN_FRONTEND=noninteractive apt install -y memcached - systemctl enable memcached - systemctl start memcached + if pgrep "lsmcd" ; then + echo -e "\n\nLiteSpeed Memcached installed and running..." fi -fi -if [[ $Server_OS = "openEuler" ]]; then - yum install -y lsphp??-memcached lsphp??-pecl-memcached - if [[ $Total_RAM -eq "2048" ]] || [[ $Total_RAM -gt "2048" ]]; then - Post_Install_Addon_Mecached_LSMCD - else - yum install -y memcached - sed -i 's|OPTIONS=""|OPTIONS="-l 127.0.0.1 -U 0"|g' /etc/sysconfig/memcached - #turn off UDP and bind to 127.0.0.1 only - systemctl enable memcached - systemctl start memcached + + if pgrep "memcached" ; then + echo -e "\n\nMemcached installed and running..." fi -fi - -if pgrep "lsmcd" ; then - echo -e "\n\nLiteSpeed Memcached installed and running..." -fi - -if pgrep "memcached" ; then - echo -e "\n\nMemcached installed and running..." -fi } Post_Install_Addon_Redis() { -if [[ "$Server_OS" = "CentOS" ]]; then - if [[ "$Server_OS_Version" = "8" || "$Server_OS_Version" = "9" ]]; then - yum install -y lsphp??-redis redis - else - yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm - yum-config-manager --disable remi - yum-config-manager --disable remi-safe - yum -y --enablerepo=remi install redis + # Install PHP Redis extension + install_php_packages "redis" + + # Install Redis server + if [[ "$Server_OS" = "CentOS" ]]; then + if [[ "$Server_OS_Version" = "8" || "$Server_OS_Version" = "9" ]]; then + install_package "redis" + else + yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm + yum-config-manager --disable remi + yum-config-manager --disable remi-safe + yum -y --enablerepo=remi install redis + fi + elif [[ "$Server_OS" = "Ubuntu" ]]; then + install_package "redis" + elif [[ "$Server_OS" = "openEuler" ]]; then + install_package "redis6" fi -fi -if [[ $Server_OS = "Ubuntu" ]]; then - DEBIAN_FRONTEND=noninteractive apt install -y "lsphp*-redis" redis -fi + # Configure Redis for IPv6 + if ifconfig -a | grep inet6; then + echo -e "\nIPv6 detected...\n" + else + sed -i 's|bind 127.0.0.1 ::1|bind 127.0.0.1|g' /etc/redis/redis.conf + echo -e "\n no IPv6 detected..." + fi -if ifconfig -a | grep inet6; then - echo -e "\nIPv6 detected...\n" -else - sed -i 's|bind 127.0.0.1 ::1|bind 127.0.0.1|g' /etc/redis/redis.conf - echo -e "\n no IPv6 detected..." -fi + # Start Redis service + if [[ $Server_OS = "Ubuntu" ]]; then + manage_service "redis-server" "stop" + rm -f /var/run/redis/redis-server.pid + manage_service "redis-server" "enable" + manage_service "redis-server" "start" + else + manage_service "redis" "enable" + manage_service "redis" "start" + fi -if [[ $Server_OS = "Ubuntu" ]]; then - systemctl stop redis-server - rm -f /var/run/redis/redis-server.pid - systemctl enable redis-server - systemctl start redis-server -else - systemctl enable redis - systemctl start redis -fi - -if [[ "$Server_OS" = "openEuler" ]]; then - yum install -y lsphp??-redis redis6 -fi - -if pgrep "redis" ; then - echo -e "\n\nRedis installed and running..." - touch /home/cyberpanel/redis -fi + if pgrep "redis" ; then + echo -e "\n\nRedis installed and running..." + touch /home/cyberpanel/redis + fi } Post_Install_PHP_Session_Setup() { @@ -1663,44 +1749,19 @@ wget -O timezonedb.tgz https://cyberpanel.sh/pecl.php.net/get/timezonedb tar xzvf timezonedb.tgz cd timezonedb-* || exit +# Install required packages for building PHP extensions if [[ "$Server_OS" = "Ubuntu" ]] ; then - DEBIAN_FRONTEND=noninteractive apt install libmagickwand-dev pkg-config build-essential -y - DEBIAN_FRONTEND=noninteractive apt install -y lsphp*-dev + install_package "libmagickwand-dev pkg-config build-essential lsphp*-dev" else + install_package "lsphp??-mysqlnd lsphp??-devel make gcc glibc-devel libmemcached-devel zlib-devel" yum remove -y lsphp??-mysql - yum install -y lsphp??-mysqlnd - yum install -y lsphp??-devel make gcc glibc-devel libmemcached-devel zlib-devel fi -for PHP_Version in /usr/local/lsws/lsphp?? ; - do - PHP_INI_Path=$(find "$PHP_Version" -name php.ini) +# Configure timezone extension for each PHP version +for PHP_Version in /usr/local/lsws/lsphp?? ; do + configure_php_timezone "$PHP_Version" +done - if [[ "$Server_OS" = "CentOS" ]] || [[ "$Server_OS" = "openEuler" ]]; then - if [[ ! -d "${PHP_Version}/tmp" ]]; then - mkdir "${PHP_Version}/tmp" - fi - "${PHP_Version}"/bin/pecl channel-update pecl.php.net - "${PHP_Version}"/bin/pear config-set temp_dir "${PHP_Version}/tmp" - "${PHP_Version}"/bin/phpize - ./configure --with-php-config="${PHP_Version}"/bin/php-config - make - make install - echo "extension=timezonedb.so" > "${PHP_Version}/etc/php.d/20-timezone.ini" - make clean - sed -i 's|expose_php = On|expose_php = Off|g' "$PHP_INI_Path" - sed -i 's|mail.add_x_header = On|mail.add_x_header = Off|g' "$PHP_INI_Path" - else - "${PHP_Version}"/bin/phpize - ./configure --with-php-config="${PHP_Version}"/bin/php-config - make - make install - echo "extension=timezonedb.so" > "/usr/local/lsws/${PHP_Version: 16:7}/etc/php/${PHP_Version: 21:1}.${PHP_Version: 22:1}/mods-available/20-timezone.ini" - make clean - sed -i 's|expose_php = On|expose_php = Off|g' "$PHP_INI_Path" - sed -i 's|mail.add_x_header = On|mail.add_x_header = Off|g' "$PHP_INI_Path" - fi - done rm -rf /usr/local/lsws/cyberpanel-tmp cd "$Current_Dir" || exit Debug_Log2 "Installing timezoneDB...,95" diff --git a/cyberpanel_upgrade.sh b/cyberpanel_upgrade.sh index add013a9d..709c49eaf 100644 --- a/cyberpanel_upgrade.sh +++ b/cyberpanel_upgrade.sh @@ -459,10 +459,10 @@ elif [[ "$Server_OS" = "Ubuntu" ]] ; then export DEBIAN_FRONTEND=noninteractive ; apt-get -o Dpkg::Options::="--force-confold" upgrade -y if [[ "$Server_OS_Version" = "22" ]] ; then - DEBIAN_FRONTEND=noninteracitve apt install -y dnsutils net-tools htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev libidn2-0-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcomerr2 libldap2-dev virtualenv git socat vim unzip zip libmariadb-dev-compat libmariadb-dev + DEBIAN_FRONTEND=noninteractive apt install -y dnsutils net-tools htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev libidn2-0-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcomerr2 libldap2-dev virtualenv git socat vim unzip zip libmariadb-dev-compat libmariadb-dev else - DEBIAN_FRONTEND=noninteracitve apt install -y htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libmariadbclient-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev libidn2-0-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcomerr2 libldap2-dev virtualenv git dnsutils + DEBIAN_FRONTEND=noninteractive apt install -y htop telnet libcurl4-gnutls-dev libgnutls28-dev libgcrypt20-dev libattr1 libattr1-dev liblzma-dev libgpgme-dev libmariadbclient-dev libcurl4-gnutls-dev libssl-dev nghttp2 libnghttp2-dev idn2 libidn2-dev libidn2-0-dev librtmp-dev libpsl-dev nettle-dev libgnutls28-dev libldap2-dev libgssapi-krb5-2 libk5crypto3 libkrb5-dev libcomerr2 libldap2-dev virtualenv git dnsutils fi DEBIAN_FRONTEND=noninteractive apt install -y python3-pip DEBIAN_FRONTEND=noninteractive apt install -y build-essential libssl-dev libffi-dev python3-dev diff --git a/ftp/templates/ftp/createFTPAccount.html b/ftp/templates/ftp/createFTPAccount.html index 883caf437..f3fa97f22 100644 --- a/ftp/templates/ftp/createFTPAccount.html +++ b/ftp/templates/ftp/createFTPAccount.html @@ -432,7 +432,7 @@ ng-model="ftpUserName" placeholder="john_ftp" required> {{ OwnerFTP }}_{$ ftpUserName $} - + {% trans "Your FTP username will be prefixed with the owner username" %} @@ -467,7 +467,7 @@ {% trans "Use This Password" %} - + {% trans "Make sure to save this password in a secure location" %} diff --git a/ftp/templates/ftp/listFTPAccounts.html b/ftp/templates/ftp/listFTPAccounts.html index d9755c750..8f0d25848 100644 --- a/ftp/templates/ftp/listFTPAccounts.html +++ b/ftp/templates/ftp/listFTPAccounts.html @@ -424,7 +424,7 @@ {% trans "Use This Password" %} - + {% trans "Make sure to save this password in a secure location" %} diff --git a/install/install.py b/install/install.py index 90bf8fa65..a8de9aeb5 100644 --- a/install/install.py +++ b/install/install.py @@ -14,112 +14,42 @@ from os.path import * from stat import * import stat import secrets +import install_utils VERSION = '2.4' BUILD = 2 -char_set = {'small': 'abcdefghijklmnopqrstuvwxyz', 'nums': '0123456789', 'big': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'} +# Using shared char_set from install_utils +char_set = install_utils.char_set -def generate_pass(length=14): - chars = string.ascii_uppercase + string.ascii_lowercase + string.digits - size = length - return ''.join(random.choice(chars) for x in range(size)) +# Using shared function from install_utils +generate_pass = install_utils.generate_pass # There can not be peace without first a great suffering. -# distros +# distros - using from install_utils +centos = install_utils.centos +ubuntu = install_utils.ubuntu +cent8 = install_utils.cent8 +openeuler = install_utils.openeuler +cent9 = 4 # Not in install_utils yet +CloudLinux8 = 0 # Not in install_utils yet -centos = 0 -ubuntu = 1 -cent8 = 2 -cent9 = 4 -openeuler = 3 -CloudLinux8 = 0 - -def FetchCloudLinuxAlmaVersionVersion(): - if os.path.exists('/etc/os-release'): - data = open('/etc/os-release', 'r').read() - if (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.9') > -1 or data.find('Anatoly Levchenko') > -1 or data.find('VERSION="8.') > -1): - return 'cl-89' - elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.8') > -1 or data.find('Anatoly Filipchenko') > -1): - return 'cl-88' - elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('9.4') > -1 or data.find('VERSION="9.') > -1): - return 'cl-88' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.9') > -1 or data.find('Midnight Oncilla') > -1 or data.find('VERSION="8.') > -1): - return 'al-88' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.7') > -1 or data.find('Stone Smilodon') > -1): - return 'al-87' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('9.4') > -1 or data.find('9.3') > -1 or data.find('Shamrock Pampas') > -1 or data.find('Seafoam Ocelot') > -1 or data.find('VERSION="9.') > -1): - return 'al-93' - else: - return -1 +# Using shared function from install_utils +FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVersion -def get_distro(): - distro = -1 - distro_file = "" - if exists("/etc/lsb-release"): - distro_file = "/etc/lsb-release" - with open(distro_file) as f: - for line in f: - if line == "DISTRIB_ID=Ubuntu\n": - distro = ubuntu - - elif exists("/etc/redhat-release"): - distro_file = "/etc/redhat-release" - distro = centos - - data = open('/etc/redhat-release', 'r').read() - - - if data.find('CentOS Linux release 8') > -1: - return cent8 - ## if almalinux 9 then pretty much same as cent8 - if data.find('AlmaLinux release 8') > -1 or data.find('AlmaLinux release 9') > -1: - return cent8 - if data.find('Rocky Linux release 8') > -1 or data.find('Rocky Linux 8') > -1 or data.find('rocky:8') > -1: - return cent8 - if data.find('CloudLinux 8') or data.find('cloudlinux 8'): - return cent8 - - else: - if exists("/etc/openEuler-release"): - distro_file = "/etc/openEuler-release" - distro = openeuler - - else: - logging.InstallLog.writeToFile("Can't find linux release file - fatal error") - preFlightsChecks.stdOut("Can't find linux release file - fatal error") - os._exit(os.EX_UNAVAILABLE) - - if distro == -1: - logging.InstallLog.writeToFile("Can't find distro name in " + distro_file + " - fatal error") - preFlightsChecks.stdOut("Can't find distro name in " + distro_file + " - fatal error") - os._exit(os.EX_UNAVAILABLE) - - return distro +# Using shared function from install_utils +get_distro = install_utils.get_distro def get_Ubuntu_release(): - release = -1 - if exists("/etc/lsb-release"): - distro_file = "/etc/lsb-release" - with open(distro_file) as f: - for line in f: - if line[:16] == "DISTRIB_RELEASE=": - release = float(line[16:]) - - if release == -1: - preFlightsChecks.stdOut("Can't find distro release name in " + distro_file + " - fatal error", 1, 1, - os.EX_UNAVAILABLE) - - else: - logging.InstallLog.writeToFile("Can't find linux release file - fatal error") - preFlightsChecks.stdOut("Can't find linux release file - fatal error") - os._exit(os.EX_UNAVAILABLE) - + release = install_utils.get_Ubuntu_release(use_print=False, exit_on_error=True) + if release == -1: + preFlightsChecks.stdOut("Can't find distro release name in /etc/lsb-release - fatal error", 1, 1, + os.EX_UNAVAILABLE) return release @@ -128,6 +58,34 @@ class preFlightsChecks: cyberPanelMirror = "mirror.cyberpanel.net/pip" cdn = 'cyberpanel.sh' SnappyVersion = '2.38.2' + apt_updated = False # Track if apt update has been run + + def install_package(self, package_name, options="", silent=False): + """Unified package installation across distributions""" + command, shell = install_utils.get_package_install_command(self.distro, package_name, options) + + if not silent: + return preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, shell) + else: + return preFlightsChecks.call(command, self.distro, command, command, 0, 0, os.EX_OSERR, shell) + + def is_centos_family(self): + """Check if distro is CentOS, CentOS 8, or OpenEuler""" + return self.distro in [centos, cent8, openeuler] + + def manage_service(self, service_name, action="start"): + """Unified service management""" + command = f'systemctl {action} {service_name}' + return preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + + def remove_package(self, package_name, silent=False): + """Unified package removal across distributions""" + command, shell = install_utils.get_package_remove_command(self.distro, package_name) + + if not silent: + return preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, shell) + else: + return preFlightsChecks.call(command, self.distro, command, command, 0, 0, os.EX_OSERR, shell) def __init__(self, rootPath, ip, path, cwd, cyberPanelPath, distro, remotemysql=None, mysqlhost=None, mysqldb=None, mysqluser=None, mysqlpassword=None, mysqlport=None): @@ -148,11 +106,8 @@ class preFlightsChecks: def installQuota(self,): try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = "yum install quota -y" - preFlightsChecks.call(command, self.distro, command, - command, - 1, 0, os.EX_OSERR) + if self.is_centos_family(): + self.install_package("quota", silent=True) if self.edit_fstab('/', '/') == 0: preFlightsChecks.stdOut("Quotas will not be abled as we failed to modify fstab file.") @@ -184,18 +139,14 @@ class preFlightsChecks: if self.distro == ubuntu: self.stdOut("Install Quota on Ubuntu") - command = 'apt update -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = 'DEBIAN_FRONTEND=noninteractive apt install quota -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + # Skip apt update as it was already done in cyberpanel.sh + self.install_package("quota", silent=True) command = "find /lib/modules/ -type f -name '*quota_v*.ko*'" if subprocess.check_output(command,shell=True).decode("utf-8").find("quota/") == -1: - command = "DEBIAN_FRONTEND=noninteractive apt install linux-image-extra-virtual -y" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("linux-image-extra-virtual", silent=True) if self.edit_fstab('/', '/') == 0: preFlightsChecks.stdOut("Quotas will not be abled as we are are failed to modify fstab file.") @@ -334,18 +285,7 @@ class preFlightsChecks: @staticmethod def stdOut(message, log=0, do_exit=0, code=os.EX_OK): - print("\n\n") - print(("[" + time.strftime( - "%m.%d.%Y_%H-%M-%S") + "] #########################################################################\n")) - print(("[" + time.strftime("%m.%d.%Y_%H-%M-%S") + "] " + message + "\n")) - print(("[" + time.strftime( - "%m.%d.%Y_%H-%M-%S") + "] #########################################################################\n")) - - if log: - logging.InstallLog.writeToFile(message) - if do_exit: - logging.InstallLog.writeToFile(message) - sys.exit(code) + install_utils.stdOut(message, log, do_exit, code) def mountTemp(self): try: @@ -357,10 +297,7 @@ class preFlightsChecks: if result.stdout.find('openvz') > -1: if self.distro == ubuntu: - command = 'DEBIAN_FRONTEND=noninteractive apt install inetutils-inetd -y' - preFlightsChecks.call(command, self.distro, command, - command, - 1, 0, os.EX_OSERR) + self.install_package("inetutils-inetd") # ## On OpenVZ there is an issue using .tempdisk for /tmp as it breaks network on container after reboot. # @@ -437,42 +374,15 @@ class preFlightsChecks: return 'pure-ftpd-mysql' return 'pure-ftpd' + # Using shared function from install_utils @staticmethod def resFailed(distro, res): - if distro == ubuntu and res != 0: - return True - elif distro == centos and res != 0: - return True - return False + return install_utils.resFailed(distro, res) + # Using shared function from install_utils @staticmethod def call(command, distro, bracket, message, log=0, do_exit=0, code=os.EX_OK, shell=False): - finalMessage = 'Running: %s' % (message) - preFlightsChecks.stdOut(finalMessage, log) - count = 0 - while True: - if shell == False: - res = subprocess.call(shlex.split(command)) - else: - res = subprocess.call(command, shell=True) - - if preFlightsChecks.resFailed(distro, res): - count = count + 1 - finalMessage = 'Running %s failed. Running again, try number %s' % (message, str(count)) - preFlightsChecks.stdOut(finalMessage) - if count == 3: - fatal_message = '' - if do_exit: - fatal_message = '. Fatal error, see /var/log/installLogs.txt for full details' - - preFlightsChecks.stdOut("[ERROR] We are not able to run " + message + ' return code: ' + str(res) + - fatal_message + ".", 1, do_exit, code) - return False - else: - preFlightsChecks.stdOut('Successfully ran: %s.' % (message), log) - break - - return True + return install_utils.call(command, distro, bracket, message, log, do_exit, code, shell) def checkIfSeLinuxDisabled(self): try: @@ -505,11 +415,8 @@ class preFlightsChecks: def setup_account_cyberpanel(self): try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = "yum install sudo -y" - preFlightsChecks.call(command, self.distro, command, - command, - 1, 0, os.EX_OSERR) + if self.is_centos_family(): + self.install_package("sudo", silent=True) ## @@ -595,13 +502,7 @@ class preFlightsChecks: def install_psmisc(self): self.stdOut("Install psmisc") - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = "yum -y install psmisc" - else: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install psmisc" - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("psmisc") def download_install_CyberPanel(self, mysqlPassword, mysql): ## @@ -879,7 +780,7 @@ password="%s" command = "find /usr/local/CyberCP/ -name '*.pyc' -delete" preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - if self.distro == cent8 or self.distro == centos or self.distro == openeuler: + if self.is_centos_family(): command = 'chown root:pdns /etc/pdns/pdns.conf' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) @@ -934,24 +835,14 @@ password="%s" def install_unzip(self): self.stdOut("Install unzip") try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum -y install unzip' - else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install unzip' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("unzip") except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_unzip]") def install_zip(self): self.stdOut("Install zip") try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum -y install zip' - else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install zip' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("zip") except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_zip]") @@ -979,7 +870,7 @@ password="%s" ## Write secret phrase - rString = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(32)]) + rString = install_utils.generate_random_string(32) data = open('/usr/local/CyberCP/public/phpmyadmin/config.sample.inc.php', 'r').readlines() @@ -1044,11 +935,9 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; try: if self.distro == centos: - command = 'yum remove postfix -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.remove_package("postfix") elif self.distro == ubuntu: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y remove postfix' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.remove_package("postfix") self.stdOut("Install dovecot - do the install") @@ -1075,8 +964,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install debconf-utils' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("debconf-utils", silent=True) file_name = self.cwd + '/pf.unattend.text' pf = open(file_name, 'w') pf.write('postfix postfix/mailname string ' + str(socket.getfqdn() + '\n')) @@ -1413,13 +1301,8 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; ################################### Restart postix - command = 'systemctl enable postfix.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = 'systemctl start postfix.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('postfix', 'enable') + self.manage_service('postfix', 'start') ######################################## Permissions @@ -1433,18 +1316,12 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; ################################### Restart dovecot - command = 'systemctl enable dovecot.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('dovecot', 'enable') + self.manage_service('dovecot', 'start') ## - command = 'systemctl start dovecot.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = 'systemctl restart postfix.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('postfix', 'restart') ## chaging permissions for main.cf @@ -1479,8 +1356,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; writeToFile.writelines(items) writeToFile.close() - command = "systemctl restart dovecot" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('dovecot', 'restart') logging.InstallLog.writeToFile("Postfix and Dovecot configured") except BaseException as msg: @@ -1653,7 +1529,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; ###################################################### Email setup ends! def reStartLiteSpeed(self): - command = '%sbin/lswsctrl restart' % (self.server_root_path) + command = install_utils.format_restart_litespeed_command(self.server_root_path) preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) def removeUfw(self): @@ -1695,29 +1571,17 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; try: preFlightsChecks.stdOut("Enabling Firewall!") - if self.distro == ubuntu: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install firewalld' - else: - command = 'yum -y install firewalld' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("firewalld") ###### if self.distro == centos: # Not available in ubuntu - command = 'systemctl restart dbus' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('dbus', 'restart') - command = 'systemctl restart systemd-logind' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('systemd-logind', 'restart') - command = 'systemctl start firewalld' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ########## - - command = 'systemctl enable firewalld' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('firewalld', 'start') + self.manage_service('firewalld', 'enable') FirewallUtilities.addRule("tcp", "8090") FirewallUtilities.addRule("tcp", "7080") @@ -1768,19 +1632,14 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; os.chdir(self.cwd) if self.distro == ubuntu: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install gcc g++ make autoconf rcs" + self.install_package("gcc g++ make autoconf rcs") else: - command = 'yum -y install gcc gcc-c++ make autoconf glibc' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("gcc gcc-c++ make autoconf glibc") if self.distro == ubuntu: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install libpcre3 libpcre3-dev openssl libexpat1 libexpat1-dev libgeoip-dev" \ - " zlib1g zlib1g-dev libudns-dev whichman curl" + self.install_package("libpcre3 libpcre3-dev openssl libexpat1 libexpat1-dev libgeoip-dev zlib1g zlib1g-dev libudns-dev whichman curl") else: - command = 'yum -y install pcre-devel openssl-devel expat-devel geoip-devel zlib-devel udns-devel' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package("pcre-devel openssl-devel expat-devel geoip-devel zlib-devel udns-devel") command = 'tar zxf lscp.tar.gz -C /usr/local/' preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) @@ -1847,14 +1706,14 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; except: pass - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: + if self.is_centos_family(): command = 'adduser lscpd -M -d /usr/local/lscp' else: command = 'useradd lscpd -M -d /usr/local/lscp' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: + if self.is_centos_family(): command = 'groupadd lscpd' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) # Added group in useradd for Ubuntu @@ -2044,8 +1903,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) ## - command = 'systemctl enable lscpd.service' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('lscpd', 'enable') ## count = 0 @@ -2075,26 +1933,17 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; try: ## first install crontab - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum install cronie -y' + if self.is_centos_family(): + self.install_package('cronie') else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install cron' + self.install_package('cron') - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl enable crond' + if self.is_centos_family(): + self.manage_service('crond', 'enable') + self.manage_service('crond', 'start') else: - command = 'systemctl enable cron' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl start crond' - else: - command = 'systemctl start cron' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('cron', 'enable') + self.manage_service('cron', 'start') ## @@ -2152,12 +2001,10 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; command = 'chmod 600 %s' % (cronPath) preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl restart crond.service' + if self.is_centos_family(): + self.manage_service('crond', 'restart') else: - command = 'systemctl restart cron.service' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('cron', 'restart') except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [setup_cron]") @@ -2179,12 +2026,7 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; def install_rsync(self): try: - if self.distro == centos or self.distro == cent8 or self.distro == openeuler: - command = 'yum -y install rsync' - else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install rsync' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + self.install_package('rsync') except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [install_rsync]") @@ -2235,22 +2077,10 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; def installOpenDKIM(self): try: - if self.distro == centos: - command = 'yum -y install opendkim' - elif self.distro == cent8 or self.distro == openeuler: - command = 'dnf install opendkim -y' + if self.distro == cent8 or self.distro == openeuler or self.distro == ubuntu: + self.install_package('opendkim opendkim-tools') else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install opendkim' - - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) - - if self.distro == cent8 or self.distro == openeuler: - command = 'dnf install opendkim-tools -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - if self.distro == ubuntu: - command = 'apt install opendkim-tools -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.install_package('opendkim') command = 'mkdir -p /etc/opendkim/keys/' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) @@ -2307,16 +2137,9 @@ milter_default_action = accept #### Restarting Postfix and OpenDKIM - command = "systemctl start opendkim" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = "systemctl enable opendkim" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - ## - - command = "systemctl start postfix" - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('opendkim', 'start') + self.manage_service('opendkim', 'enable') + self.manage_service('postfix', 'start') except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [configureOpenDKIM]") @@ -2513,9 +2336,8 @@ milter_default_action = accept preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) else: - command = 'DEBIAN_FRONTEND=noninteractive apt-get update -y' - preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) - + # Skip apt-get update as it was already done in cyberpanel.sh + # Just install the package directly command = 'DEBIAN_FRONTEND=noninteractive apt-get install restic -y' preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) @@ -2847,8 +2669,6 @@ admin_password = "12345" """) writeToFile.close() - import randomPassword - content = """SetPassword('%s'); echo $oConfig->Save() ? 'Done' : 'Error'; -?>""" % (randomPassword.generate_pass()) +?>""" % (generate_pass()) writeToFile = open('/usr/local/CyberCP/public/snappymail.php', 'w') writeToFile.write(content) diff --git a/install/installCyberPanel.py b/install/installCyberPanel.py index c9cd42af7..dfb3a1a2d 100644 --- a/install/installCyberPanel.py +++ b/install/installCyberPanel.py @@ -3,63 +3,107 @@ import subprocess import os from mysqlUtilities import mysqlUtilities import installLog as logging -import randomPassword import errno import MySQLdb as mariadb import install from os.path import exists import time +import install_utils -# distros -centos = 0 -ubuntu = 1 -cent8 = 2 -openeuler = 3 +# distros - using from install_utils +centos = install_utils.centos +ubuntu = install_utils.ubuntu +cent8 = install_utils.cent8 +openeuler = install_utils.openeuler def get_Ubuntu_release(): - release = -1 - if exists("/etc/lsb-release"): - distro_file = "/etc/lsb-release" - with open(distro_file) as f: - for line in f: - if line[:16] == "DISTRIB_RELEASE=": - release = float(line[16:]) - - if release == -1: - print("Can't find distro release name in " + distro_file + " - fatal error") - - else: - logging.InstallLog.writeToFile("Can't find linux release file - fatal error") - print("Can't find linux release file - fatal error") - os._exit(os.EX_UNAVAILABLE) - - return release + return install_utils.get_Ubuntu_release(use_print=True, exit_on_error=True) -def FetchCloudLinuxAlmaVersionVersion(): - if os.path.exists('/etc/os-release'): - data = open('/etc/os-release', 'r').read() - if (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.9') > -1 or data.find('Anatoly Levchenko') > -1 or data.find('VERSION="8.') > -1): - return 'cl-89' - elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.8') > -1 or data.find('Anatoly Filipchenko') > -1): - return 'cl-88' - elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('9.4') > -1 or data.find('VERSION="9.') > -1): - return 'cl-88' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.9') > -1 or data.find('Midnight Oncilla') > -1 or data.find('VERSION="8.') > -1): - return 'al-88' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.7') > -1 or data.find('Stone Smilodon') > -1): - return 'al-87' - elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('9.4') > -1 or data.find('9.3') > -1 or data.find('Shamrock Pampas') > -1 or data.find('Seafoam Ocelot') > -1 or data.find('VERSION="9.') > -1): - return 'al-93' - else: - return -1 +# Using shared function from install_utils +FetchCloudLinuxAlmaVersionVersion = install_utils.FetchCloudLinuxAlmaVersionVersion class InstallCyberPanel: mysql_Root_password = "" mysqlPassword = "" CloudLinux8 = 0 + def install_package(self, package_name, options=""): + """Unified package installation across distributions""" + command, shell = install_utils.get_package_install_command(self.distro, package_name, options) + + # InstallCyberPanel always uses verbose mode (no silent option) + if self.distro == ubuntu: + return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, shell) + else: + # For non-Ubuntu, original code didn't pass shell parameter + return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + + def manage_service(self, service_name, action="start"): + """Unified service management""" + service_map = { + 'mariadb': 'mariadb', + 'pureftpd': 'pure-ftpd-mysql' if self.distro == ubuntu else 'pure-ftpd', + 'pdns': 'pdns' + } + + actual_service = service_map.get(service_name, service_name) + command = f'systemctl {action} {actual_service}' + return install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + + def modify_file_content(self, file_path, replacements): + """Generic file content modification""" + try: + with open(file_path, 'r') as f: + data = f.readlines() + + with open(file_path, 'w') as f: + for line in data: + modified_line = line + for old, new in replacements.items(): + if old in line: + modified_line = line.replace(old, new) + break + f.write(modified_line) + return True + except IOError as e: + logging.InstallLog.writeToFile(f'[ERROR] {str(e)} [modify_file_content]') + return False + + def copy_config_file(self, source_dir, dest_path, mysql_mode='One'): + """Handle configuration file copying with mode selection""" + # For directories like 'dns' vs 'dns-one', 'pure-ftpd' vs 'pure-ftpd-one' + # Default mode is 'One' which uses the -one directories + if mysql_mode == 'Two': + source_path = source_dir + else: + # Default mode 'One' uses directories with -one suffix + source_path = f"{source_dir}-one" + + # Determine the actual file to copy + if os.path.isdir(source_path): + # If it's a directory, we need to copy the whole directory + if os.path.exists(dest_path): + if os.path.isdir(dest_path): + shutil.rmtree(dest_path) + shutil.copytree(source_path, dest_path) + else: + # If source is a directory but dest is a file, find the config file + if os.path.isdir(source_dir) or os.path.isdir(f"{source_dir}-one"): + # Look for pdns.conf or similar config file + if dest_path.endswith('pdns.conf'): + source_file = os.path.join(source_path, 'pdns.conf') + elif dest_path.endswith('pureftpd-mysql.conf'): + source_file = os.path.join(source_path, 'pureftpd-mysql.conf') + else: + # Generic case - use basename of dest + source_file = os.path.join(source_path, os.path.basename(dest_path)) + + if os.path.exists(dest_path): + os.remove(dest_path) + shutil.copy(source_file, dest_path) + @staticmethod def ISARM(): @@ -109,31 +153,23 @@ class InstallCyberPanel: @staticmethod def stdOut(message, log=0, exit=0, code=os.EX_OK): - install.preFlightsChecks.stdOut(message, log, exit, code) + install_utils.stdOut(message, log, exit, code) def installLiteSpeed(self): if self.ent == 0: - if self.distro == ubuntu: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install openlitespeed" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - elif self.distro == centos: - command = 'yum install -y openlitespeed' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - else: - command = 'dnf install -y openlitespeed' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + self.install_package('openlitespeed') else: try: try: command = 'groupadd nobody' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) except: pass try: command = 'usermod -a -G nobody nobody' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) except: pass @@ -142,20 +178,20 @@ class InstallCyberPanel: else: command = 'wget https://www.litespeedtech.com/packages/6.0/lsws-6.2-ent-x86_64-linux.tar.gz' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) if InstallCyberPanel.ISARM(): command = 'tar zxf lsws-6.2-ent-aarch64-linux.tar.gz' else: command = 'tar zxf lsws-6.2-ent-x86_64-linux.tar.gz' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) if str.lower(self.serial) == 'trial': command = 'wget -q --output-document=lsws-6.2/trial.key http://license.litespeedtech.com/reseller/trial.key' if self.serial == '1111-2222-3333-4444': command = 'wget -q --output-document=/root/cyberpanel/install/lsws-6.2/trial.key http://license.litespeedtech.com/reseller/trial.key' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) else: writeSerial = open('lsws-6.2/serial.no', 'w') writeSerial.writelines(self.serial) @@ -167,13 +203,13 @@ class InstallCyberPanel: os.chdir('lsws-6.2') command = 'chmod +x install.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = 'chmod +x functions.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = './install.sh' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) os.chdir(self.cwd) confPath = '/usr/local/lsws/conf/' @@ -182,7 +218,7 @@ class InstallCyberPanel: shutil.copy('litespeed/httpd.conf', confPath) command = 'chown -R lsadm:lsadm ' + confPath - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [installLiteSpeed]") @@ -191,8 +227,8 @@ class InstallCyberPanel: return 1 def reStartLiteSpeed(self): - command = self.server_root_path + "bin/lswsctrl restart" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + command = install_utils.format_restart_litespeed_command(self.server_root_path) + install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) def fix_ols_configs(self): try: @@ -224,97 +260,63 @@ class InstallCyberPanel: try: InstallCyberPanel.stdOut("Changing default port to 80..", 1) - data = open(self.server_root_path + "conf/httpd_config.conf").readlines() + file_path = self.server_root_path + "conf/httpd_config.conf" + if self.modify_file_content(file_path, {"*:8088": "*:80"}): + InstallCyberPanel.stdOut("Default port is now 80 for OpenLiteSpeed!", 1) + else: + return 0 - writeDataToFile = open(self.server_root_path + "conf/httpd_config.conf", 'w') - - for items in data: - if (items.find("*:8088") > -1): - writeDataToFile.writelines(items.replace("*:8088", "*:80")) - else: - writeDataToFile.writelines(items) - - writeDataToFile.close() - - InstallCyberPanel.stdOut("Default port is now 80 for OpenLiteSpeed!", 1) - - except IOError as msg: + except Exception as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [changePortTo80]") return 0 return self.reStartLiteSpeed() def installAllPHPVersions(self): - + php_versions = ['71', '72', '73', '74', '80', '81', '82', '83'] + if self.distro == ubuntu: + # Install base PHP 7.x packages command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install ' \ 'lsphp7? lsphp7?-common lsphp7?-curl lsphp7?-dev lsphp7?-imap lsphp7?-intl lsphp7?-json ' \ 'lsphp7?-ldap lsphp7?-mysql lsphp7?-opcache lsphp7?-pspell lsphp7?-recode ' \ 'lsphp7?-sqlite3 lsphp7?-tidy' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp80*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp81*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp82*' - os.system(command) - - command = 'DEBIAN_FRONTEND=noninteractive apt-get -y install lsphp83*' - os.system(command) - + + # Install PHP 8.x versions + for version in php_versions[4:]: # 80, 81, 82, 83 + self.install_package(f'lsphp{version}*') + elif self.distro == centos: + # First install the group command = 'yum -y groupinstall lsphp-all' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1) - - ## only php 71 - if self.distro == centos: - command = 'yum install -y lsphp71* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 72 - command = 'yum install -y lsphp72* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 73 - command = 'yum install -y lsphp73* --skip-broken' - - subprocess.call(command, shell=True) - - ## only php 74 - command = 'yum install -y lsphp74* --skip-broken' - - subprocess.call(command, shell=True) - - command = 'yum install lsphp80* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp81* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp82* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'yum install lsphp83* -y --skip-broken' - subprocess.call(command, shell=True) - - if self.distro == cent8: - command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* --exclude lsphp73-pecl-zip --exclude *imagick* -y --skip-broken' - subprocess.call(command, shell=True) - - command = 'dnf install lsphp81* lsphp82* lsphp83* --exclude *imagick* -y --skip-broken' - subprocess.call(command, shell=True) - - if self.distro == openeuler: - command = 'dnf install lsphp71* lsphp72* lsphp73* lsphp74* lsphp80* lsphp81* lsphp82* lsphp83* -y' - subprocess.call(command, shell=True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + + InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1) + + # Install individual PHP versions + for version in php_versions: + self.install_package(f'lsphp{version}*', '--skip-broken') + + elif self.distro == cent8: + # Install PHP versions in batches with exclusions + exclude_flags = "--exclude lsphp73-pecl-zip --exclude *imagick*" + + # First batch: PHP 7.x and 8.0 + versions_batch1 = ' '.join([f'lsphp{v}*' for v in php_versions[:5]]) + self.install_package(versions_batch1, f'{exclude_flags} --skip-broken') + + # Second batch: PHP 8.1+ + versions_batch2 = ' '.join([f'lsphp{v}*' for v in php_versions[5:]]) + self.install_package(versions_batch2, f'{exclude_flags} --skip-broken') + + elif self.distro == openeuler: + # Install all PHP versions at once + all_versions = ' '.join([f'lsphp{v}*' for v in php_versions]) + self.install_package(all_versions) + + if self.distro != ubuntu: + InstallCyberPanel.stdOut("LiteSpeed PHPs successfully installed!", 1) def installMySQL(self, mysql): @@ -322,17 +324,14 @@ class InstallCyberPanel: if self.distro == ubuntu: - command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - - command = "DEBIAN_FRONTEND=noninteractive apt-get install apt-transport-https curl -y" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + command = 'DEBIAN_FRONTEND=noninteractive apt-get install software-properties-common apt-transport-https curl -y' + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = "mkdir -p /etc/apt/keyrings" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = "curl -o /etc/apt/keyrings/mariadb-keyring.pgp 'https://mariadb.org/mariadb_release_signing_key.pgp'" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) RepoPath = '/etc/apt/sources.list.d/mariadb.sources' RepoContent = f""" # MariaDB 10.11 repository list - created 2023-12-11 07:53 UTC @@ -349,15 +348,27 @@ Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp if get_Ubuntu_release() > 21.00: command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) - # WriteToFile = open(RepoPath, 'w') - # WriteToFile.write(RepoContent) - # WriteToFile.close() + result = install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR, True) + + # If the download fails, use manual repo configuration as fallback + if result != 1: + install_utils.writeToFile("MariaDB repo setup script failed, using manual configuration...") + RepoPath = '/etc/apt/sources.list.d/mariadb.list' + RepoContent = f"""# MariaDB 10.11 repository list - manual fallback +deb [arch=amd64,arm64,ppc64el,s390x signed-by=/usr/share/keyrings/mariadb-keyring.pgp] https://mirror.mariadb.org/repo/10.11/ubuntu {get_Ubuntu_code_name()} main +""" + # Download and add MariaDB signing key + command = 'mkdir -p /usr/share/keyrings && curl -fsSL https://mariadb.org/mariadb_release_signing_key.pgp | gpg --dearmor -o /usr/share/keyrings/mariadb-keyring.pgp' + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + + WriteToFile = open(RepoPath, 'w') + WriteToFile.write(RepoContent) + WriteToFile.close() command = 'DEBIAN_FRONTEND=noninteractive apt-get update -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = "DEBIAN_FRONTEND=noninteractive apt-get install mariadb-server -y" @@ -387,34 +398,34 @@ gpgcheck=1 if type == 'cl' and version >= 88: command = 'yum remove db-governor db-governor-mysql -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'yum install governor-mysql -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = '/usr/share/lve/dbgovernor/mysqlgovernor.py --mysql-version=mariadb106' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = '/usr/share/lve/dbgovernor/mysqlgovernor.py --install --yes' else: command = 'curl -LsS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | sudo bash -s -- --mariadb-server-version=10.11' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'yum remove mariadb* -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'sudo dnf -qy module disable mariadb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'sudo dnf module reset mariadb -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) command = 'dnf install MariaDB-server MariaDB-client MariaDB-backup -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR, True) ############## Start mariadb ###################### @@ -431,18 +442,13 @@ gpgcheck=1 command = 'mariadb -u root -e "' + passwordCMD + '"' - install.preFlightsChecks.call(command, self.distro, command, command, 0, 0, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 0, 0, os.EX_OSERR) def startMariaDB(self): if self.remotemysql == 'OFF': ############## Start mariadb ###################### - if self.distro == cent8 or self.distro == ubuntu: - command = 'systemctl start mariadb' - else: - command = "systemctl start mariadb" - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + self.manage_service('mariadb', 'start') ############## Enable mariadb at system startup ###################### @@ -451,12 +457,7 @@ gpgcheck=1 if os.path.exists('/etc/systemd/system/mariadb.service'): os.remove('/etc/systemd/system/mariadb.service') - if self.distro == ubuntu: - command = "systemctl enable mariadb" - else: - command = "systemctl enable mariadb" - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + self.manage_service('mariadb', 'enable') def fixMariaDB(self): self.stdOut("Setup MariaDB so it can support Cyberpanel's needs") @@ -489,49 +490,38 @@ gpgcheck=1 def installPureFTPD(self): if self.distro == ubuntu: - command = 'DEBIAN_FRONTEND=noninteractive apt install pure-ftpd-mysql -y' - os.system(command) + self.install_package('pure-ftpd-mysql') if get_Ubuntu_release() == 18.10: - command = 'wget https://rep.cyberpanel.net/pure-ftpd-common_1.0.47-3_all.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'wget https://rep.cyberpanel.net/pure-ftpd-mysql_1.0.47-3_amd64.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'dpkg --install --force-confold pure-ftpd-common_1.0.47-3_all.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - command = 'dpkg --install --force-confold pure-ftpd-mysql_1.0.47-3_amd64.deb' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - - elif self.distro == centos: - command = "yum install -y pure-ftpd" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) - elif self.distro == cent8 or self.distro == openeuler: - command = 'dnf install pure-ftpd -y' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + # Special handling for Ubuntu 18.10 + packages = [ + ('pure-ftpd-common_1.0.47-3_all.deb', 'wget https://rep.cyberpanel.net/pure-ftpd-common_1.0.47-3_all.deb'), + ('pure-ftpd-mysql_1.0.47-3_amd64.deb', 'wget https://rep.cyberpanel.net/pure-ftpd-mysql_1.0.47-3_amd64.deb') + ] + + for filename, wget_cmd in packages: + install_utils.call(wget_cmd, self.distro, wget_cmd, wget_cmd, 1, 1, os.EX_OSERR) + command = f'dpkg --install --force-confold {filename}' + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + else: + self.install_package('pure-ftpd') ####### Install pureftpd to system startup command = "systemctl enable " + install.preFlightsChecks.pureFTPDServiceName(self.distro) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) ###### FTP Groups and user settings settings command = 'groupadd -g 2001 ftpgroup' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = 'useradd -u 2001 -s /bin/false -d /bin/null -c "pureftpd user" -g ftpgroup ftpuser' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) def startPureFTPD(self): ############## Start pureftpd ###################### - if self.distro == ubuntu: - command = 'systemctl start pure-ftpd-mysql' - else: - command = 'systemctl start pure-ftpd' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + self.manage_service('pureftpd', 'start') def installPureFTPDConfigurations(self, mysql): try: @@ -550,22 +540,12 @@ gpgcheck=1 else: command = 'openssl req -x509 -nodes -days 7300 -newkey rsa:2048 -subj "/C=US/ST=Denial/L=Sprinal-ield/O=Dis/CN=www.example.com" -keyout /etc/ssl/private/pure-ftpd.pem -out /etc/ssl/private/pure-ftpd.pem' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) os.chdir(self.cwd) ftpdPath = "/etc/pure-ftpd" - if os.path.exists(ftpdPath): - shutil.rmtree(ftpdPath) - if mysql == 'Two': - shutil.copytree("pure-ftpd", ftpdPath) - else: - shutil.copytree("pure-ftpd-one", ftpdPath) - else: - if mysql == 'Two': - shutil.copytree("pure-ftpd", ftpdPath) - else: - shutil.copytree("pure-ftpd-one", ftpdPath) + self.copy_config_file("pure-ftpd", ftpdPath, mysql) if self.distro == ubuntu: try: @@ -592,13 +572,13 @@ gpgcheck=1 if self.remotemysql == 'ON': command = "sed -i 's|localhost|%s|g' %s" % (self.mysqlhost, ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = "sed -i 's|3306|%s|g' %s" % (self.mysqlport, ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = "sed -i 's|MYSQLSocket /var/lib/mysql/mysql.sock||g' %s" % (ftpConfPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) if self.distro == ubuntu: @@ -624,13 +604,13 @@ gpgcheck=1 subprocess.call(command, shell=True) command = 'ln -s /etc/pure-ftpd/conf/MySQLConfigFile /etc/pure-ftpd/auth/30mysql' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = 'ln -s /etc/pure-ftpd/conf/UnixAuthentication /etc/pure-ftpd/auth/65unix' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = 'systemctl restart pure-ftpd-mysql.service' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) @@ -639,10 +619,10 @@ gpgcheck=1 ### change mysql md5 to crypt command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/db/mysql.conf" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = "systemctl restart pure-ftpd-mysql.service" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) else: try: @@ -652,7 +632,7 @@ gpgcheck=1 if type == 'al' and version >= 90: command = "sed -i 's/MYSQLCrypt md5/MYSQLCrypt crypt/g' /etc/pure-ftpd/pureftpd-mysql.conf" - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) except: pass @@ -666,43 +646,33 @@ gpgcheck=1 def installPowerDNS(self): try: - if self.distro == ubuntu or self.distro == cent8 or self.distro == openeuler: - command = 'systemctl stop systemd-resolved' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - command = 'systemctl disable systemd-resolved.service' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + # Stop and disable systemd-resolved + self.manage_service('systemd-resolved', 'stop') + self.manage_service('systemd-resolved.service', 'disable') try: - os.rename('/etc/resolv.conf', 'etc/resolved.conf') + os.rename('/etc/resolv.conf', '/etc/resolv.conf.bak') except OSError as e: if e.errno != errno.EEXIST and e.errno != errno.ENOENT: InstallCyberPanel.stdOut("[ERROR] Unable to rename /etc/resolv.conf to install PowerDNS: " + str(e), 1, 1, os.EX_OSERR) - try: - os.remove('/etc/resolv.conf') - except OSError as e1: - InstallCyberPanel.stdOut( - "[ERROR] Unable to remove existing /etc/resolv.conf to install PowerDNS: " + - str(e1), 1, 1, os.EX_OSERR) - - # try: - # f = open('/etc/resolv.conf', 'a') - # f.write('nameserver 8.8.8.8') - # f.close() - # except IOError as e: - # InstallCyberPanel.stdOut("[ERROR] Unable to create /etc/resolv.conf: " + str(e) + - # ". This may need to be fixed manually as 'echo \"nameserver 8.8.8.8\"> " - # "/etc/resolv.conf'", 1, 1, os.EX_OSERR) + + # Create a temporary resolv.conf with Google DNS for package installation + try: + with open('/etc/resolv.conf', 'w') as f: + f.write('nameserver 8.8.8.8\n') + f.write('nameserver 8.8.4.4\n') + InstallCyberPanel.stdOut("Created temporary /etc/resolv.conf with Google DNS", 1) + except IOError as e: + InstallCyberPanel.stdOut("[ERROR] Unable to create /etc/resolv.conf: " + str(e), 1, 1, os.EX_OSERR) + # Install PowerDNS packages if self.distro == ubuntu: - command = "DEBIAN_FRONTEND=noninteractive apt-get -y install pdns-server pdns-backend-mysql" - os.system(command) + self.install_package('pdns-server pdns-backend-mysql') return 1 else: - command = 'yum -y install pdns pdns-backend-mysql' - - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + self.install_package('pdns pdns-backend-mysql') except BaseException as msg: logging.InstallLog.writeToFile('[ERROR] ' + str(msg) + " [powerDNS]") @@ -718,17 +688,7 @@ gpgcheck=1 else: dnsPath = "/etc/powerdns/pdns.conf" - if os.path.exists(dnsPath): - os.remove(dnsPath) - if mysql == 'Two': - shutil.copy("dns/pdns.conf", dnsPath) - else: - shutil.copy("dns-one/pdns.conf", dnsPath) - else: - if mysql == 'Two': - shutil.copy("dns/pdns.conf", dnsPath) - else: - shutil.copy("dns-one/pdns.conf", dnsPath) + self.copy_config_file("dns", dnsPath, mysql) data = open(dnsPath, "r").readlines() @@ -749,10 +709,10 @@ gpgcheck=1 if self.remotemysql == 'ON': command = "sed -i 's|gmysql-host=localhost|gmysql-host=%s|g' %s" % (self.mysqlhost, dnsPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) command = "sed -i 's|gmysql-port=3306|gmysql-port=%s|g' %s" % (self.mysqlport, dnsPath) - install.preFlightsChecks.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) + install_utils.call(command, self.distro, command, command, 1, 1, os.EX_OSERR) InstallCyberPanel.stdOut("PowerDNS configured!", 1) @@ -765,17 +725,14 @@ gpgcheck=1 ############## Start PowerDNS ###################### - command = 'systemctl enable pdns' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) - - command = 'systemctl start pdns' - install.preFlightsChecks.call(command, self.distro, command, command, 1, 0, os.EX_OSERR) + self.manage_service('pdns', 'enable') + self.manage_service('pdns', 'start') def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, publicip=None, remotemysql=None, mysqlhost=None, mysqldb=None, mysqluser=None, mysqlpassword=None, mysqlport=None): - InstallCyberPanel.mysqlPassword = randomPassword.generate_pass() - InstallCyberPanel.mysql_Root_password = randomPassword.generate_pass() + InstallCyberPanel.mysqlPassword = install_utils.generate_pass() + InstallCyberPanel.mysql_Root_password = install_utils.generate_pass() file_name = '/etc/cyberpanel/mysqlPassword' @@ -802,18 +759,18 @@ def Main(cwd, mysql, distro, ent, serial=None, port="8090", ftp=None, dns=None, try: command = 'chmod 640 %s' % (file_name) - install.preFlightsChecks.call(command, distro, '[chmod]', + install_utils.call(command, distro, '[chmod]', '', 1, 0, os.EX_OSERR) command = 'chown root:cyberpanel %s' % (file_name) - install.preFlightsChecks.call(command, distro, '[chmod]', + install_utils.call(command, distro, '[chmod]', '', 1, 0, os.EX_OSERR) except: pass if distro == centos: - InstallCyberPanel.mysqlPassword = randomPassword.generate_pass() + InstallCyberPanel.mysqlPassword = install_utils.generate_pass() else: InstallCyberPanel.mysqlPassword = InstallCyberPanel.mysql_Root_password diff --git a/install/install_utils.py b/install/install_utils.py new file mode 100644 index 000000000..80f3a58c3 --- /dev/null +++ b/install/install_utils.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python +""" +Common utility functions for CyberPanel installation scripts. +This module contains shared functions used by both install.py and installCyberPanel.py +""" + +import os +import sys +import time +import logging +import subprocess +import shlex +import secrets +import string +from os.path import exists + + +def FetchCloudLinuxAlmaVersionVersion(): + """ + Detect CloudLinux or AlmaLinux version by parsing /etc/os-release + Returns: version string or -1 if not found + """ + if os.path.exists('/etc/os-release'): + data = open('/etc/os-release', 'r').read() + if (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.9') > -1 or data.find('Anatoly Levchenko') > -1 or data.find('VERSION="8.') > -1): + return 'cl-89' + elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('8.8') > -1 or data.find('Anatoly Filipchenko') > -1): + return 'cl-88' + elif (data.find('CloudLinux') > -1 or data.find('cloudlinux') > -1) and (data.find('9.4') > -1 or data.find('VERSION="9.') > -1): + return 'cl-88' + elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.9') > -1 or data.find('Midnight Oncilla') > -1 or data.find('VERSION="8.') > -1): + return 'al-88' + elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('8.7') > -1 or data.find('Stone Smilodon') > -1): + return 'al-87' + elif (data.find('AlmaLinux') > -1 or data.find('almalinux') > -1) and (data.find('9.4') > -1 or data.find('9.3') > -1 or data.find('Shamrock Pampas') > -1 or data.find('Seafoam Ocelot') > -1 or data.find('VERSION="9.') > -1): + return 'al-93' + else: + return -1 + + +def get_Ubuntu_release(use_print=False, exit_on_error=True): + """ + Get Ubuntu release version from /etc/lsb-release + + Args: + use_print: If True, use print() for errors, otherwise use the provided output function + exit_on_error: If True, exit on error + + Returns: float release number or -1 if not found + """ + release = -1 + if exists("/etc/lsb-release"): + distro_file = "/etc/lsb-release" + with open(distro_file) as f: + for line in f: + if line[:16] == "DISTRIB_RELEASE=": + release = float(line[16:]) + + if release == -1: + error_msg = "Can't find distro release name in " + distro_file + " - fatal error" + if use_print: + print(error_msg) + else: + # This will be overridden by the calling module + return -1 + + else: + error_msg = "Can't find linux release file - fatal error" + if hasattr(logging, 'InstallLog'): + logging.InstallLog.writeToFile(error_msg) + if use_print: + print(error_msg) + if exit_on_error: + os._exit(os.EX_UNAVAILABLE) + + return release + + +# ANSI color codes +class Colors: + HEADER = '\033[95m' # Purple + INFO = '\033[94m' # Blue + SUCCESS = '\033[92m' # Green + WARNING = '\033[93m' # Yellow + ERROR = '\033[91m' # Red + ENDC = '\033[0m' # Reset + BOLD = '\033[1m' # Bold + UNDERLINE = '\033[4m' # Underline + + +def get_message_color(message): + """ + Determine the appropriate color based on message content + + Args: + message: The message to analyze + + Returns: + str: ANSI color code + """ + message_lower = message.lower() + + # Error messages + if any(word in message_lower for word in ['error', 'failed', 'fatal', 'critical', 'unable']): + return Colors.ERROR + + # Warning messages + elif any(word in message_lower for word in ['warning', 'warn', 'caution', 'alert']): + return Colors.WARNING + + # Success messages + elif any(word in message_lower for word in ['success', 'completed', 'installed', 'finished', 'done', 'enabled']): + return Colors.SUCCESS + + # Running/Processing messages + elif any(word in message_lower for word in ['running', 'installing', 'downloading', 'processing', 'starting', 'configuring']): + return Colors.INFO + + # Default color + else: + return Colors.HEADER + + +def stdOut(message, log=0, do_exit=0, code=os.EX_OK): + """ + Standard output function with timestamps, coloring, and logging + + Args: + message: Message to output + log: If 1, write to log file + do_exit: If 1, exit after outputting + code: Exit code to use if do_exit is 1 + """ + # Get appropriate color for the message + color = get_message_color(message) + + # Check if terminal supports color + try: + # Check if output is to a terminal + if not sys.stdout.isatty(): + color = '' + color_end = '' + else: + color_end = Colors.ENDC + except: + color = '' + color_end = '' + + # Format timestamps + timestamp = time.strftime("%m.%d.%Y_%H-%M-%S") + + print("\n\n") + print(f"{color}[{timestamp}] #########################################################################{color_end}\n") + print(f"{color}[{timestamp}] {message}{color_end}\n") + print(f"{color}[{timestamp}] #########################################################################{color_end}\n") + + if log and hasattr(logging, 'InstallLog'): + logging.InstallLog.writeToFile(message) + if do_exit: + if hasattr(logging, 'InstallLog'): + logging.InstallLog.writeToFile(message) + sys.exit(code) + + +def format_restart_litespeed_command(server_root_path): + """ + Format the LiteSpeed restart command + + Args: + server_root_path: Root path of the server installation + + Returns: Formatted command string + """ + return '%sbin/lswsctrl restart' % (server_root_path) + + +# Distribution constants +ubuntu = 0 +centos = 1 +cent8 = 2 +openeuler = 3 + + +def get_distro(): + """ + Detect Linux distribution + + Returns: Distribution constant (ubuntu, centos, cent8, or openeuler) + """ + distro = -1 + distro_file = "" + if exists("/etc/lsb-release"): + distro_file = "/etc/lsb-release" + with open(distro_file) as f: + for line in f: + if line == "DISTRIB_ID=Ubuntu\n": + distro = ubuntu + + elif exists("/etc/redhat-release"): + distro_file = "/etc/redhat-release" + distro = centos + + data = open('/etc/redhat-release', 'r').read() + + if data.find('CentOS Linux release 8') > -1: + return cent8 + ## if almalinux 9 then pretty much same as cent8 + if data.find('AlmaLinux release 8') > -1 or data.find('AlmaLinux release 9') > -1: + return cent8 + if data.find('Rocky Linux release 8') > -1 or data.find('Rocky Linux 8') > -1 or data.find('rocky:8') > -1: + return cent8 + if data.find('CloudLinux 8') or data.find('cloudlinux 8'): + return cent8 + + else: + if exists("/etc/openEuler-release"): + distro_file = "/etc/openEuler-release" + distro = openeuler + + else: + if hasattr(logging, 'InstallLog'): + logging.InstallLog.writeToFile("Can't find linux release file - fatal error") + print("Can't find linux release file - fatal error") + os._exit(os.EX_UNAVAILABLE) + + if distro == -1: + error_msg = "Can't find distro name in " + distro_file + " - fatal error" + if hasattr(logging, 'InstallLog'): + logging.InstallLog.writeToFile(error_msg) + print(error_msg) + os._exit(os.EX_UNAVAILABLE) + + return distro + + +def get_package_install_command(distro, package_name, options=""): + """ + Get the package installation command for a specific distribution + + Args: + distro: Distribution constant + package_name: Name of the package to install + options: Additional options for the package manager + + Returns: + tuple: (command, shell) where shell indicates if shell=True is needed + """ + if distro == ubuntu: + command = f"DEBIAN_FRONTEND=noninteractive apt-get -y install {package_name} {options}" + shell = True + elif distro == centos: + command = f"yum install -y {package_name} {options}" + shell = False + else: # cent8, openeuler + command = f"dnf install -y {package_name} {options}" + shell = False + + return command, shell + + +def get_package_remove_command(distro, package_name): + """ + Get the package removal command for a specific distribution + + Args: + distro: Distribution constant + package_name: Name of the package to remove + + Returns: + tuple: (command, shell) where shell indicates if shell=True is needed + """ + if distro == ubuntu: + command = f"DEBIAN_FRONTEND=noninteractive apt-get -y remove {package_name}" + shell = True + elif distro == centos: + command = f"yum remove -y {package_name}" + shell = False + else: # cent8, openeuler + command = f"dnf remove -y {package_name}" + shell = False + + return command, shell + + +def resFailed(distro, res): + """ + Check if a command execution result indicates failure + + Args: + distro: Distribution constant + res: Return code from subprocess + + Returns: + bool: True if failed, False if successful + """ + if distro == ubuntu and res != 0: + return True + elif distro == centos and res != 0: + return True + return False + + +def call(command, distro, bracket, message, log=0, do_exit=0, code=os.EX_OK, shell=False): + """ + Execute a shell command with retry logic and error handling + + Args: + command: Command to execute + distro: Distribution constant + bracket: Not used (kept for compatibility) + message: Description of the command for logging + log: If 1, write to log file + do_exit: If 1, exit on failure + code: Exit code to use if do_exit is 1 + shell: If True, execute through shell + + Returns: + bool: True if successful, False if failed + """ + finalMessage = 'Running: %s' % (message) + stdOut(finalMessage, log) + count = 0 + while True: + if shell == False: + res = subprocess.call(shlex.split(command)) + else: + res = subprocess.call(command, shell=True) + + if resFailed(distro, res): + count = count + 1 + finalMessage = 'Running %s failed. Running again, try number %s' % (message, str(count)) + stdOut(finalMessage) + if count == 3: + fatal_message = '' + if do_exit: + fatal_message = '. Fatal error, see /var/log/installLogs.txt for full details' + + stdOut("[ERROR] We are not able to run " + message + ' return code: ' + str(res) + + fatal_message + ".", 1, do_exit, code) + return False + else: + stdOut('Successfully ran: %s.' % (message), log) + break + + return True + + +# Character sets for password generation (kept for backward compatibility) +char_set = { + 'small': 'abcdefghijklmnopqrstuvwxyz', + 'nums': '0123456789', + 'big': 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +} + + +def generate_pass(length=14): + """ + Generate a cryptographically secure random password + + Args: + length: Length of the password to generate (default 14) + + Returns: + str: Random password containing uppercase, lowercase letters and digits + """ + alphabet = string.ascii_letters + string.digits + return ''.join(secrets.choice(alphabet) for _ in range(length)) + + +def generate_random_string(length=32, include_special=False): + """ + Generate a random string with optional special characters + + Args: + length: Length of the string to generate + include_special: If True, include special characters + + Returns: + str: Random string + """ + alphabet = string.ascii_letters + string.digits + if include_special: + alphabet += string.punctuation + return ''.join(secrets.choice(alphabet) for _ in range(length)) diff --git a/plogical/sslUtilities.py b/plogical/sslUtilities.py index 804decf54..2eb185f5e 100644 --- a/plogical/sslUtilities.py +++ b/plogical/sslUtilities.py @@ -579,7 +579,7 @@ context /.well-known/acme-challenge { return 1 @staticmethod - def obtainSSLForADomain(virtualHostName, adminEmail, sslpath, aliasDomain=None): + def obtainSSLForADomain(virtualHostName, adminEmail, sslpath, aliasDomain=None, isHostname=False): from plogical.acl import ACLManager from plogical.sslv2 import sslUtilities as sslv2 from plogical.customACME import CustomACME @@ -609,11 +609,11 @@ context /.well-known/acme-challenge { # Start with just the main domain domains = [virtualHostName] - # Check if www subdomain has DNS records before adding it - if sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): + # Check if www subdomain has DNS records before adding it (skip for hostnames) + if not isHostname and sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): domains.append(f'www.{virtualHostName}') logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has DNS records, including in SSL request") - else: + elif not isHostname: logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has no DNS records, excluding from SSL request") if aliasDomain: @@ -648,11 +648,11 @@ context /.well-known/acme-challenge { # Start with just the main domain domains = [virtualHostName] - # Check if www subdomain has DNS records before adding it - if sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): + # Check if www subdomain has DNS records before adding it (skip for hostnames) + if not isHostname and sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): domains.append(f'www.{virtualHostName}') logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has DNS records, including in SSL request") - else: + elif not isHostname: logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has no DNS records, excluding from SSL request") if aliasDomain: @@ -692,16 +692,17 @@ context /.well-known/acme-challenge { # Build domain list for acme.sh domain_list = " -d " + virtualHostName - # Check if www subdomain has DNS records - if sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): + # Check if www subdomain has DNS records (skip for hostnames) + if not isHostname and sslUtilities.checkDNSRecords(f'www.{virtualHostName}'): domain_list += " -d www." + virtualHostName logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has DNS records, including in acme.sh SSL request") - else: + elif not isHostname: logging.CyberCPLogFileWriter.writeToFile(f"www.{virtualHostName} has no DNS records, excluding from acme.sh SSL request") command = acmePath + " --issue" + domain_list \ + ' --cert-file ' + existingCertPath + '/cert.pem' + ' --key-file ' + existingCertPath + '/privkey.pem' \ - + ' --fullchain-file ' + existingCertPath + '/fullchain.pem' + ' -w /usr/local/lsws/Example/html -k ec-256 --force --staging' + + ' --fullchain-file ' + existingCertPath + '/fullchain.pem' + ' -w /usr/local/lsws/Example/html -k ec-256 --force --staging' \ + + ' --webroot-path /usr/local/lsws/Example/html' if ProcessUtilities.decideServer() == ProcessUtilities.OLS: result = subprocess.run(command, capture_output=True, universal_newlines=True, shell=True) @@ -711,7 +712,8 @@ context /.well-known/acme-challenge { if result.returncode == 0: command = acmePath + " --issue" + domain_list \ + ' --cert-file ' + existingCertPath + '/cert.pem' + ' --key-file ' + existingCertPath + '/privkey.pem' \ - + ' --fullchain-file ' + existingCertPath + '/fullchain.pem' + ' -w /usr/local/lsws/Example/html -k ec-256 --force --server letsencrypt' + + ' --fullchain-file ' + existingCertPath + '/fullchain.pem' + ' -w /usr/local/lsws/Example/html -k ec-256 --force --server letsencrypt' \ + + ' --webroot-path /usr/local/lsws/Example/html' result = subprocess.run(command, capture_output=True, universal_newlines=True, shell=True) @@ -763,9 +765,37 @@ context /.well-known/acme-challenge { return 0 -def issueSSLForDomain(domain, adminEmail, sslpath, aliasDomain=None): +def issueSSLForDomain(domain, adminEmail, sslpath, aliasDomain=None, isHostname=False): try: - if sslUtilities.obtainSSLForADomain(domain, adminEmail, sslpath, aliasDomain) == 1: + # Check if certificate already exists and try to renew it first + existingCertPath = '/etc/letsencrypt/live/' + domain + '/fullchain.pem' + if os.path.exists(existingCertPath): + logging.CyberCPLogFileWriter.writeToFile(f"Certificate exists for {domain}, attempting renewal...") + + # Try to renew using acme.sh + acmePath = '/root/.acme.sh/acme.sh' + if os.path.exists(acmePath): + # First set the webroot path for the domain + command = f'{acmePath} --update-account --accountemail {adminEmail}' + subprocess.call(command, shell=True) + + # Build domain list for renewal + renewal_domains = f'-d {domain}' + if not isHostname and sslUtilities.checkDNSRecords(f'www.{domain}'): + renewal_domains += f' -d www.{domain}' + + # Try to renew with explicit webroot + command = f'{acmePath} --renew {renewal_domains} --webroot /usr/local/lsws/Example/html --force' + result = subprocess.run(command, capture_output=True, text=True, shell=True) + + if result.returncode == 0: + logging.CyberCPLogFileWriter.writeToFile(f"Successfully renewed SSL for {domain}") + if sslUtilities.installSSLForDomain(domain, adminEmail) == 1: + return [1, "None"] + else: + logging.CyberCPLogFileWriter.writeToFile(f"Renewal failed for {domain}, falling back to new issuance") + + if sslUtilities.obtainSSLForADomain(domain, adminEmail, sslpath, aliasDomain, isHostname) == 1: if sslUtilities.installSSLForDomain(domain, adminEmail) == 1: return [1, "None"] else: diff --git a/plogical/upgrade.py b/plogical/upgrade.py index 1a689dede..bf3d4aee6 100644 --- a/plogical/upgrade.py +++ b/plogical/upgrade.py @@ -894,6 +894,63 @@ $cfg['Servers'][$i]['LogoutURL'] = 'phpmyadminsignin.php?logout'; except: pass + # AI Scanner Scheduled Scans Tables + try: + cursor.execute(''' + CREATE TABLE `ai_scanner_scheduled_scans` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `admin_id` integer NOT NULL, + `name` varchar(200) NOT NULL, + `domains` longtext NOT NULL, + `frequency` varchar(20) NOT NULL DEFAULT 'weekly', + `scan_type` varchar(20) NOT NULL DEFAULT 'full', + `time_of_day` time NOT NULL, + `day_of_week` integer DEFAULT NULL, + `day_of_month` integer DEFAULT NULL, + `status` varchar(20) NOT NULL DEFAULT 'active', + `last_run` datetime(6) DEFAULT NULL, + `next_run` datetime(6) DEFAULT NULL, + `created_at` datetime(6) NOT NULL, + `updated_at` datetime(6) NOT NULL, + `email_notifications` bool NOT NULL DEFAULT 1, + `notification_emails` longtext NOT NULL DEFAULT '', + `notify_on_threats` bool NOT NULL DEFAULT 1, + `notify_on_completion` bool NOT NULL DEFAULT 0, + `notify_on_failure` bool NOT NULL DEFAULT 1, + KEY `ai_scanner_scheduled_scans_admin_id_idx` (`admin_id`), + KEY `ai_scanner_scheduled_scans_status_next_run_idx` (`status`, `next_run`), + CONSTRAINT `ai_scanner_scheduled_scans_admin_id_fk` FOREIGN KEY (`admin_id`) + REFERENCES `loginSystem_administrator` (`id`) ON DELETE CASCADE + ) + ''') + except: + pass + + try: + cursor.execute(''' + CREATE TABLE `ai_scanner_scheduled_executions` ( + `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, + `scheduled_scan_id` integer NOT NULL, + `execution_time` datetime(6) NOT NULL, + `status` varchar(20) NOT NULL DEFAULT 'pending', + `domains_scanned` longtext NOT NULL DEFAULT '', + `total_scans` integer NOT NULL DEFAULT 0, + `successful_scans` integer NOT NULL DEFAULT 0, + `failed_scans` integer NOT NULL DEFAULT 0, + `total_cost` decimal(10,6) NOT NULL DEFAULT 0.000000, + `scan_ids` longtext NOT NULL DEFAULT '', + `error_message` longtext DEFAULT NULL, + `started_at` datetime(6) DEFAULT NULL, + `completed_at` datetime(6) DEFAULT NULL, + KEY `ai_scanner_scheduled_executions_scheduled_scan_id_idx` (`scheduled_scan_id`), + KEY `ai_scanner_scheduled_executions_execution_time_idx` (`execution_time` DESC), + CONSTRAINT `ai_scanner_scheduled_executions_scheduled_scan_id_fk` FOREIGN KEY (`scheduled_scan_id`) + REFERENCES `ai_scanner_scheduled_scans` (`id`) ON DELETE CASCADE + ) + ''') + except: + pass + try: cursor.execute( 'CREATE TABLE `loginSystem_acl` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(50) NOT NULL UNIQUE, `adminStatus` integer NOT NULL DEFAULT 0, `versionManagement` integer NOT NULL DEFAULT 0, `createNewUser` integer NOT NULL DEFAULT 0, `deleteUser` integer NOT NULL DEFAULT 0, `resellerCenter` integer NOT NULL DEFAULT 0, `changeUserACL` integer NOT NULL DEFAULT 0, `createWebsite` integer NOT NULL DEFAULT 0, `modifyWebsite` integer NOT NULL DEFAULT 0, `suspendWebsite` integer NOT NULL DEFAULT 0, `deleteWebsite` integer NOT NULL DEFAULT 0, `createPackage` integer NOT NULL DEFAULT 0, `deletePackage` integer NOT NULL DEFAULT 0, `modifyPackage` integer NOT NULL DEFAULT 0, `createDatabase` integer NOT NULL DEFAULT 0, `deleteDatabase` integer NOT NULL DEFAULT 0, `listDatabases` integer NOT NULL DEFAULT 0, `createNameServer` integer NOT NULL DEFAULT 0, `createDNSZone` integer NOT NULL DEFAULT 0, `deleteZone` integer NOT NULL DEFAULT 0, `addDeleteRecords` integer NOT NULL DEFAULT 0, `createEmail` integer NOT NULL DEFAULT 0, `deleteEmail` integer NOT NULL DEFAULT 0, `emailForwarding` integer NOT NULL DEFAULT 0, `changeEmailPassword` integer NOT NULL DEFAULT 0, `dkimManager` integer NOT NULL DEFAULT 0, `createFTPAccount` integer NOT NULL DEFAULT 0, `deleteFTPAccount` integer NOT NULL DEFAULT 0, `listFTPAccounts` integer NOT NULL DEFAULT 0, `createBackup` integer NOT NULL DEFAULT 0, `restoreBackup` integer NOT NULL DEFAULT 0, `addDeleteDestinations` integer NOT NULL DEFAULT 0, `scheduleBackups` integer NOT NULL DEFAULT 0, `remoteBackups` integer NOT NULL DEFAULT 0, `manageSSL` integer NOT NULL DEFAULT 0, `hostnameSSL` integer NOT NULL DEFAULT 0, `mailServerSSL` integer NOT NULL DEFAULT 0)') @@ -3076,6 +3133,13 @@ vmail command = """sed -i '/CyberCP/d' /etc/crontab""" Upgrade.executioner(command, command, 0, True) + # Ensure log directory exists for scheduled scans + if not os.path.exists('/usr/local/lscp/logs'): + try: + os.makedirs('/usr/local/lscp/logs', mode=0o755) + except: + pass + if os.path.exists('/usr/local/lsws/conf/httpd.conf'): # Setup /usr/local/lsws/conf/httpd.conf to use new Logformat standard for better stats and accesslogs command = """sed -i "s|^LogFormat.*|LogFormat '%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"' combined|g" /usr/local/lsws/conf/httpd.conf""" @@ -3109,6 +3173,7 @@ vmail 0 0 * * 4 /usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/renew.py >/dev/null 2>&1 7 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null */3 * * * * if ! find /home/*/public_html/ -maxdepth 2 -type f -newer /usr/local/lsws/cgid -name '.htaccess' -exec false {} +; then /usr/local/lsws/bin/lswsctrl restart; fi +* * * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py run_scheduled_scans >/usr/local/lscp/logs/scheduled_scans.log 2>&1 """ writeToFile = open(cronPath, 'w') @@ -3133,6 +3198,15 @@ vmail 0 1 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py '1 Day' 0 0 */3 * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py '3 Days' 0 0 * * 0 /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py '1 Week' +""" + writeToFile = open(cronPath, 'a') + writeToFile.write(content) + writeToFile.close() + + # Add AI Scanner scheduled scans cron job if missing + if data.find('run_scheduled_scans') == -1: + content = """ +* * * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py run_scheduled_scans >/usr/local/lscp/logs/scheduled_scans.log 2>&1 """ writeToFile = open(cronPath, 'a') writeToFile.write(content) @@ -3149,6 +3223,7 @@ vmail 7 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null 0 0 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py Daily 0 0 * * 0 /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py Weekly +* * * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py run_scheduled_scans >/usr/local/lscp/logs/scheduled_scans.log 2>&1 """ writeToFile = open(cronPath, 'w') writeToFile.write(content) diff --git a/plogical/virtualHostUtilities.py b/plogical/virtualHostUtilities.py index e50d42ed3..c0096bd75 100644 --- a/plogical/virtualHostUtilities.py +++ b/plogical/virtualHostUtilities.py @@ -966,7 +966,7 @@ local_name %s { adminEmail = "email@" + virtualHost - retValues = sslUtilities.issueSSLForDomain(virtualHost, adminEmail, path) + retValues = sslUtilities.issueSSLForDomain(virtualHost, adminEmail, path, None, isHostname=True) if retValues[0] == 0: print("0," + str(retValues[1])) @@ -1042,7 +1042,7 @@ local_name %s { srcPrivKey = '/etc/letsencrypt/live/' + virtualHost + '/privkey.pem' adminEmail = "email@" + virtualHost - retValues = sslUtilities.issueSSLForDomain(virtualHost, adminEmail, path) + retValues = sslUtilities.issueSSLForDomain(virtualHost, adminEmail, path, None, isHostname=True) if retValues[0] == 0: print("0," + str(retValues[1])) diff --git a/static/baseTemplate/assets/finalBase/finalBase.css b/static/baseTemplate/assets/finalBase/finalBase.css index 65e913913..af337ac4e 100755 --- a/static/baseTemplate/assets/finalBase/finalBase.css +++ b/static/baseTemplate/assets/finalBase/finalBase.css @@ -1653,7 +1653,27 @@ @charset "UTF-8";.fc-button .ui-icon,.fc-content,.fc-view{position:relative}.fc-cell-overlay,.fc-grid .fc-other-month .fc-day-number{opacity:.3;filter:alpha(opacity=30)}.carousel-caption,.carousel-control{color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.6)}.irs,.jcrop-tracker{-webkit-touch-callout:none}.dd-dragel,.xchart .color2 .line .fill,.xchart .color3 .line .fill,.xchart .color4 .line .fill,.xchart .color5 .line .fill,.xchart .color6 .line .fill,.xchart .color7 .line .fill,.xchart .color8 .line .fill,.xchart .color9 .line .fill{pointer-events:none}.ui-accordion .ui-accordion-header{font-size:15px;font-weight:700;position:relative;display:block;min-height:0;margin-top:2px;padding:10px;cursor:pointer;border-width:1px;border-style:solid}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{margin-right:10px}.ui-accordion .ui-accordion-content{overflow:hidden;padding:15px 0;border-top:0}.fc{text-align:left;direction:ltr}.fc table{border-spacing:0;border-collapse:collapse}.fc-agenda table,table.fc-border-separate{border-collapse:separate}.fc td,.fc th{padding:0;vertical-align:top}.fc-header td{white-space:nowrap}.fc-header-left{width:25%;text-align:left}.fc-header-center{text-align:center}.fc-header-right,.fc-rtl .fc-event{text-align:right}.fc-header-right{width:25%}.fc-event-inner,.fc-view{width:100%;overflow:hidden}.fc-header-title{display:inline-block;vertical-align:top}.fc-header-title h2{font-size:20px;margin-top:7px;white-space:nowrap}.fc .fc-header-space{padding-left:10px}.fc-header .fc-button{margin-bottom:1em;vertical-align:top;margin-right:-1px}.fc-header .fc-corner-right,.fc-header .ui-corner-right{margin-right:0}.fc-header .fc-state-hover,.fc-header .ui-state-hover{z-index:2}.fc-header .fc-state-down{z-index:3}.fc-header .fc-state-active,.fc-header .ui-state-active{z-index:4}.fc-content{z-index:1;clear:both;zoom:1}.fc-widget-content,.fc-widget-header{border-width:1px;border-style:solid}.fc-state-highlight{background:#fcf8e3}.fc-cell-overlay{background:#bce8f1}.fc-icon-left-single-arrow:after{content:'\f104'}.fc-icon-right-single-arrow:after{content:'\f105'}.fc-icon-left-double-arrow:after{content:'\f100'}.fc-icon-right-double-arrow:after{content:'\f101'}.fc-button .ui-icon{top:50%;float:left;margin-top:-8px}.fc-event-container>*{z-index:8}.fc-event-container>.ui-draggable-dragging,.fc-event-container>.ui-resizable-resizing{z-index:9}.fc-event{font-size:11px;padding:3px;cursor:default}a.fc-event{text-decoration:none}.fc-event-draggable,a.fc-event{cursor:pointer}.fc-agenda-days th,.fc-grid th{text-align:center}.fc-event-inner{height:100%}.fc-event-time,.fc-event-title{padding:0 1px}.fc .ui-resizable-handle{font-size:300%;line-height:50%;position:absolute;z-index:99999;display:block;overflow:hidden}.fc-event-hori{margin-bottom:1px;border-width:1px 0}.fc-ltr .fc-event-hori.fc-event-start,.fc-rtl .fc-event-hori.fc-event-end{border-left-width:1px;border-top-left-radius:3px;border-bottom-left-radius:3px}.fc-ltr .fc-event-hori.fc-event-end,.fc-rtl .fc-event-hori.fc-event-start{border-right-width:1px;border-top-right-radius:3px;border-bottom-right-radius:3px}.fc-event-hori .ui-resizable-e{top:0!important;right:-3px!important;width:7px!important;height:100%!important;cursor:e-resize}.fc-event-hori .ui-resizable-w{top:0!important;left:-3px!important;width:7px!important;height:100%!important;cursor:w-resize}.fc-border-separate td,.fc-border-separate th{border-width:1px 0 0 1px}.fc-agenda-days .fc-agenda-axis,.fc-border-separate td.fc-last,.fc-border-separate th.fc-last{border-right-width:1px}.fc-border-separate tr.fc-last td,.fc-border-separate tr.fc-last th{border-bottom-width:1px}.fc-border-separate tbody tr.fc-first td,.fc-border-separate tbody tr.fc-first th{border-top-width:0}.fc .fc-week-number{width:22px;text-align:center}.fc .fc-week-number div{padding:0 2px}.fc-grid .fc-day-number{float:right;padding:0 2px}.fc-grid .fc-day-content{clear:both;padding:2px 2px 1px}.fc-grid .fc-event-time{font-weight:700}.fc-rtl .fc-grid .fc-day-number{float:left}.fc-rtl .fc-grid .fc-event-time{float:right}.fc-agenda .fc-agenda-axis{font-weight:400;width:50px;padding:0 3px;text-align:right;vertical-align:middle}.fc-agenda-slots .fc-agenda-axis{white-space:nowrap}.fc-agenda .fc-week-number{font-weight:700}.fc-agenda .fc-day-content{padding:2px 2px 1px}.fc-agenda-days .fc-col0{border-left-width:0}.fc-agenda-allday th{border-width:0 1px}.fc-agenda-allday .fc-day-content{min-height:33px}.fc-agenda-divider-inner{overflow:hidden;height:2px}.fc-widget-header .fc-agenda-divider-inner{background:#eee}.fc-agenda-slots th{border-width:1px 1px 0}.fc-agenda-slots td{border-width:1px 0 0;background:0 0}.fc-agenda-slots td div{height:20px}.fc-agenda-slots tr.fc-slot0 td,.fc-agenda-slots tr.fc-slot0 th{border-top-width:0}.fc-agenda-slots tr.fc-minor td,.fc-agenda-slots tr.fc-minor th{border-top-style:dotted}.fc-event-vert{border-width:0 1px}.fc-event-vert.fc-event-start{border-top-width:1px;border-top-left-radius:3px;border-top-right-radius:3px}.fc-event-vert.fc-event-end{border-bottom-width:1px;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.fc-event-vert .fc-event-time{font-size:10px;white-space:nowrap}.fc-event-vert .fc-event-inner{position:relative;z-index:2}.fc-event-vert .fc-event-bg{position:absolute;z-index:1;top:0;left:0;width:100%;height:100%;opacity:.25;background:#fff;filter:alpha(opacity=25)}.carousel,.carousel-inner{position:relative}.fc-event-vert .ui-resizable-s{font-family:monospace;font-size:11px!important;line-height:8px!important;bottom:0!important;overflow:hidden!important;width:100%!important;height:8px!important;cursor:s-resize;text-align:center}.carousel-inner{overflow:hidden;width:100%}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>a>img,.carousel-inner>.item>img{line-height:1}@media all and (transform-3d),(-webkit-transform-3d){.carousel-inner>.item{-webkit-transition:-webkit-transform .6s ease-in-out;-o-transition:-o-transform .6s ease-in-out;transition:transform .6s ease-in-out;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-perspective:1000;perspective:1000}.carousel-inner>.item.active.right,.carousel-inner>.item.next{left:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.carousel-inner>.item.active.left,.carousel-inner>.item.prev{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.carousel-inner>.item.active,.carousel-inner>.item.next.left,.carousel-inner>.item.prev.right{left:0;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.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{font-size:20px;position:absolute;top:0;bottom:0;left:0;width:15%;text-align:center;opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.5) 0,rgba(0,0,0,.0001) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.5)),to(rgba(0,0,0,.0001)));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{right:0;left:auto;background-image:-webkit-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-o-linear-gradient(left,rgba(0,0,0,.0001) 0,rgba(0,0,0,.5) 100%);background-image:-webkit-gradient(linear,left top,right top,from(rgba(0,0,0,.0001)),to(rgba(0,0,0,.5)));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:focus,.carousel-control:hover{text-decoration:none;opacity:.9;color:#fff;outline:0;filter:alpha(opacity=90)}.carousel-control .icon-chevron-left,.carousel-control .icon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{position:absolute;z-index:5;top:50%;display:inline-block}.carousel-control .icon-chevron-left,.carousel-control .icon-prev{left:50%;margin-left:-10px}.carousel-control .icon-chevron-right,.carousel-control .icon-next{right:50%;margin-right:-10px}.carousel-control .icon-next,.carousel-control .icon-prev{font-family:serif;width:20px;height:20px;margin-top:-10px}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;z-index:15;bottom:10px;left:50%;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;cursor:pointer;text-indent:-999px;border:1px solid #fff;border-radius:10px;background-color:#000\9;background-color:rgba(0,0,0,0)}.xchart .color2.comp .fill,.xchart .color3.comp .fill,.xchart .color4.comp .fill,.xchart .color5.comp .fill,.xchart .color6.comp .fill,.xchart .color7.comp .fill,.xchart .color8.comp .fill,.xchart .color9.comp .fill{display:none}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;z-index:10;right:15%;bottom:20px;left:15%;padding-top:20px;padding-bottom:20px;text-align:center}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .icon-chevron-left,.carousel-control .icon-chevron-right,.carousel-control .icon-next,.carousel-control .icon-prev{font-size:30px;width:30px;height:30px;margin-top:-15px}.carousel-control .icon-chevron-left,.carousel-control .icon-prev{margin-left:-15px}.carousel-control .icon-chevron-right,.carousel-control .icon-next{margin-right:-15px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.lg-gauge,.md-gauge,.sm-gauge,.xl-gauge,.xs-gauge{margin:0 auto}.xs-gauge{width:90px;height:70px}.sm-gauge{width:130px;height:100px}.md-gauge{width:170px;height:120px}.lg-gauge{width:240px;height:150px}.xl-gauge{width:340px;height:180px}.morris-hover{position:absolute;z-index:1000}.morris-hover.morris-default-style{border-radius:10px;padding:6px;color:#666;background:rgba(255,255,255,.8);border:2px solid rgba(230,230,230,.8);font-family:sans-serif;font-size:12px;text-align:center}.morris-hover.morris-default-style .morris-hover-row-label{font-weight:700;margin:.25em 0}.morris-hover.morris-default-style .morris-hover-point{white-space:nowrap;margin:.1em 0}.easyPieChart{position:relative;text-align:center;margin-left:auto;margin-right:auto}.easyPieChart canvas{position:absolute;top:0;left:0}.chart,.chart-alt,.chart-alt-1,.chart-alt-2,.chart-alt-3,.chart-home{text-align:center;font-weight:700;margin:0 auto}.chart-wrapper{width:100%;height:350px}.chart-container{width:100%;height:100%;font-size:14px;line-height:1.2em}.xchart .line{stroke-width:3px;fill:none}.xchart .fill{stroke-width:0}.xchart circle{stroke:#FFF;stroke-width:3px}.xchart .axis .domain{fill:none}.xchart .axis .tick line{stroke:#EEE;stroke-width:1px}.xchart .axis text{fill:#666;font-size:12px}.xchart .color2 .line{stroke:#f26522}.xchart .color2 circle,.xchart .color2 rect{fill:#f26522}.xchart .color2 .fill{fill:rgba(242,101,34,.1)}.xchart .color2.comp .pointer,.xchart .color2.comp circle,.xchart .color2.comp rect{fill:#f9b99a}.xchart .color2.comp .line{stroke:#f9b99a}.xchart .color3 .line{stroke:#c6080d}.xchart .color3 circle,.xchart .color3 rect{fill:#c6080d}.xchart .color3 .fill{fill:rgba(198,8,13,.1)}.xchart .color3.comp .pointer,.xchart .color3.comp circle,.xchart .color3.comp rect{fill:#f8555a}.xchart .color3.comp .line{stroke:#f8555a}.xchart .color4 .line{stroke:#672d8b}.xchart .color4 circle,.xchart .color4 rect{fill:#672d8b}.xchart .color4 .fill{fill:rgba(103,45,139,.1)}.xchart .color4.comp .pointer,.xchart .color4.comp circle,.xchart .color4.comp rect{fill:#a869ce}.xchart .color4.comp .line{stroke:#a869ce}.xchart .color5 .line{stroke:#ce1797}.xchart .color5 circle,.xchart .color5 rect{fill:#ce1797}.xchart .color5 .fill{fill:rgba(206,23,151,.1)}.xchart .color5.comp .pointer,.xchart .color5.comp circle,.xchart .color5.comp rect{fill:#f075cb}.xchart .color5.comp .line{stroke:#f075cb}.xchart .color6 .line{stroke:#d9ce00}.xchart .color6 circle,.xchart .color6 rect{fill:#d9ce00}.xchart .color6 .fill{fill:rgba(217,206,0,.1)}.xchart .color6.comp .pointer,.xchart .color6.comp circle,.xchart .color6.comp rect{fill:#fff75a}.xchart .color6.comp .line{stroke:#fff75a}.xchart .color7 .line{stroke:#754c24}.xchart .color7 circle,.xchart .color7 rect{fill:#754c24}.xchart .color7 .fill{fill:rgba(117,76,36,.1)}.xchart .color7.comp .pointer,.xchart .color7.comp circle,.xchart .color7.comp rect{fill:#c98c50}.xchart .color7.comp .line{stroke:#c98c50}.xchart .color8 .line{stroke:#2eb9b4}.xchart .color8 circle,.xchart .color8 rect{fill:#2eb9b4}.xchart .color8 .fill{fill:rgba(46,185,180,.1)}.xchart .color8.comp .pointer,.xchart .color8.comp circle,.xchart .color8.comp rect{fill:#86e1de}.xchart .color8.comp .line{stroke:#86e1de}.xchart .color9 .line{stroke:#0e2e42}.xchart .color9 circle,.xchart .color9 rect{fill:#0e2e42}.xchart .color9 .fill{fill:rgba(14,46,66,.1)}.xchart .color9.comp .pointer,.xchart .color9.comp circle,.xchart .color9.comp rect{fill:#2477ab}.xchart .color9.comp .line{stroke:#2477ab}.chosen-container{position:relative;display:inline-block;zoom:1;width:100%!important;vertical-align:middle;border-width:1px;border-style:solid}.chosen-container .chosen-drop{position:absolute;z-index:1010;top:38px;left:-9999px;width:100%;border-width:1px;border-style:solid;border-top:0;background:#fff}.chosen-container.chosen-with-drop .chosen-drop{right:-1px;left:-1px;width:auto;padding:10px}.chosen-container-single .chosen-single{line-height:38px;position:relative;display:block;overflow:hidden;height:38px;margin:0;padding:0 10px!important;cursor:pointer;white-space:nowrap;text-decoration:none}.chosen-container-single .chosen-single span{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.chosen-container-single .chosen-single-with-deselect span{margin-right:38px}.chosen-container-single .chosen-single abbr{font-size:9px;font-weight:700;line-height:16px;position:absolute;top:9px;right:26px;display:block;width:16px;height:16px;text-align:center}.chosen-container-single .chosen-search{position:relative;z-index:1010;margin:0 0 10px;white-space:nowrap}.chosen-container-single .chosen-search i,.chosen-container-single .chosen-single div{line-height:38px;position:absolute;z-index:4;top:50%;right:0;display:block;width:38px;height:38px;margin-top:-19px;text-align:center;border-left:1px solid transparent}.chosen-container-active.chosen-with-drop .chosen-single div{border-bottom:1px solid transparent;border-bottom-right-radius:0}.chosen-container-single .chosen-search i{margin-top:-19px;padding:0!important}.chosen-container-single .chosen-search input{width:100%;padding:0 38px 0 5px}.chosen-container-single.chosen-container-single-nosearch .chosen-search{position:absolute;left:-9999px}.chosen-container .chosen-results{position:relative;overflow-x:hidden;overflow-y:auto;max-height:240px;-webkit-overflow-scrolling:touch}.chosen-container .chosen-results li{line-height:20px;margin:5px 0;padding:3px 10px;list-style:none}.chosen-container .chosen-results li.group-result{font-weight:700;margin:0;text-transform:uppercase}.chosen-container .chosen-results li.active-result{display:list-item;cursor:pointer}.chosen-container .chosen-results li.disabled-result{display:list-item;cursor:default;color:#ccc}.chosen-container .chosen-results li.no-results{display:list-item;margin:0;text-align:center}.chosen-container .chosen-results li.no-results span{font-weight:700}.chosen-container .chosen-results li.group-option{padding-left:15px}.chosen-container .chosen-results li em{font-style:normal;text-decoration:underline}.chosen-container-multi{height:auto;min-height:38px;padding:0}.chosen-container-multi .chosen-choices{position:relative;overflow:hidden;box-sizing:border-box;width:100%;height:auto!important;height:1%;margin:0;padding:0;cursor:text}.minicolors-grid .minicolors-picker>div,.minicolors-panel{-webkit-box-sizing:content-box;-moz-box-sizing:content-box}.chosen-container-multi .chosen-choices li{float:left;list-style:none}.chosen-container-multi .chosen-choices li.search-field{margin:0;padding:0 10px;white-space:nowrap}.chosen-container-multi .chosen-choices li.search-field input{width:100%;height:38px;padding:0;border:0!important;outline:0;background:0 0!important;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.chosen-container-multi .chosen-choices li.search-field .default{color:#999}.chosen-container-multi .chosen-choices li.search-choice{position:relative;margin:6px 0 6px 6px;padding:3px 25px 3px 5px;cursor:default;border-width:1px;border-style:solid}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close{line-height:12px;position:absolute;top:5px;right:5px;display:block;width:12px;height:12px;cursor:pointer;text-align:center;opacity:.5}.chosen-container-multi .chosen-results li.result-selected{opacity:.6;filter:alpha(opacity=60)}.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover{opacity:1}.minicolors{position:relative}.minicolors-swatch{position:absolute;display:inline-block;margin:0;padding:0;cursor:text;vertical-align:middle;border:1px solid #ccc;background:url(../../images/colorpicker.png) -80px 0}.minicolors-swatch-color{position:absolute;top:0;right:0;bottom:0;left:0}.minicolors input[type=hidden]+.minicolors-swatch{position:static;width:28px;cursor:pointer}.minicolors-panel{box-sizing:content-box;width:173px;height:152px;border:1px solid #ccc;box-shadow:0 0 20px rgba(0,0,0,.2)}.minicolors-panel.minicolors-visible{display:block}.minicolors-position-top .minicolors-panel{top:-180px}.minicolors-position-right .minicolors-panel{right:0;left:auto}.minicolors-position-bottom .minicolors-panel{top:36px;bottom:auto}.minicolors-position-left .minicolors-panel{right:auto;left:0}.minicolors-with-opacity .minicolors-panel{width:200px}.minicolors .minicolors-grid{position:absolute;top:6px;left:6px;width:150px;height:150px;cursor:crosshair;background:url(../../images/colorpicker.png) -120px 0}.minicolors .minicolors-grid-inner{position:absolute;top:0;left:0;width:150px;height:150px;background:0 0}.minicolors-slider-saturation .minicolors-grid{background-position:-420px 0}.minicolors-slider-saturation .minicolors-grid-inner{background:url(../../images/colorpicker.png) -270px 0}.minicolors-slider-brightness .minicolors-grid{background-position:-570px 0}.minicolors-slider-brightness .minicolors-grid-inner{background:#000}.minicolors-slider-wheel .minicolors-grid{background-position:-720px 0}.minicolors-opacity-slider,.minicolors-slider{position:absolute;top:6px;left:160px;width:20px;height:150px;cursor:row-resize;background:url(../../images/colorpicker.png) #fff}.minicolors-slider-saturation .minicolors-slider{background-position:-60px 0}.minicolors-slider-brightness .minicolors-slider,.minicolors-slider-wheel .minicolors-slider{background-position:-20px 0}.minicolors-opacity-slider{left:184px;display:none;background-position:-40px 0}.minicolors-with-opacity .minicolors-opacity-slider{display:block}.minicolors-grid .minicolors-picker{position:absolute;top:70px;left:70px;width:12px;height:12px;margin-top:-6px;margin-left:-6px;border:1px solid #000;border-radius:10px;background:0 0}.minicolors-grid .minicolors-picker>div{position:absolute;top:0;left:0;box-sizing:content-box;width:8px;height:8px;border:2px solid #fff;border-radius:8px}.minicolors-picker{position:absolute;top:0;left:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;width:18px;height:2px;margin-top:-2px;border:1px solid #000;background:#fff}.minicolors-inline{display:inline-block}.minicolors-inline .minicolors-input{display:none!important}.minicolors-inline .minicolors-panel{position:relative;z-index:auto;top:auto;left:auto;display:inline-block;box-shadow:none}.minicolors-theme-default .minicolors-swatch{top:5px;left:5px;width:24px;height:24px}.minicolors-theme-default.minicolors-position-right .minicolors-swatch{right:5px;left:auto}.minicolors-theme-default.minicolors{display:inline-block;width:100%}.minicolors-theme-default.minicolors-position-right .minicolors-input{padding-right:34px}.minicolors-theme-default.minicolors-position-left .minicolors-input{padding-left:34px}.minicolors-theme-bootstrap .minicolors-swatch{top:3px;left:3px;width:28px;height:28px;border-radius:3px}.minicolors-theme-bootstrap.minicolors-position-right .minicolors-swatch{right:3px;left:auto}.minicolors-theme-bootstrap .minicolors-input{padding-left:44px}.minicolors-theme-bootstrap.minicolors-position-right .minicolors-input{padding-right:44px;padding-left:12px}div.dataTables_length label{font-weight:400;line-height:32px;text-align:left;display:block}div.dataTables_length select{float:left;width:75px;margin-right:10px}div.dataTables_filter label{font-weight:400;float:right}div.dataTables_filter input{display:inline-block;width:200px;margin-left:10px;padding:0 10px}div.dataTables_info{padding-top:8px}div.dataTables_paginate{float:right;margin:0}div.dataTables_paginate ul.pagination{margin:0;white-space:nowrap}table.dataTable{clear:both;max-width:none!important;margin-top:10px!important;margin-bottom:10px!important}div.dataTables_scrollBody table,div.dataTables_scrollFoot table{margin-top:0!important;border-top:none}table.dataTable thead .sorting,table.dataTable thead .sorting_asc,table.dataTable thead .sorting_asc_disabled,table.dataTable thead .sorting_desc,table.dataTable thead .sorting_desc_disabled{cursor:pointer}table.dataTable thead .sorting_asc_disabled .glyph-icon,table.dataTable thead .sorting_desc_disabled .glyph-icon{opacity:.7}table.dataTable thead>tr>th{padding-right:18px;padding-left:18px}table.dataTable th:active{outline:0}div.dataTables_scrollHead table{margin-bottom:0!important;border-bottom-right-radius:0;border-bottom-left-radius:0}div.DTFC_LeftHeadWrapper table,div.DTFC_LeftHeadWrapper table thead tr:last-child td:first-child,div.DTFC_LeftHeadWrapper table thead tr:last-child th:first-child,div.DTFC_RightHeadWrapper table,div.DTFC_RightHeadWrapper table thead tr:last-child td:first-child,div.DTFC_RightHeadWrapper table thead tr:last-child th:first-child,div.dataTables_scrollHead table thead tr:last-child td:first-child,div.dataTables_scrollHead table thead tr:last-child th:first-child{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}div.dataTables_scrollBody table{margin-bottom:0!important}div.dataTables_scrollBody tbody tr:first-child td,div.dataTables_scrollBody tbody tr:first-child th{border-top:none}.table tbody tr.active td,.table tbody tr.active th{color:#fff;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:#fff}div.DTTT .btn,ul.DTTT_dropdown.dropdown-menu a{color:#333!important}.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}div.DTTT .btn:hover{text-decoration:none!important}ul.DTTT_dropdown.dropdown-menu{z-index:2003}ul.DTTT_dropdown.dropdown-menu li{position:relative}ul.DTTT_dropdown.dropdown-menu li:hover a{color:#fff!important;background-color:#08c}div.DTTT_collection_background{z-index:2002}.DTTT_Print #page-content{margin:0}div.DTTT_print_info.modal{height:150px;margin-top:-75px;text-align:center}div.DTTT_print_info h6{font-size:28px;font-weight:400;line-height:28px;margin:1em}div.DTTT_print_info p{font-size:14px;line-height:20px}div.DTFC_LeftFootWrapper table,div.DTFC_LeftHeadWrapper table,div.DTFC_RightFootWrapper table,div.DTFC_RightHeadWrapper table,table.DTFC_Cloned tr.even{margin-bottom:0;background-color:#fff}div.DTFC_LeftHeadWrapper table,div.DTFC_RightHeadWrapper table{margin-bottom:0!important;border-top-right-radius:0!important}div.DTFC_LeftBodyWrapper table,div.DTFC_RightBodyWrapper table{margin-bottom:0!important;border-top:none}div.DTFC_LeftBodyWrapper tbody tr:first-child td,div.DTFC_LeftBodyWrapper tbody tr:first-child th,div.DTFC_LeftFootWrapper table,div.DTFC_RightBodyWrapper tbody tr:first-child td,div.DTFC_RightBodyWrapper tbody tr:first-child th,div.DTFC_RightFootWrapper table{border-top:none}/*! * DataTables + Font Awesome integration * License: MIT - http://datatables.net/license - */table.dataTable thead th{position:relative;background-image:none!important}table.dataTable thead th.sorting:after,table.dataTable thead th.sorting_asc:after,table.dataTable thead th.sorting_desc:after{position:absolute;top:12px;right:8px;display:block;font-family:FontAwesome}table.dataTable thead th.sorting:after{content:"\f0dc";font-size:13px}table.dataTable thead th.sorting_asc:after{content:"\f0de"}table.dataTable thead th.sorting_desc:after{content:"\f0dd"}table.table thead th.sorting:after,table.table thead th.sorting_asc:after,table.table thead th.sorting_desc:after{top:12px}div.dataTables_paginate a.paginate_button.first,div.dataTables_paginate a.paginate_button.previous{position:relative;padding-left:24px}div.dataTables_paginate a.paginate_button.last,div.dataTables_paginate a.paginate_button.next{position:relative;padding-right:24px}div.dataTables_paginate a.first:before,div.dataTables_paginate a.previous:before{position:absolute;top:8px;left:10px;display:block;font-family:FontAwesome}div.dataTables_paginate a.last:after,div.dataTables_paginate a.next:after{position:absolute;top:8px;right:10px;display:block;font-family:FontAwesome}div.dataTables_paginate a.first:before{content:"\f100"}div.dataTables_paginate a.previous:before{content:"\f104"}div.dataTables_paginate a.next:after{content:"\f105"}div.dataTables_paginate a.last:after{content:"\f101"}div.dataTables_paginate li.first>a,div.dataTables_paginate li.previous>a{position:relative;padding-left:24px}div.dataTables_paginate li.last>a,div.dataTables_paginate li.next>a{position:relative;padding-right:24px}div.dataTables_paginate li.first a:before,div.dataTables_paginate li.previous a:before{position:absolute;top:6px;left:10px;display:block;font-family:FontAwesome}div.dataTables_paginate li.last a:after,div.dataTables_paginate li.next a:after{position:absolute;top:6px;right:10px;display:block;font-family:FontAwesome}div.dataTables_paginate li.first a:before{content:"\f100"}div.dataTables_paginate li.previous a:before{content:"\f104"}div.dataTables_paginate li.next a:after{content:"\f105"}div.dataTables_paginate li.last a:after{content:"\f101"}div.columns div.dataTables_paginate li.first a:before,div.columns div.dataTables_paginate li.last a:after,div.columns div.dataTables_paginate li.next a:after,div.columns div.dataTables_paginate li.previous a:before{top:0}.DTTT_container{float:right;margin-left:10px}.DTTT_container a div{cursor:pointer}.dataTables_scrollBody table.dataTable thead th.sorting:after{display:none}.tr-selected,.tr-selected td{background:#eefacd!important;color:#393c31!important}table.dataTable.dtr-inline.collapsed tbody td:first-child,table.dataTable.dtr-inline.collapsed tbody th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed tbody td:first-child:before,table.dataTable.dtr-inline.collapsed tbody th:first-child:before{top:8px;left:4px;height:16px;width:16px;display:block;position:absolute;color:#fff;border:2px solid #fff;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed tbody td:first-child.dataTables_empty:before,table.dataTable.dtr-inline.collapsed tbody th:first-child.dataTables_empty:before,table.dataTable.dtr-inline.collapsed tbody tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed tbody tr.parent td:first-child:before,table.dataTable.dtr-inline.collapsed tbody tr.parent th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-column tbody td.control,table.dataTable.dtr-column tbody th.control{position:relative;cursor:pointer}table.dataTable.dtr-column tbody td.control:before,table.dataTable.dtr-column tbody th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:#fff;border:2px solid #fff;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#31b131}table.dataTable.dtr-column tbody tr.parent td.control:before,table.dataTable.dtr-column tbody tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable tr.child{padding:.5em 1em}table.dataTable tr.child:hover{background:0 0!important}table.dataTable tr.child ul{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable tr.child ul li{border-bottom:1px solid #efefef;padding:.5em 0}table.dataTable tr.child ul li:first-child{padding-top:0}table.dataTable tr.child ul li:last-child{border-bottom:none}table.dataTable tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:700}div.FixedHeader_Cloned td,div.FixedHeader_Cloned th{background-color:#fff!important}.DTFC_LeftBodyLiner .table,.DTFC_LeftFootWrapper .table{margin:0!important}table.DTCR_clonedTable{background-color:rgba(255,255,255,.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201}.DTFC_LeftBodyLiner .table thead th:after{display:none!important}.bsdatepicker:after,.bsdatepicker:before{position:absolute;display:inline-block;content:''}.bsdatepicker{top:0;left:0;margin-top:1px;padding:4px!important}.bsdatepicker:before{top:-7px;left:6px;border-right:7px solid transparent;border-bottom:7px solid transparent;border-bottom-color:transparent;border-left:7px solid transparent}.bsdatepicker:after{top:-6px;left:7px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.bsdatepicker>div{display:none}.bsdatepicker table{width:100%;margin:0}.bsdatepicker td,.bsdatepicker th{width:20px;height:20px;margin:3px;text-align:center}.bsdatepicker td.day:hover{cursor:pointer}.bsdatepicker td.day.disabled{color:#eee}.bsdatepicker td span.old,.bsdatepicker td.new,.bsdatepicker td.old{color:#999}.bsdatepicker td span{line-height:44px;display:block;float:left;width:54px;height:44px;margin:2px;cursor:pointer}.bsdatepicker th.switch{width:145px}.bsdatepicker th.next,.bsdatepicker th.prev{font-size:21px}.bsdatepicker thead tr:first-child th{cursor:pointer}.ui-datepicker-inline{position:static!important;width:100%;float:none;margin-top:0}.ui-datepicker .ui-datepicker-header,.ui-datepicker-header{font-size:13px;line-height:40px;position:relative;height:40px}.ui-datepicker .ui-datepicker-next,.ui-datepicker .ui-datepicker-prev{position:absolute;top:50%;overflow:hidden;width:30px;height:30px;margin-top:-15px;cursor:pointer;border-width:1px;border-style:solid}.ui-datepicker .ui-datepicker-prev{left:5px}.ui-datepicker .ui-datepicker-next{right:5px}.ui-datepicker .ui-datepicker-next span,.ui-datepicker .ui-datepicker-prev span{line-height:28px;display:block;float:none;height:28px;margin:0 auto;text-align:center}.ui-datepicker .ui-datepicker-title{font-weight:700;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:13px;height:28px;margin:0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{font-size:13px;line-height:1.6em;width:96%;margin:2%;border-collapse:collapse}.ui-datepicker th{font-weight:700;padding:0 0 5px;text-align:center;border:0}.ui-datepicker td{padding:1px;border:0}.ui-datepicker td a,.ui-datepicker td span{font-size:13px;display:block;padding:2px 5px;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{padding:10px}.ui-datepicker .ui-datepicker-buttonpane button{line-height:26px;float:right;height:28px;padding:0 15px;border-width:1px;border-style:solid;background:#fff}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-radius:0}.ui-datepicker-row-break{font-size:0;clear:both;width:100%}.daterangepicker.dropdown-menu{z-index:3000;max-width:none}.daterangepicker.opensleft .calendar,.daterangepicker.opensleft .ranges{float:left;margin:4px}.daterangepicker.opensright .calendar,.daterangepicker.opensright .ranges{float:right;margin:4px}.daterangepicker .ranges{width:188px;margin:0 0 0 10px;text-align:left}.daterangepicker .ranges .range_inputs>div{float:left}.daterangepicker .ranges .range_inputs>div:nth-child(2){padding-left:11px}.daterangepicker .calendar{display:none;max-width:270px}.show-calendar.daterangepicker .calendar{display:block}.daterangepicker .applyBtn{float:right;width:110px}.daterangepicker .cancelBtn{float:left}.daterangepicker .calendar td,.daterangepicker .calendar th{font-size:12px;text-align:center;white-space:nowrap}.daterangepicker .ranges label{font-size:11px;font-weight:700;line-height:20px;display:block;width:74px;height:20px;margin-bottom:2px;text-transform:uppercase;color:#333}.daterangepicker .ranges input{font-size:11px}.daterangepicker .ranges .input-mini{font-size:11px;line-height:30px;display:block;width:88px;height:30px;margin:0 0 10px;padding:0 6px;vertical-align:middle;color:#555;border:1px solid #ccc;border-radius:4px;background-color:#eee}.daterangepicker.opensleft:after,.daterangepicker.opensleft:before,.daterangepicker.opensright:after,.daterangepicker.opensright:before{position:absolute;display:inline-block;content:''}.daterangepicker .ranges ul{margin:0;padding:0;list-style:none}.daterangepicker .ranges li{margin-bottom:3px;padding:3px 12px;cursor:pointer}.daterangepicker .calendar-date{padding:5px;border-width:1px;border-style:solid;background:#fff}.daterangepicker .calendar-time{line-height:30px;margin:8px auto 0;text-align:center}.daterangepicker{position:absolute;top:100px;left:20px;margin-top:1px;padding:5px!important;background:#fff}.daterangepicker.opensleft:before{top:-7px;right:9px;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);border-left:7px solid transparent}.daterangepicker.opensleft:after{top:-6px;right:10px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.daterangepicker.opensright:before{top:-7px;left:9px;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);border-left:7px solid transparent}.daterangepicker.opensright:after{top:-6px;left:10px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.daterangepicker table{width:100%;margin:0}.daterangepicker td,.daterangepicker th{width:20px;height:20px;cursor:pointer;text-align:center;white-space:nowrap}.daterangepicker td.off{color:#999}.daterangepicker td.in-range{border-radius:0}.daterangepicker td.in-range:hover{color:#000}.daterangepicker td.week,.daterangepicker th.week{font-size:80%;color:#ccc}.daterangepicker select.monthselect,.daterangepicker select.yearselect{font-size:12px;height:auto;margin:0;padding:1px;cursor:default}.daterangepicker select.monthselect{width:56%;margin-right:2%}.daterangepicker select.yearselect{width:40%}.daterangepicker select.ampmselect,.daterangepicker select.hourselect,.daterangepicker select.minuteselect{width:50px;margin-bottom:0}.ui-dialog .ui-dialog-titlebar{position:relative;padding:10px;border-bottom:1px solid transparent}.ui-dialog .ui-dialog-title{overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{line-height:20px;position:absolute;top:50%;right:10px;width:20px;height:20px;margin:-10px 0 0;border:1px solid #ccc;background:#fff}.ui-dialog .ui-dialog-titlebar-close:before{line-height:18px;position:absolute;top:0;left:0;width:18px;height:18px;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-dialog .ui-dialog-titlebar-close:hover:before{opacity:.9;-moz-opacity:.9;filter:alpha(opacity: 90)}.ui-dialog .ui-dialog-titlebar-close .ui-button-text{display:none}.ui-dialog .ui-dialog-content{position:relative;overflow:auto;padding:0;border:0;background:0 0}.ui-dialog-buttonset button{padding:8px 15px;border-width:1px;border-style:solid}.ui-dialog .ui-dialog-buttonpane{border-width:1px 0 0!important}.ui-dialog .ui-dialog-buttonpane .ui-button{line-height:28px;float:right;height:28px;padding:0 15px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-dialog .infobox,.ui-dialog .ui-tabs{margin-bottom:0}.ui-dialog .ui-tabs .ui-tabs-panel{padding:10px}.ui-widget-overlay{position:fixed;z-index:1049;top:0;left:0;width:100%;height:100%}.ui-widget-overlay img{position:absolute;top:50%;left:50%;margin:-27px 0 0 -27px}.ui-resizable{position:relative}.ui-resizable-handle{font-size:.1px;position:absolute;display:block}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{top:-5px;left:0;width:100%;height:7px;cursor:n-resize}.ui-resizable-s{bottom:-5px;left:0;width:100%;height:7px;cursor:s-resize}.ui-resizable-e{top:0;right:-5px;width:7px;height:100%;cursor:e-resize}.ui-resizable-w{top:0;left:-5px;width:7px;height:100%;cursor:w-resize}.ui-resizable-se{right:1px;bottom:1px;width:12px;height:12px;cursor:se-resize}.ui-resizable-sw{bottom:-5px;left:-5px;width:9px;height:9px;cursor:sw-resize}.ui-resizable-nw{top:-5px;left:-5px;width:9px;height:9px;cursor:nw-resize}.ui-resizable-ne{top:-5px;right:-5px;width:9px;height:9px;cursor:ne-resize}.dropdown,.dropup{position:relative;display:inline-block}.dropdown-menu,.minicolors-panel,.popover,.ui-datepicker,.ui-dialog,.ui-menu{position:absolute;z-index:1050!important;top:105%;left:0;display:none;float:left;min-width:150px;margin:5px 0 0;padding:5px;list-style:none;text-align:left;border-width:1px;border-style:solid;background:#fff}.ui-datepicker{padding:0}.dropdown-menu,.popover,.ui-dialog{box-shadow:0 1px 7px 2px rgba(135,158,171,.2)}.dropdown-menu{font-size:13px;line-height:1.6em;padding:5px 0;text-transform:none;border:0;min-width:150px}.dropdown-menu,.minicolors-panel,.popover,.ui-menu{top:100%}.dropdown-menu .divider{margin:5px 1px}.dropdown-menu.float-right{right:0;left:auto}.dropdown-menu .header{font-size:11px;font-weight:700;line-height:1.4em;margin:0 0 5px;padding:5px 5px 10px;text-transform:uppercase;color:#888;border-bottom:#dfe8f1 solid 1px}.dropdown-menu .dropdown-header{font-size:11px;font-weight:300;padding:5px 15px;text-transform:uppercase;color:#000}.dropdown-menu li{position:relative}.dropdown-menu li>a,.ui-menu li>a{font-weight:400;line-height:20px;position:relative;display:block;clear:both;margin:0;padding:5px 15px;cursor:pointer;white-space:nowrap}.dropdown>.dropdown-menu:before,.minicolors-position-bottom .minicolors-panel:before{position:absolute;top:-7px;left:7px;display:inline-block;content:'';border-right:7px solid transparent;border-bottom:7px solid transparent;border-bottom-color:transparent;border-left:7px solid transparent}.dropdown>.dropdown-menu:after,.minicolors-position-bottom .minicolors-panel:after{position:absolute;top:-6px;left:8px;display:inline-block;content:'';border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.dropdown>.dropdown-menu.float-right:before,.dropup>.dropdown-menu.float-right:before,.minicolors-position-right .minicolors-panel:before{right:7px;left:auto}.dropdown>.dropdown-menu.float-right:after,.dropup>.dropdown-menu.float-right:after,.minicolors-position-right .minicolors-panel:after{right:8px;left:auto}.minicolors-inline .minicolors-panel:after,.minicolors-inline .minicolors-panel:before{display:none}.dropdown-dividers{padding:0}.dropdown-dividers li{padding:3px;border-bottom:#ccc solid 1px}.dropdown-dividers li:last-child{border-bottom:0}.dropdown-dividers li>a{padding:2px 10px}.push-left{left:100%!important;margin-left:-30px}.open>.dropdown-menu{display:block}.dropup .dropdown-menu{top:auto;bottom:100%;margin-bottom:8px}.dropup>.dropdown-menu:before,.minicolors-position-top .minicolors-panel:before{position:absolute;bottom:-7px;left:7px;display:inline-block;content:'';border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-right:7px solid transparent;border-left:7px solid transparent}.dropup>.dropdown-menu:after,.minicolors-position-top .minicolors-panel:after{position:absolute;bottom:-6px;left:8px;display:inline-block;content:'';border-top:6px solid #fff;border-right:6px solid transparent;border-left:6px solid transparent}.minicolors-position-top.minicolors-position-right .minicolors-panel:before{right:6px;left:auto}.minicolors-position-top.minicolors-position-right .minicolors-panel:after{right:7px;left:auto}.dropdown-submenu{position:relative;z-index:40}.dropdown-submenu>.dropdown-menu{top:50%;left:90%;margin-top:-6px;margin-left:-1px;border-radius:0 4px 4px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:4px 4px 4px 0}.dropdown-submenu>a:after{position:relative;display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-5px;content:' ';opacity:.4;border-width:5px 0 5px 5px;border-style:solid;border-color:transparent transparent transparent #ccc;-moz-opacity:.4;filter:alpha(opacity: 40)}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.float-left{float:none!important}.dropdown-submenu.float-left>.dropdown-menu{left:-110%;margin-left:10px;border-radius:4px 0 4px 4px}.dropdown-submenu.float-left>.dropdown-menu.dropdown-dividers{margin-left:20px}.ui-menu-item{padding:3px 6px}.dropzone,.dropzone *,.dropzone-previews,.dropzone-previews *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dropzone{padding:1em;border:1px solid rgba(0,0,0,.08);background:rgba(0,0,0,.02)}.dropzone.dz-clickable,.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message span{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone .dz-message{opacity:1;-ms-filter:none;filter:none}.dropzone.dz-drag-hover{border-color:rgba(0,0,0,.15);background:rgba(0,0,0,.04)}.dropzone.dz-started .dz-message{display:none}.dropzone .dz-preview,.dropzone-previews .dz-preview{position:relative;display:inline-block;margin:17px;padding:6px;vertical-align:top;border:1px solid #acacac;background:rgba(255,255,255,.8)}.btn-file,.fileinput .btn,.fileinput .thumbnail,.fileinput-filename{vertical-align:middle}.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail],.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail]{display:none}.dropzone .dz-preview .dz-details,.dropzone-previews .dz-preview .dz-details{position:relative;width:100px;height:100px;margin-bottom:22px;padding:5px;background:#ebebeb}.dropzone .dz-preview .dz-details .dz-filename,.dropzone-previews .dz-preview .dz-details .dz-filename{overflow:hidden;height:100%}.dropzone .dz-preview .dz-details img,.dropzone-previews .dz-preview .dz-details img{position:absolute;top:0;left:0;width:100px;height:100px}.dropzone .dz-preview .dz-details .dz-size,.dropzone-previews .dz-preview .dz-details .dz-size{line-height:28px;position:absolute;bottom:-28px;left:3px;height:28px}.dropzone .dz-preview.dz-error .dz-error-mark,.dropzone .dz-preview.dz-success .dz-success-mark,.dropzone-previews .dz-preview.dz-error .dz-error-mark,.dropzone-previews .dz-preview.dz-success .dz-success-mark{display:block}.dropzone .dz-preview:hover .dz-details img,.dropzone-previews .dz-preview:hover .dz-details img{display:none}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark,.dropzone-previews .dz-preview .dz-error-mark,.dropzone-previews .dz-preview .dz-success-mark{font-size:30px;position:absolute;top:-10px;right:-10px;display:none;width:40px;height:40px;text-align:center}.dropzone .dz-preview .dz-success-mark,.dropzone-previews .dz-preview .dz-success-mark{color:#8cc657}.dropzone .dz-preview .dz-error-mark,.dropzone-previews .dz-preview .dz-error-mark{color:#ee162d}.dropzone .dz-preview .dz-progress,.dropzone-previews .dz-preview .dz-progress{position:absolute;top:100px;right:6px;left:6px;display:none;height:6px;background:#d7d7d7}.dropzone .dz-preview .dz-progress .dz-upload,.dropzone-previews .dz-preview .dz-progress .dz-upload{position:absolute;top:0;bottom:0;left:0;width:0;background-color:#8cc657}.dropzone .dz-preview.dz-processing .dz-progress,.dropzone-previews .dz-preview.dz-processing .dz-progress{display:block}.dropzone .dz-preview .dz-error-message,.dropzone-previews .dz-preview .dz-error-message{position:absolute;z-index:500;top:-5px;left:-20px;display:none;min-width:140px;max-width:500px;padding:8px 10px;color:#800;background:rgba(245,245,245,.8)}.dropzone .dz-preview:hover.dz-error .dz-error-message,.dropzone-previews .dz-preview:hover.dz-error .dz-error-message{display:block}.dropzone{position:relative;min-height:350px;cursor:pointer}.dz-message{font-size:35px;line-height:50px;position:absolute;top:50%;left:50%;width:50%;height:50px;margin-top:-50px;margin-left:-25%;padding:25px;text-align:center}.btn-file{position:relative;overflow:hidden}.btn-file>input{position:absolute;top:0;right:0;width:100%;height:100%;margin:0;font-size:23px;cursor:pointer;filter:alpha(opacity=0);opacity:0;direction:ltr}.fileinput{display:inline-block;margin-bottom:9px}.fileinput .form-control{display:inline-block;padding-top:7px;padding-bottom:5px;margin-bottom:0;vertical-align:middle;cursor:text}.fileinput .thumbnail{display:inline-block;margin-bottom:5px;overflow:hidden;text-align:center}.fileinput .thumbnail>img{max-height:100%}.fileinput-exists .fileinput-new,.fileinput-new .fileinput-exists{display:none}.fileinput-inline .fileinput-controls{display:inline}.fileinput-filename{display:inline-block;overflow:hidden}.form-control .fileinput-filename{vertical-align:bottom}.fileinput.input-group{display:table}.fileinput.input-group>*{position:relative;z-index:2}.fileinput.input-group>.btn-file{z-index:1}.fileinput-new .input-group .btn-file,.fileinput-new.input-group .btn-file{border-radius:0 4px 4px 0}.fileinput-new .input-group .btn-file.btn-sm,.fileinput-new .input-group .btn-file.btn-xs,.fileinput-new.input-group .btn-file.btn-sm,.fileinput-new.input-group .btn-file.btn-xs{border-radius:0 3px 3px 0}.fileinput-new .input-group .btn-file.btn-lg,.fileinput-new.input-group .btn-file.btn-lg{border-radius:0 6px 6px 0}.form-group.has-warning .fileinput .fileinput-preview{color:#8a6d3b}.form-group.has-warning .fileinput .thumbnail{border-color:#faebcc}.form-group.has-error .fileinput .fileinput-preview{color:#a94442}.form-group.has-error .fileinput .thumbnail{border-color:#ebccd1}.form-group.has-success .fileinput .fileinput-preview{color:#3c763d}.form-group.has-success .fileinput .thumbnail{border-color:#d6e9c6}.bootstrap-switch{line-height:8px;position:relative;display:inline-block;overflow:hidden;min-width:100px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:left;vertical-align:middle;border:1px solid #ccc;border-radius:4px}.irs,.jcrop-tracker{-webkit-user-select:none}.bootstrap-switch.bootstrap-switch-mini{min-width:71px}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label{font-size:10px;line-height:9px;padding-top:4px;padding-bottom:4px}.bootstrap-switch.bootstrap-switch-small{min-width:79px}.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label{font-size:12px;line-height:18px;padding-top:3px;padding-bottom:3px}.bootstrap-switch.bootstrap-switch-large{min-width:120px}.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label{font-size:14px;line-height:normal;padding-top:9px;padding-bottom:9px}.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container{-webkit-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-container{margin-left:0}.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label{border-top-right-radius:3px;border-bottom-right-radius:3px}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-container{margin-left:-50%}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label{border-top-left-radius:3px;border-bottom-left-radius:3px}.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-container{margin-left:-25%}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-indeterminate,.bootstrap-switch.bootstrap-switch-readonly{cursor:default!important;opacity:.5;filter:alpha(opacity=50)}.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label{cursor:default!important}.bootstrap-switch.bootstrap-switch-focused{border-color:#ccc;outline:0}.bootstrap-switch .bootstrap-switch-container{top:0;display:inline-block;width:150%;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);border-radius:4px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-label{font-size:12px;line-height:20px;text-transform:uppercase;display:inline-block!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;height:100%;padding-top:4px;padding-bottom:4px;cursor:pointer}div.switch-toggle,div.switch-toggle:after{display:block;background:#fff;border-radius:50px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on{z-index:1;width:33.333333333%;text-align:center}.bootstrap-switch .bootstrap-switch-label{z-index:100;width:33.333333333%;margin-top:-1px;margin-bottom:-1px;text-align:center;color:#333;background:#fff}.bootstrap-switch input[type=radio],.bootstrap-switch input[type=checkbox]{position:absolute!important;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.bootstrap-switch input[type=radio].form-control,.bootstrap-switch input[type=checkbox].form-control{height:auto}div.switch-toggle{height:24px;width:48px;position:relative;cursor:pointer;box-shadow:inset 0 0 1px rgba(0,0,0,.2);-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;transition:all .2s ease}div.switch-toggle:after,div.switch-toggle:before{position:absolute;content:''}div.switch-toggle:after{height:18px;width:18px;top:3px;left:3px;box-shadow:1px 1px 3px rgba(0,0,0,.3);-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;transition:all .2s ease}div.switch-toggle:before{right:1px;top:12px;color:#fff}.irs,.irs-line{position:relative;display:block}div.switch-toggle:hover:after{left:5px}div.switch-toggle.switch-on:before{content:'';right:40px}.switch-toggle.switch-on{background:#0c0}div.switch-toggle.switch-on:after{left:26px}div.switch-toggle.switch-on:hover:after{left:24px}.irs{-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.irs-line{overflow:hidden;outline:0!important}.irs-line-left,.irs-line-mid,.irs-line-right{position:absolute;display:block;top:0}.irs-line-left{left:0;width:11%}.irs-line-mid{left:9%;width:82%}.irs-line-right{right:0;width:11%}.irs-bar,.irs-shadow{position:absolute;width:0;left:0}.irs-bar{display:block}.irs-bar-edge{position:absolute;display:block;top:0;left:0}.irs-shadow{display:none}.irs-from,.irs-max,.irs-min,.irs-single,.irs-slider,.irs-to{display:block;position:absolute;cursor:default}.irs-slider{z-index:1}.irs-slider.type_last{z-index:2}.irs-min{left:0}.irs-max{right:0}.irs-from,.irs-single,.irs-to{top:0;left:0;white-space:nowrap}.irs-grid{position:absolute;display:none;bottom:0;left:0;width:100%;height:20px}.irs-with-grid .irs-grid{display:block}.irs-grid-pol{position:absolute;top:0;left:0;width:1px;height:8px;background:#000}.irs-grid-pol.small{height:4px}.irs-grid-text{position:absolute;bottom:0;left:0;white-space:nowrap;text-align:center;font-size:9px;line-height:9px;padding:0 3px;color:#000}.irs-disable-mask{position:absolute;display:block;top:0;left:-1%;width:102%;height:100%;cursor:default;background:rgba(0,0,0,0);z-index:2}.irs-disabled{opacity:.4}.lt-ie9 .irs-disabled{filter:alpha(opacity=40)}.irs-hidden-input{position:absolute!important;display:block!important;top:0!important;left:0!important;width:0!important;height:0!important;font-size:0!important;line-height:0!important;padding:0!important;margin:0!important;outline:0!important;z-index:-9999!important;background:0 0!important;border-style:solid!important;border-color:transparent!important}.jcrop-dragbar.ord-s,.jcrop-handle.ord-s,.jcrop-handle.ord-se,.jcrop-handle.ord-sw{margin-bottom:-4px;bottom:0}.jcrop-dragbar.ord-e,.jcrop-handle.ord-e,.jcrop-handle.ord-ne,.jcrop-handle.ord-se{right:0;margin-right:-4px}.modal,.modal-content,.note-air-editor,div.pp_pic_holder a:focus{outline:0}.jcrop-holder{text-align:left;direction:ltr}.jcrop-hline,.jcrop-vline{font-size:0;position:absolute;background:url(../../images/jcrop.gif) #fff}.jcrop-vline{width:1px!important;height:100%}.jcrop-vline.right{right:0}.jcrop-hline{width:100%;height:1px!important}.jcrop-hline.bottom{bottom:0}.jcrop-tracker{width:100%;height:100%;-webkit-tap-highlight-color:transparent}.jcrop-handle{font-size:1px;width:7px;height:7px;border:1px solid #eee;background-color:#333}.jcrop-handle.ord-n{top:0;left:50%;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-s{left:50%;margin-left:-4px}.jcrop-handle.ord-e{top:50%;margin-top:-4px}.jcrop-handle.ord-w{top:50%;left:0;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-nw{top:0;left:0;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-ne{top:0;margin-top:-4px}.jcrop-handle.ord-sw{left:0;margin-left:-4px}.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{width:100%;height:7px}.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{width:7px;height:100%}.jcrop-dragbar.ord-n{margin-top:-4px}.jcrop-dragbar.ord-w{margin-left:-4px}.jcrop-light .jcrop-hline,.jcrop-light .jcrop-vline{opacity:.7!important;background:#fff;filter:alpha(opacity=70)!important}.jcrop-light .jcrop-handle{border-color:#fff;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#000}.jcrop-dark .jcrop-hline,.jcrop-dark .jcrop-vline{opacity:.7!important;background:#000;filter:alpha(opacity=70)!important}.jcrop-dark .jcrop-handle{border-color:#000;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#fff}.solid-line .jcrop-hline,.solid-line .jcrop-vline{background:#fff}.jcrop-holder img,img.jcrop-preview{max-width:none}.jcrop-holder #preview-pane{position:absolute;z-index:2000;top:10px;right:-280px;display:block;padding:6px;border:1px solid rgba(0,0,0,.4);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;background-color:#fff}#preview-pane .preview-container{overflow:hidden;width:250px;height:170px}.jGrowl{z-index:9999;position:absolute}#loadingbar,body>.jGrowl{position:fixed}.jGrowl.top-left{top:0;left:0}.jGrowl.top-right{top:0;right:0}.jGrowl.bottom-left{bottom:0;left:0}.jGrowl.bottom-right{right:0;bottom:0}.jGrowl.center{top:50%;left:50%;width:0;margin-left:-170px}.center .jGrowl-closer,.center .jGrowl-notification{margin-right:auto;margin-left:auto}.jGrowl .jGrowl-closer,.jGrowl .jGrowl-notification{font-size:12px;display:none;zoom:1;width:300px;padding:10px 15px;white-space:normal;opacity:.95;filter:progid: DXImageTransform.Microsoft.Alpha(Opacity=95);margin:10px}.jGrowl .jGrowl-notification:hover{opacity:1;filter:progid: DXImageTransform.Microsoft.Alpha(Opacity=100)}.jGrowl .jGrowl-notification{min-height:20px}.jGrowl .jGrowl-notification .jGrowl-header{font-size:.85em;font-weight:700}.jGrowl .jGrowl-notification .jGrowl-close{font-weight:700;z-index:99;float:right;cursor:pointer}.jGrowl .jGrowl-closer{font-weight:700;cursor:pointer;text-align:center}#loadingbar{z-index:2147483647;top:0;left:-6px;width:1%;height:4px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}#loadingbar.left{right:0;left:100%;width:100%}#loadingbar.up{top:100%;bottom:0;left:0;width:5px;height:100%}#loadingbar.down{left:0;width:5px;height:0}#loadingbar.waiting dd,#loadingbar.waiting dt{-webkit-animation:pulse 2s ease-out 0s infinite;-moz-animation:pulse 2s ease-out 0s infinite;-ms-animation:pulse 2s ease-out 0s infinite;-o-animation:pulse 2s ease-out 0s infinite;animation:pulse 2s ease-out 0s infinite}#loadingbar dt{right:-80px;clip:rect(-6px,90px,14px,-6px);width:180px;opacity:.6}#loadingbar dd{right:0;clip:rect(-6px,22px,14px,10px);width:20px;opacity:.6}#loadingbar dd,#loadingbar dt{position:absolute;top:0;height:2px;-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%;-webkit-box-shadow:#ff6439 1px 0 6px 1px;-moz-box-shadow:#fa7753 1px 0 6px 1px;box-shadow:#ff6439 1px 0 6px 1px;-ms-box-shadow:#fa7753 1px 0 6px 1px}.jvectormap-label,.jvectormap-zoomin,.jvectormap-zoomout{position:absolute;border-radius:3px;padding:5px;border-width:1px;border-style:solid}#loadingbar.left dt{left:-4px;clip:rect(-6px,185px,14px,25px);width:180px;opacity:.6}#loadingbar.left dd{left:0;clip:rect(-6px,22px,14px,0);width:20px;margin:0;opacity:.6}#loadingbar.down dd,#loadingbar.down dt,#loadingbar.up dd,#loadingbar.up dt{right:auto;left:-5px;width:10px}#loadingbar.left dd,#loadingbar.left dt{top:0;height:2px}#loadingbar.down dt{top:auto;bottom:-47px;clip:rect(-6px,20px,130px,-6px);height:180px;opacity:.6}#loadingbar.down dd{top:auto;bottom:0;clip:rect(-6px,22px,20px,10px);height:20px;margin:0;opacity:.6}#loadingbar.up dt{top:-10px;bottom:auto;clip:rect(13px,20px,190px,-6px);height:180px;opacity:.6}#loadingbar.up dd{top:0;bottom:auto;clip:rect(-6px,22px,25px,10px);height:20px;margin:0;opacity:.6}@keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-moz-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-ms-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-webkit-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}.jvectormap-label{display:none;font-size:12px;z-index:1200}.jvectormap-zoomin,.jvectormap-zoomout{left:10px;cursor:pointer;line-height:10px;text-align:center}.jvectormap-zoomin{top:10px}.jvectormap-zoomout{top:35px}.modal,.modal-backdrop{top:0;left:0;right:0;bottom:0}.wmd-panel{width:100%}.wmd-input{height:300px;width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box}.wmd-preview{width:100%;margin-top:20px}.wmd-panel .btn-toolbar{margin-bottom:0;padding:0 0 5px;width:100%}.fa-header:before{content:'H';font-family:arial,helvetica,sans-serif;font-weight:700}.wmd-prompt-background{background-color:#000}.wmd-prompt-dialog{border:1px solid #999;background-color:#F5F5F5}.wmd-prompt-dialog>div{font-size:.8em;font-family:arial,helvetica,sans-serif}.wmd-prompt-dialog>form>input[type=text]{border:1px solid #999;color:#000}.wmd-prompt-dialog>form>input[type=button]{border:1px solid #888;font-family:trebuchet MS,helvetica,sans-serif;font-size:.8em;font-weight:700}.wmd-button-group1{margin-left:5px!important}.wmd-button-bar{margin-bottom:5px}.close{font-size:21px;font-weight:700;line-height:1;float:right;opacity:.2;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20)}.close:focus,.close:hover{cursor:pointer;text-decoration:none;opacity:.5;color:#000;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;border:0;background:0 0;-webkit-appearance:none}.modal-open{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;z-index:1050;display:none;overflow:auto;overflow-y:scroll;-webkit-overflow-scrolling:touch}.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;border-radius:6px}.modal-content{position:relative;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;background-color:#fff;background-clip:padding-box;box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;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{min-height:16.43px;padding:15px;border-bottom:1px solid #dfe8f1}.modal-header .close{margin-top:2px}.modal-dialog{border:0;box-shadow:0 15px 45px rgba(0,0,0,.3)!important}.modal.display-block .modal-dialog{box-shadow:0 6px 25px rgba(0,0,0,.1)!important;-webkit-transform:translate(0,-20px);-ms-transform:translate(0,-20px);transform:translate(0,-20px)}.modal-title{line-height:1.42857143;margin:0}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #dfe8f1}.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}}@media (min-width:992px){.modal-lg{width:900px}}.display-block.modal{position:static;z-index:5;display:block;overflow:visible!important;opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.display-block.modal .modal-dialog{margin-bottom:0}.modal-open #page-content-wrapper{z-index:inherit}.ms-container{position:relative}.ms-container .glyph-icon{font-size:20px;line-height:30px;position:absolute;top:50%;left:50%;width:30px;height:30px;margin:-15px 0 0 -15px;text-align:center}.ms-container:after{font-size:0;line-height:0;display:block;visibility:hidden;clear:both;height:0;min-height:0;content:'.'}.ms-container .ms-selectable,.ms-container .ms-selection{float:left;width:45%;color:#555;background:#fff}.ms-container .ms-selection{float:right}.ms-container .ms-list{position:relative;overflow-y:auto;height:200px;padding:5px 10px;border-width:1px;border-style:solid}.ms-list li{line-height:20px;margin:5px 0;padding:3px 10px}.ms-container ul{margin:0;padding:0;list-style-type:none}.ms-container .ms-optgroup-container{width:100%}.ms-container .ms-optgroup-label{line-height:20px;margin:0;padding:3px 10px;cursor:pointer}.ms-container li.ms-hover{cursor:pointer}.ms-container li.disabled{cursor:text}.fileinput-button{position:relative;overflow:hidden}.fileinput-button input{font-size:200px;position:absolute;top:0;right:0;margin:0;cursor:pointer;opacity:0;-ms-filter:'alpha(opacity=0)';direction:ltr}@media screen\9{.fileinput-button input{font-size:100%;height:100%;filter:alpha(opacity=0)}}.fileupload-buttonbar .btn,.fileupload-buttonbar .toggle{float:left;margin-right:10px;margin-bottom:5px}.fileupload-buttonbar .toggle{margin-top:7px;margin-left:10px}.template-upload .size{margin:0}.progress-animated .bar,.progress-animated .progress-bar{background:url(../images/animated-overlay.gif)!important;filter:none}.fileupload-process{display:none;float:right}.files .processing .preview,.fileupload-processing .fileupload-process{display:block;width:32px;height:32px;background:url(../images/loader-dark.gif) center no-repeat;background-size:contain}.files audio,.files video{max-width:300px}table.table td .toggle{margin:7px 10px 0 0}@media (max-width:767px){.files .btn span,.files .toggle,.fileupload-buttonbar .toggle{display:none}.files .name{width:80px;word-wrap:break-word}.files audio,.files video{max-width:80px}.files canvas,.files img{max-width:100%}}.blueimp-gallery,.blueimp-gallery>.slides>.slide>.slide-content{position:absolute;top:0;right:0;bottom:0;left:0;-moz-backface-visibility:hidden}.blueimp-gallery>.slides>.slide>.slide-content{margin:auto;width:auto;height:auto;max-width:100%;max-height:100%;opacity:1}.blueimp-gallery{position:fixed;z-index:999999;overflow:hidden;background:#000;background:rgba(0,0,0,.9);opacity:0;display:none;direction:ltr;-ms-touch-action:none;touch-action:none}.blueimp-gallery-carousel{position:relative;z-index:auto;margin:1em auto;padding-bottom:56.25%;box-shadow:0 0 10px #000;-ms-touch-action:pan-y;touch-action:pan-y}.blueimp-gallery-display{display:block;opacity:1}.blueimp-gallery>.slides{position:relative;height:100%;overflow:hidden}.blueimp-gallery-carousel>.slides{position:absolute}.blueimp-gallery>.slides>.slide{position:relative;float:left;height:100%;text-align:center;-webkit-transition-timing-function:cubic-bezier(.645,.045,.355,1);-moz-transition-timing-function:cubic-bezier(.645,.045,.355,1);-ms-transition-timing-function:cubic-bezier(.645,.045,.355,1);-o-transition-timing-function:cubic-bezier(.645,.045,.355,1);transition-timing-function:cubic-bezier(.645,.045,.355,1)}.blueimp-gallery,.blueimp-gallery>.slides>.slide>.slide-content{-webkit-transition:opacity .5s linear;-moz-transition:opacity .5s linear;-ms-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear}.blueimp-gallery>.slides>.slide-loading{background:url(../img/loading.gif) center no-repeat;background-size:64px 64px}.blueimp-gallery>.slides>.slide-loading>.slide-content{opacity:0}.blueimp-gallery>.slides>.slide-error{background:url(../img/error.png) center no-repeat}.blueimp-gallery>.slides>.slide-error>.slide-content{display:none}.blueimp-gallery>.next,.blueimp-gallery>.prev{position:absolute;top:50%;left:15px;width:40px;height:40px;margin-top:-23px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-decoration:none;text-shadow:0 0 2px #000;text-align:center;background:#222;background:rgba(0,0,0,.5);-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;cursor:pointer;display:none}.blueimp-gallery>.next{left:auto;right:15px}.blueimp-gallery>.close,.blueimp-gallery>.title{position:absolute;top:15px;left:15px;margin:0 40px 0 0;font-size:20px;line-height:30px;color:#fff;text-shadow:0 0 2px #000;opacity:.8;display:none}.blueimp-gallery>.close{padding:15px;right:15px;left:auto;margin:-15px;font-size:30px;text-decoration:none;cursor:pointer}.dd,.dd-list{padding:0;list-style:none}.blueimp-gallery>.play-pause{position:absolute;right:15px;bottom:15px;width:15px;height:15px;background:url(../img/play-pause.png) no-repeat;cursor:pointer;opacity:.5;display:none}.blueimp-gallery-playing>.play-pause{background-position:-15px 0}.blueimp-gallery>.close:hover,.blueimp-gallery>.next:hover,.blueimp-gallery>.play-pause:hover,.blueimp-gallery>.prev:hover,.blueimp-gallery>.title:hover{color:#fff;opacity:1}.blueimp-gallery-controls>.close,.blueimp-gallery-controls>.next,.blueimp-gallery-controls>.play-pause,.blueimp-gallery-controls>.prev,.blueimp-gallery-controls>.title{display:block;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.blueimp-gallery-left>.prev,.blueimp-gallery-right>.next,.blueimp-gallery-single>.next,.blueimp-gallery-single>.play-pause,.blueimp-gallery-single>.prev{display:none}.blueimp-gallery>.close,.blueimp-gallery>.next,.blueimp-gallery>.play-pause,.blueimp-gallery>.prev,.blueimp-gallery>.slides>.slide>.slide-content{-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body:last-child .blueimp-gallery>.slides>.slide-error{background-image:url(../img/error.svg)}body:last-child .blueimp-gallery>.play-pause{width:20px;height:20px;background-size:40px 20px;background-image:url(../img/play-pause.svg)}body:last-child .blueimp-gallery-playing>.play-pause{background-position:-20px 0}.blueimp-gallery>.indicator{position:absolute;top:auto;right:15px;bottom:15px;left:15px;margin:0 40px;padding:0;list-style:none;text-align:center;line-height:10px;display:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.blueimp-gallery>.indicator>li{display:inline-block;width:9px;height:9px;margin:6px 3px 0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;border:1px solid transparent;background:#ccc;background:center no-repeat rgba(255,255,255,.25);border-radius:5px;box-shadow:0 0 2px #000;opacity:.5;cursor:pointer}.dd-empty,.dd-handle,.dd-placeholder{-moz-box-sizing:border-box;margin:5px 0}.blueimp-gallery>.indicator>.active,.blueimp-gallery>.indicator>li:hover{background-color:#fff;border-color:#fff;opacity:1}.blueimp-gallery-controls>.indicator{display:block;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.blueimp-gallery-single>.indicator,.blueimp-gallery>.slides>.slide>.video-content>video,.blueimp-gallery>.slides>.slide>.video-playing>a,.blueimp-gallery>.slides>.slide>.video-playing>img{display:none}.blueimp-gallery>.slides>.slide>.video-content>img{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:auto;height:auto;max-width:100%;max-height:100%;-moz-backface-visibility:hidden}.blueimp-gallery>.slides>.slide>.video-content>video{position:absolute;top:0;left:0;width:100%;height:100%}.blueimp-gallery>.slides>.slide>.video-content>iframe{position:absolute;top:100%;left:0;width:100%;height:100%;border:none}.blueimp-gallery>.slides>.slide>.video-playing>iframe{top:0}.blueimp-gallery>.slides>.slide>.video-content>a{position:absolute;top:50%;right:0;left:0;margin:-64px auto 0;width:128px;height:128px;background:url(../img/video-play.png) center no-repeat;opacity:.8;cursor:pointer}.dd,.dd-item>button,.dd-list{position:relative}.blueimp-gallery>.slides>.slide>.video-content>a:hover{opacity:1}.blueimp-gallery>.slides>.slide>.video-playing>video,.dd,.dd-list{display:block}.blueimp-gallery>.slides>.slide>.video-loading>a{background:url(../img/loading.gif) center no-repeat;background-size:64px 64px}body:last-child .blueimp-gallery>.slides>.slide>.video-content:not(.video-loading)>a{background-image:url(../img/video-play.svg)}.dd{font-size:13px;line-height:20px;margin:15px 0 0}.dd-list{margin:0}.dd-list .dd-list{padding-left:30px}.dd-collapsed .dd-list{display:none}.dd-empty,.dd-item,.dd-placeholder{font-size:13px;line-height:20px;position:relative;display:block;min-height:20px;margin:0;padding:0}.dd-handle{display:block;box-sizing:border-box;height:30px;padding:5px 10px;text-decoration:none;color:#333;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;background:#fafafa}.dd-handle:hover{background:#fff}.dd-item>button{font-size:12px;line-height:1;display:block;float:left;overflow:hidden;width:25px;height:20px;margin:5px 0;padding:0;cursor:pointer;text-align:center;white-space:nowrap;text-indent:100%;border:0;background:0 0}.dd-item>button:before{position:absolute;display:block;width:100%;content:'+';text-align:center;text-indent:0}.dd-item>button[data-action=collapse]:before{content:'-'}.dd-empty,.dd-placeholder{box-sizing:border-box;min-height:30px;padding:0;border:1px dashed #b6bcbf;background:#f2fbff}.dd-empty{min-height:100px;border:1px dashed #bbb;background-color:#dfe8f1;background-image:-webkit-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),-webkit-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-image:-moz-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),-moz-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-image:linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-position:0 0,30px 30px;background-size:60px 60px}.dd-dragel{position:absolute;z-index:9999}.dd-dragel>.dd-item .dd-handle{margin-top:0}.dd-dragel .dd-handle{-webkit-box-shadow:2px 4px 6px 0 rgba(0,0,0,.1);box-shadow:2px 4px 6px 0 rgba(0,0,0,.1)}#nestable-menu{margin:0 0 15px;padding:0}#nestable-output,#nestable2-output{-moz-box-sizing:border-box;box-sizing:border-box;width:100%;height:7em}#nestable2 .dd-handle{color:#fff;border:1px solid #999;background:#bbb}#nestable2 .dd-handle:hover{background:#bbb}#nestable2 .dd-item>button:before{color:#fff}.dd-hover>.dd-handle{background:#2ea8e5!important}.dd3-content{display:block;-moz-box-sizing:border-box;box-sizing:border-box;height:30px;margin:5px 0;padding:5px 10px 5px 40px;text-decoration:none;color:#333;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;background:#fafafa}.dd3-content:hover{color:#2ea8e5;background:#fff}.dd3-handle,.dd3-handle:hover{background:#ddd}.dd-dragel>.dd3-item>.dd3-content{margin:0}.dd3-item>button{margin-left:30px}.dd3-handle{position:absolute;top:0;left:0;overflow:hidden;width:30px;margin:0;cursor:pointer;white-space:nowrap;text-indent:100%;border:1px solid #aaa;border-top-right-radius:0;border-bottom-right-radius:0}.dd3-handle:before{font-size:20px;font-weight:400;position:absolute;top:3px;left:0;display:block;width:100%;content:'≡';text-align:center;text-indent:0;color:#fff}.popover,.popover-title:empty{display:none}.datepicker-dropdown:after,.datepicker-dropdown:before,.form-wizard>ul>li a:before,.popover .arrow:after{content:''}.noty-wrapper{font-size:14px;font-weight:700;position:fixed;z-index:10000;left:0;width:100%;margin:0;padding:0;list-style:none;opacity:95;-moz-opacity:95;filter:alpha(opacity: 95)}.noty-wrapper:hover{opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.noty_message{line-height:20px;padding:15px 10px;text-align:center}#noty_bottom{bottom:0}#noty_top{top:0}#noty_center{top:50%;left:50%}#noty_center li{margin:10px 0;border:0}.popover{z-index:1049;top:0;left:0;min-width:250px;margin:0;padding:0}.popover .popover-content{padding:15px}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{font-size:12px;font-weight:700;margin:0;padding:10px 15px;text-transform:uppercase;border-bottom-width:1px;border-bottom-style:solid}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-style:solid;border-color:transparent}.popover .arrow,.popover .arrow:after{border-width:10px}.popover.top .arrow{bottom:-22px;left:50%;margin-left:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:rgba(0,0,0,.2);border-bottom-width:0}.popover.right .arrow{top:50%;left:-22px;margin-top:-11px}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:rgba(0,0,0,.2);border-left-width:0}.popover.bottom .arrow{top:-22px;left:50%;margin-left:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:rgba(0,0,0,.2)}.popover.left .arrow{top:50%;right:-22px;margin-top:-11px}.popover.left .arrow:after{right:1px;bottom:-10px;border-right-width:0;border-left-color:rgba(0,0,0,.2)}.popover .dropdown-menu,.popover .nav-list{margin:0;border:0}.display-block.popover{box-shadow:0 0 0 transparent;float:none;width:auto;margin:15px}.fixed-header .popover{position:fixed;-webkit-transform:translate3d(0,0,0)}div.pp_default .pp_bottom,div.pp_default .pp_bottom .pp_left,div.pp_default .pp_bottom .pp_middle,div.pp_default .pp_bottom .pp_right,div.pp_default .pp_top,div.pp_default .pp_top .pp_left,div.pp_default .pp_top .pp_middle,div.pp_default .pp_top .pp_right{height:13px}div.pp_default .pp_top .pp_left{background:url(images/default/sprite.png) -78px -93px no-repeat}div.pp_default .pp_top .pp_middle{background:url(images/default/sprite_x.png) top left repeat-x}div.pp_default .pp_top .pp_right{background:url(images/default/sprite.png) -112px -93px no-repeat}div.pp_default .pp_content .ppt{color:#f8f8f8}div.pp_default .pp_content_container .pp_left{padding-left:13px;background:url(images/default/sprite_y.png) -7px 0 repeat-y}div.pp_default .pp_content_container .pp_right{padding-right:13px;background:url(images/default/sprite_y.png) top right repeat-y}div.pp_default .pp_content{background-color:#fff}div.pp_default .pp_next:hover{cursor:pointer;background:url(images/default/sprite_next.png) center right no-repeat}div.pp_default .pp_previous:hover{cursor:pointer;background:url(images/default/sprite_prev.png) center left no-repeat}div.pp_default .pp_expand{width:28px;height:28px;cursor:pointer;background:url(images/default/sprite.png) 0 -29px no-repeat}div.pp_default .pp_expand:hover{cursor:pointer;background:url(images/default/sprite.png) 0 -56px no-repeat}div.pp_default .pp_contract{width:28px;height:28px;cursor:pointer;background:url(images/default/sprite.png) 0 -84px no-repeat}div.pp_default .pp_contract:hover{cursor:pointer;background:url(images/default/sprite.png) 0 -113px no-repeat}div.pp_default .pp_close{width:30px;height:30px;cursor:pointer;background:url(images/default/sprite.png) 2px 1px no-repeat}div.pp_default #pp_full_res .pp_inline{color:#000}div.pp_default .pp_gallery ul li a{border:1px solid #aaa;background:url(images/default/default_thumb.png) center center #f8f8f8}div.pp_default .pp_gallery ul li a:hover,div.pp_default .pp_gallery ul li.selected a{border-color:#fff}div.pp_default .pp_social{margin-top:7px}div.pp_default .pp_gallery a.pp_arrow_next,div.pp_default .pp_gallery a.pp_arrow_previous{position:static;left:auto}div.pp_default .pp_nav .pp_pause,div.pp_default .pp_nav .pp_play{width:30px;height:30px;background:url(images/default/sprite.png) -51px 1px no-repeat}div.pp_default .pp_nav .pp_pause{background-position:-51px -29px}div.pp_default .pp_details{position:relative}div.pp_default a.pp_arrow_next,div.pp_default a.pp_arrow_previous{width:20px;height:20px;margin:4px 0 0;background:url(images/default/sprite.png) -31px -3px no-repeat}div.pp_default a.pp_arrow_next{left:52px;background-position:-82px -3px}div.pp_default .pp_content_container .pp_details{margin-top:5px}div.pp_default .pp_nav{position:relative;clear:none;width:110px;height:30px}div.pp_default .pp_nav .currentTextHolder{font-family:Georgia;font-size:11px;font-style:italic;line-height:25px;position:absolute;top:2px;left:75px;margin:0;padding:0 0 0 10px;color:#999}.progress-bar,.sb-slidebar .chat-box li a.chat-wrapper:hover,div.ppt{color:#fff}div.pp_default .pp_arrow_next:hover,div.pp_default .pp_arrow_previous:hover,div.pp_default .pp_close:hover,div.pp_default .pp_nav .pp_pause:hover,div.pp_default .pp_nav .pp_play:hover{opacity:.7}div.pp_default .pp_description{font-size:11px;font-weight:700;line-height:14px;margin:5px 50px 5px 0}div.pp_default .pp_bottom .pp_left{background:url(images/default/sprite.png) -78px -127px no-repeat}div.pp_default .pp_bottom .pp_middle{background:url(images/default/sprite_x.png) bottom left repeat-x}div.pp_default .pp_bottom .pp_right{background:url(images/default/sprite.png) -112px -127px no-repeat}div.pp_default .pp_loaderIcon{background:url(images/default/loader.gif) center center no-repeat}div.pp_overlay{position:absolute;z-index:9500;top:0;left:0;display:none;width:100%;background:#000}div.pp_pic_holder{position:absolute;z-index:10000;display:none;width:100px}.pp_top{position:relative;height:20px}* html .pp_top{padding:0 20px}.pp_top .pp_left{position:absolute;left:0;width:20px;height:20px}.pp_top .pp_middle{position:absolute;right:20px;left:20px;height:20px}* html .pp_top .pp_middle{position:static;left:0}.pp_top .pp_right{position:absolute;top:0;right:0;left:auto;width:20px;height:20px}.pp_content{min-width:40px;height:40px}* html .pp_content{width:40px}.pp_fade{display:none}.pp_content_container{position:relative;width:100%;text-align:left}.pp_content_container .pp_left{padding-left:20px}.pp_content_container .pp_right{padding-right:20px}.pp_content_container .pp_details{float:left;margin:10px 0 2px}.pp_description{display:none;margin:0}.pp_social{float:left;margin:0}.pp_social .facebook{float:left;overflow:hidden;width:55px;margin-left:5px}.pp_social .twitter{float:left}.pp_nav{float:left;clear:right;margin:3px 10px 0 0}.pp_nav p{float:left;margin:2px 4px;white-space:nowrap}.pp_nav .pp_pause,.pp_nav .pp_play{float:left;margin-right:4px;text-indent:-10000px}a.pp_arrow_next,a.pp_arrow_previous{display:block;float:left;overflow:hidden;width:14px;height:15px;margin-top:3px;text-indent:-10000px}.pp_hoverContainer{position:absolute;z-index:2000;top:0;width:100%}.pp_gallery{position:absolute;z-index:10000;left:50%;display:none;margin-top:-50px}.pp_gallery div{position:relative;float:left;overflow:hidden}.pp_gallery ul{position:relative;float:left;height:35px;margin:0 0 0 5px;padding:0;white-space:nowrap}a.pp_close,a.pp_contract,a.pp_expand{position:absolute;text-indent:-10000px}.pp_gallery ul a{display:block;float:left;overflow:hidden;height:33px;border:1px solid #000;border:1px solid rgba(0,0,0,.5)}.pp_gallery li.selected a,.pp_gallery ul a:hover{border-color:#fff}.pp_gallery ul a img{border:0}.pp_gallery li{display:block;float:left;margin:0 5px 0 0;padding:0}.pp_gallery li.default a{display:block;width:50px;height:33px;background:url(images/facebook/default_thumbnail.gif) no-repeat}.pp_gallery li.default a img{display:none}.pp_gallery .pp_arrow_next,.pp_gallery .pp_arrow_previous{margin-top:7px!important}a.pp_contract,a.pp_expand{z-index:20000;top:10px;right:30px;display:none;width:20px;height:20px;cursor:pointer}a.pp_close{line-height:22px;top:0;right:0;display:block}.pp_bottom{position:relative;height:20px}* html .pp_bottom{padding:0 20px}.pp_bottom .pp_left{position:absolute;left:0;width:20px;height:20px}.pp_bottom .pp_middle{position:absolute;right:20px;left:20px;height:20px}* html .pp_bottom .pp_middle{position:static;left:0}.pp_bottom .pp_right{position:absolute;top:0;right:0;left:auto;width:20px;height:20px}.pp_loaderIcon{position:absolute;top:50%;left:50%;display:block;width:24px;height:24px;margin:-12px 0 0 -12px}#pp_full_res{line-height:1!important}#pp_full_res .pp_inline{text-align:left}#pp_full_res .pp_inline p{margin:0 0 15px}div.ppt{font-size:17px;z-index:9999;display:none;margin:0 0 5px 15px}.progress,.progress-bar,.progress-label,.progress-overlay,.progressbar,.progressbar-value{font-weight:700;line-height:20px;height:20px;border-radius:4px}.progress,.progressbar{position:relative;text-align:center;background:rgba(0,0,0,.05);box-shadow:inset 1px 1px 3px rgba(0,0,0,.2)}.progress-bar,.progress-label,.progress-overlay,.progressbar-value{position:absolute;z-index:4;top:0;left:0;overflow:hidden}.progress .progress-bar{position:relative!important;border-radius:0}.progressbar-value.ui-state-default,.progressbar-value.ui-state-default .progress-label{line-height:18px;height:18px}.progress-label{z-index:6;width:100%}.progress-overlay{z-index:5;width:100%;opacity:.15;background:url(../../images/animated-overlay.gif);filter:alpha(opacity=15)}.progressbar-small .progress-label,.progressbar-small .progress-overlay,.progressbar-small .progressbar-value,.progressbar-small.progressbar{height:10px}.progressbar-small .progressbar-value.ui-state-default{height:8px}.progressbar-smaller .progress-label,.progressbar-smaller .progress-overlay,.progressbar-smaller .progressbar-value,.progressbar-smaller.progressbar{height:4px}.progressbar-smaller .progressbar-value.ui-state-default{height:2px}.bg-black .progress-overlay{opacity:1;filter:alpha(opacity=100)}@-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;border-radius:4px;background-color:#f5f5f5;-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{font-size:12px;line-height:20px;float:left;width:0;height:100%;-webkit-transition:width .6s ease;transition:width .6s ease;text-align:center;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15)}.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}.ui-rangeSlider{height:50px;padding-top:30px}.ui-rangeSlider-withArrows .ui-rangeSlider-container{margin:0 15px}.ui-rangeSlider-disabled.ui-rangeSlider-noArrow .ui-rangeSlider-container{border-color:#8490a3}.ui-rangeSlider-arrow,.ui-rangeSlider-container{height:20px}.ui-rangeSlider-arrow{width:14px;cursor:pointer}.ui-rangeSlider-leftArrow{border-radius:4px 0 0 4px}.ui-rangeSlider-rightArrow{border-radius:0 4px 4px 0}.ui-rangeSlider-arrow-inner{position:absolute;top:50%;width:0;height:0;margin-top:-5px;border:5px solid transparent}.ui-rangeSlider-leftArrow .ui-rangeSlider-arrow-inner{left:0;margin-left:-1px;border-right:5px solid #666}.ui-rangeSlider-leftArrow:hover .ui-rangeSlider-arrow-inner{border-right:5px solid #333}.ui-rangeSlider-rightArrow .ui-rangeSlider-arrow-inner{right:0;margin-right:-1px;border-left:5px solid #666}.ui-rangeSlider-rightArrow:hover .ui-rangeSlider-arrow-inner{border-left:5px solid #333}.ui-rangeSlider-innerBar{left:-10px;overflow:hidden;width:110%;height:100%}.ui-rangeSlider-bar{height:18px;margin:1px 0;cursor:move;cursor:grab;cursor:-moz-grab}.ui-rangeSlider-disabled .ui-rangeSlider-bar{background:#93aeca}.ui-rangeSlider-handle{width:10px;height:30px;cursor:col-resize;background:0 0}.ui-rangeSlider-label{font-size:15px;bottom:27px;padding:5px 10px;cursor:col-resize;color:#fff;background-color:rgba(0,0,0,.7)}.ui-rangeSlider-label:active,.ui-rangeSlider-label:hover{background:#000}.ui-rangeSlider-label-inner{position:absolute;z-index:99;top:100%;left:50%;display:block;margin-left:-5px;border-top:5px solid rgba(0,0,0,.7);border-right:5px solid transparent;border-left:5px solid transparent}.sb-left,.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-rangeSlider-label:active .ui-rangeSlider-label-inner,.ui-rangeSlider-label:hover .ui-rangeSlider-label-inner{border-top:5px solid #000}.ui-editRangeSlider-inputValue{font-size:15px;width:2em;text-align:center;border:0}#sb-site,.sb-site-container,.sb-slidebar,body,html{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}html.sb-scroll-lock.sb-active:not(.sb-static){overflow:hidden}#sb-site .sb-overlay{display:none}.sb-active #sb-site .sb-overlay{display:block}#sb-site,.sb-site-container{position:relative;width:100%}.sb-slidebar{position:fixed;z-index:0;top:0;display:none;overflow-y:auto;height:100%;overflow-x:hidden;-webkit-transform:translate(0);width:30%}.sb-slidebar.sb-right.sb-active{right:-3px}.sb-right{right:0}.sb-slidebar .scrollable-content{height:100%}.sb-slidebar.sb-static,html.sb-static .sb-slidebar{position:absolute}.sb-slidebar.sb-active{display:block}.sb-style-overlay{z-index:9999}.sb-momentum-scrolling{-webkit-overflow-scrolling:touch}.sb-width-thin{width:15%}.sb-width-wide{width:45%}@media (max-width:480px){.sb-slidebar{width:70%}.sb-width-thin{width:55%}.sb-width-wide{width:85%}}@media (min-width:481px){.sb-slidebar{width:55%}.sb-width-thin{width:40%}.sb-width-wide{width:70%}}@media (min-width:768px){.sb-slidebar{width:40%}.sb-width-thin{width:25%}.sb-width-wide{width:55%}}@media (min-width:992px){.sb-slidebar{width:30%}.sb-width-thin{width:15%}.sb-width-wide{width:45%}}@media (min-width:1200px){.sb-slidebar{width:350px}.sb-width-thin{width:5%}.sb-width-wide{width:35%}}#sb-site,.sb-site-container,.sb-slide,.sb-slidebar{-webkit-transition:-webkit-transform .4s ease;-moz-transition:-moz-transform .4s ease;-o-transition:-o-transform .4s ease;transition:transform .4s ease;-webkit-transition-property:-webkit-transform,left,right;-webkit-backface-visibility:hidden}.sb-hide{display:none}.sb-slidebar .popover-title{font-size:13px;font-size:11px;line-height:36px;display:block;height:36px;margin:2px 0;padding:0 15px;border-width:0}.sb-slidebar .divider{background:rgba(255,255,255,.1)}.sb-slidebar.sb-left .divider-header{font-size:14px;opacity:.4}.sb-slidebar .popover-title .caret{float:right;margin-top:17px}.sb-slidebar .progress-box li a{display:block;padding:0}.sb-slidebar .files-box{padding:10px 0}.sb-slidebar .files-box li.divider{margin:5px 0;padding:0}.sb-slidebar .notifications-box li,.sb-slidebar .progress-box li{padding:15px;border-color:rgba(255,255,255,.1)}.sb-slidebar .notifications-box li:last-child,.sb-slidebar .progress-box li:last-child{padding-bottom:20px}.sb-slidebar .notifications-box-alt li:first-child{padding-top:15px}.sb-slidebar ul.chat-box{margin:0;padding:0;list-style:none}.sb-slidebar .chat-box li{position:relative;margin:15px;padding:0}.sb-slidebar .chat-box li a.chat-wrapper{display:block;padding:10px}.sb-slidebar .chat-box li a.btn-md{position:absolute;top:50%;right:0;margin-top:-17px;padding:0 10px}.sb-slidebar .chat-box li a.btn-md .glyph-icon{opacity:.5}.sb-slidebar .chat-box li .status-badge{float:left;margin:0 10px 0 0}.sb-slidebar .chat-box li b{font-size:12px;display:block;padding:4px 0 0}.sb-slidebar .chat-box li p{font-size:11px;opacity:.6}.popover-title:hover{text-decoration:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle,.ui-slider .ui-slider-range,.ui-slider-horizontal,.ui-slider-vertical{-webkit-border-radius:100px;-moz-border-radius:100px;border-radius:100px}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:8px;height:8px;border:6px solid #FFF;box-sizing:initial;cursor:pointer;box-shadow:1px 1px 3px rgba(0,0,0,.3)}.ui-slider .ui-slider-handle:active,.ui-slider .ui-slider-handle:hover{border-color:#fff}.ui-slider .ui-slider-range{position:absolute;z-index:1;display:block;border:0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:7px;background:#ddd;-webkit-box-shadow:inset 0 1px 6px #717171;-moz-box-shadow:inset 0 1px 6px #717171;box-shadow:inset 0 1px 6px #717171}.ui-slider-horizontal .ui-slider-handle{top:-7px;margin-left:-7px}.ui-slider-horizontal .ui-slider-range{top:0;height:100%;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:7px;height:100px;background:#ddd;-webkit-box-shadow:inset 1px 0 6px #717171;-moz-box-shadow:inset 1px 0 6px #717171;box-shadow:inset 1px 0 6px #717171}.ui-slider-vertical .ui-slider-handle{left:-7px;margin-bottom:-8px;margin-left:0}.ui-slider-vertical .ui-slider-range{left:0;width:100%;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.note-editor{border:1px solid #bfc8d1}.note-editor .note-dropzone{position:absolute;z-index:1;display:none;opacity:.95;color:#87cefa;border:2px dashed #87cefa;background-color:#fff;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{font-size:28px;font-weight:700;display:table-cell;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf;border:2px dashed #098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor .note-toolbar{border-bottom:1px solid #bfc8d1;background-color:#FEFEFF}.note-editor.fullscreen{position:fixed;z-index:1050;top:0;left:0;width:100%}.note-editor.fullscreen .note-editable{background-color:#fff}.note-editor.codeview .note-editable,.note-editor.fullscreen .note-resizebar{display:none}.note-editor.codeview .note-codable{display:block}.note-editor .note-statusbar{background-color:#FEFEFF}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;cursor:s-resize;border-top:1px solid #bfc8d1}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #bfc8d1}.note-editor .note-editable{overflow:auto;padding:10px;outline:0}.note-editor .note-editable[contenteditable=false]{background-color:#dfe8f1}.note-editor .note-codable{font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;display:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;margin-bottom:0;padding:10px;resize:none;color:#ccc;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;background-color:#222;box-shadow:none;-ms-box-sizing:border-box}.note-popover .popover{max-width:none}.note-popover .popover .popover-content a{display:inline-block;overflow:hidden;max-width:200px;vertical-align:middle;white-space:nowrap;text-overflow:ellipsis}.editable-buttons,.editable-input,.note-dialog .note-help-dialog .note-shortcut-layout td{vertical-align:top}.note-popover .popover .arrow{left:20px}.note-popover .popover .popover-content,.note-toolbar{margin:0;padding:0 0 5px 5px}.note-popover .popover .popover-content>.btn-group,.note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,.note-popover .popover .popover-content .note-style blockquote,.note-popover .popover .popover-content .note-style h1,.note-popover .popover .popover-content .note-style h2,.note-popover .popover .popover-content .note-style h3,.note-popover .popover .popover-content .note-style h4,.note-popover .popover .popover-content .note-style h5,.note-popover .popover .popover-content .note-style h6,.note-toolbar .note-color .dropdown-menu .btn-group,.note-toolbar .note-style blockquote,.note-toolbar .note-style h1,.note-toolbar .note-style h2,.note-toolbar .note-style h3,.note-toolbar .note-style h4,.note-toolbar .note-style h5,.note-toolbar .note-style h6{margin:0}.note-popover .popover .popover-content .note-table .dropdown-menu,.note-toolbar .note-table .dropdown-menu{min-width:0;padding:5px}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker,.note-toolbar .note-table .dropdown-menu .note-dimension-picker{font-size:18px}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC)}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC)}.note-popover .popover .popover-content .note-color .dropdown-toggle,.note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover .popover-content .note-color .dropdown-menu,.note-toolbar .note-color .dropdown-menu{min-width:290px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,.note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{font-size:12px;margin:2px 7px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{font-size:12px;margin:5px;padding:0 3px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-popover .popover .popover-content .note-para .dropdown-menu,.note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-popover .popover .popover-content .note-para .dropdown-menu>div:first-child,.note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-popover .popover .popover-content .dropdown-menu,.note-toolbar .dropdown-menu{min-width:90px}.note-popover .popover .popover-content .dropdown-menu.right,.note-toolbar .dropdown-menu.right{right:0;left:auto}.note-popover .popover .popover-content .dropdown-menu.right::before,.note-toolbar .dropdown-menu.right::before{right:9px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.right::after,.note-toolbar .dropdown-menu.right::after{right:10px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu li a i,.note-toolbar .dropdown-menu li a i{visibility:hidden;color:#00bfff}.note-popover .popover .popover-content .dropdown-menu li a.checked i,.note-toolbar .dropdown-menu li a.checked i,.tooltip{visibility:visible}.note-popover .popover .popover-content .note-fontsize-10,.note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover .popover-content .note-color-palette,.note-toolbar .note-color-palette{line-height:1}.note-popover .popover .popover-content .note-color-palette div .note-color-btn,.note-toolbar .note-color-palette div .note-color-btn{width:17px;height:17px;margin:0;padding:0;border:1px solid #fff}.note-popover .popover .popover-content .note-color-palette div .note-color-btn:hover,.note-toolbar .note-color-palette div .note-color-btn:hover{border:1px solid #000}.note-dialog>div{display:none}.note-dialog .note-image-dialog .note-dropzone{font-size:30px;line-height:4;min-height:100px;margin-bottom:10px;text-align:center;color:#d3d3d3;border:4px dashed #d3d3d3}.note-dialog .note-help-dialog{font-size:12px;opacity:.9;color:#ccc;border:0;background:0 0;background-color:#222!important;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-dialog .note-help-dialog .modal-content{border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;background:0 0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-dialog .note-help-dialog a{font-size:12px;color:#fff}.note-dialog .note-help-dialog .title{font-size:14px;font-weight:700;padding-bottom:5px;color:#fff;border-bottom:#fff 1px solid}.note-dialog .note-help-dialog .modal-close{font-size:14px;cursor:pointer;color:#dd0}.note-dialog .note-help-dialog .note-shortcut-layout{width:100%}.note-dialog .note-help-dialog .note-shortcut{margin-top:8px}.note-dialog .note-help-dialog .note-shortcut th{font-size:13px;text-align:left;color:#dd0}.note-dialog .note-help-dialog .note-shortcut td:first-child{font-family:'Courier New';min-width:110px;padding-right:10px;text-align:right;color:#dd0}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid #000}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;opacity:.3;background-color:#000;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle,.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid #000}.note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;border:1px solid #000;background-color:#fff}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-selection-info{font-size:12px;right:0;bottom:0;margin:5px;padding:5px;opacity:.7;color:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;background-color:#000;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}.ui-tabs-nav{margin:0;padding:0;list-style:none;border-bottom:1px solid transparent}.ui-tabs-nav li>a{line-height:32px;height:32px;margin-right:5px;padding:0 20px;border-bottom:0}.ui-tabs-nav li{margin-bottom:-1px}.ui-tabs-panel{display:block;padding:15px;background:0 0}.ui-tabs-panel:last-child{border-bottom:0!important}.ui-tabs-nav>li,.ui-tabs-nav>li>a{position:relative;float:left}.ui-tabs-nav>li>a .float-left.glyph-icon{float:none!important;margin-right:5px}.ui-tabs-nav>li>a .float-right.glyph-icon{float:none!important;margin-right:0;margin-left:5px}.tabs-navigation>ul{margin:0;padding:0;border-width:1px;border-style:solid;border-radius:0;background:#fff}.tabs-navigation>ul li{margin:0}.tabs-navigation>ul li>a{font-size:20px;line-height:64px;height:64px;margin:0!important;padding:0 35px;border-right-width:1px;border-right-style:solid;border-radius:0;background:0 0}.tabs-navigation>ul li.ui-tabs-active a{line-height:64px;height:64px;margin:0!important;padding-bottom:0;color:#000!important;background:#eff4f6}.tabs-navigation>ul li.ui-tabs-active a:hover,.tabs-navigation>ul li>a:hover{background:#eff4f6}#theme-options{position:fixed;top:110px;right:-300px;z-index:9999;width:300px;-webkit-transition:transform .5s ease;-o-transition:transform .5s ease;transition:transform .5s ease}.btn.theme-switcher,.theme-switcher .glyph-icon{width:54px;height:50px;line-height:50px;display:block}#theme-options.active{transform:translateX(-300px);-ms-transform:translateX(-300px);-o-transform:translateX(-300px);-webkit-transform:translateX(-300px)}.btn.theme-switcher{font-size:27px;border-width:1px;border-style:solid;border-right:0;border-radius:3px 0 0 3px;text-align:center;position:absolute;left:-54px;top:25px;z-index:55;padding:0}#theme-switcher-wrapper,#theme-switcher-wrapper .header:first-child{border-top-left-radius:3px}#theme-switcher-wrapper{background:#fff;width:300px;padding:0;border-bottom-left-radius:3px;position:relative;z-index:60;-webkit-transition:transform .5s ease;-o-transition:transform .5s ease;transition:transform .5s ease;max-height:580px}#theme-options.active #theme-switcher-wrapper{box-shadow:0 4px 5px rgba(0,0,0,.3)}#theme-switcher-wrapper .header{background:#FEFEFF;border-top:#dfe8f1 solid 1px;border-bottom:#dfe8f1 solid 1px;text-transform:uppercase;padding:13px 15px 10px;font-size:12px}#theme-switcher-wrapper .header a{font-weight:700;text-transform:capitalize;float:right}#theme-switcher-wrapper ul+.header{border-radius:0}#theme-switcher-wrapper ul li{height:34px;line-height:28px;margin:5px 0;padding:0 15px;border-bottom:#dfe8f1 solid 1px}#theme-switcher-wrapper ul li:last-child{border-bottom:0;margin-bottom:0}#theme-switcher-wrapper ul li label{font-size:13px}.tocify-subheader li,.tooltip{font-size:12px}#theme-switcher-wrapper ul li .switch-toggle{float:right;margin-top:3px}.theme-color-wrapper h5{text-transform:capitalize;font-weight:700;font-size:12px;margin:0 5px 5px}.theme-color-wrapper{padding:10px}.theme-color-wrapper a{height:24px;width:24px;display:block;overflow:hidden;text-indent:-999em;float:left;margin:2px;border-radius:50px;border:2px solid #fff!important;box-shadow:1px 2px 3px rgba(0,0,0,.1);opacity:.8}.theme-color-wrapper a.active,.theme-color-wrapper a:hover{opacity:1;border-color:red!important}.bootstrap-timepicker{position:relative}.dropdown.bootstrap-timepicker{float:none}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block;padding:10px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{line-height:32px;width:42px;height:32px}.bootstrap-timepicker-widget table td.separator{width:auto;padding:0 5px}.bootstrap-timepicker-widget table td a{display:block;text-align:center}.bootstrap-timepicker-widget table td a i{margin:0 auto}.bootstrap-timepicker-widget table td input{width:100%;min-width:32px;margin:0;padding:0 5px;text-align:center}.bootstrap-timepicker-widget table td input.bootstrap-timepicker-meridian{font-weight:700}.tocify{margin-top:20px}.tocify li,.tocify ul{list-style:none;margin:0;padding:0;border:none;line-height:30px}.tocify-header{text-indent:10px}.tocify-item{margin-bottom:5px!important}.tocify-subheader{text-indent:20px;display:none}.tocify-subheader .tocify-subheader{text-indent:30px}.tocify-subheader .tocify-subheader .tocify-subheader{text-indent:40px}.nav-list .nav-header,.nav-list>li>a{margin:0}.nav-list>li>a{padding:5px}.tooltip{line-height:1.4;position:absolute;z-index:1030;display:block;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:8px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-8px;padding:0 5px}.tooltip-inner{max-width:200px;padding:10px 15px;text-align:center;text-decoration:none;color:#fff;background-color:rgba(0,0,0,.9)}.tooltip-arrow{position:absolute;width:0;height:0;border-style:solid;border-color:transparent}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,.9)}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:rgba(0,0,0,.9)}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:rgba(0,0,0,.9)}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,.9)}.bootstrap-touchspin .input-group-btn-vertical{position:relative;white-space:nowrap;width:1%;vertical-align:middle;display:table-cell}.bootstrap-touchspin .input-group-btn-vertical>.btn{display:block;float:none;width:100%;max-width:100%;padding:8px 10px;margin-left:-1px;height:auto;position:relative;overflow:hidden}.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up{border-radius:0 4px 0 0}.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down{margin-top:-2px;border-radius:0 0 4px}.bootstrap-touchspin .input-group-btn-vertical i{position:absolute;top:-8px;left:11px;font-size:9px;font-weight:400}div[id^=uniform-],div[id^=uniform-] input,div[id^=uniform-] span{line-height:18px;display:block;float:left;width:auto;width:20px;height:auto;height:20px;margin:0 3px 0 0;padding:0;cursor:pointer}div[id^=uniform-]{margin-right:10px;opacity:.9;filter:alpha(opacity=90);-moz-opacity:90}div[id^=uniform-] span{position:relative;display:-moz-inline-box;display:inline-block;zoom:1;margin-top:-1px;text-align:center;border-width:1px;border-style:solid}div.radio[id^=uniform-]>span{margin-top:-7px}.input-group-addon div[id^=uniform-] span i,div[id^=uniform-] span i{display:none}div[id^=uniform-] span.checked i{font-size:14px;line-height:18px;display:block;height:18px}div.radio[id^=uniform-] span.checked i{font-size:9px}div.radio[id^=uniform-] span{border-radius:50px}div[id^=uniform-] input{position:absolute;top:0;left:0;display:-moz-inline-box;display:inline-block;zoom:1;opacity:0;border:none;background:0 0;filter:alpha(opacity=0);-moz-opacity:0}div.checker[id^=uniform-] label{line-height:19px}div.selector{line-height:38px;position:relative;display:block;overflow:hidden;width:auto!important;height:38px;margin:0;padding:0 10px!important;cursor:pointer;white-space:nowrap;text-decoration:none;border-width:1px;border-style:solid}.selector i,div.selector span{line-height:38px;display:block;height:38px;padding:0!important}.selector i{position:absolute;z-index:4;top:50%;right:0;width:38px;margin-top:-19px;text-align:center;border-left:1px solid transparent}div.selector select{position:absolute;z-index:5;top:0;left:0;width:100%;height:38px;opacity:0;border:none;background:0 0;filter:alpha(opacity=0);-moz-opacity:0}div.selector span{width:auto!important}.form-wizard>ul{position:relative;display:table;width:100%;margin:0 0 20px;list-style:none}.form-wizard>ul>li{display:table-cell;width:1%;text-align:center}.form-wizard>ul>li a,.form-wizard>ul>li a:hover{position:relative;display:block;opacity:1;color:#666;-moz-opacity:1;filter:alpha(opacity: 100)}.form-wizard>ul>li a:before{position:absolute;z-index:4;top:20px;left:0;width:100%;height:4px;background:#ccc}.form-wizard>ul>li:first-child a:before{left:50%}.form-wizard>ul>li:last-child a:before{right:50%;left:auto;width:50%}.form-wizard>ul>li a .wizard-step{font-size:16px;line-height:42px;position:relative;z-index:5;display:block;width:40px;height:40px;margin:0 auto 5px;cursor:pointer;text-align:center;color:#fafafa;border-radius:100px;background:#ccc}.form-wizard>ul>li a .wizard-description{font-size:13px;font-weight:700;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.form-wizard>ul>li a .wizard-description small{font-size:12px;font-weight:400;display:block;padding:3px 0 0;opacity:.7;-moz-opacity:.7;filter:alpha(opacity: 70)}.form-wizard>ul>li a .wizard-description:hover,.form-wizard>ul>li.active a .wizard-description{opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.form-wizard>ul>li a.disabled .wizard-step{background:#ccc}.loader,.msgBox{display:none}.actionBar{margin-top:20px;margin-bottom:20px;padding:20px 0 0;border-top:#ddd solid 1px}.actionBar a.btn{float:right;margin-left:10px}/*! X-editable - v1.5.1 + */table.dataTable thead th{position:relative;background-image:none!important}table.dataTable thead th.sorting:after,table.dataTable thead th.sorting_asc:after,table.dataTable thead th.sorting_desc:after{position:absolute;top:12px;right:8px;display:block;font-family:FontAwesome}table.dataTable thead th.sorting:after{content:"\f0dc";font-size:13px}table.dataTable thead th.sorting_asc:after{content:"\f0de"}table.dataTable thead th.sorting_desc:after{content:"\f0dd"}table.table thead th.sorting:after,table.table thead th.sorting_asc:after,table.table thead th.sorting_desc:after{top:12px}div.dataTables_paginate a.paginate_button.first,div.dataTables_paginate a.paginate_button.previous{position:relative;padding-left:24px}div.dataTables_paginate a.paginate_button.last,div.dataTables_paginate a.paginate_button.next{position:relative;padding-right:24px}div.dataTables_paginate a.first:before,div.dataTables_paginate a.previous:before{position:absolute;top:8px;left:10px;display:block;font-family:FontAwesome}div.dataTables_paginate a.last:after,div.dataTables_paginate a.next:after{position:absolute;top:8px;right:10px;display:block;font-family:FontAwesome}div.dataTables_paginate a.first:before{content:"\f100"}div.dataTables_paginate a.previous:before{content:"\f104"}div.dataTables_paginate a.next:after{content:"\f105"}div.dataTables_paginate a.last:after{content:"\f101"}div.dataTables_paginate li.first>a,div.dataTables_paginate li.previous>a{position:relative;padding-left:24px}div.dataTables_paginate li.last>a,div.dataTables_paginate li.next>a{position:relative;padding-right:24px}div.dataTables_paginate li.first a:before,div.dataTables_paginate li.previous a:before{position:absolute;top:6px;left:10px;display:block;font-family:FontAwesome}div.dataTables_paginate li.last a:after,div.dataTables_paginate li.next a:after{position:absolute;top:6px;right:10px;display:block;font-family:FontAwesome}div.dataTables_paginate li.first a:before{content:"\f100"}div.dataTables_paginate li.previous a:before{content:"\f104"}div.dataTables_paginate li.next a:after{content:"\f105"}div.dataTables_paginate li.last a:after{content:"\f101"}div.columns div.dataTables_paginate li.first a:before,div.columns div.dataTables_paginate li.last a:after,div.columns div.dataTables_paginate li.next a:after,div.columns div.dataTables_paginate li.previous a:before{top:0}.DTTT_container{float:right;margin-left:10px}.DTTT_container a div{cursor:pointer}.dataTables_scrollBody table.dataTable thead th.sorting:after{display:none}.tr-selected,.tr-selected td{background:#eefacd!important;color:#393c31!important}table.dataTable.dtr-inline.collapsed tbody td:first-child,table.dataTable.dtr-inline.collapsed tbody th:first-child{position:relative;padding-left:30px;cursor:pointer}table.dataTable.dtr-inline.collapsed tbody td:first-child:before,table.dataTable.dtr-inline.collapsed tbody th:first-child:before{top:8px;left:4px;height:16px;width:16px;display:block;position:absolute;color:#fff;border:2px solid #fff;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#31b131}table.dataTable.dtr-inline.collapsed tbody td:first-child.dataTables_empty:before,table.dataTable.dtr-inline.collapsed tbody th:first-child.dataTables_empty:before,table.dataTable.dtr-inline.collapsed tbody tr.child td:before{display:none}table.dataTable.dtr-inline.collapsed tbody tr.parent td:first-child:before,table.dataTable.dtr-inline.collapsed tbody tr.parent th:first-child:before{content:'-';background-color:#d33333}table.dataTable.dtr-column tbody td.control,table.dataTable.dtr-column tbody th.control{position:relative;cursor:pointer}table.dataTable.dtr-column tbody td.control:before,table.dataTable.dtr-column tbody th.control:before{top:50%;left:50%;height:16px;width:16px;margin-top:-10px;margin-left:-10px;display:block;position:absolute;color:#fff;border:2px solid #fff;border-radius:16px;text-align:center;line-height:14px;box-shadow:0 0 3px #444;box-sizing:content-box;content:'+';background-color:#31b131}table.dataTable.dtr-column tbody tr.parent td.control:before,table.dataTable.dtr-column tbody tr.parent th.control:before{content:'-';background-color:#d33333}table.dataTable tr.child{padding:.5em 1em}table.dataTable tr.child:hover{background:0 0!important}table.dataTable tr.child ul{display:inline-block;list-style-type:none;margin:0;padding:0}table.dataTable tr.child ul li{border-bottom:1px solid #efefef;padding:.5em 0}table.dataTable tr.child ul li:first-child{padding-top:0}table.dataTable tr.child ul li:last-child{border-bottom:none}table.dataTable tr.child span.dtr-title{display:inline-block;min-width:75px;font-weight:700}div.FixedHeader_Cloned td,div.FixedHeader_Cloned th{background-color:#fff!important}.DTFC_LeftBodyLiner .table,.DTFC_LeftFootWrapper .table{margin:0!important}table.DTCR_clonedT + +/* Fix for tiny text throughout CyberPanel */ +small { + font-size: 0.875rem !important; + line-height: 1.4; +} + +/* Ensure form helper text is readable */ +.form-text, .help-block, .help-text { + font-size: 0.875rem !important; + line-height: 1.4; +} + +/* Fix for any inline small text */ +[style*="font-size: 0.6"], +[style*="font-size: 0.7"], +[style*="font-size: 10px"], +[style*="font-size: 11px"] { + font-size: 0.875rem !important; +}able{background-color:rgba(255,255,255,.7);z-index:202}div.DTCR_pointer{width:1px;background-color:#0259C4;z-index:201}.DTFC_LeftBodyLiner .table thead th:after{display:none!important}.bsdatepicker:after,.bsdatepicker:before{position:absolute;display:inline-block;content:''}.bsdatepicker{top:0;left:0;margin-top:1px;padding:4px!important}.bsdatepicker:before{top:-7px;left:6px;border-right:7px solid transparent;border-bottom:7px solid transparent;border-bottom-color:transparent;border-left:7px solid transparent}.bsdatepicker:after{top:-6px;left:7px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.bsdatepicker>div{display:none}.bsdatepicker table{width:100%;margin:0}.bsdatepicker td,.bsdatepicker th{width:20px;height:20px;margin:3px;text-align:center}.bsdatepicker td.day:hover{cursor:pointer}.bsdatepicker td.day.disabled{color:#eee}.bsdatepicker td span.old,.bsdatepicker td.new,.bsdatepicker td.old{color:#999}.bsdatepicker td span{line-height:44px;display:block;float:left;width:54px;height:44px;margin:2px;cursor:pointer}.bsdatepicker th.switch{width:145px}.bsdatepicker th.next,.bsdatepicker th.prev{font-size:21px}.bsdatepicker thead tr:first-child th{cursor:pointer}.ui-datepicker-inline{position:static!important;width:100%;float:none;margin-top:0}.ui-datepicker .ui-datepicker-header,.ui-datepicker-header{font-size:13px;line-height:40px;position:relative;height:40px}.ui-datepicker .ui-datepicker-next,.ui-datepicker .ui-datepicker-prev{position:absolute;top:50%;overflow:hidden;width:30px;height:30px;margin-top:-15px;cursor:pointer;border-width:1px;border-style:solid}.ui-datepicker .ui-datepicker-prev{left:5px}.ui-datepicker .ui-datepicker-next{right:5px}.ui-datepicker .ui-datepicker-next span,.ui-datepicker .ui-datepicker-prev span{line-height:28px;display:block;float:none;height:28px;margin:0 auto;text-align:center}.ui-datepicker .ui-datepicker-title{font-weight:700;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:13px;height:28px;margin:0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{font-size:13px;line-height:1.6em;width:96%;margin:2%;border-collapse:collapse}.ui-datepicker th{font-weight:700;padding:0 0 5px;text-align:center;border:0}.ui-datepicker td{padding:1px;border:0}.ui-datepicker td a,.ui-datepicker td span{font-size:13px;display:block;padding:2px 5px;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{padding:10px}.ui-datepicker .ui-datepicker-buttonpane button{line-height:26px;float:right;height:28px;padding:0 15px;border-width:1px;border-style:solid;background:#fff}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-radius:0}.ui-datepicker-row-break{font-size:0;clear:both;width:100%}.daterangepicker.dropdown-menu{z-index:3000;max-width:none}.daterangepicker.opensleft .calendar,.daterangepicker.opensleft .ranges{float:left;margin:4px}.daterangepicker.opensright .calendar,.daterangepicker.opensright .ranges{float:right;margin:4px}.daterangepicker .ranges{width:188px;margin:0 0 0 10px;text-align:left}.daterangepicker .ranges .range_inputs>div{float:left}.daterangepicker .ranges .range_inputs>div:nth-child(2){padding-left:11px}.daterangepicker .calendar{display:none;max-width:270px}.show-calendar.daterangepicker .calendar{display:block}.daterangepicker .applyBtn{float:right;width:110px}.daterangepicker .cancelBtn{float:left}.daterangepicker .calendar td,.daterangepicker .calendar th{font-size:12px;text-align:center;white-space:nowrap}.daterangepicker .ranges label{font-size:11px;font-weight:700;line-height:20px;display:block;width:74px;height:20px;margin-bottom:2px;text-transform:uppercase;color:#333}.daterangepicker .ranges input{font-size:11px}.daterangepicker .ranges .input-mini{font-size:11px;line-height:30px;display:block;width:88px;height:30px;margin:0 0 10px;padding:0 6px;vertical-align:middle;color:#555;border:1px solid #ccc;border-radius:4px;background-color:#eee}.daterangepicker.opensleft:after,.daterangepicker.opensleft:before,.daterangepicker.opensright:after,.daterangepicker.opensright:before{position:absolute;display:inline-block;content:''}.daterangepicker .ranges ul{margin:0;padding:0;list-style:none}.daterangepicker .ranges li{margin-bottom:3px;padding:3px 12px;cursor:pointer}.daterangepicker .calendar-date{padding:5px;border-width:1px;border-style:solid;background:#fff}.daterangepicker .calendar-time{line-height:30px;margin:8px auto 0;text-align:center}.daterangepicker{position:absolute;top:100px;left:20px;margin-top:1px;padding:5px!important;background:#fff}.daterangepicker.opensleft:before{top:-7px;right:9px;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);border-left:7px solid transparent}.daterangepicker.opensleft:after{top:-6px;right:10px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.daterangepicker.opensright:before{top:-7px;left:9px;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);border-left:7px solid transparent}.daterangepicker.opensright:after{top:-6px;left:10px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.daterangepicker table{width:100%;margin:0}.daterangepicker td,.daterangepicker th{width:20px;height:20px;cursor:pointer;text-align:center;white-space:nowrap}.daterangepicker td.off{color:#999}.daterangepicker td.in-range{border-radius:0}.daterangepicker td.in-range:hover{color:#000}.daterangepicker td.week,.daterangepicker th.week{font-size:80%;color:#ccc}.daterangepicker select.monthselect,.daterangepicker select.yearselect{font-size:12px;height:auto;margin:0;padding:1px;cursor:default}.daterangepicker select.monthselect{width:56%;margin-right:2%}.daterangepicker select.yearselect{width:40%}.daterangepicker select.ampmselect,.daterangepicker select.hourselect,.daterangepicker select.minuteselect{width:50px;margin-bottom:0}.ui-dialog .ui-dialog-titlebar{position:relative;padding:10px;border-bottom:1px solid transparent}.ui-dialog .ui-dialog-title{overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{line-height:20px;position:absolute;top:50%;right:10px;width:20px;height:20px;margin:-10px 0 0;border:1px solid #ccc;background:#fff}.ui-dialog .ui-dialog-titlebar-close:before{line-height:18px;position:absolute;top:0;left:0;width:18px;height:18px;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-dialog .ui-dialog-titlebar-close:hover:before{opacity:.9;-moz-opacity:.9;filter:alpha(opacity: 90)}.ui-dialog .ui-dialog-titlebar-close .ui-button-text{display:none}.ui-dialog .ui-dialog-content{position:relative;overflow:auto;padding:0;border:0;background:0 0}.ui-dialog-buttonset button{padding:8px 15px;border-width:1px;border-style:solid}.ui-dialog .ui-dialog-buttonpane{border-width:1px 0 0!important}.ui-dialog .ui-dialog-buttonpane .ui-button{line-height:28px;float:right;height:28px;padding:0 15px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-dialog .infobox,.ui-dialog .ui-tabs{margin-bottom:0}.ui-dialog .ui-tabs .ui-tabs-panel{padding:10px}.ui-widget-overlay{position:fixed;z-index:1049;top:0;left:0;width:100%;height:100%}.ui-widget-overlay img{position:absolute;top:50%;left:50%;margin:-27px 0 0 -27px}.ui-resizable{position:relative}.ui-resizable-handle{font-size:.1px;position:absolute;display:block}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{top:-5px;left:0;width:100%;height:7px;cursor:n-resize}.ui-resizable-s{bottom:-5px;left:0;width:100%;height:7px;cursor:s-resize}.ui-resizable-e{top:0;right:-5px;width:7px;height:100%;cursor:e-resize}.ui-resizable-w{top:0;left:-5px;width:7px;height:100%;cursor:w-resize}.ui-resizable-se{right:1px;bottom:1px;width:12px;height:12px;cursor:se-resize}.ui-resizable-sw{bottom:-5px;left:-5px;width:9px;height:9px;cursor:sw-resize}.ui-resizable-nw{top:-5px;left:-5px;width:9px;height:9px;cursor:nw-resize}.ui-resizable-ne{top:-5px;right:-5px;width:9px;height:9px;cursor:ne-resize}.dropdown,.dropup{position:relative;display:inline-block}.dropdown-menu,.minicolors-panel,.popover,.ui-datepicker,.ui-dialog,.ui-menu{position:absolute;z-index:1050!important;top:105%;left:0;display:none;float:left;min-width:150px;margin:5px 0 0;padding:5px;list-style:none;text-align:left;border-width:1px;border-style:solid;background:#fff}.ui-datepicker{padding:0}.dropdown-menu,.popover,.ui-dialog{box-shadow:0 1px 7px 2px rgba(135,158,171,.2)}.dropdown-menu{font-size:13px;line-height:1.6em;padding:5px 0;text-transform:none;border:0;min-width:150px}.dropdown-menu,.minicolors-panel,.popover,.ui-menu{top:100%}.dropdown-menu .divider{margin:5px 1px}.dropdown-menu.float-right{right:0;left:auto}.dropdown-menu .header{font-size:11px;font-weight:700;line-height:1.4em;margin:0 0 5px;padding:5px 5px 10px;text-transform:uppercase;color:#888;border-bottom:#dfe8f1 solid 1px}.dropdown-menu .dropdown-header{font-size:11px;font-weight:300;padding:5px 15px;text-transform:uppercase;color:#000}.dropdown-menu li{position:relative}.dropdown-menu li>a,.ui-menu li>a{font-weight:400;line-height:20px;position:relative;display:block;clear:both;margin:0;padding:5px 15px;cursor:pointer;white-space:nowrap}.dropdown>.dropdown-menu:before,.minicolors-position-bottom .minicolors-panel:before{position:absolute;top:-7px;left:7px;display:inline-block;content:'';border-right:7px solid transparent;border-bottom:7px solid transparent;border-bottom-color:transparent;border-left:7px solid transparent}.dropdown>.dropdown-menu:after,.minicolors-position-bottom .minicolors-panel:after{position:absolute;top:-6px;left:8px;display:inline-block;content:'';border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.dropdown>.dropdown-menu.float-right:before,.dropup>.dropdown-menu.float-right:before,.minicolors-position-right .minicolors-panel:before{right:7px;left:auto}.dropdown>.dropdown-menu.float-right:after,.dropup>.dropdown-menu.float-right:after,.minicolors-position-right .minicolors-panel:after{right:8px;left:auto}.minicolors-inline .minicolors-panel:after,.minicolors-inline .minicolors-panel:before{display:none}.dropdown-dividers{padding:0}.dropdown-dividers li{padding:3px;border-bottom:#ccc solid 1px}.dropdown-dividers li:last-child{border-bottom:0}.dropdown-dividers li>a{padding:2px 10px}.push-left{left:100%!important;margin-left:-30px}.open>.dropdown-menu{display:block}.dropup .dropdown-menu{top:auto;bottom:100%;margin-bottom:8px}.dropup>.dropdown-menu:before,.minicolors-position-top .minicolors-panel:before{position:absolute;bottom:-7px;left:7px;display:inline-block;content:'';border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);border-right:7px solid transparent;border-left:7px solid transparent}.dropup>.dropdown-menu:after,.minicolors-position-top .minicolors-panel:after{position:absolute;bottom:-6px;left:8px;display:inline-block;content:'';border-top:6px solid #fff;border-right:6px solid transparent;border-left:6px solid transparent}.minicolors-position-top.minicolors-position-right .minicolors-panel:before{right:6px;left:auto}.minicolors-position-top.minicolors-position-right .minicolors-panel:after{right:7px;left:auto}.dropdown-submenu{position:relative;z-index:40}.dropdown-submenu>.dropdown-menu{top:50%;left:90%;margin-top:-6px;margin-left:-1px;border-radius:0 4px 4px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;border-radius:4px 4px 4px 0}.dropdown-submenu>a:after{position:relative;display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-5px;content:' ';opacity:.4;border-width:5px 0 5px 5px;border-style:solid;border-color:transparent transparent transparent #ccc;-moz-opacity:.4;filter:alpha(opacity: 40)}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.float-left{float:none!important}.dropdown-submenu.float-left>.dropdown-menu{left:-110%;margin-left:10px;border-radius:4px 0 4px 4px}.dropdown-submenu.float-left>.dropdown-menu.dropdown-dividers{margin-left:20px}.ui-menu-item{padding:3px 6px}.dropzone,.dropzone *,.dropzone-previews,.dropzone-previews *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.dropzone{padding:1em;border:1px solid rgba(0,0,0,.08);background:rgba(0,0,0,.02)}.dropzone.dz-clickable,.dropzone.dz-clickable .dz-message,.dropzone.dz-clickable .dz-message span{cursor:pointer}.dropzone.dz-clickable *{cursor:default}.dropzone .dz-message{opacity:1;-ms-filter:none;filter:none}.dropzone.dz-drag-hover{border-color:rgba(0,0,0,.15);background:rgba(0,0,0,.04)}.dropzone.dz-started .dz-message{display:none}.dropzone .dz-preview,.dropzone-previews .dz-preview{position:relative;display:inline-block;margin:17px;padding:6px;vertical-align:top;border:1px solid #acacac;background:rgba(255,255,255,.8)}.btn-file,.fileinput .btn,.fileinput .thumbnail,.fileinput-filename{vertical-align:middle}.dropzone .dz-preview.dz-file-preview [data-dz-thumbnail],.dropzone-previews .dz-preview.dz-file-preview [data-dz-thumbnail]{display:none}.dropzone .dz-preview .dz-details,.dropzone-previews .dz-preview .dz-details{position:relative;width:100px;height:100px;margin-bottom:22px;padding:5px;background:#ebebeb}.dropzone .dz-preview .dz-details .dz-filename,.dropzone-previews .dz-preview .dz-details .dz-filename{overflow:hidden;height:100%}.dropzone .dz-preview .dz-details img,.dropzone-previews .dz-preview .dz-details img{position:absolute;top:0;left:0;width:100px;height:100px}.dropzone .dz-preview .dz-details .dz-size,.dropzone-previews .dz-preview .dz-details .dz-size{line-height:28px;position:absolute;bottom:-28px;left:3px;height:28px}.dropzone .dz-preview.dz-error .dz-error-mark,.dropzone .dz-preview.dz-success .dz-success-mark,.dropzone-previews .dz-preview.dz-error .dz-error-mark,.dropzone-previews .dz-preview.dz-success .dz-success-mark{display:block}.dropzone .dz-preview:hover .dz-details img,.dropzone-previews .dz-preview:hover .dz-details img{display:none}.dropzone .dz-preview .dz-error-mark,.dropzone .dz-preview .dz-success-mark,.dropzone-previews .dz-preview .dz-error-mark,.dropzone-previews .dz-preview .dz-success-mark{font-size:30px;position:absolute;top:-10px;right:-10px;display:none;width:40px;height:40px;text-align:center}.dropzone .dz-preview .dz-success-mark,.dropzone-previews .dz-preview .dz-success-mark{color:#8cc657}.dropzone .dz-preview .dz-error-mark,.dropzone-previews .dz-preview .dz-error-mark{color:#ee162d}.dropzone .dz-preview .dz-progress,.dropzone-previews .dz-preview .dz-progress{position:absolute;top:100px;right:6px;left:6px;display:none;height:6px;background:#d7d7d7}.dropzone .dz-preview .dz-progress .dz-upload,.dropzone-previews .dz-preview .dz-progress .dz-upload{position:absolute;top:0;bottom:0;left:0;width:0;background-color:#8cc657}.dropzone .dz-preview.dz-processing .dz-progress,.dropzone-previews .dz-preview.dz-processing .dz-progress{display:block}.dropzone .dz-preview .dz-error-message,.dropzone-previews .dz-preview .dz-error-message{position:absolute;z-index:500;top:-5px;left:-20px;display:none;min-width:140px;max-width:500px;padding:8px 10px;color:#800;background:rgba(245,245,245,.8)}.dropzone .dz-preview:hover.dz-error .dz-error-message,.dropzone-previews .dz-preview:hover.dz-error .dz-error-message{display:block}.dropzone{position:relative;min-height:350px;cursor:pointer}.dz-message{font-size:35px;line-height:50px;position:absolute;top:50%;left:50%;width:50%;height:50px;margin-top:-50px;margin-left:-25%;padding:25px;text-align:center}.btn-file{position:relative;overflow:hidden}.btn-file>input{position:absolute;top:0;right:0;width:100%;height:100%;margin:0;font-size:23px;cursor:pointer;filter:alpha(opacity=0);opacity:0;direction:ltr}.fileinput{display:inline-block;margin-bottom:9px}.fileinput .form-control{display:inline-block;padding-top:7px;padding-bottom:5px;margin-bottom:0;vertical-align:middle;cursor:text}.fileinput .thumbnail{display:inline-block;margin-bottom:5px;overflow:hidden;text-align:center}.fileinput .thumbnail>img{max-height:100%}.fileinput-exists .fileinput-new,.fileinput-new .fileinput-exists{display:none}.fileinput-inline .fileinput-controls{display:inline}.fileinput-filename{display:inline-block;overflow:hidden}.form-control .fileinput-filename{vertical-align:bottom}.fileinput.input-group{display:table}.fileinput.input-group>*{position:relative;z-index:2}.fileinput.input-group>.btn-file{z-index:1}.fileinput-new .input-group .btn-file,.fileinput-new.input-group .btn-file{border-radius:0 4px 4px 0}.fileinput-new .input-group .btn-file.btn-sm,.fileinput-new .input-group .btn-file.btn-xs,.fileinput-new.input-group .btn-file.btn-sm,.fileinput-new.input-group .btn-file.btn-xs{border-radius:0 3px 3px 0}.fileinput-new .input-group .btn-file.btn-lg,.fileinput-new.input-group .btn-file.btn-lg{border-radius:0 6px 6px 0}.form-group.has-warning .fileinput .fileinput-preview{color:#8a6d3b}.form-group.has-warning .fileinput .thumbnail{border-color:#faebcc}.form-group.has-error .fileinput .fileinput-preview{color:#a94442}.form-group.has-error .fileinput .thumbnail{border-color:#ebccd1}.form-group.has-success .fileinput .fileinput-preview{color:#3c763d}.form-group.has-success .fileinput .thumbnail{border-color:#d6e9c6}.bootstrap-switch{line-height:8px;position:relative;display:inline-block;overflow:hidden;min-width:100px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-align:left;vertical-align:middle;border:1px solid #ccc;border-radius:4px}.irs,.jcrop-tracker{-webkit-user-select:none}.bootstrap-switch.bootstrap-switch-mini{min-width:71px}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label{font-size:10px;line-height:9px;padding-top:4px;padding-bottom:4px}.bootstrap-switch.bootstrap-switch-small{min-width:79px}.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label{font-size:12px;line-height:18px;padding-top:3px;padding-bottom:3px}.bootstrap-switch.bootstrap-switch-large{min-width:120px}.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label{font-size:14px;line-height:normal;padding-top:9px;padding-bottom:9px}.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container{-webkit-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-container{margin-left:0}.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label{border-top-right-radius:3px;border-bottom-right-radius:3px}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-container{margin-left:-50%}.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label{border-top-left-radius:3px;border-bottom-left-radius:3px}.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-container{margin-left:-25%}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-indeterminate,.bootstrap-switch.bootstrap-switch-readonly{cursor:default!important;opacity:.5;filter:alpha(opacity=50)}.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label{cursor:default!important}.bootstrap-switch.bootstrap-switch-focused{border-color:#ccc;outline:0}.bootstrap-switch .bootstrap-switch-container{top:0;display:inline-block;width:150%;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);border-radius:4px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-label{font-size:12px;line-height:20px;text-transform:uppercase;display:inline-block!important;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;height:100%;padding-top:4px;padding-bottom:4px;cursor:pointer}div.switch-toggle,div.switch-toggle:after{display:block;background:#fff;border-radius:50px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on{z-index:1;width:33.333333333%;text-align:center}.bootstrap-switch .bootstrap-switch-label{z-index:100;width:33.333333333%;margin-top:-1px;margin-bottom:-1px;text-align:center;color:#333;background:#fff}.bootstrap-switch input[type=radio],.bootstrap-switch input[type=checkbox]{position:absolute!important;z-index:-1;top:0;left:0;opacity:0;filter:alpha(opacity=0)}.bootstrap-switch input[type=radio].form-control,.bootstrap-switch input[type=checkbox].form-control{height:auto}div.switch-toggle{height:24px;width:48px;position:relative;cursor:pointer;box-shadow:inset 0 0 1px rgba(0,0,0,.2);-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;transition:all .2s ease}div.switch-toggle:after,div.switch-toggle:before{position:absolute;content:''}div.switch-toggle:after{height:18px;width:18px;top:3px;left:3px;box-shadow:1px 1px 3px rgba(0,0,0,.3);-webkit-transition:all .2s ease;-moz-transition:all .2s ease;-o-transition:all .2s ease;transition:all .2s ease}div.switch-toggle:before{right:1px;top:12px;color:#fff}.irs,.irs-line{position:relative;display:block}div.switch-toggle:hover:after{left:5px}div.switch-toggle.switch-on:before{content:'';right:40px}.switch-toggle.switch-on{background:#0c0}div.switch-toggle.switch-on:after{left:26px}div.switch-toggle.switch-on:hover:after{left:24px}.irs{-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.irs-line{overflow:hidden;outline:0!important}.irs-line-left,.irs-line-mid,.irs-line-right{position:absolute;display:block;top:0}.irs-line-left{left:0;width:11%}.irs-line-mid{left:9%;width:82%}.irs-line-right{right:0;width:11%}.irs-bar,.irs-shadow{position:absolute;width:0;left:0}.irs-bar{display:block}.irs-bar-edge{position:absolute;display:block;top:0;left:0}.irs-shadow{display:none}.irs-from,.irs-max,.irs-min,.irs-single,.irs-slider,.irs-to{display:block;position:absolute;cursor:default}.irs-slider{z-index:1}.irs-slider.type_last{z-index:2}.irs-min{left:0}.irs-max{right:0}.irs-from,.irs-single,.irs-to{top:0;left:0;white-space:nowrap}.irs-grid{position:absolute;display:none;bottom:0;left:0;width:100%;height:20px}.irs-with-grid .irs-grid{display:block}.irs-grid-pol{position:absolute;top:0;left:0;width:1px;height:8px;background:#000}.irs-grid-pol.small{height:4px}.irs-grid-text{position:absolute;bottom:0;left:0;white-space:nowrap;text-align:center;font-size:9px;line-height:9px;padding:0 3px;color:#000}.irs-disable-mask{position:absolute;display:block;top:0;left:-1%;width:102%;height:100%;cursor:default;background:rgba(0,0,0,0);z-index:2}.irs-disabled{opacity:.4}.lt-ie9 .irs-disabled{filter:alpha(opacity=40)}.irs-hidden-input{position:absolute!important;display:block!important;top:0!important;left:0!important;width:0!important;height:0!important;font-size:0!important;line-height:0!important;padding:0!important;margin:0!important;outline:0!important;z-index:-9999!important;background:0 0!important;border-style:solid!important;border-color:transparent!important}.jcrop-dragbar.ord-s,.jcrop-handle.ord-s,.jcrop-handle.ord-se,.jcrop-handle.ord-sw{margin-bottom:-4px;bottom:0}.jcrop-dragbar.ord-e,.jcrop-handle.ord-e,.jcrop-handle.ord-ne,.jcrop-handle.ord-se{right:0;margin-right:-4px}.modal,.modal-content,.note-air-editor,div.pp_pic_holder a:focus{outline:0}.jcrop-holder{text-align:left;direction:ltr}.jcrop-hline,.jcrop-vline{font-size:0;position:absolute;background:url(../../images/jcrop.gif) #fff}.jcrop-vline{width:1px!important;height:100%}.jcrop-vline.right{right:0}.jcrop-hline{width:100%;height:1px!important}.jcrop-hline.bottom{bottom:0}.jcrop-tracker{width:100%;height:100%;-webkit-tap-highlight-color:transparent}.jcrop-handle{font-size:1px;width:7px;height:7px;border:1px solid #eee;background-color:#333}.jcrop-handle.ord-n{top:0;left:50%;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-s{left:50%;margin-left:-4px}.jcrop-handle.ord-e{top:50%;margin-top:-4px}.jcrop-handle.ord-w{top:50%;left:0;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-nw{top:0;left:0;margin-top:-4px;margin-left:-4px}.jcrop-handle.ord-ne{top:0;margin-top:-4px}.jcrop-handle.ord-sw{left:0;margin-left:-4px}.jcrop-dragbar.ord-n,.jcrop-dragbar.ord-s{width:100%;height:7px}.jcrop-dragbar.ord-e,.jcrop-dragbar.ord-w{width:7px;height:100%}.jcrop-dragbar.ord-n{margin-top:-4px}.jcrop-dragbar.ord-w{margin-left:-4px}.jcrop-light .jcrop-hline,.jcrop-light .jcrop-vline{opacity:.7!important;background:#fff;filter:alpha(opacity=70)!important}.jcrop-light .jcrop-handle{border-color:#fff;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#000}.jcrop-dark .jcrop-hline,.jcrop-dark .jcrop-vline{opacity:.7!important;background:#000;filter:alpha(opacity=70)!important}.jcrop-dark .jcrop-handle{border-color:#000;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#fff}.solid-line .jcrop-hline,.solid-line .jcrop-vline{background:#fff}.jcrop-holder img,img.jcrop-preview{max-width:none}.jcrop-holder #preview-pane{position:absolute;z-index:2000;top:10px;right:-280px;display:block;padding:6px;border:1px solid rgba(0,0,0,.4);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;background-color:#fff}#preview-pane .preview-container{overflow:hidden;width:250px;height:170px}.jGrowl{z-index:9999;position:absolute}#loadingbar,body>.jGrowl{position:fixed}.jGrowl.top-left{top:0;left:0}.jGrowl.top-right{top:0;right:0}.jGrowl.bottom-left{bottom:0;left:0}.jGrowl.bottom-right{right:0;bottom:0}.jGrowl.center{top:50%;left:50%;width:0;margin-left:-170px}.center .jGrowl-closer,.center .jGrowl-notification{margin-right:auto;margin-left:auto}.jGrowl .jGrowl-closer,.jGrowl .jGrowl-notification{font-size:12px;display:none;zoom:1;width:300px;padding:10px 15px;white-space:normal;opacity:.95;filter:progid: DXImageTransform.Microsoft.Alpha(Opacity=95);margin:10px}.jGrowl .jGrowl-notification:hover{opacity:1;filter:progid: DXImageTransform.Microsoft.Alpha(Opacity=100)}.jGrowl .jGrowl-notification{min-height:20px}.jGrowl .jGrowl-notification .jGrowl-header{font-size:.85em;font-weight:700}.jGrowl .jGrowl-notification .jGrowl-close{font-weight:700;z-index:99;float:right;cursor:pointer}.jGrowl .jGrowl-closer{font-weight:700;cursor:pointer;text-align:center}#loadingbar{z-index:2147483647;top:0;left:-6px;width:1%;height:4px;-webkit-transition:all .5s ease-in-out;-moz-transition:all .5s ease-in-out;-ms-transition:all .5s ease-in-out;-o-transition:all .5s ease-in-out;transition:all .5s ease-in-out;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px}#loadingbar.left{right:0;left:100%;width:100%}#loadingbar.up{top:100%;bottom:0;left:0;width:5px;height:100%}#loadingbar.down{left:0;width:5px;height:0}#loadingbar.waiting dd,#loadingbar.waiting dt{-webkit-animation:pulse 2s ease-out 0s infinite;-moz-animation:pulse 2s ease-out 0s infinite;-ms-animation:pulse 2s ease-out 0s infinite;-o-animation:pulse 2s ease-out 0s infinite;animation:pulse 2s ease-out 0s infinite}#loadingbar dt{right:-80px;clip:rect(-6px,90px,14px,-6px);width:180px;opacity:.6}#loadingbar dd{right:0;clip:rect(-6px,22px,14px,10px);width:20px;opacity:.6}#loadingbar dd,#loadingbar dt{position:absolute;top:0;height:2px;-webkit-border-radius:100%;-moz-border-radius:100%;border-radius:100%;-webkit-box-shadow:#ff6439 1px 0 6px 1px;-moz-box-shadow:#fa7753 1px 0 6px 1px;box-shadow:#ff6439 1px 0 6px 1px;-ms-box-shadow:#fa7753 1px 0 6px 1px}.jvectormap-label,.jvectormap-zoomin,.jvectormap-zoomout{position:absolute;border-radius:3px;padding:5px;border-width:1px;border-style:solid}#loadingbar.left dt{left:-4px;clip:rect(-6px,185px,14px,25px);width:180px;opacity:.6}#loadingbar.left dd{left:0;clip:rect(-6px,22px,14px,0);width:20px;margin:0;opacity:.6}#loadingbar.down dd,#loadingbar.down dt,#loadingbar.up dd,#loadingbar.up dt{right:auto;left:-5px;width:10px}#loadingbar.left dd,#loadingbar.left dt{top:0;height:2px}#loadingbar.down dt{top:auto;bottom:-47px;clip:rect(-6px,20px,130px,-6px);height:180px;opacity:.6}#loadingbar.down dd{top:auto;bottom:0;clip:rect(-6px,22px,20px,10px);height:20px;margin:0;opacity:.6}#loadingbar.up dt{top:-10px;bottom:auto;clip:rect(13px,20px,190px,-6px);height:180px;opacity:.6}#loadingbar.up dd{top:0;bottom:auto;clip:rect(-6px,22px,25px,10px);height:20px;margin:0;opacity:.6}@keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-moz-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-ms-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}@-webkit-keyframes pulse{100%,30%{opacity:.6}60%{opacity:0}}.jvectormap-label{display:none;font-size:12px;z-index:1200}.jvectormap-zoomin,.jvectormap-zoomout{left:10px;cursor:pointer;line-height:10px;text-align:center}.jvectormap-zoomin{top:10px}.jvectormap-zoomout{top:35px}.modal,.modal-backdrop{top:0;left:0;right:0;bottom:0}.wmd-panel{width:100%}.wmd-input{height:300px;width:100%;box-sizing:border-box;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box}.wmd-preview{width:100%;margin-top:20px}.wmd-panel .btn-toolbar{margin-bottom:0;padding:0 0 5px;width:100%}.fa-header:before{content:'H';font-family:arial,helvetica,sans-serif;font-weight:700}.wmd-prompt-background{background-color:#000}.wmd-prompt-dialog{border:1px solid #999;background-color:#F5F5F5}.wmd-prompt-dialog>div{font-size:.8em;font-family:arial,helvetica,sans-serif}.wmd-prompt-dialog>form>input[type=text]{border:1px solid #999;color:#000}.wmd-prompt-dialog>form>input[type=button]{border:1px solid #888;font-family:trebuchet MS,helvetica,sans-serif;font-size:.8em;font-weight:700}.wmd-button-group1{margin-left:5px!important}.wmd-button-bar{margin-bottom:5px}.close{font-size:21px;font-weight:700;line-height:1;float:right;opacity:.2;color:#000;text-shadow:0 1px 0 #fff;filter:alpha(opacity=20)}.close:focus,.close:hover{cursor:pointer;text-decoration:none;opacity:.5;color:#000;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;border:0;background:0 0;-webkit-appearance:none}.modal-open{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;z-index:1050;display:none;overflow:auto;overflow-y:scroll;-webkit-overflow-scrolling:touch}.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;border-radius:6px}.modal-content{position:relative;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;background-color:#fff;background-clip:padding-box;box-shadow:0 3px 9px rgba(0,0,0,.5)}.modal-backdrop{position:fixed;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{min-height:16.43px;padding:15px;border-bottom:1px solid #dfe8f1}.modal-header .close{margin-top:2px}.modal-dialog{border:0;box-shadow:0 15px 45px rgba(0,0,0,.3)!important}.modal.display-block .modal-dialog{box-shadow:0 6px 25px rgba(0,0,0,.1)!important;-webkit-transform:translate(0,-20px);-ms-transform:translate(0,-20px);transform:translate(0,-20px)}.modal-title{line-height:1.42857143;margin:0}.modal-body{position:relative;padding:15px}.modal-footer{padding:15px;text-align:right;border-top:1px solid #dfe8f1}.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}}@media (min-width:992px){.modal-lg{width:900px}}.display-block.modal{position:static;z-index:5;display:block;overflow:visible!important;opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.display-block.modal .modal-dialog{margin-bottom:0}.modal-open #page-content-wrapper{z-index:inherit}.ms-container{position:relative}.ms-container .glyph-icon{font-size:20px;line-height:30px;position:absolute;top:50%;left:50%;width:30px;height:30px;margin:-15px 0 0 -15px;text-align:center}.ms-container:after{font-size:0;line-height:0;display:block;visibility:hidden;clear:both;height:0;min-height:0;content:'.'}.ms-container .ms-selectable,.ms-container .ms-selection{float:left;width:45%;color:#555;background:#fff}.ms-container .ms-selection{float:right}.ms-container .ms-list{position:relative;overflow-y:auto;height:200px;padding:5px 10px;border-width:1px;border-style:solid}.ms-list li{line-height:20px;margin:5px 0;padding:3px 10px}.ms-container ul{margin:0;padding:0;list-style-type:none}.ms-container .ms-optgroup-container{width:100%}.ms-container .ms-optgroup-label{line-height:20px;margin:0;padding:3px 10px;cursor:pointer}.ms-container li.ms-hover{cursor:pointer}.ms-container li.disabled{cursor:text}.fileinput-button{position:relative;overflow:hidden}.fileinput-button input{font-size:200px;position:absolute;top:0;right:0;margin:0;cursor:pointer;opacity:0;-ms-filter:'alpha(opacity=0)';direction:ltr}@media screen\9{.fileinput-button input{font-size:100%;height:100%;filter:alpha(opacity=0)}}.fileupload-buttonbar .btn,.fileupload-buttonbar .toggle{float:left;margin-right:10px;margin-bottom:5px}.fileupload-buttonbar .toggle{margin-top:7px;margin-left:10px}.template-upload .size{margin:0}.progress-animated .bar,.progress-animated .progress-bar{background:url(../images/animated-overlay.gif)!important;filter:none}.fileupload-process{display:none;float:right}.files .processing .preview,.fileupload-processing .fileupload-process{display:block;width:32px;height:32px;background:url(../images/loader-dark.gif) center no-repeat;background-size:contain}.files audio,.files video{max-width:300px}table.table td .toggle{margin:7px 10px 0 0}@media (max-width:767px){.files .btn span,.files .toggle,.fileupload-buttonbar .toggle{display:none}.files .name{width:80px;word-wrap:break-word}.files audio,.files video{max-width:80px}.files canvas,.files img{max-width:100%}}.blueimp-gallery,.blueimp-gallery>.slides>.slide>.slide-content{position:absolute;top:0;right:0;bottom:0;left:0;-moz-backface-visibility:hidden}.blueimp-gallery>.slides>.slide>.slide-content{margin:auto;width:auto;height:auto;max-width:100%;max-height:100%;opacity:1}.blueimp-gallery{position:fixed;z-index:999999;overflow:hidden;background:#000;background:rgba(0,0,0,.9);opacity:0;display:none;direction:ltr;-ms-touch-action:none;touch-action:none}.blueimp-gallery-carousel{position:relative;z-index:auto;margin:1em auto;padding-bottom:56.25%;box-shadow:0 0 10px #000;-ms-touch-action:pan-y;touch-action:pan-y}.blueimp-gallery-display{display:block;opacity:1}.blueimp-gallery>.slides{position:relative;height:100%;overflow:hidden}.blueimp-gallery-carousel>.slides{position:absolute}.blueimp-gallery>.slides>.slide{position:relative;float:left;height:100%;text-align:center;-webkit-transition-timing-function:cubic-bezier(.645,.045,.355,1);-moz-transition-timing-function:cubic-bezier(.645,.045,.355,1);-ms-transition-timing-function:cubic-bezier(.645,.045,.355,1);-o-transition-timing-function:cubic-bezier(.645,.045,.355,1);transition-timing-function:cubic-bezier(.645,.045,.355,1)}.blueimp-gallery,.blueimp-gallery>.slides>.slide>.slide-content{-webkit-transition:opacity .5s linear;-moz-transition:opacity .5s linear;-ms-transition:opacity .5s linear;-o-transition:opacity .5s linear;transition:opacity .5s linear}.blueimp-gallery>.slides>.slide-loading{background:url(../img/loading.gif) center no-repeat;background-size:64px 64px}.blueimp-gallery>.slides>.slide-loading>.slide-content{opacity:0}.blueimp-gallery>.slides>.slide-error{background:url(../img/error.png) center no-repeat}.blueimp-gallery>.slides>.slide-error>.slide-content{display:none}.blueimp-gallery>.next,.blueimp-gallery>.prev{position:absolute;top:50%;left:15px;width:40px;height:40px;margin-top:-23px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-decoration:none;text-shadow:0 0 2px #000;text-align:center;background:#222;background:rgba(0,0,0,.5);-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;cursor:pointer;display:none}.blueimp-gallery>.next{left:auto;right:15px}.blueimp-gallery>.close,.blueimp-gallery>.title{position:absolute;top:15px;left:15px;margin:0 40px 0 0;font-size:20px;line-height:30px;color:#fff;text-shadow:0 0 2px #000;opacity:.8;display:none}.blueimp-gallery>.close{padding:15px;right:15px;left:auto;margin:-15px;font-size:30px;text-decoration:none;cursor:pointer}.dd,.dd-list{padding:0;list-style:none}.blueimp-gallery>.play-pause{position:absolute;right:15px;bottom:15px;width:15px;height:15px;background:url(../img/play-pause.png) no-repeat;cursor:pointer;opacity:.5;display:none}.blueimp-gallery-playing>.play-pause{background-position:-15px 0}.blueimp-gallery>.close:hover,.blueimp-gallery>.next:hover,.blueimp-gallery>.play-pause:hover,.blueimp-gallery>.prev:hover,.blueimp-gallery>.title:hover{color:#fff;opacity:1}.blueimp-gallery-controls>.close,.blueimp-gallery-controls>.next,.blueimp-gallery-controls>.play-pause,.blueimp-gallery-controls>.prev,.blueimp-gallery-controls>.title{display:block;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.blueimp-gallery-left>.prev,.blueimp-gallery-right>.next,.blueimp-gallery-single>.next,.blueimp-gallery-single>.play-pause,.blueimp-gallery-single>.prev{display:none}.blueimp-gallery>.close,.blueimp-gallery>.next,.blueimp-gallery>.play-pause,.blueimp-gallery>.prev,.blueimp-gallery>.slides>.slide>.slide-content{-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}body:last-child .blueimp-gallery>.slides>.slide-error{background-image:url(../img/error.svg)}body:last-child .blueimp-gallery>.play-pause{width:20px;height:20px;background-size:40px 20px;background-image:url(../img/play-pause.svg)}body:last-child .blueimp-gallery-playing>.play-pause{background-position:-20px 0}.blueimp-gallery>.indicator{position:absolute;top:auto;right:15px;bottom:15px;left:15px;margin:0 40px;padding:0;list-style:none;text-align:center;line-height:10px;display:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.blueimp-gallery>.indicator>li{display:inline-block;width:9px;height:9px;margin:6px 3px 0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;border:1px solid transparent;background:#ccc;background:center no-repeat rgba(255,255,255,.25);border-radius:5px;box-shadow:0 0 2px #000;opacity:.5;cursor:pointer}.dd-empty,.dd-handle,.dd-placeholder{-moz-box-sizing:border-box;margin:5px 0}.blueimp-gallery>.indicator>.active,.blueimp-gallery>.indicator>li:hover{background-color:#fff;border-color:#fff;opacity:1}.blueimp-gallery-controls>.indicator{display:block;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.blueimp-gallery-single>.indicator,.blueimp-gallery>.slides>.slide>.video-content>video,.blueimp-gallery>.slides>.slide>.video-playing>a,.blueimp-gallery>.slides>.slide>.video-playing>img{display:none}.blueimp-gallery>.slides>.slide>.video-content>img{position:absolute;top:0;right:0;bottom:0;left:0;margin:auto;width:auto;height:auto;max-width:100%;max-height:100%;-moz-backface-visibility:hidden}.blueimp-gallery>.slides>.slide>.video-content>video{position:absolute;top:0;left:0;width:100%;height:100%}.blueimp-gallery>.slides>.slide>.video-content>iframe{position:absolute;top:100%;left:0;width:100%;height:100%;border:none}.blueimp-gallery>.slides>.slide>.video-playing>iframe{top:0}.blueimp-gallery>.slides>.slide>.video-content>a{position:absolute;top:50%;right:0;left:0;margin:-64px auto 0;width:128px;height:128px;background:url(../img/video-play.png) center no-repeat;opacity:.8;cursor:pointer}.dd,.dd-item>button,.dd-list{position:relative}.blueimp-gallery>.slides>.slide>.video-content>a:hover{opacity:1}.blueimp-gallery>.slides>.slide>.video-playing>video,.dd,.dd-list{display:block}.blueimp-gallery>.slides>.slide>.video-loading>a{background:url(../img/loading.gif) center no-repeat;background-size:64px 64px}body:last-child .blueimp-gallery>.slides>.slide>.video-content:not(.video-loading)>a{background-image:url(../img/video-play.svg)}.dd{font-size:13px;line-height:20px;margin:15px 0 0}.dd-list{margin:0}.dd-list .dd-list{padding-left:30px}.dd-collapsed .dd-list{display:none}.dd-empty,.dd-item,.dd-placeholder{font-size:13px;line-height:20px;position:relative;display:block;min-height:20px;margin:0;padding:0}.dd-handle{display:block;box-sizing:border-box;height:30px;padding:5px 10px;text-decoration:none;color:#333;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;background:#fafafa}.dd-handle:hover{background:#fff}.dd-item>button{font-size:12px;line-height:1;display:block;float:left;overflow:hidden;width:25px;height:20px;margin:5px 0;padding:0;cursor:pointer;text-align:center;white-space:nowrap;text-indent:100%;border:0;background:0 0}.dd-item>button:before{position:absolute;display:block;width:100%;content:'+';text-align:center;text-indent:0}.dd-item>button[data-action=collapse]:before{content:'-'}.dd-empty,.dd-placeholder{box-sizing:border-box;min-height:30px;padding:0;border:1px dashed #b6bcbf;background:#f2fbff}.dd-empty{min-height:100px;border:1px dashed #bbb;background-color:#dfe8f1;background-image:-webkit-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),-webkit-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-image:-moz-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),-moz-linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-image:linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff),linear-gradient(45deg,#fff 25%,transparent 25%,transparent 75%,#fff 75%,#fff);background-position:0 0,30px 30px;background-size:60px 60px}.dd-dragel{position:absolute;z-index:9999}.dd-dragel>.dd-item .dd-handle{margin-top:0}.dd-dragel .dd-handle{-webkit-box-shadow:2px 4px 6px 0 rgba(0,0,0,.1);box-shadow:2px 4px 6px 0 rgba(0,0,0,.1)}#nestable-menu{margin:0 0 15px;padding:0}#nestable-output,#nestable2-output{-moz-box-sizing:border-box;box-sizing:border-box;width:100%;height:7em}#nestable2 .dd-handle{color:#fff;border:1px solid #999;background:#bbb}#nestable2 .dd-handle:hover{background:#bbb}#nestable2 .dd-item>button:before{color:#fff}.dd-hover>.dd-handle{background:#2ea8e5!important}.dd3-content{display:block;-moz-box-sizing:border-box;box-sizing:border-box;height:30px;margin:5px 0;padding:5px 10px 5px 40px;text-decoration:none;color:#333;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;background:#fafafa}.dd3-content:hover{color:#2ea8e5;background:#fff}.dd3-handle,.dd3-handle:hover{background:#ddd}.dd-dragel>.dd3-item>.dd3-content{margin:0}.dd3-item>button{margin-left:30px}.dd3-handle{position:absolute;top:0;left:0;overflow:hidden;width:30px;margin:0;cursor:pointer;white-space:nowrap;text-indent:100%;border:1px solid #aaa;border-top-right-radius:0;border-bottom-right-radius:0}.dd3-handle:before{font-size:20px;font-weight:400;position:absolute;top:3px;left:0;display:block;width:100%;content:'≡';text-align:center;text-indent:0;color:#fff}.popover,.popover-title:empty{display:none}.datepicker-dropdown:after,.datepicker-dropdown:before,.form-wizard>ul>li a:before,.popover .arrow:after{content:''}.noty-wrapper{font-size:14px;font-weight:700;position:fixed;z-index:10000;left:0;width:100%;margin:0;padding:0;list-style:none;opacity:95;-moz-opacity:95;filter:alpha(opacity: 95)}.noty-wrapper:hover{opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.noty_message{line-height:20px;padding:15px 10px;text-align:center}#noty_bottom{bottom:0}#noty_top{top:0}#noty_center{top:50%;left:50%}#noty_center li{margin:10px 0;border:0}.popover{z-index:1049;top:0;left:0;min-width:250px;margin:0;padding:0}.popover .popover-content{padding:15px}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{font-size:12px;font-weight:700;margin:0;padding:10px 15px;text-transform:uppercase;border-bottom-width:1px;border-bottom-style:solid}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-style:solid;border-color:transparent}.popover .arrow,.popover .arrow:after{border-width:10px}.popover.top .arrow{bottom:-22px;left:50%;margin-left:-11px}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:rgba(0,0,0,.2);border-bottom-width:0}.popover.right .arrow{top:50%;left:-22px;margin-top:-11px}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:rgba(0,0,0,.2);border-left-width:0}.popover.bottom .arrow{top:-22px;left:50%;margin-left:-11px}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:rgba(0,0,0,.2)}.popover.left .arrow{top:50%;right:-22px;margin-top:-11px}.popover.left .arrow:after{right:1px;bottom:-10px;border-right-width:0;border-left-color:rgba(0,0,0,.2)}.popover .dropdown-menu,.popover .nav-list{margin:0;border:0}.display-block.popover{box-shadow:0 0 0 transparent;float:none;width:auto;margin:15px}.fixed-header .popover{position:fixed;-webkit-transform:translate3d(0,0,0)}div.pp_default .pp_bottom,div.pp_default .pp_bottom .pp_left,div.pp_default .pp_bottom .pp_middle,div.pp_default .pp_bottom .pp_right,div.pp_default .pp_top,div.pp_default .pp_top .pp_left,div.pp_default .pp_top .pp_middle,div.pp_default .pp_top .pp_right{height:13px}div.pp_default .pp_top .pp_left{background:url(images/default/sprite.png) -78px -93px no-repeat}div.pp_default .pp_top .pp_middle{background:url(images/default/sprite_x.png) top left repeat-x}div.pp_default .pp_top .pp_right{background:url(images/default/sprite.png) -112px -93px no-repeat}div.pp_default .pp_content .ppt{color:#f8f8f8}div.pp_default .pp_content_container .pp_left{padding-left:13px;background:url(images/default/sprite_y.png) -7px 0 repeat-y}div.pp_default .pp_content_container .pp_right{padding-right:13px;background:url(images/default/sprite_y.png) top right repeat-y}div.pp_default .pp_content{background-color:#fff}div.pp_default .pp_next:hover{cursor:pointer;background:url(images/default/sprite_next.png) center right no-repeat}div.pp_default .pp_previous:hover{cursor:pointer;background:url(images/default/sprite_prev.png) center left no-repeat}div.pp_default .pp_expand{width:28px;height:28px;cursor:pointer;background:url(images/default/sprite.png) 0 -29px no-repeat}div.pp_default .pp_expand:hover{cursor:pointer;background:url(images/default/sprite.png) 0 -56px no-repeat}div.pp_default .pp_contract{width:28px;height:28px;cursor:pointer;background:url(images/default/sprite.png) 0 -84px no-repeat}div.pp_default .pp_contract:hover{cursor:pointer;background:url(images/default/sprite.png) 0 -113px no-repeat}div.pp_default .pp_close{width:30px;height:30px;cursor:pointer;background:url(images/default/sprite.png) 2px 1px no-repeat}div.pp_default #pp_full_res .pp_inline{color:#000}div.pp_default .pp_gallery ul li a{border:1px solid #aaa;background:url(images/default/default_thumb.png) center center #f8f8f8}div.pp_default .pp_gallery ul li a:hover,div.pp_default .pp_gallery ul li.selected a{border-color:#fff}div.pp_default .pp_social{margin-top:7px}div.pp_default .pp_gallery a.pp_arrow_next,div.pp_default .pp_gallery a.pp_arrow_previous{position:static;left:auto}div.pp_default .pp_nav .pp_pause,div.pp_default .pp_nav .pp_play{width:30px;height:30px;background:url(images/default/sprite.png) -51px 1px no-repeat}div.pp_default .pp_nav .pp_pause{background-position:-51px -29px}div.pp_default .pp_details{position:relative}div.pp_default a.pp_arrow_next,div.pp_default a.pp_arrow_previous{width:20px;height:20px;margin:4px 0 0;background:url(images/default/sprite.png) -31px -3px no-repeat}div.pp_default a.pp_arrow_next{left:52px;background-position:-82px -3px}div.pp_default .pp_content_container .pp_details{margin-top:5px}div.pp_default .pp_nav{position:relative;clear:none;width:110px;height:30px}div.pp_default .pp_nav .currentTextHolder{font-family:Georgia;font-size:11px;font-style:italic;line-height:25px;position:absolute;top:2px;left:75px;margin:0;padding:0 0 0 10px;color:#999}.progress-bar,.sb-slidebar .chat-box li a.chat-wrapper:hover,div.ppt{color:#fff}div.pp_default .pp_arrow_next:hover,div.pp_default .pp_arrow_previous:hover,div.pp_default .pp_close:hover,div.pp_default .pp_nav .pp_pause:hover,div.pp_default .pp_nav .pp_play:hover{opacity:.7}div.pp_default .pp_description{font-size:11px;font-weight:700;line-height:14px;margin:5px 50px 5px 0}div.pp_default .pp_bottom .pp_left{background:url(images/default/sprite.png) -78px -127px no-repeat}div.pp_default .pp_bottom .pp_middle{background:url(images/default/sprite_x.png) bottom left repeat-x}div.pp_default .pp_bottom .pp_right{background:url(images/default/sprite.png) -112px -127px no-repeat}div.pp_default .pp_loaderIcon{background:url(images/default/loader.gif) center center no-repeat}div.pp_overlay{position:absolute;z-index:9500;top:0;left:0;display:none;width:100%;background:#000}div.pp_pic_holder{position:absolute;z-index:10000;display:none;width:100px}.pp_top{position:relative;height:20px}* html .pp_top{padding:0 20px}.pp_top .pp_left{position:absolute;left:0;width:20px;height:20px}.pp_top .pp_middle{position:absolute;right:20px;left:20px;height:20px}* html .pp_top .pp_middle{position:static;left:0}.pp_top .pp_right{position:absolute;top:0;right:0;left:auto;width:20px;height:20px}.pp_content{min-width:40px;height:40px}* html .pp_content{width:40px}.pp_fade{display:none}.pp_content_container{position:relative;width:100%;text-align:left}.pp_content_container .pp_left{padding-left:20px}.pp_content_container .pp_right{padding-right:20px}.pp_content_container .pp_details{float:left;margin:10px 0 2px}.pp_description{display:none;margin:0}.pp_social{float:left;margin:0}.pp_social .facebook{float:left;overflow:hidden;width:55px;margin-left:5px}.pp_social .twitter{float:left}.pp_nav{float:left;clear:right;margin:3px 10px 0 0}.pp_nav p{float:left;margin:2px 4px;white-space:nowrap}.pp_nav .pp_pause,.pp_nav .pp_play{float:left;margin-right:4px;text-indent:-10000px}a.pp_arrow_next,a.pp_arrow_previous{display:block;float:left;overflow:hidden;width:14px;height:15px;margin-top:3px;text-indent:-10000px}.pp_hoverContainer{position:absolute;z-index:2000;top:0;width:100%}.pp_gallery{position:absolute;z-index:10000;left:50%;display:none;margin-top:-50px}.pp_gallery div{position:relative;float:left;overflow:hidden}.pp_gallery ul{position:relative;float:left;height:35px;margin:0 0 0 5px;padding:0;white-space:nowrap}a.pp_close,a.pp_contract,a.pp_expand{position:absolute;text-indent:-10000px}.pp_gallery ul a{display:block;float:left;overflow:hidden;height:33px;border:1px solid #000;border:1px solid rgba(0,0,0,.5)}.pp_gallery li.selected a,.pp_gallery ul a:hover{border-color:#fff}.pp_gallery ul a img{border:0}.pp_gallery li{display:block;float:left;margin:0 5px 0 0;padding:0}.pp_gallery li.default a{display:block;width:50px;height:33px;background:url(images/facebook/default_thumbnail.gif) no-repeat}.pp_gallery li.default a img{display:none}.pp_gallery .pp_arrow_next,.pp_gallery .pp_arrow_previous{margin-top:7px!important}a.pp_contract,a.pp_expand{z-index:20000;top:10px;right:30px;display:none;width:20px;height:20px;cursor:pointer}a.pp_close{line-height:22px;top:0;right:0;display:block}.pp_bottom{position:relative;height:20px}* html .pp_bottom{padding:0 20px}.pp_bottom .pp_left{position:absolute;left:0;width:20px;height:20px}.pp_bottom .pp_middle{position:absolute;right:20px;left:20px;height:20px}* html .pp_bottom .pp_middle{position:static;left:0}.pp_bottom .pp_right{position:absolute;top:0;right:0;left:auto;width:20px;height:20px}.pp_loaderIcon{position:absolute;top:50%;left:50%;display:block;width:24px;height:24px;margin:-12px 0 0 -12px}#pp_full_res{line-height:1!important}#pp_full_res .pp_inline{text-align:left}#pp_full_res .pp_inline p{margin:0 0 15px}div.ppt{font-size:17px;z-index:9999;display:none;margin:0 0 5px 15px}.progress,.progress-bar,.progress-label,.progress-overlay,.progressbar,.progressbar-value{font-weight:700;line-height:20px;height:20px;border-radius:4px}.progress,.progressbar{position:relative;text-align:center;background:rgba(0,0,0,.05);box-shadow:inset 1px 1px 3px rgba(0,0,0,.2)}.progress-bar,.progress-label,.progress-overlay,.progressbar-value{position:absolute;z-index:4;top:0;left:0;overflow:hidden}.progress .progress-bar{position:relative!important;border-radius:0}.progressbar-value.ui-state-default,.progressbar-value.ui-state-default .progress-label{line-height:18px;height:18px}.progress-label{z-index:6;width:100%}.progress-overlay{z-index:5;width:100%;opacity:.15;background:url(../../images/animated-overlay.gif);filter:alpha(opacity=15)}.progressbar-small .progress-label,.progressbar-small .progress-overlay,.progressbar-small .progressbar-value,.progressbar-small.progressbar{height:10px}.progressbar-small .progressbar-value.ui-state-default{height:8px}.progressbar-smaller .progress-label,.progressbar-smaller .progress-overlay,.progressbar-smaller .progressbar-value,.progressbar-smaller.progressbar{height:4px}.progressbar-smaller .progressbar-value.ui-state-default{height:2px}.bg-black .progress-overlay{opacity:1;filter:alpha(opacity=100)}@-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;border-radius:4px;background-color:#f5f5f5;-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{font-size:12px;line-height:20px;float:left;width:0;height:100%;-webkit-transition:width .6s ease;transition:width .6s ease;text-align:center;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,.15)}.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}.ui-rangeSlider{height:50px;padding-top:30px}.ui-rangeSlider-withArrows .ui-rangeSlider-container{margin:0 15px}.ui-rangeSlider-disabled.ui-rangeSlider-noArrow .ui-rangeSlider-container{border-color:#8490a3}.ui-rangeSlider-arrow,.ui-rangeSlider-container{height:20px}.ui-rangeSlider-arrow{width:14px;cursor:pointer}.ui-rangeSlider-leftArrow{border-radius:4px 0 0 4px}.ui-rangeSlider-rightArrow{border-radius:0 4px 4px 0}.ui-rangeSlider-arrow-inner{position:absolute;top:50%;width:0;height:0;margin-top:-5px;border:5px solid transparent}.ui-rangeSlider-leftArrow .ui-rangeSlider-arrow-inner{left:0;margin-left:-1px;border-right:5px solid #666}.ui-rangeSlider-leftArrow:hover .ui-rangeSlider-arrow-inner{border-right:5px solid #333}.ui-rangeSlider-rightArrow .ui-rangeSlider-arrow-inner{right:0;margin-right:-1px;border-left:5px solid #666}.ui-rangeSlider-rightArrow:hover .ui-rangeSlider-arrow-inner{border-left:5px solid #333}.ui-rangeSlider-innerBar{left:-10px;overflow:hidden;width:110%;height:100%}.ui-rangeSlider-bar{height:18px;margin:1px 0;cursor:move;cursor:grab;cursor:-moz-grab}.ui-rangeSlider-disabled .ui-rangeSlider-bar{background:#93aeca}.ui-rangeSlider-handle{width:10px;height:30px;cursor:col-resize;background:0 0}.ui-rangeSlider-label{font-size:15px;bottom:27px;padding:5px 10px;cursor:col-resize;color:#fff;background-color:rgba(0,0,0,.7)}.ui-rangeSlider-label:active,.ui-rangeSlider-label:hover{background:#000}.ui-rangeSlider-label-inner{position:absolute;z-index:99;top:100%;left:50%;display:block;margin-left:-5px;border-top:5px solid rgba(0,0,0,.7);border-right:5px solid transparent;border-left:5px solid transparent}.sb-left,.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-rangeSlider-label:active .ui-rangeSlider-label-inner,.ui-rangeSlider-label:hover .ui-rangeSlider-label-inner{border-top:5px solid #000}.ui-editRangeSlider-inputValue{font-size:15px;width:2em;text-align:center;border:0}#sb-site,.sb-site-container,.sb-slidebar,body,html{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0}html.sb-scroll-lock.sb-active:not(.sb-static){overflow:hidden}#sb-site .sb-overlay{display:none}.sb-active #sb-site .sb-overlay{display:block}#sb-site,.sb-site-container{position:relative;width:100%}.sb-slidebar{position:fixed;z-index:0;top:0;display:none;overflow-y:auto;height:100%;overflow-x:hidden;-webkit-transform:translate(0);width:30%}.sb-slidebar.sb-right.sb-active{right:-3px}.sb-right{right:0}.sb-slidebar .scrollable-content{height:100%}.sb-slidebar.sb-static,html.sb-static .sb-slidebar{position:absolute}.sb-slidebar.sb-active{display:block}.sb-style-overlay{z-index:9999}.sb-momentum-scrolling{-webkit-overflow-scrolling:touch}.sb-width-thin{width:15%}.sb-width-wide{width:45%}@media (max-width:480px){.sb-slidebar{width:70%}.sb-width-thin{width:55%}.sb-width-wide{width:85%}}@media (min-width:481px){.sb-slidebar{width:55%}.sb-width-thin{width:40%}.sb-width-wide{width:70%}}@media (min-width:768px){.sb-slidebar{width:40%}.sb-width-thin{width:25%}.sb-width-wide{width:55%}}@media (min-width:992px){.sb-slidebar{width:30%}.sb-width-thin{width:15%}.sb-width-wide{width:45%}}@media (min-width:1200px){.sb-slidebar{width:350px}.sb-width-thin{width:5%}.sb-width-wide{width:35%}}#sb-site,.sb-site-container,.sb-slide,.sb-slidebar{-webkit-transition:-webkit-transform .4s ease;-moz-transition:-moz-transform .4s ease;-o-transition:-o-transform .4s ease;transition:transform .4s ease;-webkit-transition-property:-webkit-transform,left,right;-webkit-backface-visibility:hidden}.sb-hide{display:none}.sb-slidebar .popover-title{font-size:13px;font-size:11px;line-height:36px;display:block;height:36px;margin:2px 0;padding:0 15px;border-width:0}.sb-slidebar .divider{background:rgba(255,255,255,.1)}.sb-slidebar.sb-left .divider-header{font-size:14px;opacity:.4}.sb-slidebar .popover-title .caret{float:right;margin-top:17px}.sb-slidebar .progress-box li a{display:block;padding:0}.sb-slidebar .files-box{padding:10px 0}.sb-slidebar .files-box li.divider{margin:5px 0;padding:0}.sb-slidebar .notifications-box li,.sb-slidebar .progress-box li{padding:15px;border-color:rgba(255,255,255,.1)}.sb-slidebar .notifications-box li:last-child,.sb-slidebar .progress-box li:last-child{padding-bottom:20px}.sb-slidebar .notifications-box-alt li:first-child{padding-top:15px}.sb-slidebar ul.chat-box{margin:0;padding:0;list-style:none}.sb-slidebar .chat-box li{position:relative;margin:15px;padding:0}.sb-slidebar .chat-box li a.chat-wrapper{display:block;padding:10px}.sb-slidebar .chat-box li a.btn-md{position:absolute;top:50%;right:0;margin-top:-17px;padding:0 10px}.sb-slidebar .chat-box li a.btn-md .glyph-icon{opacity:.5}.sb-slidebar .chat-box li .status-badge{float:left;margin:0 10px 0 0}.sb-slidebar .chat-box li b{font-size:12px;display:block;padding:4px 0 0}.sb-slidebar .chat-box li p{font-size:11px;opacity:.6}.popover-title:hover{text-decoration:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle,.ui-slider .ui-slider-range,.ui-slider-horizontal,.ui-slider-vertical{-webkit-border-radius:100px;-moz-border-radius:100px;border-radius:100px}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:8px;height:8px;border:6px solid #FFF;box-sizing:initial;cursor:pointer;box-shadow:1px 1px 3px rgba(0,0,0,.3)}.ui-slider .ui-slider-handle:active,.ui-slider .ui-slider-handle:hover{border-color:#fff}.ui-slider .ui-slider-range{position:absolute;z-index:1;display:block;border:0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:7px;background:#ddd;-webkit-box-shadow:inset 0 1px 6px #717171;-moz-box-shadow:inset 0 1px 6px #717171;box-shadow:inset 0 1px 6px #717171}.ui-slider-horizontal .ui-slider-handle{top:-7px;margin-left:-7px}.ui-slider-horizontal .ui-slider-range{top:0;height:100%;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:7px;height:100px;background:#ddd;-webkit-box-shadow:inset 1px 0 6px #717171;-moz-box-shadow:inset 1px 0 6px #717171;box-shadow:inset 1px 0 6px #717171}.ui-slider-vertical .ui-slider-handle{left:-7px;margin-bottom:-8px;margin-left:0}.ui-slider-vertical .ui-slider-range{left:0;width:100%;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.note-editor{border:1px solid #bfc8d1}.note-editor .note-dropzone{position:absolute;z-index:1;display:none;opacity:.95;color:#87cefa;border:2px dashed #87cefa;background-color:#fff;pointer-event:none}.note-editor .note-dropzone .note-dropzone-message{font-size:28px;font-weight:700;display:table-cell;text-align:center;vertical-align:middle}.note-editor .note-dropzone.hover{color:#098ddf;border:2px dashed #098ddf}.note-editor.dragover .note-dropzone{display:table}.note-editor .note-toolbar{border-bottom:1px solid #bfc8d1;background-color:#FEFEFF}.note-editor.fullscreen{position:fixed;z-index:1050;top:0;left:0;width:100%}.note-editor.fullscreen .note-editable{background-color:#fff}.note-editor.codeview .note-editable,.note-editor.fullscreen .note-resizebar{display:none}.note-editor.codeview .note-codable{display:block}.note-editor .note-statusbar{background-color:#FEFEFF}.note-editor .note-statusbar .note-resizebar{width:100%;height:8px;cursor:s-resize;border-top:1px solid #bfc8d1}.note-editor .note-statusbar .note-resizebar .note-icon-bar{width:20px;margin:1px auto;border-top:1px solid #bfc8d1}.note-editor .note-editable{overflow:auto;padding:10px;outline:0}.note-editor .note-editable[contenteditable=false]{background-color:#dfe8f1}.note-editor .note-codable{font-family:Menlo,Monaco,monospace,sans-serif;font-size:14px;display:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;width:100%;margin-bottom:0;padding:10px;resize:none;color:#ccc;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;background-color:#222;box-shadow:none;-ms-box-sizing:border-box}.note-popover .popover{max-width:none}.note-popover .popover .popover-content a{display:inline-block;overflow:hidden;max-width:200px;vertical-align:middle;white-space:nowrap;text-overflow:ellipsis}.editable-buttons,.editable-input,.note-dialog .note-help-dialog .note-shortcut-layout td{vertical-align:top}.note-popover .popover .arrow{left:20px}.note-popover .popover .popover-content,.note-toolbar{margin:0;padding:0 0 5px 5px}.note-popover .popover .popover-content>.btn-group,.note-toolbar>.btn-group{margin-top:5px;margin-right:5px;margin-left:0}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group,.note-popover .popover .popover-content .note-style blockquote,.note-popover .popover .popover-content .note-style h1,.note-popover .popover .popover-content .note-style h2,.note-popover .popover .popover-content .note-style h3,.note-popover .popover .popover-content .note-style h4,.note-popover .popover .popover-content .note-style h5,.note-popover .popover .popover-content .note-style h6,.note-toolbar .note-color .dropdown-menu .btn-group,.note-toolbar .note-style blockquote,.note-toolbar .note-style h1,.note-toolbar .note-style h2,.note-toolbar .note-style h3,.note-toolbar .note-style h4,.note-toolbar .note-style h5,.note-toolbar .note-style h6{margin:0}.note-popover .popover .popover-content .note-table .dropdown-menu,.note-toolbar .note-table .dropdown-menu{min-width:0;padding:5px}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker,.note-toolbar .note-table .dropdown-menu .note-dimension-picker{font-size:18px}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-mousecatcher{position:absolute!important;z-index:3;width:10em;height:10em;cursor:pointer}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-unhighlighted{position:relative!important;z-index:1;width:5em;height:5em;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIj4+Pjp6ekKlAqjAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKhmnaJzPAAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC)}.note-popover .popover .popover-content .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted,.note-toolbar .note-table .dropdown-menu .note-dimension-picker .note-dimension-picker-highlighted{position:absolute!important;z-index:2;width:1em;height:1em;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASAgMAAAAroGbEAAAACVBMVEUAAIjd6vvD2f9LKLW+AAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfYAR0BKwNDEVT0AAAAG0lEQVQI12NgAAOtVatWMTCohoaGUY+EmIkEAEruEzK2J7tvAAAAAElFTkSuQmCC)}.note-popover .popover .popover-content .note-color .dropdown-toggle,.note-toolbar .note-color .dropdown-toggle{width:20px;padding-left:5px}.note-popover .popover .popover-content .note-color .dropdown-menu,.note-toolbar .note-color .dropdown-menu{min-width:290px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group:first-child,.note-toolbar .note-color .dropdown-menu .btn-group:first-child{margin:0 5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-palette-title,.note-toolbar .note-color .dropdown-menu .btn-group .note-palette-title{font-size:12px;margin:2px 7px;text-align:center;border-bottom:1px solid #eee}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset,.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset{font-size:12px;margin:5px;padding:0 3px;cursor:pointer;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.note-popover .popover .popover-content .note-color .dropdown-menu .btn-group .note-color-reset:hover,.note-toolbar .note-color .dropdown-menu .btn-group .note-color-reset:hover{background:#eee}.note-popover .popover .popover-content .note-para .dropdown-menu,.note-toolbar .note-para .dropdown-menu{min-width:216px;padding:5px}.note-popover .popover .popover-content .note-para .dropdown-menu>div:first-child,.note-toolbar .note-para .dropdown-menu>div:first-child{margin-right:5px}.note-popover .popover .popover-content .dropdown-menu,.note-toolbar .dropdown-menu{min-width:90px}.note-popover .popover .popover-content .dropdown-menu.right,.note-toolbar .dropdown-menu.right{right:0;left:auto}.note-popover .popover .popover-content .dropdown-menu.right::before,.note-toolbar .dropdown-menu.right::before{right:9px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu.right::after,.note-toolbar .dropdown-menu.right::after{right:10px;left:auto!important}.note-popover .popover .popover-content .dropdown-menu li a i,.note-toolbar .dropdown-menu li a i{visibility:hidden;color:#00bfff}.note-popover .popover .popover-content .dropdown-menu li a.checked i,.note-toolbar .dropdown-menu li a.checked i,.tooltip{visibility:visible}.note-popover .popover .popover-content .note-fontsize-10,.note-toolbar .note-fontsize-10{font-size:10px}.note-popover .popover .popover-content .note-color-palette,.note-toolbar .note-color-palette{line-height:1}.note-popover .popover .popover-content .note-color-palette div .note-color-btn,.note-toolbar .note-color-palette div .note-color-btn{width:17px;height:17px;margin:0;padding:0;border:1px solid #fff}.note-popover .popover .popover-content .note-color-palette div .note-color-btn:hover,.note-toolbar .note-color-palette div .note-color-btn:hover{border:1px solid #000}.note-dialog>div{display:none}.note-dialog .note-image-dialog .note-dropzone{font-size:30px;line-height:4;min-height:100px;margin-bottom:10px;text-align:center;color:#d3d3d3;border:4px dashed #d3d3d3}.note-dialog .note-help-dialog{font-size:12px;opacity:.9;color:#ccc;border:0;background:0 0;background-color:#222!important;-webkit-opacity:.9;-khtml-opacity:.9;-moz-opacity:.9;-ms-filter:alpha(opacity=90);filter:alpha(opacity=90)}.note-dialog .note-help-dialog .modal-content{border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;background:0 0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.note-dialog .note-help-dialog a{font-size:12px;color:#fff}.note-dialog .note-help-dialog .title{font-size:14px;font-weight:700;padding-bottom:5px;color:#fff;border-bottom:#fff 1px solid}.note-dialog .note-help-dialog .modal-close{font-size:14px;cursor:pointer;color:#dd0}.note-dialog .note-help-dialog .note-shortcut-layout{width:100%}.note-dialog .note-help-dialog .note-shortcut{margin-top:8px}.note-dialog .note-help-dialog .note-shortcut th{font-size:13px;text-align:left;color:#dd0}.note-dialog .note-help-dialog .note-shortcut td:first-child{font-family:'Courier New';min-width:110px;padding-right:10px;text-align:right;color:#dd0}.note-handle .note-control-selection{position:absolute;display:none;border:1px solid #000}.note-handle .note-control-selection>div{position:absolute}.note-handle .note-control-selection .note-control-selection-bg{width:100%;height:100%;opacity:.3;background-color:#000;-webkit-opacity:.3;-khtml-opacity:.3;-moz-opacity:.3;-ms-filter:alpha(opacity=30);filter:alpha(opacity=30)}.note-handle .note-control-selection .note-control-handle,.note-handle .note-control-selection .note-control-holder{width:7px;height:7px;border:1px solid #000}.note-handle .note-control-selection .note-control-sizing{width:7px;height:7px;border:1px solid #000;background-color:#fff}.note-handle .note-control-selection .note-control-nw{top:-5px;left:-5px;border-right:0;border-bottom:0}.note-handle .note-control-selection .note-control-ne{top:-5px;right:-5px;border-bottom:0;border-left:none}.note-handle .note-control-selection .note-control-sw{bottom:-5px;left:-5px;border-top:0;border-right:0}.note-handle .note-control-selection .note-control-se{right:-5px;bottom:-5px;cursor:se-resize}.note-handle .note-control-selection .note-control-selection-info{font-size:12px;right:0;bottom:0;margin:5px;padding:5px;opacity:.7;color:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;background-color:#000;-webkit-opacity:.7;-khtml-opacity:.7;-moz-opacity:.7;-ms-filter:alpha(opacity=70);filter:alpha(opacity=70)}.ui-tabs-nav{margin:0;padding:0;list-style:none;border-bottom:1px solid transparent}.ui-tabs-nav li>a{line-height:32px;height:32px;margin-right:5px;padding:0 20px;border-bottom:0}.ui-tabs-nav li{margin-bottom:-1px}.ui-tabs-panel{display:block;padding:15px;background:0 0}.ui-tabs-panel:last-child{border-bottom:0!important}.ui-tabs-nav>li,.ui-tabs-nav>li>a{position:relative;float:left}.ui-tabs-nav>li>a .float-left.glyph-icon{float:none!important;margin-right:5px}.ui-tabs-nav>li>a .float-right.glyph-icon{float:none!important;margin-right:0;margin-left:5px}.tabs-navigation>ul{margin:0;padding:0;border-width:1px;border-style:solid;border-radius:0;background:#fff}.tabs-navigation>ul li{margin:0}.tabs-navigation>ul li>a{font-size:20px;line-height:64px;height:64px;margin:0!important;padding:0 35px;border-right-width:1px;border-right-style:solid;border-radius:0;background:0 0}.tabs-navigation>ul li.ui-tabs-active a{line-height:64px;height:64px;margin:0!important;padding-bottom:0;color:#000!important;background:#eff4f6}.tabs-navigation>ul li.ui-tabs-active a:hover,.tabs-navigation>ul li>a:hover{background:#eff4f6}#theme-options{position:fixed;top:110px;right:-300px;z-index:9999;width:300px;-webkit-transition:transform .5s ease;-o-transition:transform .5s ease;transition:transform .5s ease}.btn.theme-switcher,.theme-switcher .glyph-icon{width:54px;height:50px;line-height:50px;display:block}#theme-options.active{transform:translateX(-300px);-ms-transform:translateX(-300px);-o-transform:translateX(-300px);-webkit-transform:translateX(-300px)}.btn.theme-switcher{font-size:27px;border-width:1px;border-style:solid;border-right:0;border-radius:3px 0 0 3px;text-align:center;position:absolute;left:-54px;top:25px;z-index:55;padding:0}#theme-switcher-wrapper,#theme-switcher-wrapper .header:first-child{border-top-left-radius:3px}#theme-switcher-wrapper{background:#fff;width:300px;padding:0;border-bottom-left-radius:3px;position:relative;z-index:60;-webkit-transition:transform .5s ease;-o-transition:transform .5s ease;transition:transform .5s ease;max-height:580px}#theme-options.active #theme-switcher-wrapper{box-shadow:0 4px 5px rgba(0,0,0,.3)}#theme-switcher-wrapper .header{background:#FEFEFF;border-top:#dfe8f1 solid 1px;border-bottom:#dfe8f1 solid 1px;text-transform:uppercase;padding:13px 15px 10px;font-size:12px}#theme-switcher-wrapper .header a{font-weight:700;text-transform:capitalize;float:right}#theme-switcher-wrapper ul+.header{border-radius:0}#theme-switcher-wrapper ul li{height:34px;line-height:28px;margin:5px 0;padding:0 15px;border-bottom:#dfe8f1 solid 1px}#theme-switcher-wrapper ul li:last-child{border-bottom:0;margin-bottom:0}#theme-switcher-wrapper ul li label{font-size:13px}.tocify-subheader li,.tooltip{font-size:12px}#theme-switcher-wrapper ul li .switch-toggle{float:right;margin-top:3px}.theme-color-wrapper h5{text-transform:capitalize;font-weight:700;font-size:12px;margin:0 5px 5px}.theme-color-wrapper{padding:10px}.theme-color-wrapper a{height:24px;width:24px;display:block;overflow:hidden;text-indent:-999em;float:left;margin:2px;border-radius:50px;border:2px solid #fff!important;box-shadow:1px 2px 3px rgba(0,0,0,.1);opacity:.8}.theme-color-wrapper a.active,.theme-color-wrapper a:hover{opacity:1;border-color:red!important}.bootstrap-timepicker{position:relative}.dropdown.bootstrap-timepicker{float:none}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block;padding:10px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{line-height:32px;width:42px;height:32px}.bootstrap-timepicker-widget table td.separator{width:auto;padding:0 5px}.bootstrap-timepicker-widget table td a{display:block;text-align:center}.bootstrap-timepicker-widget table td a i{margin:0 auto}.bootstrap-timepicker-widget table td input{width:100%;min-width:32px;margin:0;padding:0 5px;text-align:center}.bootstrap-timepicker-widget table td input.bootstrap-timepicker-meridian{font-weight:700}.tocify{margin-top:20px}.tocify li,.tocify ul{list-style:none;margin:0;padding:0;border:none;line-height:30px}.tocify-header{text-indent:10px}.tocify-item{margin-bottom:5px!important}.tocify-subheader{text-indent:20px;display:none}.tocify-subheader .tocify-subheader{text-indent:30px}.tocify-subheader .tocify-subheader .tocify-subheader{text-indent:40px}.nav-list .nav-header,.nav-list>li>a{margin:0}.nav-list>li>a{padding:5px}.tooltip{line-height:1.4;position:absolute;z-index:1030;display:block;opacity:0;filter:alpha(opacity=0)}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-3px;padding:5px 0}.tooltip.right{margin-left:8px;padding:0 5px}.tooltip.bottom{margin-top:3px;padding:5px 0}.tooltip.left{margin-left:-8px;padding:0 5px}.tooltip-inner{max-width:200px;padding:10px 15px;text-align:center;text-decoration:none;color:#fff;background-color:rgba(0,0,0,.9)}.tooltip-arrow{position:absolute;width:0;height:0;border-style:solid;border-color:transparent}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:rgba(0,0,0,.9)}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:rgba(0,0,0,.9)}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:rgba(0,0,0,.9)}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:rgba(0,0,0,.9)}.bootstrap-touchspin .input-group-btn-vertical{position:relative;white-space:nowrap;width:1%;vertical-align:middle;display:table-cell}.bootstrap-touchspin .input-group-btn-vertical>.btn{display:block;float:none;width:100%;max-width:100%;padding:8px 10px;margin-left:-1px;height:auto;position:relative;overflow:hidden}.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-up{border-radius:0 4px 0 0}.bootstrap-touchspin .input-group-btn-vertical .bootstrap-touchspin-down{margin-top:-2px;border-radius:0 0 4px}.bootstrap-touchspin .input-group-btn-vertical i{position:absolute;top:-8px;left:11px;font-size:9px;font-weight:400}div[id^=uniform-],div[id^=uniform-] input,div[id^=uniform-] span{line-height:18px;display:block;float:left;width:auto;width:20px;height:auto;height:20px;margin:0 3px 0 0;padding:0;cursor:pointer}div[id^=uniform-]{margin-right:10px;opacity:.9;filter:alpha(opacity=90);-moz-opacity:90}div[id^=uniform-] span{position:relative;display:-moz-inline-box;display:inline-block;zoom:1;margin-top:-1px;text-align:center;border-width:1px;border-style:solid}div.radio[id^=uniform-]>span{margin-top:-7px}.input-group-addon div[id^=uniform-] span i,div[id^=uniform-] span i{display:none}div[id^=uniform-] span.checked i{font-size:14px;line-height:18px;display:block;height:18px}div.radio[id^=uniform-] span.checked i{font-size:9px}div.radio[id^=uniform-] span{border-radius:50px}div[id^=uniform-] input{position:absolute;top:0;left:0;display:-moz-inline-box;display:inline-block;zoom:1;opacity:0;border:none;background:0 0;filter:alpha(opacity=0);-moz-opacity:0}div.checker[id^=uniform-] label{line-height:19px}div.selector{line-height:38px;position:relative;display:block;overflow:hidden;width:auto!important;height:38px;margin:0;padding:0 10px!important;cursor:pointer;white-space:nowrap;text-decoration:none;border-width:1px;border-style:solid}.selector i,div.selector span{line-height:38px;display:block;height:38px;padding:0!important}.selector i{position:absolute;z-index:4;top:50%;right:0;width:38px;margin-top:-19px;text-align:center;border-left:1px solid transparent}div.selector select{position:absolute;z-index:5;top:0;left:0;width:100%;height:38px;opacity:0;border:none;background:0 0;filter:alpha(opacity=0);-moz-opacity:0}div.selector span{width:auto!important}.form-wizard>ul{position:relative;display:table;width:100%;margin:0 0 20px;list-style:none}.form-wizard>ul>li{display:table-cell;width:1%;text-align:center}.form-wizard>ul>li a,.form-wizard>ul>li a:hover{position:relative;display:block;opacity:1;color:#666;-moz-opacity:1;filter:alpha(opacity: 100)}.form-wizard>ul>li a:before{position:absolute;z-index:4;top:20px;left:0;width:100%;height:4px;background:#ccc}.form-wizard>ul>li:first-child a:before{left:50%}.form-wizard>ul>li:last-child a:before{right:50%;left:auto;width:50%}.form-wizard>ul>li a .wizard-step{font-size:16px;line-height:42px;position:relative;z-index:5;display:block;width:40px;height:40px;margin:0 auto 5px;cursor:pointer;text-align:center;color:#fafafa;border-radius:100px;background:#ccc}.form-wizard>ul>li a .wizard-description{font-size:13px;font-weight:700;opacity:.6;-moz-opacity:.6;filter:alpha(opacity: 60)}.form-wizard>ul>li a .wizard-description small{font-size:12px;font-weight:400;display:block;padding:3px 0 0;opacity:.7;-moz-opacity:.7;filter:alpha(opacity: 70)}.form-wizard>ul>li a .wizard-description:hover,.form-wizard>ul>li.active a .wizard-description{opacity:1;-moz-opacity:1;filter:alpha(opacity: 100)}.form-wizard>ul>li a.disabled .wizard-step{background:#ccc}.loader,.msgBox{display:none}.actionBar{margin-top:20px;margin-bottom:20px;padding:20px 0 0;border-top:#ddd solid 1px}.actionBar a.btn{float:right;margin-left:10px}/*! X-editable - v1.5.1 * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery * http://github.com/vitalets/x-editable * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */.editableform{margin-bottom:0}.editableform .control-group{margin-bottom:0;white-space:nowrap;line-height:20px}.editableform .form-control{width:auto}.editable-buttons{display:inline-block;margin-left:7px;zoom:1}.editable-buttons.editable-buttons-bottom{display:block;margin-top:7px;margin-left:0}.editable-input{display:inline-block;width:auto;white-space:normal;zoom:1}.editable-buttons .editable-cancel{margin-left:7px}.editable-buttons button.ui-button-icon-only{height:24px;width:30px}.editableform-loading{background:url(../img/loading.gif) center center no-repeat;height:25px;width:auto;min-width:25px}.editable-inline .editableform-loading{background-position:left 5px}.editable-error-block{max-width:300px;margin:5px 0 0;width:auto;white-space:normal}.editable-error-block.ui-state-error{padding:3px}.editable-error{color:red}.editableform .editable-date{padding:0;margin:0;float:left}.editable-inline .add-on .icon-th{margin-top:3px;margin-left:1px}.editable-checklist label input[type=checkbox],.editable-checklist label span{vertical-align:middle;margin:0}.editable-checklist label{white-space:nowrap}.editable-wysihtml5{width:566px;height:250px}.editable-clear{clear:both;font-size:.9em;text-decoration:none;text-align:right}.editable-clear-x{background:url(../img/clear.png) center center no-repeat;display:block;width:13px;height:13px;position:absolute;opacity:.6;z-index:100;top:50%;right:6px;margin-top:-6px}.editable-clear-x:hover{opacity:1}.editable-pre-wrapped{white-space:pre-wrap}.editable-container.editable-popup{max-width:none!important}.editable-container.popover{width:auto}.editable-container.editable-inline{display:inline-block;vertical-align:middle;width:auto;zoom:1}.editable-container.ui-widget{font-size:inherit;z-index:9990}.editable-click,a.editable-click,a.editable-click:hover{text-decoration:none;border-bottom:dashed 1px #08c}.editable-click.editable-disabled,a.editable-click.editable-disabled,a.editable-click.editable-disabled:hover{color:#585858;cursor:default;border-bottom:none}.editable-empty,.editable-empty:focus,.editable-empty:hover{font-style:italic;color:#D14;text-decoration:none}.editable-unsaved{font-weight:700}.editable-bg-transition{-webkit-transition:background-color 1.4s ease-out;-moz-transition:background-color 1.4s ease-out;-o-transition:background-color 1.4s ease-out;-ms-transition:background-color 1.4s ease-out;transition:background-color 1.4s ease-out}.form-horizontal .editable{padding-top:5px;display:inline-block}/*! diff --git a/websiteFunctions/templates/websiteFunctions/listWebsites.html b/websiteFunctions/templates/websiteFunctions/listWebsites.html index 87edb3e7c..8b2ec1f2c 100644 --- a/websiteFunctions/templates/websiteFunctions/listWebsites.html +++ b/websiteFunctions/templates/websiteFunctions/listWebsites.html @@ -681,7 +681,7 @@
- {$ web.domain $}