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 += `
+
+
+
+
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 @@
-