diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index b0c81ad8f265..ee5dfed09405 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -64,7 +64,7 @@ class CheckData extends Command public function fire() { - $this->logMessage(date('Y-m-d') . ' Running CheckData...'); + $this->logMessage(date('Y-m-d h:i:s') . ' Running CheckData...'); if ($database = $this->option('database')) { config(['database.default' => $database]); @@ -84,9 +84,9 @@ class CheckData extends Command if (! $this->option('client_id')) { $this->checkOAuth(); $this->checkInvitations(); - $this->checkFailedJobs(); $this->checkAccountData(); $this->checkLookupData(); + $this->checkFailedJobs(); } $this->logMessage('Done: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE)); @@ -143,6 +143,11 @@ class CheckData extends Command return; } + if ($this->option('fix') == 'true') { + return; + } + + $isValid = true; $date = new Carbon(); $date = $date->subDays(1)->format('Y-m-d'); @@ -159,12 +164,12 @@ class CheckData extends Command //$this->logMessage('Result: ' . $result); if ($result && $result != $invoice->balance) { - $this->logMessage("Amounts do not match {$link} - PHP: {$invoice->balance}, JS: {$result}"); - $this->isValid = false; + $this->logMessage("PHP/JS amounts do not match {$link} - PHP: {$invoice->balance}, JS: {$result}"); + $this->isValid = $isValid = false; } } - if ($this->isValid) { + if ($isValid) { $this->logMessage('0 invoices with mismatched PHP/JS balances'); } } @@ -371,6 +376,13 @@ class CheckData extends Command private function checkFailedJobs() { + if (Utils::isTravis()) { + return; + } + + $current = config('database.default'); + config(['database.default' => env('QUEUE_DATABASE')]); + $count = DB::table('failed_jobs')->count(); if ($count > 0) { @@ -378,6 +390,8 @@ class CheckData extends Command } $this->logMessage($count . ' failed jobs'); + + config(['database.default' => $current]); } private function checkBlankInvoiceHistory() diff --git a/app/Console/Commands/SendReminders.php b/app/Console/Commands/SendReminders.php index cb76a83ef9f0..b95ff4d90df8 100644 --- a/app/Console/Commands/SendReminders.php +++ b/app/Console/Commands/SendReminders.php @@ -63,8 +63,30 @@ class SendReminders extends Command config(['database.default' => $database]); } + $accounts = $this->accountRepo->findWithFees(); + $this->info(count($accounts) . ' accounts found with fees'); + + foreach ($accounts as $account) { + if (! $account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { + continue; + } + + $invoices = $this->invoiceRepo->findNeedingReminding($account, false); + $this->info($account->name . ': ' . count($invoices) . ' invoices found'); + + foreach ($invoices as $invoice) { + if ($reminder = $account->getInvoiceReminder($invoice, false)) { + $this->info('Charge fee: ' . $invoice->id); + $number = preg_replace('/[^0-9]/', '', $reminder); + $amount = $account->account_email_settings->{"late_fee{$number}_amount"}; + $percent = $account->account_email_settings->{"late_fee{$number}_percent"}; + $this->invoiceRepo->setLateFee($invoice, $amount, $percent); + } + } + } + $accounts = $this->accountRepo->findWithReminders(); - $this->info(count($accounts) . ' accounts found'); + $this->info(count($accounts) . ' accounts found with reminders'); /** @var \App\Models\Account $account */ foreach ($accounts as $account) { @@ -78,7 +100,7 @@ class SendReminders extends Command /** @var Invoice $invoice */ foreach ($invoices as $invoice) { if ($reminder = $account->getInvoiceReminder($invoice)) { - $this->info('Send to ' . $invoice->id); + $this->info('Send email: ' . $invoice->id); $this->mailer->sendInvoice($invoice, $reminder); } } diff --git a/app/Console/Commands/UpdateKey.php b/app/Console/Commands/UpdateKey.php new file mode 100644 index 000000000000..d2c1b2f2098c --- /dev/null +++ b/app/Console/Commands/UpdateKey.php @@ -0,0 +1,80 @@ +info(date('Y-m-d h:i:s') . ' Running UpdateKey...'); + + // load the current values + $gatewayConfigs = []; + $bankUsernames = []; + + foreach (AccountGateway::all() as $gateway) { + $gatewayConfigs[$gateway->id] = $gateway->getConfig(); + } + + foreach (BankAccount::all() as $bank) { + $bankUsernames[$bank->id] = $bank->getUsername(); + } + + // set the new key and create a new encrypter + Artisan::call('key:generate'); + $key = base64_decode(str_replace('base64:', '', config('app.key'))); + $crypt = new Encrypter($key, config('app.cipher')); + + // update values using the new key/encrypter + foreach (AccountGateway::all() as $gateway) { + $config = $gatewayConfigs[$gateway->id]; + $gateway->config = $crypt->encrypt(json_encode($config)); + $gateway->save(); + } + + foreach (BankAccount::all() as $bank) { + $username = $bankUsernames[$bank->id]; + $bank->username = $crypt->encrypt($username); + $bank->save(); + } + + $this->info(date('Y-m-d h:i:s') . ' Successfully updated the application key'); + } + + /** + * @return array + */ + protected function getArguments() + { + return []; + } + + /** + * @return array + */ + protected function getOptions() + { + return []; + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 46ab045be1c1..f43e8fafaa3e 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -29,6 +29,7 @@ class Kernel extends ConsoleKernel 'App\Console\Commands\MakeClass', 'App\Console\Commands\InitLookup', 'App\Console\Commands\CalculatePayouts', + 'App\Console\Commands\UpdateKey', ]; /** diff --git a/app/Constants.php b/app/Constants.php index 177f28d9f566..650aee0b1373 100644 --- a/app/Constants.php +++ b/app/Constants.php @@ -46,6 +46,7 @@ if (! defined('APP_NAME')) { define('INVOICE_ITEM_TYPE_TASK', 2); define('INVOICE_ITEM_TYPE_PENDING_GATEWAY_FEE', 3); define('INVOICE_ITEM_TYPE_PAID_GATEWAY_FEE', 4); + define('INVOICE_ITEM_TYPE_LATE_FEE', 5); define('PERSON_CONTACT', 'contact'); define('PERSON_USER', 'user'); @@ -307,7 +308,7 @@ if (! defined('APP_NAME')) { define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com')); define('NINJA_DOCS_URL', env('NINJA_DOCS_URL', 'http://docs.invoiceninja.com/en/latest')); define('NINJA_DATE', '2000-01-01'); - define('NINJA_VERSION', '3.5.1' . env('NINJA_VERSION_SUFFIX')); + define('NINJA_VERSION', '3.6.0' . env('NINJA_VERSION_SUFFIX')); define('SOCIAL_LINK_FACEBOOK', env('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja')); define('SOCIAL_LINK_TWITTER', env('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja')); @@ -569,6 +570,9 @@ if (! defined('APP_NAME')) { ]; define('CACHED_TABLES', serialize($cachedTables)); + // Fix for mPDF: https://github.com/kartik-v/yii2-mpdf/issues/9 + define('_MPDF_TTFONTDATAPATH', storage_path('framework/cache/')); + // TODO remove these translation functions function uctrans($text) { diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index dce0cbec061c..b76051abe1c8 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -423,7 +423,6 @@ class AccountController extends BaseController 'timezones' => Cache::get('timezones'), 'dateFormats' => Cache::get('dateFormats'), 'datetimeFormats' => Cache::get('datetimeFormats'), - 'currencies' => Cache::get('currencies'), 'title' => trans('texts.localization'), 'weekdays' => Utils::getTranslatedWeekdayNames(), 'months' => Utils::getMonthOptions(), @@ -823,6 +822,10 @@ class AccountController extends BaseController $account->{"num_days_{$type}"} = Input::get("num_days_{$type}"); $account->{"field_{$type}"} = Input::get("field_{$type}"); $account->{"direction_{$type}"} = Input::get("field_{$type}") == REMINDER_FIELD_INVOICE_DATE ? REMINDER_DIRECTION_AFTER : Input::get("direction_{$type}"); + + $number = preg_replace('/[^0-9]/', '', $type); + $account->account_email_settings->{"late_fee{$number}_amount"} = Input::get("late_fee{$number}_amount"); + $account->account_email_settings->{"late_fee{$number}_percent"} = Input::get("late_fee{$number}_percent"); } $account->save(); diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php index a9e4d9ae02b9..e590bae9eba7 100644 --- a/app/Http/Controllers/ClientController.php +++ b/app/Http/Controllers/ClientController.php @@ -191,7 +191,6 @@ class ClientController extends BaseController 'data' => Input::old('data'), 'account' => Auth::user()->account, 'sizes' => Cache::get('sizes'), - 'currencies' => Cache::get('currencies'), 'customLabel1' => Auth::user()->account->custom_client_label1, 'customLabel2' => Auth::user()->account->custom_client_label2, ]; @@ -225,25 +224,51 @@ class ClientController extends BaseController return $this->returnBulk(ENTITY_CLIENT, $action, $ids); } - public function statement() + public function statement($clientPublicId, $statusId = false, $startDate = false, $endDate = false) { $account = Auth::user()->account; + $statusId = intval($statusId); $client = Client::scope(request()->client_id)->with('contacts')->firstOrFail(); + + if (! $startDate) { + $startDate = Utils::today(false)->modify('-6 month')->format('Y-m-d'); + $endDate = Utils::today(false)->format('Y-m-d'); + } + $invoice = $account->createInvoice(ENTITY_INVOICE); $invoice->client = $client; $invoice->date_format = $account->date_format ? $account->date_format->format_moment : 'MMM D, YYYY'; - $invoice->invoice_items = Invoice::scope() + + $invoices = Invoice::scope() ->with(['client']) - ->whereClientId($client->id) ->invoices() + ->whereClientId($client->id) ->whereIsPublic(true) - ->where('balance', '>', 0) - ->get(); + ->orderBy('invoice_date', 'asc'); + + if ($statusId == INVOICE_STATUS_PAID) { + $invoices->where('invoice_status_id', '=', INVOICE_STATUS_PAID); + } elseif ($statusId == INVOICE_STATUS_UNPAID) { + $invoices->where('invoice_status_id', '!=', INVOICE_STATUS_PAID); + } + + if ($statusId == INVOICE_STATUS_PAID || ! $statusId) { + $invoices->where('invoice_date', '>=', $startDate) + ->where('invoice_date', '<=', $endDate); + } + + $invoice->invoice_items = $invoices->get(); + + if (request()->json) { + return json_encode($invoice); + } $data = [ 'showBreadcrumbs' => false, 'client' => $client, - 'invoice' => $invoice, + 'account' => $account, + 'startDate' => $startDate, + 'endDate' => $endDate, ]; return view('clients.statement', $data); diff --git a/app/Http/Controllers/ClientPortalController.php b/app/Http/Controllers/ClientPortalController.php index bde187be3386..7548ed46e273 100644 --- a/app/Http/Controllers/ClientPortalController.php +++ b/app/Http/Controllers/ClientPortalController.php @@ -130,7 +130,7 @@ class ClientPortalController extends BaseController $showApprove = $invoice->quote_invoice_id ? false : true; if ($invoice->due_date) { - $showApprove = time() < strtotime($invoice->due_date); + $showApprove = time() < strtotime($invoice->getOriginal('due_date')); } if ($invoice->invoice_status_id >= INVOICE_STATUS_APPROVED) { $showApprove = false; @@ -369,7 +369,7 @@ class ClientPortalController extends BaseController 'client' => $contact->client, 'title' => trans('texts.invoices'), 'entityType' => ENTITY_INVOICE, - 'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date']), + 'columns' => Utils::trans(['invoice_number', 'invoice_date', 'invoice_total', 'balance_due', 'due_date', 'status']), ]; return response()->view('public_list', $data); @@ -431,7 +431,7 @@ class ClientPortalController extends BaseController return $model->invitation_key ? link_to('/view/'.$model->invitation_key, $model->invoice_number)->toHtml() : $model->invoice_number; }) ->addColumn('transaction_reference', function ($model) { - return $model->transaction_reference ? $model->transaction_reference : ''.trans('texts.manual_entry').''; + return $model->transaction_reference ? e($model->transaction_reference) : ''.trans('texts.manual_entry').''; }) ->addColumn('payment_type', function ($model) { return ($model->payment_type && ! $model->last4) ? $model->payment_type : ($model->account_gateway_id ? 'Online payment' : ''); @@ -497,7 +497,7 @@ class ClientPortalController extends BaseController 'account' => $account, 'title' => trans('texts.quotes'), 'entityType' => ENTITY_QUOTE, - 'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date']), + 'columns' => Utils::trans(['quote_number', 'quote_date', 'quote_total', 'due_date', 'status']), ]; return response()->view('public_list', $data); @@ -584,6 +584,10 @@ class ClientPortalController extends BaseController private function returnError($error = false) { + if (request()->phantomjs) { + abort(404); + } + return response()->view('error', [ 'error' => $error ?: trans('texts.invoice_not_found'), 'hideHeader' => true, @@ -745,7 +749,9 @@ class ClientPortalController extends BaseController $document = Document::scope($publicId, $invitation->account_id)->firstOrFail(); $authorized = false; - if ($document->expense && $document->expense->invoice_documents && $document->expense->client_id == $invitation->invoice->client_id) { + if ($document->is_default) { + $authorized = true; + } elseif ($document->expense && $document->expense->invoice_documents && $document->expense->client_id == $invitation->invoice->client_id) { $authorized = true; } elseif ($document->invoice && $document->invoice->client_id == $invitation->invoice->client_id) { $authorized = true; diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php index d45a11366c2f..1940a26f3d97 100644 --- a/app/Http/Controllers/ExpenseController.php +++ b/app/Http/Controllers/ExpenseController.php @@ -94,11 +94,20 @@ class ExpenseController extends BaseController return View::make('expenses.edit', $data); } - public function edit(ExpenseRequest $request) + public function clone(ExpenseRequest $request, $publicId) + { + return self::edit($request, $publicId, true); + } + + public function edit(ExpenseRequest $request, $publicId = false, $clone = false) { $expense = $request->entity(); $actions = []; + + if (! $clone) { + $actions[] = ['url' => 'javascript:submitAction("clone")', 'label' => trans("texts.clone_expense")]; + } if ($expense->invoice) { $actions[] = ['url' => URL::to("invoices/{$expense->invoice->public_id}/edit"), 'label' => trans('texts.view_invoice')]; } else { @@ -124,12 +133,28 @@ class ExpenseController extends BaseController $actions[] = ['url' => 'javascript:submitAction("restore")', 'label' => trans('texts.restore_expense')]; } + if ($clone) { + $expense->id = null; + $expense->public_id = null; + $expense->expense_date = date_create()->format('Y-m-d'); + $expense->deleted_at = null; + $expense->invoice_id = null; + $expense->payment_date = null; + $expense->payment_type_id = null; + $expense->transaction_reference = null; + $method = 'POST'; + $url = 'expenses'; + } else { + $method = 'PUT'; + $url = 'expenses/' . $expense->public_id; + } + $data = [ 'vendor' => null, 'expense' => $expense, 'entity' => $expense, - 'method' => 'PUT', - 'url' => 'expenses/'.$expense->public_id, + 'method' => $method, + 'url' => $url, 'title' => 'Edit Expense', 'actions' => $actions, 'vendors' => Vendor::scope()->with('vendor_contacts')->orderBy('name')->get(), @@ -165,7 +190,11 @@ class ExpenseController extends BaseController return self::bulk(); } - return redirect()->to("expenses/{$expense->public_id}/edit"); + if ($action == 'clone') { + return redirect()->to(sprintf('expenses/%s/clone', $expense->public_id)); + } else { + return redirect()->to("expenses/{$expense->public_id}/edit"); + } } public function store(CreateExpenseRequest $request) @@ -260,14 +289,6 @@ class ExpenseController extends BaseController return [ 'data' => Input::old('data'), 'account' => Auth::user()->account, - 'sizes' => Cache::get('sizes'), - 'paymentTerms' => Cache::get('paymentTerms'), - 'industries' => Cache::get('industries'), - 'currencies' => Cache::get('currencies'), - 'languages' => Cache::get('languages'), - 'countries' => Cache::get('countries'), - 'customLabel1' => Auth::user()->account->custom_vendor_label1, - 'customLabel2' => Auth::user()->account->custom_vendor_label2, 'categories' => ExpenseCategory::whereAccountId(Auth::user()->account_id)->withArchived()->orderBy('name')->get(), 'taxRates' => TaxRate::scope()->whereIsInclusive(false)->orderBy('name')->get(), 'isRecurring' => false, diff --git a/app/Http/Controllers/ExportController.php b/app/Http/Controllers/ExportController.php index bef47f2386a6..046682cc7ee2 100644 --- a/app/Http/Controllers/ExportController.php +++ b/app/Http/Controllers/ExportController.php @@ -170,7 +170,7 @@ class ExportController extends BaseController if ($request->input('include') === 'all' || $request->input('clients')) { $data['clients'] = Client::scope() - ->with('user', 'contacts', 'country') + ->with('user', 'contacts', 'country', 'currency') ->withArchived() ->get(); } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index 6672944bc0ec..f073b99cfae0 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -132,9 +132,11 @@ class HomeController extends BaseController public function contactUs() { Mail::raw(request()->contact_us_message, function ($message) { - $subject = 'Customer Message'; - if (! Utils::isNinja()) { - $subject .= ': v' . NINJA_VERSION; + $subject = 'Customer Message: '; + if (Utils::isNinja()) { + $subject .= config('database.default'); + } else { + $subject .= 'v' . NINJA_VERSION; } $message->to(env('CONTACT_EMAIL', 'contact@invoiceninja.com')) ->from(CONTACT_EMAIL, Auth::user()->present()->fullName) diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php index 7eeb44e1ebd7..a6f700ef0f84 100644 --- a/app/Http/Controllers/InvoiceApiController.php +++ b/app/Http/Controllers/InvoiceApiController.php @@ -423,7 +423,12 @@ class InvoiceApiController extends BaseAPIController public function download(InvoiceRequest $request) { $invoice = $request->entity(); + $pdfString = $invoice->getPDFString(); - return $this->fileReponse($invoice->getFileName(), $invoice->getPDFString()); + if ($pdfString) { + return $this->fileReponse($invoice->getFileName(), $pdfString); + } else { + abort(404); + } } } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 902ffcf61302..d8232b426439 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -305,7 +305,6 @@ class InvoiceController extends BaseController 'account' => Auth::user()->account->load('country'), 'products' => Product::scope()->orderBy('product_key')->get(), 'taxRateOptions' => $taxRateOptions, - 'currencies' => Cache::get('currencies'), 'sizes' => Cache::get('sizes'), 'invoiceDesigns' => InvoiceDesign::getDesigns(), 'invoiceFonts' => Cache::get('fonts'), @@ -480,6 +479,8 @@ class InvoiceController extends BaseController $key = 'emailed_' . $entityType; } elseif ($action == 'markPaid') { $key = 'created_payment'; + } elseif ($action == 'download') { + $key = 'downloaded_invoice'; } else { $key = "{$action}d_{$entityType}"; } diff --git a/app/Http/Controllers/OnlinePaymentController.php b/app/Http/Controllers/OnlinePaymentController.php index 61014bbcc8d3..696a4c6736dd 100644 --- a/app/Http/Controllers/OnlinePaymentController.php +++ b/app/Http/Controllers/OnlinePaymentController.php @@ -339,6 +339,9 @@ class OnlinePaymentController extends BaseController if (request()->currency_code) { $data['currency_code'] = request()->currency_code; } + if (request()->country_code) { + $data['country_code'] = request()->country_code; + } $client = $clientRepo->save($data, $client); } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 69383e337194..e0e92015920e 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -236,7 +236,6 @@ class PaymentController extends BaseController public function bulk() { $action = Input::get('action'); - $amount = Input::get('refund_amount'); $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); if ($action === 'email') { @@ -244,7 +243,10 @@ class PaymentController extends BaseController $this->contactMailer->sendPaymentConfirmation($payment); Session::flash('message', trans('texts.emailed_payment')); } else { - $count = $this->paymentService->bulk($ids, $action, ['refund_amount' => $amount]); + $count = $this->paymentService->bulk($ids, $action, [ + 'refund_amount' => Input::get('refund_amount'), + 'refund_email' => Input::get('refund_email'), + ]); if ($count > 0) { $message = Utils::pluralize($action == 'refund' ? 'refunded_payment' : $action.'d_payment', $count); Session::flash('message', $message); diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 264b2f7acb27..630c4b8f18a0 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -100,18 +100,15 @@ class QuoteController extends BaseController 'account' => $account, 'products' => Product::scope()->orderBy('product_key')->get(), 'taxRateOptions' => $account->present()->taxRateOptions, - 'countries' => Cache::get('countries'), 'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(), 'taxRates' => TaxRate::scope()->orderBy('name')->get(), - 'currencies' => Cache::get('currencies'), 'sizes' => Cache::get('sizes'), 'paymentTerms' => Cache::get('paymentTerms'), - 'languages' => Cache::get('languages'), - 'industries' => Cache::get('industries'), 'invoiceDesigns' => InvoiceDesign::getDesigns(), 'invoiceFonts' => Cache::get('fonts'), 'invoiceLabels' => Auth::user()->account->getInvoiceLabels(), 'isRecurring' => false, + 'expenses' => [], ]; } @@ -133,7 +130,13 @@ class QuoteController extends BaseController $count = $this->invoiceService->bulk($ids, $action); if ($count > 0) { - $key = $action == 'markSent' ? 'updated_quote' : "{$action}d_quote"; + if ($action == 'markSent') { + $key = 'updated_quote'; + } elseif ($action == 'download') { + $key = 'downloaded_quote'; + } else { + $key = "{$action}d_quote"; + } $message = Utils::pluralize($key, $count); Session::flash('message', $message); } diff --git a/app/Http/Controllers/RecurringExpenseController.php b/app/Http/Controllers/RecurringExpenseController.php index 2f72077466b9..3e512b751e7c 100644 --- a/app/Http/Controllers/RecurringExpenseController.php +++ b/app/Http/Controllers/RecurringExpenseController.php @@ -115,14 +115,6 @@ class RecurringExpenseController extends BaseController return [ 'data' => Input::old('data'), 'account' => Auth::user()->account, - 'sizes' => Cache::get('sizes'), - 'paymentTerms' => Cache::get('paymentTerms'), - 'industries' => Cache::get('industries'), - 'currencies' => Cache::get('currencies'), - 'languages' => Cache::get('languages'), - 'countries' => Cache::get('countries'), - 'customLabel1' => Auth::user()->account->custom_vendor_label1, - 'customLabel2' => Auth::user()->account->custom_vendor_label2, 'categories' => ExpenseCategory::whereAccountId(Auth::user()->account_id)->withArchived()->orderBy('name')->get(), 'taxRates' => TaxRate::scope()->whereIsInclusive(false)->orderBy('name')->get(), 'isRecurring' => true, diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 354b6b00f286..f0ab3fa7ef30 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -8,6 +8,7 @@ use Input; use Str; use Utils; use View; +use Excel; /** * Class ReportController. @@ -53,6 +54,7 @@ class ReportController extends BaseController } $action = Input::get('action'); + $format = Input::get('format'); if (Input::get('report_type')) { $reportType = Input::get('report_type'); @@ -104,7 +106,7 @@ class ReportController extends BaseController $params['report'] = $report; $params = array_merge($params, $report->results()); if ($isExport) { - self::export($reportType, $params['displayData'], $params['columns'], $params['reportTotals']); + return self::export($format, $reportType, $params); } } else { $params['columns'] = []; @@ -117,49 +119,80 @@ class ReportController extends BaseController } /** + * @param $format * @param $reportType - * @param $data - * @param $columns - * @param $totals + * @param $params + * @todo: Add summary to export */ - private function export($reportType, $data, $columns, $totals) + private function export($format, $reportType, $params) { if (! Auth::user()->hasPermission('view_all')) { exit; } - $output = fopen('php://output', 'w') or Utils::fatalError(); - $date = date('Y-m-d'); + $format = strtolower($format); + $data = $params['displayData']; + $columns = $params['columns']; + $totals = $params['reportTotals']; + $report = $params['report']; - $columns = array_map(function($key, $val) { - return is_array($val) ? $key : $val; - }, array_keys($columns), $columns); + $filename = "{$params['startDate']}-{$params['endDate']}_invoiceninja-".strtolower(Utils::normalizeChars(trans("texts.$reportType")))."-report"; - header('Content-Type:application/csv'); - header("Content-Disposition:attachment;filename={$date}-invoiceninja-{$reportType}-report.csv"); - - Utils::exportData($output, $data, Utils::trans($columns)); - - /* - fwrite($output, trans('texts.totals')); - foreach ($totals as $currencyId => $fields) { - foreach ($fields as $key => $value) { - fwrite($output, ',' . trans("texts.{$key}")); - } - fwrite($output, "\n"); - break; + $formats = ['csv', 'pdf', 'xlsx']; + if(!in_array($format, $formats)) { + throw new \Exception("Invalid format request to export report"); } - foreach ($totals as $currencyId => $fields) { - $csv = Utils::getFromCache($currencyId, 'currencies')->name . ','; - foreach ($fields as $key => $value) { - $csv .= '"' . Utils::formatMoney($value, $currencyId).'",'; - } - fwrite($output, $csv."\n"); - } - */ + //Get labeled header + $columns_labeled = $report->tableHeaderArray(); - fclose($output); - exit; + /*$summary = []; + if(count(array_values($totals))) { + $summary[] = array_merge([ + trans("texts.totals") + ], array_map(function ($key) {return trans("texts.{$key}");}, array_keys(array_values(array_values($totals)[0])[0]))); + } + + foreach ($totals as $currencyId => $each) { + foreach ($each as $dimension => $val) { + $tmp = []; + $tmp[] = Utils::getFromCache($currencyId, 'currencies')->name . (($dimension) ? ' - ' . $dimension : ''); + + foreach ($val as $id => $field) $tmp[] = Utils::formatMoney($field, $currencyId); + + $summary[] = $tmp; + } + } + + dd($summary);*/ + + return Excel::create($filename, function($excel) use($report, $data, $reportType, $format, $columns_labeled) { + $excel->sheet(trans("texts.$reportType"), function($sheet) use($report, $data, $format, $columns_labeled) { + + $sheet->setOrientation('landscape'); + $sheet->freezeFirstRow(); + + //Add border on PDF + if($format == 'pdf') + $sheet->setAllBorders('thin'); + + $sheet->rows(array_merge( + [array_map(function($col) {return $col['label'];}, $columns_labeled)], + $data + )); + + //Styling header + $sheet->cells('A1:'.Utils::num2alpha(count($columns_labeled)-1).'1', function($cells) { + $cells->setBackground('#777777'); + $cells->setFontColor('#FFFFFF'); + $cells->setFontSize(13); + $cells->setFontFamily('Calibri'); + $cells->setFontWeight('bold'); + }); + + + $sheet->setAutoSize(true); + }); + })->export($format); } } diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php index 03eec1a7510d..62404903b91f 100644 --- a/app/Http/Controllers/TaskController.php +++ b/app/Http/Controllers/TaskController.php @@ -161,7 +161,7 @@ class TaskController extends BaseController $invoices = $task->client_id ? $this->invoiceRepo->findOpenInvoices($task->client_id) : []; foreach ($invoices as $invoice) { - $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans('texts.add_to_invoice', ['invoice' => $invoice->invoice_number])]; + $actions[] = ['url' => 'javascript:submitAction("add_to_invoice", '.$invoice->public_id.')', 'label' => trans('texts.add_to_invoice', ['invoice' => e($invoice->invoice_number)])]; } } diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index dd7f96f23cf8..7f364b7716a9 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -156,79 +156,81 @@ class UserController extends BaseController */ public function save($userPublicId = false) { - if (Auth::user()->hasFeature(FEATURE_USERS)) { - $rules = [ - 'first_name' => 'required', - 'last_name' => 'required', - ]; - - if ($userPublicId) { - $user = User::where('account_id', '=', Auth::user()->account_id) - ->where('public_id', '=', $userPublicId) - ->withTrashed() - ->firstOrFail(); - - $rules['email'] = 'required|email|unique:users,email,'.$user->id.',id'; - } else { - $user = false; - $rules['email'] = 'required|email|unique:users'; - } - - $validator = Validator::make(Input::all(), $rules); - - if ($validator->fails()) { - return Redirect::to($userPublicId ? 'users/edit' : 'users/create') - ->withErrors($validator) - ->withInput(); - } - - if (! \App\Models\LookupUser::validateField('email', Input::get('email'), $user)) { - return Redirect::to($userPublicId ? 'users/edit' : 'users/create') - ->withError(trans('texts.email_taken')) - ->withInput(); - } - - if ($userPublicId) { - $user->first_name = trim(Input::get('first_name')); - $user->last_name = trim(Input::get('last_name')); - $user->username = trim(Input::get('email')); - $user->email = trim(Input::get('email')); - if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { - $user->is_admin = boolval(Input::get('is_admin')); - $user->permissions = Input::get('permissions'); - } - } else { - $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) - ->orderBy('public_id', 'DESC')->first(); - - $user = new User(); - $user->account_id = Auth::user()->account_id; - $user->first_name = trim(Input::get('first_name')); - $user->last_name = trim(Input::get('last_name')); - $user->username = trim(Input::get('email')); - $user->email = trim(Input::get('email')); - $user->registered = true; - $user->password = strtolower(str_random(RANDOM_KEY_LENGTH)); - $user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH)); - $user->public_id = $lastUser->public_id + 1; - if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { - $user->is_admin = boolval(Input::get('is_admin')); - $user->permissions = Input::get('permissions'); - } - } - - $user->save(); - - if (! $user->confirmed && Input::get('action') === 'email') { - $this->userMailer->sendConfirmation($user, Auth::user()); - $message = trans('texts.sent_invite'); - } else { - $message = trans('texts.updated_user'); - } - - Session::flash('message', $message); + if (! Auth::user()->hasFeature(FEATURE_USERS)) { + return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } + $rules = [ + 'first_name' => 'required', + 'last_name' => 'required', + ]; + + if ($userPublicId) { + $user = User::where('account_id', '=', Auth::user()->account_id) + ->where('public_id', '=', $userPublicId) + ->withTrashed() + ->firstOrFail(); + + $rules['email'] = 'required|email|unique:users,email,'.$user->id.',id'; + } else { + $user = false; + $rules['email'] = 'required|email|unique:users'; + } + + $validator = Validator::make(Input::all(), $rules); + + if ($validator->fails()) { + return Redirect::to($userPublicId ? 'users/edit' : 'users/create') + ->withErrors($validator) + ->withInput(); + } + + if (! \App\Models\LookupUser::validateField('email', Input::get('email'), $user)) { + return Redirect::to($userPublicId ? 'users/edit' : 'users/create') + ->withError(trans('texts.email_taken')) + ->withInput(); + } + + if ($userPublicId) { + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { + $user->is_admin = boolval(Input::get('is_admin')); + $user->permissions = Input::get('permissions'); + } + } else { + $lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id) + ->orderBy('public_id', 'DESC')->first(); + + $user = new User(); + $user->account_id = Auth::user()->account_id; + $user->first_name = trim(Input::get('first_name')); + $user->last_name = trim(Input::get('last_name')); + $user->username = trim(Input::get('email')); + $user->email = trim(Input::get('email')); + $user->registered = true; + $user->password = strtolower(str_random(RANDOM_KEY_LENGTH)); + $user->confirmation_code = strtolower(str_random(RANDOM_KEY_LENGTH)); + $user->public_id = $lastUser->public_id + 1; + if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) { + $user->is_admin = boolval(Input::get('is_admin')); + $user->permissions = Input::get('permissions'); + } + } + + $user->save(); + + if (! $user->confirmed && Input::get('action') === 'email') { + $this->userMailer->sendConfirmation($user, Auth::user()); + $message = trans('texts.sent_invite'); + } else { + $message = trans('texts.updated_user'); + } + + Session::flash('message', $message); + return Redirect::to('users/' . $user->public_id . '/edit'); } diff --git a/app/Http/Controllers/VendorController.php b/app/Http/Controllers/VendorController.php index 828cb9f542ba..654a725a7bb3 100644 --- a/app/Http/Controllers/VendorController.php +++ b/app/Http/Controllers/VendorController.php @@ -151,7 +151,6 @@ class VendorController extends BaseController return [ 'data' => Input::old('data'), 'account' => Auth::user()->account, - 'currencies' => Cache::get('currencies'), ]; } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index fef40c5cfdab..ccd3a90c4a08 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -68,7 +68,7 @@ class Authenticate } $account = $contact->account; - if (Auth::guard('user')->check() && Auth::user('user')->account_id === $account->id) { + if (Auth::guard('user')->check() && Auth::user('user')->account_id == $account->id) { // This is an admin; let them pretend to be a client $authenticated = true; } diff --git a/app/Http/Requests/CreatePaymentAPIRequest.php b/app/Http/Requests/CreatePaymentAPIRequest.php index f7a521c4c918..c6b4657080c3 100644 --- a/app/Http/Requests/CreatePaymentAPIRequest.php +++ b/app/Http/Requests/CreatePaymentAPIRequest.php @@ -33,7 +33,11 @@ class CreatePaymentAPIRequest extends PaymentRequest $this->invoice = $invoice = Invoice::scope($this->invoice_id) ->withArchived() ->invoices() - ->firstOrFail(); + ->first(); + + if (! $this->invoice) { + abort(404, 'Invoice was not found'); + } $this->merge([ 'invoice_id' => $invoice->id, diff --git a/app/Http/Requests/RegisterRequest.php b/app/Http/Requests/RegisterRequest.php index 17840be5983e..6275a8ce300d 100644 --- a/app/Http/Requests/RegisterRequest.php +++ b/app/Http/Requests/RegisterRequest.php @@ -31,7 +31,7 @@ class RegisterRequest extends Request public function rules() { $rules = [ - 'email' => 'required|unique:users', + 'email' => 'email|required|unique:users', 'first_name' => 'required', 'last_name' => 'required', 'password' => 'required', diff --git a/app/Http/ViewComposers/TranslationComposer.php b/app/Http/ViewComposers/TranslationComposer.php index ff2dc954199f..89f3fb267049 100644 --- a/app/Http/ViewComposers/TranslationComposer.php +++ b/app/Http/ViewComposers/TranslationComposer.php @@ -2,6 +2,7 @@ namespace App\Http\ViewComposers; +use Str; use Cache; use Illuminate\View\View; @@ -44,5 +45,11 @@ class TranslationComposer })->sortBy(function ($lang) { return $lang->name; })); + + $view->with('currencies', Cache::get('currencies')->each(function ($currency) { + $currency->name = trans('texts.currency_' . Str::slug($currency->name, '_')); + })->sortBy(function ($currency) { + return $currency->name; + })); } } diff --git a/app/Http/routes.php b/app/Http/routes.php index 54a6b7333dca..98f1b869c10c 100644 --- a/app/Http/routes.php +++ b/app/Http/routes.php @@ -144,7 +144,7 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () { Route::get('api/clients', 'ClientController@getDatatable'); Route::get('api/activities/{client_id?}', 'ActivityController@getDatatable'); Route::post('clients/bulk', 'ClientController@bulk'); - Route::get('clients/statement/{client_id}', 'ClientController@statement'); + Route::get('clients/statement/{client_id}/{status_id?}/{start_date?}/{end_date?}', 'ClientController@statement'); Route::resource('tasks', 'TaskController'); Route::get('api/tasks/{client_id?}', 'TaskController@getDatatable'); @@ -224,6 +224,7 @@ Route::group(['middleware' => ['lookup:user', 'auth:user']], function () { // Expense Route::resource('expenses', 'ExpenseController'); Route::get('expenses/create/{vendor_id?}/{client_id?}/{category_id?}', 'ExpenseController@create'); + Route::get('expenses/{expenses}/clone', 'ExpenseController@clone'); Route::get('api/expenses', 'ExpenseController@getDatatable'); Route::get('api/expenses/{id}', 'ExpenseController@getDatatableVendor'); Route::post('expenses/bulk', 'ExpenseController@bulk'); diff --git a/app/Jobs/DownloadInvoices.php b/app/Jobs/DownloadInvoices.php new file mode 100644 index 000000000000..651d0012837c --- /dev/null +++ b/app/Jobs/DownloadInvoices.php @@ -0,0 +1,87 @@ +user = $user; + $this->invoices = $invoices; + } + + /** + * Execute the job. + * + * @param ContactMailer $mailer + */ + public function handle(UserMailer $userMailer) + { + $zip = Archive::instance_by_useragent(date('Y-m-d') . '-Invoice_PDFs'); + + foreach ($this->invoices as $invoice) { + $zip->add_file($invoice->getFileName(), $invoice->getPDFString()); + } + + $zip->finish(); + exit; + + /* + // if queues are disabled download a zip file + if (config('queue.default') === 'sync' || count($this->invoices) <= 10) { + $zip = Archive::instance_by_useragent(date('Y-m-d') . '-Invoice_PDFs'); + foreach ($this->invoices as $invoice) { + $zip->add_file($invoice->getFileName(), $invoice->getPDFString()); + } + $zip->finish(); + exit; + + // otherwise sends the PDFs in an email + } else { + $data = []; + foreach ($this->invoices as $invoice) { + $data[] = [ + 'name' => $invoice->getFileName(), + 'data' => $invoice->getPDFString(), + ]; + } + + $subject = trans('texts.invoices_are_attached'); + $data = [ + 'documents' => $data + ]; + + $userMailer->sendMessage($this->user, $subject, false, $data); + } + */ + } +} diff --git a/app/Jobs/PurgeAccountData.php b/app/Jobs/PurgeAccountData.php index 6e928420adbd..2430292c76f1 100644 --- a/app/Jobs/PurgeAccountData.php +++ b/app/Jobs/PurgeAccountData.php @@ -61,6 +61,8 @@ class PurgeAccountData extends Job $account->client_number_counter = $account->client_number_counter > 0 ? 1 : 0; $account->save(); + session([RECENTLY_VIEWED => false]); + if (env('MULTI_DB_ENABLED')) { $current = config('database.default'); config(['database.default' => DB_NINJA_LOOKUP]); diff --git a/app/Jobs/SendNotificationEmail.php b/app/Jobs/SendNotificationEmail.php index 2b1213bb1bec..cf475f77db4c 100644 --- a/app/Jobs/SendNotificationEmail.php +++ b/app/Jobs/SendNotificationEmail.php @@ -7,13 +7,16 @@ use App\Ninja\Mailers\UserMailer; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; +use App\Models\Traits\SerialisesDeletedModels; /** * Class SendInvoiceEmail. */ class SendNotificationEmail extends Job implements ShouldQueue { - use InteractsWithQueue, SerializesModels; + use InteractsWithQueue, SerializesModels, SerialisesDeletedModels { + SerialisesDeletedModels::getRestoredPropertyValue insteadof SerializesModels; + } /** * @var User diff --git a/app/Libraries/HTMLUtils.php b/app/Libraries/HTMLUtils.php index 24dd67a6b5da..ad8ea6c8cb53 100644 --- a/app/Libraries/HTMLUtils.php +++ b/app/Libraries/HTMLUtils.php @@ -39,6 +39,8 @@ class HTMLUtils public static function sanitizeHTML($html) { + $html = html_entity_decode($html); + $config = HTMLPurifier_Config::createDefault(); $purifier = new HTMLPurifier($config); diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index df0c26a8a9c6..0e932c450514 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -916,7 +916,7 @@ class Utils $str = ''; if (property_exists($model, 'is_deleted')) { - $str = $model->is_deleted || ($model->deleted_at && $model->deleted_at != '0000-00-00') ? 'DISABLED ' : ''; + $str = $model->is_deleted ? 'DISABLED ' : ''; if ($model->is_deleted) { $str .= 'ENTITY_DELETED '; @@ -1052,20 +1052,15 @@ class Utils } } - public static function formatWebsite($website) + public static function formatWebsite($link) { - if (! $website) { + if (! $link) { return ''; } - $link = $website; - $title = $website; - $prefix = 'http://'; - - if (strlen($link) > 7 && substr($link, 0, 7) === $prefix) { - $title = substr($title, 7); - } else { - $link = $prefix.$link; + $title = $link; + if (substr($link, 0, 4) != 'http') { + $link = 'http://' . $link; } return link_to($link, $title, ['target' => '_blank']); @@ -1246,4 +1241,64 @@ class Utils fclose($handle); return( ord($contents[28]) != 0 ); } + + //Source: https://stackoverflow.com/questions/3302857/algorithm-to-get-the-excel-like-column-name-of-a-number + public static function num2alpha($n) + { + for($r = ""; $n >= 0; $n = intval($n / 26) - 1) + $r = chr($n%26 + 0x41) . $r; + return $r; + } + + /** + * Replace language-specific characters by ASCII-equivalents. + * @param string $s + * @return string + * Source: https://stackoverflow.com/questions/3371697/replacing-accented-characters-php/16427125#16427125 + */ + public static function normalizeChars($s) { + $replace = array( + 'ъ'=>'-', 'Ь'=>'-', 'Ъ'=>'-', 'ь'=>'-', + 'Ă'=>'A', 'Ą'=>'A', 'À'=>'A', 'Ã'=>'A', 'Á'=>'A', 'Æ'=>'A', 'Â'=>'A', 'Å'=>'A', 'Ä'=>'Ae', + 'Þ'=>'B', + 'Ć'=>'C', 'ץ'=>'C', 'Ç'=>'C', + 'È'=>'E', 'Ę'=>'E', 'É'=>'E', 'Ë'=>'E', 'Ê'=>'E', + 'Ğ'=>'G', + 'İ'=>'I', 'Ï'=>'I', 'Î'=>'I', 'Í'=>'I', 'Ì'=>'I', + 'Ł'=>'L', + 'Ñ'=>'N', 'Ń'=>'N', + 'Ø'=>'O', 'Ó'=>'O', 'Ò'=>'O', 'Ô'=>'O', 'Õ'=>'O', 'Ö'=>'Oe', + 'Ş'=>'S', 'Ś'=>'S', 'Ș'=>'S', 'Š'=>'S', + 'Ț'=>'T', + 'Ù'=>'U', 'Û'=>'U', 'Ú'=>'U', 'Ü'=>'Ue', + 'Ý'=>'Y', + 'Ź'=>'Z', 'Ž'=>'Z', 'Ż'=>'Z', + 'â'=>'a', 'ǎ'=>'a', 'ą'=>'a', 'á'=>'a', 'ă'=>'a', 'ã'=>'a', 'Ǎ'=>'a', 'а'=>'a', 'А'=>'a', 'å'=>'a', 'à'=>'a', 'א'=>'a', 'Ǻ'=>'a', 'Ā'=>'a', 'ǻ'=>'a', 'ā'=>'a', 'ä'=>'ae', 'æ'=>'ae', 'Ǽ'=>'ae', 'ǽ'=>'ae', + 'б'=>'b', 'ב'=>'b', 'Б'=>'b', 'þ'=>'b', + 'ĉ'=>'c', 'Ĉ'=>'c', 'Ċ'=>'c', 'ć'=>'c', 'ç'=>'c', 'ц'=>'c', 'צ'=>'c', 'ċ'=>'c', 'Ц'=>'c', 'Č'=>'c', 'č'=>'c', 'Ч'=>'ch', 'ч'=>'ch', + 'ד'=>'d', 'ď'=>'d', 'Đ'=>'d', 'Ď'=>'d', 'đ'=>'d', 'д'=>'d', 'Д'=>'D', 'ð'=>'d', + 'є'=>'e', 'ע'=>'e', 'е'=>'e', 'Е'=>'e', 'Ə'=>'e', 'ę'=>'e', 'ĕ'=>'e', 'ē'=>'e', 'Ē'=>'e', 'Ė'=>'e', 'ė'=>'e', 'ě'=>'e', 'Ě'=>'e', 'Є'=>'e', 'Ĕ'=>'e', 'ê'=>'e', 'ə'=>'e', 'è'=>'e', 'ë'=>'e', 'é'=>'e', + 'ф'=>'f', 'ƒ'=>'f', 'Ф'=>'f', + 'ġ'=>'g', 'Ģ'=>'g', 'Ġ'=>'g', 'Ĝ'=>'g', 'Г'=>'g', 'г'=>'g', 'ĝ'=>'g', 'ğ'=>'g', 'ג'=>'g', 'Ґ'=>'g', 'ґ'=>'g', 'ģ'=>'g', + 'ח'=>'h', 'ħ'=>'h', 'Х'=>'h', 'Ħ'=>'h', 'Ĥ'=>'h', 'ĥ'=>'h', 'х'=>'h', 'ה'=>'h', + 'î'=>'i', 'ï'=>'i', 'í'=>'i', 'ì'=>'i', 'į'=>'i', 'ĭ'=>'i', 'ı'=>'i', 'Ĭ'=>'i', 'И'=>'i', 'ĩ'=>'i', 'ǐ'=>'i', 'Ĩ'=>'i', 'Ǐ'=>'i', 'и'=>'i', 'Į'=>'i', 'י'=>'i', 'Ї'=>'i', 'Ī'=>'i', 'І'=>'i', 'ї'=>'i', 'і'=>'i', 'ī'=>'i', 'ij'=>'ij', 'IJ'=>'ij', + 'й'=>'j', 'Й'=>'j', 'Ĵ'=>'j', 'ĵ'=>'j', 'я'=>'ja', 'Я'=>'ja', 'Э'=>'je', 'э'=>'je', 'ё'=>'jo', 'Ё'=>'jo', 'ю'=>'ju', 'Ю'=>'ju', + 'ĸ'=>'k', 'כ'=>'k', 'Ķ'=>'k', 'К'=>'k', 'к'=>'k', 'ķ'=>'k', 'ך'=>'k', + 'Ŀ'=>'l', 'ŀ'=>'l', 'Л'=>'l', 'ł'=>'l', 'ļ'=>'l', 'ĺ'=>'l', 'Ĺ'=>'l', 'Ļ'=>'l', 'л'=>'l', 'Ľ'=>'l', 'ľ'=>'l', 'ל'=>'l', + 'מ'=>'m', 'М'=>'m', 'ם'=>'m', 'м'=>'m', + 'ñ'=>'n', 'н'=>'n', 'Ņ'=>'n', 'ן'=>'n', 'ŋ'=>'n', 'נ'=>'n', 'Н'=>'n', 'ń'=>'n', 'Ŋ'=>'n', 'ņ'=>'n', 'ʼn'=>'n', 'Ň'=>'n', 'ň'=>'n', + 'о'=>'o', 'О'=>'o', 'ő'=>'o', 'õ'=>'o', 'ô'=>'o', 'Ő'=>'o', 'ŏ'=>'o', 'Ŏ'=>'o', 'Ō'=>'o', 'ō'=>'o', 'ø'=>'o', 'ǿ'=>'o', 'ǒ'=>'o', 'ò'=>'o', 'Ǿ'=>'o', 'Ǒ'=>'o', 'ơ'=>'o', 'ó'=>'o', 'Ơ'=>'o', 'œ'=>'oe', 'Œ'=>'oe', 'ö'=>'oe', + 'פ'=>'p', 'ף'=>'p', 'п'=>'p', 'П'=>'p', + 'ק'=>'q', + 'ŕ'=>'r', 'ř'=>'r', 'Ř'=>'r', 'ŗ'=>'r', 'Ŗ'=>'r', 'ר'=>'r', 'Ŕ'=>'r', 'Р'=>'r', 'р'=>'r', + 'ș'=>'s', 'с'=>'s', 'Ŝ'=>'s', 'š'=>'s', 'ś'=>'s', 'ס'=>'s', 'ş'=>'s', 'С'=>'s', 'ŝ'=>'s', 'Щ'=>'sch', 'щ'=>'sch', 'ш'=>'sh', 'Ш'=>'sh', 'ß'=>'ss', + 'т'=>'t', 'ט'=>'t', 'ŧ'=>'t', 'ת'=>'t', 'ť'=>'t', 'ţ'=>'t', 'Ţ'=>'t', 'Т'=>'t', 'ț'=>'t', 'Ŧ'=>'t', 'Ť'=>'t', '™'=>'tm', + 'ū'=>'u', 'у'=>'u', 'Ũ'=>'u', 'ũ'=>'u', 'Ư'=>'u', 'ư'=>'u', 'Ū'=>'u', 'Ǔ'=>'u', 'ų'=>'u', 'Ų'=>'u', 'ŭ'=>'u', 'Ŭ'=>'u', 'Ů'=>'u', 'ů'=>'u', 'ű'=>'u', 'Ű'=>'u', 'Ǖ'=>'u', 'ǔ'=>'u', 'Ǜ'=>'u', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'У'=>'u', 'ǚ'=>'u', 'ǜ'=>'u', 'Ǚ'=>'u', 'Ǘ'=>'u', 'ǖ'=>'u', 'ǘ'=>'u', 'ü'=>'ue', + 'в'=>'v', 'ו'=>'v', 'В'=>'v', + 'ש'=>'w', 'ŵ'=>'w', 'Ŵ'=>'w', + 'ы'=>'y', 'ŷ'=>'y', 'ý'=>'y', 'ÿ'=>'y', 'Ÿ'=>'y', 'Ŷ'=>'y', + 'Ы'=>'y', 'ž'=>'z', 'З'=>'z', 'з'=>'z', 'ź'=>'z', 'ז'=>'z', 'ż'=>'z', 'ſ'=>'z', 'Ж'=>'zh', 'ж'=>'zh' + ); + return strtr($s, $replace); + } } diff --git a/app/Listeners/HandleUserLoggedIn.php b/app/Listeners/HandleUserLoggedIn.php index 10208ab1639d..030d73251e33 100644 --- a/app/Listeners/HandleUserLoggedIn.php +++ b/app/Listeners/HandleUserLoggedIn.php @@ -71,19 +71,31 @@ class HandleUserLoggedIn Session::flash('warning', trans('texts.logo_too_large', ['size' => $account->getLogoSize() . 'KB'])); } - // check custom gateway id is correct if (! Utils::isNinja()) { + // check custom gateway id is correct $gateway = Gateway::find(GATEWAY_CUSTOM); if (! $gateway || $gateway->name !== 'Custom') { Session::flash('error', trans('texts.error_incorrect_gateway_ids')); } - /* - if (! env('APP_KEY')) { - Session::flash('error', trans('texts.error_app_key_not_set')); - } elseif (strstr(env('APP_KEY'), 'SomeRandomString')) { + + // make sure APP_KEY and APP_CIPHER are in the .env file + $appKey = env('APP_KEY'); + $appCipher = env('APP_CIPHER'); + if (! $appKey || ! $appCipher) { + $fp = fopen(base_path().'/.env', 'a'); + if (! $appKey) { + fwrite($fp, "\nAPP_KEY=" . config('app.key')); + } + if (! $appCipher) { + fwrite($fp, "\nAPP_CIPHER=" . config('app.cipher')); + } + fclose($fp); + } + + // warn if using the default app key + if (in_array(config('app.key'), ['SomeRandomString', 'SomeRandomStringSomeRandomString', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'])) { Session::flash('error', trans('texts.error_app_key_set_to_default')); } - */ } } } diff --git a/app/Models/Account.php b/app/Models/Account.php index e50c0d36fcc7..3e415e65dfa6 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -332,6 +332,14 @@ class Account extends Eloquent return $this->hasMany('App\Models\Product'); } + /** + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function defaultDocuments() + { + return $this->hasMany('App\Models\Document')->whereIsDefault(true); + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Models/AccountEmailSettings.php b/app/Models/AccountEmailSettings.php index 752b2aea1e19..8de75d1d3451 100644 --- a/app/Models/AccountEmailSettings.php +++ b/app/Models/AccountEmailSettings.php @@ -27,6 +27,12 @@ class AccountEmailSettings extends Eloquent 'email_template_reminder1', 'email_template_reminder2', 'email_template_reminder3', + 'late_fee1_amount', + 'late_fee1_percent', + 'late_fee2_amount', + 'late_fee2_percent', + 'late_fee3_amount', + 'late_fee3_percent', ]; } diff --git a/app/Models/Activity.php b/app/Models/Activity.php index 8d9fe10e9316..c637f467913f 100644 --- a/app/Models/Activity.php +++ b/app/Models/Activity.php @@ -123,11 +123,11 @@ class Activity extends Eloquent $data = [ 'client' => $client ? link_to($client->getRoute(), $client->getDisplayName()) : null, - 'user' => $isSystem ? '' . trans('texts.system') . '' : $user->getDisplayName(), + 'user' => $isSystem ? '' . trans('texts.system') . '' : e($user->getDisplayName()), 'invoice' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null, 'quote' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null, - 'contact' => $contactId ? $client->getDisplayName() : $user->getDisplayName(), - 'payment' => $payment ? $payment->transaction_reference : null, + 'contact' => $contactId ? e($client->getDisplayName()) : e($user->getDisplayName()), + 'payment' => $payment ? e($payment->transaction_reference) : null, 'payment_amount' => $payment ? $account->formatMoney($payment->amount, $payment) : null, 'adjustment' => $this->adjustment ? $account->formatMoney($this->adjustment, $this) : null, 'credit' => $credit ? $account->formatMoney($credit->amount, $client) : null, diff --git a/app/Models/BankAccount.php b/app/Models/BankAccount.php index 2cd4a65646ef..a5365ee9f8e2 100644 --- a/app/Models/BankAccount.php +++ b/app/Models/BankAccount.php @@ -2,6 +2,7 @@ namespace App\Models; +use Crypt; use Illuminate\Database\Eloquent\SoftDeletes; /** @@ -33,6 +34,22 @@ class BankAccount extends EntityModel return ENTITY_BANK_ACCOUNT; } + /** + * @return mixed + */ + public function getUsername() + { + return Crypt::decrypt($this->username); + } + + /** + * @param $config + */ + public function setUsername($value) + { + $this->username = Crypt::encrypt($value); + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ diff --git a/app/Models/Client.php b/app/Models/Client.php index 31009197ff9a..4a6d8486e67e 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -54,54 +54,7 @@ class Client extends EntityModel 'public_notes', ]; - /** - * @var string - */ - public static $fieldName = 'name'; - /** - * @var string - */ - public static $fieldPhone = 'work_phone'; - /** - * @var string - */ - public static $fieldAddress1 = 'address1'; - /** - * @var string - */ - public static $fieldAddress2 = 'address2'; - /** - * @var string - */ - public static $fieldCity = 'city'; - /** - * @var string - */ - public static $fieldState = 'state'; - /** - * @var string - */ - public static $fieldPostalCode = 'postal_code'; - /** - * @var string - */ - public static $fieldNotes = 'notes'; - /** - * @var string - */ - public static $fieldCountry = 'country'; - /** - * @var string - */ - public static $fieldWebsite = 'website'; - /** - * @var string - */ - public static $fieldVatNumber = 'vat_number'; - /** - * @var string - */ - public static $fieldIdNumber = 'id_number'; + /** * @return array @@ -109,22 +62,28 @@ class Client extends EntityModel public static function getImportColumns() { return [ - self::$fieldName, - self::$fieldPhone, - self::$fieldAddress1, - self::$fieldAddress2, - self::$fieldCity, - self::$fieldState, - self::$fieldPostalCode, - self::$fieldCountry, - self::$fieldNotes, - self::$fieldWebsite, - self::$fieldVatNumber, - self::$fieldIdNumber, - Contact::$fieldFirstName, - Contact::$fieldLastName, - Contact::$fieldPhone, - Contact::$fieldEmail, + 'name', + 'work_phone', + 'address1', + 'address2', + 'city', + 'state', + 'postal_code', + 'public_notes', + 'private_notes', + 'country', + 'website', + 'currency', + 'vat_number', + 'id_number', + 'custom1', + 'custom2', + 'contact_first_name', + 'contact_last_name', + 'contact_phone', + 'contact_email', + 'contact_custom1', + 'contact_custom2', ]; } @@ -134,10 +93,11 @@ class Client extends EntityModel public static function getImportMap() { return [ - 'first' => 'first_name', - 'last' => 'last_name', - 'email' => 'email', - 'mobile|phone' => 'phone', + 'first' => 'contact_first_name', + 'last' => 'contact_last_name', + 'email' => 'contact_email', + 'work|office' => 'work_phone', + 'mobile|phone' => 'contact_phone', 'name|organization' => 'name', 'apt|street2|address2' => 'address2', 'street|address|address1' => 'address1', @@ -145,8 +105,10 @@ class Client extends EntityModel 'state|province' => 'state', 'zip|postal|code' => 'postal_code', 'country' => 'country', - 'note' => 'notes', + 'public' => 'public_notes', + 'private|note' => 'private_notes', 'site|website' => 'website', + 'currency' => 'currency', 'vat' => 'vat_number', 'number' => 'id_number', ]; @@ -282,7 +244,9 @@ class Client extends EntityModel { $publicId = isset($data['public_id']) ? $data['public_id'] : (isset($data['id']) ? $data['id'] : false); - if ($publicId && $publicId != '-1') { + // check if this client wasRecentlyCreated to ensure a new contact is + // always created even if the request includes a contact id + if (! $this->wasRecentlyCreated && $publicId && $publicId != '-1') { $contact = Contact::scope($publicId)->firstOrFail(); } else { $contact = Contact::createNew(); diff --git a/app/Models/Document.php b/app/Models/Document.php index f1f83436fbf3..90de300f5b81 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -24,6 +24,7 @@ class Document extends EntityModel protected $fillable = [ 'invoice_id', 'expense_id', + 'is_default', ]; /** diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index c186d027ac3e..c5582c808291 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -115,6 +115,8 @@ class Invoice extends EntityModel implements BalanceAffecting 'terms', 'product', 'quantity', + 'tax1', + 'tax2', ]; } @@ -135,6 +137,7 @@ class Invoice extends EntityModel implements BalanceAffecting 'notes' => 'notes', 'product|item' => 'product', 'quantity|qty' => 'quantity', + 'tax' => 'tax1', ]; } @@ -305,6 +308,23 @@ class Invoice extends EntityModel implements BalanceAffecting return $this->hasMany('App\Models\Document')->orderBy('id'); } + /** + * @return mixed + */ + public function allDocuments() + { + $documents = $this->documents; + $documents = $documents->merge($this->account->defaultDocuments); + + foreach ($this->expenses as $expense) { + if ($expense->invoice_documents) { + $documents = $documents->merge($expense->documents); + } + } + + return $documents; + } + /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ @@ -1319,7 +1339,7 @@ class Invoice extends EntityModel implements BalanceAffecting /** * @return int */ - public function countDocuments() + public function countDocuments($expenses = false) { $count = count($this->documents); @@ -1329,6 +1349,14 @@ class Invoice extends EntityModel implements BalanceAffecting } } + if ($expenses) { + foreach ($expenses as $expense) { + if ($expense->invoice_documents) { + $count += count($expense->documents); + } + } + } + return $count; } @@ -1337,7 +1365,11 @@ class Invoice extends EntityModel implements BalanceAffecting */ public function hasDocuments() { - if (count($this->documents)) { + if ($this->documents->count()) { + return true; + } + + if ($this->account->defaultDocuments->count()) { return true; } diff --git a/app/Models/LookupModel.php b/app/Models/LookupModel.php index 1e406191628b..023287306bfc 100644 --- a/app/Models/LookupModel.php +++ b/app/Models/LookupModel.php @@ -34,7 +34,7 @@ class LookupModel extends Eloquent if ($lookupAccount) { $data['lookup_account_id'] = $lookupAccount->id; } else { - abort('Lookup account not found for ' . $accountKey); + abort(500, 'Lookup account not found for ' . $accountKey); } static::create($data); @@ -96,7 +96,7 @@ class LookupModel extends Eloquent ->first(); } if (! $isFound) { - abort("Looked up {$className} not found: {$field} => {$value}"); + abort(500, "Looked up {$className} not found: {$field} => {$value}"); } Cache::put($key, $server, 120); diff --git a/app/Models/Traits/PresentsInvoice.php b/app/Models/Traits/PresentsInvoice.php index 641e6bdb7ab4..53647cf9675a 100644 --- a/app/Models/Traits/PresentsInvoice.php +++ b/app/Models/Traits/PresentsInvoice.php @@ -290,7 +290,7 @@ trait PresentsInvoice 'contact.custom_value1' => 'custom_contact_label1', 'contact.custom_value2' => 'custom_contact_label2', ] as $field => $property) { - $data[$field] = $this->$property ?: trans('texts.custom_field'); + $data[$field] = e($this->$property) ?: trans('texts.custom_field'); } return $data; diff --git a/app/Models/Traits/SendsEmails.php b/app/Models/Traits/SendsEmails.php index 2e5ecc11e98b..0d9abb2c7b43 100644 --- a/app/Models/Traits/SendsEmails.php +++ b/app/Models/Traits/SendsEmails.php @@ -4,6 +4,7 @@ namespace App\Models\Traits; use App\Constants\Domain; use Utils; +use HTMLUtils; /** * Class SendsEmails. @@ -36,7 +37,8 @@ trait SendsEmails $value = $this->account_email_settings->$field; if ($value) { - return preg_replace("/\r\n|\r|\n/", ' ', $value); + $value = preg_replace("/\r\n|\r|\n/", ' ', $value); + return HTMLUtils::sanitizeHTML($value); } } @@ -94,7 +96,9 @@ trait SendsEmails $template = preg_replace("/\r\n|\r|\n/", ' ', $template); //
is causing page breaks with the email designs - return str_replace('/>', ' />', $template); + $template = str_replace('/>', ' />', $template); + + return HTMLUtils::sanitizeHTML($template); } /** @@ -125,9 +129,9 @@ trait SendsEmails * * @return bool */ - public function getReminderDate($reminder) + public function getReminderDate($reminder, $filterEnabled = true) { - if (! $this->{"enable_reminder{$reminder}"}) { + if ($filterEnabled && ! $this->{"enable_reminder{$reminder}"}) { return false; } @@ -142,10 +146,10 @@ trait SendsEmails * * @return bool|string */ - public function getInvoiceReminder($invoice) + public function getInvoiceReminder($invoice, $filterEnabled = true) { for ($i = 1; $i <= 3; $i++) { - if ($date = $this->getReminderDate($i)) { + if ($date = $this->getReminderDate($i, $filterEnabled)) { $field = $this->{"field_reminder{$i}"} == REMINDER_FIELD_DUE_DATE ? 'due_date' : 'invoice_date'; if ($invoice->$field == $date) { return "reminder{$i}"; diff --git a/app/Models/Traits/SerialisesDeletedModels.php b/app/Models/Traits/SerialisesDeletedModels.php new file mode 100644 index 000000000000..fc963368977b --- /dev/null +++ b/app/Models/Traits/SerialisesDeletedModels.php @@ -0,0 +1,36 @@ +id)) { + return $this->restoreCollection($value); + } + + $instance = new $value->class; + $query = $instance->newQuery()->useWritePdo(); + + if (property_exists($instance, 'forceDeleting')) { + return $query->withTrashed()->find($value->id); + } + + return $query->findOrFail($value->id); + } +} diff --git a/app/Ninja/Datatables/CreditDatatable.php b/app/Ninja/Datatables/CreditDatatable.php index 2fd96e09155e..53ff00b58845 100644 --- a/app/Ninja/Datatables/CreditDatatable.php +++ b/app/Ninja/Datatables/CreditDatatable.php @@ -50,13 +50,13 @@ class CreditDatatable extends EntityDatatable [ 'public_notes', function ($model) { - return $model->public_notes; + return e($model->public_notes); }, ], [ 'private_notes', function ($model) { - return $model->private_notes; + return e($model->private_notes); }, ], ]; diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php index 30ccffab4fd5..c3c344e92099 100644 --- a/app/Ninja/Datatables/ExpenseDatatable.php +++ b/app/Ninja/Datatables/ExpenseDatatable.php @@ -84,7 +84,7 @@ class ExpenseDatatable extends EntityDatatable [ 'public_notes', function ($model) { - return $model->public_notes != null ? substr($model->public_notes, 0, 100) : ''; + return $model->public_notes != null ? e(substr($model->public_notes, 0, 100)) : ''; }, ], [ @@ -108,6 +108,15 @@ class ExpenseDatatable extends EntityDatatable return Auth::user()->can('editByOwner', [ENTITY_EXPENSE, $model->user_id]); }, ], + [ + trans("texts.clone_expense"), + function ($model) { + return URL::to("expenses/{$model->public_id}/clone"); + }, + function ($model) { + return Auth::user()->can('create', ENTITY_EXPENSE); + }, + ], [ trans('texts.view_invoice'), function ($model) { diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php index f76144b3faeb..efbd4e9905cf 100644 --- a/app/Ninja/Datatables/InvoiceDatatable.php +++ b/app/Ninja/Datatables/InvoiceDatatable.php @@ -181,14 +181,18 @@ class InvoiceDatatable extends EntityDatatable public function bulkActions() { - $actions = parent::bulkActions(); + $actions = []; if ($this->entityType == ENTITY_INVOICE || $this->entityType == ENTITY_QUOTE) { - $actions[] = \DropdownButton::DIVIDER; + $actions[] = [ + 'label' => mtrans($this->entityType, 'download_' . $this->entityType), + 'url' => 'javascript:submitForm_'.$this->entityType.'("download")', + ]; $actions[] = [ 'label' => mtrans($this->entityType, 'email_' . $this->entityType), 'url' => 'javascript:submitForm_'.$this->entityType.'("emailInvoice")', ]; + $actions[] = \DropdownButton::DIVIDER; $actions[] = [ 'label' => mtrans($this->entityType, 'mark_sent'), 'url' => 'javascript:submitForm_'.$this->entityType.'("markSent")', @@ -202,6 +206,9 @@ class InvoiceDatatable extends EntityDatatable ]; } + $actions[] = \DropdownButton::DIVIDER; + $actions = array_merge($actions, parent::bulkActions()); + return $actions; } } diff --git a/app/Ninja/Datatables/PaymentDatatable.php b/app/Ninja/Datatables/PaymentDatatable.php index 2da386dc106d..05d23b59e297 100644 --- a/app/Ninja/Datatables/PaymentDatatable.php +++ b/app/Ninja/Datatables/PaymentDatatable.php @@ -46,7 +46,7 @@ class PaymentDatatable extends EntityDatatable [ 'transaction_reference', function ($model) { - return $model->transaction_reference ? $model->transaction_reference : ''.trans('texts.manual_entry').''; + return $model->transaction_reference ? e($model->transaction_reference) : ''.trans('texts.manual_entry').''; }, ], [ diff --git a/app/Ninja/Datatables/ProductDatatable.php b/app/Ninja/Datatables/ProductDatatable.php index 467efedbc347..43343f0cf753 100644 --- a/app/Ninja/Datatables/ProductDatatable.php +++ b/app/Ninja/Datatables/ProductDatatable.php @@ -24,7 +24,7 @@ class ProductDatatable extends EntityDatatable [ 'notes', function ($model) { - return nl2br(Str::limit($model->notes, 100)); + return e(nl2br(Str::limit($model->notes, 100))); }, ], [ diff --git a/app/Ninja/Datatables/RecurringInvoiceDatatable.php b/app/Ninja/Datatables/RecurringInvoiceDatatable.php index 797d3ca0cf1c..a7d20ad355a8 100644 --- a/app/Ninja/Datatables/RecurringInvoiceDatatable.php +++ b/app/Ninja/Datatables/RecurringInvoiceDatatable.php @@ -64,7 +64,7 @@ class RecurringInvoiceDatatable extends EntityDatatable [ 'private_notes', function ($model) { - return $model->private_notes; + return e($model->private_notes); }, ], [ diff --git a/app/Ninja/Datatables/TaskDatatable.php b/app/Ninja/Datatables/TaskDatatable.php index a63460a31b1d..85722feec296 100644 --- a/app/Ninja/Datatables/TaskDatatable.php +++ b/app/Ninja/Datatables/TaskDatatable.php @@ -55,7 +55,7 @@ class TaskDatatable extends EntityDatatable [ 'description', function ($model) { - return $model->description; + return e($model->description); }, ], [ diff --git a/app/Ninja/Datatables/UserDatatable.php b/app/Ninja/Datatables/UserDatatable.php index ecc47039b9a1..4841dea1ea33 100644 --- a/app/Ninja/Datatables/UserDatatable.php +++ b/app/Ninja/Datatables/UserDatatable.php @@ -14,7 +14,7 @@ class UserDatatable extends EntityDatatable [ 'first_name', function ($model) { - return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : ($model->first_name.' '.$model->last_name); + return $model->public_id ? link_to('users/'.$model->public_id.'/edit', $model->first_name.' '.$model->last_name)->toHtml() : e($model->first_name.' '.$model->last_name); }, ], [ diff --git a/app/Ninja/Import/BaseTransformer.php b/app/Ninja/Import/BaseTransformer.php index d136b159f1ff..f83112c6a7ce 100644 --- a/app/Ninja/Import/BaseTransformer.php +++ b/app/Ninja/Import/BaseTransformer.php @@ -101,35 +101,17 @@ class BaseTransformer extends TransformerAbstract * * @return null */ - public function getProductId($name) + public function getProduct($data, $key, $field, $default = false) { - $name = strtolower(trim($name)); + $productKey = trim(strtolower($data->$key)); - return isset($this->maps[ENTITY_PRODUCT][$name]) ? $this->maps[ENTITY_PRODUCT][$name] : null; - } + if (! isset($this->maps['product'][$productKey])) { + return $default; + } - /** - * @param $name - * - * @return null - */ - public function getProductNotes($name) - { - $name = strtolower(trim($name)); + $product = $this->maps['product'][$productKey]; - return isset($this->maps['product_notes'][$name]) ? $this->maps['product_notes'][$name] : null; - } - - /** - * @param $name - * - * @return null - */ - public function getProductCost($name) - { - $name = strtolower(trim($name)); - - return isset($this->maps['product_cost'][$name]) ? $this->maps['product_cost'][$name] : null; + return $product->$field ?: $default; } /** @@ -156,6 +138,30 @@ class BaseTransformer extends TransformerAbstract return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null; } + /** + * @param $name + * + * @return null + */ + public function getTaxRate($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['tax_rates'][$name]) ? $this->maps['tax_rates'][$name] : 0; + } + + /** + * @param $name + * + * @return null + */ + public function getTaxName($name) + { + $name = strtolower(trim($name)); + + return isset($this->maps['tax_names'][$name]) ? $this->maps['tax_names'][$name] : ''; + } + /** * @param $name * diff --git a/app/Ninja/Import/CSV/ClientTransformer.php b/app/Ninja/Import/CSV/ClientTransformer.php index b53a714530af..07ccab2ea5d4 100644 --- a/app/Ninja/Import/CSV/ClientTransformer.php +++ b/app/Ninja/Import/CSV/ClientTransformer.php @@ -26,22 +26,29 @@ class ClientTransformer extends BaseTransformer 'name' => $this->getString($data, 'name'), 'work_phone' => $this->getString($data, 'work_phone'), 'address1' => $this->getString($data, 'address1'), + 'address2' => $this->getString($data, 'address2'), 'city' => $this->getString($data, 'city'), 'state' => $this->getString($data, 'state'), 'postal_code' => $this->getString($data, 'postal_code'), - 'private_notes' => $this->getString($data, 'notes'), + 'public_notes' => $this->getString($data, 'public_notes'), + 'private_notes' => $this->getString($data, 'private_notes'), 'website' => $this->getString($data, 'website'), 'vat_number' => $this->getString($data, 'vat_number'), 'id_number' => $this->getString($data, 'id_number'), + 'custom_value1' => $this->getString($data, 'custom1'), + 'custom_value2' => $this->getString($data, 'custom2'), 'contacts' => [ [ - 'first_name' => $this->getString($data, 'first_name'), - 'last_name' => $this->getString($data, 'last_name'), - 'email' => $this->getString($data, 'email'), - 'phone' => $this->getString($data, 'phone'), + 'first_name' => $this->getString($data, 'contact_first_name'), + 'last_name' => $this->getString($data, 'contact_last_name'), + 'email' => $this->getString($data, 'contact_email'), + 'phone' => $this->getString($data, 'contact_phone'), + 'custom_value1' => $this->getString($data, 'contact_custom1'), + 'custom_value2' => $this->getString($data, 'contact_custom2'), ], ], 'country_id' => isset($data->country) ? $this->getCountryId($data->country) : null, + 'currency_code' => $this->getString($data, 'currency'), ]; }); } diff --git a/app/Ninja/Import/CSV/InvoiceTransformer.php b/app/Ninja/Import/CSV/InvoiceTransformer.php index 0692badfb3fc..6d8f2e414888 100644 --- a/app/Ninja/Import/CSV/InvoiceTransformer.php +++ b/app/Ninja/Import/CSV/InvoiceTransformer.php @@ -38,9 +38,13 @@ class InvoiceTransformer extends BaseTransformer 'invoice_items' => [ [ 'product_key' => $this->getString($data, 'product'), - 'notes' => $this->getString($data, 'notes') ?: $this->getProductNotes($this->getString($data, 'product')), - 'cost' => $this->getFloat($data, 'amount') ?: $this->getProductCost($this->getString($data, 'product')), + 'notes' => $this->getString($data, 'notes') ?: $this->getProduct($data, 'product', 'notes', ''), + 'cost' => $this->getFloat($data, 'amount') ?: $this->getProduct($data, 'product', 'cost', 0), 'qty' => $this->getFloat($data, 'quantity') ?: 1, + 'tax_name1' => $this->getTaxName($this->getString($data, 'tax1')), + 'tax_rate1' => $this->getTaxRate($this->getString($data, 'tax1')), + 'tax_name2' => $this->getTaxName($this->getString($data, 'tax2')), + 'tax_rate2' => $this->getTaxRate($this->getString($data, 'tax2')), ], ], ]; diff --git a/app/Ninja/Import/CSV/ProductTransformer.php b/app/Ninja/Import/CSV/ProductTransformer.php index 8b372e28baa5..22e146e2c98a 100644 --- a/app/Ninja/Import/CSV/ProductTransformer.php +++ b/app/Ninja/Import/CSV/ProductTransformer.php @@ -23,6 +23,7 @@ class ProductTransformer extends BaseTransformer return new Item($data, function ($data) { return [ + 'public_id' => $this->getProduct($data, 'product_key', 'public_id'), 'product_key' => $this->getString($data, 'product_key'), 'notes' => $this->getString($data, 'notes'), 'cost' => $this->getFloat($data, 'cost'), diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php index a9803550ebfe..5507ef2ccfce 100644 --- a/app/Ninja/Mailers/ContactMailer.php +++ b/app/Ninja/Mailers/ContactMailer.php @@ -68,14 +68,7 @@ class ContactMailer extends Mailer $documentStrings = []; if ($account->document_email_attachment && $invoice->hasDocuments()) { - $documents = $invoice->documents; - - foreach ($invoice->expenses as $expense) { - if ($expense->invoice_documents) { - $documents = $documents->merge($expense->documents); - } - } - + $documents = $invoice->allDocuments(); $documents = $documents->sortBy('size'); $size = 0; @@ -238,17 +231,25 @@ class ContactMailer extends Mailer /** * @param Payment $payment */ - public function sendPaymentConfirmation(Payment $payment) + public function sendPaymentConfirmation(Payment $payment, $refunded = 0) { $account = $payment->account; $client = $payment->client; $account->loadLocalizationSettings($client); - $invoice = $payment->invoice; $accountName = $account->getDisplayName(); - $emailTemplate = $account->getEmailTemplate(ENTITY_PAYMENT); - $emailSubject = $invoice->account->getEmailSubject(ENTITY_PAYMENT); + + if ($refunded > 0) { + $emailSubject = trans('texts.refund_subject'); + $emailTemplate = trans('texts.refund_body', [ + 'amount' => $account->formatMoney($refunded, $client), + 'invoice_number' => $invoice->invoice_number, + ]); + } else { + $emailSubject = $invoice->account->getEmailSubject(ENTITY_PAYMENT); + $emailTemplate = $account->getEmailTemplate(ENTITY_PAYMENT); + } if ($payment->invitation) { $user = $payment->invitation->user; @@ -277,9 +278,10 @@ class ContactMailer extends Mailer 'entityType' => ENTITY_INVOICE, 'bccEmail' => $account->getBccEmail(), 'fromEmail' => $account->getFromEmail(), + 'isRefund' => $refunded > 0, ]; - if ($account->attachPDF()) { + if (! $refunded && $account->attachPDF()) { $data['pdfString'] = $invoice->getPDFString(); $data['pdfFileName'] = $invoice->getFileName(); } diff --git a/app/Ninja/Mailers/UserMailer.php b/app/Ninja/Mailers/UserMailer.php index e4698897195f..aacfb530fadb 100644 --- a/app/Ninja/Mailers/UserMailer.php +++ b/app/Ninja/Mailers/UserMailer.php @@ -119,14 +119,17 @@ class UserMailer extends Mailer /** * @param Invitation $invitation */ - public function sendMessage($user, $subject, $message, $invoice = false) + public function sendMessage($user, $subject, $message, $data = false) { if (! $user->email) { return; } + $invoice = $data && isset($data['invoice']) ? $data['invoice'] : false; $view = 'user_message'; - $data = [ + + $data = $data ?: []; + $data += [ 'userName' => $user->getDisplayName(), 'primaryMessage' => $subject, 'secondaryMessage' => $message, diff --git a/app/Ninja/PaymentDrivers/StripePaymentDriver.php b/app/Ninja/PaymentDrivers/StripePaymentDriver.php index c97d3ebfc2b1..fc93b1325069 100644 --- a/app/Ninja/PaymentDrivers/StripePaymentDriver.php +++ b/app/Ninja/PaymentDrivers/StripePaymentDriver.php @@ -119,6 +119,18 @@ class StripePaymentDriver extends BasePaymentDriver $data = $this->paymentDetails(); $data['description'] = $client->getDisplayName(); + // if a customer already exists link the token to it + if ($customer = $this->customer()) { + $data['customerReference'] = $customer->token; + // otherwise create a new customer + } else { + $response = $this->gateway()->createCustomer([ + 'description' => $client->getDisplayName(), + 'email' => $this->contact()->email, + ])->send(); + $data['customerReference'] = $response->getCustomerReference(); + } + if (! empty($data['plaidPublicToken'])) { $plaidResult = $this->getPlaidToken($data['plaidPublicToken'], $data['plaidAccountId']); unset($data['plaidPublicToken']); @@ -126,11 +138,6 @@ class StripePaymentDriver extends BasePaymentDriver $data['token'] = $plaidResult['stripe_bank_account_token']; } - // if a customer already exists link the token to it - if ($customer = $this->customer()) { - $data['customerReference'] = $customer->token; - } - $tokenResponse = $this->gateway() ->createCard($data) ->send(); @@ -146,7 +153,11 @@ class StripePaymentDriver extends BasePaymentDriver public function creatingCustomer($customer) { - $customer->token = $this->tokenResponse['id']; + if (isset($this->tokenResponse['customer'])) { + $customer->token = $this->tokenResponse['customer']; + } else { + $customer->token = $this->tokenResponse['id']; + } return $customer; } diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index 156aade6237c..5cfd0e70dd68 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -22,6 +22,28 @@ class AccountPresenter extends Presenter return $this->entity->name ?: trans('texts.untitled_account'); } + /** + * @return string + */ + public function address() + { + $account = $this->entity; + + $str = $account->address1 ?: ''; + + if ($account->address2 && $str) { + $str .= ', '; + } + + $str .= $account->address2; + + if ($account->getCityState() && $str) { + $str .= ' - '; + } + + return $str . $account->getCityState(); + } + /** * @return string */ @@ -144,7 +166,7 @@ class AccountPresenter extends Presenter if ($rate->is_inclusive) { $name .= ' - ' . trans('texts.inclusive'); } - $options[($rate->is_inclusive ? '1 ' : '0 ') . $rate->rate . ' ' . $rate->name] = $name; + $options[($rate->is_inclusive ? '1 ' : '0 ') . $rate->rate . ' ' . $rate->name] = e($name); } return $options; diff --git a/app/Ninja/Presenters/EntityPresenter.php b/app/Ninja/Presenters/EntityPresenter.php index 863199b05a18..89dc552817f3 100644 --- a/app/Ninja/Presenters/EntityPresenter.php +++ b/app/Ninja/Presenters/EntityPresenter.php @@ -33,7 +33,9 @@ class EntityPresenter extends Presenter { $class = $text = ''; - if ($this->entity->is_deleted) { + if (! $this->entity->id) { + return ''; + } elseif ($this->entity->is_deleted) { $class = 'danger'; $label = trans('texts.deleted'); } elseif ($this->entity->trashed()) { diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php index 1d7e969a3e1c..2063675aca0a 100644 --- a/app/Ninja/Presenters/InvoicePresenter.php +++ b/app/Ninja/Presenters/InvoicePresenter.php @@ -285,7 +285,11 @@ class InvoicePresenter extends EntityPresenter $label = trans('texts.fee'); } - return ' - ' . $fee . ' ' . $label; + $label = ' - ' . $fee . ' ' . $label; + + $label .= '   '; + + return $label; } public function multiAccountLink() diff --git a/app/Ninja/Reports/AbstractReport.php b/app/Ninja/Reports/AbstractReport.php index e327c60b7170..701147b15b91 100644 --- a/app/Ninja/Reports/AbstractReport.php +++ b/app/Ninja/Reports/AbstractReport.php @@ -52,9 +52,8 @@ class AbstractReport $this->totals[$currencyId][$dimension][$field] += $value; } - public function tableHeader() - { - $str = ''; + public function tableHeaderArray() { + $columns_labeled = []; foreach ($this->columns as $key => $val) { if (is_array($val)) { @@ -75,9 +74,21 @@ class AbstractReport $class = count($class) ? implode(' ', $class) : 'group-false'; $label = trans("texts.{$field}"); - $str .= "{$label}"; + + $columns_labeled[] = ['label' => $label, 'class' => $class, 'key' => $field]; } + return $columns_labeled; + } + + public function tableHeader() + { + $columns_labeled = $this->tableHeaderArray(); + $str = ''; + + foreach ($columns_labeled as $field => $attr) + $str .= "{$attr['label']}"; + return $str; } diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 477ba5e366e0..3551ee430ab4 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -662,6 +662,18 @@ class AccountRepository return Account::whereRaw('enable_reminder1 = 1 OR enable_reminder2 = 1 OR enable_reminder3 = 1')->get(); } + public function findWithFees() + { + return Account::whereHas('account_email_settings', function($query) { + $query->where('late_fee1_amount', '>', 0) + ->orWhere('late_fee1_percent', '>', 0) + ->orWhere('late_fee2_amount', '>', 0) + ->orWhere('late_fee2_percent', '>', 0) + ->orWhere('late_fee3_amount', '>', 0) + ->orWhere('late_fee3_percent', '>', 0); + })->get(); + } + public function createTokens($user, $name) { $name = trim($name) ?: 'TOKEN'; diff --git a/app/Ninja/Repositories/CreditRepository.php b/app/Ninja/Repositories/CreditRepository.php index 346156cd91ee..c5152cbc732f 100644 --- a/app/Ninja/Repositories/CreditRepository.php +++ b/app/Ninja/Repositories/CreditRepository.php @@ -89,7 +89,7 @@ class CreditRepository extends BaseRepository return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id); }) ->addColumn('public_notes', function ($model) { - return $model->public_notes; + return e($model->public_notes); }) ->make(); diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index dc5fa56999ab..aae3ebbda156 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -290,6 +290,9 @@ class InvoiceRepository extends BaseRepository 'invoices.invoice_date', 'invoices.balance as balance', 'invoices.due_date', + 'invoices.invoice_status_id', + 'invoices.due_date', + 'invoices.quote_invoice_id', 'clients.public_id as client_public_id', DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client_name"), 'invoices.public_id', @@ -324,7 +327,35 @@ class InvoiceRepository extends BaseRepository return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); }) - ->make(); + ->addColumn('status', function ($model) use ($entityType) { + if ($model->invoice_status_id == INVOICE_STATUS_PAID) { + $label = trans('texts.status_paid'); + $class = 'success'; + } elseif ($model->invoice_status_id == INVOICE_STATUS_PARTIAL) { + $label = trans('texts.status_partial'); + $class = 'info'; + } elseif (Invoice::calcIsOverdue($model->balance, $model->due_date)) { + $class = 'danger'; + if ($entityType == ENTITY_INVOICE) { + $label = trans('texts.overdue'); + } else { + $label = trans('texts.expired'); + } + } elseif ($entityType == ENTITY_QUOTE && ($model->invoice_status_id >= INVOICE_STATUS_APPROVED || $model->quote_invoice_id)) { + $label = trans('texts.status_approved'); + $class = 'success'; + } else { + $class = 'default'; + if ($entityType == ENTITY_INVOICE) { + $label = trans('texts.unpaid'); + } else { + $label = trans('texts.pending'); + } + } + + return "

$label

"; + }) + ->make(); } /** @@ -655,7 +686,7 @@ class InvoiceRepository extends BaseRepository if ($account->update_products && ! $invoice->has_tasks && ! $invoice->has_expenses - && $productKey != trans('texts.surcharge') + && ! in_array($productKey, Utils::trans(['surcharge', 'discount', 'fee'])) ) { $product = Product::findProductByKey($productKey); if (! $product) { @@ -1096,19 +1127,24 @@ class InvoiceRepository extends BaseRepository * * @return mixed */ - public function findNeedingReminding(Account $account) + public function findNeedingReminding(Account $account, $filterEnabled = true) { $dates = []; for ($i = 1; $i <= 3; $i++) { - if ($date = $account->getReminderDate($i)) { + if ($date = $account->getReminderDate($i, $filterEnabled)) { $field = $account->{"field_reminder{$i}"} == REMINDER_FIELD_DUE_DATE ? 'due_date' : 'invoice_date'; $dates[] = "$field = '$date'"; } } + if (! count($dates)) { + return []; + } + $sql = implode(' OR ', $dates); $invoices = Invoice::invoiceType(INVOICE_TYPE_STANDARD) + ->with('invoice_items') ->whereAccountId($account->id) ->where('balance', '>', 0) ->where('is_recurring', '=', false) @@ -1137,6 +1173,32 @@ class InvoiceRepository extends BaseRepository } } + public function setLateFee($invoice, $amount, $percent) + { + if ($amount <= 0 && $percent <= 0) { + return false; + } + + $account = $invoice->account; + + $data = $invoice->toArray(); + $fee = $amount; + + if ($invoice->amount > 0) { + $fee += round($invoice->amount * $percent / 100, 2); + } + + $item = []; + $item['product_key'] = trans('texts.fee'); + $item['notes'] = trans('texts.late_fee_added', ['date' => $account->formatDate('now')]); + $item['qty'] = 1; + $item['cost'] = $fee; + $item['invoice_item_type_id'] = INVOICE_ITEM_TYPE_LATE_FEE; + $data['invoice_items'][] = $item; + + $this->save($data, $invoice); + } + public function setGatewayFee($invoice, $gatewayTypeId) { $account = $invoice->account; diff --git a/app/Ninja/Repositories/ProductRepository.php b/app/Ninja/Repositories/ProductRepository.php index 49659beddaea..78212cef65b5 100644 --- a/app/Ninja/Repositories/ProductRepository.php +++ b/app/Ninja/Repositories/ProductRepository.php @@ -17,6 +17,7 @@ class ProductRepository extends BaseRepository { return Product::scope() ->withTrashed() + ->where('is_deleted', '=', false) ->get(); } @@ -54,7 +55,7 @@ class ProductRepository extends BaseRepository if ($product) { // do nothing } elseif ($publicId) { - $product = Product::scope($publicId)->firstOrFail(); + $product = Product::scope($publicId)->withArchived()->firstOrFail(); \Log::warning('Entity not set in product repo save'); } else { $product = Product::createNew(); diff --git a/app/Ninja/Repositories/TaxRateRepository.php b/app/Ninja/Repositories/TaxRateRepository.php index d16973941b50..2bfea8dbc72b 100644 --- a/app/Ninja/Repositories/TaxRateRepository.php +++ b/app/Ninja/Repositories/TaxRateRepository.php @@ -13,6 +13,11 @@ class TaxRateRepository extends BaseRepository return 'App\Models\TaxRate'; } + public function all() + { + return TaxRate::scope()->get(); + } + public function find($accountId) { return DB::table('tax_rates') diff --git a/app/Services/DatatableService.php b/app/Services/DatatableService.php index 44fa83bf3f82..d9924f7f5867 100644 --- a/app/Services/DatatableService.php +++ b/app/Services/DatatableService.php @@ -78,7 +78,7 @@ class DatatableService $dropdown_contents = ''; $lastIsDivider = false; - if (! $model->deleted_at || $model->deleted_at == '0000-00-00') { + if (! property_exists($model, 'is_deleted') || ! $model->is_deleted) { foreach ($datatable->actions() as $action) { if (count($action)) { // if show function isn't set default to true @@ -119,11 +119,15 @@ class DatatableService $dropdown_contents .= '
  • '; } - if (($datatable->entityType != ENTITY_USER || $model->public_id) && $can_edit) { - $dropdown_contents .= "
  • entityType}('archive', {$model->public_id})\">" - . mtrans($datatable->entityType, "archive_{$datatable->entityType}") . '
  • '; + if (! $model->deleted_at || $model->deleted_at == '0000-00-00') { + if (($datatable->entityType != ENTITY_USER || $model->public_id) && $can_edit) { + $dropdown_contents .= "
  • entityType}('archive', {$model->public_id})\">" + . mtrans($datatable->entityType, "archive_{$datatable->entityType}") . '
  • '; + } } - } elseif ($can_edit) { + } + + if ($model->deleted_at && $model->deleted_at != '0000-00-00' && $can_edit) { $dropdown_contents .= "
  • entityType}('restore', {$model->public_id})\">" . mtrans($datatable->entityType, "restore_{$datatable->entityType}") . '
  • '; } diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index 9fd7fea6f8ca..1e604a5ede61 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -19,6 +19,7 @@ use App\Ninja\Repositories\InvoiceRepository; use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\ProductRepository; use App\Ninja\Repositories\VendorRepository; +use App\Ninja\Repositories\TaxRateRepository; use App\Ninja\Serializers\ArraySerializer; use Auth; use Cache; @@ -126,7 +127,8 @@ class ImportService ProductRepository $productRepo, ExpenseRepository $expenseRepo, VendorRepository $vendorRepo, - ExpenseCategoryRepository $expenseCategoryRepo + ExpenseCategoryRepository $expenseCategoryRepo, + TaxRateRepository $taxRateRepository ) { $this->fractal = $manager; $this->fractal->setSerializer(new ArraySerializer()); @@ -139,6 +141,7 @@ class ImportService $this->expenseRepo = $expenseRepo; $this->vendorRepo = $vendorRepo; $this->expenseCategoryRepo = $expenseCategoryRepo; + $this->taxRateRepository = $taxRateRepository; } /** @@ -849,6 +852,8 @@ class ImportService 'invoice_ids' => [], 'vendors' => [], 'expense_categories' => [], + 'tax_rates' => [], + 'tax_names' => [], ]; $clients = $this->clientRepo->all(); @@ -886,6 +891,13 @@ class ImportService foreach ($expenseCaegories as $category) { $this->addExpenseCategoryToMaps($category); } + + $taxRates = $this->taxRateRepository->all(); + foreach ($taxRates as $taxRate) { + $name = trim(strtolower($taxRate->name)); + $this->maps['tax_rates'][$name] = $taxRate->rate; + $this->maps['tax_names'][$name] = $taxRate->name; + } } /** @@ -921,9 +933,7 @@ class ImportService private function addProductToMaps(Product $product) { if ($key = strtolower(trim($product->product_key))) { - $this->maps['product'][$key] = $product->id; - $this->maps['product_notes'][$key] = $product->notes; - $this->maps['product_cost'][$key] = $product->cost; + $this->maps['product'][$key] = $product; } } diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php index db84008750f0..282fd00a8558 100644 --- a/app/Services/InvoiceService.php +++ b/app/Services/InvoiceService.php @@ -9,6 +9,7 @@ use App\Models\Invoice; use App\Ninja\Datatables\InvoiceDatatable; use App\Ninja\Repositories\ClientRepository; use App\Ninja\Repositories\InvoiceRepository; +use App\Jobs\DownloadInvoices; use Auth; use Utils; @@ -54,6 +55,23 @@ class InvoiceService extends BaseService return $this->invoiceRepo; } + /** + * @param $ids + * @param $action + * + * @return int + */ + public function bulk($ids, $action) + { + if ($action == 'download') { + $invoices = $this->getRepo()->findByPublicIdsWithTrashed($ids); + dispatch(new DownloadInvoices(Auth::user(), $invoices)); + return count($invoices); + } else { + return parent::bulk($ids, $action); + } + } + /** * @param array $data * @param Invoice|null $invoice diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index e65e57e7f439..7e12baaeec59 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -140,7 +140,9 @@ class PaymentService extends BaseService $subject = trans('texts.auto_bill_failed', ['invoice_number' => $invoice->invoice_number]); $message = sprintf('%s: %s', ucwords($paymentDriver->providerName()), $exception->getMessage()); $mailer = app('App\Ninja\Mailers\UserMailer'); - $mailer->sendMessage($invoice->user, $subject, $message, $invoice); + $mailer->sendMessage($invoice->user, $subject, $message, [ + 'invoice' => $invoice + ]); } return false; @@ -178,17 +180,28 @@ class PaymentService extends BaseService foreach ($payments as $payment) { if (Auth::user()->can('edit', $payment)) { $amount = ! empty($params['refund_amount']) ? floatval($params['refund_amount']) : null; + $sendEmail = ! empty($params['refund_email']) ? boolval($params['refund_email']) : false; $paymentDriver = false; + $refunded = false; + if ($accountGateway = $payment->account_gateway) { $paymentDriver = $accountGateway->paymentDriver(); } + if ($paymentDriver && $paymentDriver->canRefundPayments) { if ($paymentDriver->refundPayment($payment, $amount)) { $successful++; + $refunded = true; } } else { $payment->recordRefund($amount); $successful++; + $refunded = true; + } + + if ($refunded && $sendEmail) { + $mailer = app('App\Ninja\Mailers\ContactMailer'); + $mailer->sendPaymentConfirmation($payment, $amount); } } } diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php index 6d9b1a66c8b2..bb370b555b2b 100644 --- a/app/Services/TemplateService.php +++ b/app/Services/TemplateService.php @@ -34,16 +34,9 @@ class TemplateService if ($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()) { $documentsHTML .= trans('texts.email_documents_header').''; } diff --git a/bower.json b/bower.json index 95317418c289..d0fc82a59a34 100644 --- a/bower.json +++ b/bower.json @@ -16,10 +16,10 @@ "bootstrap-datepicker": "1.4.0", "typeahead.js": "0.11.1", "accounting": "0.3.2", - "spectrum": "1.3.4", + "spectrum": "1.8.0", "d3": "3.4.11", "handsontable": "*", - "pdfmake": "0.1.24", + "pdfmake": "0.1.31", "moment": "*", "jsoneditor": "*", "moment-timezone": "~0.4.0", diff --git a/composer.json b/composer.json index b18b56a8905d..fea2bd3b9446 100644 --- a/composer.json +++ b/composer.json @@ -66,6 +66,7 @@ "meebio/omnipay-creditcall": "dev-master", "meebio/omnipay-secure-trading": "dev-master", "mfauveau/omnipay-pacnet": "~2.0", + "mpdf/mpdf": "^6.1", "nwidart/laravel-modules": "^1.14", "omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248", "omnipay/bitpay": "dev-master", diff --git a/composer.lock b/composer.lock index f79ef5bb553f..a3d7da98e61b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "e8611674b74a220909d4c70784f2e227", - "content-hash": "8d418324fd6e8b5af5c7b2058e31d898", + "hash": "f57537fe1dab41aac024b12e4a284570", + "content-hash": "9d0ce024f2c50440bf896ecc2a37350f", "packages": [ { "name": "agmscode/omnipay-agms", @@ -68,12 +68,12 @@ "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/alfaproject/omnipay-skrill.git", + "url": "https://github.com/xcaliber-tech/omnipay-skrill.git", "reference": "41a7a03c5b90d496720e288bebc157d898837ccd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alfaproject/omnipay-skrill/zipball/41a7a03c5b90d496720e288bebc157d898837ccd", + "url": "https://api.github.com/repos/xcaliber-tech/omnipay-skrill/zipball/41a7a03c5b90d496720e288bebc157d898837ccd", "reference": "41a7a03c5b90d496720e288bebc157d898837ccd", "shasum": "" }, @@ -4723,6 +4723,57 @@ ], "time": "2017-06-19 01:22:40" }, + { + "name": "mpdf/mpdf", + "version": "v6.1.3", + "source": { + "type": "git", + "url": "https://github.com/mpdf/mpdf.git", + "reference": "7f138bf7508eac895ac2c13d2509b056ac7e7e97" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mpdf/mpdf/zipball/7f138bf7508eac895ac2c13d2509b056ac7e7e97", + "reference": "7f138bf7508eac895ac2c13d2509b056ac7e7e97", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.4.0", + "setasign/fpdi": "1.6.*" + }, + "require-dev": { + "phpunit/phpunit": "^4.7" + }, + "suggest": { + "ext-zlib": "Needed for compression of embedded resources, such as fonts" + }, + "type": "library", + "autoload": { + "classmap": [ + "mpdf.php", + "classes" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0" + ], + "authors": [ + { + "name": "Ian Back", + "role": "Developer" + } + ], + "description": "A PHP class to generate PDF files from HTML with Unicode/UTF-8 and CJK support", + "homepage": "http://mpdf.github.io", + "keywords": [ + "pdf", + "php", + "utf-8" + ], + "time": "2016-12-12 10:42:18" + }, { "name": "mtdowling/cron-expression", "version": "v1.2.0", @@ -7537,6 +7588,55 @@ ], "time": "2017-06-14 03:57:53" }, + { + "name": "setasign/fpdi", + "version": "1.6.2", + "source": { + "type": "git", + "url": "https://github.com/Setasign/FPDI.git", + "reference": "a6ad58897a6d97cc2d2cd2adaeda343b25a368ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6ad58897a6d97cc2d2cd2adaeda343b25a368ea", + "reference": "a6ad58897a6d97cc2d2cd2adaeda343b25a368ea", + "shasum": "" + }, + "suggest": { + "setasign/fpdf": "FPDI will extend this class but as it is also possible to use \"tecnickcom/tcpdf\" as an alternative there's no fixed dependency configured.", + "setasign/fpdi-fpdf": "Use this package to automatically evaluate dependencies to FPDF.", + "setasign/fpdi-tcpdf": "Use this package to automatically evaluate dependencies to TCPDF." + }, + "type": "library", + "autoload": { + "classmap": [ + "filters/", + "fpdi.php", + "fpdf_tpl.php", + "fpdi_pdf_parser.php", + "pdf_context.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Slabon", + "email": "jan.slabon@setasign.com", + "homepage": "https://www.setasign.com" + } + ], + "description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.", + "homepage": "https://www.setasign.com/fpdi", + "keywords": [ + "fpdf", + "fpdi", + "pdf" + ], + "time": "2017-05-11 14:25:49" + }, { "name": "simshaun/recurr", "version": "dev-master", @@ -8044,7 +8144,7 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.24", + "version": "v2.8.26", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", @@ -8202,16 +8302,16 @@ }, { "name": "symfony/http-foundation", - "version": "v2.8.24", + "version": "v2.8.26", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "2b592ca5fe2ad7ee8a92d409d2b830277ad58231" + "reference": "9ff3a0b3756ace2e3da7dded37e920ee776faa4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/2b592ca5fe2ad7ee8a92d409d2b830277ad58231", - "reference": "2b592ca5fe2ad7ee8a92d409d2b830277ad58231", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/9ff3a0b3756ace2e3da7dded37e920ee776faa4e", + "reference": "9ff3a0b3756ace2e3da7dded37e920ee776faa4e", "shasum": "" }, "require": { @@ -8253,7 +8353,7 @@ ], "description": "Symfony HttpFoundation Component", "homepage": "https://symfony.com", - "time": "2017-06-20 23:27:56" + "time": "2017-07-17 14:02:19" }, { "name": "symfony/http-kernel", diff --git a/config/excel.php b/config/excel.php index 3151039dee9f..34f170155660 100644 --- a/config/excel.php +++ b/config/excel.php @@ -1,5 +1,23 @@ array( @@ -171,7 +189,7 @@ return array( | having the appropriate fonts installed. | */ - 'autosize-method' => PHPExcel_Shared_Font::AUTOSIZE_METHOD_APPROX, + 'autosize-method' => constant('\PHPExcel_Shared_Font::AUTOSIZE_METHOD_' . env('EXCEL_AUTOSIZE_MODE', 'APPROX')), /* |-------------------------------------------------------------------------- @@ -291,7 +309,7 @@ return array( |-------------------------------------------------------------------------- | Supported: DomPDF, tcPDF, mPDF */ - 'driver' => 'DomPDF', + 'driver' => 'mPDF', /* |-------------------------------------------------------------------------- @@ -306,7 +324,7 @@ return array( |-------------------------------------------------------------------------- */ 'DomPDF' => array( - 'path' => base_path('vendor/dompdf/dompdf/') + 'path' => base_path('vendor/dompdf/dompdf/'), ), /* diff --git a/config/session.php b/config/session.php index 9a432a212ae0..beb02c87d793 100644 --- a/config/session.php +++ b/config/session.php @@ -31,7 +31,7 @@ return [ 'lifetime' => env('SESSION_LIFETIME', (60 * 8)), - 'expire_on_close' => false, + 'expire_on_close' => true, /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2017_07_18_124150_add_late_fees.php b/database/migrations/2017_07_18_124150_add_late_fees.php new file mode 100644 index 000000000000..51aa1ae096f3 --- /dev/null +++ b/database/migrations/2017_07_18_124150_add_late_fees.php @@ -0,0 +1,49 @@ +decimal('late_fee1_amount', 13, 2)->nullable(); + $table->decimal('late_fee1_percent', 13, 3)->nullable(); + $table->decimal('late_fee2_amount', 13, 2)->nullable(); + $table->decimal('late_fee2_percent', 13, 3)->nullable(); + $table->decimal('late_fee3_amount', 13, 2)->nullable(); + $table->decimal('late_fee3_percent', 13, 3)->nullable(); + }); + + Schema::table('documents', function ($table) { + $table->boolean('is_default')->default(false)->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_email_settings', function ($table) { + $table->dropColumn('late_fee1_amount'); + $table->dropColumn('late_fee1_percent'); + $table->dropColumn('late_fee2_amount'); + $table->dropColumn('late_fee2_percent'); + $table->dropColumn('late_fee3_amount'); + $table->dropColumn('late_fee3_percent'); + }); + + Schema::table('documents', function ($table) { + $table->dropColumn('is_default'); + }); + } +} diff --git a/database/setup.sql b/database/setup.sql index 6384429fb044..aab7b116e445 100644 --- a/database/setup.sql +++ b/database/setup.sql @@ -1,8 +1,8 @@ --- MySQL dump 10.13 Distrib 5.7.18, for Linux (x86_64) +-- MySQL dump 10.13 Distrib 5.7.19, for Linux (x86_64) -- -- Host: localhost Database: ninja -- ------------------------------------------------------ --- Server version 5.7.18-0ubuntu0.16.04.1 +-- Server version 5.7.19-0ubuntu0.16.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -41,6 +41,12 @@ CREATE TABLE `account_email_settings` ( `email_template_reminder1` text COLLATE utf8_unicode_ci NOT NULL, `email_template_reminder2` text COLLATE utf8_unicode_ci NOT NULL, `email_template_reminder3` text COLLATE utf8_unicode_ci NOT NULL, + `late_fee1_amount` decimal(13,2) DEFAULT NULL, + `late_fee1_percent` decimal(13,3) DEFAULT NULL, + `late_fee2_amount` decimal(13,2) DEFAULT NULL, + `late_fee2_percent` decimal(13,3) DEFAULT NULL, + `late_fee3_amount` decimal(13,2) DEFAULT NULL, + `late_fee3_percent` decimal(13,3) DEFAULT NULL, PRIMARY KEY (`id`), KEY `account_email_settings_account_id_index` (`account_id`), CONSTRAINT `account_email_settings_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE @@ -961,6 +967,7 @@ CREATE TABLE `documents` ( `height` int(10) unsigned DEFAULT NULL, `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL, + `is_default` tinyint(1) DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `documents_account_id_public_id_unique` (`account_id`,`public_id`), KEY `documents_user_id_foreign` (`user_id`), @@ -1224,7 +1231,7 @@ CREATE TABLE `gateways` ( LOCK TABLES `gateways` WRITE; /*!40000 ALTER TABLE `gateways` DISABLE KEYS */; -INSERT INTO `gateways` VALUES (1,'2017-07-17 14:14:38','2017-07-17 14:14:38','Authorize.Net AIM','AuthorizeNet_AIM',1,1,4,0,NULL,0,0),(2,'2017-07-17 14:14:38','2017-07-17 14:14:38','Authorize.Net SIM','AuthorizeNet_SIM',1,2,10000,0,NULL,0,0),(3,'2017-07-17 14:14:38','2017-07-17 14:14:38','CardSave','CardSave',1,1,10000,0,NULL,0,0),(4,'2017-07-17 14:14:38','2017-07-17 14:14:38','Eway Rapid','Eway_RapidShared',1,1,10000,0,NULL,1,0),(5,'2017-07-17 14:14:38','2017-07-17 14:14:38','FirstData Connect','FirstData_Connect',1,1,10000,0,NULL,0,0),(6,'2017-07-17 14:14:38','2017-07-17 14:14:38','GoCardless','GoCardless',1,1,10000,0,NULL,1,0),(7,'2017-07-17 14:14:38','2017-07-17 14:14:38','Migs ThreeParty','Migs_ThreeParty',1,1,10000,0,NULL,0,0),(8,'2017-07-17 14:14:38','2017-07-17 14:14:38','Migs TwoParty','Migs_TwoParty',1,1,10000,0,NULL,0,0),(9,'2017-07-17 14:14:38','2017-07-17 14:14:38','Mollie','Mollie',1,1,7,0,NULL,1,0),(10,'2017-07-17 14:14:38','2017-07-17 14:14:38','MultiSafepay','MultiSafepay',1,1,10000,0,NULL,0,0),(11,'2017-07-17 14:14:38','2017-07-17 14:14:38','Netaxept','Netaxept',1,1,10000,0,NULL,0,0),(12,'2017-07-17 14:14:38','2017-07-17 14:14:38','NetBanx','NetBanx',1,1,10000,0,NULL,0,0),(13,'2017-07-17 14:14:38','2017-07-17 14:14:38','PayFast','PayFast',1,1,10000,0,NULL,1,0),(14,'2017-07-17 14:14:38','2017-07-17 14:14:38','Payflow Pro','Payflow_Pro',1,1,10000,0,NULL,0,0),(15,'2017-07-17 14:14:38','2017-07-17 14:14:38','PaymentExpress PxPay','PaymentExpress_PxPay',1,1,10000,0,NULL,0,0),(16,'2017-07-17 14:14:38','2017-07-17 14:14:38','PaymentExpress PxPost','PaymentExpress_PxPost',1,1,10000,0,NULL,0,0),(17,'2017-07-17 14:14:38','2017-07-17 14:14:38','PayPal Express','PayPal_Express',1,1,3,0,NULL,1,0),(18,'2017-07-17 14:14:38','2017-07-17 14:14:38','PayPal Pro','PayPal_Pro',1,1,10000,0,NULL,0,0),(19,'2017-07-17 14:14:38','2017-07-17 14:14:38','Pin','Pin',1,1,10000,0,NULL,0,0),(20,'2017-07-17 14:14:38','2017-07-17 14:14:38','SagePay Direct','SagePay_Direct',1,1,10000,0,NULL,0,0),(21,'2017-07-17 14:14:38','2017-07-17 14:14:38','SagePay Server','SagePay_Server',1,1,10000,0,NULL,0,0),(22,'2017-07-17 14:14:38','2017-07-17 14:14:38','SecurePay DirectPost','SecurePay_DirectPost',1,1,10000,0,NULL,0,0),(23,'2017-07-17 14:14:38','2017-07-17 14:14:38','Stripe','Stripe',1,1,1,0,NULL,0,0),(24,'2017-07-17 14:14:38','2017-07-17 14:14:38','TargetPay Direct eBanking','TargetPay_Directebanking',1,1,10000,0,NULL,0,0),(25,'2017-07-17 14:14:38','2017-07-17 14:14:38','TargetPay Ideal','TargetPay_Ideal',1,1,10000,0,NULL,0,0),(26,'2017-07-17 14:14:38','2017-07-17 14:14:38','TargetPay Mr Cash','TargetPay_Mrcash',1,1,10000,0,NULL,0,0),(27,'2017-07-17 14:14:38','2017-07-17 14:14:38','TwoCheckout','TwoCheckout',1,1,10000,0,NULL,1,0),(28,'2017-07-17 14:14:38','2017-07-17 14:14:38','WorldPay','WorldPay',1,1,10000,0,NULL,0,0),(29,'2017-07-17 14:14:38','2017-07-17 14:14:38','BeanStream','BeanStream',1,2,10000,0,NULL,0,0),(30,'2017-07-17 14:14:38','2017-07-17 14:14:38','Psigate','Psigate',1,2,10000,0,NULL,0,0),(31,'2017-07-17 14:14:38','2017-07-17 14:14:38','moolah','AuthorizeNet_AIM',1,1,10000,0,NULL,0,0),(32,'2017-07-17 14:14:38','2017-07-17 14:14:38','Alipay','Alipay_Express',1,1,10000,0,NULL,0,0),(33,'2017-07-17 14:14:38','2017-07-17 14:14:38','Buckaroo','Buckaroo_CreditCard',1,1,10000,0,NULL,0,0),(34,'2017-07-17 14:14:38','2017-07-17 14:14:38','Coinbase','Coinbase',1,1,10000,0,NULL,0,0),(35,'2017-07-17 14:14:38','2017-07-17 14:14:38','DataCash','DataCash',1,1,10000,0,NULL,0,0),(36,'2017-07-17 14:14:38','2017-07-17 14:14:38','Neteller','Neteller',1,2,10000,0,NULL,0,0),(37,'2017-07-17 14:14:38','2017-07-17 14:14:38','Pacnet','Pacnet',1,1,10000,0,NULL,0,0),(38,'2017-07-17 14:14:38','2017-07-17 14:14:38','PaymentSense','PaymentSense',1,2,10000,0,NULL,0,0),(39,'2017-07-17 14:14:38','2017-07-17 14:14:38','Realex','Realex_Remote',1,1,10000,0,NULL,0,0),(40,'2017-07-17 14:14:38','2017-07-17 14:14:38','Sisow','Sisow',1,1,10000,0,NULL,0,0),(41,'2017-07-17 14:14:38','2017-07-17 14:14:38','Skrill','Skrill',1,1,10000,0,NULL,1,0),(42,'2017-07-17 14:14:38','2017-07-17 14:14:38','BitPay','BitPay',1,1,6,0,NULL,1,0),(43,'2017-07-17 14:14:38','2017-07-17 14:14:38','Dwolla','Dwolla',1,1,5,0,NULL,1,0),(44,'2017-07-17 14:14:38','2017-07-17 14:14:38','AGMS','Agms',1,1,10000,0,NULL,0,0),(45,'2017-07-17 14:14:38','2017-07-17 14:14:38','Barclays','BarclaysEpdq\\Essential',1,1,10000,0,NULL,0,0),(46,'2017-07-17 14:14:38','2017-07-17 14:14:38','Cardgate','Cardgate',1,1,10000,0,NULL,0,0),(47,'2017-07-17 14:14:38','2017-07-17 14:14:38','Checkout.com','CheckoutCom',1,1,10000,0,NULL,0,0),(48,'2017-07-17 14:14:38','2017-07-17 14:14:38','Creditcall','Creditcall',1,1,10000,0,NULL,0,0),(49,'2017-07-17 14:14:38','2017-07-17 14:14:38','Cybersource','Cybersource',1,1,10000,0,NULL,0,0),(50,'2017-07-17 14:14:38','2017-07-17 14:14:38','ecoPayz','Ecopayz',1,1,10000,0,NULL,0,0),(51,'2017-07-17 14:14:38','2017-07-17 14:14:38','Fasapay','Fasapay',1,1,10000,0,NULL,0,0),(52,'2017-07-17 14:14:38','2017-07-17 14:14:38','Komoju','Komoju',1,1,10000,0,NULL,0,0),(53,'2017-07-17 14:14:38','2017-07-17 14:14:38','Multicards','Multicards',1,1,10000,0,NULL,0,0),(54,'2017-07-17 14:14:38','2017-07-17 14:14:38','Pagar.Me','Pagarme',1,2,10000,0,NULL,0,0),(55,'2017-07-17 14:14:38','2017-07-17 14:14:38','Paysafecard','Paysafecard',1,1,10000,0,NULL,0,0),(56,'2017-07-17 14:14:38','2017-07-17 14:14:38','Paytrace','Paytrace_CreditCard',1,1,10000,0,NULL,0,0),(57,'2017-07-17 14:14:38','2017-07-17 14:14:38','Secure Trading','SecureTrading',1,1,10000,0,NULL,0,0),(58,'2017-07-17 14:14:38','2017-07-17 14:14:38','SecPay','SecPay',1,1,10000,0,NULL,0,0),(59,'2017-07-17 14:14:38','2017-07-17 14:14:38','WeChat Express','WeChat_Express',1,2,10000,0,NULL,0,0),(60,'2017-07-17 14:14:38','2017-07-17 14:14:38','WePay','WePay',1,1,10000,0,NULL,0,0),(61,'2017-07-17 14:14:38','2017-07-17 14:14:38','Braintree','Braintree',1,1,2,0,NULL,0,0),(62,'2017-07-17 14:14:38','2017-07-17 14:14:38','Custom','Custom',1,1,8,0,NULL,1,0),(63,'2017-07-17 14:14:38','2017-07-17 14:14:38','FirstData Payeezy','FirstData_Payeezy',1,1,10000,0,NULL,0,0); +INSERT INTO `gateways` VALUES (1,'2017-08-07 08:11:39','2017-08-07 08:11:39','Authorize.Net AIM','AuthorizeNet_AIM',1,1,4,0,NULL,0,0),(2,'2017-08-07 08:11:39','2017-08-07 08:11:39','Authorize.Net SIM','AuthorizeNet_SIM',1,2,10000,0,NULL,0,0),(3,'2017-08-07 08:11:39','2017-08-07 08:11:39','CardSave','CardSave',1,1,10000,0,NULL,0,0),(4,'2017-08-07 08:11:39','2017-08-07 08:11:39','Eway Rapid','Eway_RapidShared',1,1,10000,0,NULL,1,0),(5,'2017-08-07 08:11:39','2017-08-07 08:11:39','FirstData Connect','FirstData_Connect',1,1,10000,0,NULL,0,0),(6,'2017-08-07 08:11:39','2017-08-07 08:11:39','GoCardless','GoCardless',1,1,10000,0,NULL,1,0),(7,'2017-08-07 08:11:39','2017-08-07 08:11:39','Migs ThreeParty','Migs_ThreeParty',1,1,10000,0,NULL,0,0),(8,'2017-08-07 08:11:39','2017-08-07 08:11:39','Migs TwoParty','Migs_TwoParty',1,1,10000,0,NULL,0,0),(9,'2017-08-07 08:11:39','2017-08-07 08:11:39','Mollie','Mollie',1,1,7,0,NULL,1,0),(10,'2017-08-07 08:11:39','2017-08-07 08:11:39','MultiSafepay','MultiSafepay',1,1,10000,0,NULL,0,0),(11,'2017-08-07 08:11:39','2017-08-07 08:11:39','Netaxept','Netaxept',1,1,10000,0,NULL,0,0),(12,'2017-08-07 08:11:39','2017-08-07 08:11:39','NetBanx','NetBanx',1,1,10000,0,NULL,0,0),(13,'2017-08-07 08:11:39','2017-08-07 08:11:39','PayFast','PayFast',1,1,10000,0,NULL,1,0),(14,'2017-08-07 08:11:39','2017-08-07 08:11:39','Payflow Pro','Payflow_Pro',1,1,10000,0,NULL,0,0),(15,'2017-08-07 08:11:39','2017-08-07 08:11:39','PaymentExpress PxPay','PaymentExpress_PxPay',1,1,10000,0,NULL,0,0),(16,'2017-08-07 08:11:39','2017-08-07 08:11:39','PaymentExpress PxPost','PaymentExpress_PxPost',1,1,10000,0,NULL,0,0),(17,'2017-08-07 08:11:39','2017-08-07 08:11:39','PayPal Express','PayPal_Express',1,1,3,0,NULL,1,0),(18,'2017-08-07 08:11:39','2017-08-07 08:11:39','PayPal Pro','PayPal_Pro',1,1,10000,0,NULL,0,0),(19,'2017-08-07 08:11:39','2017-08-07 08:11:39','Pin','Pin',1,1,10000,0,NULL,0,0),(20,'2017-08-07 08:11:39','2017-08-07 08:11:39','SagePay Direct','SagePay_Direct',1,1,10000,0,NULL,0,0),(21,'2017-08-07 08:11:39','2017-08-07 08:11:39','SagePay Server','SagePay_Server',1,1,10000,0,NULL,0,0),(22,'2017-08-07 08:11:39','2017-08-07 08:11:39','SecurePay DirectPost','SecurePay_DirectPost',1,1,10000,0,NULL,0,0),(23,'2017-08-07 08:11:39','2017-08-07 08:11:39','Stripe','Stripe',1,1,1,0,NULL,0,0),(24,'2017-08-07 08:11:39','2017-08-07 08:11:39','TargetPay Direct eBanking','TargetPay_Directebanking',1,1,10000,0,NULL,0,0),(25,'2017-08-07 08:11:39','2017-08-07 08:11:39','TargetPay Ideal','TargetPay_Ideal',1,1,10000,0,NULL,0,0),(26,'2017-08-07 08:11:39','2017-08-07 08:11:39','TargetPay Mr Cash','TargetPay_Mrcash',1,1,10000,0,NULL,0,0),(27,'2017-08-07 08:11:39','2017-08-07 08:11:39','TwoCheckout','TwoCheckout',1,1,10000,0,NULL,1,0),(28,'2017-08-07 08:11:39','2017-08-07 08:11:39','WorldPay','WorldPay',1,1,10000,0,NULL,0,0),(29,'2017-08-07 08:11:39','2017-08-07 08:11:39','BeanStream','BeanStream',1,2,10000,0,NULL,0,0),(30,'2017-08-07 08:11:39','2017-08-07 08:11:39','Psigate','Psigate',1,2,10000,0,NULL,0,0),(31,'2017-08-07 08:11:39','2017-08-07 08:11:39','moolah','AuthorizeNet_AIM',1,1,10000,0,NULL,0,0),(32,'2017-08-07 08:11:39','2017-08-07 08:11:39','Alipay','Alipay_Express',1,1,10000,0,NULL,0,0),(33,'2017-08-07 08:11:39','2017-08-07 08:11:39','Buckaroo','Buckaroo_CreditCard',1,1,10000,0,NULL,0,0),(34,'2017-08-07 08:11:39','2017-08-07 08:11:39','Coinbase','Coinbase',1,1,10000,0,NULL,0,0),(35,'2017-08-07 08:11:39','2017-08-07 08:11:39','DataCash','DataCash',1,1,10000,0,NULL,0,0),(36,'2017-08-07 08:11:39','2017-08-07 08:11:39','Neteller','Neteller',1,2,10000,0,NULL,0,0),(37,'2017-08-07 08:11:39','2017-08-07 08:11:39','Pacnet','Pacnet',1,1,10000,0,NULL,0,0),(38,'2017-08-07 08:11:39','2017-08-07 08:11:39','PaymentSense','PaymentSense',1,2,10000,0,NULL,0,0),(39,'2017-08-07 08:11:39','2017-08-07 08:11:39','Realex','Realex_Remote',1,1,10000,0,NULL,0,0),(40,'2017-08-07 08:11:39','2017-08-07 08:11:39','Sisow','Sisow',1,1,10000,0,NULL,0,0),(41,'2017-08-07 08:11:39','2017-08-07 08:11:39','Skrill','Skrill',1,1,10000,0,NULL,1,0),(42,'2017-08-07 08:11:39','2017-08-07 08:11:39','BitPay','BitPay',1,1,6,0,NULL,1,0),(43,'2017-08-07 08:11:39','2017-08-07 08:11:39','Dwolla','Dwolla',1,1,5,0,NULL,1,0),(44,'2017-08-07 08:11:39','2017-08-07 08:11:39','AGMS','Agms',1,1,10000,0,NULL,0,0),(45,'2017-08-07 08:11:39','2017-08-07 08:11:39','Barclays','BarclaysEpdq\\Essential',1,1,10000,0,NULL,0,0),(46,'2017-08-07 08:11:39','2017-08-07 08:11:39','Cardgate','Cardgate',1,1,10000,0,NULL,0,0),(47,'2017-08-07 08:11:39','2017-08-07 08:11:39','Checkout.com','CheckoutCom',1,1,10000,0,NULL,0,0),(48,'2017-08-07 08:11:39','2017-08-07 08:11:39','Creditcall','Creditcall',1,1,10000,0,NULL,0,0),(49,'2017-08-07 08:11:39','2017-08-07 08:11:39','Cybersource','Cybersource',1,1,10000,0,NULL,0,0),(50,'2017-08-07 08:11:39','2017-08-07 08:11:39','ecoPayz','Ecopayz',1,1,10000,0,NULL,0,0),(51,'2017-08-07 08:11:39','2017-08-07 08:11:39','Fasapay','Fasapay',1,1,10000,0,NULL,0,0),(52,'2017-08-07 08:11:39','2017-08-07 08:11:39','Komoju','Komoju',1,1,10000,0,NULL,0,0),(53,'2017-08-07 08:11:39','2017-08-07 08:11:39','Multicards','Multicards',1,1,10000,0,NULL,0,0),(54,'2017-08-07 08:11:39','2017-08-07 08:11:39','Pagar.Me','Pagarme',1,2,10000,0,NULL,0,0),(55,'2017-08-07 08:11:39','2017-08-07 08:11:39','Paysafecard','Paysafecard',1,1,10000,0,NULL,0,0),(56,'2017-08-07 08:11:39','2017-08-07 08:11:39','Paytrace','Paytrace_CreditCard',1,1,10000,0,NULL,0,0),(57,'2017-08-07 08:11:39','2017-08-07 08:11:39','Secure Trading','SecureTrading',1,1,10000,0,NULL,0,0),(58,'2017-08-07 08:11:39','2017-08-07 08:11:39','SecPay','SecPay',1,1,10000,0,NULL,0,0),(59,'2017-08-07 08:11:39','2017-08-07 08:11:39','WeChat Express','WeChat_Express',1,2,10000,0,NULL,0,0),(60,'2017-08-07 08:11:39','2017-08-07 08:11:39','WePay','WePay',1,1,10000,0,NULL,0,0),(61,'2017-08-07 08:11:39','2017-08-07 08:11:39','Braintree','Braintree',1,1,2,0,NULL,0,0),(62,'2017-08-07 08:11:39','2017-08-07 08:11:39','Custom','Custom',1,1,8,0,NULL,1,0),(63,'2017-08-07 08:11:39','2017-08-07 08:11:39','FirstData Payeezy','FirstData_Payeezy',1,1,10000,0,NULL,0,0); /*!40000 ALTER TABLE `gateways` ENABLE KEYS */; UNLOCK TABLES; @@ -1765,7 +1772,7 @@ CREATE TABLE `migrations` ( LOCK TABLES `migrations` WRITE; /*!40000 ALTER TABLE `migrations` DISABLE KEYS */; -INSERT INTO `migrations` VALUES ('2013_11_05_180133_confide_setup_users_table',1),('2013_11_28_195703_setup_countries_table',1),('2014_02_13_151500_add_cascase_drops',1),('2014_02_19_151817_add_support_for_invoice_designs',1),('2014_03_03_155556_add_phone_to_account',1),('2014_03_19_201454_add_language_support',1),('2014_03_20_200300_create_payment_libraries',1),('2014_03_23_051736_enable_forcing_jspdf',1),('2014_03_25_102200_add_sort_and_recommended_to_gateways',1),('2014_04_03_191105_add_pro_plan',1),('2014_04_17_100523_add_remember_token',1),('2014_04_17_145108_add_custom_fields',1),('2014_04_23_170909_add_products_settings',1),('2014_04_29_174315_add_advanced_settings',1),('2014_05_17_175626_add_quotes',1),('2014_06_17_131940_add_accepted_credit_cards_to_account_gateways',1),('2014_07_13_142654_one_click_install',1),('2014_07_17_205900_support_hiding_quantity',1),('2014_07_24_171214_add_zapier_support',1),('2014_10_01_141248_add_company_vat_number',1),('2014_10_05_141856_track_last_seen_message',1),('2014_10_06_103529_add_timesheets',1),('2014_10_06_195330_add_invoice_design_table',1),('2014_10_13_054100_add_invoice_number_settings',1),('2014_10_14_225227_add_danish_translation',1),('2014_10_22_174452_add_affiliate_price',1),('2014_10_30_184126_add_company_id_number',1),('2014_11_04_200406_allow_null_client_currency',1),('2014_12_03_154119_add_discount_type',1),('2015_02_12_102940_add_email_templates',1),('2015_02_17_131714_support_token_billing',1),('2015_02_27_081836_add_invoice_footer',1),('2015_03_03_140259_add_tokens',1),('2015_03_09_151011_add_ip_to_activity',1),('2015_03_15_174122_add_pdf_email_attachment_option',1),('2015_03_30_100000_create_password_resets_table',1),('2015_04_12_093447_add_sv_language',1),('2015_04_13_100333_add_notify_approved',1),('2015_04_16_122647_add_partial_amount_to_invoices',1),('2015_05_21_184104_add_font_size',1),('2015_05_27_121828_add_tasks',1),('2015_05_27_170808_add_custom_invoice_labels',1),('2015_06_09_134208_add_has_tasks_to_invoices',1),('2015_06_14_093410_enable_resuming_tasks',1),('2015_06_14_173025_multi_company_support',1),('2015_07_07_160257_support_locking_account',1),('2015_07_08_114333_simplify_tasks',1),('2015_07_19_081332_add_custom_design',1),('2015_07_27_183830_add_pdfmake_support',1),('2015_08_13_084041_add_formats_to_datetime_formats_table',1),('2015_09_04_080604_add_swap_postal_code',1),('2015_09_07_135935_add_account_domain',1),('2015_09_10_185135_add_reminder_emails',1),('2015_10_07_135651_add_social_login',1),('2015_10_21_075058_add_default_tax_rates',1),('2015_10_21_185724_add_invoice_number_pattern',1),('2015_10_27_180214_add_is_system_to_activities',1),('2015_10_29_133747_add_default_quote_terms',1),('2015_11_01_080417_encrypt_tokens',1),('2015_11_03_181318_improve_currency_localization',1),('2015_11_30_133206_add_email_designs',1),('2015_12_27_154513_add_reminder_settings',1),('2015_12_30_042035_add_client_view_css',1),('2016_01_04_175228_create_vendors_table',1),('2016_01_06_153144_add_invoice_font_support',1),('2016_01_17_155725_add_quote_to_invoice_option',1),('2016_01_18_195351_add_bank_accounts',1),('2016_01_24_112646_add_bank_subaccounts',1),('2016_01_27_173015_add_header_footer_option',1),('2016_02_01_135956_add_source_currency_to_expenses',1),('2016_02_25_152948_add_client_password',1),('2016_02_28_081424_add_custom_invoice_fields',1),('2016_03_14_066181_add_user_permissions',1),('2016_03_14_214710_add_support_three_decimal_taxes',1),('2016_03_22_168362_add_documents',1),('2016_03_23_215049_support_multiple_tax_rates',1),('2016_04_16_103943_enterprise_plan',1),('2016_04_18_174135_add_page_size',1),('2016_04_23_182223_payments_changes',1),('2016_05_16_102925_add_swap_currency_symbol_to_currency',1),('2016_05_18_085739_add_invoice_type_support',1),('2016_05_24_164847_wepay_ach',1),('2016_07_08_083802_support_new_pricing',1),('2016_07_13_083821_add_buy_now_buttons',1),('2016_08_10_184027_add_support_for_bots',1),('2016_09_05_150625_create_gateway_types',1),('2016_10_20_191150_add_expense_to_activities',1),('2016_11_03_113316_add_invoice_signature',1),('2016_11_03_161149_add_bluevine_fields',1),('2016_11_28_092904_add_task_projects',1),('2016_12_13_113955_add_pro_plan_discount',1),('2017_01_01_214241_add_inclusive_taxes',1),('2017_02_23_095934_add_custom_product_fields',1),('2017_03_16_085702_add_gateway_fee_location',1),('2017_04_16_101744_add_custom_contact_fields',1),('2017_04_30_174702_add_multiple_database_support',1),('2017_05_10_144928_add_oauth_to_lookups',1),('2017_05_16_101715_add_default_note_to_client',1),('2017_06_19_111515_update_dark_mode',1); +INSERT INTO `migrations` VALUES ('2013_11_05_180133_confide_setup_users_table',1),('2013_11_28_195703_setup_countries_table',1),('2014_02_13_151500_add_cascase_drops',1),('2014_02_19_151817_add_support_for_invoice_designs',1),('2014_03_03_155556_add_phone_to_account',1),('2014_03_19_201454_add_language_support',1),('2014_03_20_200300_create_payment_libraries',1),('2014_03_23_051736_enable_forcing_jspdf',1),('2014_03_25_102200_add_sort_and_recommended_to_gateways',1),('2014_04_03_191105_add_pro_plan',1),('2014_04_17_100523_add_remember_token',1),('2014_04_17_145108_add_custom_fields',1),('2014_04_23_170909_add_products_settings',1),('2014_04_29_174315_add_advanced_settings',1),('2014_05_17_175626_add_quotes',1),('2014_06_17_131940_add_accepted_credit_cards_to_account_gateways',1),('2014_07_13_142654_one_click_install',1),('2014_07_17_205900_support_hiding_quantity',1),('2014_07_24_171214_add_zapier_support',1),('2014_10_01_141248_add_company_vat_number',1),('2014_10_05_141856_track_last_seen_message',1),('2014_10_06_103529_add_timesheets',1),('2014_10_06_195330_add_invoice_design_table',1),('2014_10_13_054100_add_invoice_number_settings',1),('2014_10_14_225227_add_danish_translation',1),('2014_10_22_174452_add_affiliate_price',1),('2014_10_30_184126_add_company_id_number',1),('2014_11_04_200406_allow_null_client_currency',1),('2014_12_03_154119_add_discount_type',1),('2015_02_12_102940_add_email_templates',1),('2015_02_17_131714_support_token_billing',1),('2015_02_27_081836_add_invoice_footer',1),('2015_03_03_140259_add_tokens',1),('2015_03_09_151011_add_ip_to_activity',1),('2015_03_15_174122_add_pdf_email_attachment_option',1),('2015_03_30_100000_create_password_resets_table',1),('2015_04_12_093447_add_sv_language',1),('2015_04_13_100333_add_notify_approved',1),('2015_04_16_122647_add_partial_amount_to_invoices',1),('2015_05_21_184104_add_font_size',1),('2015_05_27_121828_add_tasks',1),('2015_05_27_170808_add_custom_invoice_labels',1),('2015_06_09_134208_add_has_tasks_to_invoices',1),('2015_06_14_093410_enable_resuming_tasks',1),('2015_06_14_173025_multi_company_support',1),('2015_07_07_160257_support_locking_account',1),('2015_07_08_114333_simplify_tasks',1),('2015_07_19_081332_add_custom_design',1),('2015_07_27_183830_add_pdfmake_support',1),('2015_08_13_084041_add_formats_to_datetime_formats_table',1),('2015_09_04_080604_add_swap_postal_code',1),('2015_09_07_135935_add_account_domain',1),('2015_09_10_185135_add_reminder_emails',1),('2015_10_07_135651_add_social_login',1),('2015_10_21_075058_add_default_tax_rates',1),('2015_10_21_185724_add_invoice_number_pattern',1),('2015_10_27_180214_add_is_system_to_activities',1),('2015_10_29_133747_add_default_quote_terms',1),('2015_11_01_080417_encrypt_tokens',1),('2015_11_03_181318_improve_currency_localization',1),('2015_11_30_133206_add_email_designs',1),('2015_12_27_154513_add_reminder_settings',1),('2015_12_30_042035_add_client_view_css',1),('2016_01_04_175228_create_vendors_table',1),('2016_01_06_153144_add_invoice_font_support',1),('2016_01_17_155725_add_quote_to_invoice_option',1),('2016_01_18_195351_add_bank_accounts',1),('2016_01_24_112646_add_bank_subaccounts',1),('2016_01_27_173015_add_header_footer_option',1),('2016_02_01_135956_add_source_currency_to_expenses',1),('2016_02_25_152948_add_client_password',1),('2016_02_28_081424_add_custom_invoice_fields',1),('2016_03_14_066181_add_user_permissions',1),('2016_03_14_214710_add_support_three_decimal_taxes',1),('2016_03_22_168362_add_documents',1),('2016_03_23_215049_support_multiple_tax_rates',1),('2016_04_16_103943_enterprise_plan',1),('2016_04_18_174135_add_page_size',1),('2016_04_23_182223_payments_changes',1),('2016_05_16_102925_add_swap_currency_symbol_to_currency',1),('2016_05_18_085739_add_invoice_type_support',1),('2016_05_24_164847_wepay_ach',1),('2016_07_08_083802_support_new_pricing',1),('2016_07_13_083821_add_buy_now_buttons',1),('2016_08_10_184027_add_support_for_bots',1),('2016_09_05_150625_create_gateway_types',1),('2016_10_20_191150_add_expense_to_activities',1),('2016_11_03_113316_add_invoice_signature',1),('2016_11_03_161149_add_bluevine_fields',1),('2016_11_28_092904_add_task_projects',1),('2016_12_13_113955_add_pro_plan_discount',1),('2017_01_01_214241_add_inclusive_taxes',1),('2017_02_23_095934_add_custom_product_fields',1),('2017_03_16_085702_add_gateway_fee_location',1),('2017_04_16_101744_add_custom_contact_fields',1),('2017_04_30_174702_add_multiple_database_support',1),('2017_05_10_144928_add_oauth_to_lookups',1),('2017_05_16_101715_add_default_note_to_client',1),('2017_06_19_111515_update_dark_mode',1),('2017_07_18_124150_add_late_fees',1); /*!40000 ALTER TABLE `migrations` ENABLE KEYS */; UNLOCK TABLES; @@ -1816,7 +1823,7 @@ CREATE TABLE `payment_libraries` ( LOCK TABLES `payment_libraries` WRITE; /*!40000 ALTER TABLE `payment_libraries` DISABLE KEYS */; -INSERT INTO `payment_libraries` VALUES (1,'2017-07-17 14:14:37','2017-07-17 14:14:37','Omnipay',1),(2,'2017-07-17 14:14:37','2017-07-17 14:14:37','PHP-Payments [Deprecated]',1); +INSERT INTO `payment_libraries` VALUES (1,'2017-08-07 08:11:37','2017-08-07 08:11:37','Omnipay',1),(2,'2017-08-07 08:11:37','2017-08-07 08:11:37','PHP-Payments [Deprecated]',1); /*!40000 ALTER TABLE `payment_libraries` ENABLE KEYS */; UNLOCK TABLES; @@ -1926,7 +1933,7 @@ CREATE TABLE `payment_terms` ( LOCK TABLES `payment_terms` WRITE; /*!40000 ALTER TABLE `payment_terms` DISABLE KEYS */; -INSERT INTO `payment_terms` VALUES (1,7,'Net 7','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,1),(2,10,'Net 10','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,2),(3,14,'Net 14','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,3),(4,15,'Net 15','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,4),(5,30,'Net 30','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,5),(6,60,'Net 60','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,6),(7,90,'Net 90','2017-07-17 14:14:37','2017-07-17 14:14:37',NULL,0,0,7),(8,-1,'Net 0','2017-07-17 14:14:40','2017-07-17 14:14:40',NULL,0,0,0); +INSERT INTO `payment_terms` VALUES (1,7,'Net 7','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,1),(2,10,'Net 10','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,2),(3,14,'Net 14','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,3),(4,15,'Net 15','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,4),(5,30,'Net 30','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,5),(6,60,'Net 60','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,6),(7,90,'Net 90','2017-08-07 08:11:37','2017-08-07 08:11:37',NULL,0,0,7),(8,-1,'Net 0','2017-08-07 08:11:41','2017-08-07 08:11:41',NULL,0,0,0); /*!40000 ALTER TABLE `payment_terms` ENABLE KEYS */; UNLOCK TABLES; @@ -2584,4 +2591,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2017-07-17 20:14:41 +-- Dump completed on 2017-08-07 14:11:41 diff --git a/docs/conf.py b/docs/conf.py index 95dbd732516b..e10a986998d4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -57,9 +57,9 @@ author = u'Invoice Ninja' # built documents. # # The short X.Y version. -version = u'3.5' +version = u'3.6' # The full version, including alpha/beta/rc tags. -release = u'3.5.1' +release = u'3.6.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/configure.rst b/docs/configure.rst index 4572de556586..c36d1d851859 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -67,6 +67,8 @@ Troubleshooting - We suggest using PhantomJS version >= 2.1.1, users have reported seeing 'Error: 0' with older versions. - You can use `this script `_ to test from the command line, change ``__YOUR_LINK_HERE__`` to a 'View as recipient' link. - If you require contacts to enter a password to see their invoice you'll need to set a random value for ``PHANTOMJS_SECRET``. +- If you're using a proxy and/or self-signed certificate `this comment `_ may help. +- If you're using a custom design try using a standard one, if the PDF is outside the printable area it can fail. Custom Fonts """""""""""" diff --git a/gulpfile.js b/gulpfile.js index c79457f6927b..e3f133634544 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -86,8 +86,7 @@ elixir(function(mix) { mix.scripts([ 'pdf_viewer.js', 'compatibility.js', - //bowerDir + '/pdfmake/build/pdfmake.js', - 'pdfmake.js', + bowerDir + '/pdfmake/build/pdfmake.js', 'vfs.js' ], 'public/pdf.built.js'); diff --git a/public/built.js b/public/built.js index bb1e257fe51a..8849fdffcad7 100644 --- a/public/built.js +++ b/public/built.js @@ -1,27 +1,27 @@ -function generatePDF(t,e,n,i){if(t&&e){if(!n)return refreshTimer&&clearTimeout(refreshTimer),void(refreshTimer=setTimeout(function(){generatePDF(t,e,!0,i)},500));refreshTimer=null,t=calculateAmounts(t);var o=GetPdfMake(t,e,i);return i&&o.getDataUrl(i),o}}function copyObject(t){return!!t&&JSON.parse(JSON.stringify(t))}function processVariables(t){if(!t)return"";for(var e=["MONTH","QUARTER","YEAR"],n=0;n1?c=r.split("+")[1]:r.split("-").length>1&&(c=parseInt(r.split("-")[1])*-1),t=t.replace(r,getDatePart(i,c))}}return t}function getDatePart(t,e){return e=parseInt(e),e||(e=0),"MONTH"==t?getMonth(e):"QUARTER"==t?getQuarter(e):"YEAR"==t?getYear(e):void 0}function getMonth(t){var e=new Date,n=["January","February","March","April","May","June","July","August","September","October","November","December"],i=e.getMonth();return i=parseInt(i)+t,i%=12,i<0&&(i+=12),n[i]}function getYear(t){var e=new Date,n=e.getFullYear();return parseInt(n)+t}function getQuarter(t){var e=new Date,n=Math.floor((e.getMonth()+3)/3);return n+=t,n%=4,0==n&&(n=4),"Q"+n}function isStorageSupported(){try{return"localStorage"in window&&null!==window.localStorage}catch(t){return!1}}function isValidEmailAddress(t){var e=new RegExp(/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i);return e.test(t)}function enableHoverClick(t,e,n){}function setAsLink(t,e){e?(t.css("text-decoration","underline"),t.css("cursor","pointer")):(t.css("text-decoration","none"),t.css("cursor","text"))}function setComboboxValue(t,e,n){t.find("input").val(e),t.find("input.form-control").val(n),e&&n?(t.find("select").combobox("setSelected"),t.find(".combobox-container").addClass("combobox-selected")):t.find(".combobox-container").removeClass("combobox-selected")}function convertDataURIToBinary(t){var e=t.indexOf(BASE64_MARKER)+BASE64_MARKER.length,n=t.substring(e);return base64DecToArr(n)}function comboboxHighlighter(t){var e=this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"),n=t.replace(new RegExp("
    ","g"),"\n");return n=stripHtmlTags(n),n=n.replace(new RegExp("("+e+")","ig"),function(t,n){return n?""+n+"":e}),n.replace(new RegExp("\n","g"),"
    ")}function comboboxMatcher(t){return~stripHtmlTags(t).toLowerCase().indexOf(this.query.toLowerCase())}function stripHtmlTags(t){var e=document.createElement("div");return e.innerHTML=t,e.textContent||e.innerText||""}function getContactDisplayName(t){return t.first_name||t.last_name?$.trim((t.first_name||"")+" "+(t.last_name||"")):t.email}function getContactDisplayNameWithEmail(t){var e="";return(t.first_name||t.last_name)&&(e+=$.trim((t.first_name||"")+" "+(t.last_name||""))),t.email&&(e&&(e+=" - "),e+=t.email),$.trim(e)}function getClientDisplayName(t){var e=!!t.contacts&&t.contacts[0];return t.name?t.name:e?getContactDisplayName(e):""}function populateInvoiceComboboxes(t,e){for(var n={},i={},o={},a=$("select#client"),s=0;s1?t+=", ":n64&&t<91?t-65:t>96&&t<123?t-71:t>47&&t<58?t+4:43===t?62:47===t?63:0}function base64DecToArr(t,e){for(var n,i,o=t.replace(/[^A-Za-z0-9\+\/]/g,""),a=o.length,s=e?Math.ceil((3*a+1>>2)/e)*e:3*a+1>>2,r=new Uint8Array(s),c=0,l=0,u=0;u>>(16>>>n&24)&255;c=0}return r}function uint6ToB64(t){return t<26?t+65:t<52?t+71:t<62?t-4:62===t?43:63===t?47:65}function base64EncArr(t){for(var e=2,n="",i=t.length,o=0,a=0;a0&&4*a/3%76===0&&(n+="\r\n"),o|=t[a]<<(16>>>e&24),2!==e&&t.length-a!==1||(n+=String.fromCharCode(uint6ToB64(o>>>18&63),uint6ToB64(o>>>12&63),uint6ToB64(o>>>6&63),uint6ToB64(63&o)),o=0);return n.substr(0,n.length-2+e)+(2===e?"":1===e?"=":"==")}function UTF8ArrToStr(t){for(var e,n="",i=t.length,o=0;o251&&e<254&&o+5247&&e<252&&o+4239&&e<248&&o+3223&&e<240&&o+2191&&e<224&&o+1>>6),e[s++]=128+(63&n)):n<65536?(e[s++]=224+(n>>>12),e[s++]=128+(n>>>6&63),e[s++]=128+(63&n)):n<2097152?(e[s++]=240+(n>>>18),e[s++]=128+(n>>>12&63),e[s++]=128+(n>>>6&63),e[s++]=128+(63&n)):n<67108864?(e[s++]=248+(n>>>24),e[s++]=128+(n>>>18&63),e[s++]=128+(n>>>12&63),e[s++]=128+(n>>>6&63),e[s++]=128+(63&n)):(e[s++]=252+n/1073741824,e[s++]=128+(n>>>24&63),e[s++]=128+(n>>>18&63),e[s++]=128+(n>>>12&63),e[s++]=128+(n>>>6&63),e[s++]=128+(63&n));return e}function hexToR(t){return parseInt(cutHex(t).substring(0,2),16)}function hexToG(t){return parseInt(cutHex(t).substring(2,4),16)}function hexToB(t){return parseInt(cutHex(t).substring(4,6),16)}function cutHex(t){return"#"==t.charAt(0)?t.substring(1,7):t}function setDocHexColor(t,e){var n=hexToR(e),i=hexToG(e),o=hexToB(e);return t.setTextColor(n,i,o)}function setDocHexFill(t,e){var n=hexToR(e),i=hexToG(e),o=hexToB(e);return t.setFillColor(n,i,o)}function setDocHexDraw(t,e){var n=hexToR(e),i=hexToG(e),o=hexToB(e);return t.setDrawColor(n,i,o)}function toggleDatePicker(t){$("#"+t).datepicker("show")}function roundToTwo(t,e){var n=+(Math.round(t+"e+2")+"e-2");return e?n.toFixed(2):n||0}function roundToFour(t,e){var n=+(Math.round(t+"e+4")+"e-4");return e?n.toFixed(4):n||0}function truncate(t,e){return t&&t.length>e?t.substr(0,e-1)+"...":t}function endsWith(t,e){return t.indexOf(e,t.length-e.length)!==-1}function secondsToTime(t){t=Math.round(t);var e=Math.floor(t/3600),n=t%3600,i=Math.floor(n/60),o=n%60,a=Math.ceil(o),s={h:e,m:i,s:a};return s}function twoDigits(t){return t<10?"0"+t:t}function toSnakeCase(t){return t?t.replace(/([A-Z])/g,function(t){return"_"+t.toLowerCase()}):""}function snakeToCamel(t){return t.replace(/_([a-z])/g,function(t){return t[1].toUpperCase()})}function getDescendantProp(t,e){for(var n=e.split(".");n.length&&(t=t[n.shift()]););return t}function doubleDollarSign(t){return t?t.replace?t.replace(/\$/g,"$$$"):t:""}function truncate(t,e){return t.length>e?t.substring(0,e)+"...":t}function actionListHandler(){$("tbody tr .tr-action").closest("tr").mouseover(function(){$(this).closest("tr").find(".tr-action").show(),$(this).closest("tr").find(".tr-status").hide()}).mouseout(function(){$dropdown=$(this).closest("tr").find(".tr-action"),$dropdown.hasClass("open")||($dropdown.hide(),$(this).closest("tr").find(".tr-status").show())})}function loadImages(t){$(t+" img").each(function(t,e){var n=$(e).attr("data-src");$(e).attr("src",n),$(e).attr("data-src",n)})}function prettyJson(t){return"string"!=typeof t&&(t=JSON.stringify(t,void 0,2)),t=t.replace(/&/g,"&").replace(//g,">"),t.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,function(t){var e="number";return/^"/.test(t)?e=/:$/.test(t)?"key":"string":/true|false/.test(t)?e="boolean":/null/.test(t)&&(e="null"),t=snakeToCamel(t),''+t+""})}function searchData(t,e,n){return function(i,o){var a;if(n){var s={keys:[e]},r=new Fuse(t,s);a=r.search(i)}else a=[],substrRegex=new RegExp(escapeRegExp(i),"i"),$.each(t,function(t,n){substrRegex.test(n[e])&&a.push(n)});o(a)}}function escapeRegExp(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}function firstJSONError(t){for(var e in t)if(t.hasOwnProperty(e)){var n=t[e];for(var i in n)if(n.hasOwnProperty(i))return n[i]}return!1}function pad(t,e,n){return n=n||"0",t+="",t.length>=e?t:new Array(e-t.length+1).join(n)+t}function GetPdfMake(t,e,n){function i(e,n){if("string"==typeof n){if(0===n.indexOf("$firstAndLast")){var i=n.split(":");return function(t,e){return 0===t||t===e.table.body.length?parseFloat(i[1]):0}}if(0===n.indexOf("$none"))return function(t,e){return 0};if(0===n.indexOf("$notFirstAndLastColumn")){var i=n.split(":");return function(t,e){return 0===t||t===e.table.widths.length?0:parseFloat(i[1])}}if(0===n.indexOf("$notFirst")){var i=n.split(":");return function(t,e){return 0===t?0:parseFloat(i[1])}}if(0===n.indexOf("$amount")){var i=n.split(":");return function(t,e){return parseFloat(i[1])}}if(0===n.indexOf("$primaryColor")){var i=n.split(":");return NINJA.primaryColor||i[1]}if(0===n.indexOf("$secondaryColor")){var i=n.split(":");return NINJA.secondaryColor||i[1]}}if(t.features.customize_invoice_design){if("header"===e)return function(e,i){return 1===e||"1"==t.account.all_pages_header?t.features.remove_created_by?NINJA.updatePageCount(JSON.parse(JSON.stringify(n)),e,i):n:""};if("footer"===e)return function(e,i){return e===i||"1"==t.account.all_pages_footer?t.features.remove_created_by?NINJA.updatePageCount(JSON.parse(JSON.stringify(n)),e,i):n:""}}return"text"===e&&(n=NINJA.parseMarkdownText(n,!0)),n}function o(t){window.ninjaFontVfs[t.folder]&&(folder="fonts/"+t.folder,pdfMake.fonts[t.name]={normal:folder+"/"+t.normal,italics:folder+"/"+t.italics,bold:folder+"/"+t.bold,bolditalics:folder+"/"+t.bolditalics})}var a=!1;if(t.hasSecondTable){for(var s=JSON.parse(e),r=0;r0&&e-1 in t))}function i(t,e,n){if(ot.isFunction(e))return ot.grep(t,function(t,i){return!!e.call(t,i,t)!==n});if(e.nodeType)return ot.grep(t,function(t){return t===e!==n});if("string"==typeof e){if(dt.test(e))return ot.filter(e,t,n);e=ot.filter(e,t)}return ot.grep(t,function(t){return ot.inArray(t,e)>=0!==n})}function o(t,e){do t=t[e];while(t&&1!==t.nodeType);return t}function a(t){var e=yt[t]={};return ot.each(t.match(Mt)||[],function(t,n){e[n]=!0}),e}function s(){ft.addEventListener?(ft.removeEventListener("DOMContentLoaded",r,!1),t.removeEventListener("load",r,!1)):(ft.detachEvent("onreadystatechange",r),t.detachEvent("onload",r))}function r(){(ft.addEventListener||"load"===event.type||"complete"===ft.readyState)&&(s(),ot.ready())}function c(t,e,n){if(void 0===n&&1===t.nodeType){var i="data-"+e.replace(wt,"-$1").toLowerCase();if(n=t.getAttribute(i),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:Tt.test(n)?ot.parseJSON(n):n)}catch(o){}ot.data(t,e,n)}else n=void 0}return n}function l(t){var e;for(e in t)if(("data"!==e||!ot.isEmptyObject(t[e]))&&"toJSON"!==e)return!1;return!0}function u(t,e,n,i){if(ot.acceptData(t)){var o,a,s=ot.expando,r=t.nodeType,c=r?ot.cache:t,l=r?t[s]:t[s]&&s;if(l&&c[l]&&(i||c[l].data)||void 0!==n||"string"!=typeof e)return l||(l=r?t[s]=Y.pop()||ot.guid++:s),c[l]||(c[l]=r?{}:{toJSON:ot.noop}),"object"!=typeof e&&"function"!=typeof e||(i?c[l]=ot.extend(c[l],e):c[l].data=ot.extend(c[l].data,e)),a=c[l],i||(a.data||(a.data={}),a=a.data),void 0!==n&&(a[ot.camelCase(e)]=n),"string"==typeof e?(o=a[e],null==o&&(o=a[ot.camelCase(e)])):o=a,o}}function h(t,e,n){if(ot.acceptData(t)){var i,o,a=t.nodeType,s=a?ot.cache:t,r=a?t[ot.expando]:ot.expando;if(s[r]){if(e&&(i=n?s[r]:s[r].data)){ot.isArray(e)?e=e.concat(ot.map(e,ot.camelCase)):e in i?e=[e]:(e=ot.camelCase(e),e=e in i?[e]:e.split(" ")),o=e.length;for(;o--;)delete i[e[o]];if(n?!l(i):!ot.isEmptyObject(i))return}(n||(delete s[r].data,l(s[r])))&&(a?ot.cleanData([t],!0):nt.deleteExpando||s!=s.window?delete s[r]:s[r]=null)}}}function d(){return!0}function p(){return!1}function f(){try{return ft.activeElement}catch(t){}}function m(t){var e=Et.split("|"),n=t.createDocumentFragment();if(n.createElement)for(;e.length;)n.createElement(e.pop());return n}function g(t,e){var n,i,o=0,a=typeof t.getElementsByTagName!==_t?t.getElementsByTagName(e||"*"):typeof t.querySelectorAll!==_t?t.querySelectorAll(e||"*"):void 0;if(!a)for(a=[],n=t.childNodes||t;null!=(i=n[o]);o++)!e||ot.nodeName(i,e)?a.push(i):ot.merge(a,g(i,e));return void 0===e||e&&ot.nodeName(t,e)?ot.merge([t],a):a}function b(t){xt.test(t.type)&&(t.defaultChecked=t.checked)}function v(t,e){return ot.nodeName(t,"table")&&ot.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function M(t){return t.type=(null!==ot.find.attr(t,"type"))+"/"+t.type,t}function y(t){var e=Vt.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function A(t,e){for(var n,i=0;null!=(n=t[i]);i++)ot._data(n,"globalEval",!e||ot._data(e[i],"globalEval"))}function z(t,e){if(1===e.nodeType&&ot.hasData(t)){var n,i,o,a=ot._data(t),s=ot._data(e,a),r=a.events;if(r){delete s.handle,s.events={};for(n in r)for(i=0,o=r[n].length;i")).appendTo(e.documentElement),e=(Qt[0].contentWindow||Qt[0].contentDocument).document,e.write(),e.close(),n=T(t,e),Qt.detach()),Zt[t]=n),n}function C(t,e){return{get:function(){var n=t();if(null!=n)return n?void delete this.get:(this.get=e).apply(this,arguments)}}}function O(t,e){if(e in t)return e;for(var n=e.charAt(0).toUpperCase()+e.slice(1),i=e,o=de.length;o--;)if(e=de[o]+n,e in t)return e;return i}function N(t,e){for(var n,i,o,a=[],s=0,r=t.length;s=0&&n=0},isEmptyObject:function(t){var e;for(e in t)return!1;return!0},isPlainObject:function(t){var e;if(!t||"object"!==ot.type(t)||t.nodeType||ot.isWindow(t))return!1;try{if(t.constructor&&!et.call(t,"constructor")&&!et.call(t.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(nt.ownLast)for(e in t)return et.call(t,e);for(e in t);return void 0===e||et.call(t,e)},type:function(t){return null==t?t+"":"object"==typeof t||"function"==typeof t?Z[tt.call(t)]||"object":typeof t},globalEval:function(e){e&&ot.trim(e)&&(t.execScript||function(e){t.eval.call(t,e)})(e)},camelCase:function(t){return t.replace(st,"ms-").replace(rt,ct)},nodeName:function(t,e){return t.nodeName&&t.nodeName.toLowerCase()===e.toLowerCase()},each:function(t,e,i){var o,a=0,s=t.length,r=n(t);if(i){if(r)for(;az.cacheLength&&delete t[e.shift()],t[n+" "]=i}var e=[];return t}function i(t){return t[X]=!0,t}function o(t){var e=D.createElement("div");try{return!!t(e)}catch(n){return!1}finally{e.parentNode&&e.parentNode.removeChild(e),e=null}}function a(t,e){for(var n=t.split("|"),i=t.length;i--;)z.attrHandle[n[i]]=e}function s(t,e){var n=e&&t,i=n&&1===t.nodeType&&1===e.nodeType&&(~e.sourceIndex||V)-(~t.sourceIndex||V);if(i)return i;if(n)for(;n=n.nextSibling;)if(n===e)return-1;return t?1:-1}function r(t){return function(e){var n=e.nodeName.toLowerCase();return"input"===n&&e.type===t}}function c(t){return function(e){var n=e.nodeName.toLowerCase();return("input"===n||"button"===n)&&e.type===t}}function l(t){return i(function(e){return e=+e,i(function(n,i){for(var o,a=t([],n.length,e),s=a.length;s--;)n[o=a[s]]&&(n[o]=!(i[o]=n[o]))})})}function u(t){return t&&"undefined"!=typeof t.getElementsByTagName&&t}function h(){}function d(t){for(var e=0,n=t.length,i="";e1?function(e,n,i){for(var o=t.length;o--;)if(!t[o](e,n,i))return!1;return!0}:t[0]}function m(t,n,i){for(var o=0,a=n.length;o-1&&(i[l]=!(s[l]=h))}}else M=g(M===s?M.splice(f,M.length):M),a?a(null,s,M,c):Q.apply(s,M)})}function v(t){for(var e,n,i,o=t.length,a=z.relative[t[0].type],s=a||z.relative[" "],r=a?1:0,c=p(function(t){return t===e},s,!0),l=p(function(t){return tt(e,t)>-1},s,!0),u=[function(t,n,i){var o=!a&&(i||n!==N)||((e=n).nodeType?c(t,n,i):l(t,n,i));return e=null,o}];r1&&f(u),r>1&&d(t.slice(0,r-1).concat({value:" "===t[r-2].type?"*":""})).replace(ct,"$1"),n,r0,a=t.length>0,s=function(i,s,r,c,l){var u,h,d,p=0,f="0",m=i&&[],b=[],v=N,M=i||a&&z.find.TAG("*",l),y=R+=null==v?1:Math.random()||.1,A=M.length;for(l&&(N=s!==D&&s);f!==A&&null!=(u=M[f]);f++){if(a&&u){for(h=0;d=t[h++];)if(d(u,s,r)){c.push(u);break}l&&(R=y)}o&&((u=!d&&u)&&p--,i&&m.push(u))}if(p+=f,o&&f!==p){for(h=0;d=n[h++];)d(m,b,s,r);if(i){if(p>0)for(;f--;)m[f]||b[f]||(b[f]=K.call(c));b=g(b)}Q.apply(c,b),l&&!i&&b.length>0&&p+n.length>1&&e.uniqueSort(c)}return l&&(R=y,N=v),m};return o?i(s):s}var y,A,z,_,T,w,C,O,N,S,x,L,D,k,q,W,E,B,I,X="sizzle"+1*new Date,P=t.document,R=0,F=0,H=n(),j=n(),U=n(),$=function(t,e){return t===e&&(x=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],K=J.pop,G=J.push,Q=J.push,Z=J.slice,tt=function(t,e){for(var n=0,i=t.length;n+~]|"+nt+")"+nt+"*"),ht=new RegExp("="+nt+"*([^\\]'\"]*?)"+nt+"*\\]","g"),dt=new RegExp(st),pt=new RegExp("^"+ot+"$"),ft={ID:new RegExp("^#("+it+")"),CLASS:new RegExp("^\\.("+it+")"),TAG:new RegExp("^("+it.replace("w","w*")+")"),ATTR:new RegExp("^"+at),PSEUDO:new RegExp("^"+st),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+nt+"*(even|odd|(([+-]|)(\\d*)n|)"+nt+"*(?:([+-]|)"+nt+"*(\\d+)|))"+nt+"*\\)|)","i"),bool:new RegExp("^(?:"+et+")$","i"),needsContext:new RegExp("^"+nt+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+nt+"*((?:-\\d)?\\d*)"+nt+"*\\)|)(?=[^-]|$)","i")},mt=/^(?:input|select|textarea|button)$/i,gt=/^h\d$/i,bt=/^[^{]+\{\s*\[native \w/,vt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Mt=/[+~]/,yt=/'|\\/g,At=new RegExp("\\\\([\\da-f]{1,6}"+nt+"?|("+nt+")|.)","ig"),zt=function(t,e,n){var i="0x"+e-65536;return i!==i||n?e:i<0?String.fromCharCode(i+65536):String.fromCharCode(i>>10|55296,1023&i|56320)},_t=function(){L()};try{Q.apply(J=Z.call(P.childNodes),P.childNodes),J[P.childNodes.length].nodeType}catch(Tt){Q={apply:J.length?function(t,e){G.apply(t,Z.call(e))}:function(t,e){for(var n=t.length,i=0;t[n++]=e[i++];);t.length=n-1}}}A=e.support={},T=e.isXML=function(t){var e=t&&(t.ownerDocument||t).documentElement;return!!e&&"HTML"!==e.nodeName},L=e.setDocument=function(t){var e,n,i=t?t.ownerDocument||t:P;return i!==D&&9===i.nodeType&&i.documentElement?(D=i,k=i.documentElement,n=i.defaultView,n&&n!==n.top&&(n.addEventListener?n.addEventListener("unload",_t,!1):n.attachEvent&&n.attachEvent("onunload",_t)),q=!T(i),A.attributes=o(function(t){return t.className="i",!t.getAttribute("className")}),A.getElementsByTagName=o(function(t){return t.appendChild(i.createComment("")),!t.getElementsByTagName("*").length}),A.getElementsByClassName=bt.test(i.getElementsByClassName),A.getById=o(function(t){return k.appendChild(t).id=X,!i.getElementsByName||!i.getElementsByName(X).length}),A.getById?(z.find.ID=function(t,e){if("undefined"!=typeof e.getElementById&&q){var n=e.getElementById(t);return n&&n.parentNode?[n]:[]}},z.filter.ID=function(t){var e=t.replace(At,zt);return function(t){return t.getAttribute("id")===e}}):(delete z.find.ID,z.filter.ID=function(t){var e=t.replace(At,zt);return function(t){var n="undefined"!=typeof t.getAttributeNode&&t.getAttributeNode("id");return n&&n.value===e}}),z.find.TAG=A.getElementsByTagName?function(t,e){return"undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t):A.qsa?e.querySelectorAll(t):void 0}:function(t,e){var n,i=[],o=0,a=e.getElementsByTagName(t);if("*"===t){for(;n=a[o++];)1===n.nodeType&&i.push(n);return i}return a},z.find.CLASS=A.getElementsByClassName&&function(t,e){if(q)return e.getElementsByClassName(t)},E=[],W=[],(A.qsa=bt.test(i.querySelectorAll))&&(o(function(t){k.appendChild(t).innerHTML="",t.querySelectorAll("[msallowcapture^='']").length&&W.push("[*^$]="+nt+"*(?:''|\"\")"),t.querySelectorAll("[selected]").length||W.push("\\["+nt+"*(?:value|"+et+")"),t.querySelectorAll("[id~="+X+"-]").length||W.push("~="),t.querySelectorAll(":checked").length||W.push(":checked"),t.querySelectorAll("a#"+X+"+*").length||W.push(".#.+[+~]")}),o(function(t){var e=i.createElement("input");e.setAttribute("type","hidden"),t.appendChild(e).setAttribute("name","D"),t.querySelectorAll("[name=d]").length&&W.push("name"+nt+"*[*^$|!~]?="),t.querySelectorAll(":enabled").length||W.push(":enabled",":disabled"),t.querySelectorAll("*,:x"),W.push(",.*:")})),(A.matchesSelector=bt.test(B=k.matches||k.webkitMatchesSelector||k.mozMatchesSelector||k.oMatchesSelector||k.msMatchesSelector))&&o(function(t){A.disconnectedMatch=B.call(t,"div"),B.call(t,"[s!='']:x"),E.push("!=",st)}),W=W.length&&new RegExp(W.join("|")),E=E.length&&new RegExp(E.join("|")),e=bt.test(k.compareDocumentPosition),I=e||bt.test(k.contains)?function(t,e){var n=9===t.nodeType?t.documentElement:t,i=e&&e.parentNode;return t===i||!(!i||1!==i.nodeType||!(n.contains?n.contains(i):t.compareDocumentPosition&&16&t.compareDocumentPosition(i)))}:function(t,e){if(e)for(;e=e.parentNode;)if(e===t)return!0;return!1},$=e?function(t,e){if(t===e)return x=!0,0;var n=!t.compareDocumentPosition-!e.compareDocumentPosition;return n?n:(n=(t.ownerDocument||t)===(e.ownerDocument||e)?t.compareDocumentPosition(e):1,1&n||!A.sortDetached&&e.compareDocumentPosition(t)===n?t===i||t.ownerDocument===P&&I(P,t)?-1:e===i||e.ownerDocument===P&&I(P,e)?1:S?tt(S,t)-tt(S,e):0:4&n?-1:1)}:function(t,e){if(t===e)return x=!0,0;var n,o=0,a=t.parentNode,r=e.parentNode,c=[t],l=[e];if(!a||!r)return t===i?-1:e===i?1:a?-1:r?1:S?tt(S,t)-tt(S,e):0;if(a===r)return s(t,e);for(n=t;n=n.parentNode;)c.unshift(n);for(n=e;n=n.parentNode;)l.unshift(n);for(;c[o]===l[o];)o++;return o?s(c[o],l[o]):c[o]===P?-1:l[o]===P?1:0},i):D},e.matches=function(t,n){return e(t,null,null,n)},e.matchesSelector=function(t,n){if((t.ownerDocument||t)!==D&&L(t),n=n.replace(ht,"='$1']"),A.matchesSelector&&q&&(!E||!E.test(n))&&(!W||!W.test(n)))try{var i=B.call(t,n);if(i||A.disconnectedMatch||t.document&&11!==t.document.nodeType)return i}catch(o){}return e(n,D,null,[t]).length>0},e.contains=function(t,e){return(t.ownerDocument||t)!==D&&L(t),I(t,e)},e.attr=function(t,e){(t.ownerDocument||t)!==D&&L(t);var n=z.attrHandle[e.toLowerCase()],i=n&&Y.call(z.attrHandle,e.toLowerCase())?n(t,e,!q):void 0;return void 0!==i?i:A.attributes||!q?t.getAttribute(e):(i=t.getAttributeNode(e))&&i.specified?i.value:null},e.error=function(t){throw new Error("Syntax error, unrecognized expression: "+t)},e.uniqueSort=function(t){var e,n=[],i=0,o=0;if(x=!A.detectDuplicates,S=!A.sortStable&&t.slice(0),t.sort($),x){for(;e=t[o++];)e===t[o]&&(i=n.push(o));for(;i--;)t.splice(n[i],1)}return S=null,t},_=e.getText=function(t){var e,n="",i=0,o=t.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof t.textContent)return t.textContent;for(t=t.firstChild;t;t=t.nextSibling)n+=_(t)}else if(3===o||4===o)return t.nodeValue}else for(;e=t[i++];)n+=_(e);return n},z=e.selectors={cacheLength:50,createPseudo:i,match:ft,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(t){return t[1]=t[1].replace(At,zt),t[3]=(t[3]||t[4]||t[5]||"").replace(At,zt),"~="===t[2]&&(t[3]=" "+t[3]+" "),t.slice(0,4)},CHILD:function(t){return t[1]=t[1].toLowerCase(),"nth"===t[1].slice(0,3)?(t[3]||e.error(t[0]),t[4]=+(t[4]?t[5]+(t[6]||1):2*("even"===t[3]||"odd"===t[3])),t[5]=+(t[7]+t[8]||"odd"===t[3])):t[3]&&e.error(t[0]),t},PSEUDO:function(t){var e,n=!t[6]&&t[2];return ft.CHILD.test(t[0])?null:(t[3]?t[2]=t[4]||t[5]||"":n&&dt.test(n)&&(e=w(n,!0))&&(e=n.indexOf(")",n.length-e)-n.length)&&(t[0]=t[0].slice(0,e),t[2]=n.slice(0,e)),t.slice(0,3))}},filter:{TAG:function(t){var e=t.replace(At,zt).toLowerCase();return"*"===t?function(){return!0}:function(t){return t.nodeName&&t.nodeName.toLowerCase()===e}},CLASS:function(t){var e=H[t+" "];return e||(e=new RegExp("(^|"+nt+")"+t+"("+nt+"|$)"))&&H(t,function(t){return e.test("string"==typeof t.className&&t.className||"undefined"!=typeof t.getAttribute&&t.getAttribute("class")||"")})},ATTR:function(t,n,i){return function(o){var a=e.attr(o,t);return null==a?"!="===n:!n||(a+="","="===n?a===i:"!="===n?a!==i:"^="===n?i&&0===a.indexOf(i):"*="===n?i&&a.indexOf(i)>-1:"$="===n?i&&a.slice(-i.length)===i:"~="===n?(" "+a.replace(rt," ")+" ").indexOf(i)>-1:"|="===n&&(a===i||a.slice(0,i.length+1)===i+"-"))}},CHILD:function(t,e,n,i,o){var a="nth"!==t.slice(0,3),s="last"!==t.slice(-4),r="of-type"===e;return 1===i&&0===o?function(t){return!!t.parentNode}:function(e,n,c){var l,u,h,d,p,f,m=a!==s?"nextSibling":"previousSibling",g=e.parentNode,b=r&&e.nodeName.toLowerCase(),v=!c&&!r;if(g){if(a){for(;m;){for(h=e;h=h[m];)if(r?h.nodeName.toLowerCase()===b:1===h.nodeType)return!1;f=m="only"===t&&!f&&"nextSibling"}return!0}if(f=[s?g.firstChild:g.lastChild],s&&v){for(u=g[X]||(g[X]={}),l=u[t]||[],p=l[0]===R&&l[1],d=l[0]===R&&l[2],h=p&&g.childNodes[p];h=++p&&h&&h[m]||(d=p=0)||f.pop();)if(1===h.nodeType&&++d&&h===e){u[t]=[R,p,d];break}}else if(v&&(l=(e[X]||(e[X]={}))[t])&&l[0]===R)d=l[1];else for(;(h=++p&&h&&h[m]||(d=p=0)||f.pop())&&((r?h.nodeName.toLowerCase()!==b:1!==h.nodeType)||!++d||(v&&((h[X]||(h[X]={}))[t]=[R,d]),h!==e)););return d-=o,d===i||d%i===0&&d/i>=0}}},PSEUDO:function(t,n){var o,a=z.pseudos[t]||z.setFilters[t.toLowerCase()]||e.error("unsupported pseudo: "+t);return a[X]?a(n):a.length>1?(o=[t,t,"",n],z.setFilters.hasOwnProperty(t.toLowerCase())?i(function(t,e){for(var i,o=a(t,n),s=o.length;s--;)i=tt(t,o[s]),t[i]=!(e[i]=o[s])}):function(t){return a(t,0,o)}):a}},pseudos:{not:i(function(t){var e=[],n=[],o=C(t.replace(ct,"$1"));return o[X]?i(function(t,e,n,i){for(var a,s=o(t,null,i,[]),r=t.length;r--;)(a=s[r])&&(t[r]=!(e[r]=a))}):function(t,i,a){return e[0]=t,o(e,null,a,n),e[0]=null,!n.pop()}}),has:i(function(t){return function(n){return e(t,n).length>0}}),contains:i(function(t){return t=t.replace(At,zt),function(e){return(e.textContent||e.innerText||_(e)).indexOf(t)>-1}}),lang:i(function(t){return pt.test(t||"")||e.error("unsupported lang: "+t),t=t.replace(At,zt).toLowerCase(),function(e){var n;do if(n=q?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return n=n.toLowerCase(),n===t||0===n.indexOf(t+"-");while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var n=t.location&&t.location.hash;return n&&n.slice(1)===e.id},root:function(t){return t===k},focus:function(t){return t===D.activeElement&&(!D.hasFocus||D.hasFocus())&&!!(t.type||t.href||~t.tabIndex)},enabled:function(t){return t.disabled===!1},disabled:function(t){return t.disabled===!0},checked:function(t){var e=t.nodeName.toLowerCase();return"input"===e&&!!t.checked||"option"===e&&!!t.selected},selected:function(t){return t.parentNode&&t.parentNode.selectedIndex,t.selected===!0},empty:function(t){for(t=t.firstChild;t;t=t.nextSibling)if(t.nodeType<6)return!1;return!0},parent:function(t){return!z.pseudos.empty(t)},header:function(t){return gt.test(t.nodeName)},input:function(t){return mt.test(t.nodeName)},button:function(t){var e=t.nodeName.toLowerCase();return"input"===e&&"button"===t.type||"button"===e},text:function(t){var e;return"input"===t.nodeName.toLowerCase()&&"text"===t.type&&(null==(e=t.getAttribute("type"))||"text"===e.toLowerCase())},first:l(function(){return[0]}),last:l(function(t,e){return[e-1]}),eq:l(function(t,e,n){return[n<0?n+e:n]}),even:l(function(t,e){for(var n=0;n=0;)t.push(i);return t}),gt:l(function(t,e,n){for(var i=n<0?n+e:n;++i2&&"ID"===(s=a[0]).type&&A.getById&&9===e.nodeType&&q&&z.relative[a[1].type]){if(e=(z.find.ID(s.matches[0].replace(At,zt),e)||[])[0],!e)return n;l&&(e=e.parentNode),t=t.slice(a.shift().value.length)}for(o=ft.needsContext.test(t)?0:a.length;o--&&(s=a[o],!z.relative[r=s.type]);)if((c=z.find[r])&&(i=c(s.matches[0].replace(At,zt),Mt.test(a[0].type)&&u(e.parentNode)||e))){if(a.splice(o,1),t=i.length&&d(a),!t)return Q.apply(n,i),n;break}}return(l||C(t,h))(i,e,!q,n,Mt.test(t)&&u(e.parentNode)||e),n},A.sortStable=X.split("").sort($).join("")===X,A.detectDuplicates=!!x,L(),A.sortDetached=o(function(t){return 1&t.compareDocumentPosition(D.createElement("div"))}),o(function(t){return t.innerHTML="","#"===t.firstChild.getAttribute("href")})||a("type|href|height|width",function(t,e,n){if(!n)return t.getAttribute(e,"type"===e.toLowerCase()?1:2)}),A.attributes&&o(function(t){return t.innerHTML="",t.firstChild.setAttribute("value",""),""===t.firstChild.getAttribute("value")})||a("value",function(t,e,n){if(!n&&"input"===t.nodeName.toLowerCase())return t.defaultValue}),o(function(t){return null==t.getAttribute("disabled")})||a(et,function(t,e,n){var i;if(!n)return t[e]===!0?e.toLowerCase():(i=t.getAttributeNode(e))&&i.specified?i.value:null}),e}(t);ot.find=lt,ot.expr=lt.selectors,ot.expr[":"]=ot.expr.pseudos,ot.unique=lt.uniqueSort,ot.text=lt.getText,ot.isXMLDoc=lt.isXML,ot.contains=lt.contains;var ut=ot.expr.match.needsContext,ht=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,dt=/^.[^:#\[\.,]*$/;ot.filter=function(t,e,n){var i=e[0];return n&&(t=":not("+t+")"),1===e.length&&1===i.nodeType?ot.find.matchesSelector(i,t)?[i]:[]:ot.find.matches(t,ot.grep(e,function(t){return 1===t.nodeType}))},ot.fn.extend({find:function(t){var e,n=[],i=this,o=i.length;if("string"!=typeof t)return this.pushStack(ot(t).filter(function(){for(e=0;e1?ot.unique(n):n),n.selector=this.selector?this.selector+" "+t:t,n},filter:function(t){return this.pushStack(i(this,t||[],!1))},not:function(t){return this.pushStack(i(this,t||[],!0))},is:function(t){return!!i(this,"string"==typeof t&&ut.test(t)?ot(t):t||[],!1).length}});var pt,ft=t.document,mt=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,gt=ot.fn.init=function(t,e){var n,i;if(!t)return this;if("string"==typeof t){if(n="<"===t.charAt(0)&&">"===t.charAt(t.length-1)&&t.length>=3?[null,t,null]:mt.exec(t),!n||!n[1]&&e)return!e||e.jquery?(e||pt).find(t):this.constructor(e).find(t);if(n[1]){if(e=e instanceof ot?e[0]:e,ot.merge(this,ot.parseHTML(n[1],e&&e.nodeType?e.ownerDocument||e:ft,!0)),ht.test(n[1])&&ot.isPlainObject(e))for(n in e)ot.isFunction(this[n])?this[n](e[n]):this.attr(n,e[n]);return this}if(i=ft.getElementById(n[2]),i&&i.parentNode){if(i.id!==n[2])return pt.find(t);this.length=1,this[0]=i}return this.context=ft,this.selector=t,this}return t.nodeType?(this.context=this[0]=t,this.length=1,this):ot.isFunction(t)?"undefined"!=typeof pt.ready?pt.ready(t):t(ot):(void 0!==t.selector&&(this.selector=t.selector,this.context=t.context),ot.makeArray(t,this))};gt.prototype=ot.fn,pt=ot(ft);var bt=/^(?:parents|prev(?:Until|All))/,vt={children:!0,contents:!0,next:!0,prev:!0};ot.extend({dir:function(t,e,n){for(var i=[],o=t[e];o&&9!==o.nodeType&&(void 0===n||1!==o.nodeType||!ot(o).is(n));)1===o.nodeType&&i.push(o),o=o[e];return i},sibling:function(t,e){for(var n=[];t;t=t.nextSibling)1===t.nodeType&&t!==e&&n.push(t);return n}}),ot.fn.extend({has:function(t){var e,n=ot(t,this),i=n.length;return this.filter(function(){for(e=0;e-1:1===n.nodeType&&ot.find.matchesSelector(n,t))){a.push(n);break}return this.pushStack(a.length>1?ot.unique(a):a)},index:function(t){return t?"string"==typeof t?ot.inArray(this[0],ot(t)):ot.inArray(t.jquery?t[0]:t,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(t,e){return this.pushStack(ot.unique(ot.merge(this.get(),ot(t,e))))},addBack:function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}}),ot.each({parent:function(t){var e=t.parentNode;return e&&11!==e.nodeType?e:null},parents:function(t){return ot.dir(t,"parentNode")},parentsUntil:function(t,e,n){return ot.dir(t,"parentNode",n)},next:function(t){return o(t,"nextSibling")},prev:function(t){return o(t,"previousSibling")},nextAll:function(t){return ot.dir(t,"nextSibling")},prevAll:function(t){return ot.dir(t,"previousSibling")},nextUntil:function(t,e,n){return ot.dir(t,"nextSibling",n)},prevUntil:function(t,e,n){return ot.dir(t,"previousSibling",n)},siblings:function(t){return ot.sibling((t.parentNode||{}).firstChild,t)},children:function(t){return ot.sibling(t.firstChild)},contents:function(t){return ot.nodeName(t,"iframe")?t.contentDocument||t.contentWindow.document:ot.merge([],t.childNodes)}},function(t,e){ot.fn[t]=function(n,i){var o=ot.map(this,e,n);return"Until"!==t.slice(-5)&&(i=n),i&&"string"==typeof i&&(o=ot.filter(i,o)),this.length>1&&(vt[t]||(o=ot.unique(o)),bt.test(t)&&(o=o.reverse())),this.pushStack(o)}});var Mt=/\S+/g,yt={};ot.Callbacks=function(t){t="string"==typeof t?yt[t]||a(t):ot.extend({},t);var e,n,i,o,s,r,c=[],l=!t.once&&[],u=function(a){for(n=t.memory&&a,i=!0,s=r||0,r=0,o=c.length,e=!0;c&&s-1;)c.splice(i,1),e&&(i<=o&&o--,i<=s&&s--)}),this},has:function(t){return t?ot.inArray(t,c)>-1:!(!c||!c.length)},empty:function(){return c=[],o=0,this},disable:function(){return c=l=n=void 0,this},disabled:function(){return!c},lock:function(){return l=void 0,n||h.disable(),this},locked:function(){return!l},fireWith:function(t,n){return!c||i&&!l||(n=n||[],n=[t,n.slice?n.slice():n],e?l.push(n):u(n)),this},fire:function(){return h.fireWith(this,arguments),this},fired:function(){return!!i}};return h},ot.extend({Deferred:function(t){var e=[["resolve","done",ot.Callbacks("once memory"),"resolved"],["reject","fail",ot.Callbacks("once memory"),"rejected"],["notify","progress",ot.Callbacks("memory")]],n="pending",i={state:function(){return n},always:function(){return o.done(arguments).fail(arguments),this},then:function(){var t=arguments;return ot.Deferred(function(n){ot.each(e,function(e,a){var s=ot.isFunction(t[e])&&t[e];o[a[1]](function(){var t=s&&s.apply(this,arguments);t&&ot.isFunction(t.promise)?t.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a[0]+"With"](this===i?n.promise():this,s?[t]:arguments)})}),t=null}).promise()},promise:function(t){return null!=t?ot.extend(t,i):i}},o={};return i.pipe=i.then,ot.each(e,function(t,a){var s=a[2],r=a[3];i[a[1]]=s.add,r&&s.add(function(){n=r},e[1^t][2].disable,e[2][2].lock),o[a[0]]=function(){return o[a[0]+"With"](this===o?i:this,arguments),this},o[a[0]+"With"]=s.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(t){var e,n,i,o=0,a=J.call(arguments),s=a.length,r=1!==s||t&&ot.isFunction(t.promise)?s:0,c=1===r?t:ot.Deferred(),l=function(t,n,i){return function(o){n[t]=this,i[t]=arguments.length>1?J.call(arguments):o,i===e?c.notifyWith(n,i):--r||c.resolveWith(n,i)}};if(s>1)for(e=new Array(s),n=new Array(s),i=new Array(s);o0||(At.resolveWith(ft,[ot]),ot.fn.triggerHandler&&(ot(ft).triggerHandler("ready"),ot(ft).off("ready")))}}}),ot.ready.promise=function(e){if(!At)if(At=ot.Deferred(),"complete"===ft.readyState)setTimeout(ot.ready);else if(ft.addEventListener)ft.addEventListener("DOMContentLoaded",r,!1),t.addEventListener("load",r,!1);else{ft.attachEvent("onreadystatechange",r),t.attachEvent("onload",r);var n=!1;try{n=null==t.frameElement&&ft.documentElement}catch(i){}n&&n.doScroll&&!function o(){if(!ot.isReady){try{n.doScroll("left")}catch(t){return setTimeout(o,50)}s(),ot.ready()}}()}return At.promise(e)};var zt,_t="undefined";for(zt in ot(nt))break;nt.ownLast="0"!==zt,nt.inlineBlockNeedsLayout=!1,ot(function(){var t,e,n,i;n=ft.getElementsByTagName("body")[0],n&&n.style&&(e=ft.createElement("div"),i=ft.createElement("div"),i.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(i).appendChild(e),typeof e.style.zoom!==_t&&(e.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",nt.inlineBlockNeedsLayout=t=3===e.offsetWidth,t&&(n.style.zoom=1)),n.removeChild(i))}),function(){var t=ft.createElement("div");if(null==nt.deleteExpando){nt.deleteExpando=!0;try{delete t.test}catch(e){nt.deleteExpando=!1}}t=null}(),ot.acceptData=function(t){var e=ot.noData[(t.nodeName+" ").toLowerCase()],n=+t.nodeType||1;return(1===n||9===n)&&(!e||e!==!0&&t.getAttribute("classid")===e)};var Tt=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,wt=/([A-Z])/g;ot.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(t){return t=t.nodeType?ot.cache[t[ot.expando]]:t[ot.expando],!!t&&!l(t)},data:function(t,e,n){return u(t,e,n)},removeData:function(t,e){return h(t,e)},_data:function(t,e,n){return u(t,e,n,!0)},_removeData:function(t,e){return h(t,e,!0)}}),ot.fn.extend({data:function(t,e){var n,i,o,a=this[0],s=a&&a.attributes;if(void 0===t){if(this.length&&(o=ot.data(a),1===a.nodeType&&!ot._data(a,"parsedAttrs"))){for(n=s.length;n--;)s[n]&&(i=s[n].name,0===i.indexOf("data-")&&(i=ot.camelCase(i.slice(5)),c(a,i,o[i])));ot._data(a,"parsedAttrs",!0)}return o}return"object"==typeof t?this.each(function(){ot.data(this,t)}):arguments.length>1?this.each(function(){ot.data(this,t,e)}):a?c(a,t,ot.data(a,t)):void 0},removeData:function(t){return this.each(function(){ot.removeData(this,t)})}}),ot.extend({queue:function(t,e,n){var i;if(t)return e=(e||"fx")+"queue",i=ot._data(t,e),n&&(!i||ot.isArray(n)?i=ot._data(t,e,ot.makeArray(n)):i.push(n)),i||[]},dequeue:function(t,e){e=e||"fx";var n=ot.queue(t,e),i=n.length,o=n.shift(),a=ot._queueHooks(t,e),s=function(){ot.dequeue(t,e)};"inprogress"===o&&(o=n.shift(),i--),o&&("fx"===e&&n.unshift("inprogress"),delete a.stop,o.call(t,s,a)),!i&&a&&a.empty.fire()},_queueHooks:function(t,e){var n=e+"queueHooks";return ot._data(t,n)||ot._data(t,n,{empty:ot.Callbacks("once memory").add(function(){ot._removeData(t,e+"queue"),ot._removeData(t,n)})})}}),ot.fn.extend({queue:function(t,e){var n=2;return"string"!=typeof t&&(e=t,t="fx",n--),arguments.length
    a",nt.leadingWhitespace=3===e.firstChild.nodeType,nt.tbody=!e.getElementsByTagName("tbody").length,nt.htmlSerialize=!!e.getElementsByTagName("link").length,nt.html5Clone="<:nav>"!==ft.createElement("nav").cloneNode(!0).outerHTML,t.type="checkbox",t.checked=!0,n.appendChild(t),nt.appendChecked=t.checked,e.innerHTML="",nt.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,n.appendChild(e),e.innerHTML="",nt.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,nt.noCloneEvent=!0,e.attachEvent&&(e.attachEvent("onclick",function(){nt.noCloneEvent=!1}),e.cloneNode(!0).click()),null==nt.deleteExpando){nt.deleteExpando=!0;try{delete e.test}catch(i){nt.deleteExpando=!1}}}(),function(){var e,n,i=ft.createElement("div");for(e in{submit:!0,change:!0,focusin:!0})n="on"+e,(nt[e+"Bubbles"]=n in t)||(i.setAttribute(n,"t"),nt[e+"Bubbles"]=i.attributes[n].expando===!1);i=null}();var Lt=/^(?:input|select|textarea)$/i,Dt=/^key/,kt=/^(?:mouse|pointer|contextmenu)|click/,qt=/^(?:focusinfocus|focusoutblur)$/,Wt=/^([^.]*)(?:\.(.+)|)$/;ot.event={global:{},add:function(t,e,n,i,o){var a,s,r,c,l,u,h,d,p,f,m,g=ot._data(t);if(g){for(n.handler&&(c=n,n=c.handler,o=c.selector),n.guid||(n.guid=ot.guid++),(s=g.events)||(s=g.events={}),(u=g.handle)||(u=g.handle=function(t){return typeof ot===_t||t&&ot.event.triggered===t.type?void 0:ot.event.dispatch.apply(u.elem,arguments)},u.elem=t),e=(e||"").match(Mt)||[""],r=e.length;r--;)a=Wt.exec(e[r])||[],p=m=a[1],f=(a[2]||"").split(".").sort(),p&&(l=ot.event.special[p]||{},p=(o?l.delegateType:l.bindType)||p,l=ot.event.special[p]||{},h=ot.extend({type:p,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&ot.expr.match.needsContext.test(o),namespace:f.join(".")},c),(d=s[p])||(d=s[p]=[],d.delegateCount=0,l.setup&&l.setup.call(t,i,f,u)!==!1||(t.addEventListener?t.addEventListener(p,u,!1):t.attachEvent&&t.attachEvent("on"+p,u))),l.add&&(l.add.call(t,h),h.handler.guid||(h.handler.guid=n.guid)),o?d.splice(d.delegateCount++,0,h):d.push(h),ot.event.global[p]=!0);t=null}},remove:function(t,e,n,i,o){var a,s,r,c,l,u,h,d,p,f,m,g=ot.hasData(t)&&ot._data(t);if(g&&(u=g.events)){for(e=(e||"").match(Mt)||[""],l=e.length;l--;)if(r=Wt.exec(e[l])||[],p=m=r[1],f=(r[2]||"").split(".").sort(),p){for(h=ot.event.special[p]||{},p=(i?h.delegateType:h.bindType)||p,d=u[p]||[],r=r[2]&&new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"),c=a=d.length;a--;)s=d[a],!o&&m!==s.origType||n&&n.guid!==s.guid||r&&!r.test(s.namespace)||i&&i!==s.selector&&("**"!==i||!s.selector)||(d.splice(a,1), -s.selector&&d.delegateCount--,h.remove&&h.remove.call(t,s));c&&!d.length&&(h.teardown&&h.teardown.call(t,f,g.handle)!==!1||ot.removeEvent(t,p,g.handle),delete u[p])}else for(p in u)ot.event.remove(t,p+e[l],n,i,!0);ot.isEmptyObject(u)&&(delete g.handle,ot._removeData(t,"events"))}},trigger:function(e,n,i,o){var a,s,r,c,l,u,h,d=[i||ft],p=et.call(e,"type")?e.type:e,f=et.call(e,"namespace")?e.namespace.split("."):[];if(r=u=i=i||ft,3!==i.nodeType&&8!==i.nodeType&&!qt.test(p+ot.event.triggered)&&(p.indexOf(".")>=0&&(f=p.split("."),p=f.shift(),f.sort()),s=p.indexOf(":")<0&&"on"+p,e=e[ot.expando]?e:new ot.Event(p,"object"==typeof e&&e),e.isTrigger=o?2:3,e.namespace=f.join("."),e.namespace_re=e.namespace?new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=i),n=null==n?[e]:ot.makeArray(n,[e]),l=ot.event.special[p]||{},o||!l.trigger||l.trigger.apply(i,n)!==!1)){if(!o&&!l.noBubble&&!ot.isWindow(i)){for(c=l.delegateType||p,qt.test(c+p)||(r=r.parentNode);r;r=r.parentNode)d.push(r),u=r;u===(i.ownerDocument||ft)&&d.push(u.defaultView||u.parentWindow||t)}for(h=0;(r=d[h++])&&!e.isPropagationStopped();)e.type=h>1?c:l.bindType||p,a=(ot._data(r,"events")||{})[e.type]&&ot._data(r,"handle"),a&&a.apply(r,n),a=s&&r[s],a&&a.apply&&ot.acceptData(r)&&(e.result=a.apply(r,n),e.result===!1&&e.preventDefault());if(e.type=p,!o&&!e.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&ot.acceptData(i)&&s&&i[p]&&!ot.isWindow(i)){u=i[s],u&&(i[s]=null),ot.event.triggered=p;try{i[p]()}catch(m){}ot.event.triggered=void 0,u&&(i[s]=u)}return e.result}},dispatch:function(t){t=ot.event.fix(t);var e,n,i,o,a,s=[],r=J.call(arguments),c=(ot._data(this,"events")||{})[t.type]||[],l=ot.event.special[t.type]||{};if(r[0]=t,t.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,t)!==!1){for(s=ot.event.handlers.call(this,t,c),e=0;(o=s[e++])&&!t.isPropagationStopped();)for(t.currentTarget=o.elem,a=0;(i=o.handlers[a++])&&!t.isImmediatePropagationStopped();)t.namespace_re&&!t.namespace_re.test(i.namespace)||(t.handleObj=i,t.data=i.data,n=((ot.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,r),void 0!==n&&(t.result=n)===!1&&(t.preventDefault(),t.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,t),t.result}},handlers:function(t,e){var n,i,o,a,s=[],r=e.delegateCount,c=t.target;if(r&&c.nodeType&&(!t.button||"click"!==t.type))for(;c!=this;c=c.parentNode||this)if(1===c.nodeType&&(c.disabled!==!0||"click"!==t.type)){for(o=[],a=0;a=0:ot.find(n,this,null,[c]).length),o[n]&&o.push(i);o.length&&s.push({elem:c,handlers:o})}return r]","i"),Xt=/^\s+/,Pt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Rt=/<([\w:]+)/,Ft=/\s*$/g,Jt={option:[1,""],legend:[1,"
    ","
    "],area:[1,"",""],param:[1,"",""],thead:[1,"","
    "],tr:[2,"","
    "],col:[2,"","
    "],td:[3,"","
    "],_default:nt.htmlSerialize?[0,"",""]:[1,"X
    ","
    "]},Kt=m(ft),Gt=Kt.appendChild(ft.createElement("div"));Jt.optgroup=Jt.option,Jt.tbody=Jt.tfoot=Jt.colgroup=Jt.caption=Jt.thead,Jt.th=Jt.td,ot.extend({clone:function(t,e,n){var i,o,a,s,r,c=ot.contains(t.ownerDocument,t);if(nt.html5Clone||ot.isXMLDoc(t)||!It.test("<"+t.nodeName+">")?a=t.cloneNode(!0):(Gt.innerHTML=t.outerHTML,Gt.removeChild(a=Gt.firstChild)),!(nt.noCloneEvent&&nt.noCloneChecked||1!==t.nodeType&&11!==t.nodeType||ot.isXMLDoc(t)))for(i=g(a),r=g(t),s=0;null!=(o=r[s]);++s)i[s]&&_(o,i[s]);if(e)if(n)for(r=r||g(t),i=i||g(a),s=0;null!=(o=r[s]);s++)z(o,i[s]);else z(t,a);return i=g(a,"script"),i.length>0&&A(i,!c&&g(t,"script")),i=r=o=null,a},buildFragment:function(t,e,n,i){for(var o,a,s,r,c,l,u,h=t.length,d=m(e),p=[],f=0;f")+u[2],o=u[0];o--;)r=r.lastChild;if(!nt.leadingWhitespace&&Xt.test(a)&&p.push(e.createTextNode(Xt.exec(a)[0])),!nt.tbody)for(a="table"!==c||Ft.test(a)?""!==u[1]||Ft.test(a)?0:r:r.firstChild,o=a&&a.childNodes.length;o--;)ot.nodeName(l=a.childNodes[o],"tbody")&&!l.childNodes.length&&a.removeChild(l);for(ot.merge(p,r.childNodes),r.textContent="";r.firstChild;)r.removeChild(r.firstChild);r=d.lastChild}else p.push(e.createTextNode(a));for(r&&d.removeChild(r),nt.appendChecked||ot.grep(g(p,"input"),b),f=0;a=p[f++];)if((!i||ot.inArray(a,i)===-1)&&(s=ot.contains(a.ownerDocument,a),r=g(d.appendChild(a),"script"),s&&A(r),n))for(o=0;a=r[o++];)$t.test(a.type||"")&&n.push(a);return r=null,d},cleanData:function(t,e){for(var n,i,o,a,s=0,r=ot.expando,c=ot.cache,l=nt.deleteExpando,u=ot.event.special;null!=(n=t[s]);s++)if((e||ot.acceptData(n))&&(o=n[r],a=o&&c[o])){if(a.events)for(i in a.events)u[i]?ot.event.remove(n,i):ot.removeEvent(n,i,a.handle);c[o]&&(delete c[o],l?delete n[r]:typeof n.removeAttribute!==_t?n.removeAttribute(r):n[r]=null,Y.push(o))}}}),ot.fn.extend({text:function(t){return St(this,function(t){return void 0===t?ot.text(this):this.empty().append((this[0]&&this[0].ownerDocument||ft).createTextNode(t))},null,t,arguments.length)},append:function(){return this.domManip(arguments,function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=v(this,t);e.appendChild(t)}})},prepend:function(){return this.domManip(arguments,function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=v(this,t);e.insertBefore(t,e.firstChild)}})},before:function(){return this.domManip(arguments,function(t){this.parentNode&&this.parentNode.insertBefore(t,this)})},after:function(){return this.domManip(arguments,function(t){this.parentNode&&this.parentNode.insertBefore(t,this.nextSibling)})},remove:function(t,e){for(var n,i=t?ot.filter(t,this):this,o=0;null!=(n=i[o]);o++)e||1!==n.nodeType||ot.cleanData(g(n)),n.parentNode&&(e&&ot.contains(n.ownerDocument,n)&&A(g(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){for(var t,e=0;null!=(t=this[e]);e++){for(1===t.nodeType&&ot.cleanData(g(t,!1));t.firstChild;)t.removeChild(t.firstChild);t.options&&ot.nodeName(t,"select")&&(t.options.length=0)}return this},clone:function(t,e){return t=null!=t&&t,e=null==e?t:e,this.map(function(){return ot.clone(this,t,e)})},html:function(t){return St(this,function(t){var e=this[0]||{},n=0,i=this.length;if(void 0===t)return 1===e.nodeType?e.innerHTML.replace(Bt,""):void 0;if("string"==typeof t&&!jt.test(t)&&(nt.htmlSerialize||!It.test(t))&&(nt.leadingWhitespace||!Xt.test(t))&&!Jt[(Rt.exec(t)||["",""])[1].toLowerCase()]){t=t.replace(Pt,"<$1>");try{for(;n1&&"string"==typeof d&&!nt.checkClone&&Ut.test(d))return this.each(function(n){var i=u.eq(n);p&&(t[0]=d.call(this,n,i.html())),i.domManip(t,e)});if(l&&(r=ot.buildFragment(t,this[0].ownerDocument,!1,this),n=r.firstChild,1===r.childNodes.length&&(r=n),n)){for(a=ot.map(g(r,"script"),M),o=a.length;c
    t
    ",o=e.getElementsByTagName("td"),o[0].style.cssText="margin:0;border:0;padding:0;display:none",r=0===o[0].offsetHeight,r&&(o[0].style.display="",o[1].style.display="none",r=0===o[0].offsetHeight),n.removeChild(i))}var n,i,o,a,s,r,c;n=ft.createElement("div"),n.innerHTML="
    a",o=n.getElementsByTagName("a")[0],i=o&&o.style,i&&(i.cssText="float:left;opacity:.5",nt.opacity="0.5"===i.opacity,nt.cssFloat=!!i.cssFloat,n.style.backgroundClip="content-box",n.cloneNode(!0).style.backgroundClip="",nt.clearCloneStyle="content-box"===n.style.backgroundClip,nt.boxSizing=""===i.boxSizing||""===i.MozBoxSizing||""===i.WebkitBoxSizing,ot.extend(nt,{reliableHiddenOffsets:function(){return null==r&&e(),r},boxSizingReliable:function(){return null==s&&e(),s},pixelPosition:function(){return null==a&&e(),a},reliableMarginRight:function(){return null==c&&e(),c}}))}(),ot.swap=function(t,e,n,i){var o,a,s={};for(a in e)s[a]=t.style[a],t.style[a]=e[a];o=n.apply(t,i||[]);for(a in e)t.style[a]=s[a];return o};var ae=/alpha\([^)]*\)/i,se=/opacity\s*=\s*([^)]*)/,re=/^(none|table(?!-c[ea]).+)/,ce=new RegExp("^("+Ct+")(.*)$","i"),le=new RegExp("^([+-])=("+Ct+")","i"),ue={position:"absolute",visibility:"hidden",display:"block"},he={letterSpacing:"0",fontWeight:"400"},de=["Webkit","O","Moz","ms"];ot.extend({cssHooks:{opacity:{get:function(t,e){if(e){var n=ee(t,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":nt.cssFloat?"cssFloat":"styleFloat"},style:function(t,e,n,i){if(t&&3!==t.nodeType&&8!==t.nodeType&&t.style){var o,a,s,r=ot.camelCase(e),c=t.style;if(e=ot.cssProps[r]||(ot.cssProps[r]=O(c,r)),s=ot.cssHooks[e]||ot.cssHooks[r],void 0===n)return s&&"get"in s&&void 0!==(o=s.get(t,!1,i))?o:c[e];if(a=typeof n,"string"===a&&(o=le.exec(n))&&(n=(o[1]+1)*o[2]+parseFloat(ot.css(t,e)),a="number"),null!=n&&n===n&&("number"!==a||ot.cssNumber[r]||(n+="px"),nt.clearCloneStyle||""!==n||0!==e.indexOf("background")||(c[e]="inherit"),!(s&&"set"in s&&void 0===(n=s.set(t,n,i)))))try{c[e]=n}catch(l){}}},css:function(t,e,n,i){var o,a,s,r=ot.camelCase(e);return e=ot.cssProps[r]||(ot.cssProps[r]=O(t.style,r)),s=ot.cssHooks[e]||ot.cssHooks[r],s&&"get"in s&&(a=s.get(t,!0,n)),void 0===a&&(a=ee(t,e,i)),"normal"===a&&e in he&&(a=he[e]),""===n||n?(o=parseFloat(a),n===!0||ot.isNumeric(o)?o||0:a):a}}),ot.each(["height","width"],function(t,e){ot.cssHooks[e]={get:function(t,n,i){if(n)return re.test(ot.css(t,"display"))&&0===t.offsetWidth?ot.swap(t,ue,function(){return L(t,e,i)}):L(t,e,i)},set:function(t,n,i){var o=i&&te(t);return S(t,n,i?x(t,e,i,nt.boxSizing&&"border-box"===ot.css(t,"boxSizing",!1,o),o):0)}}}),nt.opacity||(ot.cssHooks.opacity={get:function(t,e){return se.test((e&&t.currentStyle?t.currentStyle.filter:t.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":e?"1":""},set:function(t,e){var n=t.style,i=t.currentStyle,o=ot.isNumeric(e)?"alpha(opacity="+100*e+")":"",a=i&&i.filter||n.filter||"";n.zoom=1,(e>=1||""===e)&&""===ot.trim(a.replace(ae,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===e||i&&!i.filter)||(n.filter=ae.test(a)?a.replace(ae,o):a+" "+o)}}),ot.cssHooks.marginRight=C(nt.reliableMarginRight,function(t,e){if(e)return ot.swap(t,{display:"inline-block"},ee,[t,"marginRight"])}),ot.each({margin:"",padding:"",border:"Width"},function(t,e){ot.cssHooks[t+e]={expand:function(n){for(var i=0,o={},a="string"==typeof n?n.split(" "):[n];i<4;i++)o[t+Ot[i]+e]=a[i]||a[i-2]||a[0];return o}},ne.test(t)||(ot.cssHooks[t+e].set=S)}),ot.fn.extend({css:function(t,e){return St(this,function(t,e,n){var i,o,a={},s=0;if(ot.isArray(e)){for(i=te(t),o=e.length;s1)},show:function(){return N(this,!0)},hide:function(){return N(this)},toggle:function(t){return"boolean"==typeof t?t?this.show():this.hide():this.each(function(){Nt(this)?ot(this).show():ot(this).hide()})}}),ot.Tween=D,D.prototype={constructor:D,init:function(t,e,n,i,o,a){this.elem=t,this.prop=n,this.easing=o||"swing",this.options=e,this.start=this.now=this.cur(),this.end=i,this.unit=a||(ot.cssNumber[n]?"":"px")},cur:function(){var t=D.propHooks[this.prop];return t&&t.get?t.get(this):D.propHooks._default.get(this)},run:function(t){var e,n=D.propHooks[this.prop];return this.options.duration?this.pos=e=ot.easing[this.easing](t,this.options.duration*t,0,1,this.options.duration):this.pos=e=t,this.now=(this.end-this.start)*e+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):D.propHooks._default.set(this),this}},D.prototype.init.prototype=D.prototype,D.propHooks={_default:{get:function(t){var e;return null==t.elem[t.prop]||t.elem.style&&null!=t.elem.style[t.prop]?(e=ot.css(t.elem,t.prop,""),e&&"auto"!==e?e:0):t.elem[t.prop]},set:function(t){ot.fx.step[t.prop]?ot.fx.step[t.prop](t):t.elem.style&&(null!=t.elem.style[ot.cssProps[t.prop]]||ot.cssHooks[t.prop])?ot.style(t.elem,t.prop,t.now+t.unit):t.elem[t.prop]=t.now}}},D.propHooks.scrollTop=D.propHooks.scrollLeft={set:function(t){t.elem.nodeType&&t.elem.parentNode&&(t.elem[t.prop]=t.now)}},ot.easing={linear:function(t){return t},swing:function(t){return.5-Math.cos(t*Math.PI)/2}},ot.fx=D.prototype.init,ot.fx.step={};var pe,fe,me=/^(?:toggle|show|hide)$/,ge=new RegExp("^(?:([+-])=|)("+Ct+")([a-z%]*)$","i"),be=/queueHooks$/,ve=[E],Me={"*":[function(t,e){var n=this.createTween(t,e),i=n.cur(),o=ge.exec(e),a=o&&o[3]||(ot.cssNumber[t]?"":"px"),s=(ot.cssNumber[t]||"px"!==a&&+i)&&ge.exec(ot.css(n.elem,t)),r=1,c=20;if(s&&s[3]!==a){a=a||s[3],o=o||[],s=+i||1;do r=r||".5",s/=r,ot.style(n.elem,t,s+a);while(r!==(r=n.cur()/i)&&1!==r&&--c)}return o&&(s=n.start=+s||+i||0,n.unit=a,n.end=o[1]?s+(o[1]+1)*o[2]:+o[2]),n}]};ot.Animation=ot.extend(I,{tweener:function(t,e){ot.isFunction(t)?(e=t,t=["*"]):t=t.split(" ");for(var n,i=0,o=t.length;i
    a",i=e.getElementsByTagName("a")[0],n=ft.createElement("select"),o=n.appendChild(ft.createElement("option")),t=e.getElementsByTagName("input")[0],i.style.cssText="top:1px",nt.getSetAttribute="t"!==e.className,nt.style=/top/.test(i.getAttribute("style")),nt.hrefNormalized="/a"===i.getAttribute("href"),nt.checkOn=!!t.value,nt.optSelected=o.selected,nt.enctype=!!ft.createElement("form").enctype,n.disabled=!0,nt.optDisabled=!o.disabled,t=ft.createElement("input"),t.setAttribute("value",""),nt.input=""===t.getAttribute("value"),t.value="t",t.setAttribute("type","radio"),nt.radioValue="t"===t.value}();var ye=/\r/g;ot.fn.extend({val:function(t){var e,n,i,o=this[0];{if(arguments.length)return i=ot.isFunction(t),this.each(function(n){var o;1===this.nodeType&&(o=i?t.call(this,n,ot(this).val()):t,null==o?o="":"number"==typeof o?o+="":ot.isArray(o)&&(o=ot.map(o,function(t){return null==t?"":t+""})),e=ot.valHooks[this.type]||ot.valHooks[this.nodeName.toLowerCase()],e&&"set"in e&&void 0!==e.set(this,o,"value")||(this.value=o))});if(o)return e=ot.valHooks[o.type]||ot.valHooks[o.nodeName.toLowerCase()],e&&"get"in e&&void 0!==(n=e.get(o,"value"))?n:(n=o.value,"string"==typeof n?n.replace(ye,""):null==n?"":n)}}}),ot.extend({valHooks:{option:{get:function(t){var e=ot.find.attr(t,"value");return null!=e?e:ot.trim(ot.text(t))}},select:{get:function(t){for(var e,n,i=t.options,o=t.selectedIndex,a="select-one"===t.type||o<0,s=a?null:[],r=a?o+1:i.length,c=o<0?r:a?o:0;c=0)try{i.selected=n=!0}catch(r){i.scrollHeight}else i.selected=!1;return n||(t.selectedIndex=-1),o}}}}),ot.each(["radio","checkbox"],function(){ot.valHooks[this]={set:function(t,e){if(ot.isArray(e))return t.checked=ot.inArray(ot(t).val(),e)>=0}},nt.checkOn||(ot.valHooks[this].get=function(t){return null===t.getAttribute("value")?"on":t.value})});var Ae,ze,_e=ot.expr.attrHandle,Te=/^(?:checked|selected)$/i,we=nt.getSetAttribute,Ce=nt.input;ot.fn.extend({attr:function(t,e){return St(this,ot.attr,t,e,arguments.length>1)},removeAttr:function(t){return this.each(function(){ot.removeAttr(this,t)})}}),ot.extend({attr:function(t,e,n){var i,o,a=t.nodeType;if(t&&3!==a&&8!==a&&2!==a)return typeof t.getAttribute===_t?ot.prop(t,e,n):(1===a&&ot.isXMLDoc(t)||(e=e.toLowerCase(),i=ot.attrHooks[e]||(ot.expr.match.bool.test(e)?ze:Ae)),void 0===n?i&&"get"in i&&null!==(o=i.get(t,e))?o:(o=ot.find.attr(t,e),null==o?void 0:o):null!==n?i&&"set"in i&&void 0!==(o=i.set(t,n,e))?o:(t.setAttribute(e,n+""),n):void ot.removeAttr(t,e))},removeAttr:function(t,e){var n,i,o=0,a=e&&e.match(Mt);if(a&&1===t.nodeType)for(;n=a[o++];)i=ot.propFix[n]||n,ot.expr.match.bool.test(n)?Ce&&we||!Te.test(n)?t[i]=!1:t[ot.camelCase("default-"+n)]=t[i]=!1:ot.attr(t,n,""),t.removeAttribute(we?n:i)},attrHooks:{type:{set:function(t,e){if(!nt.radioValue&&"radio"===e&&ot.nodeName(t,"input")){var n=t.value;return t.setAttribute("type",e),n&&(t.value=n),e}}}}}),ze={set:function(t,e,n){return e===!1?ot.removeAttr(t,n):Ce&&we||!Te.test(n)?t.setAttribute(!we&&ot.propFix[n]||n,n):t[ot.camelCase("default-"+n)]=t[n]=!0,n}},ot.each(ot.expr.match.bool.source.match(/\w+/g),function(t,e){var n=_e[e]||ot.find.attr;_e[e]=Ce&&we||!Te.test(e)?function(t,e,i){var o,a;return i||(a=_e[e],_e[e]=o,o=null!=n(t,e,i)?e.toLowerCase():null,_e[e]=a),o}:function(t,e,n){if(!n)return t[ot.camelCase("default-"+e)]?e.toLowerCase():null}}),Ce&&we||(ot.attrHooks.value={set:function(t,e,n){return ot.nodeName(t,"input")?void(t.defaultValue=e):Ae&&Ae.set(t,e,n)}}),we||(Ae={set:function(t,e,n){var i=t.getAttributeNode(n);if(i||t.setAttributeNode(i=t.ownerDocument.createAttribute(n)),i.value=e+="","value"===n||e===t.getAttribute(n))return e}},_e.id=_e.name=_e.coords=function(t,e,n){var i;if(!n)return(i=t.getAttributeNode(e))&&""!==i.value?i.value:null},ot.valHooks.button={get:function(t,e){var n=t.getAttributeNode(e);if(n&&n.specified)return n.value},set:Ae.set},ot.attrHooks.contenteditable={set:function(t,e,n){Ae.set(t,""!==e&&e,n)}},ot.each(["width","height"],function(t,e){ot.attrHooks[e]={set:function(t,n){if(""===n)return t.setAttribute(e,"auto"),n}}})),nt.style||(ot.attrHooks.style={get:function(t){return t.style.cssText||void 0},set:function(t,e){return t.style.cssText=e+""}});var Oe=/^(?:input|select|textarea|button|object)$/i,Ne=/^(?:a|area)$/i;ot.fn.extend({prop:function(t,e){return St(this,ot.prop,t,e,arguments.length>1)},removeProp:function(t){return t=ot.propFix[t]||t,this.each(function(){try{this[t]=void 0,delete this[t]}catch(e){}})}}),ot.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(t,e,n){var i,o,a,s=t.nodeType;if(t&&3!==s&&8!==s&&2!==s)return a=1!==s||!ot.isXMLDoc(t),a&&(e=ot.propFix[e]||e,o=ot.propHooks[e]),void 0!==n?o&&"set"in o&&void 0!==(i=o.set(t,n,e))?i:t[e]=n:o&&"get"in o&&null!==(i=o.get(t,e))?i:t[e]},propHooks:{tabIndex:{get:function(t){var e=ot.find.attr(t,"tabindex");return e?parseInt(e,10):Oe.test(t.nodeName)||Ne.test(t.nodeName)&&t.href?0:-1; -}}}}),nt.hrefNormalized||ot.each(["href","src"],function(t,e){ot.propHooks[e]={get:function(t){return t.getAttribute(e,4)}}}),nt.optSelected||(ot.propHooks.selected={get:function(t){var e=t.parentNode;return e&&(e.selectedIndex,e.parentNode&&e.parentNode.selectedIndex),null}}),ot.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ot.propFix[this.toLowerCase()]=this}),nt.enctype||(ot.propFix.enctype="encoding");var Se=/[\t\r\n\f]/g;ot.fn.extend({addClass:function(t){var e,n,i,o,a,s,r=0,c=this.length,l="string"==typeof t&&t;if(ot.isFunction(t))return this.each(function(e){ot(this).addClass(t.call(this,e,this.className))});if(l)for(e=(t||"").match(Mt)||[];r=0;)i=i.replace(" "+o+" "," ");s=t?ot.trim(i):"",n.className!==s&&(n.className=s)}return this},toggleClass:function(t,e){var n=typeof t;return"boolean"==typeof e&&"string"===n?e?this.addClass(t):this.removeClass(t):ot.isFunction(t)?this.each(function(n){ot(this).toggleClass(t.call(this,n,this.className,e),e)}):this.each(function(){if("string"===n)for(var e,i=0,o=ot(this),a=t.match(Mt)||[];e=a[i++];)o.hasClass(e)?o.removeClass(e):o.addClass(e);else n!==_t&&"boolean"!==n||(this.className&&ot._data(this,"__className__",this.className),this.className=this.className||t===!1?"":ot._data(this,"__className__")||"")})},hasClass:function(t){for(var e=" "+t+" ",n=0,i=this.length;n=0)return!0;return!1}}),ot.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(t,e){ot.fn[e]=function(t,n){return arguments.length>0?this.on(e,null,t,n):this.trigger(e)}}),ot.fn.extend({hover:function(t,e){return this.mouseenter(t).mouseleave(e||t)},bind:function(t,e,n){return this.on(t,null,e,n)},unbind:function(t,e){return this.off(t,null,e)},delegate:function(t,e,n,i){return this.on(e,t,n,i)},undelegate:function(t,e,n){return 1===arguments.length?this.off(t,"**"):this.off(e,t||"**",n)}});var xe=ot.now(),Le=/\?/,De=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;ot.parseJSON=function(e){if(t.JSON&&t.JSON.parse)return t.JSON.parse(e+"");var n,i=null,o=ot.trim(e+"");return o&&!ot.trim(o.replace(De,function(t,e,o,a){return n&&e&&(i=0),0===i?t:(n=o||e,i+=!a-!o,"")}))?Function("return "+o)():ot.error("Invalid JSON: "+e)},ot.parseXML=function(e){var n,i;if(!e||"string"!=typeof e)return null;try{t.DOMParser?(i=new DOMParser,n=i.parseFromString(e,"text/xml")):(n=new ActiveXObject("Microsoft.XMLDOM"),n.async="false",n.loadXML(e))}catch(o){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName("parsererror").length||ot.error("Invalid XML: "+e),n};var ke,qe,We=/#.*$/,Ee=/([?&])_=[^&]*/,Be=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Ie=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Xe=/^(?:GET|HEAD)$/,Pe=/^\/\//,Re=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Fe={},He={},je="*/".concat("*");try{qe=location.href}catch(Ue){qe=ft.createElement("a"),qe.href="",qe=qe.href}ke=Re.exec(qe.toLowerCase())||[],ot.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:qe,type:"GET",isLocal:Ie.test(ke[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":je,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":ot.parseJSON,"text xml":ot.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(t,e){return e?R(R(t,ot.ajaxSettings),e):R(ot.ajaxSettings,t)},ajaxPrefilter:X(Fe),ajaxTransport:X(He),ajax:function(t,e){function n(t,e,n,i){var o,u,b,v,y,z=e;2!==M&&(M=2,r&&clearTimeout(r),l=void 0,s=i||"",A.readyState=t>0?4:0,o=t>=200&&t<300||304===t,n&&(v=F(h,A,n)),v=H(h,v,A,o),o?(h.ifModified&&(y=A.getResponseHeader("Last-Modified"),y&&(ot.lastModified[a]=y),y=A.getResponseHeader("etag"),y&&(ot.etag[a]=y)),204===t||"HEAD"===h.type?z="nocontent":304===t?z="notmodified":(z=v.state,u=v.data,b=v.error,o=!b)):(b=z,!t&&z||(z="error",t<0&&(t=0))),A.status=t,A.statusText=(e||z)+"",o?f.resolveWith(d,[u,z,A]):f.rejectWith(d,[A,z,b]),A.statusCode(g),g=void 0,c&&p.trigger(o?"ajaxSuccess":"ajaxError",[A,h,o?u:b]),m.fireWith(d,[A,z]),c&&(p.trigger("ajaxComplete",[A,h]),--ot.active||ot.event.trigger("ajaxStop")))}"object"==typeof t&&(e=t,t=void 0),e=e||{};var i,o,a,s,r,c,l,u,h=ot.ajaxSetup({},e),d=h.context||h,p=h.context&&(d.nodeType||d.jquery)?ot(d):ot.event,f=ot.Deferred(),m=ot.Callbacks("once memory"),g=h.statusCode||{},b={},v={},M=0,y="canceled",A={readyState:0,getResponseHeader:function(t){var e;if(2===M){if(!u)for(u={};e=Be.exec(s);)u[e[1].toLowerCase()]=e[2];e=u[t.toLowerCase()]}return null==e?null:e},getAllResponseHeaders:function(){return 2===M?s:null},setRequestHeader:function(t,e){var n=t.toLowerCase();return M||(t=v[n]=v[n]||t,b[t]=e),this},overrideMimeType:function(t){return M||(h.mimeType=t),this},statusCode:function(t){var e;if(t)if(M<2)for(e in t)g[e]=[g[e],t[e]];else A.always(t[A.status]);return this},abort:function(t){var e=t||y;return l&&l.abort(e),n(0,e),this}};if(f.promise(A).complete=m.add,A.success=A.done,A.error=A.fail,h.url=((t||h.url||qe)+"").replace(We,"").replace(Pe,ke[1]+"//"),h.type=e.method||e.type||h.method||h.type,h.dataTypes=ot.trim(h.dataType||"*").toLowerCase().match(Mt)||[""],null==h.crossDomain&&(i=Re.exec(h.url.toLowerCase()),h.crossDomain=!(!i||i[1]===ke[1]&&i[2]===ke[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(ke[3]||("http:"===ke[1]?"80":"443")))),h.data&&h.processData&&"string"!=typeof h.data&&(h.data=ot.param(h.data,h.traditional)),P(Fe,h,e,A),2===M)return A;c=ot.event&&h.global,c&&0===ot.active++&&ot.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Xe.test(h.type),a=h.url,h.hasContent||(h.data&&(a=h.url+=(Le.test(a)?"&":"?")+h.data,delete h.data),h.cache===!1&&(h.url=Ee.test(a)?a.replace(Ee,"$1_="+xe++):a+(Le.test(a)?"&":"?")+"_="+xe++)),h.ifModified&&(ot.lastModified[a]&&A.setRequestHeader("If-Modified-Since",ot.lastModified[a]),ot.etag[a]&&A.setRequestHeader("If-None-Match",ot.etag[a])),(h.data&&h.hasContent&&h.contentType!==!1||e.contentType)&&A.setRequestHeader("Content-Type",h.contentType),A.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+je+"; q=0.01":""):h.accepts["*"]);for(o in h.headers)A.setRequestHeader(o,h.headers[o]);if(h.beforeSend&&(h.beforeSend.call(d,A,h)===!1||2===M))return A.abort();y="abort";for(o in{success:1,error:1,complete:1})A[o](h[o]);if(l=P(He,h,e,A)){A.readyState=1,c&&p.trigger("ajaxSend",[A,h]),h.async&&h.timeout>0&&(r=setTimeout(function(){A.abort("timeout")},h.timeout));try{M=1,l.send(b,n)}catch(z){if(!(M<2))throw z;n(-1,z)}}else n(-1,"No Transport");return A},getJSON:function(t,e,n){return ot.get(t,e,n,"json")},getScript:function(t,e){return ot.get(t,void 0,e,"script")}}),ot.each(["get","post"],function(t,e){ot[e]=function(t,n,i,o){return ot.isFunction(n)&&(o=o||i,i=n,n=void 0),ot.ajax({url:t,type:e,dataType:o,data:n,success:i})}}),ot._evalUrl=function(t){return ot.ajax({url:t,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},ot.fn.extend({wrapAll:function(t){if(ot.isFunction(t))return this.each(function(e){ot(this).wrapAll(t.call(this,e))});if(this[0]){var e=ot(t,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&e.insertBefore(this[0]),e.map(function(){for(var t=this;t.firstChild&&1===t.firstChild.nodeType;)t=t.firstChild;return t}).append(this)}return this},wrapInner:function(t){return ot.isFunction(t)?this.each(function(e){ot(this).wrapInner(t.call(this,e))}):this.each(function(){var e=ot(this),n=e.contents();n.length?n.wrapAll(t):e.append(t)})},wrap:function(t){var e=ot.isFunction(t);return this.each(function(n){ot(this).wrapAll(e?t.call(this,n):t)})},unwrap:function(){return this.parent().each(function(){ot.nodeName(this,"body")||ot(this).replaceWith(this.childNodes)}).end()}}),ot.expr.filters.hidden=function(t){return t.offsetWidth<=0&&t.offsetHeight<=0||!nt.reliableHiddenOffsets()&&"none"===(t.style&&t.style.display||ot.css(t,"display"))},ot.expr.filters.visible=function(t){return!ot.expr.filters.hidden(t)};var $e=/%20/g,Ve=/\[\]$/,Ye=/\r?\n/g,Je=/^(?:submit|button|image|reset|file)$/i,Ke=/^(?:input|select|textarea|keygen)/i;ot.param=function(t,e){var n,i=[],o=function(t,e){e=ot.isFunction(e)?e():null==e?"":e,i[i.length]=encodeURIComponent(t)+"="+encodeURIComponent(e)};if(void 0===e&&(e=ot.ajaxSettings&&ot.ajaxSettings.traditional),ot.isArray(t)||t.jquery&&!ot.isPlainObject(t))ot.each(t,function(){o(this.name,this.value)});else for(n in t)j(n,t[n],e,o);return i.join("&").replace($e,"+")},ot.fn.extend({serialize:function(){return ot.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var t=ot.prop(this,"elements");return t?ot.makeArray(t):this}).filter(function(){var t=this.type;return this.name&&!ot(this).is(":disabled")&&Ke.test(this.nodeName)&&!Je.test(t)&&(this.checked||!xt.test(t))}).map(function(t,e){var n=ot(this).val();return null==n?null:ot.isArray(n)?ot.map(n,function(t){return{name:e.name,value:t.replace(Ye,"\r\n")}}):{name:e.name,value:n.replace(Ye,"\r\n")}}).get()}}),ot.ajaxSettings.xhr=void 0!==t.ActiveXObject?function(){return!this.isLocal&&/^(get|post|head|put|delete|options)$/i.test(this.type)&&U()||$()}:U;var Ge=0,Qe={},Ze=ot.ajaxSettings.xhr();t.attachEvent&&t.attachEvent("onunload",function(){for(var t in Qe)Qe[t](void 0,!0)}),nt.cors=!!Ze&&"withCredentials"in Ze,Ze=nt.ajax=!!Ze,Ze&&ot.ajaxTransport(function(t){if(!t.crossDomain||nt.cors){var e;return{send:function(n,i){var o,a=t.xhr(),s=++Ge;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(o in n)void 0!==n[o]&&a.setRequestHeader(o,n[o]+"");a.send(t.hasContent&&t.data||null),e=function(n,o){var r,c,l;if(e&&(o||4===a.readyState))if(delete Qe[s],e=void 0,a.onreadystatechange=ot.noop,o)4!==a.readyState&&a.abort();else{l={},r=a.status,"string"==typeof a.responseText&&(l.text=a.responseText);try{c=a.statusText}catch(u){c=""}r||!t.isLocal||t.crossDomain?1223===r&&(r=204):r=l.text?200:404}l&&i(r,c,l,a.getAllResponseHeaders())},t.async?4===a.readyState?setTimeout(e):a.onreadystatechange=Qe[s]=e:e()},abort:function(){e&&e(void 0,!0)}}}}),ot.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(t){return ot.globalEval(t),t}}}),ot.ajaxPrefilter("script",function(t){void 0===t.cache&&(t.cache=!1),t.crossDomain&&(t.type="GET",t.global=!1)}),ot.ajaxTransport("script",function(t){if(t.crossDomain){var e,n=ft.head||ot("head")[0]||ft.documentElement;return{send:function(i,o){e=ft.createElement("script"),e.async=!0,t.scriptCharset&&(e.charset=t.scriptCharset),e.src=t.url,e.onload=e.onreadystatechange=function(t,n){(n||!e.readyState||/loaded|complete/.test(e.readyState))&&(e.onload=e.onreadystatechange=null,e.parentNode&&e.parentNode.removeChild(e),e=null,n||o(200,"success"))},n.insertBefore(e,n.firstChild)},abort:function(){e&&e.onload(void 0,!0)}}}});var tn=[],en=/(=)\?(?=&|$)|\?\?/;ot.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var t=tn.pop()||ot.expando+"_"+xe++;return this[t]=!0,t}}),ot.ajaxPrefilter("json jsonp",function(e,n,i){var o,a,s,r=e.jsonp!==!1&&(en.test(e.url)?"url":"string"==typeof e.data&&!(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&en.test(e.data)&&"data");if(r||"jsonp"===e.dataTypes[0])return o=e.jsonpCallback=ot.isFunction(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,r?e[r]=e[r].replace(en,"$1"+o):e.jsonp!==!1&&(e.url+=(Le.test(e.url)?"&":"?")+e.jsonp+"="+o),e.converters["script json"]=function(){return s||ot.error(o+" was not called"),s[0]},e.dataTypes[0]="json",a=t[o],t[o]=function(){s=arguments},i.always(function(){t[o]=a,e[o]&&(e.jsonpCallback=n.jsonpCallback,tn.push(o)),s&&ot.isFunction(a)&&a(s[0]),s=a=void 0}),"script"}),ot.parseHTML=function(t,e,n){if(!t||"string"!=typeof t)return null;"boolean"==typeof e&&(n=e,e=!1),e=e||ft;var i=ht.exec(t),o=!n&&[];return i?[e.createElement(i[1])]:(i=ot.buildFragment([t],e,o),o&&o.length&&ot(o).remove(),ot.merge([],i.childNodes))};var nn=ot.fn.load;ot.fn.load=function(t,e,n){if("string"!=typeof t&&nn)return nn.apply(this,arguments);var i,o,a,s=this,r=t.indexOf(" ");return r>=0&&(i=ot.trim(t.slice(r,t.length)),t=t.slice(0,r)),ot.isFunction(e)?(n=e,e=void 0):e&&"object"==typeof e&&(a="POST"),s.length>0&&ot.ajax({url:t,type:a,dataType:"html",data:e}).done(function(t){o=arguments,s.html(i?ot("
    ").append(ot.parseHTML(t)).find(i):t)}).complete(n&&function(t,e){s.each(n,o||[t.responseText,e,t])}),this},ot.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(t,e){ot.fn[e]=function(t){return this.on(e,t)}}),ot.expr.filters.animated=function(t){return ot.grep(ot.timers,function(e){return t===e.elem}).length};var on=t.document.documentElement;ot.offset={setOffset:function(t,e,n){var i,o,a,s,r,c,l,u=ot.css(t,"position"),h=ot(t),d={};"static"===u&&(t.style.position="relative"),r=h.offset(),a=ot.css(t,"top"),c=ot.css(t,"left"),l=("absolute"===u||"fixed"===u)&&ot.inArray("auto",[a,c])>-1,l?(i=h.position(),s=i.top,o=i.left):(s=parseFloat(a)||0,o=parseFloat(c)||0),ot.isFunction(e)&&(e=e.call(t,n,r)),null!=e.top&&(d.top=e.top-r.top+s),null!=e.left&&(d.left=e.left-r.left+o),"using"in e?e.using.call(t,d):h.css(d)}},ot.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ot.offset.setOffset(this,t,e)});var e,n,i={top:0,left:0},o=this[0],a=o&&o.ownerDocument;if(a)return e=a.documentElement,ot.contains(e,o)?(typeof o.getBoundingClientRect!==_t&&(i=o.getBoundingClientRect()),n=V(a),{top:i.top+(n.pageYOffset||e.scrollTop)-(e.clientTop||0),left:i.left+(n.pageXOffset||e.scrollLeft)-(e.clientLeft||0)}):i},position:function(){if(this[0]){var t,e,n={top:0,left:0},i=this[0];return"fixed"===ot.css(i,"position")?e=i.getBoundingClientRect():(t=this.offsetParent(),e=this.offset(),ot.nodeName(t[0],"html")||(n=t.offset()),n.top+=ot.css(t[0],"borderTopWidth",!0),n.left+=ot.css(t[0],"borderLeftWidth",!0)),{top:e.top-n.top-ot.css(i,"marginTop",!0),left:e.left-n.left-ot.css(i,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||on;t&&!ot.nodeName(t,"html")&&"static"===ot.css(t,"position");)t=t.offsetParent;return t||on})}}),ot.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,e){var n=/Y/.test(e);ot.fn[t]=function(i){return St(this,function(t,i,o){var a=V(t);return void 0===o?a?e in a?a[e]:a.document.documentElement[i]:t[i]:void(a?a.scrollTo(n?ot(a).scrollLeft():o,n?o:ot(a).scrollTop()):t[i]=o)},t,i,arguments.length,null)}}),ot.each(["top","left"],function(t,e){ot.cssHooks[e]=C(nt.pixelPosition,function(t,n){if(n)return n=ee(t,e),ie.test(n)?ot(t).position()[e]+"px":n})}),ot.each({Height:"height",Width:"width"},function(t,e){ot.each({padding:"inner"+t,content:e,"":"outer"+t},function(n,i){ot.fn[i]=function(i,o){var a=arguments.length&&(n||"boolean"!=typeof i),s=n||(i===!0||o===!0?"margin":"border");return St(this,function(e,n,i){var o;return ot.isWindow(e)?e.document.documentElement["client"+t]:9===e.nodeType?(o=e.documentElement,Math.max(e.body["scroll"+t],o["scroll"+t],e.body["offset"+t],o["offset"+t],o["client"+t])):void 0===i?ot.css(e,n,s):ot.style(e,n,i,s)},e,a?i:void 0,a,null)}})}),ot.fn.size=function(){return this.length},ot.fn.andSelf=ot.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return ot});var an=t.jQuery,sn=t.$;return ot.noConflict=function(e){return t.$===ot&&(t.$=sn),e&&t.jQuery===ot&&(t.jQuery=an),ot},typeof e===_t&&(t.jQuery=t.$=ot),ot}),function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(t){function e(e,i){var o,a,s,r=e.nodeName.toLowerCase();return"area"===r?(o=e.parentNode,a=o.name,!(!e.href||!a||"map"!==o.nodeName.toLowerCase())&&(s=t("img[usemap='#"+a+"']")[0],!!s&&n(s))):(/input|select|textarea|button|object/.test(r)?!e.disabled:"a"===r?e.href||i:i)&&n(e)}function n(e){return t.expr.filters.visible(e)&&!t(e).parents().addBack().filter(function(){return"hidden"===t.css(this,"visibility")}).length}function i(t){for(var e,n;t.length&&t[0]!==document;){if(e=t.css("position"),("absolute"===e||"relative"===e||"fixed"===e)&&(n=parseInt(t.css("zIndex"),10),!isNaN(n)&&0!==n))return n;t=t.parent()}return 0}function o(){this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},t.extend(this._defaults,this.regional[""]),this.regional.en=t.extend(!0,{},this.regional[""]),this.regional["en-US"]=t.extend(!0,{},this.regional.en),this.dpDiv=a(t("
    "))}function a(e){var n="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return e.delegate(n,"mouseout",function(){t(this).removeClass("ui-state-hover"),this.className.indexOf("ui-datepicker-prev")!==-1&&t(this).removeClass("ui-datepicker-prev-hover"),this.className.indexOf("ui-datepicker-next")!==-1&&t(this).removeClass("ui-datepicker-next-hover")}).delegate(n,"mouseover",s)}function s(){t.datepicker._isDisabledDatepicker(b.inline?b.dpDiv.parent()[0]:b.input[0])||(t(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),t(this).addClass("ui-state-hover"),this.className.indexOf("ui-datepicker-prev")!==-1&&t(this).addClass("ui-datepicker-prev-hover"),this.className.indexOf("ui-datepicker-next")!==-1&&t(this).addClass("ui-datepicker-next-hover"))}function r(e,n){t.extend(e,n);for(var i in n)null==n[i]&&(e[i]=n[i]);return e}function c(t){return function(){var e=this.element.val();t.apply(this,arguments),this._refresh(),e!==this.element.val()&&this._trigger("change")}}t.ui=t.ui||{},t.extend(t.ui,{version:"1.11.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),t.fn.extend({scrollParent:function(e){var n=this.css("position"),i="absolute"===n,o=e?/(auto|scroll|hidden)/:/(auto|scroll)/,a=this.parents().filter(function(){var e=t(this);return(!i||"static"!==e.css("position"))&&o.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==n&&a.length?a:t(this[0].ownerDocument||document)},uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(n){return!!t.data(n,e)}}):function(e,n,i){return!!t.data(e,i[3])},focusable:function(n){return e(n,!isNaN(t.attr(n,"tabindex")))},tabbable:function(n){var i=t.attr(n,"tabindex"),o=isNaN(i);return(o||i>=0)&&e(n,!o)}}),t("").outerWidth(1).jquery||t.each(["Width","Height"],function(e,n){function i(e,n,i,a){return t.each(o,function(){n-=parseFloat(t.css(e,"padding"+this))||0,i&&(n-=parseFloat(t.css(e,"border"+this+"Width"))||0),a&&(n-=parseFloat(t.css(e,"margin"+this))||0)}),n}var o="Width"===n?["Left","Right"]:["Top","Bottom"],a=n.toLowerCase(),s={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+n]=function(e){return void 0===e?s["inner"+n].call(this):this.each(function(){t(this).css(a,i(this,e)+"px")})},t.fn["outer"+n]=function(e,o){return"number"!=typeof e?s["outer"+n].call(this,e):this.each(function(){t(this).css(a,i(this,e,!0,o)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(n){return arguments.length?e.call(this,t.camelCase(n)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.fn.extend({focus:function(e){return function(n,i){return"number"==typeof n?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),i&&i.call(e)},n)}):e.apply(this,arguments)}}(t.fn.focus),disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(e){if(void 0!==e)return this.css("zIndex",e);if(this.length)for(var n,i,o=t(this[0]);o.length&&o[0]!==document;){if(n=o.css("position"),("absolute"===n||"relative"===n||"fixed"===n)&&(i=parseInt(o.css("zIndex"),10),!isNaN(i)&&0!==i))return i;o=o.parent()}return 0}}),t.ui.plugin={add:function(e,n,i){var o,a=t.ui[e].prototype;for(o in i)a.plugins[o]=a.plugins[o]||[],a.plugins[o].push([n,i[o]])},call:function(t,e,n,i){var o,a=t.plugins[e];if(a&&(i||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(o=0;o",options:{disabled:!1,create:null},_createWidget:function(e,n){n=t(n||this.defaultElement||this)[0],this.element=t(n),this.uuid=l++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),n!==this&&(t.data(n,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===n&&this.destroy()}}),this.document=t(n.style?n.ownerDocument:n.document||n),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(e,n){var i,o,a,s=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(s={},i=e.split("."),e=i.shift(),i.length){for(o=s[e]=t.widget.extend({},this.options[e]),a=0;a=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}});!function(){function e(t,e,n){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?n/100:1)]}function n(e,n){return parseInt(t.css(e,n),10)||0}function i(e){var n=e[0];return 9===n.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(n)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:n.preventDefault?{width:0,height:0,offset:{top:n.pageY,left:n.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var o,a,s=Math.max,r=Math.abs,c=Math.round,l=/left|center|right/,u=/top|center|bottom/,h=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==o)return o;var e,n,i=t("
    "),a=i.children()[0];return t("body").append(i),e=a.offsetWidth,i.css("overflow","scroll"),n=a.offsetWidth,e===n&&(n=i[0].clientWidth),i.remove(),o=e-n},getScrollInfo:function(e){var n=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),i=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),o="scroll"===n||"auto"===n&&e.width0?"right":"center",vertical:a<0?"top":i>0?"bottom":"middle"};ms(r(i),r(a))?c.important="horizontal":c.important="vertical",o.using.call(this,t,c)}),u.offset(t.extend(O,{using:l}))})},t.ui.position={fit:{left:function(t,e){var n,i=e.within,o=i.isWindow?i.scrollLeft:i.offset.left,a=i.width,r=t.left-e.collisionPosition.marginLeft,c=o-r,l=r+e.collisionWidth-a-o;e.collisionWidth>a?c>0&&l<=0?(n=t.left+c+e.collisionWidth-a-o,t.left+=c-n):l>0&&c<=0?t.left=o:c>l?t.left=o+a-e.collisionWidth:t.left=o:c>0?t.left+=c:l>0?t.left-=l:t.left=s(t.left-r,t.left)},top:function(t,e){var n,i=e.within,o=i.isWindow?i.scrollTop:i.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,c=o-r,l=r+e.collisionHeight-a-o;e.collisionHeight>a?c>0&&l<=0?(n=t.top+c+e.collisionHeight-a-o,t.top+=c-n):l>0&&c<=0?t.top=o:c>l?t.top=o+a-e.collisionHeight:t.top=o:c>0?t.top+=c:l>0?t.top-=l:t.top=s(t.top-r,t.top)}},flip:{left:function(t,e){var n,i,o=e.within,a=o.offset.left+o.scrollLeft,s=o.width,c=o.isWindow?o.scrollLeft:o.offset.left,l=t.left-e.collisionPosition.marginLeft,u=l-c,h=l+e.collisionWidth-s-c,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];u<0?(n=t.left+d+p+f+e.collisionWidth-s-a,(n<0||n0&&(i=t.left-e.collisionPosition.marginLeft+d+p+f-c,(i>0||r(i)u&&(i<0||i0&&(n=t.top-e.collisionPosition.marginTop+p+f+m-c,t.top+p+f+m>h&&(n>0||r(n)10&&o<11,e.innerHTML="",n.removeChild(e)}()}();t.ui.position,t.widget("ui.accordion",{version:"1.11.2",options:{active:0,animate:{},collapsible:!1,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var e=this.options;this.prevShow=this.prevHide=t(),this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist"),e.collapsible||e.active!==!1&&null!=e.active||(e.active=0),this._processPanels(),e.active<0&&(e.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():t()}},_createIcons:function(){var e=this.options.icons;e&&(t("").addClass("ui-accordion-header-icon ui-icon "+e.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(e.header).addClass(e.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){return"active"===t?void this._activate(e):("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||this.options.active!==!1||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons()),void("disabled"===t&&(this.element.toggleClass("ui-state-disabled",!!e).attr("aria-disabled",e),this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!e))))},_keydown:function(e){if(!e.altKey&&!e.ctrlKey){var n=t.ui.keyCode,i=this.headers.length,o=this.headers.index(e.target),a=!1;switch(e.keyCode){case n.RIGHT:case n.DOWN:a=this.headers[(o+1)%i];break;case n.LEFT:case n.UP:a=this.headers[(o-1+i)%i];break;case n.SPACE:case n.ENTER:this._eventHandler(e);break;case n.HOME:a=this.headers[0];break;case n.END:a=this.headers[i-1]}a&&(t(e.target).attr("tabIndex",-1),t(a).attr("tabIndex",0),a.focus(),e.preventDefault())}},_panelKeyDown:function(e){e.keyCode===t.ui.keyCode.UP&&e.ctrlKey&&t(e.currentTarget).prev().focus()},refresh:function(){var e=this.options;this._processPanels(),e.active===!1&&e.collapsible===!0||!this.headers.length?(e.active=!1,this.active=t()):e.active===!1?this._activate(0):this.active.length&&!t.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(e.active=!1,this.active=t()):this._activate(Math.max(0,e.active-1)):e.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-state-default ui-corner-all"),this.panels=this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide(),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var e,n=this.options,i=n.heightStyle,o=this.element.parent();this.active=this._findActive(n.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all"),this.active.next().addClass("ui-accordion-content-active").show(),this.headers.attr("role","tab").each(function(){var e=t(this),n=e.uniqueId().attr("id"),i=e.next(),o=i.uniqueId().attr("id");e.attr("aria-controls",o),i.attr("aria-labelledby",n)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(n.event),"fill"===i?(e=o.height(),this.element.siblings(":visible").each(function(){var n=t(this),i=n.css("position");"absolute"!==i&&"fixed"!==i&&(e-=n.outerHeight(!0))}),this.headers.each(function(){e-=t(this).outerHeight(!0)}),this.headers.next().each(function(){t(this).height(Math.max(0,e-t(this).innerHeight()+t(this).height()))}).css("overflow","auto")):"auto"===i&&(e=0,this.headers.next().each(function(){e=Math.max(e,t(this).css("height","").height())}).height(e))},_activate:function(e){var n=this._findActive(e)[0];n!==this.active[0]&&(n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:t.noop}))},_findActive:function(e){return"number"==typeof e?this.headers.eq(e):t()},_setupEvents:function(e){var n={keydown:"_keydown"};e&&t.each(e.split(" "),function(t,e){n[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,n),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(e){var n=this.options,i=this.active,o=t(e.currentTarget),a=o[0]===i[0],s=a&&n.collapsible,r=s?t():o.next(),c=i.next(),l={oldHeader:i,oldPanel:c,newHeader:s?t():o,newPanel:r};e.preventDefault(),a&&!n.collapsible||this._trigger("beforeActivate",e,l)===!1||(n.active=!s&&this.headers.index(o),this.active=a?t():o,this._toggle(l),i.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),a||(o.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&o.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),o.next().addClass("ui-accordion-content-active")))},_toggle:function(e){var n=e.newPanel,i=this.prevShow.length?this.prevShow:e.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=i,this.options.animate?this._animate(n,i,e):(i.hide(),n.show(),this._toggleComplete(e)),i.attr({"aria-hidden":"true"}),i.prev().attr("aria-selected","false"),n.length&&i.length?i.prev().attr({tabIndex:-1,"aria-expanded":"false"}):n.length&&this.headers.filter(function(){return 0===t(this).attr("tabIndex")}).attr("tabIndex",-1),n.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"})},_animate:function(t,e,n){var i,o,a,s=this,r=0,c=t.length&&(!e.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},items:"> *",menus:"ul",position:{my:"left-1 top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault()},"click .ui-menu-item":function(e){var n=t(e.target);!this.mouseHandled&&n.not(".ui-state-disabled").length&&(this.select(e),e.isPropagationStopped()||(this.mouseHandled=!0),n.has(".ui-menu").length?this.expand(e):!this.element.is(":focus")&&t(this.document[0].activeElement).closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(e){if(!this.previousFilter){var n=t(e.currentTarget);n.siblings(".ui-state-active").removeClass("ui-state-active"),this.focus(e,n)}},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var n=this.active||this.element.find(this.options.items).eq(0);e||this.focus(t,n)},blur:function(e){this._delay(function(){t.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(e)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t),this.mouseHandled=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-menu-icons ui-front").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").removeUniqueId().removeClass("ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var e=t(this);e.data("ui-menu-submenu-carat")&&e.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(e){var n,i,o,a,s=!0;switch(e.keyCode){case t.ui.keyCode.PAGE_UP:this.previousPage(e);break;case t.ui.keyCode.PAGE_DOWN:this.nextPage(e);break;case t.ui.keyCode.HOME:this._move("first","first",e);break;case t.ui.keyCode.END:this._move("last","last",e);break;case t.ui.keyCode.UP:this.previous(e);break;case t.ui.keyCode.DOWN:this.next(e);break;case t.ui.keyCode.LEFT:this.collapse(e);break;case t.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(e);break;case t.ui.keyCode.ENTER:case t.ui.keyCode.SPACE:this._activate(e);break;case t.ui.keyCode.ESCAPE:this.collapse(e);break;default:s=!1,i=this.previousFilter||"",o=String.fromCharCode(e.keyCode),a=!1,clearTimeout(this.filterTimer),o===i?a=!0:o=i+o,n=this._filterMenuItems(o),n=a&&n.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):n,n.length||(o=String.fromCharCode(e.keyCode),n=this._filterMenuItems(o)),n.length?(this.focus(e,n),this.previousFilter=o,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}s&&e.preventDefault()},_activate:function(t){this.active.is(".ui-state-disabled")||(this.active.is("[aria-haspopup='true']")?this.expand(t):this.select(t))},refresh:function(){var e,n,i=this,o=this.options.icons.submenu,a=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length),a.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-front").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var e=t(this),n=e.parent(),i=t("").addClass("ui-menu-icon ui-icon "+o).data("ui-menu-submenu-carat",!0);n.attr("aria-haspopup","true").prepend(i),e.attr("aria-labelledby",n.attr("id"))}),e=a.add(this.element),n=e.find(this.options.items),n.not(".ui-menu-item").each(function(){var e=t(this);i._isDivider(e)&&e.addClass("ui-widget-content ui-menu-divider")}),n.not(".ui-menu-item, .ui-menu-divider").addClass("ui-menu-item").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),n.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!t.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){"icons"===t&&this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(e.submenu),"disabled"===t&&this.element.toggleClass("ui-state-disabled",!!e).attr("aria-disabled",e),this._super(t,e)},focus:function(t,e){var n,i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.addClass("ui-state-focus").removeClass("ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),this.active.parent().closest(".ui-menu-item").addClass("ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),n=e.children(".ui-menu"),n.length&&t&&/^mouse/.test(t.type)&&this._startOpening(n),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(e){var n,i,o,a,s,r;this._hasScroll()&&(n=parseFloat(t.css(this.activeMenu[0],"borderTopWidth"))||0,i=parseFloat(t.css(this.activeMenu[0],"paddingTop"))||0,o=e.offset().top-this.activeMenu.offset().top-n-i,a=this.activeMenu.scrollTop(),s=this.activeMenu.height(),r=e.outerHeight(),o<0?this.activeMenu.scrollTop(a+o):o+r>s&&this.activeMenu.scrollTop(a+o-s+r))},blur:function(t,e){e||clearTimeout(this.timer),this.active&&(this.active.removeClass("ui-state-focus"),this.active=null,this._trigger("blur",t,{item:this.active}))},_startOpening:function(t){clearTimeout(this.timer),"true"===t.attr("aria-hidden")&&(this.timer=this._delay(function(){this._close(),this._open(t)},this.delay))},_open:function(e){var n=t.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(e.parents(".ui-menu")).hide().attr("aria-hidden","true"),e.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(n)},collapseAll:function(e,n){clearTimeout(this.timer),this.timer=this._delay(function(){var i=n?this.element:t(e&&e.target).closest(this.element.find(".ui-menu"));i.length||(i=this.element),this._close(i),this.blur(e),this.activeMenu=i},this.delay)},_close:function(t){t||(t=this.active?this.active.parent():this.element),t.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find(".ui-state-active").not(".ui-state-focus").removeClass("ui-state-active")},_closeOnDocumentClick:function(e){return!t(e.target).closest(".ui-menu").length},_isDivider:function(t){return!/[^\-\u2014\u2013\s]/.test(t.text())},collapse:function(t){var e=this.active&&this.active.parent().closest(".ui-menu-item",this.element);e&&e.length&&(this._close(),this.focus(t,e))},expand:function(t){var e=this.active&&this.active.children(".ui-menu ").find(this.options.items).first();e&&e.length&&(this._open(e.parent()),this._delay(function(){this.focus(t,e)}))},next:function(t){this._move("next","first",t)},previous:function(t){this._move("prev","last",t)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(t,e,n){var i;this.active&&(i="first"===t||"last"===t?this.active["first"===t?"prevAll":"nextAll"](".ui-menu-item").eq(-1):this.active[t+"All"](".ui-menu-item").eq(0)),i&&i.length&&this.active||(i=this.activeMenu.find(this.options.items)[e]()),this.focus(n,i)},nextPage:function(e){var n,i,o;return this.active?void(this.isLastItem()||(this._hasScroll()?(i=this.active.offset().top,o=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return n=t(this),n.offset().top-i-o<0}),this.focus(e,n)):this.focus(e,this.activeMenu.find(this.options.items)[this.active?"last":"first"]()))):void this.next(e)},previousPage:function(e){var n,i,o;return this.active?void(this.isFirstItem()||(this._hasScroll()?(i=this.active.offset().top,o=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return n=t(this),n.offset().top-i+o>0}),this.focus(e,n)):this.focus(e,this.activeMenu.find(this.options.items).first()))):void this.next(e)},_hasScroll:function(){return this.element.outerHeight()",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var e,n,i,o=this.element[0].nodeName.toLowerCase(),a="textarea"===o,s="input"===o;this.isMultiLine=!!a||!s&&this.element.prop("isContentEditable"),this.valueMethod=this.element[a||s?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(o){if(this.element.prop("readOnly"))return e=!0,i=!0,void(n=!0);e=!1,i=!1,n=!1;var a=t.ui.keyCode;switch(o.keyCode){case a.PAGE_UP:e=!0,this._move("previousPage",o);break;case a.PAGE_DOWN:e=!0,this._move("nextPage",o);break;case a.UP:e=!0,this._keyEvent("previous",o);break;case a.DOWN:e=!0,this._keyEvent("next",o);break;case a.ENTER:this.menu.active&&(e=!0,o.preventDefault(),this.menu.select(o));break;case a.TAB:this.menu.active&&this.menu.select(o);break;case a.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(o),o.preventDefault());break;default:n=!0,this._searchTimeout(o)}},keypress:function(i){if(e)return e=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||i.preventDefault());if(!n){var o=t.ui.keyCode;switch(i.keyCode){case o.PAGE_UP:this._move("previousPage",i);break;case o.PAGE_DOWN:this._move("nextPage",i);break;case o.UP:this._keyEvent("previous",i);break;case o.DOWN:this._keyEvent("next",i)}}},input:function(t){return i?(i=!1,void t.preventDefault()):void this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){return this.cancelBlur?void delete this.cancelBlur:(clearTimeout(this.searching),this.close(t),void this._change(t))}}),this._initSource(),this.menu=t("
    ',e=n.createElement(i),"FORM"!==this.element.tagName?(o=n.createElement('
    '),o.appendChild(e)):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=o?o:e)},n.prototype.getExistingFallback=function(){var t,e,n,i,o,a;for(e=function(t){var e,n,i;for(n=0,i=t.length;n0){for(s=["TB","GB","MB","KB","b"],n=r=0,c=s.length;r=e){i=t/Math.pow(this.options.filesizeBase,4-n),o=a;break}i=Math.round(10*i)/10}return""+i+" "+o},n.prototype._updateMaxFilesReachedClass=function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")},n.prototype.drop=function(t){var e,n;t.dataTransfer&&(this.emit("drop",t),e=t.dataTransfer.files,this.emit("addedfiles",e),e.length&&(n=t.dataTransfer.items,n&&n.length&&null!=n[0].webkitGetAsEntry?this._addFilesFromItems(n):this.handleFiles(e)))},n.prototype.paste=function(t){var e,n;if(null!=(null!=t&&null!=(n=t.clipboardData)?n.items:void 0))return this.emit("paste",t),e=t.clipboardData.items,e.length?this._addFilesFromItems(e):void 0},n.prototype.handleFiles=function(t){var e,n,i,o;for(o=[],n=0,i=t.length;n0){for(a=0,s=n.length;a1024*this.options.maxFilesize*1024?e(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(t.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):n.isValidFile(t,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(e(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",t)):this.options.accept.call(this,t,e):e(this.options.dictInvalidFileType)},n.prototype.addFile=function(t){return t.upload={progress:0,total:t.size,bytesSent:0},this.files.push(t),t.status=n.ADDED,this.emit("addedfile",t),this._enqueueThumbnail(t),this.accept(t,function(e){return function(n){return n?(t.accepted=!1,e._errorProcessing([t],n)):(t.accepted=!0,e.options.autoQueue&&e.enqueueFile(t)),e._updateMaxFilesReachedClass()}}(this))},n.prototype.enqueueFiles=function(t){var e,n,i;for(n=0,i=t.length;n=e)&&(i=this.getQueuedFiles(),i.length>0)){if(this.options.uploadMultiple)return this.processFiles(i.slice(0,e-n));for(;t=B;u=0<=B?++L:--L)a.append(this._getParamName(u),t[u],this._renameFilename(t[u].name));return this.submitRequest(z,a,t)},n.prototype.submitRequest=function(t,e,n){return t.send(e)},n.prototype._finished=function(t,e,i){var o,a,s;for(a=0,s=t.length;au;)e=o[4*(c-1)+3],0===e?a=c:u=c,c=a+u>>1;return l=c/s,0===l?1:l},a=function(t,e,n,i,a,s,r,c,l,u){var h;return h=o(e),t.drawImage(e,n,i,a,s,r,c,l,u/h)},i=function(t,e){var n,i,o,a,s,r,c,l,u;if(o=!1,u=!0,i=t.document,l=i.documentElement,n=i.addEventListener?"addEventListener":"attachEvent",c=i.addEventListener?"removeEventListener":"detachEvent",r=i.addEventListener?"":"on",a=function(n){if("readystatechange"!==n.type||"complete"===i.readyState)return("load"===n.type?t:i)[c](r+n.type,a,!1),!o&&(o=!0)?e.call(t,n.type||n):void 0},s=function(){var t;try{l.doScroll("left")}catch(e){return t=e,void setTimeout(s,50)}return a("poll")},"complete"!==i.readyState){if(i.createEventObject&&l.doScroll){try{u=!t.frameElement}catch(h){}u&&s()}return i[n](r+"DOMContentLoaded",a,!1),i[n](r+"readystatechange",a,!1),t[n](r+"load",a,!1)}},t._autoDiscoverFunction=function(){if(t.autoDiscover)return t.discover()},i(window,t._autoDiscoverFunction)}.call(this),function(t,e){"function"==typeof define&&define.amd?define("typeahead.js",["jquery"],function(t){return e(t)}):"object"==typeof exports?module.exports=e(require("jquery")):e(jQuery)}(this,function(t){var e=function(){"use strict";return{isMsie:function(){return!!/(msie|trident)/i.test(navigator.userAgent)&&navigator.userAgent.match(/(msie |rv:)(\d+(.\d+)?)/i)[2]},isBlankString:function(t){return!t||/^\s*$/.test(t)},escapeRegExChars:function(t){return t.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")},isString:function(t){return"string"==typeof t},isNumber:function(t){return"number"==typeof t},isArray:t.isArray,isFunction:t.isFunction,isObject:t.isPlainObject,isUndefined:function(t){return"undefined"==typeof t},isElement:function(t){return!(!t||1!==t.nodeType)},isJQuery:function(e){return e instanceof t},toStr:function(t){return e.isUndefined(t)||null===t?"":t+""},bind:t.proxy,each:function(e,n){function i(t,e){return n(e,t)}t.each(e,i)},map:t.map,filter:t.grep,every:function(e,n){var i=!0;return e?(t.each(e,function(t,o){if(!(i=n.call(null,o,t,e)))return!1}),!!i):i},some:function(e,n){var i=!1;return e?(t.each(e,function(t,o){if(i=n.call(null,o,t,e))return!1}),!!i):i},mixin:t.extend,identity:function(t){return t},clone:function(e){return t.extend(!0,{},e)},getIdGenerator:function(){var t=0;return function(){return t++}},templatify:function(e){function n(){return String(e)}return t.isFunction(e)?e:n},defer:function(t){setTimeout(t,0)},debounce:function(t,e,n){var i,o;return function(){var a,s,r=this,c=arguments;return a=function(){i=null,n||(o=t.apply(r,c))},s=n&&!i,clearTimeout(i),i=setTimeout(a,e),s&&(o=t.apply(r,c)),o}},throttle:function(t,e){var n,i,o,a,s,r;return s=0,r=function(){s=new Date,o=null,a=t.apply(n,i)},function(){var c=new Date,l=e-(c-s);return n=this,i=arguments,l<=0?(clearTimeout(o),o=null,s=c,a=t.apply(n,i)):o||(o=setTimeout(r,l)),a}},stringify:function(t){return e.isString(t)?t:JSON.stringify(t)},noop:function(){}}}(),n=function(){"use strict";function t(t){var s,r;return r=e.mixin({},a,t),s={css:o(),classes:r,html:n(r),selectors:i(r)},{css:s.css,html:s.html,classes:s.classes,selectors:s.selectors,mixin:function(t){e.mixin(t,s)}}}function n(t){return{wrapper:'',menu:'
    '}}function i(t){var n={};return e.each(t,function(t,e){n[e]="."+t}),n}function o(){var t={wrapper:{position:"relative",display:"inline-block"},hint:{position:"absolute",top:"0",left:"0",borderColor:"transparent",boxShadow:"none",opacity:"1"},input:{position:"relative",verticalAlign:"top",backgroundColor:"transparent"},inputWithNoHint:{position:"relative",verticalAlign:"top"},menu:{position:"absolute",top:"100%",left:"0",zIndex:"100",display:"none"},ltr:{left:"0",right:"auto"},rtl:{left:"auto",right:" 0"}};return e.isMsie()&&e.mixin(t.input,{backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)"}),t}var a={wrapper:"twitter-typeahead",input:"tt-input",hint:"tt-hint",menu:"tt-menu",dataset:"tt-dataset",suggestion:"tt-suggestion",selectable:"tt-selectable",empty:"tt-empty",open:"tt-open",cursor:"tt-cursor",highlight:"tt-highlight"};return t}(),i=function(){"use strict";function n(e){e&&e.el||t.error("EventBus initialized without el"),this.$el=t(e.el)}var i,o;return i="typeahead:",o={render:"rendered",cursorchange:"cursorchanged",select:"selected",autocomplete:"autocompleted"},e.mixin(n.prototype,{_trigger:function(e,n){var o;return o=t.Event(i+e),(n=n||[]).unshift(o),this.$el.trigger.apply(this.$el,n),o},before:function(t){var e,n;return e=[].slice.call(arguments,1),n=this._trigger("before"+t,e),n.isDefaultPrevented()},trigger:function(t){var e;this._trigger(t,[].slice.call(arguments,1)),(e=o[t])&&this._trigger(e,[].slice.call(arguments,1))}}),n}(),o=function(){"use strict";function t(t,e,n,i){var o;if(!n)return this;for(e=e.split(c),n=i?r(n,i):n,this._callbacks=this._callbacks||{};o=e.shift();)this._callbacks[o]=this._callbacks[o]||{sync:[],async:[]},this._callbacks[o][t].push(n);return this}function e(e,n,i){return t.call(this,"async",e,n,i)}function n(e,n,i){return t.call(this,"sync",e,n,i)}function i(t){var e;if(!this._callbacks)return this;for(t=t.split(c);e=t.shift();)delete this._callbacks[e];return this}function o(t){var e,n,i,o,s;if(!this._callbacks)return this;for(t=t.split(c),i=[].slice.call(arguments,1);(e=t.shift())&&(n=this._callbacks[e]);)o=a(n.sync,this,[e].concat(i)),s=a(n.async,this,[e].concat(i)),o()&&l(s);return this}function a(t,e,n){function i(){for(var i,o=0,a=t.length;!i&&o