diff --git a/app/Console/Commands/ChargeRenewalInvoices.php b/app/Console/Commands/ChargeRenewalInvoices.php index 6ccdd59b4dfe..2a33e6b73094 100644 --- a/app/Console/Commands/ChargeRenewalInvoices.php +++ b/app/Console/Commands/ChargeRenewalInvoices.php @@ -73,7 +73,7 @@ class ChargeRenewalInvoices extends Command ->orderBy('id') ->get(); - $this->info(count($invoices).' invoices found'); + $this->info($invoices->count() . ' invoices found'); foreach ($invoices as $invoice) { diff --git a/app/Console/Commands/CheckData.php b/app/Console/Commands/CheckData.php index 28f994a86e08..479c780aefcd 100644 --- a/app/Console/Commands/CheckData.php +++ b/app/Console/Commands/CheckData.php @@ -5,6 +5,7 @@ namespace App\Console\Commands; use Carbon; use App\Libraries\CurlUtils; use DB; +use App; use Exception; use Illuminate\Console\Command; use Mail; @@ -81,6 +82,7 @@ class CheckData extends Command } //$this->checkInvoices(); + $this->checkTranslations(); $this->checkInvoiceBalances(); $this->checkClientBalances(); $this->checkContacts(); @@ -115,6 +117,40 @@ class CheckData extends Command $this->log .= $str . "\n"; } + private function checkTranslations() + { + $invalid = 0; + + foreach (cache('languages') as $language) { + App::setLocale($language->locale); + foreach (trans('texts') as $text) { + if (strpos($text, '=') !== false) { + $invalid++; + $this->logMessage($language->locale . ' is invalid: ' . $text); + } + + preg_match('/(.script)/', strtolower($text), $matches); + if (count($matches)) { + foreach ($matches as $match) { + if (in_array($match, ['escript', 'bscript', 'nscript'])) { + continue; + } + $invalid++; + $this->logMessage(sprintf('%s is invalid: %s', $language->locale, $text)); + break; + } + } + } + } + + if ($invalid > 0) { + $this->isValid = false; + } + + App::setLocale('en'); + $this->logMessage($invalid . ' invalid text strings'); + } + private function checkDraftSentInvoices() { $invoices = Invoice::whereInvoiceStatusId(INVOICE_STATUS_SENT) @@ -122,9 +158,9 @@ class CheckData extends Command ->withTrashed() ->get(); - $this->logMessage(count($invoices) . ' draft sent invoices'); + $this->logMessage($invoices->count() . ' draft sent invoices'); - if (count($invoices) > 0) { + if ($invoices->count() > 0) { $this->isValid = false; } @@ -190,9 +226,9 @@ class CheckData extends Command ->havingRaw('count(users.id) > 1') ->get(['users.oauth_user_id']); - $this->logMessage(count($users) . ' users with duplicate oauth ids'); + $this->logMessage($users->count() . ' users with duplicate oauth ids'); - if (count($users) > 0) { + if ($users->count() > 0) { $this->isValid = false; } @@ -308,9 +344,9 @@ class CheckData extends Command ->whereNull('contact_key') ->orderBy('id') ->get(['id']); - $this->logMessage(count($contacts) . ' contacts without a contact_key'); + $this->logMessage($contacts->count() . ' contacts without a contact_key'); - if (count($contacts) > 0) { + if ($contacts->count() > 0) { $this->isValid = false; } @@ -339,9 +375,9 @@ class CheckData extends Command } $clients = $clients->get(['clients.id', 'clients.user_id', 'clients.account_id']); - $this->logMessage(count($clients) . ' clients without any contacts'); + $this->logMessage($clients->count() . ' clients without any contacts'); - if (count($clients) > 0) { + if ($clients->count() > 0) { $this->isValid = false; } @@ -374,9 +410,9 @@ class CheckData extends Command } $clients = $clients->get(['clients.id', DB::raw('count(contacts.id)')]); - $this->logMessage(count($clients) . ' clients without a single primary contact'); + $this->logMessage($clients->count() . ' clients without a single primary contact'); - if (count($clients) > 0) { + if ($clients->count() > 0) { $this->isValid = false; } } @@ -423,9 +459,9 @@ class CheckData extends Command ->havingRaw('count(invitations.id) = 0') ->get(['invoices.id', 'invoices.user_id', 'invoices.account_id', 'invoices.client_id']); - $this->logMessage(count($invoices) . ' invoices without any invitations'); + $this->logMessage($invoices->count() . ' invoices without any invitations'); - if (count($invoices) > 0) { + if ($invoices->count() > 0) { $this->isValid = false; } @@ -469,6 +505,10 @@ class CheckData extends Command ENTITY_INVOICE, ENTITY_CLIENT, ENTITY_USER, + ENTITY_TASK_STATUS, + ], + 'task_statuses' => [ + ENTITY_USER, ], 'credits' => [ ENTITY_CLIENT, @@ -496,6 +536,25 @@ class CheckData extends Command ENTITY_USER, ENTITY_CLIENT, ], + 'proposals' => [ + ENTITY_USER, + ENTITY_INVOICE, + ENTITY_PROPOSAL_TEMPLATE, + ], + 'proposal_categories' => [ + ENTITY_USER, + ], + 'proposal_templates' => [ + ENTITY_USER, + ], + 'proposal_snippets' => [ + ENTITY_USER, + ENTITY_PROPOSAL_CATEGORY, + ], + 'proposal_invitations' => [ + ENTITY_USER, + ENTITY_PROPOSAL, + ], ]; foreach ($tables as $table => $entityTypes) { @@ -512,9 +571,9 @@ class CheckData extends Command ->where("{$table}.{$accountId}", '!=', DB::raw("{$tableName}.account_id")) ->get(["{$table}.id"]); - if (count($records)) { + if ($records->count()) { $this->isValid = false; - $this->logMessage(count($records) . " {$table} records with incorrect {$entityType} account id"); + $this->logMessage($records->count() . " {$table} records with incorrect {$entityType} account id"); if ($this->option('fix') == 'true') { foreach ($records as $record) { @@ -549,9 +608,9 @@ class CheckData extends Command ->groupBy('clients.id') ->havingRaw('clients.paid_to_date != sum(coalesce(payments.amount - payments.refunded, 0)) and clients.paid_to_date != 999999999.9999') ->get(['clients.id', 'clients.paid_to_date', DB::raw('sum(coalesce(payments.amount - payments.refunded, 0)) as amount')]); - $this->logMessage(count($clients) . ' clients with incorrect paid to date'); + $this->logMessage($clients->count() . ' clients with incorrect paid to date'); - if (count($clients) > 0) { + if ($clients->count() > 0) { $this->isValid = false; } @@ -580,9 +639,9 @@ class CheckData extends Command ->havingRaw('(invoices.amount - invoices.balance) != coalesce(sum(payments.amount - payments.refunded), 0)') ->get(['invoices.id', 'invoices.amount', 'invoices.balance', DB::raw('coalesce(sum(payments.amount - payments.refunded), 0)')]); - $this->logMessage(count($invoices) . ' invoices with incorrect balances'); + $this->logMessage($invoices->count() . ' invoices with incorrect balances'); - if (count($invoices) > 0) { + if ($invoices->count() > 0) { $this->isValid = false; } } @@ -608,9 +667,9 @@ class CheckData extends Command $clients = $clients->groupBy('clients.id', 'clients.balance') ->orderBy('accounts.company_id', 'DESC') ->get(['accounts.company_id', 'clients.account_id', 'clients.id', 'clients.balance', 'clients.paid_to_date', DB::raw('sum(invoices.balance) actual_balance')]); - $this->logMessage(count($clients) . ' clients with incorrect balance/activities'); + $this->logMessage($clients->count() . ' clients with incorrect balance/activities'); - if (count($clients) > 0) { + if ($clients->count() > 0) { $this->isValid = false; } diff --git a/app/Console/Commands/InitLookup.php b/app/Console/Commands/InitLookup.php index f37de078be2f..7caf1944fe81 100644 --- a/app/Console/Commands/InitLookup.php +++ b/app/Console/Commands/InitLookup.php @@ -360,6 +360,7 @@ class InitLookup extends Command DB::statement('truncate lookup_users'); DB::statement('truncate lookup_contacts'); DB::statement('truncate lookup_invitations'); + DB::statement('truncate lookup_proposal_invitations'); DB::statement('truncate lookup_account_tokens'); DB::statement('SET FOREIGN_KEY_CHECKS = 1'); } diff --git a/app/Console/Commands/RemoveOrphanedDocuments.php b/app/Console/Commands/RemoveOrphanedDocuments.php index c6d921424027..f53e1f6ac082 100644 --- a/app/Console/Commands/RemoveOrphanedDocuments.php +++ b/app/Console/Commands/RemoveOrphanedDocuments.php @@ -32,7 +32,7 @@ class RemoveOrphanedDocuments extends Command $documents = Document::whereRaw('invoice_id IS NULL AND expense_id IS NULL AND updated_at <= ?', [new DateTime('-1 hour')]) ->get(); - $this->info(count($documents).' orphaned document(s) found'); + $this->info($documents->count() . ' orphaned document(s) found'); foreach ($documents as $document) { $document->delete(); diff --git a/app/Console/Commands/SendRecurringInvoices.php b/app/Console/Commands/SendRecurringInvoices.php index 65c87bb5dc94..533f14d3c0ae 100644 --- a/app/Console/Commands/SendRecurringInvoices.php +++ b/app/Console/Commands/SendRecurringInvoices.php @@ -98,7 +98,7 @@ class SendRecurringInvoices extends Command ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND is_recurring IS TRUE AND is_public IS TRUE AND frequency_id > 0 AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today]) ->orderBy('id', 'asc') ->get(); - $this->info(count($invoices).' recurring invoice(s) found'); + $this->info($invoices->count() . ' recurring invoice(s) found'); foreach ($invoices as $recurInvoice) { $shouldSendToday = $recurInvoice->shouldSendToday(); @@ -140,7 +140,7 @@ class SendRecurringInvoices extends Command [$today->format('Y-m-d')]) ->orderBy('invoices.id', 'asc') ->get(); - $this->info(count($delayedAutoBillInvoices).' due recurring invoice instance(s) found'); + $this->info($delayedAutoBillInvoices->count() . ' due recurring invoice instance(s) found'); /** @var Invoice $invoice */ foreach ($delayedAutoBillInvoices as $invoice) { @@ -165,7 +165,7 @@ class SendRecurringInvoices extends Command ->whereRaw('is_deleted IS FALSE AND deleted_at IS NULL AND start_date <= ? AND (end_date IS NULL OR end_date >= ?)', [$today, $today]) ->orderBy('id', 'asc') ->get(); - $this->info(count($expenses).' recurring expenses(s) found'); + $this->info($expenses->count() . ' recurring expenses(s) found'); foreach ($expenses as $expense) { $shouldSendToday = $expense->shouldSendToday(); diff --git a/app/Console/Commands/SendReminders.php b/app/Console/Commands/SendReminders.php index 9e3a5640e506..480b2dfabd31 100644 --- a/app/Console/Commands/SendReminders.php +++ b/app/Console/Commands/SendReminders.php @@ -92,7 +92,7 @@ class SendReminders extends Command private function chargeLateFees() { $accounts = $this->accountRepo->findWithFees(); - $this->info(count($accounts) . ' accounts found with fees'); + $this->info($accounts->count() . ' accounts found with fees'); foreach ($accounts as $account) { if (! $account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) { @@ -100,7 +100,7 @@ class SendReminders extends Command } $invoices = $this->invoiceRepo->findNeedingReminding($account, false); - $this->info($account->name . ': ' . count($invoices) . ' invoices found'); + $this->info($account->name . ': ' . $invoices->count() . ' invoices found'); foreach ($invoices as $invoice) { if ($reminder = $account->getInvoiceReminder($invoice, false)) { @@ -128,7 +128,7 @@ class SendReminders extends Command // standard reminders $invoices = $this->invoiceRepo->findNeedingReminding($account); - $this->info($account->name . ': ' . count($invoices) . ' invoices found'); + $this->info($account->name . ': ' . $invoices->count() . ' invoices found'); foreach ($invoices as $invoice) { if ($reminder = $account->getInvoiceReminder($invoice)) { @@ -142,7 +142,7 @@ class SendReminders extends Command // endless reminders $invoices = $this->invoiceRepo->findNeedingEndlessReminding($account); - $this->info($account->name . ': ' . count($invoices) . ' endless invoices found'); + $this->info($account->name . ': ' . $invoices->count() . ' endless invoices found'); foreach ($invoices as $invoice) { if ($invoice->last_sent_date == date('Y-m-d')) { @@ -159,7 +159,7 @@ class SendReminders extends Command $scheduledReports = ScheduledReport::where('send_date', '<=', date('Y-m-d')) ->with('user', 'account.company') ->get(); - $this->info(count($scheduledReports) . ' scheduled reports'); + $this->info($scheduledReports->count() . ' scheduled reports'); foreach ($scheduledReports as $scheduledReport) { $user = $scheduledReport->user; diff --git a/app/Console/Commands/SendRenewalInvoices.php b/app/Console/Commands/SendRenewalInvoices.php index ce661153fb3f..dcd1bcc2e018 100644 --- a/app/Console/Commands/SendRenewalInvoices.php +++ b/app/Console/Commands/SendRenewalInvoices.php @@ -60,10 +60,10 @@ class SendRenewalInvoices extends Command $companies = Company::whereRaw("datediff(plan_expires, curdate()) = 10 and (plan = 'pro' or plan = 'enterprise')") ->orderBy('id') ->get(); - $this->info(count($companies).' companies found renewing in 10 days'); + $this->info($companies->count() . ' companies found renewing in 10 days'); foreach ($companies as $company) { - if (! count($company->accounts)) { + if (! $company->accounts->count()) { continue; } diff --git a/app/Console/Commands/stubs/scaffold/provider.stub b/app/Console/Commands/stubs/scaffold/provider.stub index 048eaddf70a6..145464efeb05 100755 --- a/app/Console/Commands/stubs/scaffold/provider.stub +++ b/app/Console/Commands/stubs/scaffold/provider.stub @@ -28,10 +28,10 @@ class $CLASS$ extends AuthServiceProvider * * @return void */ - public function boot(GateContract $gate) + public function boot() { - parent::boot($gate); - + parent::boot(); + $this->registerTranslations(); $this->registerConfig(); $this->registerViews(); diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index f43e8fafaa3e..99b6c0a82135 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -53,17 +53,5 @@ class Kernel extends ConsoleKernel ->command('ninja:send-reminders --force') ->sendOutputTo($logFile) ->daily(); - - if (Utils::isNinja()) { - $schedule - ->command('ninja:send-renewals --force') - ->sendOutputTo($logFile) - ->daily(); - } - - $schedule - ->command('updater:check-for-update --prefixVersionWith=v') - ->sendOutputTo($logFile) - ->daily(); } } diff --git a/app/Constants.php b/app/Constants.php index 11017db15a0b..03f5e1429fb1 100644 --- a/app/Constants.php +++ b/app/Constants.php @@ -42,6 +42,11 @@ if (! defined('APP_NAME')) { define('ENTITY_RECURRING_EXPENSE', 'recurring_expense'); define('ENTITY_CUSTOMER', 'customer'); define('ENTITY_SUBSCRIPTION', 'subscription'); + define('ENTITY_PROPOSAL', 'proposal'); + define('ENTITY_PROPOSAL_TEMPLATE', 'proposal_template'); + define('ENTITY_PROPOSAL_SNIPPET', 'proposal_snippet'); + define('ENTITY_PROPOSAL_CATEGORY', 'proposal_category'); + define('ENTITY_PROPOSAL_INVITATION', 'proposal_invitation'); define('INVOICE_TYPE_STANDARD', 1); define('INVOICE_TYPE_QUOTE', 2); @@ -153,6 +158,7 @@ if (! defined('APP_NAME')) { define('MAX_DOCUMENT_SIZE', env('MAX_DOCUMENT_SIZE', 10000)); // KB define('MAX_EMAIL_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 10000)); // Total KB define('MAX_ZIP_DOCUMENTS_SIZE', env('MAX_EMAIL_DOCUMENTS_SIZE', 30000)); // Total KB (uncompressed) + define('MAX_EMAILS_SENT_PER_HOUR', 90); define('DOCUMENT_PREVIEW_SIZE', env('DOCUMENT_PREVIEW_SIZE', 300)); // pixels define('DEFAULT_FONT_SIZE', 9); define('DEFAULT_HEADER_FONT', 1); // Roboto @@ -290,6 +296,7 @@ if (! defined('APP_NAME')) { define('GATEWAY_DWOLLA', 43); define('GATEWAY_CHECKOUT_COM', 47); define('GATEWAY_CYBERSOURCE', 49); + define('GATEWAY_PAYTRACE', 56); define('GATEWAY_WEPAY', 60); define('GATEWAY_BRAINTREE', 61); define('GATEWAY_CUSTOM', 62); @@ -331,7 +338,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', '4.1.5' . env('NINJA_VERSION_SUFFIX')); + define('NINJA_VERSION', '4.2.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')); @@ -452,6 +459,7 @@ if (! defined('APP_NAME')) { define('TEMPLATE_INVOICE', 'invoice'); define('TEMPLATE_QUOTE', 'quote'); + define('TEMPLATE_PROPOSAL', 'proposal'); define('TEMPLATE_PARTIAL', 'partial'); define('TEMPLATE_PAYMENT', 'payment'); define('TEMPLATE_REMINDER1', 'reminder1'); @@ -517,6 +525,9 @@ if (! defined('APP_NAME')) { define('PLAN_TERM_MONTHLY', 'month'); define('PLAN_TERM_YEARLY', 'year'); + define('SUBSCRIPTION_FORMAT_JSON', 'JSON'); + define('SUBSCRIPTION_FORMAT_UBL', 'UBL'); + // Pro define('FEATURE_CUSTOMIZE_INVOICE_DESIGN', 'customize_invoice_design'); define('FEATURE_REMOVE_CREATED_BY', 'remove_created_by'); @@ -602,7 +613,6 @@ if (! defined('APP_NAME')) { 'dateFormats' => 'App\Models\DateFormat', 'datetimeFormats' => 'App\Models\DatetimeFormat', 'languages' => 'App\Models\Language', - 'paymentTerms' => 'App\Models\PaymentTerm', 'paymentTypes' => 'App\Models\PaymentType', 'countries' => 'App\Models\Country', 'invoiceDesigns' => 'App\Models\InvoiceDesign', diff --git a/app/Events/SubdomainWasRemoved.php b/app/Events/SubdomainWasRemoved.php new file mode 100644 index 000000000000..ef0a1a2a969c --- /dev/null +++ b/app/Events/SubdomainWasRemoved.php @@ -0,0 +1,21 @@ +account = $account; + } +} diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 54df4167eab3..bdaf103dd36e 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -2,7 +2,6 @@ namespace App\Exceptions; -use Crawler; use Exception; use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\Access\AuthorizationException; @@ -51,11 +50,12 @@ class Handler extends ExceptionHandler return false; } - if (! class_exists('Utils')) { + // if these classes don't exist the install is broken, maybe due to permissions + if (! class_exists('Utils') || ! class_exists('Crawler')) { return parent::report($e); } - if (Crawler::isCrawler()) { + if (\Crawler::isCrawler()) { return false; } diff --git a/app/Http/Controllers/AccountApiController.php b/app/Http/Controllers/AccountApiController.php index dc6c335cc887..91184eb68183 100644 --- a/app/Http/Controllers/AccountApiController.php +++ b/app/Http/Controllers/AccountApiController.php @@ -184,12 +184,10 @@ class AccountApiController extends BaseAPIController $devices = json_decode($account->devices, true); - foreach($devices as $key => $value) + for($x=0; $xtoken == $value['token']) - unset($devices[$key]); - + if($request->token == $devices[$x]['token']) + unset($devices[$x]); } $account->devices = json_encode(array_values($devices)); diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php index f1b3041de441..c86bb1aef975 100644 --- a/app/Http/Controllers/AccountController.php +++ b/app/Http/Controllers/AccountController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Events\SubdomainWasRemoved; use App\Events\SubdomainWasUpdated; use App\Events\UserSettingsChanged; use App\Events\UserSignedUp; @@ -105,6 +106,7 @@ class AccountController extends BaseController public function getStarted() { $user = false; + $account = false; $guestKey = Input::get('guest_key'); // local storage key to login until registered if (Auth::check()) { @@ -131,7 +133,13 @@ class AccountController extends BaseController Auth::login($user, true); event(new UserSignedUp()); - $redirectTo = Input::get('redirect_to') ? SITE_URL . '/' . ltrim(Input::get('redirect_to'), '/') : 'invoices/create'; + if ($account && $account->language_id && $account->language_id != DEFAULT_LANGUAGE) { + $link = link_to('/invoices/create?lang=en', 'click here'); + $message = sprintf('Your account language has been set automatically, %s to change to English', $link); + Session::flash('warning', $message); + } + + $redirectTo = Input::get('redirect_to') ? SITE_URL . '/' . ltrim(Input::get('redirect_to'), '/') : 'dashboard'; return Redirect::to($redirectTo)->with('sign_up', Input::get('sign_up')); } @@ -177,7 +185,7 @@ class AccountController extends BaseController $days_total = $planDetails['paid']->diff($planDetails['expires'])->days; $percent_used = $days_used / $days_total; - $credit = floatval($company->payment->amount) * (1 - $percent_used); + $credit = round(floatval($company->payment->amount) * (1 - $percent_used), 2); } if ($newPlan['price'] > $credit) { @@ -186,6 +194,10 @@ class AccountController extends BaseController } else { if ($plan == PLAN_FREE) { $company->discount = 0; + + $ninjaClient = $this->accountRepo->getNinjaClient($account); + $ninjaClient->send_reminders = false; + $ninjaClient->save(); } else { $company->plan_term = $term; $company->plan_price = $newPlan['price']; @@ -288,13 +300,18 @@ class AccountController extends BaseController } elseif ($section === ACCOUNT_SYSTEM_SETTINGS) { return self::showSystemSettings(); } else { + $view = "accounts.{$section}"; + if (! view()->exists($view)) { + return redirect('/settings/company_details'); + } + $data = [ 'account' => Account::with('users')->findOrFail(Auth::user()->account_id), 'title' => trans("texts.{$section}"), 'section' => $section, ]; - return View::make("accounts.{$section}", $data); + return View::make($view, $data); } } @@ -392,6 +409,10 @@ class AccountController extends BaseController */ public function showUserDetails() { + if (! auth()->user()->registered) { + return redirect('/')->withError(trans('texts.sign_up_to_save')); + } + $oauthLoginUrls = []; foreach (AuthService::$providers as $provider) { $oauthLoginUrls[] = ['label' => $provider, 'url' => URL::to('/auth/'.strtolower($provider))]; @@ -448,7 +469,7 @@ class AccountController extends BaseController { $account = Auth::user()->account; $account->load('account_gateways'); - $count = count($account->account_gateways); + $count = $account->account_gateways->count(); $trashedCount = AccountGateway::scope()->withTrashed()->count(); if ($accountGateway = $account->getGatewayConfig(GATEWAY_STRIPE)) { @@ -539,11 +560,25 @@ class AccountController extends BaseController $client->vat_number = $account->vat_number ? '1234567890' : ''; $client->id_number = $account->id_number ? '1234567890' : ''; + if ($account->custom_client_label1) { + $client->custom_value1 = '0000'; + } + if ($account->custom_client_label2) { + $client->custom_value2 = '0000'; + } + $invoice->invoice_number = '0000'; $invoice->invoice_date = Utils::fromSqlDate(date('Y-m-d')); $invoice->account = json_decode($account->toJson()); $invoice->amount = $invoice->balance = 100; + if ($account->custom_invoice_text_label1) { + $invoice->custom_text_value1 = '0000'; + } + if ($account->custom_invoice_text_label2) { + $invoice->custom_text_value2 = '0000'; + } + $invoice->terms = trim($account->invoice_terms); $invoice->invoice_footer = trim($account->invoice_footer); @@ -556,6 +591,16 @@ class AccountController extends BaseController $invoiceItem->qty = 1; $invoiceItem->notes = 'Notes'; $invoiceItem->product_key = 'Item'; + $invoiceItem->discount = 10; + $invoiceItem->tax_name1 = 'Tax'; + $invoiceItem->tax_rate1 = 10; + + if ($account->custom_invoice_item_label1) { + $invoiceItem->custom_value1 = '0000'; + } + if ($account->custom_invoice_item_label2) { + $invoiceItem->custom_value2 = '0000'; + } $document->base64 = 'data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAyAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNBCUAAAAAABAAAAAAAAAAAAAAAAAAAAAA/+4AIUFkb2JlAGTAAAAAAQMAEAMDBgkAAAW8AAALrQAAEWf/2wCEAAgGBgYGBggGBggMCAcIDA4KCAgKDhANDQ4NDRARDA4NDQ4MEQ8SExQTEg8YGBoaGBgjIiIiIycnJycnJycnJycBCQgICQoJCwkJCw4LDQsOEQ4ODg4REw0NDg0NExgRDw8PDxEYFhcUFBQXFhoaGBgaGiEhICEhJycnJycnJycnJ//CABEIAGQAlgMBIgACEQEDEQH/xADtAAABBQEBAAAAAAAAAAAAAAAAAQIDBAUGBwEBAAMBAQEAAAAAAAAAAAAAAAIDBAUBBhAAAQQCAQMDBQEAAAAAAAAAAgABAwQRBRIQIBMwIQYxIiMUFUARAAIBAgMFAwgHBwUBAAAAAAECAwARIRIEMUFRYROhIkIgcYGRsdFSIzDBMpKyFAVA4WJyM0MkUPGiU3OTEgABAgQBCQYEBwAAAAAAAAABEQIAITESAyBBUWFxkaGxIhAwgdEyE8HxYnLw4UJSgiMUEwEAAgIBAwQCAwEBAAAAAAABABEhMVFBYXEQgZGhILEwwdHw8f/aAAwDAQACEQMRAAAA9ScqiDlGjgRUUcqSCOVfTEeETZI/TABQBHCxAiDmcvz1O3rM7i7HG29J1nGW6c/ZO4i1ry9ZZwJOzk2Gc11N8YVe6FsZKEQqwR8v0vnEpz4isza7FaovCjNThxulztSxiz6597PwkfQ99R6vxT0S7N2yuXJpQceKrkIq3L9kK/OuR9F8rpjCsmdZXLUN+H0Obp9Hp8azkdPd1q58T21bV6XK6dcjW2UPGl0amXp5VdnIV3c5n6t508/srbbd+3Hbl2Ib8GXV2E59tXOvLwNmfv5sueVzWhPqsNggNdcKwOifnXlS4iDvkho4bP8ASEeyPrpZktFYLMbCPudZsNzzcsTdVc5CemqECqHoAEQBABXAOABAGtD0AH//2gAIAQIAAQUB9TkSnkPEFiKNhvcnhfysQuPbJwZijLkNUGZicWCZ3X1DsIRdZZlnKmPMnOImhsWBQSifR/o7sy+5fb0OIuU8EblCBxtFGQv14ssdjQxMXqf/2gAIAQMAAQUB9Qa5LwxipBck8bMjIY0BsXYJ4Q2QT2BdFK7uMGW/QJmKIo5OrimGZ0MDm4xjEw+PMhDibBi7Y6DjkIkT/iZn8uEzoSLBYdE7dcrzGmkFn68nx6n/2gAIAQEAAQUB9HCwsLHq5XJkxC/+ByZmsbSpCi2JG3GOM68rcOZOuU7IJuRJ+uFjsd8K1tCE55wIYpBYqrzHIAQlKdmty5KG6POC2RSTXwjUGxm8ywsLHX6KMJLrXNdLXCarQd4jeY5ZrHmLYwk0Vo5k85FJZlPjTOxYDySNa2H4wpTNYrLHZKQxhHJsHGzYsRFHe17KbYHI5tVZeGlxI67yOZmTx2wYbDpmsSu9iKCL49M/DtswNZrjb2GvjtW9XsY/EKliOSQXAXnaubRQ2JWoNJWvXbu1G0FmS0MOur+L+VPKNGs0FzvvaSjZUma8xwX5isVyhUFOWwUGg2LtV+OiSOnLAMNeig1tJ1Jr5RNor9Zq91pHz12N0dfTCtvbkcl7f6xr/wAjjvUKW3LgWv2VlRaXVg8NWnHG1aBNBaFmmtiQVDIJIJIyCyYEF1ibDSms9NlUa/THY7vXtb2tSzshj+JbBF8TeI/2vklNVvkVOeV61ck9SB1+qQLx3UVa9C47HDhHDJKEQw2eS5LKz0wzqbX1LCsfF6Mqajv6S/s7eurtmbeRg/EeS5LKyjCORnpCzxxNGsrksrKysrKysrKysrKysrKysrPXK917r3Xuvde/rf/aAAgBAgIGPwHvOlq6z0t3wbnNAFWg1+mS84LiQC6drJgfCJYTrf3UHlxhWA1T8GJ5KEF1aRb7YaD6cNovcmcn5xPDnXq6o9QaIQ9Z1S/OC3OyfgckXL/FxaeESBHjAkvARd7RxGNVtLgNJatYH+XG9p6+k9LdgFF2Q9uJhh7gJoUcQaEKoO8QUUJUGRG3slFSDrhQVifHsuY8jV6m7s3hDi9rsIn9Y6mH7tEe5h4oQuDNN2YIDDnPdc5yUCBBSU8jRsiuReGNu0pPvf/aAAgBAwIGPwHvFdLnEq6awBXWUhC8LojqcIlkETU6NEI5xJGq3eYJYiCpJQecJ7hI0Ycod/SVdS4pxcnKFb0pWrifhxgPUFuJ0+I05CgpEgHbacYAMytEoBXq+cG1zcMlM1x5+UTMzUhGkmEtKZ86iGNCMa1yyElHLtF1FnsijXN+kDdmi1zS3OLgUWJIn0JyHYhA5GJG7VQwhGZdkIM2Qh6vunzi4MC7Sm7IRe9//9oACAEBAQY/Af2u18eH7Bjsq2bO3wpjQUrldsRED3wvxGlkGpbvYAtgQeOHDzVYTdf+I7f+N/ZXcYX4Gx/CQeysYwfM1vxCspRkPP3j6MxQAYYGR9noG+i+q1Dtw8CUrRfNP2sO6gA8TE7qkeRMkUpvfHPMeWw5aMussuXBIr7uYW/qoJFpgzHYcAMOdXkyIN1+9b0sbVkXW7d+FhblsrLJKGTaGAC+uu4Q5pV1GQxObBk8J3X+g6rgvcmwZssY5ALiaZxNg7fZC4JzBONXn62olH/YTl7KJy5kG24GUEbBYbbbhXXDBpVwyKLqF3hicMaPX06cdpAvzzHGm6EkcEY4WUdgzH0CssbjUMONx3ud8ppRPpelN4Zdg9GXbSZFjY+IsQT90mo5XcRMD0mVAtrfFaszsGK3ubANy+ztxqOXiMfP5TPJgqgsTyFGXTuNPBISVVw5w43AIpfzMqzq++KS34lwodXSl5PCSc/Ze1dOJQFawyLhbje9hQSR3aTeLgKvIZb+2nZ5cbd1AM3o3UhddgtfxYbMBWWOMkbl/wBsTV54nEe0KFbtNArkj4bj7GolXTL8Ze1z671G6SNK4/qxnvxm+BymwtUulP8AbN18x8qSC9uopW/npYtVozLHGMomgN8Bh9miA/SnA7okGUE8G3dtG36fKrn+7G90B4gi+FWnMmYWsxxJvwzWvsoxh2yri4Pd5bi9Hpl5bDFU7q+ktc9lHoBQvEkAe+o1lkUByEkZTsW/xCpAJzB02ISFLgADZev8zRpqD8QBVv8A6Jann0yNplkFssq9RVIO0MmK7N4oMZBKhPe6FmHZa3qqPKdkdpBwPD6Bpf6L4szqbDmTfCsn6fqGmO54wV9m2upqcyse6WlNvRdhXSzJlOLMDm9GFZNMjytwQfXWX8uYv59nrx9lP+aPUbYFUlFHp2mguqTqxKLJK+LKP/VMfWKvKrsu5y5ZfWmFdTRytAx8UbYdtxQMpDFjhqYflSA7s4XBquttRz2NaunIpR+DeRJqiuYrgq8WOAoaiXVPEzYqkZCKOVt9X1DJPFsvKMp+8hqTStE0Er2xBDobG5FxY40kGi02nifZfMSSfNtr/OlcRHwxKO0A3q8smduDfL/FXTiQCPbbKHHrF6+WbH+B3TsufZRyTSfyu1/usR7ayPKM3wulj2VnAVGOJTZjxBGNZiuVvi+w331wPprLIbkbn7resd013hbz4fupbDYb38iTTE2z7DzGIoJrNN+ZjXDOO61h5rg0mp1Wmkk0yplEDG2Vt5wwNWH+NIdxJj9t1pZ/0/V5WQhk6gvzGI91fP0sesUeKI5W9X7qXTauJ9JM2AWYd0nhermNb+a3srxfeP118qdhyYBhWEkf81jf1Vnim658QfA+giulqUyNwbC/1GiLfLOOU7jypek3d8Q3Vw8r5sKt6PdV4i0Z5Yjtq2k1YmQbI5cfxe+ra39OLD44fd3qXSQaJ0uwJnlFsluFBSb2Fr+TldQw518pynLaO2rli7cT9Q/0r//aAAgBAgMBPxD8BHIj4/gUu+n/AKDL7Eqh2LDnpJp36uxcBVJSQBqzju2/1Mo/rVB3tkuO1ZHHZYne4pQ3+A1jS9SIA5pdrL6FN29E1HHIwAiNNrOl06RtUaBbO7u6gApbHBXuAv3EB7MGADleztFGRKsm7wY7RPX6jyyGlEcPVK65Tfd263KMLBdl5vh/uDZC0O5wdmKVo4YKKAOVMbNnutFAI9eEuQ4e6ahKuKj2+B/en0tbqrHmAfYICaGFNJdQyMh/5uV4l03drL4SfIR6aL1b1BlPXXmNhFlAM7NwL0U7zACUS0VtC3J6+u9zqhb2fqLSlI+JcuIO5SQ4R9ofyf/aAAgBAwMBPxD+RAWF0BeXwHuzQV9CbX26fUGyI3Q+OsxIrVsvtv6l5UovefjcHV637+PwAhSpEW03npcCcYFf6CUJoVSLxaKfBDaWsSw47vyTCEodeVls2/8AUQ7CBsMHauvOIZ9gwKrOdefH4MthVWOO9y9BzaCnDeJ8kzpIwbaLNkqtAQS0QFwTYlN+IQGULuC0pXHSWlpFWocCQV3A4dhwVblrrFrfXSZH08asO7MfiaKWfA2PeN7MUMgK5fu4Urrgge+T6jfLDqw7/wBkMAgG2DxzG9uzsd1xQBRbbbn1ENij2hXaE6AkMCOSsjnKOW/Qai9iTi/5f//aAAgBAQMBPxAIEqVKlSpUCEHoUiRjGX6BAlSpUqIIaIhUI6G34hXMIeiRjE9OkqB63HygG1aCOt3TKzCFkCino59iplOlzY8tvCMIxuwf0/mBqJ40DUb89L4/sgg43QRGuFT0ESVfo0gRlyha0dVlpKlKrm6raQySjYol1lVfgj8C3g6iJbHNxPeAW9yDaQdgrpMZAK1eq2o7Q7EFEVS8X6HaIQYrdr7U0YQobDxRja4mPhsgnSp/cLbjYA4K51OOKoU0zRiegjSEq4oFegvxGpy4QRr5JcRHqajXulVBqlghaxQnLR092G41E0g3djqcHWMXuExr0VmhZdW7FsLT+gynKYpXXjGV7wreJppoapXL7oQD0sBYvCAX4tIpESrHmFyooWQqCbMCN1vpBgtacBgtAYVZcF7afsYf9lQisQlRdvDkWyqGZBthXx7RPvKkUrlb5Q/CrdFT5neoWdIZSWgR/VBQwZ0nUGPeBAJdZvWE38qghbIlumjVcdMzdAL5o/BAVDYFa5xT2qVhDQIAA5pB+5aemryoxhX0jk3pALPvUXhzAK5y/XUnskCEqEqMLSHNUwwLAQBRotLMeIdlDn5FpRZUUm5R2ZJ7EpNZRMobAO5K5hOAUuBYHYG+8SddNHz0+EKEOCcKzlT1BZYb4uB90OpYUAVM2rcL3vCknNK+bjWGKs6bZa9oVhmRdpg/YWAAlUVJkcjdXD11Lgke0VcU2MbHfygaFKWEnTL5GJZzMyGuGMPMbSQlbPagPOZaKOHjusEyaLtXgeW3iK4+oDc4bNYnwcKiQaks/Caxh5wK7kdeZvb3LEJhAMqbKrhAqim522Qv5gPgqp9FxlL7mnZpXi3MxIMgDkG/ug65qHbsEF8zXvjwBFAU4jmwArRmKjV6XLdNd1TvoiF1X5vX/fMHBChWDvd+4paeJz4FDgzLjs70CdhHznQBjzv7Sxo8bd2NfcZmYNWs8RxQGYGe1+olGV9n7Z+0UPFyYwlYvmDNJctGQPGwnyQAWPv0haPhQ4abtsUxZfaFBalqvypK8pGizJpYO+aShBw+h2xgHf3CNeSAXzRnTRxS/szKo3P+IMAszsGE7iUiOwZy99tXZg3BCqz2L+qH0gU09RzxfaMDrstvwgKoDsPRrCLj7jcKSy6oH5pLZC0I+L/UPAvRNDQUa9oMU7aNedH3NWIKBWuO+m4lsAS60VfopKsCajNR6AT7l8D418EaQCisod0YIUK9U/PBh6loQegqKly/QfkBmNzMzM/i+jOk/9k='; @@ -587,21 +632,6 @@ class AccountController extends BaseController } else { $data['customDesign'] = $design; } - - // sample invoice to help determine variables - $invoice = Invoice::scope() - ->invoiceType(INVOICE_TYPE_STANDARD) - ->with('client', 'account') - ->where('is_recurring', '=', false) - ->first(); - - if ($invoice) { - $invoice->hidePrivateFields(); - unset($invoice->account); - unset($invoice->invoice_items); - unset($invoice->client->contacts); - $data['sampleInvoice'] = $invoice; - } } return View::make("accounts.{$section}", $data); @@ -733,7 +763,7 @@ class AccountController extends BaseController return $font->id == $account->header_font_id || $font->id == $account->body_font_id; }); - if ($account->live_preview && count($fonts)) { + if ($account->live_preview && $fonts->count()) { $account->live_preview = false; Session::flash('warning', trans('texts.live_preview_disabled')); } @@ -784,18 +814,27 @@ class AccountController extends BaseController } } + + (bool) $fireUpdateSubdomainEvent = false; + if ($account->subdomain !== $request->subdomain) { - event(new SubdomainWasUpdated($account)); + $fireUpdateSubdomainEvent = true; + event(new SubdomainWasRemoved($account)); } $account->fill($request->all()); $account->client_view_css = $request->client_view_css; - $account->subdomain = $request->subdomain; + $account->subdomain = $request->subdomain; $account->iframe_url = $request->iframe_url; $account->save(); + if ($fireUpdateSubdomainEvent) { + event(new SubdomainWasUpdated($account)); + } + + return redirect('settings/' . ACCOUNT_CLIENT_PORTAL) - ->with('message', trans('texts.updated_settings')); + ->with('message', trans('texts.updated_settings')); } /** @@ -812,7 +851,7 @@ class AccountController extends BaseController $settings->save(); return redirect('settings/' . ACCOUNT_EMAIL_SETTINGS) - ->with('message', trans('texts.updated_settings')); + ->with('message', trans('texts.updated_settings')); } /** @@ -967,8 +1006,8 @@ class AccountController extends BaseController } if (! $account->share_counter - && $account->invoice_number_prefix == $account->quote_number_prefix - && $account->invoice_number_pattern == $account->quote_number_pattern) { + && $account->invoice_number_prefix == $account->quote_number_prefix + && $account->invoice_number_pattern == $account->quote_number_pattern) { Session::flash('error', trans('texts.invalid_counter')); return Redirect::to('settings/'.ACCOUNT_INVOICE_SETTINGS)->withInput(); @@ -1271,8 +1310,8 @@ class AccountController extends BaseController } $email = User::withTrashed()->where('email', '=', $email) - ->where('id', '<>', $user->registered ? 0 : $user->id) - ->first(); + ->where('id', '<>', $user->registered ? 0 : $user->id) + ->first(); if ($email) { return 'taken'; @@ -1480,8 +1519,8 @@ class AccountController extends BaseController { $template = Input::get('template'); $invitation = \App\Models\Invitation::scope() - ->with('invoice.client.contacts') - ->first(); + ->with('invoice.client.contacts') + ->first(); if (! $invitation) { return trans('texts.create_invoice_for_sample'); diff --git a/app/Http/Controllers/AccountGatewayController.php b/app/Http/Controllers/AccountGatewayController.php index 559840caaa2b..5a112b9baae7 100644 --- a/app/Http/Controllers/AccountGatewayController.php +++ b/app/Http/Controllers/AccountGatewayController.php @@ -152,7 +152,7 @@ class AccountGatewayController extends BaseController 'config' => false, 'gateways' => $gateways, 'creditCardTypes' => $creditCards, - 'countGateways' => count($currentGateways), + 'countGateways' => $currentGateways->count(), ]; } diff --git a/app/Http/Controllers/AppController.php b/app/Http/Controllers/AppController.php index f095ce9d1080..cb0b6ed3dcd3 100644 --- a/app/Http/Controllers/AppController.php +++ b/app/Http/Controllers/AppController.php @@ -175,14 +175,18 @@ class AppController extends BaseController $_ENV['DB_PASSWORD'] = $db['type']['password']; if ($mail) { - $_ENV['MAIL_DRIVER'] = $mail['driver']; - $_ENV['MAIL_PORT'] = $mail['port']; - $_ENV['MAIL_ENCRYPTION'] = $mail['encryption']; - $_ENV['MAIL_HOST'] = $mail['host']; - $_ENV['MAIL_USERNAME'] = $mail['username']; - $_ENV['MAIL_FROM_NAME'] = $mail['from']['name']; - $_ENV['MAIL_FROM_ADDRESS'] = $mail['from']['address']; - $_ENV['MAIL_PASSWORD'] = $mail['password']; + $prefix = ''; + if (($user = auth()->user()) && Account::count() > 1) { + $prefix = $user->account_id . '_'; + } + $_ENV[$prefix . 'MAIL_DRIVER'] = $mail['driver']; + $_ENV[$prefix . 'MAIL_PORT'] = $mail['port']; + $_ENV[$prefix . 'MAIL_ENCRYPTION'] = $mail['encryption']; + $_ENV[$prefix . 'MAIL_HOST'] = $mail['host']; + $_ENV[$prefix . 'MAIL_USERNAME'] = $mail['username']; + $_ENV[$prefix . 'MAIL_FROM_NAME'] = $mail['from']['name']; + $_ENV[$prefix . 'MAIL_FROM_ADDRESS'] = $mail['from']['address']; + $_ENV[$prefix . 'MAIL_PASSWORD'] = $mail['password']; $_ENV['MAILGUN_DOMAIN'] = $mail['mailgun_domain']; $_ENV['MAILGUN_SECRET'] = $mail['mailgun_secret']; } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index eb2e6d8cc293..f99fc56e397b 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -4,7 +4,6 @@ namespace App\Http\Controllers\Auth; use Event; use Illuminate\Http\Request; -use App\Models\PasswordReset; use App\Events\UserLoggedIn; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; diff --git a/app/Http/Controllers/BankAccountController.php b/app/Http/Controllers/BankAccountController.php index 8b0bdba22281..7295e931211e 100644 --- a/app/Http/Controllers/BankAccountController.php +++ b/app/Http/Controllers/BankAccountController.php @@ -92,9 +92,11 @@ class BankAccountController extends BaseController if ($publicId) { $bankAccount = BankAccount::scope($publicId)->firstOrFail(); if ($username != $bankAccount->username) { - // TODO update username + $bankAccount->setUsername($username); + $bankAccount->save(); + } else { + $username = Crypt::decrypt($username); } - $username = Crypt::decrypt($username); $bankId = $bankAccount->bank_id; } else { $bankAccount = new BankAccount; diff --git a/app/Http/Controllers/BaseAPIController.php b/app/Http/Controllers/BaseAPIController.php index 35956179e4c0..5b59a5b38b8a 100644 --- a/app/Http/Controllers/BaseAPIController.php +++ b/app/Http/Controllers/BaseAPIController.php @@ -99,15 +99,17 @@ class BaseAPIController extends Controller $query->with($includes); - if ($updatedAt = intval(Input::get('updated_at'))) { - $query->where('updated_at', '>=', date('Y-m-d H:i:s', $updatedAt)); + if (Input::get('updated_at') > 0) { + $updatedAt = intval(Input::get('updated_at')); + $query->where('updated_at', '>=', date('Y-m-d H:i:s', $updatedAt)); } - - if ($clientPublicId = Input::get('client_id')) { - $filter = function ($query) use ($clientPublicId) { + + if (Input::get('client_id') > 0) { + $clientPublicId = Input::get('client_id'); + $filter = function ($query) use ($clientPublicId) { $query->where('public_id', '=', $clientPublicId); - }; - $query->whereHas('client', $filter); + }; + $query->whereHas('client', $filter); } if (! Utils::hasPermission('view_all')) { diff --git a/app/Http/Controllers/CalendarController.php b/app/Http/Controllers/CalendarController.php index 80abe6b2cd20..7911d8127994 100644 --- a/app/Http/Controllers/CalendarController.php +++ b/app/Http/Controllers/CalendarController.php @@ -15,6 +15,7 @@ class CalendarController extends BaseController public function showCalendar() { $data = [ + 'title' => trans('texts.calendar'), 'account' => auth()->user()->account, ]; diff --git a/app/Http/Controllers/ClientAuth/LoginController.php b/app/Http/Controllers/ClientAuth/LoginController.php index c264320a0639..d7fdc8c8c76d 100644 --- a/app/Http/Controllers/ClientAuth/LoginController.php +++ b/app/Http/Controllers/ClientAuth/LoginController.php @@ -58,7 +58,7 @@ class LoginController extends Controller public function showLoginForm() { $subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST')); - $hasAccountIndentifier = request()->account_key || ($subdomain && $subdomain != 'app'); + $hasAccountIndentifier = request()->account_key || ($subdomain && ! in_array($subdomain, ['www', 'app'])); if (! session('contact_key')) { if (Utils::isNinja()) { diff --git a/app/Http/Controllers/ClientAuth/ResetPasswordController.php b/app/Http/Controllers/ClientAuth/ResetPasswordController.php index 70dfbb1322c1..511c10cfa92e 100644 --- a/app/Http/Controllers/ClientAuth/ResetPasswordController.php +++ b/app/Http/Controllers/ClientAuth/ResetPasswordController.php @@ -4,7 +4,6 @@ namespace App\Http\Controllers\ClientAuth; use Password; use Config; -use App\Models\PasswordReset; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Http\Request; @@ -55,14 +54,8 @@ class ResetPasswordController extends Controller public function showResetForm(Request $request, $token = null) { - $passwordReset = PasswordReset::whereToken($token)->first(); - - if (! $passwordReset) { - return redirect('login')->withMessage(trans('texts.invalid_code')); - } - return view('clientauth.passwords.reset')->with( - ['token' => $token, 'email' => $passwordReset->email] + ['token' => $token] ); } diff --git a/app/Http/Controllers/ClientPortalController.php b/app/Http/Controllers/ClientPortalController.php index 92e04ecd77d5..a47e1a62f814 100644 --- a/app/Http/Controllers/ClientPortalController.php +++ b/app/Http/Controllers/ClientPortalController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers; use App\Events\InvoiceInvitationWasViewed; use App\Events\QuoteInvitationWasViewed; +use App\Models\Account; use App\Models\Contact; use App\Models\Document; use App\Models\Gateway; @@ -55,7 +56,7 @@ class ClientPortalController extends BaseController $this->taskRepo = $taskRepo; } - public function view($invitationKey) + public function viewInvoice($invitationKey) { if (! $invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { return $this->returnError(); @@ -76,8 +77,6 @@ class ClientPortalController extends BaseController ]); } - $account->loadLocalizationSettings($client); - if (! Input::has('phantomjs') && ! session('silent:' . $client->id) && ! Session::has($invitation->invitation_key) && (! Auth::check() || Auth::user()->account_id != $invoice->account_id)) { if ($invoice->isType(INVOICE_TYPE_QUOTE)) { @@ -117,10 +116,10 @@ class ClientPortalController extends BaseController // translate the country names if ($invoice->client->country) { - $invoice->client->country->name = trans('texts.country_' . $invoice->client->country->name); + $invoice->client->country->name = $invoice->client->country->getName(); } if ($invoice->account->country) { - $invoice->account->country->name = trans('texts.country_' . $invoice->account->country->name); + $invoice->account->country->name = $invoice->account->country->getName(); } $data = []; @@ -226,7 +225,7 @@ class ClientPortalController extends BaseController return $pdfString; } - public function sign($invitationKey) + public function authorizeInvoice($invitationKey) { if (! $invitation = $this->invoiceRepo->findInvoiceByInvitation($invitationKey)) { return RESULT_FAILURE; @@ -262,13 +261,13 @@ class ClientPortalController extends BaseController return redirect(request()->url()); } - $account->loadLocalizationSettings($client); $color = $account->primary_color ? $account->primary_color : '#0b4d78'; $customer = false; if (! $account->enable_client_portal) { return $this->returnError(); } elseif (! $account->enable_client_portal_dashboard) { + session()->reflash(); return redirect()->to('/client/invoices/'); } @@ -334,7 +333,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -368,7 +366,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -414,7 +411,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -499,7 +495,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -535,7 +530,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -571,7 +565,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $contact->client->show_tasks_in_portal) { return redirect()->to($account->enable_client_portal_dashboard ? '/client/dashboard' : '/client/payment_methods/'); @@ -611,7 +604,6 @@ class ClientPortalController extends BaseController } $account = $contact->account; - $account->loadLocalizationSettings($contact->client); if (! $account->enable_client_portal) { return $this->returnError(); @@ -962,4 +954,65 @@ class ClientPortalController extends BaseController return Redirect::to('client/invoices/recurring'); } + + public function showDetails() + { + if (! $contact = $this->getContact()) { + return $this->returnError(); + } + + $data = [ + 'contact' => $contact, + 'client' => $contact->client, + 'account' => $contact->account, + ]; + + return view('invited.details', $data); + } + + public function updateDetails(\Illuminate\Http\Request $request) + { + if (! $contact = $this->getContact()) { + return $this->returnError(); + } + + $client = $contact->client; + $account = $contact->account; + + if (! $account->enable_client_portal) { + return $this->returnError(); + } + + $rules = [ + 'email' => 'required', + 'address1' => 'required', + 'city' => 'required', + 'state' => 'required', + 'postal_code' => 'required', + 'country_id' => 'required', + ]; + + if ($client->name) { + $rules['name'] = 'required'; + } else { + $rules['first_name'] = 'required'; + $rules['last_name'] = 'required'; + } + if ($account->vat_number || $account->isNinjaAccount()) { + $rules['vat_number'] = 'required'; + } + + $this->validate($request, $rules); + + $contact->fill(request()->all()); + $contact->save(); + + $client->fill(request()->all()); + $client->save(); + + event(new \App\Events\ClientWasUpdated($client)); + + return redirect($account->enable_client_portal_dashboard ? '/client/dashboard' : '/client/payment_methods') + ->withMessage(trans('texts.updated_client_details')); + } } diff --git a/app/Http/Controllers/ClientPortalProposalController.php b/app/Http/Controllers/ClientPortalProposalController.php new file mode 100644 index 000000000000..1dd19ab9fc87 --- /dev/null +++ b/app/Http/Controllers/ClientPortalProposalController.php @@ -0,0 +1,70 @@ +propoosalRepo = $propoosalRepo; + } + + public function viewProposal($invitationKey) + { + if (! $invitation = $this->propoosalRepo->findInvitationByKey($invitationKey)) { + return $this->returnError(trans('texts.proposal_not_found')); + } + + $account = $invitation->account; + $proposal = $invitation->proposal; + $invoiceInvitation = Invitation::whereContactId($invitation->contact_id) + ->whereInvoiceId($proposal->invoice_id) + ->firstOrFail(); + + $data = [ + 'proposal' => $proposal, + 'account' => $account, + 'invoiceInvitation' => $invoiceInvitation, + 'proposalInvitation' => $invitation, + ]; + + return view('invited.proposal', $data); + } + + public function downloadProposal($invitationKey) + { + if (! $invitation = $this->propoosalRepo->findInvitationByKey($invitationKey)) { + return $this->returnError(trans('texts.proposal_not_found')); + } + + $proposal = $invitation->proposal; + + $mpdf = new mPDF(); + $mpdf->WriteHTML($proposal->present()->htmlDocument); + $mpdf->Output($proposal->present()->filename, 'D'); + } + + public function getProposalImage($accountKey, $documentKey) + { + $account = Account::whereAccountKey($accountKey) + ->firstOrFail(); + + $document = Document::whereAccountId($account->id) + ->whereDocumentKey($documentKey) + ->whereIsProposal(true) + ->firstOrFail(); + + return DocumentController::getDownloadResponse($document); + } +} diff --git a/app/Http/Controllers/DashboardApiController.php b/app/Http/Controllers/DashboardApiController.php index d87ea271392a..0ca7eb6475bc 100644 --- a/app/Http/Controllers/DashboardApiController.php +++ b/app/Http/Controllers/DashboardApiController.php @@ -43,12 +43,12 @@ class DashboardApiController extends BaseAPIController $data = [ 'id' => 1, - 'paidToDate' => count($paidToDate) && $paidToDate[0]->value ? $paidToDate[0]->value : 0, - 'paidToDateCurrency' => count($paidToDate) && $paidToDate[0]->currency_id ? $paidToDate[0]->currency_id : 0, - 'balances' => count($balances) && $balances[0]->value ? $balances[0]->value : 0, - 'balancesCurrency' => count($balances) && $balances[0]->currency_id ? $balances[0]->currency_id : 0, - 'averageInvoice' => count($averageInvoice) && $averageInvoice[0]->invoice_avg ? $averageInvoice[0]->invoice_avg : 0, - 'averageInvoiceCurrency' => count($averageInvoice) && $averageInvoice[0]->currency_id ? $averageInvoice[0]->currency_id : 0, + 'paidToDate' => $paidToDate->count() && $paidToDate[0]->value ? $paidToDate[0]->value : 0, + 'paidToDateCurrency' => $paidToDate->count() && $paidToDate[0]->currency_id ? $paidToDate[0]->currency_id : 0, + 'balances' => $balances->count() && $balances[0]->value ? $balances[0]->value : 0, + 'balancesCurrency' => $balances->count() && $balances[0]->currency_id ? $balances[0]->currency_id : 0, + 'averageInvoice' => $averageInvoice->count() && $averageInvoice[0]->invoice_avg ? $averageInvoice[0]->invoice_avg : 0, + 'averageInvoiceCurrency' => $averageInvoice->count() && $averageInvoice[0]->currency_id ? $averageInvoice[0]->currency_id : 0, 'invoicesSent' => $metrics ? $metrics->invoices_sent : 0, 'activeClients' => $metrics ? $metrics->active_clients : 0, 'activities' => $this->createCollection($activities, new ActivityTransformer(), ENTITY_ACTIVITY), diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php index 1d6f931099f9..d69b9f150c5d 100644 --- a/app/Http/Controllers/DashboardController.php +++ b/app/Http/Controllers/DashboardController.php @@ -83,7 +83,7 @@ class DashboardController extends BaseController 'tasks' => $tasks, 'showBlueVinePromo' => $showBlueVinePromo, 'showWhiteLabelExpired' => $showWhiteLabelExpired, - 'showExpenses' => count($expenses) && $account->isModuleEnabled(ENTITY_EXPENSE), + 'showExpenses' => $expenses->count() && $account->isModuleEnabled(ENTITY_EXPENSE), 'headerClass' => in_array(\App::getLocale(), ['lt', 'pl', 'cs', 'sl', 'tr_TR']) ? 'in-large' : 'in-thin', 'footerClass' => in_array(\App::getLocale(), ['lt', 'pl', 'cs', 'sl', 'tr_TR']) ? '' : 'in-thin', ]; diff --git a/app/Http/Controllers/DocumentController.php b/app/Http/Controllers/DocumentController.php index 28a544cb3dc5..4ed2ea0c095c 100644 --- a/app/Http/Controllers/DocumentController.php +++ b/app/Http/Controllers/DocumentController.php @@ -105,11 +105,20 @@ class DocumentController extends BaseController 'code' => 400, ], 400); } else { - return Response::json([ - 'error' => false, - 'document' => $doc_array, - 'code' => 200, - ], 200); + if ($request->grapesjs) { + $response = [ + 'data' => [ + $result->getProposalUrl() + ] + ]; + } else { + $response = [ + 'error' => false, + 'document' => $doc_array, + 'code' => 200, + ]; + } + return Response::json($response, 200); } } diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php index eb2d5d067757..e29c173c92b2 100644 --- a/app/Http/Controllers/HomeController.php +++ b/app/Http/Controllers/HomeController.php @@ -161,7 +161,7 @@ class HomeController extends BaseController } $subject .= '] '; } else { - $subject .= 'Self-Host | '; + $subject .= 'Self-Host] | '; } $subject .= date('M jS, g:ia'); $message->to(env('CONTACT_EMAIL', 'contact@invoiceninja.com')) diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php index 1510325c8d92..84e5666cf74d 100644 --- a/app/Http/Controllers/InvoiceApiController.php +++ b/app/Http/Controllers/InvoiceApiController.php @@ -68,6 +68,11 @@ class InvoiceApiController extends BaseAPIController $invoices->whereInvoiceNumber($invoiceNumber); } + // Fllter by status + if ($statusId = Input::get('status_id')) { + $invoices->where('invoice_status_id', '>=', $statusId); + } + return $this->listResponse($invoices); } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index 01594fa5a89b..690c6086c72e 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -403,7 +403,11 @@ class InvoiceController extends BaseController } if (! Auth::user()->confirmed) { - $errorMessage = trans(Auth::user()->registered ? 'texts.confirmation_required' : 'texts.registration_required'); + if (Auth::user()->registered) { + $errorMessage = trans('texts.confirmation_required', ['link' => link_to('/resend_confirmation', trans('texts.click_here'))]); + } else { + $errorMessage = trans('texts.registration_required'); + } Session::flash('error', $errorMessage); return Redirect::to('invoices/'.$invoice->public_id.'/edit'); diff --git a/app/Http/Controllers/NinjaController.php b/app/Http/Controllers/NinjaController.php index 520551578d5c..c74f705f3e1e 100644 --- a/app/Http/Controllers/NinjaController.php +++ b/app/Http/Controllers/NinjaController.php @@ -294,6 +294,7 @@ class NinjaController extends BaseController } $user = Auth::user(); + $account = $user->account; $url = NINJA_APP_URL . '/buy_now'; $contactKey = $user->primaryAccount()->account_key; @@ -301,9 +302,17 @@ class NinjaController extends BaseController 'account_key' => NINJA_LICENSE_ACCOUNT_KEY, 'contact_key' => $contactKey, 'product_id' => PRODUCT_WHITE_LABEL, - 'first_name' => Auth::user()->first_name, - 'last_name' => Auth::user()->last_name, - 'email' => Auth::user()->email, + 'first_name' => $user->first_name, + 'last_name' => $user->last_name, + 'email' => $user->email, + 'name' => $account->name, + 'address1' => $account->address1, + 'address2' => $account->address2, + 'city' => $account->city, + 'state' => $account->state, + 'postal_code' => $account->postal_code, + 'country_id' => $account->country_id, + 'vat_number' => $account->vat_number, 'return_link' => true, ]; diff --git a/app/Http/Controllers/OnlinePaymentController.php b/app/Http/Controllers/OnlinePaymentController.php index 852f0f7bc1e6..f45667893886 100644 --- a/app/Http/Controllers/OnlinePaymentController.php +++ b/app/Http/Controllers/OnlinePaymentController.php @@ -356,12 +356,14 @@ class OnlinePaymentController extends BaseController return redirect()->to("{$failureUrl}/?error=" . $validator->errors()->first()); } - $data = [ - 'currency_id' => $account->currency_id, - 'contact' => Input::all(), - 'custom_value1' => Input::get('custom_client1'), - 'custom_value2' => Input::get('custom_client2'), - ]; + $data = request()->all(); + $data['currency_id'] = $account->currency_id; + $data['custom_value1'] = request()->custom_client1; + $data['custom_value2'] = request()->custom_client2; + $data['contact'] = request()->all(); + $data['contact']['custom_value1'] = request()->custom_contact1; + $data['contact']['custom_value2'] = request()->custom_contact2; + if (request()->currency_code) { $data['currency_code'] = request()->currency_code; } @@ -425,20 +427,23 @@ class OnlinePaymentController extends BaseController { if (Utils::isNinja()) { $subdomain = Utils::getSubdomain(\Request::server('HTTP_HOST')); + if (! $subdomain || $subdomain == 'app') { + exit('Invalid subdomain'); + } $account = Account::whereSubdomain($subdomain)->first(); } else { $account = Account::first(); } if (! $account) { - exit("Account not found"); + exit('Account not found'); } $accountGateway = $account->account_gateways() ->whereGatewayId(GATEWAY_STRIPE)->first(); if (! $account) { - exit("Apple merchant id not set"); + exit('Apple merchant id not set'); } echo $accountGateway->getConfigField('appleMerchantId'); diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index 7b8ad7081755..e7da8b5367e6 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/app/Http/Controllers/PaymentController.php @@ -89,16 +89,29 @@ class PaymentController extends BaseController */ public function create(PaymentRequest $request) { + $user = auth()->user(); + $account = $user->account; + $invoices = Invoice::scope() ->invoices() ->where('invoices.invoice_status_id', '!=', INVOICE_STATUS_PAID) ->with('client', 'invoice_status') ->orderBy('invoice_number')->get(); + $clientPublicId = Input::old('client') ? Input::old('client') : ($request->client_id ?: 0); + $invoicePublicId = Input::old('invoice') ? Input::old('invoice') : ($request->invoice_id ?: 0); + + $totalCredit = false; + if ($clientPublicId && $client = Client::scope($clientPublicId)->first()) { + $totalCredit = $account->formatMoney($client->getTotalCredit(), $client); + } elseif ($invoicePublicId && $invoice = Invoice::scope($invoicePublicId)->first()) { + $totalCredit = $account->formatMoney($invoice->client->getTotalCredit(), $client); + } + $data = [ 'account' => Auth::user()->account, - 'clientPublicId' => Input::old('client') ? Input::old('client') : ($request->client_id ?: 0), - 'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : ($request->invoice_id ?: 0), + 'clientPublicId' => $clientPublicId, + 'invoicePublicId' => $invoicePublicId, 'invoice' => null, 'invoices' => $invoices, 'payment' => null, @@ -106,7 +119,9 @@ class PaymentController extends BaseController 'url' => 'payments', 'title' => trans('texts.new_payment'), 'paymentTypeId' => Input::get('paymentTypeId'), - 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), ]; + 'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), + 'totalCredit' => $totalCredit, + ]; return View::make('payments.edit', $data); } diff --git a/app/Http/Controllers/PaymentTermApiController.php b/app/Http/Controllers/PaymentTermApiController.php new file mode 100644 index 000000000000..ef11a64e19f5 --- /dev/null +++ b/app/Http/Controllers/PaymentTermApiController.php @@ -0,0 +1,160 @@ +paymentTermRepo = $paymentTermRepo; + } + + /** + * @SWG\Get( + * path="/paymentTerms", + * summary="List payment terms", + * operationId="listPaymentTerms", + * tags={"payment terms"}, + * @SWG\Response( + * response=200, + * description="A list of payment terms", + * @SWG\Schema(type="array", @SWG\Items(ref="#/definitions/PaymentTerms")) + * ), + * @SWG\Response( + * response="default", + * description="an ""unexpected"" error" + * ) + * ) + */ + + public function index() + { + + $paymentTerms = PaymentTerm::scope() + ->orWhere('account_id',0) + ->orderBy('num_days', 'asc'); + + return $this->listResponse($paymentTerms); + } + + /** + * @SWG\Get( + * path="/paymentTerms/{payment_term_id}", + * summary="Retrieve a payment term", + * operationId="getPaymentTermId", + * tags={"payment term"}, + * @SWG\Parameter( + * in="path", + * name="payment_term_id", + * type="integer", + * required=true + * ), + * @SWG\Response( + * response=200, + * description="A single payment term", + * @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/PaymentTerms")) + * ), + * @SWG\Response( + * response="default", + * description="an ""unexpected"" error" + * ) + * ) + */ + + public function show(PaymentTermRequest $request) + { + return $this->itemResponse($request->entity()); + } + + + /** + * @SWG\Post( + * path="/paymentTerms", + * summary="Create a payment Term", + * operationId="createPaymentTerm", + * tags={"payment term"}, + * @SWG\Parameter( + * in="body", + * name="payment term", + * @SWG\Schema(ref="#/definitions/PaymentTerm") + * ), + * @SWG\Response( + * response=200, + * description="New payment Term", + * @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/PaymentTerm")) + * ), + * @SWG\Response( + * response="default", + * description="an ""unexpected"" error" + * ) + * ) + */ + public function store(CreatePaymentTermAPIRequest $request) + { + + $paymentTerm = PaymentTerm::createNew(); + + $paymentTerm->num_days = Utils::parseInt(Input::get('num_days')); + $paymentTerm->name = 'Net ' . $paymentTerm->num_days; + $paymentTerm->save(); + + return $this->itemResponse($paymentTerm); + } + + /** + * @SWG\Delete( + * path="/paymentTerm/{num_days}", + * summary="Delete a payment term", + * operationId="deletePaymentTerm", + * tags={"payment term"}, + * @SWG\Parameter( + * in="path", + * name="num_days", + * type="integer", + * required=true + * ), + * @SWG\Response( + * response=200, + * description="Deleted payment Term", + * @SWG\Schema(type="object", @SWG\Items(ref="#/definitions/PaymentTerm")) + * ), + * @SWG\Response( + * response="default", + * description="an ""unexpected"" error" + * ) + * ) + */ + public function destroy($numDays) + { + + $paymentTerm = PaymentTerm::where('num_days', $numDays)->first(); + + if(!$paymentTerm || $paymentTerm->account_id == 0) + return $this->errorResponse(['message'=>'Cannot delete a default or non existent Payment Term'], 400); + + $this->paymentTermRepo->archive($paymentTerm); + + return $this->itemResponse($paymentTerm); + } +} diff --git a/app/Http/Controllers/ProposalCategoryController.php b/app/Http/Controllers/ProposalCategoryController.php new file mode 100644 index 000000000000..18259c442782 --- /dev/null +++ b/app/Http/Controllers/ProposalCategoryController.php @@ -0,0 +1,128 @@ +proposalCategoryRepo = $proposalCategoryRepo; + $this->proposalCategoryService = $proposalCategoryService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_CATEGORY, + 'datatable' => new ProposalCategoryDatatable(), + 'title' => trans('texts.proposal_categories'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalCategoryService->getDatatable($search, $userId); + } + + public function create(ProposalCategoryRequest $request) + { + $data = [ + 'account' => auth()->user()->account, + 'category' => null, + 'method' => 'POST', + 'url' => 'proposals/categories', + 'title' => trans('texts.new_proposal_category'), + 'quotes' => Invoice::scope()->with('client.contacts')->quotes()->orderBy('id')->get(), + 'templates' => ProposalCategory::scope()->orderBy('name')->get(), + 'quotePublicId' => $request->quote_id, + ]; + + return View::make('proposals/categories.edit', $data); + } + + public function show($publicId) + { + Session::reflash(); + + return redirect("proposals/categories/$publicId/edit"); + } + + public function edit(ProposalCategoryRequest $request) + { + $proposalCategory = $request->entity(); + + $data = [ + 'account' => auth()->user()->account, + 'category' => $proposalCategory, + 'method' => 'PUT', + 'url' => 'proposals/categories/' . $proposalCategory->public_id, + 'title' => trans('texts.edit_proposal_category'), + ]; + + return View::make('proposals/categories.edit', $data); + } + + public function store(CreateProposalCategoryRequest $request) + { + $proposalCategory = $this->proposalCategoryService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_category')); + + return redirect()->to($proposalCategory->getRoute()); + } + + public function update(UpdateProposalCategoryRequest $request) + { + $proposalCategory = $this->proposalCategoryService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_category')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalCategory->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalCategoryService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_category" : "{$action}d_proposal_categories"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposals/categories'); + } +} diff --git a/app/Http/Controllers/ProposalController.php b/app/Http/Controllers/ProposalController.php new file mode 100644 index 000000000000..9b5fa1a841c4 --- /dev/null +++ b/app/Http/Controllers/ProposalController.php @@ -0,0 +1,178 @@ +proposalRepo = $proposalRepo; + $this->proposalService = $proposalService; + $this->contactMailer = $contactMailer; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL, + 'datatable' => new ProposalDatatable(), + 'title' => trans('texts.proposals'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalService->getDatatable($search, $userId); + } + + public function create(ProposalRequest $request) + { + $data = array_merge($this->getViewmodel(), [ + 'proposal' => null, + 'method' => 'POST', + 'url' => 'proposals', + 'title' => trans('texts.new_proposal'), + 'invoices' => Invoice::scope()->with('client.contacts', 'client.country')->unapprovedQuotes()->orderBy('id')->get(), + 'invoicePublicId' => $request->invoice_id, + 'templatePublicId' => $request->proposal_template_id, + ]); + + return View::make('proposals.edit', $data); + } + + public function show($publicId) + { + Session::reflash(); + + return redirect("proposals/$publicId/edit"); + } + + public function edit(ProposalRequest $request) + { + $proposal = $request->entity(); + + $data = array_merge($this->getViewmodel(), [ + 'proposal' => $proposal, + 'entity' => $proposal, + 'method' => 'PUT', + 'url' => 'proposals/' . $proposal->public_id, + 'title' => trans('texts.edit_proposal'), + 'invoices' => Invoice::scope()->with('client.contacts', 'client.country')->unapprovedQuotes($proposal->invoice_id)->orderBy('id')->get(), + 'invoicePublicId' => $proposal->invoice ? $proposal->invoice->public_id : null, + 'templatePublicId' => $proposal->proposal_template ? $proposal->proposal_template->public_id : null, + ]); + + return View::make('proposals.edit', $data); + } + + private function getViewmodel() + { + $account = auth()->user()->account; + $templates = ProposalTemplate::whereAccountId($account->id)->orderBy('name')->get(); + + if (! $templates->count()) { + $templates = ProposalTemplate::whereNull('account_id')->orderBy('name')->get(); + } + + $data = [ + 'templates' => $templates, + 'account' => $account, + ]; + + return $data; + } + + public function store(CreateProposalRequest $request) + { + $proposal = $this->proposalService->save($request->input()); + $action = Input::get('action'); + + if ($action == 'email') { + $this->dispatch(new SendInvoiceEmail($proposal->invoice, auth()->user()->id, false, false, $proposal)); + Session::flash('message', trans('texts.emailed_proposal')); + } else { + Session::flash('message', trans('texts.created_proposal')); + } + + return redirect()->to($proposal->getRoute()); + } + + public function update(UpdateProposalRequest $request) + { + $proposal = $this->proposalService->save($request->input(), $request->entity()); + $action = Input::get('action'); + + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + if ($action == 'email') { + $this->dispatch(new SendInvoiceEmail($proposal->invoice, auth()->user()->id, false, false, $proposal)); + Session::flash('message', trans('texts.emailed_proposal')); + } else { + Session::flash('message', trans('texts.updated_proposal')); + } + + return redirect()->to($proposal->getRoute()); + } + + public function bulk() + { + $action = Input::get('bulk_action') ?: Input::get('action'); + $ids = Input::get('bulk_public_id') ?: (Input::get('public_id') ?: Input::get('ids')); + + $count = $this->proposalService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal" : "{$action}d_proposals"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposals'); + } + + public function download(ProposalRequest $request) + { + $proposal = $request->entity(); + + $mpdf = new mPDF(); + $mpdf->showImageErrors = true; + $mpdf->WriteHTML($proposal->present()->htmlDocument); + + //$mpdf->Output(); + + $mpdf->Output($proposal->present()->filename, 'D'); + } +} diff --git a/app/Http/Controllers/ProposalSnippetController.php b/app/Http/Controllers/ProposalSnippetController.php new file mode 100644 index 000000000000..c0bcd03c49e0 --- /dev/null +++ b/app/Http/Controllers/ProposalSnippetController.php @@ -0,0 +1,732 @@ +proposalSnippetRepo = $proposalSnippetRepo; + $this->proposalSnippetService = $proposalSnippetService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_SNIPPET, + 'datatable' => new ProposalSnippetDatatable(), + 'title' => trans('texts.proposal_snippets'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalSnippetService->getDatatable($search, $userId); + } + + public function create(ProposalSnippetRequest $request) + { + $data = [ + 'account' => auth()->user()->account, + 'snippet' => null, + 'method' => 'POST', + 'url' => 'proposals/snippets', + 'title' => trans('texts.new_proposal_snippet'), + 'categories' => ProposalCategory::scope()->orderBy('name')->get(), + 'categoryPublicId' => 0, + 'icons' => $this->getIcons(), + ]; + + return View::make('proposals/snippets/edit', $data); + } + + public function show($publicId) + { + Session::reflash(); + + return redirect("proposals/snippets/$publicId/edit"); + } + + public function edit(ProposalSnippetRequest $request) + { + $proposalSnippet = $request->entity(); + + $data = [ + 'account' => auth()->user()->account, + 'snippet' => $proposalSnippet, + 'entity' => $proposalSnippet, + 'method' => 'PUT', + 'url' => 'proposals/snippets/' . $proposalSnippet->public_id, + 'title' => trans('texts.edit_proposal_snippet'), + 'categories' => ProposalCategory::scope()->orderBy('name')->get(), + 'categoryPublicId' => $proposalSnippet->proposal_category ? $proposalSnippet->proposal_category->public_id : null, + 'icons' => $this->getIcons(), + ]; + + return View::make('proposals/snippets.edit', $data); + } + + public function store(CreateProposalSnippetRequest $request) + { + $proposalSnippet = $this->proposalSnippetService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_snippet')); + + return redirect()->to($proposalSnippet->getRoute()); + } + + public function update(UpdateProposalSnippetRequest $request) + { + $proposalSnippet = $this->proposalSnippetService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_snippet')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalSnippet->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalSnippetService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_snippet" : "{$action}d_proposal_snippets"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposals/snippets'); + } + + private function getIcons() { + $data = []; + $icons = [ + ['name'=>'glass','code'=>'f000'], + ['name'=>'music','code'=>'f001'], + ['name'=>'search','code'=>'f002'], + ['name'=>'envelope-o','code'=>'f003'], + ['name'=>'heart','code'=>'f004'], + ['name'=>'star','code'=>'f005'], + ['name'=>'star-o','code'=>'f006'], + ['name'=>'user','code'=>'f007'], + ['name'=>'film','code'=>'f008'], + ['name'=>'th-large','code'=>'f009'], + ['name'=>'th','code'=>'f00a'], + ['name'=>'th-list','code'=>'f00b'], + ['name'=>'check','code'=>'f00c'], + ['name'=>'times','code'=>'f00d'], + ['name'=>'search-plus','code'=>'f00e'], + ['name'=>'search-minus','code'=>'f010'], + ['name'=>'power-off','code'=>'f011'], + ['name'=>'signal','code'=>'f012'], + ['name'=>'cog','code'=>'f013'], + ['name'=>'trash-o','code'=>'f014'], + ['name'=>'home','code'=>'f015'], + ['name'=>'file-o','code'=>'f016'], + ['name'=>'clock-o','code'=>'f017'], + ['name'=>'road','code'=>'f018'], + ['name'=>'download','code'=>'f019'], + ['name'=>'arrow-circle-o-down','code'=>'f01a'], + ['name'=>'arrow-circle-o-up','code'=>'f01b'], + ['name'=>'inbox','code'=>'f01c'], + ['name'=>'play-circle-o','code'=>'f01d'], + ['name'=>'repeat','code'=>'f01e'], + ['name'=>'refresh','code'=>'f021'], + ['name'=>'list-alt','code'=>'f022'], + ['name'=>'lock','code'=>'f023'], + ['name'=>'flag','code'=>'f024'], + ['name'=>'headphones','code'=>'f025'], + ['name'=>'volume-off','code'=>'f026'], + ['name'=>'volume-down','code'=>'f027'], + ['name'=>'volume-up','code'=>'f028'], + ['name'=>'qrcode','code'=>'f029'], + ['name'=>'barcode','code'=>'f02a'], + ['name'=>'tag','code'=>'f02b'], + ['name'=>'tags','code'=>'f02c'], + ['name'=>'book','code'=>'f02d'], + ['name'=>'bookmark','code'=>'f02e'], + ['name'=>'print','code'=>'f02f'], + ['name'=>'camera','code'=>'f030'], + ['name'=>'font','code'=>'f031'], + ['name'=>'bold','code'=>'f032'], + ['name'=>'italic','code'=>'f033'], + ['name'=>'text-height','code'=>'f034'], + ['name'=>'text-width','code'=>'f035'], + ['name'=>'align-left','code'=>'f036'], + ['name'=>'align-center','code'=>'f037'], + ['name'=>'align-right','code'=>'f038'], + ['name'=>'align-justify','code'=>'f039'], + ['name'=>'list','code'=>'f03a'], + ['name'=>'outdent','code'=>'f03b'], + ['name'=>'indent','code'=>'f03c'], + ['name'=>'video-camera','code'=>'f03d'], + ['name'=>'picture-o','code'=>'f03e'], + ['name'=>'pencil','code'=>'f040'], + ['name'=>'map-marker','code'=>'f041'], + ['name'=>'adjust','code'=>'f042'], + ['name'=>'tint','code'=>'f043'], + ['name'=>'pencil-square-o','code'=>'f044'], + ['name'=>'share-square-o','code'=>'f045'], + ['name'=>'check-square-o','code'=>'f046'], + ['name'=>'arrows','code'=>'f047'], + ['name'=>'step-backward','code'=>'f048'], + ['name'=>'fast-backward','code'=>'f049'], + ['name'=>'backward','code'=>'f04a'], + ['name'=>'play','code'=>'f04b'], + ['name'=>'pause','code'=>'f04c'], + ['name'=>'stop','code'=>'f04d'], + ['name'=>'forward','code'=>'f04e'], + ['name'=>'fast-forward','code'=>'f050'], + ['name'=>'step-forward','code'=>'f051'], + ['name'=>'eject','code'=>'f052'], + ['name'=>'chevron-left','code'=>'f053'], + ['name'=>'chevron-right','code'=>'f054'], + ['name'=>'plus-circle','code'=>'f055'], + ['name'=>'minus-circle','code'=>'f056'], + ['name'=>'times-circle','code'=>'f057'], + ['name'=>'check-circle','code'=>'f058'], + ['name'=>'question-circle','code'=>'f059'], + ['name'=>'info-circle','code'=>'f05a'], + ['name'=>'crosshairs','code'=>'f05b'], + ['name'=>'times-circle-o','code'=>'f05c'], + ['name'=>'check-circle-o','code'=>'f05d'], + ['name'=>'ban','code'=>'f05e'], + ['name'=>'arrow-left','code'=>'f060'], + ['name'=>'arrow-right','code'=>'f061'], + ['name'=>'arrow-up','code'=>'f062'], + ['name'=>'arrow-down','code'=>'f063'], + ['name'=>'share','code'=>'f064'], + ['name'=>'expand','code'=>'f065'], + ['name'=>'compress','code'=>'f066'], + ['name'=>'plus','code'=>'f067'], + ['name'=>'minus','code'=>'f068'], + ['name'=>'asterisk','code'=>'f069'], + ['name'=>'exclamation-circle','code'=>'f06a'], + ['name'=>'gift','code'=>'f06b'], + ['name'=>'leaf','code'=>'f06c'], + ['name'=>'fire','code'=>'f06d'], + ['name'=>'eye','code'=>'f06e'], + ['name'=>'eye-slash','code'=>'f070'], + ['name'=>'exclamation-triangle','code'=>'f071'], + ['name'=>'plane','code'=>'f072'], + ['name'=>'calendar','code'=>'f073'], + ['name'=>'random','code'=>'f074'], + ['name'=>'comment','code'=>'f075'], + ['name'=>'magnet','code'=>'f076'], + ['name'=>'chevron-up','code'=>'f077'], + ['name'=>'chevron-down','code'=>'f078'], + ['name'=>'retweet','code'=>'f079'], + ['name'=>'shopping-cart','code'=>'f07a'], + ['name'=>'folder','code'=>'f07b'], + ['name'=>'folder-open','code'=>'f07c'], + ['name'=>'arrows-v','code'=>'f07d'], + ['name'=>'arrows-h','code'=>'f07e'], + ['name'=>'bar-chart','code'=>'f080'], + ['name'=>'twitter-square','code'=>'f081'], + ['name'=>'facebook-square','code'=>'f082'], + ['name'=>'camera-retro','code'=>'f083'], + ['name'=>'key','code'=>'f084'], + ['name'=>'cogs','code'=>'f085'], + ['name'=>'comments','code'=>'f086'], + ['name'=>'thumbs-o-up','code'=>'f087'], + ['name'=>'thumbs-o-down','code'=>'f088'], + ['name'=>'star-half','code'=>'f089'], + ['name'=>'heart-o','code'=>'f08a'], + ['name'=>'sign-out','code'=>'f08b'], + ['name'=>'linkedin-square','code'=>'f08c'], + ['name'=>'thumb-tack','code'=>'f08d'], + ['name'=>'external-link','code'=>'f08e'], + ['name'=>'sign-in','code'=>'f090'], + ['name'=>'trophy','code'=>'f091'], + ['name'=>'github-square','code'=>'f092'], + ['name'=>'upload','code'=>'f093'], + ['name'=>'lemon-o','code'=>'f094'], + ['name'=>'phone','code'=>'f095'], + ['name'=>'square-o','code'=>'f096'], + ['name'=>'bookmark-o','code'=>'f097'], + ['name'=>'phone-square','code'=>'f098'], + ['name'=>'twitter','code'=>'f099'], + ['name'=>'facebook','code'=>'f09a'], + ['name'=>'github','code'=>'f09b'], + ['name'=>'unlock','code'=>'f09c'], + ['name'=>'credit-card','code'=>'f09d'], + ['name'=>'rss','code'=>'f09e'], + ['name'=>'hdd-o','code'=>'f0a0'], + ['name'=>'bullhorn','code'=>'f0a1'], + ['name'=>'bell','code'=>'f0f3'], + ['name'=>'certificate','code'=>'f0a3'], + ['name'=>'hand-o-right','code'=>'f0a4'], + ['name'=>'hand-o-left','code'=>'f0a5'], + ['name'=>'hand-o-up','code'=>'f0a6'], + ['name'=>'hand-o-down','code'=>'f0a7'], + ['name'=>'arrow-circle-left','code'=>'f0a8'], + ['name'=>'arrow-circle-right','code'=>'f0a9'], + ['name'=>'arrow-circle-up','code'=>'f0aa'], + ['name'=>'arrow-circle-down','code'=>'f0ab'], + ['name'=>'globe','code'=>'f0ac'], + ['name'=>'wrench','code'=>'f0ad'], + ['name'=>'tasks','code'=>'f0ae'], + ['name'=>'filter','code'=>'f0b0'], + ['name'=>'briefcase','code'=>'f0b1'], + ['name'=>'arrows-alt','code'=>'f0b2'], + ['name'=>'users','code'=>'f0c0'], + ['name'=>'link','code'=>'f0c1'], + ['name'=>'cloud','code'=>'f0c2'], + ['name'=>'flask','code'=>'f0c3'], + ['name'=>'scissors','code'=>'f0c4'], + ['name'=>'files-o','code'=>'f0c5'], + ['name'=>'paperclip','code'=>'f0c6'], + ['name'=>'floppy-o','code'=>'f0c7'], + ['name'=>'square','code'=>'f0c8'], + ['name'=>'bars','code'=>'f0c9'], + ['name'=>'list-ul','code'=>'f0ca'], + ['name'=>'list-ol','code'=>'f0cb'], + ['name'=>'strikethrough','code'=>'f0cc'], + ['name'=>'underline','code'=>'f0cd'], + ['name'=>'table','code'=>'f0ce'], + ['name'=>'magic','code'=>'f0d0'], + ['name'=>'truck','code'=>'f0d1'], + ['name'=>'pinterest','code'=>'f0d2'], + ['name'=>'pinterest-square','code'=>'f0d3'], + ['name'=>'google-plus-square','code'=>'f0d4'], + ['name'=>'google-plus','code'=>'f0d5'], + ['name'=>'money','code'=>'f0d6'], + ['name'=>'caret-down','code'=>'f0d7'], + ['name'=>'caret-up','code'=>'f0d8'], + ['name'=>'caret-left','code'=>'f0d9'], + ['name'=>'caret-right','code'=>'f0da'], + ['name'=>'columns','code'=>'f0db'], + ['name'=>'sort','code'=>'f0dc'], + ['name'=>'sort-desc','code'=>'f0dd'], + ['name'=>'sort-asc','code'=>'f0de'], + ['name'=>'envelope','code'=>'f0e0'], + ['name'=>'linkedin','code'=>'f0e1'], + ['name'=>'undo','code'=>'f0e2'], + ['name'=>'gavel','code'=>'f0e3'], + ['name'=>'tachometer','code'=>'f0e4'], + ['name'=>'comment-o','code'=>'f0e5'], + ['name'=>'comments-o','code'=>'f0e6'], + ['name'=>'bolt','code'=>'f0e7'], + ['name'=>'sitemap','code'=>'f0e8'], + ['name'=>'umbrella','code'=>'f0e9'], + ['name'=>'clipboard','code'=>'f0ea'], + ['name'=>'lightbulb-o','code'=>'f0eb'], + ['name'=>'exchange','code'=>'f0ec'], + ['name'=>'cloud-download','code'=>'f0ed'], + ['name'=>'cloud-upload','code'=>'f0ee'], + ['name'=>'user-md','code'=>'f0f0'], + ['name'=>'stethoscope','code'=>'f0f1'], + ['name'=>'suitcase','code'=>'f0f2'], + ['name'=>'bell-o','code'=>'f0a2'], + ['name'=>'coffee','code'=>'f0f4'], + ['name'=>'cutlery','code'=>'f0f5'], + ['name'=>'file-text-o','code'=>'f0f6'], + ['name'=>'building-o','code'=>'f0f7'], + ['name'=>'hospital-o','code'=>'f0f8'], + ['name'=>'ambulance','code'=>'f0f9'], + ['name'=>'medkit','code'=>'f0fa'], + ['name'=>'fighter-jet','code'=>'f0fb'], + ['name'=>'beer','code'=>'f0fc'], + ['name'=>'h-square','code'=>'f0fd'], + ['name'=>'plus-square','code'=>'f0fe'], + ['name'=>'angle-double-left','code'=>'f100'], + ['name'=>'angle-double-right','code'=>'f101'], + ['name'=>'angle-double-up','code'=>'f102'], + ['name'=>'angle-double-down','code'=>'f103'], + ['name'=>'angle-left','code'=>'f104'], + ['name'=>'angle-right','code'=>'f105'], + ['name'=>'angle-up','code'=>'f106'], + ['name'=>'angle-down','code'=>'f107'], + ['name'=>'desktop','code'=>'f108'], + ['name'=>'laptop','code'=>'f109'], + ['name'=>'tablet','code'=>'f10a'], + ['name'=>'mobile','code'=>'f10b'], + ['name'=>'circle-o','code'=>'f10c'], + ['name'=>'quote-left','code'=>'f10d'], + ['name'=>'quote-right','code'=>'f10e'], + ['name'=>'spinner','code'=>'f110'], + ['name'=>'circle','code'=>'f111'], + ['name'=>'reply','code'=>'f112'], + ['name'=>'github-alt','code'=>'f113'], + ['name'=>'folder-o','code'=>'f114'], + ['name'=>'folder-open-o','code'=>'f115'], + ['name'=>'smile-o','code'=>'f118'], + ['name'=>'frown-o','code'=>'f119'], + ['name'=>'meh-o','code'=>'f11a'], + ['name'=>'gamepad','code'=>'f11b'], + ['name'=>'keyboard-o','code'=>'f11c'], + ['name'=>'flag-o','code'=>'f11d'], + ['name'=>'flag-checkered','code'=>'f11e'], + ['name'=>'terminal','code'=>'f120'], + ['name'=>'code','code'=>'f121'], + ['name'=>'reply-all','code'=>'f122'], + ['name'=>'star-half-o','code'=>'f123'], + ['name'=>'location-arrow','code'=>'f124'], + ['name'=>'crop','code'=>'f125'], + ['name'=>'code-fork','code'=>'f126'], + ['name'=>'chain-broken','code'=>'f127'], + ['name'=>'question','code'=>'f128'], + ['name'=>'info','code'=>'f129'], + ['name'=>'exclamation','code'=>'f12a'], + ['name'=>'superscript','code'=>'f12b'], + ['name'=>'subscript','code'=>'f12c'], + ['name'=>'eraser','code'=>'f12d'], + ['name'=>'puzzle-piece','code'=>'f12e'], + ['name'=>'microphone','code'=>'f130'], + ['name'=>'microphone-slash','code'=>'f131'], + ['name'=>'shield','code'=>'f132'], + ['name'=>'calendar-o','code'=>'f133'], + ['name'=>'fire-extinguisher','code'=>'f134'], + ['name'=>'rocket','code'=>'f135'], + ['name'=>'maxcdn','code'=>'f136'], + ['name'=>'chevron-circle-left','code'=>'f137'], + ['name'=>'chevron-circle-right','code'=>'f138'], + ['name'=>'chevron-circle-up','code'=>'f139'], + ['name'=>'chevron-circle-down','code'=>'f13a'], + ['name'=>'html5','code'=>'f13b'], + ['name'=>'css3','code'=>'f13c'], + ['name'=>'anchor','code'=>'f13d'], + ['name'=>'unlock-alt','code'=>'f13e'], + ['name'=>'bullseye','code'=>'f140'], + ['name'=>'ellipsis-h','code'=>'f141'], + ['name'=>'ellipsis-v','code'=>'f142'], + ['name'=>'rss-square','code'=>'f143'], + ['name'=>'play-circle','code'=>'f144'], + ['name'=>'ticket','code'=>'f145'], + ['name'=>'minus-square','code'=>'f146'], + ['name'=>'minus-square-o','code'=>'f147'], + ['name'=>'level-up','code'=>'f148'], + ['name'=>'level-down','code'=>'f149'], + ['name'=>'check-square','code'=>'f14a'], + ['name'=>'pencil-square','code'=>'f14b'], + ['name'=>'external-link-square','code'=>'f14c'], + ['name'=>'share-square','code'=>'f14d'], + ['name'=>'compass','code'=>'f14e'], + ['name'=>'caret-square-o-down','code'=>'f150'], + ['name'=>'caret-square-o-up','code'=>'f151'], + ['name'=>'caret-square-o-right','code'=>'f152'], + ['name'=>'eur','code'=>'f153'], + ['name'=>'gbp','code'=>'f154'], + ['name'=>'usd','code'=>'f155'], + ['name'=>'inr','code'=>'f156'], + ['name'=>'jpy','code'=>'f157'], + ['name'=>'rub','code'=>'f158'], + ['name'=>'krw','code'=>'f159'], + ['name'=>'btc','code'=>'f15a'], + ['name'=>'file','code'=>'f15b'], + ['name'=>'file-text','code'=>'f15c'], + ['name'=>'sort-alpha-asc','code'=>'f15d'], + ['name'=>'sort-alpha-desc','code'=>'f15e'], + ['name'=>'sort-amount-asc','code'=>'f160'], + ['name'=>'sort-amount-desc','code'=>'f161'], + ['name'=>'sort-numeric-asc','code'=>'f162'], + ['name'=>'sort-numeric-desc','code'=>'f163'], + ['name'=>'thumbs-up','code'=>'f164'], + ['name'=>'thumbs-down','code'=>'f165'], + ['name'=>'youtube-square','code'=>'f166'], + ['name'=>'youtube','code'=>'f167'], + ['name'=>'xing','code'=>'f168'], + ['name'=>'xing-square','code'=>'f169'], + ['name'=>'youtube-play','code'=>'f16a'], + ['name'=>'dropbox','code'=>'f16b'], + ['name'=>'stack-overflow','code'=>'f16c'], + ['name'=>'instagram','code'=>'f16d'], + ['name'=>'flickr','code'=>'f16e'], + ['name'=>'adn','code'=>'f170'], + ['name'=>'bitbucket','code'=>'f171'], + ['name'=>'bitbucket-square','code'=>'f172'], + ['name'=>'tumblr','code'=>'f173'], + ['name'=>'tumblr-square','code'=>'f174'], + ['name'=>'long-arrow-down','code'=>'f175'], + ['name'=>'long-arrow-up','code'=>'f176'], + ['name'=>'long-arrow-left','code'=>'f177'], + ['name'=>'long-arrow-right','code'=>'f178'], + ['name'=>'apple','code'=>'f179'], + ['name'=>'windows','code'=>'f17a'], + ['name'=>'android','code'=>'f17b'], + ['name'=>'linux','code'=>'f17c'], + ['name'=>'dribbble','code'=>'f17d'], + ['name'=>'skype','code'=>'f17e'], + ['name'=>'foursquare','code'=>'f180'], + ['name'=>'trello','code'=>'f181'], + ['name'=>'female','code'=>'f182'], + ['name'=>'male','code'=>'f183'], + ['name'=>'gratipay','code'=>'f184'], + ['name'=>'sun-o','code'=>'f185'], + ['name'=>'moon-o','code'=>'f186'], + ['name'=>'archive','code'=>'f187'], + ['name'=>'bug','code'=>'f188'], + ['name'=>'vk','code'=>'f189'], + ['name'=>'weibo','code'=>'f18a'], + ['name'=>'renren','code'=>'f18b'], + ['name'=>'pagelines','code'=>'f18c'], + ['name'=>'stack-exchange','code'=>'f18d'], + ['name'=>'arrow-circle-o-right','code'=>'f18e'], + ['name'=>'arrow-circle-o-left','code'=>'f190'], + ['name'=>'caret-square-o-left','code'=>'f191'], + ['name'=>'dot-circle-o','code'=>'f192'], + ['name'=>'wheelchair','code'=>'f193'], + ['name'=>'vimeo-square','code'=>'f194'], + ['name'=>'try','code'=>'f195'], + ['name'=>'plus-square-o','code'=>'f196'], + ['name'=>'space-shuttle','code'=>'f197'], + ['name'=>'slack','code'=>'f198'], + ['name'=>'envelope-square','code'=>'f199'], + ['name'=>'wordpress','code'=>'f19a'], + ['name'=>'openid','code'=>'f19b'], + ['name'=>'university','code'=>'f19c'], + ['name'=>'graduation-cap','code'=>'f19d'], + ['name'=>'yahoo','code'=>'f19e'], + ['name'=>'google','code'=>'f1a0'], + ['name'=>'reddit','code'=>'f1a1'], + ['name'=>'reddit-square','code'=>'f1a2'], + ['name'=>'stumbleupon-circle','code'=>'f1a3'], + ['name'=>'stumbleupon','code'=>'f1a4'], + ['name'=>'delicious','code'=>'f1a5'], + ['name'=>'digg','code'=>'f1a6'], + ['name'=>'pied-piper','code'=>'f1a7'], + ['name'=>'pied-piper-alt','code'=>'f1a8'], + ['name'=>'drupal','code'=>'f1a9'], + ['name'=>'joomla','code'=>'f1aa'], + ['name'=>'language','code'=>'f1ab'], + ['name'=>'fax','code'=>'f1ac'], + ['name'=>'building','code'=>'f1ad'], + ['name'=>'child','code'=>'f1ae'], + ['name'=>'paw','code'=>'f1b0'], + ['name'=>'spoon','code'=>'f1b1'], + ['name'=>'cube','code'=>'f1b2'], + ['name'=>'cubes','code'=>'f1b3'], + ['name'=>'behance','code'=>'f1b4'], + ['name'=>'behance-square','code'=>'f1b5'], + ['name'=>'steam','code'=>'f1b6'], + ['name'=>'steam-square','code'=>'f1b7'], + ['name'=>'recycle','code'=>'f1b8'], + ['name'=>'car','code'=>'f1b9'], + ['name'=>'taxi','code'=>'f1ba'], + ['name'=>'tree','code'=>'f1bb'], + ['name'=>'spotify','code'=>'f1bc'], + ['name'=>'deviantart','code'=>'f1bd'], + ['name'=>'soundcloud','code'=>'f1be'], + ['name'=>'database','code'=>'f1c0'], + ['name'=>'file-pdf-o','code'=>'f1c1'], + ['name'=>'file-word-o','code'=>'f1c2'], + ['name'=>'file-excel-o','code'=>'f1c3'], + ['name'=>'file-powerpoint-o','code'=>'f1c4'], + ['name'=>'file-image-o','code'=>'f1c5'], + ['name'=>'file-archive-o','code'=>'f1c6'], + ['name'=>'file-audio-o','code'=>'f1c7'], + ['name'=>'file-video-o','code'=>'f1c8'], + ['name'=>'file-code-o','code'=>'f1c9'], + ['name'=>'vine','code'=>'f1ca'], + ['name'=>'codepen','code'=>'f1cb'], + ['name'=>'jsfiddle','code'=>'f1cc'], + ['name'=>'life-ring','code'=>'f1cd'], + ['name'=>'circle-o-notch','code'=>'f1ce'], + ['name'=>'rebel','code'=>'f1d0'], + ['name'=>'empire','code'=>'f1d1'], + ['name'=>'git-square','code'=>'f1d2'], + ['name'=>'git','code'=>'f1d3'], + ['name'=>'hacker-news','code'=>'f1d4'], + ['name'=>'tencent-weibo','code'=>'f1d5'], + ['name'=>'qq','code'=>'f1d6'], + ['name'=>'weixin','code'=>'f1d7'], + ['name'=>'paper-plane','code'=>'f1d8'], + ['name'=>'paper-plane-o','code'=>'f1d9'], + ['name'=>'history','code'=>'f1da'], + ['name'=>'circle-thin','code'=>'f1db'], + ['name'=>'header','code'=>'f1dc'], + ['name'=>'paragraph','code'=>'f1dd'], + ['name'=>'sliders','code'=>'f1de'], + ['name'=>'share-alt','code'=>'f1e0'], + ['name'=>'share-alt-square','code'=>'f1e1'], + ['name'=>'bomb','code'=>'f1e2'], + ['name'=>'futbol-o','code'=>'f1e3'], + ['name'=>'tty','code'=>'f1e4'], + ['name'=>'binoculars','code'=>'f1e5'], + ['name'=>'plug','code'=>'f1e6'], + ['name'=>'slideshare','code'=>'f1e7'], + ['name'=>'twitch','code'=>'f1e8'], + ['name'=>'yelp','code'=>'f1e9'], + ['name'=>'newspaper-o','code'=>'f1ea'], + ['name'=>'wifi','code'=>'f1eb'], + ['name'=>'calculator','code'=>'f1ec'], + ['name'=>'paypal','code'=>'f1ed'], + ['name'=>'google-wallet','code'=>'f1ee'], + ['name'=>'cc-visa','code'=>'f1f0'], + ['name'=>'cc-mastercard','code'=>'f1f1'], + ['name'=>'cc-discover','code'=>'f1f2'], + ['name'=>'cc-amex','code'=>'f1f3'], + ['name'=>'cc-paypal','code'=>'f1f4'], + ['name'=>'cc-stripe','code'=>'f1f5'], + ['name'=>'bell-slash','code'=>'f1f6'], + ['name'=>'bell-slash-o','code'=>'f1f7'], + ['name'=>'trash','code'=>'f1f8'], + ['name'=>'copyright','code'=>'f1f9'], + ['name'=>'at','code'=>'f1fa'], + ['name'=>'eyedropper','code'=>'f1fb'], + ['name'=>'paint-brush','code'=>'f1fc'], + ['name'=>'birthday-cake','code'=>'f1fd'], + ['name'=>'area-chart','code'=>'f1fe'], + ['name'=>'pie-chart','code'=>'f200'], + ['name'=>'line-chart','code'=>'f201'], + ['name'=>'lastfm','code'=>'f202'], + ['name'=>'lastfm-square','code'=>'f203'], + ['name'=>'toggle-off','code'=>'f204'], + ['name'=>'toggle-on','code'=>'f205'], + ['name'=>'bicycle','code'=>'f206'], + ['name'=>'bus','code'=>'f207'], + ['name'=>'ioxhost','code'=>'f208'], + ['name'=>'angellist','code'=>'f209'], + ['name'=>'cc','code'=>'f20a'], + ['name'=>'ils','code'=>'f20b'], + ['name'=>'meanpath','code'=>'f20c'], + ['name'=>'buysellads','code'=>'f20d'], + ['name'=>'connectdevelop','code'=>'f20e'], + ['name'=>'dashcube','code'=>'f210'], + ['name'=>'forumbee','code'=>'f211'], + ['name'=>'leanpub','code'=>'f212'], + ['name'=>'sellsy','code'=>'f213'], + ['name'=>'shirtsinbulk','code'=>'f214'], + ['name'=>'simplybuilt','code'=>'f215'], + ['name'=>'skyatlas','code'=>'f216'], + ['name'=>'cart-plus','code'=>'f217'], + ['name'=>'cart-arrow-down','code'=>'f218'], + ['name'=>'diamond','code'=>'f219'], + ['name'=>'ship','code'=>'f21a'], + ['name'=>'user-secret','code'=>'f21b'], + ['name'=>'motorcycle','code'=>'f21c'], + ['name'=>'street-view','code'=>'f21d'], + ['name'=>'heartbeat','code'=>'f21e'], + ['name'=>'venus','code'=>'f221'], + ['name'=>'mars','code'=>'f222'], + ['name'=>'mercury','code'=>'f223'], + ['name'=>'transgender','code'=>'f224'], + ['name'=>'transgender-alt','code'=>'f225'], + ['name'=>'venus-double','code'=>'f226'], + ['name'=>'mars-double','code'=>'f227'], + ['name'=>'venus-mars','code'=>'f228'], + ['name'=>'mars-stroke','code'=>'f229'], + ['name'=>'mars-stroke-v','code'=>'f22a'], + ['name'=>'mars-stroke-h','code'=>'f22b'], + ['name'=>'neuter','code'=>'f22c'], + ['name'=>'genderless','code'=>'f22d'], + ['name'=>'facebook-official','code'=>'f230'], + ['name'=>'pinterest-p','code'=>'f231'], + ['name'=>'whatsapp','code'=>'f232'], + ['name'=>'server','code'=>'f233'], + ['name'=>'user-plus','code'=>'f234'], + ['name'=>'user-times','code'=>'f235'], + ['name'=>'bed','code'=>'f236'], + ['name'=>'viacoin','code'=>'f237'], + ['name'=>'train','code'=>'f238'], + ['name'=>'subway','code'=>'f239'], + ['name'=>'medium','code'=>'f23a'], + ['name'=>'y-combinator','code'=>'f23b'], + ['name'=>'optin-monster','code'=>'f23c'], + ['name'=>'opencart','code'=>'f23d'], + ['name'=>'expeditedssl','code'=>'f23e'], + ['name'=>'battery-full','code'=>'f240'], + ['name'=>'battery-three-quarters','code'=>'f241'], + ['name'=>'battery-half','code'=>'f242'], + ['name'=>'battery-quarter','code'=>'f243'], + ['name'=>'battery-empty','code'=>'f244'], + ['name'=>'mouse-pointer','code'=>'f245'], + ['name'=>'i-cursor','code'=>'f246'], + ['name'=>'object-group','code'=>'f247'], + ['name'=>'object-ungroup','code'=>'f248'], + ['name'=>'sticky-note','code'=>'f249'], + ['name'=>'sticky-note-o','code'=>'f24a'], + ['name'=>'cc-jcb','code'=>'f24b'], + ['name'=>'cc-diners-club','code'=>'f24c'], + ['name'=>'clone','code'=>'f24d'], + ['name'=>'balance-scale','code'=>'f24e'], + ['name'=>'hourglass-o','code'=>'f250'], + ['name'=>'hourglass-start','code'=>'f251'], + ['name'=>'hourglass-half','code'=>'f252'], + ['name'=>'hourglass-end','code'=>'f253'], + ['name'=>'hourglass','code'=>'f254'], + ['name'=>'hand-rock-o','code'=>'f255'], + ['name'=>'hand-paper-o','code'=>'f256'], + ['name'=>'hand-scissors-o','code'=>'f257'], + ['name'=>'hand-lizard-o','code'=>'f258'], + ['name'=>'hand-spock-o','code'=>'f259'], + ['name'=>'hand-pointer-o','code'=>'f25a'], + ['name'=>'hand-peace-o','code'=>'f25b'], + ['name'=>'trademark','code'=>'f25c'], + ['name'=>'registered','code'=>'f25d'], + ['name'=>'creative-commons','code'=>'f25e'], + ['name'=>'gg','code'=>'f260'], + ['name'=>'gg-circle','code'=>'f261'], + ['name'=>'tripadvisor','code'=>'f262'], + ['name'=>'odnoklassniki','code'=>'f263'], + ['name'=>'odnoklassniki-square','code'=>'f264'], + ['name'=>'get-pocket','code'=>'f265'], + ['name'=>'wikipedia-w','code'=>'f266'], + ['name'=>'safari','code'=>'f267'], + ['name'=>'chrome','code'=>'f268'], + ['name'=>'firefox','code'=>'f269'], + ['name'=>'opera','code'=>'f26a'], + ['name'=>'internet-explorer','code'=>'f26b'], + ['name'=>'television','code'=>'f26c'], + ['name'=>'contao','code'=>'f26d'], + ['name'=>'500px','code'=>'f26e'], + ['name'=>'amazon','code'=>'f270'], + ['name'=>'calendar-plus-o','code'=>'f271'], + ['name'=>'calendar-minus-o','code'=>'f272'], + ['name'=>'calendar-times-o','code'=>'f273'], + ['name'=>'calendar-check-o','code'=>'f274'], + ['name'=>'industry','code'=>'f275'], + ['name'=>'map-pin','code'=>'f276'], + ['name'=>'map-signs','code'=>'f277'], + ['name'=>'map-o','code'=>'f278'], + ['name'=>'map','code'=>'f279'], + ['name'=>'commenting','code'=>'f27a'], + ['name'=>'commenting-o','code'=>'f27b'], + ['name'=>'houzz','code'=>'f27c'], + ['name'=>'vimeo','code'=>'f27d'], + ['name'=>'black-tie','code'=>'f27e'], + ['name'=>'fonticons','code'=>'f280'], + ]; + + foreach ($icons as $icon) { + $data[$icon['name']] = '&#x' . $icon['code'] . ' ' . ucwords(str_replace('-', ' ', $icon['name'])); + } + + ksort($data); + + return $data; + } +} diff --git a/app/Http/Controllers/ProposalTemplateController.php b/app/Http/Controllers/ProposalTemplateController.php new file mode 100644 index 000000000000..846466e4a110 --- /dev/null +++ b/app/Http/Controllers/ProposalTemplateController.php @@ -0,0 +1,173 @@ +proposalTemplateRepo = $proposalTemplateRepo; + $this->proposalTemplateService = $proposalTemplateService; + } + + /** + * Display a listing of the resource. + * + * @return Response + */ + public function index() + { + return View::make('list_wrapper', [ + 'entityType' => ENTITY_PROPOSAL_TEMPLATE, + 'datatable' => new ProposalTemplateDatatable(), + 'title' => trans('texts.proposal_templates'), + ]); + } + + public function getDatatable($expensePublicId = null) + { + $search = Input::get('sSearch'); + $userId = Auth::user()->filterId(); + + return $this->proposalTemplateService->getDatatable($search, $userId); + } + + public function create(ProposalTemplateRequest $request) + { + $data = array_merge($this->getViewmodel(), [ + 'template' => null, + 'method' => 'POST', + 'url' => 'proposals/templates', + 'title' => trans('texts.new_proposal_template'), + ]); + + return View::make('proposals/templates/edit', $data); + } + + private function getViewmodel() + { + $customTemplates = ProposalTemplate::scope()->orderBy('name')->get(); + $defaultTemplates = ProposalTemplate::whereNull('account_id')->orderBy('public_id')->get(); + + $options = []; + $customLabel = trans('texts.custom'); + $defaultLabel = trans('texts.default'); + + foreach ($customTemplates as $template) { + if (! isset($options[$customLabel])) { + $options[$customLabel] = []; + } + $options[trans('texts.custom')][$template->public_id] = $template->name; + } + foreach ($defaultTemplates as $template) { + if (! isset($options[$defaultLabel])) { + $options[$defaultLabel] = []; + } + $options[trans('texts.default')][$template->public_id] = $template->name; + } + + $data = [ + 'account' => auth()->user()->account, + 'customTemplates' => $customTemplates, + 'defaultTemplates' => $defaultTemplates, + 'templateOptions' => $options, + ]; + + return $data; + } + + public function show($publicId) + { + Session::reflash(); + + return redirect("proposals/templates/$publicId/edit"); + } + + public function edit(ProposalTemplateRequest $request, $publicId = false, $clone = false) + { + $template = $request->entity(); + + if ($clone) { + $template->id = null; + $template->public_id = null; + $template->name = ''; + $template->private_notes = ''; + $method = 'POST'; + $url = 'proposals/templates'; + } else { + $method = 'PUT'; + $url = 'proposals/templates/' . $template->public_id; + } + + $data = array_merge($this->getViewmodel(), [ + 'template' => $template, + 'entity' => $clone ? false : $template, + 'method' => $method, + 'url' => $url, + 'title' => trans('texts.edit_proposal_template'), + ]); + + return View::make('proposals/templates/edit', $data); + } + + public function cloneProposal(ProposalTemplateRequest $request, $publicId) + { + return self::edit($request, $publicId, true); + } + + public function store(CreateProposalTemplateRequest $request) + { + $proposalTemplate = $this->proposalTemplateService->save($request->input()); + + Session::flash('message', trans('texts.created_proposal_template')); + + return redirect()->to($proposalTemplate->getRoute()); + } + + public function update(UpdateProposalTemplateRequest $request) + { + $proposalTemplate = $this->proposalTemplateService->save($request->input(), $request->entity()); + + Session::flash('message', trans('texts.updated_proposal_template')); + + $action = Input::get('action'); + if (in_array($action, ['archive', 'delete', 'restore'])) { + return self::bulk(); + } + + return redirect()->to($proposalTemplate->getRoute()); + } + + public function bulk() + { + $action = Input::get('action'); + $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); + + $count = $this->proposalTemplateService->bulk($ids, $action); + + if ($count > 0) { + $field = $count == 1 ? "{$action}d_proposal_template" : "{$action}d_proposal_templates"; + $message = trans("texts.$field", ['count' => $count]); + Session::flash('message', $message); + } + + return redirect()->to('/proposals/templates'); + } +} diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php index 27eed69b6442..06b363297d2f 100644 --- a/app/Http/Controllers/QuoteController.php +++ b/app/Http/Controllers/QuoteController.php @@ -97,7 +97,7 @@ class QuoteController extends BaseController return [ 'entityType' => ENTITY_QUOTE, - 'account' => $account, + 'account' => Auth::user()->account->load('country'), 'products' => Product::scope()->orderBy('product_key')->get(), 'taxRateOptions' => $account->present()->taxRateOptions, 'clients' => Client::scope()->with('contacts', 'country')->orderBy('name')->get(), @@ -148,6 +148,11 @@ class QuoteController extends BaseController { $invitation = Invitation::with('invoice.invoice_items', 'invoice.invitations')->where('invitation_key', '=', $invitationKey)->firstOrFail(); $invoice = $invitation->invoice; + $account = $invoice->account; + + if ($account->requiresAuthorization($invoice) && ! session('authorized:' . $invitation->invitation_key)) { + return redirect()->to('view/' . $invitation->invitation_key); + } if ($invoice->due_date) { $carbonDueDate = \Carbon::parse($invoice->due_date); diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index 0fc43d99433d..6b2ee1e90f46 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -75,6 +75,7 @@ class ReportController extends BaseController 'activity', 'aging', 'client', + 'credit', 'document', 'expense', 'invoice', diff --git a/app/Http/Controllers/SubscriptionController.php b/app/Http/Controllers/SubscriptionController.php index 82d4d2fcbc9b..adb97de565a3 100644 --- a/app/Http/Controllers/SubscriptionController.php +++ b/app/Http/Controllers/SubscriptionController.php @@ -134,6 +134,7 @@ class SubscriptionController extends BaseController $subscription = Subscription::scope($subscriptionPublicId)->firstOrFail(); } else { $subscription = Subscription::createNew(); + $subscriptionPublicId = $subscription->public_id; } $validator = Validator::make(Input::all(), $rules); @@ -154,6 +155,14 @@ class SubscriptionController extends BaseController Session::flash('message', $message); } - return Redirect::to('settings/' . ACCOUNT_API_TOKENS); + return redirect('/settings/api_tokens'); + + /* + if ($subscriptionPublicId) { + return Redirect::to('subscriptions/' . $subscriptionPublicId . '/edit'); + } else { + return redirect('/settings/api_tokens'); + } + */ } } diff --git a/app/Http/Controllers/TaskKanbanController.php b/app/Http/Controllers/TaskKanbanController.php index b493c784d7a8..f00be58d7f92 100644 --- a/app/Http/Controllers/TaskKanbanController.php +++ b/app/Http/Controllers/TaskKanbanController.php @@ -55,8 +55,16 @@ class TaskKanbanController extends BaseController $task->task_status_sort_order = $i++; $task->save(); } - // otherwise, check that the tasks orders are correct + // otherwise, check that the orders are correct } else { + for ($i=0; $i<$statuses->count(); $i++) { + $status = $statuses[$i]; + if ($status->sort_order != $i) { + $status->sort_order = $i; + $status->save(); + } + } + $firstStatus = $statuses[0]; $counts = []; foreach ($tasks as $task) { diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index f4f5ac3a29af..384bd48a9186 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -118,7 +118,7 @@ class UserController extends BaseController } if (! Auth::user()->confirmed) { - Session::flash('error', trans('texts.confirmation_required')); + Session::flash('error', trans('texts.confirmation_required', ['link' => link_to('/resend_confirmation', trans('texts.click_here'))])); return Redirect::to('settings/' . ACCOUNT_USER_MANAGEMENT); } diff --git a/app/Http/Middleware/ApiCheck.php b/app/Http/Middleware/ApiCheck.php index 310ebaaf60aa..7bd19386d6ea 100644 --- a/app/Http/Middleware/ApiCheck.php +++ b/app/Http/Middleware/ApiCheck.php @@ -100,8 +100,8 @@ class ApiCheck return Response::json("Please wait {$wait} second(s)", 403, $headers); } - Cache::put("hour_throttle:{$key}", $new_hour_throttle, 10); - Cache::put("last_api_request:{$key}", time(), 10); + Cache::put("hour_throttle:{$key}", $new_hour_throttle, 60); + Cache::put("last_api_request:{$key}", time(), 60); } return $next($request); diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php index c233ac7e770d..852bef8abf46 100644 --- a/app/Http/Middleware/Authenticate.php +++ b/app/Http/Middleware/Authenticate.php @@ -4,6 +4,7 @@ namespace App\Http\Middleware; use App\Models\Contact; use App\Models\Invitation; +use App\Models\ProposalInvitation; use Auth; use Closure; use Session; @@ -25,13 +26,14 @@ class Authenticate public function handle($request, Closure $next, $guard = 'user') { $authenticated = Auth::guard($guard)->check(); + $invitationKey = $request->invitation_key ?: $request->proposal_invitation_key; if ($guard == 'client') { - if (! empty($request->invitation_key)) { + if (! empty($request->invitation_key) || ! empty($request->proposal_invitation_key)) { $contact_key = session('contact_key'); if ($contact_key) { $contact = $this->getContact($contact_key); - $invitation = $this->getInvitation($request->invitation_key); + $invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key)); if (! $invitation) { return response()->view('error', [ @@ -59,7 +61,7 @@ class Authenticate $contact = false; if ($contact_key) { $contact = $this->getContact($contact_key); - } elseif ($invitation = $this->getInvitation($request->invitation_key)) { + } elseif ($invitation = $this->getInvitation($invitationKey, ! empty($request->proposal_invitation_key))) { $contact = $invitation->contact; Session::put('contact_key', $contact->contact_key); } @@ -89,6 +91,7 @@ class Authenticate if ($authenticated) { $request->merge(['contact' => $contact]); + $account->loadLocalizationSettings($contact->client); } } @@ -108,7 +111,7 @@ class Authenticate * * @return \Illuminate\Database\Eloquent\Model|null|static */ - protected function getInvitation($key) + protected function getInvitation($key, $isProposal = false) { if (! $key) { return false; @@ -118,7 +121,12 @@ class Authenticate list($key) = explode('&', $key); $key = substr($key, 0, RANDOM_KEY_LENGTH); - $invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first(); + if ($isProposal) { + $invitation = ProposalInvitation::withTrashed()->where('invitation_key', '=', $key)->first(); + } else { + $invitation = Invitation::withTrashed()->where('invitation_key', '=', $key)->first(); + } + if ($invitation && ! $invitation->is_deleted) { return $invitation; } else { diff --git a/app/Http/Middleware/DatabaseLookup.php b/app/Http/Middleware/DatabaseLookup.php index b01f68e9b031..6f8546376bd3 100644 --- a/app/Http/Middleware/DatabaseLookup.php +++ b/app/Http/Middleware/DatabaseLookup.php @@ -7,6 +7,7 @@ use Closure; use App\Models\LookupAccount; use App\Models\LookupContact; use App\Models\LookupInvitation; +use App\Models\LookupProposalInvitation; use App\Models\LookupAccountToken; use App\Models\LookupUser; use Auth; @@ -43,6 +44,8 @@ class DatabaseLookup } elseif ($guard == 'contact') { if ($key = request()->invitation_key) { LookupInvitation::setServerByField('invitation_key', $key); + } elseif ($key = request()->proposal_invitation_key) { + LookupProposalInvitation::setServerByField('invitation_key', $key); } elseif ($key = request()->contact_key ?: session('contact_key')) { LookupContact::setServerByField('contact_key', $key); } elseif ($key = request()->account_key) { diff --git a/app/Http/Middleware/StartupCheck.php b/app/Http/Middleware/StartupCheck.php index 6f96aee3ba3c..f4cd6e23d864 100644 --- a/app/Http/Middleware/StartupCheck.php +++ b/app/Http/Middleware/StartupCheck.php @@ -36,8 +36,13 @@ class StartupCheck // Set up trusted X-Forwarded-Proto proxies // TRUSTED_PROXIES accepts a comma delimited list of subnets // ie, TRUSTED_PROXIES='10.0.0.0/8,172.16.0.0/12,192.168.0.0/16' + // set TRUSTED_PROXIES=* if you want to trust every proxy. if (isset($_ENV['TRUSTED_PROXIES'])) { - $request->setTrustedProxies(array_map('trim', explode(',', env('TRUSTED_PROXIES')))); + if (env('TRUSTED_PROXIES') == '*') { + $request->setTrustedProxies(['127.0.0.1', $request->server->get('REMOTE_ADDR')]); + } else{ + $request->setTrustedProxies(array_map('trim', explode(',', env('TRUSTED_PROXIES')))); + } } // Ensure all request are over HTTPS in production @@ -218,7 +223,7 @@ class StartupCheck // Show message to IE 8 and before users if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(?i)msie [2-8]/', $_SERVER['HTTP_USER_AGENT'])) { - Session::flash('error', trans('texts.old_browser', ['link' => OUTDATE_BROWSER_URL])); + Session::flash('error', trans('texts.old_browser', ['link' => link_to(OUTDATE_BROWSER_URL, trans('texts.newer_browser'), ['target' => '_blank'])])); } $response = $next($request); diff --git a/app/Http/Requests/CreatePaymentTermAPIRequest.php b/app/Http/Requests/CreatePaymentTermAPIRequest.php new file mode 100644 index 000000000000..44002ecf90ee --- /dev/null +++ b/app/Http/Requests/CreatePaymentTermAPIRequest.php @@ -0,0 +1,36 @@ +user()->can('create', ENTITY_PAYMENT_TERM); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + + public function rules() + { + + $rules = [ + 'num_days' => 'required|numeric|unique:payment_terms', + ]; + + + return $rules; + } +} diff --git a/app/Http/Requests/CreateProposalCategoryRequest.php b/app/Http/Requests/CreateProposalCategoryRequest.php new file mode 100644 index 000000000000..3a11ddd73e2a --- /dev/null +++ b/app/Http/Requests/CreateProposalCategoryRequest.php @@ -0,0 +1,28 @@ +user()->can('create', ENTITY_PROPOSAL_CATEGORY); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => sprintf('required|unique:proposal_categories,name,,id,account_id,%s', $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/CreateProposalRequest.php b/app/Http/Requests/CreateProposalRequest.php new file mode 100644 index 000000000000..1c1c0fd59888 --- /dev/null +++ b/app/Http/Requests/CreateProposalRequest.php @@ -0,0 +1,28 @@ +user()->can('create', ENTITY_PROPOSAL); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'invoice_id' => 'required', + ]; + } +} diff --git a/app/Http/Requests/CreateProposalSnippetRequest.php b/app/Http/Requests/CreateProposalSnippetRequest.php new file mode 100644 index 000000000000..b54d976e08ea --- /dev/null +++ b/app/Http/Requests/CreateProposalSnippetRequest.php @@ -0,0 +1,28 @@ +user()->can('create', ENTITY_PROPOSAL_SNIPPET); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => sprintf('required|unique:proposal_snippets,name,,id,account_id,%s', $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/CreateProposalTemplateRequest.php b/app/Http/Requests/CreateProposalTemplateRequest.php new file mode 100644 index 000000000000..faebe4a157d9 --- /dev/null +++ b/app/Http/Requests/CreateProposalTemplateRequest.php @@ -0,0 +1,28 @@ +user()->can('create', ENTITY_PROPOSAL_TEMPLATE); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => sprintf('required|unique:proposal_templates,name,,id,account_id,%s', $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/EntityRequest.php b/app/Http/Requests/EntityRequest.php index 37734f183d47..92b3533dd842 100644 --- a/app/Http/Requests/EntityRequest.php +++ b/app/Http/Requests/EntityRequest.php @@ -35,6 +35,7 @@ class EntityRequest extends Request if (! $publicId) { $publicId = Input::get('public_id') ?: Input::get('id'); } + if (! $publicId) { return null; } diff --git a/app/Http/Requests/PaymentTermRequest.php b/app/Http/Requests/PaymentTermRequest.php new file mode 100644 index 000000000000..adb224eb4788 --- /dev/null +++ b/app/Http/Requests/PaymentTermRequest.php @@ -0,0 +1,8 @@ +all(); + + // check if we're creating a new proposal category + if ($this->proposal_category_id == '-1') { + $data = [ + 'name' => trim($this->proposal_category_name) + ]; + if (ProposalCategory::validate($data) === true) { + $category = app('App\Ninja\Repositories\ProposalCategoryRepository')->save($data); + $input['proposal_category_id'] = $category->id; + } else { + $input['proposal_category_id'] = null; + } + } elseif ($this->proposal_category_id) { + $input['proposal_category_id'] = ProposalCategory::getPrivateId($this->proposal_category_id); + } + + $this->replace($input); + + return $this->all(); + } +} diff --git a/app/Http/Requests/ProposalTemplateRequest.php b/app/Http/Requests/ProposalTemplateRequest.php new file mode 100644 index 000000000000..07d83fe9f45d --- /dev/null +++ b/app/Http/Requests/ProposalTemplateRequest.php @@ -0,0 +1,8 @@ +entity()->id; $rules = [ - 'invoice_items' => 'valid_invoice_items', + 'invoice_items' => 'required|valid_invoice_items', 'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id, 'discount' => 'positive', //'invoice_date' => 'date', diff --git a/app/Http/Requests/UpdateInvoiceRequest.php b/app/Http/Requests/UpdateInvoiceRequest.php index 07f39406e3e5..a3bc5f9ab2f2 100644 --- a/app/Http/Requests/UpdateInvoiceRequest.php +++ b/app/Http/Requests/UpdateInvoiceRequest.php @@ -31,7 +31,7 @@ class UpdateInvoiceRequest extends InvoiceRequest $rules = [ 'client' => 'required', - 'invoice_items' => 'valid_invoice_items', + 'invoice_items' => 'required|valid_invoice_items', 'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id, 'discount' => 'positive', 'invoice_date' => 'required', diff --git a/app/Http/Requests/UpdatePaymentTermRequest.php b/app/Http/Requests/UpdatePaymentTermRequest.php new file mode 100644 index 000000000000..022a65087d39 --- /dev/null +++ b/app/Http/Requests/UpdatePaymentTermRequest.php @@ -0,0 +1,17 @@ +entity() && $this->user()->can('edit', $this->entity()); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + if (! $this->entity()) { + return []; + } + + return [ + 'name' => sprintf('required|unique:proposal_categories,name,,id,account_id,%s', $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/UpdateProposalRequest.php b/app/Http/Requests/UpdateProposalRequest.php new file mode 100644 index 000000000000..8e106e045232 --- /dev/null +++ b/app/Http/Requests/UpdateProposalRequest.php @@ -0,0 +1,32 @@ +entity() && $this->user()->can('edit', $this->entity()); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + if (! $this->entity()) { + return []; + } + + return [ + 'invoice_id' => 'required', + ]; + } +} diff --git a/app/Http/Requests/UpdateProposalSnippetRequest.php b/app/Http/Requests/UpdateProposalSnippetRequest.php new file mode 100644 index 000000000000..052d4e7a0b43 --- /dev/null +++ b/app/Http/Requests/UpdateProposalSnippetRequest.php @@ -0,0 +1,32 @@ +entity() && $this->user()->can('edit', $this->entity()); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + if (! $this->entity()) { + return []; + } + + return [ + 'name' => sprintf('required|unique:proposal_snippets,name,%s,id,account_id,%s', $this->entity()->id, $this->user()->account_id), + ]; + } +} diff --git a/app/Http/Requests/UpdateProposalTemplateRequest.php b/app/Http/Requests/UpdateProposalTemplateRequest.php new file mode 100644 index 000000000000..68cfde293e1f --- /dev/null +++ b/app/Http/Requests/UpdateProposalTemplateRequest.php @@ -0,0 +1,32 @@ +entity() && $this->user()->can('edit', $this->entity()); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + if (! $this->entity()) { + return []; + } + + return [ + 'name' => sprintf('required|unique:proposal_templates,name,%s,id,account_id,%s', $this->entity()->id, $this->user()->account_id), + ]; + } +} diff --git a/app/Http/ViewComposers/ProposalComposer.php b/app/Http/ViewComposers/ProposalComposer.php new file mode 100644 index 000000000000..e491b52d6592 --- /dev/null +++ b/app/Http/ViewComposers/ProposalComposer.php @@ -0,0 +1,48 @@ +with('proposal_category') + ->orderBy('name') + ->get(); + + $view->with('snippets', $snippets); + + + $documents = Document::scope() + ->whereNull('invoice_id') + ->whereNull('expense_id') + ->get(); + + $data = []; + foreach ($documents as $document) { + $data[] = [ + 'src' => $document->getProposalUrl(), + 'public_id' => $document->public_id, + ]; + } + + $view->with('documents', $data); + } +} diff --git a/app/Jobs/ConvertInvoiceToUbl.php b/app/Jobs/ConvertInvoiceToUbl.php new file mode 100644 index 000000000000..c19abc5111fb --- /dev/null +++ b/app/Jobs/ConvertInvoiceToUbl.php @@ -0,0 +1,157 @@ +invoice = $invoice; + } + + public function handle() + { + $invoice = $this->invoice; + $account = $invoice->account; + $client = $invoice->client; + $ublInvoice = new Invoice(); + + // invoice + $ublInvoice->setId($invoice->invoice_number); + $ublInvoice->setIssueDate(date_create($invoice->invoice_date)); + $ublInvoice->setInvoiceTypeCode($invoice->amount < 0 ? self::INVOICE_TYPE_CREDIT : self::INVOICE_TYPE_STANDARD); + + $supplierParty = $this->createParty($account, $invoice->user); + $ublInvoice->setAccountingSupplierParty($supplierParty); + + $customerParty = $this->createParty($client, $client->contacts[0]); + $ublInvoice->setAccountingCustomerParty($customerParty); + + // line items + $invoiceLine = []; + $taxable = $invoice->getTaxable(); + + foreach ($invoice->invoice_items as $index => $item) { + $itemTaxable = $invoice->getItemTaxable($item, $taxable); + $item->setRelation('invoice', $invoice); + $invoiceLines[] = $this->createInvoiceLine($index, $item, $itemTaxable); + } + + $ublInvoice->setInvoiceLines($invoiceLines); + + if ($invoice->hasTaxes()) { + $taxtotal = new TaxTotal(); + $taxAmount1 = $taxAmount2 = 0; + + if ($invoice->tax_name1 || floatval($invoice->tax_rate1)) { + $taxAmount1 = $this->createTaxRate($taxtotal, $taxable, $invoice->tax_rate1, $invoice->tax_name1); + } + + if ($invoice->tax_name2 || floatval($invoice->tax_rate2)) { + $taxAmount2 = $this->createTaxRate($taxtotal, $taxable, $invoice->tax_rate2, $invoice->tax_name2); + } + + $taxtotal->setTaxAmount($taxAmount1 + $taxAmount2); + $ublInvoice->setTaxTotal($taxtotal); + } + + $ublInvoice->setLegalMonetaryTotal((new LegalMonetaryTotal()) + //->setLineExtensionAmount() + ->setTaxExclusiveAmount($taxable) + ->setPayableAmount($invoice->balance)); + + return Generator::invoice($ublInvoice, $invoice->client->getCurrencyCode()); + } + + private function createParty($company, $user) + { + $party = new Party(); + $party->setName($company->name); + $address = (new Address()) + ->setCityName($company->city) + ->setStreetName($company->address1) + ->setBuildingNumber($company->address2) + ->setPostalZone($company->postal_code); + + if ($company->country_id) { + $country = new Country(); + $country->setIdentificationCode($company->country->iso_3166_2); + $address->setCountry($country); + } + + $party->setPostalAddress($address); + $party->setPhysicalLocation($address); + + $contact = new Contact(); + $contact->setElectronicMail($user->email); + $party->setContact($contact); + + return $party; + } + + private function createInvoiceLine($index, $item, $taxable) + { + $invoiceLine = (new InvoiceLine()) + ->setId($index + 1) + ->setInvoicedQuantity($item->qty) + ->setLineExtensionAmount($item->costWithDiscount()) + ->setItem((new Item()) + ->setName($item->product_key) + ->setDescription($item->description)); + //->setSellersItemIdentification("1ABCD")); + + if ($item->hasTaxes()) { + $taxtotal = new TaxTotal(); + $itemTaxAmount1 = $itemTaxAmount2 = 0; + + if ($item->tax_name1 || floatval($item->tax_rate1)) { + $itemTaxAmount1 = $this->createTaxRate($taxtotal, $taxable, $item->tax_rate1, $item->tax_name1); + } + + if ($item->tax_name2 || floatval($item->tax_rate2)) { + $itemTaxAmount2 = $this->createTaxRate($taxtotal, $taxable, $item->tax_rate2, $item->tax_name2); + } + + $taxtotal->setTaxAmount($itemTaxAmount1 + $itemTaxAmount2); + $invoiceLine->setTaxTotal($taxtotal); + } + + return $invoiceLine; + } + + private function createTaxRate(&$taxtotal, $taxable, $taxRate, $taxName) + { + $invoice = $this->invoice; + $taxAmount = $invoice->taxAmount($taxable, $taxRate); + $taxScheme = ((new TaxScheme()))->setId($taxName); + + $taxtotal->addTaxSubTotal((new TaxSubTotal()) + ->setTaxAmount($taxAmount) + ->setTaxableAmount($taxable) + ->setTaxCategory((new TaxCategory()) + ->setId($taxName) + ->setName($taxName) + ->setTaxScheme($taxScheme) + ->setPercent($taxRate))); + + return $taxAmount; + } +} diff --git a/app/Jobs/DownloadInvoices.php b/app/Jobs/DownloadInvoices.php index 4304e3cc2170..2fd37b97198f 100644 --- a/app/Jobs/DownloadInvoices.php +++ b/app/Jobs/DownloadInvoices.php @@ -46,6 +46,10 @@ class DownloadInvoices extends Job */ public function handle(UserMailer $userMailer) { + if (! extension_loaded('GMP')) { + die(trans('texts.gmp_required')); + } + $zip = Archive::instance_by_useragent(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoice_pdfs'))); foreach ($this->invoices as $invoice) { @@ -54,34 +58,5 @@ class DownloadInvoices extends Job $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 1151d70c7f97..a43a3f0a907f 100644 --- a/app/Jobs/PurgeAccountData.php +++ b/app/Jobs/PurgeAccountData.php @@ -50,6 +50,11 @@ class PurgeAccountData extends Job 'vendors', 'contacts', 'clients', + 'proposals', + 'proposal_templates', + 'proposal_snippets', + 'proposal_categories', + 'proposal_invitations', ]; foreach ($tables as $table) { @@ -71,6 +76,7 @@ class PurgeAccountData extends Job $lookupAccount = LookupAccount::whereAccountKey($account->account_key)->firstOrFail(); DB::table('lookup_contacts')->where('lookup_account_id', '=', $lookupAccount->id)->delete(); DB::table('lookup_invitations')->where('lookup_account_id', '=', $lookupAccount->id)->delete(); + DB::table('lookup_proposal_invitations')->where('lookup_account_id', '=', $lookupAccount->id)->delete(); config(['database.default' => $current]); } diff --git a/app/Jobs/SendInvoiceEmail.php b/app/Jobs/SendInvoiceEmail.php index 1046372686ca..effa021b9be7 100644 --- a/app/Jobs/SendInvoiceEmail.php +++ b/app/Jobs/SendInvoiceEmail.php @@ -43,6 +43,11 @@ class SendInvoiceEmail extends Job implements ShouldQueue */ protected $server; + /** + * @var Proposal + */ + protected $proposal; + /** * Create a new job instance. * @@ -51,12 +56,13 @@ class SendInvoiceEmail extends Job implements ShouldQueue * @param bool $reminder * @param mixed $pdfString */ - public function __construct(Invoice $invoice, $userId = false, $reminder = false, $template = false) + public function __construct(Invoice $invoice, $userId = false, $reminder = false, $template = false, $proposal = false) { $this->invoice = $invoice; $this->userId = $userId; $this->reminder = $reminder; $this->template = $template; + $this->proposal = $proposal; $this->server = config('database.default'); } @@ -72,7 +78,7 @@ class SendInvoiceEmail extends Job implements ShouldQueue Auth::onceUsingId($this->userId); } - $mailer->sendInvoice($this->invoice, $this->reminder, $this->template); + $mailer->sendInvoice($this->invoice, $this->reminder, $this->template, $this->proposal); if (App::runningInConsole() && $this->userId) { Auth::logout(); diff --git a/app/Libraries/HTMLUtils.php b/app/Libraries/HTMLUtils.php index 1b42f1bbe7b7..3fc7b5957bbb 100644 --- a/app/Libraries/HTMLUtils.php +++ b/app/Libraries/HTMLUtils.php @@ -61,4 +61,17 @@ class HTMLUtils return $previous; } } + + public static function getEnvForAccount($field, $default = '') + { + $key = ''; + + if ($user = auth()->user()) { + $key .= $user->account->id . '_'; + } + + $key .= $field; + + return env($key, env($field, $default)); + } } diff --git a/app/Libraries/HistoryUtils.php b/app/Libraries/HistoryUtils.php index 63734d218570..b9782b6dab9a 100644 --- a/app/Libraries/HistoryUtils.php +++ b/app/Libraries/HistoryUtils.php @@ -12,6 +12,7 @@ class HistoryUtils public static function loadHistory($users) { $userIds = []; + session([RECENTLY_VIEWED => false]); if (is_array($users)) { foreach ($users as $user) { @@ -37,7 +38,7 @@ class HistoryUtils ACTIVITY_TYPE_VIEW_QUOTE, ]; - $activities = Activity::with(['client.contacts', 'invoice', 'task', 'expense']) + $activities = Activity::with(['client.contacts', 'invoice', 'task.project', 'expense']) ->whereIn('user_id', $userIds) ->whereIn('activity_type_id', $activityTypes) ->orderBy('id', 'desc') @@ -53,6 +54,12 @@ class HistoryUtils continue; } $entity->setRelation('client', $activity->client); + + if ($entity->project) { + $project = $entity->project; + $project->setRelation('client', $activity->client); + static::trackViewed($project); + } } elseif ($activity->activity_type_id == ACTIVITY_TYPE_CREATE_EXPENSE || $activity->activity_type_id == ACTIVITY_TYPE_UPDATE_EXPENSE) { $entity = $activity->expense; if (! $entity) { @@ -80,6 +87,8 @@ class HistoryUtils ENTITY_QUOTE, ENTITY_TASK, ENTITY_EXPENSE, + ENTITY_PROJECT, + ENTITY_PROPOSAL, //ENTITY_RECURRING_EXPENSE, ]; @@ -87,6 +96,10 @@ class HistoryUtils return; } + if ($entity->is_deleted) { + return; + } + $object = static::convertToObject($entity); $history = Session::get(RECENTLY_VIEWED) ?: []; $accountHistory = isset($history[$entity->account_id]) ? $history[$entity->account_id] : []; @@ -135,6 +148,9 @@ class HistoryUtils } elseif (method_exists($entity, 'client') && $entity->client) { $object->client_id = $entity->client->public_id; $object->client_name = $entity->client->getDisplayName(); + } elseif (method_exists($entity, 'invoice') && $entity->invoice) { + $object->client_id = $entity->invoice->client->public_id; + $object->client_name = $entity->invoice->client->getDisplayName(); } else { $object->client_id = 0; $object->client_name = 0; @@ -175,7 +191,8 @@ class HistoryUtils $button = ''; } - $str .= sprintf('
  • %s
    %s %s
  • ', $button, $link, $icon, $name); + $padding = $str ? 16 : 0; + $str .= sprintf('
  • %s
    %s %s
  • ', $padding, $button, $link, $icon, $name); $lastClientId = $item->client_id; } diff --git a/app/Libraries/Utils.php b/app/Libraries/Utils.php index 6464043d6b3f..3de931825126 100644 --- a/app/Libraries/Utils.php +++ b/app/Libraries/Utils.php @@ -364,7 +364,9 @@ class Utils if ($field == 'checkbox') { $data[] = $field; } elseif ($field) { - if ($module) { + if (substr($field, 0, 1) == '-') { + $data[] = substr($field, 1); + } elseif ($module) { $data[] = mtrans($module, $field); } else { $data[] = trans("texts.$field"); @@ -564,6 +566,10 @@ class Utils if ($type === ENTITY_EXPENSE_CATEGORY) { return 'expense_categories'; + } elseif ($type === ENTITY_PROPOSAL_CATEGORY) { + return 'proposal_categories'; + } elseif ($type === ENTITY_TASK_STATUS) { + return 'task_statuses'; } else { return $type . 's'; } @@ -1087,6 +1093,25 @@ class Utils } } + public static function getCustomLabel($value) + { + if (strpos($value, '|') !== false) { + return explode('|', $value)[0]; + } else { + return $value; + } + } + + public static function getCustomValues($value) + { + if (strpos($value, '|') !== false) { + $values = explode(',', explode('|', $value)[1]); + return array_combine($values, $values); + } else { + return $value; + } + } + public static function formatWebsite($link) { if (! $link) { @@ -1260,7 +1285,7 @@ class Utils $tax1 = round($amount * $taxRate1 / 100, 2); $tax2 = round($amount * $taxRate2 / 100, 2); - return round($amount + $tax1 + $tax2, 2); + return round($tax1 + $tax2, 2); } public static function roundSignificant($value, $precision = 2) { diff --git a/app/Listeners/DNSListener.php b/app/Listeners/DNSListener.php index 83d6253a74a4..33126f86520a 100644 --- a/app/Listeners/DNSListener.php +++ b/app/Listeners/DNSListener.php @@ -2,6 +2,7 @@ namespace App\Listeners; +use App\Events\SubdomainWasRemoved; use App\Events\SubdomainWasUpdated; use App\Ninja\DNS\Cloudflare; @@ -19,4 +20,11 @@ class DNSListener if(env("CLOUDFLARE_DNS_ENABLED")) Cloudflare::addDNSRecord($event->account); } + + public function removeDNSRecord(SubdomainWasRemoved $event) + { + if(env("CLOUDFLARE_DNS_ENABLED")) + Cloudflare::removeDNSRecord($event->account); + } + } diff --git a/app/Listeners/HandleUserLoggedIn.php b/app/Listeners/HandleUserLoggedIn.php index 9eee5232041c..3fd5380f4e04 100644 --- a/app/Listeners/HandleUserLoggedIn.php +++ b/app/Listeners/HandleUserLoggedIn.php @@ -102,7 +102,7 @@ class HandleUserLoggedIn if (in_array(config('app.key'), ['SomeRandomString', 'SomeRandomStringSomeRandomString', 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'])) { Session::flash('error', trans('texts.error_app_key_set_to_default')); } elseif (in_array($appCipher, ['MCRYPT_RIJNDAEL_256', 'MCRYPT_RIJNDAEL_128'])) { - Session::flash('error', trans('texts.mcrypt_warning')); + Session::flash('error', trans('texts.mcrypt_warning', ['command' => 'php artisan ninja:update-key --legacy=true'])); } } } diff --git a/app/Listeners/HandleUserSettingsChanged.php b/app/Listeners/HandleUserSettingsChanged.php index f1910ab2f116..3413812eaba7 100644 --- a/app/Listeners/HandleUserSettingsChanged.php +++ b/app/Listeners/HandleUserSettingsChanged.php @@ -46,6 +46,8 @@ class HandleUserSettingsChanged if ($event->user && $event->user->isEmailBeingChanged()) { $this->userMailer->sendConfirmation($event->user); + $this->userMailer->sendEmailChanged($event->user); + Session::flash('warning', trans('texts.verify_email')); } } diff --git a/app/Listeners/SubscriptionListener.php b/app/Listeners/SubscriptionListener.php index 769e007da422..bb610d4deeed 100644 --- a/app/Listeners/SubscriptionListener.php +++ b/app/Listeners/SubscriptionListener.php @@ -254,19 +254,30 @@ class SubscriptionListener return; } + // generate JSON data $manager = new Manager(); $manager->setSerializer(new ArraySerializer()); $manager->parseIncludes($include); $resource = new Item($entity, $transformer, $entity->getEntityType()); - $data = $manager->createData($resource)->toArray(); + $jsonData = $manager->createData($resource)->toArray(); // For legacy Zapier support - if (isset($data['client_id'])) { - $data['client_name'] = $entity->client->getDisplayName(); + if (isset($jsonData['client_id'])) { + $jsonData['client_name'] = $entity->client->getDisplayName(); } + + foreach ($subscriptions as $subscription) { + switch ($subscription->format) { + case SUBSCRIPTION_FORMAT_JSON: + $data = $jsonData; + break; + case SUBSCRIPTION_FORMAT_UBL: + $data = $ublData; + break; + } self::notifySubscription($subscription, $data); } } diff --git a/app/Models/Account.php b/app/Models/Account.php index 86c0de60ec6d..184a15fba043 100644 --- a/app/Models/Account.php +++ b/app/Models/Account.php @@ -146,6 +146,7 @@ class Account extends Eloquent 'invoice_fields', 'invoice_embed_documents', 'document_email_attachment', + 'ubl_email_attachment', 'enable_client_portal_dashboard', 'page_size', 'live_preview', @@ -237,6 +238,8 @@ class Account extends Eloquent 'hours', 'id_number', 'invoice', + 'invoice_date', + 'invoice_number', 'item', 'line_total', 'outstanding', @@ -245,6 +248,8 @@ class Account extends Eloquent 'po_number', 'quantity', 'quote', + 'quote_date', + 'quote_number', 'rate', 'service', 'subtotal', @@ -500,7 +505,7 @@ class Account extends Eloquent if ($gatewayId) { return $this->getGatewayConfig($gatewayId) != false; } else { - return count($this->account_gateways) > 0; + return $this->account_gateways->count() > 0; } } @@ -1484,6 +1489,14 @@ class Account extends Eloquent return $this->hasFeature(FEATURE_PDF_ATTACHMENT) && $this->pdf_email_attachment; } + /** + * @return bool + */ + public function attachUBL() + { + return $this->hasFeature(FEATURE_PDF_ATTACHMENT) && $this->ubl_email_attachment; + } + /** * @return mixed */ @@ -1643,6 +1656,7 @@ class Account extends Eloquent ENTITY_EXPENSE, ENTITY_VENDOR, ENTITY_PROJECT, + ENTITY_PROPOSAL, ])) { return true; } @@ -1651,6 +1665,8 @@ class Account extends Eloquent $entityType = ENTITY_EXPENSE; } elseif ($entityType == ENTITY_PROJECT) { $entityType = ENTITY_TASK; + } elseif ($entityType == ENTITY_PROPOSAL) { + $entityType = ENTITY_QUOTE; } // note: single & checks bitmask match diff --git a/app/Models/AccountEmailSettings.php b/app/Models/AccountEmailSettings.php index e949127710ef..19865151cc06 100644 --- a/app/Models/AccountEmailSettings.php +++ b/app/Models/AccountEmailSettings.php @@ -38,6 +38,7 @@ class AccountEmailSettings extends Eloquent public static $templates = [ TEMPLATE_INVOICE, TEMPLATE_QUOTE, + TEMPLATE_PROPOSAL, //TEMPLATE_PARTIAL, TEMPLATE_PAYMENT, TEMPLATE_REMINDER1, diff --git a/app/Models/AccountGateway.php b/app/Models/AccountGateway.php index a5757ad7448e..535ec60de72c 100644 --- a/app/Models/AccountGateway.php +++ b/app/Models/AccountGateway.php @@ -268,4 +268,13 @@ class AccountGateway extends EntityModel return \URL::to(env('WEBHOOK_PREFIX', '').'payment_hook/'.$account->account_key.'/'.$this->gateway_id.env('WEBHOOK_SUFFIX', '')); } + + public function isTestMode() + { + if ($this->isGateway(GATEWAY_STRIPE)) { + return strpos($this->getPublishableStripeKey(), 'test') !== false; + } else { + return $this->getConfigField('testMode'); + } + } } diff --git a/app/Models/Client.php b/app/Models/Client.php index 7d992d6c90fb..de128945adb3 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -351,7 +351,7 @@ class Client extends EntityModel return $this->name; } - if (! count($this->contacts)) { + if (! $this->contacts->count()) { return ''; } @@ -386,6 +386,29 @@ class Client extends EntityModel return $this->hasAddress() && env('GOOGLE_MAPS_ENABLED') !== false; } + /** + * @return bool + */ + public function addressesMatch() + { + $fields = [ + 'address1', + 'address2', + 'city', + 'state', + 'postal_code', + 'country_id', + ]; + + foreach ($fields as $field) { + if ($this->$field != $this->{'shipping_' . $field}) { + return false; + } + } + + return true; + } + /** * @return bool */ diff --git a/app/Models/Contact.php b/app/Models/Contact.php index 2f20a8f8aa10..4a73944549db 100644 --- a/app/Models/Contact.php +++ b/app/Models/Contact.php @@ -131,6 +131,21 @@ class Contact extends EntityModel implements AuthenticatableContract, CanResetPa } } + /** + * @return mixed|string + */ + public function getSearchName() + { + $name = $this->getFullName(); + $email = $this->email; + + if ($name && $email) { + return sprintf('%s <%s>', $name, $email); + } else { + return $name ?: $email; + } + } + /** * @param $contact_key * diff --git a/app/Models/Country.php b/app/Models/Country.php index e10719ff2904..ca6d7747f50c 100644 --- a/app/Models/Country.php +++ b/app/Models/Country.php @@ -41,6 +41,6 @@ class Country extends Eloquent */ public function getName() { - return $this->name; + return trans('texts.country_' . $this->name); } } diff --git a/app/Models/Document.php b/app/Models/Document.php index 90de300f5b81..a1d03ee355b6 100644 --- a/app/Models/Document.php +++ b/app/Models/Document.php @@ -272,6 +272,15 @@ class Document extends EntityModel return url('client/documents/'.$invitation->invitation_key.'/'.$this->public_id.'/'.$this->name); } + public function getProposalUrl() + { + if (! $this->is_proposal || ! $this->document_key) { + return ''; + } + + return url('proposal/image/'. $this->account->account_key . '/' . $this->document_key . '/' . $this->name); + } + /** * @return bool */ diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php index e830e56a0348..d922d641e7ad 100644 --- a/app/Models/EntityModel.php +++ b/app/Models/EntityModel.php @@ -321,6 +321,7 @@ class EntityModel extends Eloquent 'recurring_expenses' => 'files-o', 'credits' => 'credit-card', 'quotes' => 'file-text-o', + 'proposals' => 'th-large', 'tasks' => 'clock-o', 'expenses' => 'file-image-o', 'vendors' => 'building', @@ -354,6 +355,15 @@ class EntityModel extends Eloquent return false; } + public static function getFormUrl($entityType) + { + if (in_array($entityType, [ENTITY_PROPOSAL_CATEGORY, ENTITY_PROPOSAL_SNIPPET, ENTITY_PROPOSAL_TEMPLATE])) { + return str_replace('_', 's/', Utils::pluralizeEntityType($entityType)); + } else { + return Utils::pluralizeEntityType($entityType); + } + } + public static function getStates($entityType = false) { $data = []; diff --git a/app/Models/Expense.php b/app/Models/Expense.php index 1dc81d2c381e..34c92288a83c 100644 --- a/app/Models/Expense.php +++ b/app/Models/Expense.php @@ -61,6 +61,7 @@ class Expense extends EntityModel 'vendor', 'amount', 'public_notes', + 'private_notes', 'expense_category', 'expense_date', ]; @@ -73,7 +74,8 @@ class Expense extends EntityModel 'category' => 'expense_category', 'client' => 'client', 'vendor' => 'vendor', - 'notes|details' => 'public_notes', + 'notes|details^private' => 'public_notes', + 'notes|details^public' => 'private_notes', 'date' => 'expense_date', ]; } @@ -253,6 +255,11 @@ class Expense extends EntityModel } public function amountWithTax() + { + return $this->amount + $this->taxAmount(); + } + + public function taxAmount() { return Utils::calculateTaxes($this->amount, $this->tax_rate1, $this->tax_rate2); } diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php index 76d395efd744..8fa8a23b73c0 100644 --- a/app/Models/Invitation.php +++ b/app/Models/Invitation.php @@ -2,10 +2,9 @@ namespace App\Models; -use Carbon; use Illuminate\Database\Eloquent\SoftDeletes; -use Utils; use App\Models\LookupInvitation; +use App\Models\Traits\Inviteable; /** * Class Invitation. @@ -13,6 +12,8 @@ use App\Models\LookupInvitation; class Invitation extends EntityModel { use SoftDeletes; + use Inviteable; + /** * @var array */ @@ -58,102 +59,6 @@ class Invitation extends EntityModel return $this->belongsTo('App\Models\Account'); } - // If we're getting the link for PhantomJS to generate the PDF - // we need to make sure it's served from our site - - /** - * @param string $type - * @param bool $forceOnsite - * - * @return string - */ - public function getLink($type = 'view', $forceOnsite = false, $forcePlain = false) - { - if (! $this->account) { - $this->load('account'); - } - - $account = $this->account; - $iframe_url = $account->iframe_url; - $url = trim(SITE_URL, '/'); - - if (env('REQUIRE_HTTPS')) { - $url = str_replace('http://', 'https://', $url); - } - - if ($account->hasFeature(FEATURE_CUSTOM_URL)) { - if (Utils::isNinjaProd() && ! Utils::isReseller()) { - $url = $account->present()->clientPortalLink(); - } - - if ($iframe_url && ! $forceOnsite) { - return "{$iframe_url}?{$this->invitation_key}"; - } elseif ($this->account->subdomain && ! $forcePlain) { - $url = Utils::replaceSubdomain($url, $account->subdomain); - } - } - - return "{$url}/{$type}/{$this->invitation_key}"; - } - - /** - * @return bool|string - */ - public function getStatus() - { - $hasValue = false; - $parts = []; - $statuses = $this->message_id ? ['sent', 'opened', 'viewed'] : ['sent', 'viewed']; - - foreach ($statuses as $status) { - $field = "{$status}_date"; - $date = ''; - if ($this->$field && $this->field != '0000-00-00 00:00:00') { - $date = Utils::dateToString($this->$field); - $hasValue = true; - $parts[] = trans('texts.invitation_status_' . $status) . ': ' . $date; - } - } - - return $hasValue ? implode($parts, '
    ') : false; - } - - /** - * @return mixed - */ - public function getName() - { - return $this->invitation_key; - } - - /** - * @param null $messageId - */ - public function markSent($messageId = null) - { - $this->message_id = $messageId; - $this->email_error = null; - $this->sent_date = Carbon::now()->toDateTimeString(); - $this->save(); - } - - public function isSent() - { - return $this->sent_date && $this->sent_date != '0000-00-00 00:00:00'; - } - - public function markViewed() - { - $invoice = $this->invoice; - $client = $invoice->client; - - $this->viewed_date = Carbon::now()->toDateTimeString(); - $this->save(); - - $invoice->markViewed(); - $client->markLoggedIn(); - } - public function signatureDiv() { if (! $this->signature_base64) { diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 9e7334ede818..a9f5ea0d36d9 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -451,6 +451,23 @@ class Invoice extends EntityModel implements BalanceAffecting ->where('is_recurring', '=', false); } + /** + * @param $query + * + * @return mixed + */ + public function scopeUnapprovedQuotes($query, $includeInvoiceId = false) + { + return $query->quotes() + ->where(function ($query) use ($includeInvoiceId) { + $query->whereId($includeInvoiceId) + ->orWhere(function ($query) { + $query->where('invoice_status_id', '<', INVOICE_STATUS_APPROVED) + ->whereNull('quote_invoice_id'); + }); + }); + } + /** * @param $query * @param $typeId @@ -710,11 +727,11 @@ class Invoice extends EntityModel implements BalanceAffecting /** * @return string */ - public function getFileName() + public function getFileName($extension = 'pdf') { $entityType = $this->getEntityType(); - return trans("texts.$entityType") . '_' . $this->invoice_number . '.pdf'; + return trans("texts.$entityType") . '_' . $this->invoice_number . '.' . $extension; } /** @@ -841,6 +858,14 @@ class Invoice extends EntityModel implements BalanceAffecting return $this->invoice_status_id >= INVOICE_STATUS_VIEWED; } + /** + * @return bool + */ + public function isApproved() + { + return $this->invoice_status_id >= INVOICE_STATUS_APPROVED || $this->quote_invoice_id; + } + /** * @return bool */ @@ -1403,21 +1428,12 @@ class Invoice extends EntityModel implements BalanceAffecting $paidAmount = $this->getAmountPaid($calculatePaid); if ($this->tax_name1) { - if ($account->inclusive_taxes) { - $invoiceTaxAmount = round($taxable - ($taxable / (1 + ($this->tax_rate1 / 100))), 2); - } else { - $invoiceTaxAmount = round($taxable * ($this->tax_rate1 / 100), 2); - } + $invoiceTaxAmount = $this->taxAmount($taxable, $this->tax_rate1); $invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0; $this->calculateTax($taxes, $this->tax_name1, $this->tax_rate1, $invoiceTaxAmount, $invoicePaidAmount); } - if ($this->tax_name2) { - if ($account->inclusive_taxes) { - $invoiceTaxAmount = round($taxable - ($taxable / (1 + ($this->tax_rate2 / 100))), 2); - } else { - $invoiceTaxAmount = round($taxable * ($this->tax_rate2 / 100), 2); - } + $invoiceTaxAmount = $this->taxAmount($taxable, $this->tax_rate2); $invoicePaidAmount = floatval($this->amount) && $invoiceTaxAmount ? ($paidAmount / $this->amount * $invoiceTaxAmount) : 0; $this->calculateTax($taxes, $this->tax_name2, $this->tax_rate2, $invoiceTaxAmount, $invoicePaidAmount); } @@ -1426,21 +1442,12 @@ class Invoice extends EntityModel implements BalanceAffecting $itemTaxable = $this->getItemTaxable($invoiceItem, $taxable); if ($invoiceItem->tax_name1) { - if ($account->inclusive_taxes) { - $itemTaxAmount = round($taxable - ($taxable / (1 + ($invoiceItem->tax_rate1 / 100))), 2); - } else { - $itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate1 / 100), 2); - } + $itemTaxAmount = $this->taxAmount($itemTaxable, $invoiceItem->tax_rate1); $itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0; $this->calculateTax($taxes, $invoiceItem->tax_name1, $invoiceItem->tax_rate1, $itemTaxAmount, $itemPaidAmount); } - if ($invoiceItem->tax_name2) { - if ($account->inclusive_taxes) { - $itemTaxAmount = round($taxable - ($taxable / (1 + ($invoiceItem->tax_rate2 / 100))), 2); - } else { - $itemTaxAmount = round($itemTaxable * ($invoiceItem->tax_rate2 / 100), 2); - } + $itemTaxAmount = $this->taxAmount($itemTaxable, $invoiceItem->tax_rate2); $itemPaidAmount = floatval($this->amount) && $itemTaxAmount ? ($paidAmount / $this->amount * $itemTaxAmount) : 0; $this->calculateTax($taxes, $invoiceItem->tax_name2, $invoiceItem->tax_rate2, $itemTaxAmount, $itemPaidAmount); } @@ -1449,6 +1456,28 @@ class Invoice extends EntityModel implements BalanceAffecting return $taxes; } + public function getTaxTotal() + { + $total = 0; + + foreach ($this->getTaxes() as $tax) { + $total += $tax['amount']; + } + + return $total; + } + + public function taxAmount($taxable, $rate) + { + $account = $this->account; + + if ($account->inclusive_taxes) { + return round($taxable - ($taxable / (1 + ($rate / 100))), 2); + } else { + return round($taxable * ($rate / 100), 2); + } + } + /** * @param $taxes * @param $name @@ -1484,18 +1513,18 @@ class Invoice extends EntityModel implements BalanceAffecting */ public function countDocuments($expenses = false) { - $count = count($this->documents); + $count = $this->documents->count(); foreach ($this->expenses as $expense) { if ($expense->invoice_documents) { - $count += count($expense->documents); + $count += $expense->documents->count(); } } if ($expenses) { foreach ($expenses as $expense) { if ($expense->invoice_documents) { - $count += count($expense->documents); + $count += $expense->documents->count(); } } } @@ -1525,7 +1554,7 @@ class Invoice extends EntityModel implements BalanceAffecting public function hasExpenseDocuments() { foreach ($this->expenses as $expense) { - if ($expense->invoice_documents && count($expense->documents)) { + if ($expense->invoice_documents && $expense->documents->count()) { return true; } } @@ -1606,6 +1635,28 @@ class Invoice extends EntityModel implements BalanceAffecting return true; } + + public function hasTaxes() + { + if ($this->tax_name1 || $this->tax_rate1) { + return true; + } + + if ($this->tax_name2 || $this->tax_rate2) { + return false; + } + + return false; + } + + public function isLocked() + { + if (! config('ninja.lock_sent_invoices')) { + return false; + } + + return $this->isSent() && ! $this->is_recurring; + } } Invoice::creating(function ($invoice) { diff --git a/app/Models/InvoiceItem.php b/app/Models/InvoiceItem.php index c30b16037f99..6d96e7201ec1 100644 --- a/app/Models/InvoiceItem.php +++ b/app/Models/InvoiceItem.php @@ -107,4 +107,33 @@ class InvoiceItem extends EntityModel $this->save(); } } + + public function hasTaxes() + { + if ($this->tax_name1 || $this->tax_rate1) { + return true; + } + + if ($this->tax_name2 || $this->tax_rate2) { + return false; + } + + return false; + } + + public function costWithDiscount() + { + $cost = $this->cost; + + if ($this->discount != 0) { + if ($this->invoice->is_amount_discount) { + $cost -= $discount / $this->qty; + } else { + $cost -= $cost * $discount / 100; + } + } + + return $cost; + } + } diff --git a/app/Models/LookupProposalInvitation.php b/app/Models/LookupProposalInvitation.php new file mode 100644 index 000000000000..cd5b348db362 --- /dev/null +++ b/app/Models/LookupProposalInvitation.php @@ -0,0 +1,47 @@ +message_id) { + return; + } + + $current = config('database.default'); + config(['database.default' => DB_NINJA_LOOKUP]); + + $lookupAccount = LookupAccount::whereAccountKey($accountKey) + ->firstOrFail(); + + $lookupInvitation = LookupProposalInvitation::whereLookupAccountId($lookupAccount->id) + ->whereInvitationKey($invitation->invitation_key) + ->firstOrFail(); + + $lookupInvitation->message_id = $invitation->message_id; + $lookupInvitation->save(); + + config(['database.default' => $current]); + } + +} diff --git a/app/Models/Product.php b/app/Models/Product.php index ca632d655ab8..455f75bc9fdf 100644 --- a/app/Models/Product.php +++ b/app/Models/Product.php @@ -47,6 +47,8 @@ class Product extends EntityModel 'product_key', 'notes', 'cost', + 'custom_value1', + 'custom_value2', ]; } @@ -59,6 +61,8 @@ class Product extends EntityModel 'product|item' => 'product_key', 'notes|description|details' => 'notes', 'cost|amount|price' => 'cost', + 'custom_value1' => 'custom_value1', + 'custom_value2' => 'custom_value2', ]; } diff --git a/app/Models/Proposal.php b/app/Models/Proposal.php new file mode 100644 index 000000000000..37ffe27b2402 --- /dev/null +++ b/app/Models/Proposal.php @@ -0,0 +1,107 @@ +public_id}"; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account() + { + return $this->belongsTo('App\Models\Account'); + } + + /** + * @return mixed + */ + public function invoice() + { + return $this->belongsTo('App\Models\Invoice')->withTrashed(); + } + + /** + * @return mixed + */ + public function invitations() + { + return $this->hasMany('App\Models\ProposalInvitation')->orderBy('proposal_invitations.contact_id'); + } + + /** + * @return mixed + */ + public function proposal_invitations() + { + return $this->hasMany('App\Models\ProposalInvitation')->orderBy('proposal_invitations.contact_id'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function proposal_template() + { + return $this->belongsTo('App\Models\ProposalTemplate')->withTrashed(); + } + + public function getDisplayName() + { + return $this->invoice->invoice_number; + } +} + +Proposal::creating(function ($project) { + $project->setNullValues(); +}); + +Proposal::updating(function ($project) { + $project->setNullValues(); +}); diff --git a/app/Models/ProposalCategory.php b/app/Models/ProposalCategory.php new file mode 100644 index 000000000000..2efda4258c3f --- /dev/null +++ b/app/Models/ProposalCategory.php @@ -0,0 +1,71 @@ +public_id}"; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account() + { + return $this->belongsTo('App\Models\Account'); + } + + public function getDisplayName() + { + return $this->name; + } +} + +/* +Proposal::creating(function ($project) { + $project->setNullValues(); +}); + +Proposal::updating(function ($project) { + $project->setNullValues(); +}); +*/ diff --git a/app/Models/ProposalInvitation.php b/app/Models/ProposalInvitation.php new file mode 100644 index 000000000000..0bfc6c1cc284 --- /dev/null +++ b/app/Models/ProposalInvitation.php @@ -0,0 +1,85 @@ +belongsTo('App\Models\Proposal')->withTrashed(); + } + + /** + * @return mixed + */ + public function contact() + { + return $this->belongsTo('App\Models\Contact')->withTrashed(); + } + + /** + * @return mixed + */ + public function user() + { + return $this->belongsTo('App\Models\User')->withTrashed(); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account() + { + return $this->belongsTo('App\Models\Account'); + } +} + +ProposalInvitation::creating(function ($invitation) +{ + LookupProposalInvitation::createNew($invitation->account->account_key, [ + 'invitation_key' => $invitation->invitation_key, + ]); +}); + +ProposalInvitation::updating(function ($invitation) +{ + $dirty = $invitation->getDirty(); + if (array_key_exists('message_id', $dirty)) { + LookupProposalInvitation::updateInvitation($invitation->account->account_key, $invitation); + } +}); + +ProposalInvitation::deleted(function ($invitation) +{ + if ($invitation->forceDeleting) { + LookupProposalInvitation::deleteWhere([ + 'invitation_key' => $invitation->invitation_key, + ]); + } +}); diff --git a/app/Models/ProposalSnippet.php b/app/Models/ProposalSnippet.php new file mode 100644 index 000000000000..b53720db9f2f --- /dev/null +++ b/app/Models/ProposalSnippet.php @@ -0,0 +1,84 @@ +public_id}"; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account() + { + return $this->belongsTo('App\Models\Account'); + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function proposal_category() + { + return $this->belongsTo('App\Models\ProposalCategory')->withTrashed(); + } + + public function getDisplayName() + { + return $this->name; + } +} + +/* +Proposal::creating(function ($project) { + $project->setNullValues(); +}); + +Proposal::updating(function ($project) { + $project->setNullValues(); +}); +*/ diff --git a/app/Models/ProposalTemplate.php b/app/Models/ProposalTemplate.php new file mode 100644 index 000000000000..1bd221ce95ba --- /dev/null +++ b/app/Models/ProposalTemplate.php @@ -0,0 +1,74 @@ +public_id}"; + } + + /** + * @return \Illuminate\Database\Eloquent\Relations\BelongsTo + */ + public function account() + { + return $this->belongsTo('App\Models\Account'); + } + + public function getDisplayName() + { + return $this->name; + } +} + +/* +Proposal::creating(function ($project) { + $project->setNullValues(); +}); + +Proposal::updating(function ($project) { + $project->setNullValues(); +}); +*/ diff --git a/app/Models/RecurringExpense.php b/app/Models/RecurringExpense.php index 04703e916104..8eb8b6c6f374 100644 --- a/app/Models/RecurringExpense.php +++ b/app/Models/RecurringExpense.php @@ -129,7 +129,7 @@ class RecurringExpense extends EntityModel public function amountWithTax() { - return Utils::calculateTaxes($this->amount, $this->tax_rate1, $this->tax_rate2); + return $this->amount + Utils::calculateTaxes($this->amount, $this->tax_rate1, $this->tax_rate2); } } diff --git a/app/Models/Subscription.php b/app/Models/Subscription.php index ad29cd07aa34..130195ee125e 100644 --- a/app/Models/Subscription.php +++ b/app/Models/Subscription.php @@ -28,6 +28,7 @@ class Subscription extends EntityModel protected $fillable = [ 'event_id', 'target_url', + 'format', ]; /** diff --git a/app/Models/Task.php b/app/Models/Task.php index 43a24cc6f81d..d6b01e2a60b4 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -129,17 +129,27 @@ class Task extends EntityModel * * @return int */ - public static function calcDuration($task) + public static function calcDuration($task, $startTimeCutoff = 0, $endTimeCutoff = 0) { $duration = 0; $parts = json_decode($task->time_log) ?: []; foreach ($parts as $part) { + $startTime = $part[0]; if (count($part) == 1 || ! $part[1]) { - $duration += time() - $part[0]; + $endTime = time(); } else { - $duration += $part[1] - $part[0]; + $endTime = $part[1]; } + + if ($startTimeCutoff) { + $startTime = max($startTime, $startTimeCutoff); + } + if ($endTimeCutoff) { + $endTime = min($endTime, $endTimeCutoff); + } + + $duration += $endTime - $startTime; } return $duration; @@ -148,9 +158,9 @@ class Task extends EntityModel /** * @return int */ - public function getDuration() + public function getDuration($startTimeCutoff = 0, $endTimeCutoff = 0) { - return self::calcDuration($this); + return self::calcDuration($this, $startTimeCutoff, $endTimeCutoff); } /** @@ -230,8 +240,11 @@ class Task extends EntityModel public function scopeDateRange($query, $startDate, $endDate) { - $query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) >= ' . $startDate->format('U')); - $query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) <= ' . $endDate->modify('+1 day')->format('U')); + $query->whereRaw('cast(substring(time_log, 3, 10) as unsigned) <= ' . $endDate->modify('+1 day')->format('U')) + ->whereRaw('case + when is_running then unix_timestamp() + else cast(substring(time_log, length(time_log) - 11, 10) as unsigned) + end >= ' . $startDate->format('U')); return $query; } diff --git a/app/Models/Traits/Inviteable.php b/app/Models/Traits/Inviteable.php new file mode 100644 index 000000000000..098c65cf5fe5 --- /dev/null +++ b/app/Models/Traits/Inviteable.php @@ -0,0 +1,113 @@ +account) { + $this->load('account'); + } + + if ($this->proposal_id) { + $type = 'proposal'; + } + + $account = $this->account; + $iframe_url = $account->iframe_url; + $url = trim(SITE_URL, '/'); + + if (env('REQUIRE_HTTPS')) { + $url = str_replace('http://', 'https://', $url); + } + + if ($account->hasFeature(FEATURE_CUSTOM_URL)) { + if (Utils::isNinjaProd() && ! Utils::isReseller()) { + $url = $account->present()->clientPortalLink(); + } + + if ($iframe_url && ! $forceOnsite) { + return "{$iframe_url}?{$this->invitation_key}"; + } elseif ($this->account->subdomain && ! $forcePlain) { + $url = Utils::replaceSubdomain($url, $account->subdomain); + } + } + + return "{$url}/{$type}/{$this->invitation_key}"; + } + + /** + * @return bool|string + */ + public function getStatus() + { + $hasValue = false; + $parts = []; + $statuses = $this->message_id ? ['sent', 'opened', 'viewed'] : ['sent', 'viewed']; + + foreach ($statuses as $status) { + $field = "{$status}_date"; + $date = ''; + if ($this->$field && $this->field != '0000-00-00 00:00:00') { + $date = Utils::dateToString($this->$field); + $hasValue = true; + $parts[] = trans('texts.invitation_status_' . $status) . ': ' . $date; + } + } + + return $hasValue ? implode($parts, '
    ') : false; + } + + /** + * @return mixed + */ + public function getName() + { + return $this->invitation_key; + } + + /** + * @param null $messageId + */ + public function markSent($messageId = null) + { + $this->message_id = $messageId; + $this->email_error = null; + $this->sent_date = Carbon::now()->toDateTimeString(); + $this->save(); + } + + public function isSent() + { + return $this->sent_date && $this->sent_date != '0000-00-00 00:00:00'; + } + + public function markViewed() + { + $this->viewed_date = Carbon::now()->toDateTimeString(); + $this->save(); + + if ($this->invoice) { + $invoice = $this->invoice; + $client = $invoice->client; + + $invoice->markViewed(); + $client->markLoggedIn(); + } + } +} diff --git a/app/Models/Traits/PresentsInvoice.php b/app/Models/Traits/PresentsInvoice.php index d715121208d0..e6961dadf53a 100644 --- a/app/Models/Traits/PresentsInvoice.php +++ b/app/Models/Traits/PresentsInvoice.php @@ -2,6 +2,8 @@ namespace App\Models\Traits; +use Utils; + /** * Class PresentsInvoice. */ @@ -362,7 +364,7 @@ trait PresentsInvoice 'product.custom_value1' => 'custom_invoice_item_label1', 'product.custom_value2' => 'custom_invoice_item_label2', ] as $field => $property) { - $data[$field] = e($this->$property) ?: trans('texts.custom_field'); + $data[$field] = e(Utils::getCustomLabel($this->$property)) ?: trans('texts.custom_field'); } return $data; diff --git a/app/Models/User.php b/app/Models/User.php index e1a5556a80a4..6162bffef2bb 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -319,9 +319,7 @@ class User extends Authenticatable */ public function isEmailBeingChanged() { - return Utils::isNinjaProd() - && $this->email != $this->getOriginal('email') - && $this->getOriginal('confirmed'); + return Utils::isNinjaProd() && $this->email != $this->getOriginal('email'); } /** diff --git a/app/Models/Vendor.php b/app/Models/Vendor.php index 1dd933396ce6..4f4a7112d33d 100644 --- a/app/Models/Vendor.php +++ b/app/Models/Vendor.php @@ -214,7 +214,6 @@ class Vendor extends EntityModel */ public function addVendorContact($data, $isPrimary = false) { - //$publicId = isset($data['public_id']) ? $data['public_id'] : false; $publicId = isset($data['public_id']) ? $data['public_id'] : (isset($data['id']) ? $data['id'] : false); if ($publicId && $publicId != '-1') { diff --git a/app/Ninja/DNS/Cloudflare.php b/app/Ninja/DNS/Cloudflare.php index 56b7bea19281..3c6f31327399 100644 --- a/app/Ninja/DNS/Cloudflare.php +++ b/app/Ninja/DNS/Cloudflare.php @@ -15,36 +15,117 @@ class Cloudflare foreach($zones as $zone) { - $curl = curl_init(); - $jsonEncodedData = json_encode(['type'=>'A', 'name'=>$account->subdomain, 'content'=>env('CLOUDFLARE_TARGET_IP_ADDRESS',''),'proxied'=>true]); + if($account->subdomain != "") + { - $opts = [ - CURLOPT_URL => 'https://api.cloudflare.com/client/v4/zones/'.$zone.'/dns_records', - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => 'POST', - CURLOPT_POST => 1, - CURLOPT_POSTFIELDS => $jsonEncodedData, - CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', - 'Content-Length: '.strlen($jsonEncodedData), - 'X-Auth-Email: '.env('CLOUDFLARE_EMAIL', ''), - 'X-Auth-Key: '.env('CLOUDFLARE_API_KEY', '') - ], - ]; + $jsonEncodedData = json_encode(['type' => 'A', 'name' => $account->subdomain, 'content' => env('CLOUDFLARE_TARGET_IP_ADDRESS', ''), 'proxied' => true]); - curl_setopt_array($curl, $opts); + $requestType = 'POST'; - $result = curl_exec($curl); - $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + $url = 'https://api.cloudflare.com/client/v4/zones/' . $zone . '/dns_records'; - curl_close($curl); + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); - if ($status != 200) - Utils::logError('unable to update subdomain ' . $account->subdomain . ' @ Cloudflare - '.$result); + if ($response['status'] != 200) + Utils::logError('Unable to update subdomain ' . $account->subdomain . ' @ Cloudflare - ' . $response['result']['result']); + + } } } + public static function removeDNSRecord(Account $account) { + + $zones = json_decode(env('CLOUDFLARE_ZONE_IDS',''), true); + + foreach($zones as $zone) + { + + if($account->subdomain != "") + { + + $dnsRecordId = self::getDNSRecord($zone, $account->subdomain); + + $jsonEncodedData = json_encode([]); + + $requestType = 'DELETE'; + + $url = 'https://api.cloudflare.com/client/v4/zones/' . $zone . '/dns_records/'. $dnsRecordId .''; + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to delete subdomain ' . $account->subdomain . ' @ Cloudflare - ' . $response['result']['result']); + + } + + } + + } + + public static function getDNSRecord($zone, $aRecord) + { + //harvest the zone_name + $url = 'https://api.cloudflare.com/client/v4/zones/'. $zone .'/dns_records?type=A&per_page=1'; + + $requestType = 'GET'; + + $jsonEncodedData = json_encode([]); + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to get the zone name for ' . $aRecord . ' @ Cloudflare - ' . $response['result']['result']); + + $zoneName = $response['result']['result'][0]['zone_name']; + + //get the A record + $url = 'https://api.cloudflare.com/client/v4/zones/'. $zone .'/dns_records?type=A&name='. $aRecord .'.'. $zoneName .' '; + + $response = self::curlCloudFlare($requestType, $url, $jsonEncodedData); + + if ($response['status'] != 200) + Utils::logError('Unable to get the record ID for ' . $aRecord . ' @ Cloudflare - ' . $response['result']['result']); + + return $response['result']['result'][0]['id']; + + } + + private static function curlCloudFlare($requestType, $url, $jsonEncodedData) + { + + $curl = curl_init(); + + $opts = [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $requestType, + CURLOPT_POST => 1, + CURLOPT_POSTFIELDS => $jsonEncodedData, + CURLOPT_HTTPHEADER => ['Content-Type: application/json', + 'Content-Length: ' . strlen($jsonEncodedData), + 'X-Auth-Email: ' . env('CLOUDFLARE_EMAIL', ''), + 'X-Auth-Key: ' . env('CLOUDFLARE_API_KEY', '') + ], + ]; + + curl_setopt_array($curl, $opts); + + $result = curl_exec($curl); + + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + $data['status'] = $status; + + $data['result'] = \json_decode($result, true); + + curl_close($curl); + + return $data; + + } + } \ No newline at end of file diff --git a/app/Ninja/Datatables/AccountGatewayDatatable.php b/app/Ninja/Datatables/AccountGatewayDatatable.php index e427ed5e17b1..a97df299b869 100644 --- a/app/Ninja/Datatables/AccountGatewayDatatable.php +++ b/app/Ninja/Datatables/AccountGatewayDatatable.php @@ -22,17 +22,19 @@ class AccountGatewayDatatable extends EntityDatatable [ 'gateway', function ($model) { + $accountGateway = $this->getAccountGateway($model->id); if ($model->deleted_at) { return $model->name; } elseif ($model->gateway_id == GATEWAY_CUSTOM) { - $accountGateway = $this->getAccountGateway($model->id); $name = $accountGateway->getConfigField('name') . ' [' . trans('texts.custom') . ']'; - return link_to("gateways/{$model->public_id}/edit", $name)->toHtml(); } elseif ($model->gateway_id != GATEWAY_WEPAY) { - return link_to("gateways/{$model->public_id}/edit", $model->name)->toHtml(); + $name = $model->name; + if ($accountGateway->isTestMode()) { + $name .= sprintf(' [%s]', trans('texts.test')); + } + return link_to("gateways/{$model->public_id}/edit", $name)->toHtml(); } else { - $accountGateway = $this->getAccountGateway($model->id); $config = $accountGateway->getConfig(); $endpoint = WEPAY_ENVIRONMENT == WEPAY_STAGE ? 'https://stage.wepay.com/' : 'https://www.wepay.com/'; $wepayAccountId = $config->accountId; diff --git a/app/Ninja/Datatables/EntityDatatable.php b/app/Ninja/Datatables/EntityDatatable.php index 02fd80845756..08e55549e959 100644 --- a/app/Ninja/Datatables/EntityDatatable.php +++ b/app/Ninja/Datatables/EntityDatatable.php @@ -98,4 +98,14 @@ class EntityDatatable return $str . '  '; } + + public function showWithTooltip($str, $max = 60) { + $str = e($str); + + if (strlen($str) > $max) { + return '' . trim(substr($str, 0, $max)) . '...' . ''; + } else { + return $str; + } + } } diff --git a/app/Ninja/Datatables/ExpenseDatatable.php b/app/Ninja/Datatables/ExpenseDatatable.php index 620366c21ccc..e489c89a71a5 100644 --- a/app/Ninja/Datatables/ExpenseDatatable.php +++ b/app/Ninja/Datatables/ExpenseDatatable.php @@ -59,7 +59,7 @@ class ExpenseDatatable extends EntityDatatable [ 'amount', function ($model) { - $amount = Utils::calculateTaxes($model->amount, $model->tax_rate1, $model->tax_rate2); + $amount = $model->amount + Utils::calculateTaxes($model->amount, $model->tax_rate1, $model->tax_rate2); $str = Utils::formatMoney($amount, $model->expense_currency_id); // show both the amount and the converted amount @@ -85,7 +85,7 @@ class ExpenseDatatable extends EntityDatatable [ 'public_notes', function ($model) { - return $model->public_notes != null ? e(substr($model->public_notes, 0, 100)) : ''; + return $this->showWithTooltip($model->public_notes); }, ], [ @@ -115,7 +115,7 @@ class ExpenseDatatable extends EntityDatatable return URL::to("expenses/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_EXPENSE); + return Auth::user()->can('viewByOwner', [ENTITY_EXPENSE, $model->user_id]) && Auth::user()->can('create', ENTITY_EXPENSE); }, ], [ diff --git a/app/Ninja/Datatables/InvoiceDatatable.php b/app/Ninja/Datatables/InvoiceDatatable.php index 801fb52a97f9..3cba7faf46ed 100644 --- a/app/Ninja/Datatables/InvoiceDatatable.php +++ b/app/Ninja/Datatables/InvoiceDatatable.php @@ -96,7 +96,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("invoices/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_INVOICE); + return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_INVOICE); }, ], [ @@ -105,7 +105,7 @@ class InvoiceDatatable extends EntityDatatable return URL::to("quotes/{$model->public_id}/clone"); }, function ($model) { - return Auth::user()->can('create', ENTITY_QUOTE); + return Auth::user()->can('viewByOwner', [ENTITY_INVOICE, $model->user_id]) && Auth::user()->can('create', ENTITY_QUOTE); }, ], [ @@ -137,7 +137,7 @@ class InvoiceDatatable extends EntityDatatable return "javascript:submitForm_{$entityType}('markSent', {$model->public_id})"; }, function ($model) { - return $model->invoice_status_id < INVOICE_STATUS_SENT && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); + return ! $model->is_public && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); }, ], [ @@ -167,6 +167,15 @@ class InvoiceDatatable extends EntityDatatable return $entityType == ENTITY_QUOTE && $model->quote_invoice_id && Auth::user()->can('editByOwner', [ENTITY_INVOICE, $model->user_id]); }, ], + [ + trans('texts.new_proposal'), + function ($model) { + return URL::to("proposals/create/{$model->public_id}"); + }, + function ($model) use ($entityType) { + return $entityType == ENTITY_QUOTE && ! $model->quote_invoice_id && $model->invoice_status_id < INVOICE_STATUS_APPROVED && Auth::user()->can('create', ENTITY_PROPOSAL); + }, + ], [ trans('texts.convert_to_invoice'), function ($model) { diff --git a/app/Ninja/Datatables/PaymentDatatable.php b/app/Ninja/Datatables/PaymentDatatable.php index 193207f9d82a..e0be4b78c86d 100644 --- a/app/Ninja/Datatables/PaymentDatatable.php +++ b/app/Ninja/Datatables/PaymentDatatable.php @@ -146,8 +146,9 @@ class PaymentDatatable extends EntityDatatable $max_refund = number_format($model->amount - $model->refunded, 2); $formatted = Utils::formatMoney($max_refund, $model->currency_id, $model->country_id); $symbol = Utils::getFromCache($model->currency_id ? $model->currency_id : 1, 'currencies')->symbol; + $local = in_array($model->gateway_id, [GATEWAY_BRAINTREE, GATEWAY_STRIPE, GATEWAY_WEPAY]) || ! $model->gateway_id ? 0 : 1; - return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}')"; + return "javascript:showRefundModal({$model->public_id}, '{$max_refund}', '{$formatted}', '{$symbol}', {$local})"; }, function ($model) { return Auth::user()->can('editByOwner', [ENTITY_PAYMENT, $model->user_id]) diff --git a/app/Ninja/Datatables/ProductDatatable.php b/app/Ninja/Datatables/ProductDatatable.php index d5a3aba104d6..33c691806b85 100644 --- a/app/Ninja/Datatables/ProductDatatable.php +++ b/app/Ninja/Datatables/ProductDatatable.php @@ -14,6 +14,8 @@ class ProductDatatable extends EntityDatatable public function columns() { + $account = Auth::user()->account; + return [ [ 'product_key', @@ -24,7 +26,7 @@ class ProductDatatable extends EntityDatatable [ 'notes', function ($model) { - return e(Str::limit($model->notes, 100)); + return $this->showWithTooltip($model->notes); }, ], [ @@ -38,8 +40,22 @@ class ProductDatatable extends EntityDatatable function ($model) { return $model->tax_rate ? ($model->tax_name . ' ' . $model->tax_rate . '%') : ''; }, - Auth::user()->account->invoice_item_taxes, + $account->invoice_item_taxes, ], + [ + 'custom_value1', + function ($model) { + return $model->custom_value1; + }, + $account->custom_invoice_item_label1 + ], + [ + 'custom_value2', + function ($model) { + return $model->custom_value2; + }, + $account->custom_invoice_item_label2 + ] ]; } diff --git a/app/Ninja/Datatables/ProposalCategoryDatatable.php b/app/Ninja/Datatables/ProposalCategoryDatatable.php new file mode 100644 index 000000000000..53d44b8509a8 --- /dev/null +++ b/app/Ninja/Datatables/ProposalCategoryDatatable.php @@ -0,0 +1,44 @@ +can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->user_id])) { + return $model->name; + } + + return link_to("proposals/categories/{$model->public_id}/edit", $model->name)->toHtml(); + }, + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_category'), + function ($model) { + return URL::to("proposals/categories/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->user_id]); + }, + ], + ]; + } +} diff --git a/app/Ninja/Datatables/ProposalDatatable.php b/app/Ninja/Datatables/ProposalDatatable.php new file mode 100644 index 000000000000..596f28f7a430 --- /dev/null +++ b/app/Ninja/Datatables/ProposalDatatable.php @@ -0,0 +1,86 @@ +can('viewByOwner', [ENTITY_QUOTE, $model->invoice_user_id])) { + return $model->invoice_number; + } + + return link_to("quotes/{$model->invoice_public_id}", $model->invoice_number)->toHtml(); + }, + ], + [ + 'client', + function ($model) { + if (! Auth::user()->can('viewByOwner', [ENTITY_CLIENT, $model->client_user_id])) { + return $model->client; + } + + return link_to("clients/{$model->client_public_id}", $model->client)->toHtml(); + }, + ], + [ + 'template', + function ($model) { + if (! Auth::user()->can('viewByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->template_user_id])) { + return $model->template ?: ' '; + } + + return link_to("proposals/templates/{$model->template_public_id}/edit", $model->template ?: ' ')->toHtml(); + }, + ], + [ + 'created_at', + function ($model) { + if (! Auth::user()->can('viewByOwner', [ENTITY_PROPOSAL, $model->user_id])) { + return Utils::timestampToDateString(strtotime($model->created_at)); + } + + return link_to("proposals/{$model->public_id}/edit", Utils::timestampToDateString(strtotime($model->created_at)))->toHtml(); + }, + ], + [ + 'content', + function ($model) { + return $this->showWithTooltip(strip_tags($model->content)); + }, + ], + [ + 'private_notes', + function ($model) { + return $this->showWithTooltip($model->private_notes); + }, + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_proposal'), + function ($model) { + return URL::to("proposals/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL, $model->user_id]); + }, + ], + ]; + } +} diff --git a/app/Ninja/Datatables/ProposalSnippetDatatable.php b/app/Ninja/Datatables/ProposalSnippetDatatable.php new file mode 100644 index 000000000000..7e97c2a83140 --- /dev/null +++ b/app/Ninja/Datatables/ProposalSnippetDatatable.php @@ -0,0 +1,68 @@ +icon . '">  '; + + if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_SNIPPET, $model->user_id])) { + return $icon . $model->name; + } + + return $icon . link_to("proposals/snippets/{$model->public_id}/edit", $model->name)->toHtml(); + }, + ], + [ + 'category', + function ($model) { + if (! Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_CATEGORY, $model->category_user_id])) { + return $model->category; + } + + return link_to("proposals/categories/{$model->category_public_id}/edit", $model->category ?: ' ')->toHtml(); + }, + ], + [ + 'content', + function ($model) { + return $this->showWithTooltip(strip_tags($model->content)); + }, + ], + [ + 'private_notes', + function ($model) { + return $this->showWithTooltip($model->private_notes); + }, + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_proposal_snippet'), + function ($model) { + return URL::to("proposals/snippets/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_SNIPPET, $model->user_id]); + }, + ], + ]; + } +} diff --git a/app/Ninja/Datatables/ProposalTemplateDatatable.php b/app/Ninja/Datatables/ProposalTemplateDatatable.php new file mode 100644 index 000000000000..9b18798bbd95 --- /dev/null +++ b/app/Ninja/Datatables/ProposalTemplateDatatable.php @@ -0,0 +1,76 @@ +can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id])) { + return $model->name; + } + + return link_to("proposals/templates/{$model->public_id}", $model->name)->toHtml(); + //$str = link_to("quotes/{$model->quote_public_id}", $model->quote_number)->toHtml(); + //return $this->addNote($str, $model->private_notes); + }, + ], + [ + 'content', + function ($model) { + return $this->showWithTooltip(strip_tags($model->content)); + }, + ], + [ + 'private_notes', + function ($model) { + return $this->showWithTooltip($model->private_notes); + }, + ], + ]; + } + + public function actions() + { + return [ + [ + trans('texts.edit_proposal_template'), + function ($model) { + return URL::to("proposals/templates/{$model->public_id}/edit"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); + }, + ], + [ + trans('texts.clone_proposal_template'), + function ($model) { + return URL::to("proposals/templates/{$model->public_id}/clone"); + }, + function ($model) { + return Auth::user()->can('editByOwner', [ENTITY_PROPOSAL_TEMPLATE, $model->user_id]); + }, + ], + [ + trans('texts.new_proposal'), + function ($model) { + return URL::to("proposals/create/0/{$model->public_id}"); + }, + function ($model) { + return Auth::user()->can('create', [ENTITY_PROPOSAL, $model->user_id]); + }, + ], + ]; + } +} diff --git a/app/Ninja/Datatables/RecurringExpenseDatatable.php b/app/Ninja/Datatables/RecurringExpenseDatatable.php index e8a1311595d2..78a6fdb7df8c 100644 --- a/app/Ninja/Datatables/RecurringExpenseDatatable.php +++ b/app/Ninja/Datatables/RecurringExpenseDatatable.php @@ -70,7 +70,7 @@ class RecurringExpenseDatatable extends EntityDatatable [ 'amount', function ($model) { - $amount = Utils::calculateTaxes($model->amount, $model->tax_rate1, $model->tax_rate2); + $amount = $model->amount + Utils::calculateTaxes($model->amount, $model->tax_rate1, $model->tax_rate2); $str = Utils::formatMoney($amount, $model->expense_currency_id); /* @@ -98,7 +98,7 @@ class RecurringExpenseDatatable extends EntityDatatable [ 'public_notes', function ($model) { - return $model->public_notes != null ? substr($model->public_notes, 0, 100) : ''; + return $this->showWithTooltip($model->public_notes, 100); }, ], ]; diff --git a/app/Ninja/Datatables/RecurringInvoiceDatatable.php b/app/Ninja/Datatables/RecurringInvoiceDatatable.php index df434b11902f..2f4555da7ee5 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 e($model->private_notes); + return $this->showWithTooltip($model->private_notes); }, ], [ diff --git a/app/Ninja/Datatables/SubscriptionDatatable.php b/app/Ninja/Datatables/SubscriptionDatatable.php index d83d9a501fe2..c07cac012332 100644 --- a/app/Ninja/Datatables/SubscriptionDatatable.php +++ b/app/Ninja/Datatables/SubscriptionDatatable.php @@ -20,7 +20,7 @@ class SubscriptionDatatable extends EntityDatatable [ 'target', function ($model) { - return e(substr($model->target, 0, 40) . (strlen($model->target) > 40 ? '...' : '')); + return $this->showWithTooltip($model->target, 40); }, ], ]; diff --git a/app/Ninja/Datatables/TaskDatatable.php b/app/Ninja/Datatables/TaskDatatable.php index e019c899b1bf..c4a5814afd44 100644 --- a/app/Ninja/Datatables/TaskDatatable.php +++ b/app/Ninja/Datatables/TaskDatatable.php @@ -59,7 +59,7 @@ class TaskDatatable extends EntityDatatable [ 'description', function ($model) { - return e(substr($model->description, 0, 80) . (strlen($model->description) > 80 ? '...' : '')); + return $this->showWithTooltip($model->description); }, ], [ diff --git a/app/Ninja/Datatables/TaxRateDatatable.php b/app/Ninja/Datatables/TaxRateDatatable.php index e42308b0b5de..7a29cc065567 100644 --- a/app/Ninja/Datatables/TaxRateDatatable.php +++ b/app/Ninja/Datatables/TaxRateDatatable.php @@ -20,7 +20,7 @@ class TaxRateDatatable extends EntityDatatable [ 'rate', function ($model) { - return $model->rate . '%'; + return ($model->rate + 0) . '%'; }, ], [ diff --git a/app/Ninja/Import/CSV/ExpenseTransformer.php b/app/Ninja/Import/CSV/ExpenseTransformer.php index b64ade053cb2..4d1c5299f176 100644 --- a/app/Ninja/Import/CSV/ExpenseTransformer.php +++ b/app/Ninja/Import/CSV/ExpenseTransformer.php @@ -24,6 +24,7 @@ class ExpenseTransformer extends BaseTransformer 'client_id' => isset($data->client) ? $this->getClientId($data->client) : null, 'expense_date' => isset($data->expense_date) ? date('Y-m-d', strtotime($data->expense_date)) : null, 'public_notes' => $this->getString($data, 'public_notes'), + 'private_notes' => $this->getString($data, 'private_notes'), 'expense_category_id' => isset($data->expense_category) ? $this->getExpenseCategoryId($data->expense_category) : null, ]; }); diff --git a/app/Ninja/Import/CSV/ProductTransformer.php b/app/Ninja/Import/CSV/ProductTransformer.php index 22e146e2c98a..cdfde4b8f843 100644 --- a/app/Ninja/Import/CSV/ProductTransformer.php +++ b/app/Ninja/Import/CSV/ProductTransformer.php @@ -27,6 +27,8 @@ class ProductTransformer extends BaseTransformer 'product_key' => $this->getString($data, 'product_key'), 'notes' => $this->getString($data, 'notes'), 'cost' => $this->getFloat($data, 'cost'), + 'custom_value1' => $this->getString($data, 'custom_value1'), + 'custom_value2' => $this->getString($data, 'custom_value2'), ]; }); } diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php index 6647f56d5ebc..50dbb8727919 100644 --- a/app/Ninja/Mailers/ContactMailer.php +++ b/app/Ninja/Mailers/ContactMailer.php @@ -4,12 +4,15 @@ namespace App\Ninja\Mailers; use App\Events\InvoiceWasEmailed; use App\Events\QuoteWasEmailed; -use App\Models\Invitation; use App\Models\Invoice; +use App\Models\Proposal; use App\Models\Payment; use App\Services\TemplateService; +use App\Jobs\ConvertInvoiceToUbl; use Event; use Utils; +use Cache; +use Mail; class ContactMailer extends Mailer { @@ -35,18 +38,22 @@ class ContactMailer extends Mailer * * @return bool|null|string */ - public function sendInvoice(Invoice $invoice, $reminder = false, $template = false) + public function sendInvoice(Invoice $invoice, $reminder = false, $template = false, $proposal = false) { if ($invoice->is_recurring) { return false; } $invoice->load('invitations', 'client.language', 'account'); - $entityType = $invoice->getEntityType(); + + if ($proposal) { + $entityType = ENTITY_PROPOSAL; + } else { + $entityType = $invoice->getEntityType(); + } $client = $invoice->client; $account = $invoice->account; - $response = null; if ($client->trashed()) { @@ -61,10 +68,14 @@ class ContactMailer extends Mailer $sent = false; $pdfString = false; + $ublString = false; - if ($account->attachPDF()) { + if ($account->attachPDF() && ! $proposal) { $pdfString = $invoice->getPDFString(); } + if ($account->attachUBL() && ! $proposal) { + $ublString = dispatch(new ConvertInvoiceToUbl($invoice)); + } $documentStrings = []; if ($account->document_email_attachment && $invoice->hasDocuments()) { @@ -87,8 +98,15 @@ class ContactMailer extends Mailer } $isFirst = true; - foreach ($invoice->invitations as $invitation) { - $response = $this->sendInvitation($invitation, $invoice, $emailTemplate, $emailSubject, $pdfString, $documentStrings, $reminder, $isFirst); + $invitations = $proposal ? $proposal->invitations : $invoice->invitations; + foreach ($invitations as $invitation) { + $data = [ + 'pdfString' => $pdfString, + 'documentStrings' => $documentStrings, + 'ublString' => $ublString, + 'proposal' => $proposal, + ]; + $response = $this->sendInvitation($invitation, $invoice, $emailTemplate, $emailSubject, $reminder, $isFirst, $data); $isFirst = false; if ($response === true) { $sent = true; @@ -97,7 +115,7 @@ class ContactMailer extends Mailer $account->loadLocalizationSettings(); - if ($sent === true) { + if ($sent === true && ! $proposal) { if ($invoice->isType(INVOICE_TYPE_QUOTE)) { event(new QuoteWasEmailed($invoice, $reminder)); } else { @@ -122,18 +140,18 @@ class ContactMailer extends Mailer * @return bool|string */ private function sendInvitation( - Invitation $invitation, + $invitation, Invoice $invoice, $body, $subject, - $pdfString, - $documentStrings, $reminder, - $isFirst + $isFirst, + $extra ) { $client = $invoice->client; $account = $invoice->account; $user = $invitation->user; + $proposal = $extra['proposal']; if ($user->trashed()) { $user = $account->users()->orderBy('id')->first(); @@ -141,7 +159,7 @@ class ContactMailer extends Mailer if (! $user->email || ! $user->registered) { return trans('texts.email_error_user_unregistered'); - } elseif (! $user->confirmed) { + } elseif (! $user->confirmed || $this->isThrottled($account)) { return trans('texts.email_error_user_unconfirmed'); } elseif (! $invitation->contact->email) { return trans('texts.email_error_invalid_contact_email'); @@ -156,16 +174,18 @@ class ContactMailer extends Mailer 'amount' => $invoice->getRequestedAmount(), ]; - // Let the client know they'll be billed later - if ($client->autoBillLater()) { - $variables['autobill'] = $invoice->present()->autoBillEmailMessage(); - } + if (! $proposal) { + // Let the client know they'll be billed later + if ($client->autoBillLater()) { + $variables['autobill'] = $invoice->present()->autoBillEmailMessage(); + } - if (empty($invitation->contact->password) && $account->isClientPortalPasswordEnabled() && $account->send_portal_password) { - // The contact needs a password - $variables['password'] = $password = $this->generatePassword(); - $invitation->contact->password = bcrypt($password); - $invitation->contact->save(); + if (empty($invitation->contact->password) && $account->isClientPortalPasswordEnabled() && $account->send_portal_password) { + // The contact needs a password + $variables['password'] = $password = $this->generatePassword(); + $invitation->contact->password = bcrypt($password); + $invitation->contact->save(); + } } $data = [ @@ -177,15 +197,21 @@ class ContactMailer extends Mailer 'account' => $account, 'client' => $client, 'invoice' => $invoice, - 'documents' => $documentStrings, + 'documents' => $extra['documentStrings'], 'notes' => $reminder, 'bccEmail' => $isFirst ? $account->getBccEmail() : false, 'fromEmail' => $account->getFromEmail(), ]; - if ($account->attachPDF()) { - $data['pdfString'] = $pdfString; - $data['pdfFileName'] = $invoice->getFileName(); + if (! $proposal) { + if ($account->attachPDF()) { + $data['pdfString'] = $extra['pdfString']; + $data['pdfFileName'] = $invoice->getFileName(); + } + if ($account->attachUBL()) { + $data['ublString'] = $extra['ublString']; + $data['ublFileName'] = $invoice->getFileName('xml'); + } } $subject = $this->templateService->processVariables($subject, $variables); @@ -257,7 +283,7 @@ class ContactMailer extends Mailer $invitation = $payment->invitation; } else { $user = $payment->user; - $contact = count($client->contacts) ? $client->contacts[0] : ''; + $contact = $client->contacts->count() ? $client->contacts[0] : ''; $invitation = $payment->invoice->invitations[0]; } @@ -342,4 +368,48 @@ class ContactMailer extends Mailer $this->sendTo($contact->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); } + + private function isThrottled($account) + { + if (Utils::isSelfHost()) { + return false; + } + + $key = $account->company_id; + + // http://stackoverflow.com/questions/1375501/how-do-i-throttle-my-sites-api-users + $hour = 60 * 60; + $hour_limit = MAX_EMAILS_SENT_PER_HOUR; + $hour_throttle = Cache::get("email_hour_throttle:{$key}", null); + $last_api_request = Cache::get("last_email_request:{$key}", 0); + $last_api_diff = time() - $last_api_request; + + if (is_null($hour_throttle)) { + $new_hour_throttle = 0; + } else { + $new_hour_throttle = $hour_throttle - $last_api_diff; + $new_hour_throttle = $new_hour_throttle < 0 ? 0 : $new_hour_throttle; + $new_hour_throttle += $hour / $hour_limit; + $hour_hits_remaining = floor(($hour - $new_hour_throttle) * $hour_limit / $hour); + $hour_hits_remaining = $hour_hits_remaining >= 0 ? $hour_hits_remaining : 0; + } + + Cache::put("email_hour_throttle:{$key}", $new_hour_throttle, 60); + Cache::put("last_email_request:{$key}", time(), 60); + + if ($new_hour_throttle > $hour) { + $errorEmail = env('ERROR_EMAIL'); + if ($errorEmail && ! Cache::get("throttle_notified:{$key}")) { + Mail::raw('Account Throttle', function ($message) use ($errorEmail, $account) { + $message->to($errorEmail) + ->from(CONTACT_EMAIL) + ->subject("Email throttle triggered for account " . $account->id); + }); + } + Cache::put("throttle_notified:{$key}", true, 60); + return true; + } + + return false; + } } diff --git a/app/Ninja/Mailers/Mailer.php b/app/Ninja/Mailers/Mailer.php index aac226b3fcfe..26cd5165d71c 100644 --- a/app/Ninja/Mailers/Mailer.php +++ b/app/Ninja/Mailers/Mailer.php @@ -29,22 +29,36 @@ class Mailer return true; } - /* - if (isset($_ENV['POSTMARK_API_TOKEN'])) { - $views = 'emails.'.$view.'_html'; - } else { - $views = [ - 'emails.'.$view.'_html', - 'emails.'.$view.'_text', - ]; - } - */ - $views = [ 'emails.'.$view.'_html', 'emails.'.$view.'_text', ]; + if (Utils::isSelfHost()) { + if (isset($data['account'])) { + $account = $data['account']; + if (env($account->id . '_MAIL_FROM_ADDRESS')) { + $fields = [ + 'driver', + 'host', + 'port', + 'from.address', + 'from.name', + 'encryption', + 'username', + 'password', + ]; + foreach ($fields as $field) { + $envKey = strtoupper(str_replace('.', '_', $field)); + if ($value = env($account->id . '_MAIL_' . $envKey)) { + config(['mail.' . $field => $value]); + } + } + (new \Illuminate\Mail\MailServiceProvider(app()))->register(); + } + } + } + try { $response = Mail::send($views, $data, function ($message) use ($toEmail, $fromEmail, $fromName, $subject, $data) { $toEmail = strtolower($toEmail); @@ -67,12 +81,13 @@ class Mailer $message->bcc($data['bccEmail']); } - // Attach the PDF to the email + // Handle invoice attachments if (! empty($data['pdfString']) && ! empty($data['pdfFileName'])) { $message->attachData($data['pdfString'], $data['pdfFileName']); } - - // Attach documents to the email + if (! empty($data['ublString']) && ! empty($data['ublFileName'])) { + $message->attachData($data['ublString'], $data['ublFileName']); + } if (! empty($data['documents'])) { foreach ($data['documents'] as $document) { $message->attachData($document['data'], $document['name']); @@ -106,7 +121,12 @@ class Mailer } $notes = isset($data['notes']) ? $data['notes'] : false; - $invoice->markInvitationSent($invitation, $messageId, true, $notes); + + if (! empty($data['proposal'])) { + $invitation->markSent($messageId); + } else { + $invoice->markInvitationSent($invitation, $messageId, true, $notes); + } } return true; diff --git a/app/Ninja/Mailers/UserMailer.php b/app/Ninja/Mailers/UserMailer.php index 6b5d130b697a..9cd34e9455f3 100644 --- a/app/Ninja/Mailers/UserMailer.php +++ b/app/Ninja/Mailers/UserMailer.php @@ -38,6 +38,31 @@ class UserMailer extends Mailer $this->sendTo($user->email, $fromEmail, $fromName, $subject, $view, $data); } + /** + * @param User $user + * @param User|null $invitor + */ + public function sendEmailChanged(User $user) + { + $oldEmail = $user->getOriginal('email'); + $newEmail = $user->email; + + if (! $oldEmail || ! $newEmail) { + return; + } + + $view = 'user_message'; + $subject = trans('texts.email_address_changed'); + + $data = [ + 'user' => $user, + 'userName' => $user->getDisplayName(), + 'primaryMessage' => trans('texts.email_address_changed_message', ['old_email' => $oldEmail, 'new_email' => $newEmail]), + ]; + + $this->sendTo($oldEmail, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data); + } + /** * @param User $user * @param Invoice $invoice diff --git a/app/Ninja/PaymentDrivers/BasePaymentDriver.php b/app/Ninja/PaymentDrivers/BasePaymentDriver.php index 8e414fff026d..c20ee7b8e8ad 100644 --- a/app/Ninja/PaymentDrivers/BasePaymentDriver.php +++ b/app/Ninja/PaymentDrivers/BasePaymentDriver.php @@ -822,11 +822,6 @@ class BasePaymentDriver $invoiceItem = $payment->invoice->invoice_items->first(); $invoiceItem->notes .= "\n\n#{$license->license_key}"; $invoiceItem->save(); - - // Add the license key to the redirect URL - $key = 'redirect_url:' . $payment->invitation->invitation_key; - $redirectUrl = session($key); - session([$key => "{$redirectUrl}?license_key={$license->license_key}&product_id={$productId}"]); } protected function creatingPayment($payment, $paymentMethod) diff --git a/app/Ninja/PaymentDrivers/StripePaymentDriver.php b/app/Ninja/PaymentDrivers/StripePaymentDriver.php index 901d2a3071e3..2be1c5b83327 100644 --- a/app/Ninja/PaymentDrivers/StripePaymentDriver.php +++ b/app/Ninja/PaymentDrivers/StripePaymentDriver.php @@ -114,7 +114,7 @@ class StripePaymentDriver extends BasePaymentDriver $this->tokenResponse = $response->getData(); // import Stripe tokens created before payment methods table was added - if (! count($customer->payment_methods)) { + if (! $customer->payment_methods->count()) { if ($paymentMethod = $this->createPaymentMethod($customer)) { $customer->default_payment_method_id = $paymentMethod->id; $customer->save(); diff --git a/app/Ninja/Presenters/AccountPresenter.php b/app/Ninja/Presenters/AccountPresenter.php index 0b3904c1d446..f95082322736 100644 --- a/app/Ninja/Presenters/AccountPresenter.php +++ b/app/Ninja/Presenters/AccountPresenter.php @@ -208,7 +208,7 @@ class AccountPresenter extends Presenter foreach ($fields as $key => $val) { if ($this->$key) { - $data[$this->$key] = [ + $data[Utils::getCustomLabel($this->$key)] = [ 'value' => $val, 'name' => $val, ]; @@ -264,4 +264,56 @@ class AccountPresenter extends Presenter return $url; } + + + public function customClientLabel1() + { + return Utils::getCustomLabel($this->entity->custom_client_label1); + } + + public function customClientLabel2() + { + return Utils::getCustomLabel($this->entity->custom_client_label2); + } + + public function customContactLabel1() + { + return Utils::getCustomLabel($this->entity->custom_contact_label1); + } + + public function customContactLabel2() + { + return Utils::getCustomLabel($this->entity->custom_contact_label2); + } + + public function customInvoiceLabel1() + { + return Utils::getCustomLabel($this->entity->custom_invoice_label1); + } + + public function customInvoiceLabel2() + { + return Utils::getCustomLabel($this->entity->custom_invoice_label2); + } + + public function customInvoiceTextLabel1() + { + return Utils::getCustomLabel($this->entity->custom_invoice_text_label1); + } + + public function customInvoiceTextLabel2() + { + return Utils::getCustomLabel($this->entity->custom_invoice_text_label1); + } + + public function customProductLabel1() + { + return Utils::getCustomLabel($this->entity->custom_invoice_item_label1); + } + + public function customProductLabel2() + { + return Utils::getCustomLabel($this->entity->custom_invoice_item_label2); + } + } diff --git a/app/Ninja/Presenters/ClientPresenter.php b/app/Ninja/Presenters/ClientPresenter.php index 2296cb5acb33..5ed162b51072 100644 --- a/app/Ninja/Presenters/ClientPresenter.php +++ b/app/Ninja/Presenters/ClientPresenter.php @@ -8,12 +8,12 @@ class ClientPresenter extends EntityPresenter { public function country() { - return $this->entity->country ? $this->entity->country->name : ''; + return $this->entity->country ? $this->entity->country->getName() : ''; } public function shipping_country() { - return $this->entity->shipping_country ? $this->entity->shipping_country->name : ''; + return $this->entity->shipping_country ? $this->entity->shipping_country->getName() : ''; } public function balance() @@ -56,7 +56,7 @@ class ClientPresenter extends EntityPresenter return sprintf('%s: %s %s', trans('texts.payment_terms'), trans('texts.payment_terms_net'), $client->defaultDaysDue()); } - public function address($addressType = ADDRESS_BILLING) + public function address($addressType = ADDRESS_BILLING, $showHeader = false) { $str = ''; $prefix = $addressType == ADDRESS_BILLING ? '' : 'shipping_'; @@ -72,10 +72,10 @@ class ClientPresenter extends EntityPresenter $str .= e($cityState) . '
    '; } if ($country = $client->{$prefix . 'country'}) { - $str .= e($country->name) . '
    '; + $str .= e($country->getName()) . '
    '; } - if ($str) { + if ($str && $showHeader) { $str = '' . trans('texts.' . $addressType) . '
    ' . $str; } diff --git a/app/Ninja/Presenters/EntityPresenter.php b/app/Ninja/Presenters/EntityPresenter.php index 3bc6ab03096e..17f08a323cc1 100644 --- a/app/Ninja/Presenters/EntityPresenter.php +++ b/app/Ninja/Presenters/EntityPresenter.php @@ -84,7 +84,7 @@ class EntityPresenter extends Presenter $entity = $this->entity; $entityType = $entity->getEntityType(); - return sprintf('%s %s', trans('texts.' . $entityType), $entity->getDisplayName()); + return sprintf('%s: %s', trans('texts.' . $entityType), $entity->getDisplayName()); } public function calendarEvent($subColors = false) diff --git a/app/Ninja/Presenters/ExpensePresenter.php b/app/Ninja/Presenters/ExpensePresenter.php index fda0104bf3c7..2cac47973ddd 100644 --- a/app/Ninja/Presenters/ExpensePresenter.php +++ b/app/Ninja/Presenters/ExpensePresenter.php @@ -41,7 +41,12 @@ class ExpensePresenter extends EntityPresenter public function amount() { - return Utils::formatMoney($this->entity->amount, $this->entity->expense_currency_id); + return Utils::formatMoney($this->entity->amountWithTax(), $this->entity->expense_currency_id); + } + + public function taxAmount() + { + return Utils::formatMoney($this->entity->taxAmount(), $this->entity->expense_currency_id); } public function category() diff --git a/app/Ninja/Presenters/InvoiceItemPresenter.php b/app/Ninja/Presenters/InvoiceItemPresenter.php index 0411df7a5b32..e7a0acf92d61 100644 --- a/app/Ninja/Presenters/InvoiceItemPresenter.php +++ b/app/Ninja/Presenters/InvoiceItemPresenter.php @@ -18,8 +18,17 @@ class InvoiceItemPresenter extends EntityPresenter return $data; } - public function notes() + public function tax1() { - return Str::limit($this->entity->notes); + $item = $this->entity; + + return $item->tax_name1 . ' ' . $item->tax_rate1 . '%'; + } + + public function tax2() + { + $item = $this->entity; + + return $item->tax_name2 . ' ' . $item->tax_rate2 . '%'; } } diff --git a/app/Ninja/Presenters/InvoicePresenter.php b/app/Ninja/Presenters/InvoicePresenter.php index 07ffa8789977..e3c0177c7729 100644 --- a/app/Ninja/Presenters/InvoicePresenter.php +++ b/app/Ninja/Presenters/InvoicePresenter.php @@ -38,6 +38,14 @@ class InvoicePresenter extends EntityPresenter return $account->formatMoney($invoice->balance, $invoice->client); } + public function paid() + { + $invoice = $this->entity; + $account = $invoice->account; + + return $account->formatMoney($invoice->amount - $invoice->balance, $invoice->client); + } + public function partial() { $invoice = $this->entity; @@ -175,7 +183,7 @@ class InvoicePresenter extends EntityPresenter { $client = $this->entity->client; - return count($client->contacts) ? $client->contacts[0]->email : ''; + return $client->contacts->count() ? $client->contacts[0]->email : ''; } public function autoBillEmailMessage() @@ -253,6 +261,9 @@ class InvoicePresenter extends EntityPresenter if ($invoice->quote_invoice_id) { $actions[] = ['url' => url("invoices/{$invoice->quote_invoice_id}/edit"), 'label' => trans('texts.view_invoice')]; } else { + if (! $invoice->isApproved()) { + $actions[] = ['url' => url("proposals/create/{$invoice->public_id}"), 'label' => trans('texts.new_proposal')]; + } $actions[] = ['url' => 'javascript:onConvertClick()', 'label' => trans('texts.convert_to_invoice')]; } } elseif ($entityType == ENTITY_INVOICE) { @@ -271,7 +282,7 @@ class InvoicePresenter extends EntityPresenter foreach ($invoice->payments as $payment) { $label = trans('texts.view_payment'); - if (count($invoice->payments) > 1) { + if ($invoice->payments->count() > 1) { $label .= ' - ' . $invoice->account->formatMoney($payment->amount, $invoice->client); } $actions[] = ['url' => $payment->present()->url, 'label' => $label]; diff --git a/app/Ninja/Presenters/ProposalPresenter.php b/app/Ninja/Presenters/ProposalPresenter.php new file mode 100644 index 000000000000..eca4e906df81 --- /dev/null +++ b/app/Ninja/Presenters/ProposalPresenter.php @@ -0,0 +1,60 @@ +entity; + $invitation = $proposal->invitations->first(); + $actions = []; + + $actions[] = ['url' => $invitation->getLink('proposal'), 'label' => trans("texts.view_as_recipient")]; + + $actions[] = DropdownButton::DIVIDER; + + if (! $proposal->trashed()) { + $actions[] = ['url' => 'javascript:onArchiveClick()', 'label' => trans("texts.archive_proposal")]; + } + if (! $proposal->is_deleted) { + $actions[] = ['url' => 'javascript:onDeleteClick()', 'label' => trans("texts.delete_proposal")]; + } + + return $actions; + } + + public function htmlDocument() + { + $proposal = $this->entity; + + $html = " + + + + + {$proposal->html} + + "; + + return $html; + } + + public function filename() + { + $proposal = $this->entity; + + return sprintf('%s_%s.pdf', trans('texts.proposal'), $proposal->invoice->invoice_number); + } +} diff --git a/app/Ninja/Presenters/ProposalSnippetPresenter.php b/app/Ninja/Presenters/ProposalSnippetPresenter.php new file mode 100644 index 000000000000..fd94da49fe9a --- /dev/null +++ b/app/Ninja/Presenters/ProposalSnippetPresenter.php @@ -0,0 +1,14 @@ +entity->country ? $this->entity->country->name : ''; + return $this->entity->country ? $this->entity->country->getName() : ''; } } diff --git a/app/Ninja/Reports/AbstractReport.php b/app/Ninja/Reports/AbstractReport.php index 701147b15b91..a96f0e4ca010 100644 --- a/app/Ninja/Reports/AbstractReport.php +++ b/app/Ninja/Reports/AbstractReport.php @@ -12,7 +12,6 @@ class AbstractReport public $options; public $totals = []; - public $columns = []; public $data = []; public function __construct($startDate, $endDate, $isExport, $options = false) @@ -28,10 +27,15 @@ class AbstractReport } + public function getColumns() + { + return []; + } + public function results() { return [ - 'columns' => $this->columns, + 'columns' => $this->getColumns(), 'displayData' => $this->data, 'reportTotals' => $this->totals, ]; @@ -55,7 +59,7 @@ class AbstractReport public function tableHeaderArray() { $columns_labeled = []; - foreach ($this->columns as $key => $val) { + foreach ($this->getColumns() as $key => $val) { if (is_array($val)) { $field = $key; $class = $val; @@ -70,12 +74,22 @@ class AbstractReport $class[] = 'group-letter-100'; } elseif (in_array($field, ['amount', 'paid', 'balance'])) { $class[] = 'group-number-50'; + } elseif (in_array($field, ['age'])) { + $class[] = 'group-number-30'; } + if (! in_array('custom', $class)) { + $label = trans("texts.{$field}"); + } else { + $label = $field; + } $class = count($class) ? implode(' ', $class) : 'group-false'; - $label = trans("texts.{$field}"); - $columns_labeled[] = ['label' => $label, 'class' => $class, 'key' => $field]; + $columns_labeled[] = [ + 'label' => $label, + 'class' => $class, + 'key' => $field + ]; } return $columns_labeled; @@ -86,8 +100,9 @@ class AbstractReport $columns_labeled = $this->tableHeaderArray(); $str = ''; - foreach ($columns_labeled as $field => $attr) - $str .= "{$attr['label']}"; + foreach ($columns_labeled as $field => $attr) { + $str .= sprintf('%s', $attr['class'], $attr['label']); + } return $str; } diff --git a/app/Ninja/Reports/ActivityReport.php b/app/Ninja/Reports/ActivityReport.php index 2aaac5188af9..cf4e9dce9359 100644 --- a/app/Ninja/Reports/ActivityReport.php +++ b/app/Ninja/Reports/ActivityReport.php @@ -7,12 +7,15 @@ use Auth; class ActivityReport extends AbstractReport { - public $columns = [ - 'date', - 'client', - 'user', - 'activity', - ]; + public function getColumns() + { + return [ + 'date' => [], + 'client' => [], + 'user' => [], + 'activity' => [], + ]; + } public function run() { diff --git a/app/Ninja/Reports/AgingReport.php b/app/Ninja/Reports/AgingReport.php index dc0ec6381da6..0b4a3ada5881 100644 --- a/app/Ninja/Reports/AgingReport.php +++ b/app/Ninja/Reports/AgingReport.php @@ -7,15 +7,19 @@ use Auth; class AgingReport extends AbstractReport { - public $columns = [ - 'client', - 'invoice_number', - 'invoice_date', - 'due_date', - 'age' => ['group-number-30'], - 'amount', - 'balance', - ]; + public function getColumns() + { + return [ + 'client' => [], + 'invoice_number' => [], + 'invoice_date' => [], + 'due_date' => [], + 'age' => [], + 'amount' => [], + 'balance' => [], + ]; + } + public function run() { diff --git a/app/Ninja/Reports/ClientReport.php b/app/Ninja/Reports/ClientReport.php index befde9b3bc67..a51e0c6c2d3c 100644 --- a/app/Ninja/Reports/ClientReport.php +++ b/app/Ninja/Reports/ClientReport.php @@ -7,12 +7,30 @@ use Auth; class ClientReport extends AbstractReport { - public $columns = [ - 'client', - 'amount', - 'paid', - 'balance', - ]; + public function getColumns() + { + $columns = [ + 'client' => [], + 'amount' => [], + 'paid' => [], + 'balance' => [], + 'public_notes' => ['columnSelector-false'], + 'private_notes' => ['columnSelector-false'], + 'user' => ['columnSelector-false'], + ]; + + $user = auth()->user(); + $account = $user->account; + + if ($account->custom_client_label1) { + $columns[$account->present()->customClientLabel1] = ['columnSelector-false', 'custom']; + } + if ($account->custom_client_label2) { + $columns[$account->present()->customClientLabel2] = ['columnSelector-false', 'custom']; + } + + return $columns; + } public function run() { @@ -21,7 +39,7 @@ class ClientReport extends AbstractReport $clients = Client::scope() ->orderBy('name') ->withArchived() - ->with('contacts') + ->with(['contacts', 'user']) ->with(['invoices' => function ($query) { $query->where('invoice_date', '>=', $this->startDate) ->where('invoice_date', '<=', $this->endDate) @@ -39,13 +57,25 @@ class ClientReport extends AbstractReport $paid += $invoice->getAmountPaid(); } - $this->data[] = [ + $row = [ $this->isExport ? $client->getDisplayName() : $client->present()->link, $account->formatMoney($amount, $client), $account->formatMoney($paid, $client), $account->formatMoney($amount - $paid, $client), + $client->public_notes, + $client->private_notes, + $client->user->getDisplayName(), ]; + if ($account->custom_client_label1) { + $row[] = $client->custom_value1; + } + if ($account->custom_client_label2) { + $row[] = $client->custom_value2; + } + + $this->data[] = $row; + $this->addToTotals($client->currency_id, 'amount', $amount); $this->addToTotals($client->currency_id, 'paid', $paid); $this->addToTotals($client->currency_id, 'balance', $amount - $paid); diff --git a/app/Ninja/Reports/CreditReport.php b/app/Ninja/Reports/CreditReport.php new file mode 100644 index 000000000000..6ba311c3897f --- /dev/null +++ b/app/Ninja/Reports/CreditReport.php @@ -0,0 +1,61 @@ + [], + 'amount' => [], + 'balance' => [], + 'user' => ['columnSelector-false'], + ]; + + return $columns; + } + + public function run() + { + $account = Auth::user()->account; + + $clients = Client::scope() + ->orderBy('name') + ->withArchived() + ->with(['user', 'credits' => function ($query) { + $query->where('credit_date', '>=', $this->startDate) + ->where('credit_date', '<=', $this->endDate) + ->withArchived(); + }]); + + foreach ($clients->get() as $client) { + $amount = 0; + $balance = 0; + + foreach ($client->credits as $credit) { + $amount += $credit->amount; + $balance += $credit->balance; + } + + if (! $amount && ! $balance) { + continue; + } + + $row = [ + $this->isExport ? $client->getDisplayName() : $client->present()->link, + $account->formatMoney($amount, $client), + $account->formatMoney($balance, $client), + $client->user->getDisplayName(), + ]; + + $this->data[] = $row; + + $this->addToTotals($client->currency_id, 'amount', $amount); + $this->addToTotals($client->currency_id, 'balance', $balance); + } + } +} diff --git a/app/Ninja/Reports/DocumentReport.php b/app/Ninja/Reports/DocumentReport.php index c87408731923..bfa195034dbd 100644 --- a/app/Ninja/Reports/DocumentReport.php +++ b/app/Ninja/Reports/DocumentReport.php @@ -8,12 +8,16 @@ use Barracuda\ArchiveStream\Archive; class DocumentReport extends AbstractReport { - public $columns = [ - 'document', - 'client', - 'invoice_or_expense', - 'date', - ]; + public function getColumns() + { + return [ + 'document' => [], + 'client' => [], + 'invoice_or_expense' => [], + 'date' => [], + ]; + } + public function run() { @@ -47,6 +51,10 @@ class DocumentReport extends AbstractReport } if ($this->isExport && $exportFormat == 'zip') { + if (! extension_loaded('GMP')) { + die(trans('texts.gmp_required')); + } + $zip = Archive::instance_by_useragent(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.documents'))); foreach ($records as $record) { foreach ($record->documents as $document) { diff --git a/app/Ninja/Reports/ExpenseReport.php b/app/Ninja/Reports/ExpenseReport.php index 788b33908ee8..85c915d8a159 100644 --- a/app/Ninja/Reports/ExpenseReport.php +++ b/app/Ninja/Reports/ExpenseReport.php @@ -4,24 +4,38 @@ namespace App\Ninja\Reports; use Barracuda\ArchiveStream\Archive; use App\Models\Expense; +use App\Models\TaxRate; use Auth; use Utils; class ExpenseReport extends AbstractReport { - public $columns = [ - 'vendor', - 'client', - 'date', - 'category', - 'amount', - ]; + public function getColumns() + { + $columns = [ + 'vendor' => [], + 'client' => [], + 'date' => [], + 'category' => [], + 'amount' => [], + 'public_notes' => ['columnSelector-false'], + 'private_notes' => ['columnSelector-false'], + 'user' => ['columnSelector-false'], + ]; + + if (TaxRate::scope()->count()) { + $columns['tax'] = ['columnSelector-false']; + } + + return $columns; + } public function run() { $account = Auth::user()->account; $exportFormat = $this->options['export_format']; $with = ['client.contacts', 'vendor']; + $hasTaxRates = TaxRate::scope()->count(); if ($exportFormat == 'zip') { $with[] = ['documents']; @@ -30,11 +44,15 @@ class ExpenseReport extends AbstractReport $expenses = Expense::scope() ->orderBy('expense_date', 'desc') ->withArchived() - ->with('client.contacts', 'vendor') + ->with('client.contacts', 'vendor', 'expense_category', 'user') ->where('expense_date', '>=', $this->startDate) ->where('expense_date', '<=', $this->endDate); if ($this->isExport && $exportFormat == 'zip') { + if (! extension_loaded('GMP')) { + die(trans('texts.gmp_required')); + } + $zip = Archive::instance_by_useragent(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.expense_documents'))); foreach ($expenses->get() as $expense) { foreach ($expense->documents as $document) { @@ -51,14 +69,23 @@ class ExpenseReport extends AbstractReport foreach ($expenses->get() as $expense) { $amount = $expense->amountWithTax(); - $this->data[] = [ + $row = [ $expense->vendor ? ($this->isExport ? $expense->vendor->name : $expense->vendor->present()->link) : '', $expense->client ? ($this->isExport ? $expense->client->getDisplayName() : $expense->client->present()->link) : '', $this->isExport ? $expense->present()->expense_date : link_to($expense->present()->url, $expense->present()->expense_date), $expense->present()->category, Utils::formatMoney($amount, $expense->currency_id), + $expense->public_notes, + $expense->private_notes, + $expense->user->getDisplayName(), ]; + if ($hasTaxRates) { + $row[] = $expense->present()->taxAmount; + } + + $this->data[] = $row; + $this->addToTotals($expense->expense_currency_id, 'amount', $amount); $this->addToTotals($expense->invoice_currency_id, 'amount', 0); } diff --git a/app/Ninja/Reports/InvoiceReport.php b/app/Ninja/Reports/InvoiceReport.php index 54b5353e9cf4..51be25981c2a 100644 --- a/app/Ninja/Reports/InvoiceReport.php +++ b/app/Ninja/Reports/InvoiceReport.php @@ -5,30 +5,53 @@ namespace App\Ninja\Reports; use App\Models\Client; use Auth; use Barracuda\ArchiveStream\Archive; +use App\Models\TaxRate; class InvoiceReport extends AbstractReport { - public $columns = [ - 'client', - 'invoice_number', - 'invoice_date', - 'amount', - 'status', - 'payment_date', - 'paid', - 'method', - ]; + public function getColumns() + { + $columns = [ + 'client' => [], + 'invoice_number' => [], + 'invoice_date' => [], + 'amount' => [], + 'status' => [], + 'payment_date' => [], + 'paid' => [], + 'method' => [], + 'po_number' => ['columnSelector-false'], + 'private_notes' => ['columnSelector-false'], + 'user' => ['columnSelector-false'], + ]; + + if (TaxRate::scope()->count()) { + $columns['tax'] = ['columnSelector-false']; + } + + $account = auth()->user()->account; + + if ($account->custom_invoice_text_label1) { + $columns[$account->present()->customInvoiceTextLabel1] = ['columnSelector-false', 'custom']; + } + if ($account->custom_invoice_text_label1) { + $columns[$account->present()->customInvoiceTextLabel2] = ['columnSelector-false', 'custom']; + } + + return $columns; + } public function run() { $account = Auth::user()->account; $statusIds = $this->options['status_ids']; $exportFormat = $this->options['export_format']; + $hasTaxRates = TaxRate::scope()->count(); $clients = Client::scope() ->orderBy('name') ->withArchived() - ->with('contacts') + ->with('contacts', 'user') ->with(['invoices' => function ($query) use ($statusIds) { $query->invoices() ->withArchived() @@ -39,11 +62,15 @@ class InvoiceReport extends AbstractReport $query->withArchived() ->excludeFailed() ->with('payment_type', 'account_gateway.gateway'); - }, 'invoice_items']); + }, 'invoice_items', 'invoice_status']); }]); if ($this->isExport && $exportFormat == 'zip') { + if (! extension_loaded('GMP')) { + die(trans('texts.gmp_required')); + } + $zip = Archive::instance_by_useragent(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.invoice_documents'))); foreach ($clients->get() as $client) { foreach ($client->invoices as $invoice) { @@ -59,20 +86,38 @@ class InvoiceReport extends AbstractReport foreach ($clients->get() as $client) { foreach ($client->invoices as $invoice) { - $payments = count($invoice->payments) ? $invoice->payments : [false]; + $isFirst = true; + $payments = $invoice->payments->count() ? $invoice->payments : [false]; foreach ($payments as $payment) { - $this->data[] = [ + $row = [ $this->isExport ? $client->getDisplayName() : $client->present()->link, $this->isExport ? $invoice->invoice_number : $invoice->present()->link, $invoice->present()->invoice_date, - $account->formatMoney($invoice->amount, $client), + $isFirst ? $account->formatMoney($invoice->amount, $client) : '', $invoice->statusLabel(), $payment ? $payment->present()->payment_date : '', $payment ? $account->formatMoney($payment->getCompletedAmount(), $client) : '', $payment ? $payment->present()->method : '', + $invoice->po_number, + $invoice->private_notes, + $invoice->user->getDisplayName(), ]; + if ($hasTaxRates) { + $row[] = $isFirst ? $account->formatMoney($invoice->getTaxTotal(), $client) : ''; + } + + if ($account->custom_invoice_text_label1) { + $row[] = $invoice->custom_text_value1; + } + if ($account->custom_invoice_text_label2) { + $row[] = $invoice->custom_text_value2; + } + + $this->data[] = $row; + $this->addToTotals($client->currency_id, 'paid', $payment ? $payment->getCompletedAmount() : 0); + $isFirst = false; } $this->addToTotals($client->currency_id, 'amount', $invoice->amount); diff --git a/app/Ninja/Reports/PaymentReport.php b/app/Ninja/Reports/PaymentReport.php index 53d201f1880f..13dd355b83bb 100644 --- a/app/Ninja/Reports/PaymentReport.php +++ b/app/Ninja/Reports/PaymentReport.php @@ -8,15 +8,20 @@ use Utils; class PaymentReport extends AbstractReport { - public $columns = [ - 'client', - 'invoice_number', - 'invoice_date', - 'amount', - 'payment_date', - 'paid', - 'method', - ]; + public function getColumns() + { + return [ + 'client' => [], + 'invoice_number' => [], + 'invoice_date' => [], + 'amount' => [], + 'payment_date' => [], + 'paid' => [], + 'method' => [], + 'private_notes' => ['columnSelector-false'], + 'user' => ['columnSelector-false'], + ]; + } public function run() { @@ -34,10 +39,11 @@ class PaymentReport extends AbstractReport ->whereHas('invoice', function ($query) { $query->where('is_deleted', '=', false); }) - ->with('client.contacts', 'invoice', 'payment_type', 'account_gateway.gateway') + ->with('client.contacts', 'invoice', 'payment_type', 'account_gateway.gateway', 'user') ->where('payment_date', '>=', $this->startDate) ->where('payment_date', '<=', $this->endDate); + $lastInvoiceId = 0; foreach ($payments->get() as $payment) { $invoice = $payment->invoice; $client = $payment->client; @@ -56,10 +62,12 @@ class PaymentReport extends AbstractReport $this->isExport ? $client->getDisplayName() : $client->present()->link, $this->isExport ? $invoice->invoice_number : $invoice->present()->link, $invoice->present()->invoice_date, - $account->formatMoney($invoice->amount, $client), + $lastInvoiceId == $invoice->id ? '' : $account->formatMoney($invoice->amount, $client), $payment->present()->payment_date, $amount, $payment->present()->method, + $payment->private_notes, + $payment->user->getDisplayName(), ]; if (! isset($invoiceMap[$invoice->id])) { @@ -71,6 +79,8 @@ class PaymentReport extends AbstractReport $this->addToTotals($client->currency_id, 'amount', $invoice->amount); } } + + $lastInvoiceId = $invoice->id; } } } diff --git a/app/Ninja/Reports/ProductReport.php b/app/Ninja/Reports/ProductReport.php index d0a9c7c96a7e..9ccc7ea03c5e 100644 --- a/app/Ninja/Reports/ProductReport.php +++ b/app/Ninja/Reports/ProductReport.php @@ -8,17 +8,39 @@ use Utils; class ProductReport extends AbstractReport { - public $columns = [ - 'client', - 'invoice_number', - 'invoice_date', - 'product', - 'description', - 'qty', - 'cost', - //'tax_rate1', - //'tax_rate2', - ]; + public function getColumns() + { + $columns = [ + 'client' => [], + 'invoice_number' => [], + 'invoice_date' => [], + 'product' => [], + 'description' => [], + 'qty' => [], + 'cost' => [], + //'tax_rate1', + //'tax_rate2', + ]; + + $account = auth()->user()->account; + + if ($account->invoice_item_taxes) { + $columns['tax'] = ['columnSelector-false']; + if ($account->enable_second_tax_rate) { + $columns['tax'] = ['columnSelector-false']; + } + } + + if ($account->custom_invoice_item_label1) { + $columns[$account->present()->customProductLabel1] = ['columnSelector-false', 'custom']; + } + + if ($account->custom_invoice_item_label2) { + $columns[$account->present()->customProductLabel2] = ['columnSelector-false', 'custom']; + } + + return $columns; + } public function run() { @@ -41,15 +63,33 @@ class ProductReport extends AbstractReport foreach ($clients->get() as $client) { foreach ($client->invoices as $invoice) { foreach ($invoice->invoice_items as $item) { - $this->data[] = [ + $row = [ $this->isExport ? $client->getDisplayName() : $client->present()->link, $this->isExport ? $invoice->invoice_number : $invoice->present()->link, $invoice->present()->invoice_date, $item->product_key, - $this->isExport ? $item->notes : $item->present()->notes, + $item->notes, Utils::roundSignificant($item->qty, 0), Utils::roundSignificant($item->cost, 2), ]; + + if ($account->invoice_item_taxes) { + $row[] = $item->present()->tax1; + if ($account->enable_second_tax_rate) { + $row[] = $item->present()->tax2; + } + } + + if ($account->custom_invoice_item_label1) { + $row[] = $item->custom_value1; + } + + if ($account->custom_invoice_item_label2) { + $row[] = $item->custom_value2; + } + + $this->data[] = $row; + } //$this->addToTotals($client->currency_id, 'paid', $payment ? $payment->getCompletedAmount() : 0); diff --git a/app/Ninja/Reports/ProfitAndLossReport.php b/app/Ninja/Reports/ProfitAndLossReport.php index cd16ed49b0c9..fd2372d96531 100644 --- a/app/Ninja/Reports/ProfitAndLossReport.php +++ b/app/Ninja/Reports/ProfitAndLossReport.php @@ -8,13 +8,16 @@ use Auth; class ProfitAndLossReport extends AbstractReport { - public $columns = [ - 'type', - 'client', - 'amount', - 'date', - 'notes', - ]; + public function getColumns() + { + return [ + 'type' => [], + 'client' => [], + 'amount' => [], + 'date' => [], + 'notes' => [], + ]; + } public function run() { @@ -65,8 +68,8 @@ class ProfitAndLossReport extends AbstractReport ]; $this->addToTotals($expense->expense_currency_id, 'revenue', 0, $expense->present()->month); - $this->addToTotals($expense->expense_currency_id, 'expenses', $expense->amount, $expense->present()->month); - $this->addToTotals($expense->expense_currency_id, 'profit', $expense->amount * -1, $expense->present()->month); + $this->addToTotals($expense->expense_currency_id, 'expenses', $expense->amountWithTax(), $expense->present()->month); + $this->addToTotals($expense->expense_currency_id, 'profit', $expense->amountWithTax() * -1, $expense->present()->month); } //$this->addToTotals($client->currency_id, 'paid', $payment ? $payment->getCompletedAmount() : 0); diff --git a/app/Ninja/Reports/QuoteReport.php b/app/Ninja/Reports/QuoteReport.php index 704bc4820bd7..fbc1e2152aaa 100644 --- a/app/Ninja/Reports/QuoteReport.php +++ b/app/Ninja/Reports/QuoteReport.php @@ -5,37 +5,63 @@ namespace App\Ninja\Reports; use App\Models\Client; use Auth; use Barracuda\ArchiveStream\Archive; +use App\Models\TaxRate; class QuoteReport extends AbstractReport { - public $columns = [ - 'client', - 'quote_number', - 'quote_date', - 'amount', - 'status', - ]; + public function getColumns() + { + $columns = [ + 'client' => [], + 'quote_number' => [], + 'quote_date' => [], + 'amount' => [], + 'status' => [], + 'private_notes' => ['columnSelector-false'], + 'user' => ['columnSelector-false'], + ]; + + if (TaxRate::scope()->count()) { + $columns['tax'] = ['columnSelector-false']; + } + + $account = auth()->user()->account; + + if ($account->custom_invoice_text_label1) { + $columns[$account->present()->customInvoiceTextLabel1] = ['columnSelector-false', 'custom']; + } + if ($account->custom_invoice_text_label1) { + $columns[$account->present()->customInvoiceTextLabel2] = ['columnSelector-false', 'custom']; + } + + return $columns; + } public function run() { $account = Auth::user()->account; $statusIds = $this->options['status_ids']; $exportFormat = $this->options['export_format']; + $hasTaxRates = TaxRate::scope()->count(); $clients = Client::scope() ->orderBy('name') ->withArchived() - ->with('contacts') + ->with('contacts', 'user') ->with(['invoices' => function ($query) use ($statusIds) { $query->quotes() ->withArchived() ->statusIds($statusIds) ->where('invoice_date', '>=', $this->startDate) ->where('invoice_date', '<=', $this->endDate) - ->with(['invoice_items']); + ->with(['invoice_items', 'invoice_status']); }]); if ($this->isExport && $exportFormat == 'zip') { + if (! extension_loaded('GMP')) { + die(trans('texts.gmp_required')); + } + $zip = Archive::instance_by_useragent(date('Y-m-d') . '_' . str_replace(' ', '_', trans('texts.quote_documents'))); foreach ($clients->get() as $client) { foreach ($client->invoices as $invoice) { @@ -52,14 +78,29 @@ class QuoteReport extends AbstractReport foreach ($clients->get() as $client) { foreach ($client->invoices as $invoice) { - $this->data[] = [ + $row = [ $this->isExport ? $client->getDisplayName() : $client->present()->link, $this->isExport ? $invoice->invoice_number : $invoice->present()->link, $invoice->present()->invoice_date, $account->formatMoney($invoice->amount, $client), $invoice->present()->status(), + $invoice->private_notes, + $invoice->user->getDisplayName(), ]; + if ($hasTaxRates) { + $row[] = $account->formatMoney($invoice->getTaxTotal(), $client); + } + + if ($account->custom_invoice_text_label1) { + $row[] = $invoice->custom_text_value1; + } + if ($account->custom_invoice_text_label2) { + $row[] = $invoice->custom_text_value2; + } + + $this->data[] = $row; + $this->addToTotals($client->currency_id, 'amount', $invoice->amount); } } diff --git a/app/Ninja/Reports/TaskReport.php b/app/Ninja/Reports/TaskReport.php index b19e871c8639..9419af24b43c 100644 --- a/app/Ninja/Reports/TaskReport.php +++ b/app/Ninja/Reports/TaskReport.php @@ -7,14 +7,18 @@ use Utils; class TaskReport extends AbstractReport { - public $columns = [ - 'client', - 'date', - 'project', - 'description', - 'duration', - 'amount', - ]; + public function getColumns() + { + return [ + 'client' => [], + 'start_date' => [], + 'project' => [], + 'description' => [], + 'duration' => [], + 'amount' => [], + 'user' => ['columnSelector-false'], + ]; + } public function run() { @@ -23,12 +27,13 @@ class TaskReport extends AbstractReport $tasks = Task::scope() ->orderBy('created_at', 'desc') - ->with('client.contacts', 'project', 'account') + ->with('client.contacts', 'project', 'account', 'user') ->withArchived() ->dateRange($startDate, $endDate); foreach ($tasks->get() as $task) { - $amount = $task->getRate() * ($task->getDuration() / 60 / 60); + $duration = $task->getDuration($startDate->format('U'), $endDate->modify('+1 day')->format('U')); + $amount = $task->getRate() * ($duration / 60 / 60); if ($task->client && $task->client->currency_id) { $currencyId = $task->client->currency_id; } else { @@ -40,11 +45,12 @@ class TaskReport extends AbstractReport $this->isExport ? $task->getStartTime() : link_to($task->present()->url, $task->getStartTime()), $task->present()->project, $task->description, - Utils::formatTime($task->getDuration()), + Utils::formatTime($duration), Utils::formatMoney($amount, $currencyId), + $task->user->getDisplayName(), ]; - $this->addToTotals($currencyId, 'duration', $task->getDuration()); + $this->addToTotals($currencyId, 'duration', $duration); $this->addToTotals($currencyId, 'amount', $amount); } } diff --git a/app/Ninja/Reports/TaxRateReport.php b/app/Ninja/Reports/TaxRateReport.php index 7fad4c6e1c31..f4005134091b 100644 --- a/app/Ninja/Reports/TaxRateReport.php +++ b/app/Ninja/Reports/TaxRateReport.php @@ -7,14 +7,19 @@ use Auth; class TaxRateReport extends AbstractReport { - public $columns = [ - 'client', - 'invoice', - 'tax_name', - 'tax_rate', - 'amount', - 'paid', - ]; + public function getColumns() + { + return [ + 'client' => [], + 'invoice' => [], + 'tax_name' => [], + 'tax_rate' => [], + 'tax_amount' => [], + 'tax_paid' => [], + 'invoice_amount' => ['columnSelector-false'], + 'payment_amount' => ['columnSelector-false'], + ]; + } public function run() { @@ -74,6 +79,8 @@ class TaxRateReport extends AbstractReport $tax['rate'] . '%', $account->formatMoney($tax['amount'], $client), $account->formatMoney($tax['paid'], $client), + $invoice->present()->amount, + $invoice->present()->paid, ]; $this->addToTotals($client->currency_id, 'amount', $tax['amount']); diff --git a/app/Ninja/Repositories/AccountRepository.php b/app/Ninja/Repositories/AccountRepository.php index 9ec579aedec6..236f340e164c 100644 --- a/app/Ninja/Repositories/AccountRepository.php +++ b/app/Ninja/Repositories/AccountRepository.php @@ -144,25 +144,25 @@ class AccountRepository // include custom client fields in search if ($account->custom_client_label1) { - $data[$account->custom_client_label1] = []; + $data[$account->present()->customClientLabel1] = []; } if ($account->custom_client_label2) { - $data[$account->custom_client_label2] = []; + $data[$account->present()->customClientLabel2] = []; } if ($user->hasPermission('view_all')) { $clients = Client::scope() ->with('contacts', 'invoices') - ->withArchived() + ->withTrashed() ->with(['contacts', 'invoices' => function ($query) use ($user) { - $query->withArchived(); + $query->withTrashed(); }])->get(); } else { $clients = Client::scope() ->where('user_id', '=', $user->id) - ->withArchived() + ->withTrashed() ->with(['contacts', 'invoices' => function ($query) use ($user) { - $query->withArchived() + $query->withTrashed() ->where('user_id', '=', $user->id); }])->get(); } @@ -177,14 +177,14 @@ class AccountRepository } if ($client->custom_value1) { - $data[$account->custom_client_label1][] = [ + $data[$account->present()->customClientLabel1][] = [ 'value' => "{$client->custom_value1}: " . $client->getDisplayName(), 'tokens' => $client->custom_value1, 'url' => $client->present()->url, ]; } if ($client->custom_value2) { - $data[$account->custom_client_label2][] = [ + $data[$account->present()->customClientLabel2][] = [ 'value' => "{$client->custom_value2}: " . $client->getDisplayName(), 'tokens' => $client->custom_value2, 'url' => $client->present()->url, @@ -193,7 +193,7 @@ class AccountRepository foreach ($client->contacts as $contact) { $data['contacts'][] = [ - 'value' => $contact->getDisplayName(), + 'value' => $contact->getSearchName(), 'tokens' => implode(',', [$contact->first_name, $contact->last_name, $contact->email, $contact->phone]), 'url' => $client->present()->url, ]; @@ -226,6 +226,7 @@ class AccountRepository ENTITY_PAYMENT, ENTITY_CREDIT, ENTITY_PROJECT, + ENTITY_PROPOSAL, ]; foreach ($entityTypes as $entityType) { diff --git a/app/Ninja/Repositories/DocumentRepository.php b/app/Ninja/Repositories/DocumentRepository.php index 450d48f2b231..e470348a3a45 100644 --- a/app/Ninja/Repositories/DocumentRepository.php +++ b/app/Ninja/Repositories/DocumentRepository.php @@ -54,7 +54,14 @@ class DocumentRepository extends BaseRepository public function upload($data, &$doc_array = null) { - $uploaded = $data['file']; + if (! empty($data['grapesjs']) && $data['grapesjs']) { + $isProposal = true; + $uploaded = $data['files'][0]; + } else { + $isProposal = false; + $uploaded = $data['file']; + } + $extension = strtolower($uploaded->getClientOriginalExtension()); if (empty(Document::$types[$extension]) && ! empty(Document::$extraExtensions[$extension])) { $documentType = Document::$extraExtensions[$extension]; @@ -87,6 +94,11 @@ class DocumentRepository extends BaseRepository $document = Document::createNew(); $document->fill($data); + if ($isProposal) { + $document->is_proposal = true; + $document->document_key = strtolower(str_random(RANDOM_KEY_LENGTH)); + } + $disk = $document->getDisk(); if (! $disk->exists($filename)) {// Have we already stored the same file $stream = fopen($filePath, 'r'); diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php index e9e9cc66e685..d46bac6fa21c 100644 --- a/app/Ninja/Repositories/InvoiceRepository.php +++ b/app/Ninja/Repositories/InvoiceRepository.php @@ -240,7 +240,7 @@ class InvoiceRepository extends BaseRepository $table = \Datatable::query($query) ->addColumn('frequency', function ($model) { - return $model->frequency; + return trans('texts.freq_' . \Str::snake($model->frequency)); }) ->addColumn('start_date', function ($model) { return Utils::fromSqlDate($model->start_date); @@ -390,7 +390,7 @@ class InvoiceRepository extends BaseRepository $invoice->custom_taxes2 = $account->custom_invoice_taxes2 ?: false; // set the default due date - if ($entityType == ENTITY_INVOICE && empty($data['partial_due_date'])) { + if (empty($data['partial_due_date'])) { $client = Client::scope()->whereId($data['client_id'])->first(); $invoice->due_date = $account->defaultDueDate($client); } @@ -403,7 +403,7 @@ class InvoiceRepository extends BaseRepository if ($invoice->is_deleted) { return $invoice; - } elseif ($invoice->isSent() && config('ninja.lock_sent_invoices')) { + } elseif ($invoice->isLocked()) { return $invoice; } @@ -742,7 +742,7 @@ class InvoiceRepository extends BaseRepository if ($product && (Auth::user()->can('edit', $product))) { $product->notes = ($task || $expense) ? '' : $item['notes']; if (! $account->convert_products) { - $product->cost = $expense ? 0 : $item['cost']; + $product->cost = $expense ? 0 : Utils::parseFloat($item['cost']); } $product->tax_name1 = isset($item['tax_name1']) ? $item['tax_name1'] : null; $product->tax_rate1 = isset($item['tax_rate1']) ? $item['tax_rate1'] : 0; @@ -804,7 +804,7 @@ class InvoiceRepository extends BaseRepository $client->load('contacts'); $sendInvoiceIds = []; - if (! count($client->contacts)) { + if (! $client->contacts->count()) { return $invoice; } @@ -1213,13 +1213,14 @@ class InvoiceRepository extends BaseRepository public function findNeedingEndlessReminding(Account $account) { - $frequencyId = $account->account_email_settings->frequency_id_reminder4; - $frequency = Utils::getFromCache($frequencyId, 'frequencies'); + $settings = $account->account_email_settings; + $frequencyId = $settings->frequency_id_reminder4; if (! $frequencyId || ! $account->enable_reminder4) { return []; } + $frequency = Utils::getFromCache($frequencyId, 'frequencies'); $lastSentDate = date_create(); $lastSentDate->sub(date_interval_create_from_date_string($frequency->date_interval)); diff --git a/app/Ninja/Repositories/ProductRepository.php b/app/Ninja/Repositories/ProductRepository.php index 78212cef65b5..86f9cfed59e4 100644 --- a/app/Ninja/Repositories/ProductRepository.php +++ b/app/Ninja/Repositories/ProductRepository.php @@ -33,13 +33,17 @@ class ProductRepository extends BaseRepository 'products.tax_name1 as tax_name', 'products.tax_rate1 as tax_rate', 'products.deleted_at', - 'products.is_deleted' + 'products.is_deleted', + 'products.custom_value1', + 'products.custom_value2' ); if ($filter) { $query->where(function ($query) use ($filter) { $query->where('products.product_key', 'like', '%'.$filter.'%') - ->orWhere('products.notes', 'like', '%'.$filter.'%'); + ->orWhere('products.notes', 'like', '%'.$filter.'%') + ->orWhere('products.custom_value1', 'like', '%'.$filter.'%') + ->orWhere('products.custom_value2', 'like', '%'.$filter.'%'); }); } diff --git a/app/Ninja/Repositories/ProposalCategoryRepository.php b/app/Ninja/Repositories/ProposalCategoryRepository.php new file mode 100644 index 000000000000..734977bcf0c4 --- /dev/null +++ b/app/Ninja/Repositories/ProposalCategoryRepository.php @@ -0,0 +1,58 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_categories') + ->where('proposal_categories.account_id', '=', Auth::user()->account_id) + ->select( + 'proposal_categories.name', + 'proposal_categories.public_id', + 'proposal_categories.user_id', + 'proposal_categories.deleted_at', + 'proposal_categories.is_deleted' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_CATEGORY); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->Where('proposal_categories.name', 'like', '%'.$filter.'%'); + }); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($input['public_id']) ? $input['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalCategory::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/ProposalRepository.php b/app/Ninja/Repositories/ProposalRepository.php new file mode 100644 index 000000000000..6e7bf01a008c --- /dev/null +++ b/app/Ninja/Repositories/ProposalRepository.php @@ -0,0 +1,158 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposals') + ->where('proposals.account_id', '=', Auth::user()->account_id) + ->leftjoin('invoices', 'invoices.id', '=', 'proposals.invoice_id') + ->leftjoin('clients', 'clients.id', '=', 'invoices.client_id') + ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id') + ->leftJoin('proposal_templates', 'proposal_templates.id', '=', 'proposals.proposal_template_id') + ->where('clients.deleted_at', '=', null) + ->where('contacts.deleted_at', '=', null) + ->where('contacts.is_primary', '=', true) + ->select( + 'proposals.public_id', + 'proposals.user_id', + 'proposals.deleted_at', + 'proposals.created_at', + 'proposals.is_deleted', + 'proposals.private_notes', + 'proposals.html as content', + DB::raw("COALESCE(NULLIF(clients.name,''), NULLIF(CONCAT(contacts.first_name, ' ', contacts.last_name),''), NULLIF(contacts.email,'')) client"), + 'clients.user_id as client_user_id', + 'clients.public_id as client_public_id', + 'invoices.invoice_number as quote', + 'invoices.invoice_number as invoice_number', + 'invoices.public_id as invoice_public_id', + 'invoices.user_id as invoice_user_id', + 'proposal_templates.name as template', + 'proposal_templates.public_id as template_public_id', + 'proposal_templates.user_id as template_user_id' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposals.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + if (! $proposal) { + $proposal = Proposal::createNew(); + } + + $proposal->fill($input); + + if (isset($input['invoice_id'])) { + $proposal->invoice_id = $input['invoice_id'] ? Invoice::getPrivateId($input['invoice_id']) : null; + } + + if (isset($input['proposal_template_id'])) { + $proposal->proposal_template_id = $input['proposal_template_id'] ? ProposalTemplate::getPrivateId($input['proposal_template_id']) : null; + } + + $proposal->save(); + + // create invitations + $contactIds = []; + + foreach ($proposal->invoice->invitations as $invitation) { + $conactIds[] = $invitation->contact_id; + $found = false; + foreach ($proposal->proposal_invitations as $proposalInvitation) { + if ($invitation->contact_id == $proposalInvitation->contact_id) { + $found = true; + break; + } + } + if (! $found) { + $proposalInvitation = ProposalInvitation::createNew(); + $proposalInvitation->proposal_id = $proposal->id; + $proposalInvitation->contact_id = $invitation->contact_id; + $proposalInvitation->invitation_key = strtolower(str_random(RANDOM_KEY_LENGTH)); + $proposalInvitation->save(); + } + } + + // delete invitations + foreach ($proposal->proposal_invitations as $proposalInvitation) { + if (! in_array($proposalInvitation->contact_id, $conactIds)) { + $proposalInvitation->delete(); + } + } + + return $proposal; + } + + /** + * @param $invitationKey + * + * @return Invitation|bool + */ + public function findInvitationByKey($invitationKey) + { + // check for extra params at end of value (from website feature) + list($invitationKey) = explode('&', $invitationKey); + $invitationKey = substr($invitationKey, 0, RANDOM_KEY_LENGTH); + + /** @var \App\Models\Invitation $invitation */ + $invitation = ProposalInvitation::where('invitation_key', '=', $invitationKey)->first(); + if (! $invitation) { + return false; + } + + $proposal = $invitation->proposal; + if (! $proposal || $proposal->is_deleted) { + return false; + } + + $invoice = $proposal->invoice; + if (! $invoice || $invoice->is_deleted) { + return false; + } + + $client = $invoice->client; + if (! $client || $client->is_deleted) { + return false; + } + + return $invitation; + } +} diff --git a/app/Ninja/Repositories/ProposalSnippetRepository.php b/app/Ninja/Repositories/ProposalSnippetRepository.php new file mode 100644 index 000000000000..5a413815c3d4 --- /dev/null +++ b/app/Ninja/Repositories/ProposalSnippetRepository.php @@ -0,0 +1,74 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_snippets') + ->leftjoin('proposal_categories', 'proposal_categories.id', '=', 'proposal_snippets.proposal_category_id') + ->where('proposal_snippets.account_id', '=', Auth::user()->account_id) + ->select( + 'proposal_snippets.name', + 'proposal_snippets.public_id', + 'proposal_snippets.user_id', + 'proposal_snippets.deleted_at', + 'proposal_snippets.is_deleted', + 'proposal_snippets.icon', + 'proposal_snippets.private_notes', + 'proposal_snippets.html as content', + 'proposal_categories.name as category', + 'proposal_categories.public_id as category_public_id', + 'proposal_categories.user_id as category_user_id' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_SNIPPET); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('proposal_snippets.name', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposal_snippets.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalSnippet::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/ProposalTemplateRepository.php b/app/Ninja/Repositories/ProposalTemplateRepository.php new file mode 100644 index 000000000000..9470a98d37ae --- /dev/null +++ b/app/Ninja/Repositories/ProposalTemplateRepository.php @@ -0,0 +1,68 @@ +get(); + } + + public function find($filter = null, $userId = false) + { + $query = DB::table('proposal_templates') + ->where('proposal_templates.account_id', '=', Auth::user()->account_id) + ->select( + 'proposal_templates.name', + 'proposal_templates.public_id', + 'proposal_templates.user_id', + 'proposal_templates.deleted_at', + 'proposal_templates.is_deleted', + 'proposal_templates.html as content', + 'proposal_templates.private_notes' + ); + + $this->applyFilters($query, ENTITY_PROPOSAL_TEMPLATE); + + if ($filter) { + $query->where(function ($query) use ($filter) { + $query->where('clients.name', 'like', '%'.$filter.'%') + ->orWhere('contacts.first_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.last_name', 'like', '%'.$filter.'%') + ->orWhere('contacts.email', 'like', '%'.$filter.'%') + ->orWhere('proposal_templates.name', 'like', '%'.$filter.'%'); + }); + } + + if ($userId) { + $query->where('proposal_templates.user_id', '=', $userId); + } + + return $query; + } + + public function save($input, $proposal = false) + { + $publicId = isset($data['public_id']) ? $data['public_id'] : false; + + if (! $proposal) { + $proposal = ProposalTemplate::createNew(); + } + + $proposal->fill($input); + $proposal->save(); + + return $proposal; + } +} diff --git a/app/Ninja/Repositories/SubscriptionRepository.php b/app/Ninja/Repositories/SubscriptionRepository.php index b4687f8b192e..e59af6999e31 100644 --- a/app/Ninja/Repositories/SubscriptionRepository.php +++ b/app/Ninja/Repositories/SubscriptionRepository.php @@ -21,7 +21,8 @@ class SubscriptionRepository extends BaseRepository 'subscriptions.public_id', 'subscriptions.target_url as target', 'subscriptions.event_id as event', - 'subscriptions.deleted_at' + 'subscriptions.deleted_at', + 'subscriptions.format' ); return $query; diff --git a/app/Ninja/Transformers/PaymentTermTransformer.php b/app/Ninja/Transformers/PaymentTermTransformer.php new file mode 100644 index 000000000000..57fc1304e985 --- /dev/null +++ b/app/Ninja/Transformers/PaymentTermTransformer.php @@ -0,0 +1,36 @@ +paymentTerm = $paymentTerm; + } + + + public function transform(PaymentTerm $paymentTerm) + { + return array_merge($this->getDefaults($paymentTerm), [ + 'num_days' => (int) $paymentTerm->num_days, + 'name' => trans('texts.payment_terms_net') . ' ' . $paymentTerm->getNumDays(), + 'updated_at' => $this->getTimestamp($paymentTerm->updated_at), + 'archived_at' => $this->getTimestamp($paymentTerm->deleted_at), + 'is_default' => (bool) $paymentTerm->account_id == 0 ? true : false, + ]); + } +} diff --git a/app/Ninja/Transformers/ProjectTransformer.php b/app/Ninja/Transformers/ProjectTransformer.php index dbff6390a40a..ad049b183727 100644 --- a/app/Ninja/Transformers/ProjectTransformer.php +++ b/app/Ninja/Transformers/ProjectTransformer.php @@ -17,6 +17,9 @@ class ProjectTransformer extends EntityTransformer * @SWG\Property(property="archived_at", type="integer", example=1451160233, readOnly=true) * @SWG\Property(property="is_deleted", type="boolean", example=false, readOnly=true) * @SWG\Property(property="task_rate", type="number", format="float", example=10) + * @SWG\Property(property="due_date", type="string", format="date", example="2016-01-01") + * @SWG\Property(property="private_notes", type="string", format="Sample notes", example=10) + * @SWG\Property(property="budgeted_hours", type="number", format="float", example=10) */ public function transform(Project $project) { @@ -28,6 +31,9 @@ class ProjectTransformer extends EntityTransformer 'archived_at' => $this->getTimestamp($project->deleted_at), 'is_deleted' => (bool) $project->is_deleted, 'task_rate' => (float) $project->task_rate, + 'due_date' => $project->due_date, + 'private_notes' => $project->private_notes, + 'budgeted_hours' => (float) $project->budgeted_hours, ]); } } diff --git a/app/Policies/ProposalCategoryPolicy.php b/app/Policies/ProposalCategoryPolicy.php new file mode 100644 index 000000000000..4d89178eade8 --- /dev/null +++ b/app/Policies/ProposalCategoryPolicy.php @@ -0,0 +1,7 @@ +'; // Get the breadcrumbs by exploding the current path. @@ -133,6 +134,9 @@ class AppServiceProvider extends ServiceProvider if ($i == count($crumbs) - 1) { $str .= "
  • $name
  • "; } else { + if (count($crumbs) > 2 && $crumbs[1] == 'proposals' && $crumb != 'proposals') { + $crumb = 'proposals/' . $crumb; + } $str .= '
  • '.link_to($crumb, $name).'
  • '; } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index 97714c29fa6c..bbc80083ec8b 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/app/Providers/AuthServiceProvider.php @@ -34,6 +34,10 @@ class AuthServiceProvider extends ServiceProvider \App\Models\PaymentTerm::class => \App\Policies\PaymentTermPolicy::class, \App\Models\Project::class => \App\Policies\ProjectPolicy::class, \App\Models\AccountGatewayToken::class => \App\Policies\CustomerPolicy::class, + \App\Models\Proposal::class => \App\Policies\ProposalPolicy::class, + \App\Models\ProposalSnippet::class => \App\Policies\ProposalSnippetPolicy::class, + \App\Models\ProposalTemplate::class => \App\Policies\ProposalTemplatePolicy::class, + \App\Models\ProposalCategory::class => \App\Policies\ProposalCategoryPolicy::class, ]; /** diff --git a/app/Providers/ComposerServiceProvider.php b/app/Providers/ComposerServiceProvider.php index ef2512c796f0..8978f2ac0006 100644 --- a/app/Providers/ComposerServiceProvider.php +++ b/app/Providers/ComposerServiceProvider.php @@ -23,6 +23,7 @@ class ComposerServiceProvider extends ServiceProvider 'expenses.edit', 'accounts.localization', 'payments.credit_card', + 'invited.details', ], 'App\Http\ViewComposers\TranslationComposer' ); @@ -41,6 +42,15 @@ class ComposerServiceProvider extends ServiceProvider ], 'App\Http\ViewComposers\ClientPortalHeaderComposer' ); + + view()->composer( + [ + 'proposals.edit', + 'proposals.templates.edit', + 'proposals.snippets.edit', + ], + 'App\Http\ViewComposers\ProposalComposer' + ); } /** diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index 3f9723c93358..5a501e891df9 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -225,9 +225,14 @@ class EventServiceProvider extends ServiceProvider 'App\Listeners\InvoiceListener@jobFailed' ], - //DNS + //DNS Add A record to Cloudflare 'App\Events\SubdomainWasUpdated' => [ 'App\Listeners\DNSListener@addDNSRecord' + ], + + //DNS Remove A record from Cloudflare + 'App\Events\SubdomainWasRemoved' => [ + 'App\Listeners\DNSListener@removeDNSRecord' ] /* diff --git a/app/Services/BankAccountService.php b/app/Services/BankAccountService.php index 4738e0eaf98f..245741caac8c 100644 --- a/app/Services/BankAccountService.php +++ b/app/Services/BankAccountService.php @@ -165,7 +165,7 @@ class BankAccountService extends BaseService } // if we can't find a match skip the account - if (count($bankAccounts) && ! $obj->account_name) { + if ($bankAccounts->count() && ! $obj->account_name) { return false; } diff --git a/app/Services/ImportService.php b/app/Services/ImportService.php index b8508f6f3722..7c927660b964 100644 --- a/app/Services/ImportService.php +++ b/app/Services/ImportService.php @@ -947,7 +947,7 @@ class ImportService $this->maps['client'][$name] = $client->id; $this->maps['client_ids'][$client->public_id] = $client->id; } - if (count($client->contacts) && $name = strtolower(trim($client->contacts[0]->email))) { + if ($client->contacts->count() && $name = strtolower(trim($client->contacts[0]->email))) { $this->maps['client'][$name] = $client->id; $this->maps['client_ids'][$client->public_id] = $client->id; } diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php index 00eec4ddfb99..386755926cbc 100644 --- a/app/Services/PaymentService.php +++ b/app/Services/PaymentService.php @@ -153,7 +153,7 @@ class PaymentService extends BaseService public function save($input, $payment = null, $invoice = null) { // if the payment amount is more than the balance create a credit - if ($invoice && $input['amount'] > $invoice->balance) { + if ($invoice && Utils::parseFloat($input['amount']) > $invoice->balance) { $credit = Credit::createNew(); $credit->client_id = $invoice->client_id; $credit->credit_date = date_create()->format('Y-m-d'); diff --git a/app/Services/ProposalCategoryService.php b/app/Services/ProposalCategoryService.php new file mode 100644 index 000000000000..5fff79695831 --- /dev/null +++ b/app/Services/ProposalCategoryService.php @@ -0,0 +1,71 @@ +proposalCategoryRepo = $proposalCategoryRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalCategoryRepo; + } + + /** + * @param $data + * @param mixed $proposalCategory + * + * @return mixed|null + */ + public function save($data, $proposalCategory = false) + { + return $this->proposalCategoryRepo->save($data, $proposalCategory); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalCategoryDatatable(); + + $query = $this->proposalCategoryRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalService.php b/app/Services/ProposalService.php new file mode 100644 index 000000000000..eb7542738f13 --- /dev/null +++ b/app/Services/ProposalService.php @@ -0,0 +1,71 @@ +proposalRepo = $proposalRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalRepo; + } + + /** + * @param $data + * @param mixed $proposal + * + * @return mixed|null + */ + public function save($data, $proposal = false) + { + return $this->proposalRepo->save($data, $proposal); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalDatatable(); + + $query = $this->proposalRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalSnippetService.php b/app/Services/ProposalSnippetService.php new file mode 100644 index 000000000000..981ac8c3415c --- /dev/null +++ b/app/Services/ProposalSnippetService.php @@ -0,0 +1,71 @@ +proposalSnippetRepo = $proposalSnippetRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalSnippetRepo; + } + + /** + * @param $data + * @param mixed $proposalSnippet + * + * @return mixed|null + */ + public function save($data, $proposalSnippet = false) + { + return $this->proposalSnippetRepo->save($data, $proposalSnippet); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalSnippetDatatable(); + + $query = $this->proposalSnippetRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/ProposalTemplateService.php b/app/Services/ProposalTemplateService.php new file mode 100644 index 000000000000..c367051b0e3b --- /dev/null +++ b/app/Services/ProposalTemplateService.php @@ -0,0 +1,71 @@ +proposalTemplateRepo = $proposalTemplateRepo; + $this->datatableService = $datatableService; + } + + /** + * @return CreditRepository + */ + protected function getRepo() + { + return $this->proposalTemplateRepo; + } + + /** + * @param $data + * @param mixed $proposalTemplate + * + * @return mixed|null + */ + public function save($data, $proposalTemplate = false) + { + return $this->proposalTemplateRepo->save($data, $proposalTemplate); + } + + /** + * @param $clientPublicId + * @param $search + * @param mixed $userId + * + * @return \Illuminate\Http\JsonResponse + */ + public function getDatatable($search, $userId) + { + // we don't support bulk edit and hide the client on the individual client page + $datatable = new ProposalTemplateDatatable(); + + $query = $this->proposalTemplateRepo->find($search, $userId); + + return $this->datatableService->createDatatable($datatable, $query); + } +} diff --git a/app/Services/TemplateService.php b/app/Services/TemplateService.php index e98cfff390f7..8ed901d406d3 100644 --- a/app/Services/TemplateService.php +++ b/app/Services/TemplateService.php @@ -27,7 +27,13 @@ class TemplateService /** @var \App\Models\Invitation $invitation */ $invitation = $data['invitation']; - $invoice = $invitation->invoice; + // check if it's a proposal + if ($invitation->proposal) { + $invoice = $invitation->proposal->invoice; + } else { + $invoice = $invitation->invoice; + } + $contact = $invitation->contact; $passwordHTML = isset($data['password']) ? '

    '.trans('texts.password').': '.$data['password'].'

    ' : false; $documentsHTML = ''; diff --git a/bower.json b/bower.json index 5b9c049bb8fc..f8330738a111 100644 --- a/bower.json +++ b/bower.json @@ -40,7 +40,8 @@ "toastr": "^2.1.3", "jt.timepicker": "jquery-timepicker-jt#^1.11.12", "qrcode.js": "qrcode-js#*", - "money.js": "^0.1.3" + "money.js": "^0.1.3", + "grapesjs": "^0.13.8" }, "resolutions": { "jquery": "~1.11" diff --git a/composer.json b/composer.json index b5e50395018b..b7d93290c6c8 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": ">=7.0.0", + "php": ">=7.0.0 <7.2", "ext-gd": "*", "ext-gmp": "*", "anahkiasen/former": "4.*", @@ -25,6 +25,7 @@ "barryvdh/laravel-ide-helper": "~2.2", "cerdic/css-tidy": "~v1.5", "chumper/datatable": "dev-develop#04ef2bf", + "cleverit/ubl_invoice": "1.*", "codedge/laravel-selfupdater": "5.x-dev", "collizo4sky/omnipay-wepay": "dev-address-fix", "digitickets/omnipay-gocardlessv2": "dev-payment-fix", diff --git a/composer.lock b/composer.lock index a83703eb226f..7370febc379e 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": "7bcccd99be4c828e4192fd08c530a5e5", - "content-hash": "e886e481ac6825f0b1d9402360938147", + "hash": "93dd175ac0d4991745c24edb65807e04", + "content-hash": "2fafcc49fe838509079aea7e46db843f", "packages": [ { "name": "abdala/omnipay-pagseguro", @@ -169,16 +169,16 @@ }, { "name": "anahkiasen/former", - "version": "4.1.5", + "version": "4.1.6", "source": { "type": "git", "url": "https://github.com/formers/former.git", - "reference": "657151b3cbe5eb13d59f93d0ca413c7778d15a6f" + "reference": "53327a674c9b5607106784a9161ff91e62ade6e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/formers/former/zipball/657151b3cbe5eb13d59f93d0ca413c7778d15a6f", - "reference": "657151b3cbe5eb13d59f93d0ca413c7778d15a6f", + "url": "https://api.github.com/repos/formers/former/zipball/53327a674c9b5607106784a9161ff91e62ade6e4", + "reference": "53327a674c9b5607106784a9161ff91e62ade6e4", "shasum": "" }, "require": { @@ -237,7 +237,7 @@ "foundation", "laravel" ], - "time": "2017-11-27 14:58:10" + "time": "2018-01-02 20:20:00" }, { "name": "anahkiasen/html-object", @@ -393,16 +393,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.44.1", + "version": "3.49.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "3f88cb0b9eb6ca34b2823c1cb42e10ac4d52fa6d" + "reference": "b4a698296c5772a959b131481d11b6c1d7498a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/3f88cb0b9eb6ca34b2823c1cb42e10ac4d52fa6d", - "reference": "3f88cb0b9eb6ca34b2823c1cb42e10ac4d52fa6d", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/b4a698296c5772a959b131481d11b6c1d7498a66", + "reference": "b4a698296c5772a959b131481d11b6c1d7498a66", "shasum": "" }, "require": { @@ -424,7 +424,7 @@ "ext-dom": "*", "ext-openssl": "*", "nette/neon": "^2.3", - "phpunit/phpunit": "^4.8.35|^5.4.0", + "phpunit/phpunit": "^4.8.35|^5.4.3", "psr/cache": "^1.0" }, "suggest": { @@ -469,7 +469,7 @@ "s3", "sdk" ], - "time": "2017-12-01 20:57:47" + "time": "2018-01-16 23:44:11" }, { "name": "bacon/bacon-qr-code", @@ -793,16 +793,16 @@ }, { "name": "braintree/braintree_php", - "version": "3.26.0", + "version": "3.26.1", "source": { "type": "git", "url": "https://github.com/braintree/braintree_php.git", - "reference": "184bbdd65951a3ad766992ef73bb6e93aeba82b7" + "reference": "7f66ed17f38efd45904f920695b02603b091bae6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/braintree/braintree_php/zipball/184bbdd65951a3ad766992ef73bb6e93aeba82b7", - "reference": "184bbdd65951a3ad766992ef73bb6e93aeba82b7", + "url": "https://api.github.com/repos/braintree/braintree_php/zipball/7f66ed17f38efd45904f920695b02603b091bae6", + "reference": "7f66ed17f38efd45904f920695b02603b091bae6", "shasum": "" }, "require": { @@ -836,7 +836,7 @@ } ], "description": "Braintree PHP Client Library", - "time": "2017-11-17 21:47:27" + "time": "2017-12-14 00:08:17" }, { "name": "cardgate/omnipay-cardgate", @@ -1031,16 +1031,16 @@ }, { "name": "classpreloader/classpreloader", - "version": "3.1.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/ClassPreloader/ClassPreloader.git", - "reference": "bc7206aa892b5a33f4680421b69b191efd32b096" + "reference": "4729e438e0ada350f91148e7d4bb9809342575ff" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/bc7206aa892b5a33f4680421b69b191efd32b096", - "reference": "bc7206aa892b5a33f4680421b69b191efd32b096", + "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/4729e438e0ada350f91148e7d4bb9809342575ff", + "reference": "4729e438e0ada350f91148e7d4bb9809342575ff", "shasum": "" }, "require": { @@ -1053,7 +1053,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.2-dev" } }, "autoload": { @@ -1081,7 +1081,59 @@ "class", "preload" ], - "time": "2016-09-16 12:50:15" + "time": "2017-12-10 11:40:39" + }, + { + "name": "cleverit/ubl_invoice", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/CleverIT/UBL_invoice.git", + "reference": "8b98ed26b975cae24eea319f3f2cefd82add735e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CleverIT/UBL_invoice/zipball/8b98ed26b975cae24eea319f3f2cefd82add735e", + "reference": "8b98ed26b975cae24eea319f3f2cefd82add735e", + "shasum": "" + }, + "require": { + "sabre/xml": "^1.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "CleverIt\\UBL\\Invoice\\": [ + "src/", + "src/classes" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bram van Eijk | CleverIT", + "email": "bram@cleverit.nl", + "homepage": "http://www.cleverit.nl", + "role": "Developer" + } + ], + "description": "A PHP wrapper for UBL invoices", + "homepage": "https://github.com/CleverIT/UBL_invoice", + "keywords": [ + "clever invoice", + "cleverit", + "electronic invoice", + "invoice", + "ubl", + "ublinvoice", + "xml", + "xml invoice" + ], + "time": "2018-01-13 00:27:05" }, { "name": "codedge/laravel-selfupdater", @@ -1629,16 +1681,16 @@ }, { "name": "digitickets/omnipay-realex", - "version": "5.0.0", + "version": "5.1.0", "source": { "type": "git", "url": "https://github.com/digitickets/omnipay-realex.git", - "reference": "4d1c5bf3a027f3862e2533414a00c14e06f02b74" + "reference": "eb9d4c8f78c9360248eab901f541069e08defafd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/digitickets/omnipay-realex/zipball/4d1c5bf3a027f3862e2533414a00c14e06f02b74", - "reference": "4d1c5bf3a027f3862e2533414a00c14e06f02b74", + "url": "https://api.github.com/repos/digitickets/omnipay-realex/zipball/eb9d4c8f78c9360248eab901f541069e08defafd", + "reference": "eb9d4c8f78c9360248eab901f541069e08defafd", "shasum": "" }, "require": { @@ -1674,7 +1726,7 @@ "purchase", "realex" ], - "time": "2016-11-17 13:44:19" + "time": "2017-12-19 19:14:50" }, { "name": "dioscouri/omnipay-cybersource", @@ -2555,16 +2607,16 @@ }, { "name": "gocardless/gocardless-pro", - "version": "1.3.0", + "version": "1.4.0", "source": { "type": "git", "url": "https://github.com/gocardless/gocardless-pro-php.git", - "reference": "16ac38c2531e08c15e54b4a82d44854349cbfcf6" + "reference": "38ecc74aed51d2135d6e0b5419d1449dcf1ff692" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/16ac38c2531e08c15e54b4a82d44854349cbfcf6", - "reference": "16ac38c2531e08c15e54b4a82d44854349cbfcf6", + "url": "https://api.github.com/repos/gocardless/gocardless-pro-php/zipball/38ecc74aed51d2135d6e0b5419d1449dcf1ff692", + "reference": "38ecc74aed51d2135d6e0b5419d1449dcf1ff692", "shasum": "" }, "require": { @@ -2603,7 +2655,7 @@ "direct debit", "gocardless" ], - "time": "2017-11-14 15:46:50" + "time": "2017-12-04 16:46:06" }, { "name": "google/apiclient", @@ -2666,16 +2718,16 @@ }, { "name": "google/apiclient-services", - "version": "v0.36", + "version": "v0.42", "source": { "type": "git", "url": "https://github.com/google/google-api-php-client-services.git", - "reference": "2fd7d2876fbc0174faddba3241956a1393536159" + "reference": "873421bf7cd0cab613da792124db04e203ff196b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/2fd7d2876fbc0174faddba3241956a1393536159", - "reference": "2fd7d2876fbc0174faddba3241956a1393536159", + "url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/873421bf7cd0cab613da792124db04e203ff196b", + "reference": "873421bf7cd0cab613da792124db04e203ff196b", "shasum": "" }, "require": { @@ -2699,20 +2751,20 @@ "keywords": [ "google" ], - "time": "2017-11-25 00:23:12" + "time": "2018-01-13 00:23:28" }, { "name": "google/auth", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/google/google-auth-library-php.git", - "reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd" + "reference": "f3fc99fd621f339ee3d4de01bd6a709ed1396116" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/548d27d670f0236dc5258fa4cdde6e7b63464cfd", - "reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd", + "url": "https://api.github.com/repos/google/google-auth-library-php/zipball/f3fc99fd621f339ee3d4de01bd6a709ed1396116", + "reference": "f3fc99fd621f339ee3d4de01bd6a709ed1396116", "shasum": "" }, "require": { @@ -2725,7 +2777,9 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "^1.11", - "phpunit/phpunit": "3.7.*" + "guzzlehttp/promises": "0.1.1|^1.3", + "phpunit/phpunit": "^4.8.36", + "sebastian/comparator": ">=1.2.3" }, "type": "library", "autoload": { @@ -2744,26 +2798,26 @@ "google", "oauth2" ], - "time": "2017-10-10 17:01:45" + "time": "2017-12-06 21:27:53" }, { "name": "google/cloud", - "version": "v0.46.0", + "version": "v0.51.0", "source": { "type": "git", "url": "https://github.com/GoogleCloudPlatform/google-cloud-php.git", - "reference": "288c3daf85300233dd93f1dfd4f1d040a0cdb536" + "reference": "563469c033d82412fc5eaa0884e55c2ee0bcfe05" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/zipball/288c3daf85300233dd93f1dfd4f1d040a0cdb536", - "reference": "288c3daf85300233dd93f1dfd4f1d040a0cdb536", + "url": "https://api.github.com/repos/GoogleCloudPlatform/google-cloud-php/zipball/563469c033d82412fc5eaa0884e55c2ee0bcfe05", + "reference": "563469c033d82412fc5eaa0884e55c2ee0bcfe05", "shasum": "" }, "require": { "google/auth": "~0.9|^1.0", - "google/gax": "0.27.0", - "google/proto-client": "0.27.0", + "google/gax": "^0.29", + "google/proto-client": "^0.29.0", "guzzlehttp/guzzle": "^5.3|^6.0", "guzzlehttp/psr7": "^1.2", "monolog/monolog": "~1", @@ -2773,24 +2827,28 @@ "rize/uri-template": "~0.3" }, "replace": { - "google/cloud-bigquery": "0.3.1", - "google/cloud-bigtable": "0.1.0", - "google/cloud-core": "1.14.0", - "google/cloud-datastore": "1.1.0", - "google/cloud-dlp": "0.4.0", - "google/cloud-error-reporting": "0.7.0", - "google/cloud-firestore": "0.2.0", - "google/cloud-language": "0.10.0", - "google/cloud-logging": "1.7.0", - "google/cloud-monitoring": "0.7.0", - "google/cloud-pubsub": "0.10.0", - "google/cloud-spanner": "0.10.0", - "google/cloud-speech": "0.9.0", - "google/cloud-storage": "1.2.1", - "google/cloud-trace": "0.3.3", - "google/cloud-translate": "1.0.2", - "google/cloud-videointelligence": "0.8.0", - "google/cloud-vision": "0.7.0" + "google/cloud-bigquery": "1.0.1", + "google/cloud-bigtable": "0.1.1", + "google/cloud-container": "0.1.1", + "google/cloud-core": "1.15.1", + "google/cloud-dataproc": "0.1.1", + "google/cloud-datastore": "1.2.1", + "google/cloud-debugger": "0.2.0", + "google/cloud-dlp": "0.4.3", + "google/cloud-error-reporting": "0.7.3", + "google/cloud-firestore": "0.3.4", + "google/cloud-language": "0.11.2", + "google/cloud-logging": "1.8.3", + "google/cloud-monitoring": "0.7.3", + "google/cloud-oslogin": "0.1.1", + "google/cloud-pubsub": "0.11.3", + "google/cloud-spanner": "1.0.1", + "google/cloud-speech": "0.10.2", + "google/cloud-storage": "1.3.2", + "google/cloud-trace": "0.5.1", + "google/cloud-translate": "1.1.0", + "google/cloud-videointelligence": "0.8.3", + "google/cloud-vision": "0.8.2" }, "require-dev": { "erusev/parsedown": "^1.6", @@ -2804,10 +2862,12 @@ "vierbergenlars/php-semver": "^3.0" }, "suggest": { + "google/cloud-bigquerydatatransfer": "Client library for the BigQuery Data Transfer API.", "phpseclib/phpseclib": "May be used in place of OpenSSL for creating signed Cloud Storage URLs. Please require version ^2." }, "bin": [ - "src/Core/bin/google-cloud-batch" + "src/Core/bin/google-cloud-batch", + "src/Debugger/bin/google-cloud-debugger" ], "type": "library", "extra": { @@ -2868,25 +2928,25 @@ "translation", "vision" ], - "time": "2017-12-02 00:32:15" + "time": "2018-01-12 19:19:47" }, { "name": "google/gax", - "version": "0.27.0", + "version": "0.29.0", "source": { "type": "git", "url": "https://github.com/googleapis/gax-php.git", - "reference": "28d91f30966b91004d1ef66ca09df04fa730c8d9" + "reference": "eb4787747f6c90cbe760a31801ef224ccf3a9b36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/gax-php/zipball/28d91f30966b91004d1ef66ca09df04fa730c8d9", - "reference": "28d91f30966b91004d1ef66ca09df04fa730c8d9", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/eb4787747f6c90cbe760a31801ef224ccf3a9b36", + "reference": "eb4787747f6c90cbe760a31801ef224ccf3a9b36", "shasum": "" }, "require": { "google/auth": "~0.9|^1.0", - "google/protobuf": "3.4.*", + "google/protobuf": "^3.5.1", "grpc/grpc": "^1.4", "php": ">=5.5" }, @@ -2910,20 +2970,20 @@ "keywords": [ "google" ], - "time": "2017-11-21 23:04:00" + "time": "2017-12-28 17:31:08" }, { "name": "google/proto-client", - "version": "0.27.0", + "version": "0.29.0", "source": { "type": "git", "url": "https://github.com/googleapis/proto-client-php.git", - "reference": "39a6917748da381945e23876e8a9bf6a8e917937" + "reference": "47e52e5819426edff97c2831efe022b0141c44f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/googleapis/proto-client-php/zipball/39a6917748da381945e23876e8a9bf6a8e917937", - "reference": "39a6917748da381945e23876e8a9bf6a8e917937", + "url": "https://api.github.com/repos/googleapis/proto-client-php/zipball/47e52e5819426edff97c2831efe022b0141c44f1", + "reference": "47e52e5819426edff97c2831efe022b0141c44f1", "shasum": "" }, "require": { @@ -2950,20 +3010,20 @@ "keywords": [ "google" ], - "time": "2017-11-22 22:05:44" + "time": "2017-12-21 21:59:33" }, { "name": "google/protobuf", - "version": "v3.4.1", + "version": "v3.5.1.1", "source": { "type": "git", "url": "https://github.com/google/protobuf.git", - "reference": "b04e5cba356212e4e8c66c61bbe0c3a20537c5b9" + "reference": "860bd12fec5c69e6529565165532b3d5108a7d97" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/google/protobuf/zipball/b04e5cba356212e4e8c66c61bbe0c3a20537c5b9", - "reference": "b04e5cba356212e4e8c66c61bbe0c3a20537c5b9", + "url": "https://api.github.com/repos/google/protobuf/zipball/860bd12fec5c69e6529565165532b3d5108a7d97", + "reference": "860bd12fec5c69e6529565165532b3d5108a7d97", "shasum": "" }, "require": { @@ -2991,7 +3051,7 @@ "keywords": [ "proto" ], - "time": "2017-09-14 19:24:28" + "time": "2018-01-05 21:42:10" }, { "name": "grpc/grpc", @@ -3618,16 +3678,16 @@ }, { "name": "jaybizzle/crawler-detect", - "version": "v1.2.54", + "version": "v1.2.55", "source": { "type": "git", "url": "https://github.com/JayBizzle/Crawler-Detect.git", - "reference": "9af25770d9382917b680009a88497162405bbe48" + "reference": "e745d69502afc610ff993315e2607ad41e3bc13c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/9af25770d9382917b680009a88497162405bbe48", - "reference": "9af25770d9382917b680009a88497162405bbe48", + "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/e745d69502afc610ff993315e2607ad41e3bc13c", + "reference": "e745d69502afc610ff993315e2607ad41e3bc13c", "shasum": "" }, "require": { @@ -3663,7 +3723,7 @@ "crawlerdetect", "php crawler detect" ], - "time": "2017-10-28 13:05:55" + "time": "2018-01-05 07:59:11" }, { "name": "jaybizzle/laravel-crawler-detect", @@ -4730,16 +4790,16 @@ }, { "name": "maatwebsite/excel", - "version": "2.1.23", + "version": "2.1.24", "source": { "type": "git", "url": "https://github.com/Maatwebsite/Laravel-Excel.git", - "reference": "8682c955601b6de15a8c7d6e373b927cc8380627" + "reference": "bd71c9f462ea4a7945944691cc58acd2c85abd47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/8682c955601b6de15a8c7d6e373b927cc8380627", - "reference": "8682c955601b6de15a8c7d6e373b927cc8380627", + "url": "https://api.github.com/repos/Maatwebsite/Laravel-Excel/zipball/bd71c9f462ea4a7945944691cc58acd2c85abd47", + "reference": "bd71c9f462ea4a7945944691cc58acd2c85abd47", "shasum": "" }, "require": { @@ -4750,11 +4810,11 @@ "jeremeamia/superclosure": "^2.3", "nesbot/carbon": "~1.0", "php": ">=5.5", - "phpoffice/phpexcel": "1.8.*", + "phpoffice/phpexcel": "^1.8.1", "tijsverkoyen/css-to-inline-styles": "~2.0" }, "require-dev": { - "mockery/mockery": "~0.9", + "mockery/mockery": "~1.0", "orchestra/testbench": "3.1.*|3.2.*|3.3.*|3.4.*|3.5.*", "phpseclib/phpseclib": "~1.0", "phpunit/phpunit": "~4.0" @@ -4804,7 +4864,7 @@ "import", "laravel" ], - "time": "2017-09-19 19:36:48" + "time": "2018-01-10 11:58:11" }, { "name": "maximebf/debugbar", @@ -5348,16 +5408,16 @@ }, { "name": "nikic/php-parser", - "version": "v3.1.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89" + "reference": "579f4ce846734a1cf55d6a531d00ca07a43e3cda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/08131e7ff29de6bb9f12275c7d35df71f25f4d89", - "reference": "08131e7ff29de6bb9f12275c7d35df71f25f4d89", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/579f4ce846734a1cf55d6a531d00ca07a43e3cda", + "reference": "579f4ce846734a1cf55d6a531d00ca07a43e3cda", "shasum": "" }, "require": { @@ -5395,7 +5455,7 @@ "parser", "php" ], - "time": "2017-11-04 11:48:34" + "time": "2017-12-26 14:43:21" }, { "name": "nwidart/laravel-modules", @@ -7601,16 +7661,16 @@ }, { "name": "pragmarx/google2fa", - "version": "v2.0.6", + "version": "v2.0.7", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa.git", - "reference": "bc2d654305e4d09254125f8cd390a7fbc4742d46" + "reference": "5a818bda62fab0c0a79060b06d50d50b5525d631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/bc2d654305e4d09254125f8cd390a7fbc4742d46", - "reference": "bc2d654305e4d09254125f8cd390a7fbc4742d46", + "url": "https://api.github.com/repos/antonioribeiro/google2fa/zipball/5a818bda62fab0c0a79060b06d50d50b5525d631", + "reference": "5a818bda62fab0c0a79060b06d50d50b5525d631", "shasum": "" }, "require": { @@ -7621,8 +7681,7 @@ }, "require-dev": { "bacon/bacon-qr-code": "~1.0", - "phpspec/phpspec": "~2.1", - "phpunit/phpunit": "~4" + "phpunit/phpunit": "~4|~5|~6" }, "suggest": { "bacon/bacon-qr-code": "Required to generate inline QR Codes." @@ -7636,7 +7695,8 @@ }, "autoload": { "psr-4": { - "PragmaRX\\Google2FA\\": "src/" + "PragmaRX\\Google2FA\\": "src/", + "PragmaRX\\Google2FA\\Tests\\": "tests/" } }, "notification-url": "https://packagist.org/downloads/", @@ -7658,24 +7718,24 @@ "google2fa", "laravel" ], - "time": "2017-09-12 06:55:05" + "time": "2018-01-06 16:21:07" }, { "name": "pragmarx/google2fa-laravel", - "version": "v0.1.2", + "version": "v0.1.4", "source": { "type": "git", "url": "https://github.com/antonioribeiro/google2fa-laravel.git", - "reference": "ebc24520bea1f1ef5659e39d4024a3275ce49a49" + "reference": "38bd96a1732b9dea963c52e0f503a65265c077c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/ebc24520bea1f1ef5659e39d4024a3275ce49a49", - "reference": "ebc24520bea1f1ef5659e39d4024a3275ce49a49", + "url": "https://api.github.com/repos/antonioribeiro/google2fa-laravel/zipball/38bd96a1732b9dea963c52e0f503a65265c077c9", + "reference": "38bd96a1732b9dea963c52e0f503a65265c077c9", "shasum": "" }, "require": { - "laravel/framework": "~5", + "laravel/framework": ">=5.2", "php": ">=5.4", "pragmarx/google2fa": "~2.0" }, @@ -7684,7 +7744,8 @@ "phpspec/phpspec": "~3" }, "suggest": { - "bacon/bacon-qr-code": "Required to generate inline QR Codes." + "bacon/bacon-qr-code": "Required to generate inline QR Codes.", + "pragmarx/recovery": "Generate recovery codes." }, "type": "library", "extra": { @@ -7728,7 +7789,7 @@ "google2fa", "laravel" ], - "time": "2017-06-23 00:45:24" + "time": "2017-12-06 03:26:14" }, { "name": "predis/predis", @@ -7974,16 +8035,16 @@ }, { "name": "psy/psysh", - "version": "v0.8.15", + "version": "v0.8.17", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "b1d289c2cb03a2f8249912c53e96ced38f879926" + "reference": "5069b70e8c4ea492c2b5939b6eddc78bfe41cfec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/b1d289c2cb03a2f8249912c53e96ced38f879926", - "reference": "b1d289c2cb03a2f8249912c53e96ced38f879926", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/5069b70e8c4ea492c2b5939b6eddc78bfe41cfec", + "reference": "5069b70e8c4ea492c2b5939b6eddc78bfe41cfec", "shasum": "" }, "require": { @@ -7991,14 +8052,13 @@ "jakub-onderka/php-console-highlighter": "0.3.*", "nikic/php-parser": "~1.3|~2.0|~3.0", "php": ">=5.3.9", - "symfony/console": "~2.3.10|^2.4.2|~3.0", - "symfony/var-dumper": "~2.7|~3.0" + "symfony/console": "~2.3.10|^2.4.2|~3.0|~4.0", + "symfony/var-dumper": "~2.7|~3.0|~4.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~1.11", "hoa/console": "~3.16|~1.14", "phpunit/phpunit": "^4.8.35|^5.4.3", - "symfony/finder": "~2.1|~3.0" + "symfony/finder": "~2.1|~3.0|~4.0" }, "suggest": { "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", @@ -8043,7 +8103,7 @@ "interactive", "shell" ], - "time": "2017-11-16 14:29:51" + "time": "2017-12-28 16:14:16" }, { "name": "rackspace/php-opencloud", @@ -8104,16 +8164,16 @@ }, { "name": "ramsey/uuid", - "version": "3.7.1", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334" + "reference": "bba83ad77bb9deb6d3c352a7361b818e415b221d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/45cffe822057a09e05f7bd09ec5fb88eeecd2334", - "reference": "45cffe822057a09e05f7bd09ec5fb88eeecd2334", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/bba83ad77bb9deb6d3c352a7361b818e415b221d", + "reference": "bba83ad77bb9deb6d3c352a7361b818e415b221d", "shasum": "" }, "require": { @@ -8125,7 +8185,7 @@ }, "require-dev": { "apigen/apigen": "^4.1", - "codeception/aspect-mock": "^1.0 | ^2.0", + "codeception/aspect-mock": "^1.0 | ~2.0.0", "doctrine/annotations": "~1.2.0", "goaop/framework": "1.0.0-alpha.2 | ^1.0 | ^2.1", "ircmaxell/random-lib": "^1.1", @@ -8133,7 +8193,7 @@ "mockery/mockery": "^0.9.4", "moontoast/math": "^1.1", "php-mock/php-mock-phpunit": "^0.3|^1.1", - "phpunit/phpunit": "^4.7|>=5.0 <5.4", + "phpunit/phpunit": "^4.7|^5.0", "satooshi/php-coveralls": "^0.6.1", "squizlabs/php_codesniffer": "^2.3" }, @@ -8182,7 +8242,7 @@ "identifier", "uuid" ], - "time": "2017-09-22 20:46:04" + "time": "2018-01-13 22:22:03" }, { "name": "rize/uri-template", @@ -8234,12 +8294,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "f793fe6ff54acabd9bc9f76f4a9ad3c89a68c789" + "reference": "a54d4cf91890993ee599c446e2eb3dba3f9eae32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/f793fe6ff54acabd9bc9f76f4a9ad3c89a68c789", - "reference": "f793fe6ff54acabd9bc9f76f4a9ad3c89a68c789", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/a54d4cf91890993ee599c446e2eb3dba3f9eae32", + "reference": "a54d4cf91890993ee599c446e2eb3dba3f9eae32", "shasum": "" }, "conflict": { @@ -8272,6 +8332,7 @@ "firebase/php-jwt": "<2", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "gree/jose": "<=2.2", "gregwar/rst": "<1.0.3", "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", @@ -8289,7 +8350,7 @@ "oro/platform": ">=1.7,<1.7.4", "phpmailer/phpmailer": ">=5,<5.2.24", "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpxmlrpc/extras": "<6.0.1", + "phpxmlrpc/extras": "<0.6.1", "pusher/pusher-php-server": "<2.2.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", "shopware/shopware": "<5.2.25", @@ -8321,7 +8382,7 @@ "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", + "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3", "twig/twig": "<1.20", "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5", "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5", @@ -8370,7 +8431,121 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2017-11-24 16:44:41" + "time": "2018-01-13 18:31:46" + }, + { + "name": "sabre/uri", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/uri.git", + "reference": "a42126042c7dcb53e2978dadb6d22574d1359b4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/uri/zipball/a42126042c7dcb53e2978dadb6d22574d1359b4c", + "reference": "a42126042c7dcb53e2978dadb6d22574d1359b4c", + "shasum": "" + }, + "require": { + "php": ">=7" + }, + "require-dev": { + "phpunit/phpunit": "^6.0", + "sabre/cs": "~1.0.0" + }, + "type": "library", + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Sabre\\Uri\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "Functions for making sense out of URIs.", + "homepage": "http://sabre.io/uri/", + "keywords": [ + "rfc3986", + "uri", + "url" + ], + "time": "2017-02-20 20:02:35" + }, + { + "name": "sabre/xml", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/sabre-io/xml.git", + "reference": "59b20e5bbace9912607481634f97d05a776ffca7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sabre-io/xml/zipball/59b20e5bbace9912607481634f97d05a776ffca7", + "reference": "59b20e5bbace9912607481634f97d05a776ffca7", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "lib-libxml": ">=2.6.20", + "php": ">=5.5.5", + "sabre/uri": ">=1.0,<3.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*", + "sabre/cs": "~1.0.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Sabre\\Xml\\": "lib/" + }, + "files": [ + "lib/Deserializer/functions.php", + "lib/Serializer/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + }, + { + "name": "Markus Staab", + "email": "markus.staab@redaxo.de", + "role": "Developer" + } + ], + "description": "sabre/xml is an XML library that you may not hate.", + "homepage": "https://sabre.io/xml/", + "keywords": [ + "XMLReader", + "XMLWriter", + "dom", + "xml" + ], + "time": "2016-10-09 22:57:52" }, { "name": "setasign/fpdi", @@ -8583,16 +8758,16 @@ }, { "name": "symfony/class-loader", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/class-loader.git", - "reference": "e8d36a7b5568d232f5c3f8ef92665836b9f1e038" + "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/class-loader/zipball/e8d36a7b5568d232f5c3f8ef92665836b9f1e038", - "reference": "e8d36a7b5568d232f5c3f8ef92665836b9f1e038", + "url": "https://api.github.com/repos/symfony/class-loader/zipball/e63c12699822bb3b667e7216ba07fbcc3a3e203e", + "reference": "e63c12699822bb3b667e7216ba07fbcc3a3e203e", "shasum": "" }, "require": { @@ -8635,7 +8810,7 @@ ], "description": "Symfony ClassLoader Component", "homepage": "https://symfony.com", - "time": "2017-11-05 16:10:10" + "time": "2018-01-03 07:37:34" }, { "name": "symfony/config", @@ -8756,16 +8931,16 @@ }, { "name": "symfony/css-selector", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "7134b93e90ea7e7881fcb2da006d21b4c5f31908" + "reference": "e66394bc7610e69279bfdb3ab11b4fe65403f556" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/7134b93e90ea7e7881fcb2da006d21b4c5f31908", - "reference": "7134b93e90ea7e7881fcb2da006d21b4c5f31908", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/e66394bc7610e69279bfdb3ab11b4fe65403f556", + "reference": "e66394bc7610e69279bfdb3ab11b4fe65403f556", "shasum": "" }, "require": { @@ -8805,7 +8980,7 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "time": "2017-11-05 16:10:10" + "time": "2018-01-03 07:37:34" }, { "name": "symfony/debug", @@ -8929,16 +9104,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v2.8.31", + "version": "v2.8.33", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b59aacf238fadda50d612c9de73b74751872a903" + "reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b59aacf238fadda50d612c9de73b74751872a903", - "reference": "b59aacf238fadda50d612c9de73b74751872a903", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/d64be24fc1eba62f9daace8a8918f797fc8e87cc", + "reference": "d64be24fc1eba62f9daace8a8918f797fc8e87cc", "shasum": "" }, "require": { @@ -8985,20 +9160,20 @@ ], "description": "Symfony EventDispatcher Component", "homepage": "https://symfony.com", - "time": "2017-11-05 15:25:56" + "time": "2018-01-03 07:36:31" }, { "name": "symfony/filesystem", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "de56eee71e0a128d8c54ccc1909cdefd574bad0f" + "reference": "e078773ad6354af38169faf31c21df0f18ace03d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/de56eee71e0a128d8c54ccc1909cdefd574bad0f", - "reference": "de56eee71e0a128d8c54ccc1909cdefd574bad0f", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e078773ad6354af38169faf31c21df0f18ace03d", + "reference": "e078773ad6354af38169faf31c21df0f18ace03d", "shasum": "" }, "require": { @@ -9034,7 +9209,7 @@ ], "description": "Symfony Filesystem Component", "homepage": "https://symfony.com", - "time": "2017-11-19 18:59:05" + "time": "2018-01-03 07:37:34" }, { "name": "symfony/finder", @@ -9222,16 +9397,16 @@ }, { "name": "symfony/options-resolver", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "08748edfe6982f4d878cc42b8325b19a276fb1cf" + "reference": "f31f4d3ce4eaf7597abc41bd5ba53d634c2fdb0e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/08748edfe6982f4d878cc42b8325b19a276fb1cf", - "reference": "08748edfe6982f4d878cc42b8325b19a276fb1cf", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/f31f4d3ce4eaf7597abc41bd5ba53d634c2fdb0e", + "reference": "f31f4d3ce4eaf7597abc41bd5ba53d634c2fdb0e", "shasum": "" }, "require": { @@ -9272,7 +9447,7 @@ "configuration", "options" ], - "time": "2017-11-05 16:10:10" + "time": "2018-01-03 07:37:34" }, { "name": "symfony/polyfill-mbstring", @@ -9694,16 +9869,16 @@ }, { "name": "symfony/yaml", - "version": "v3.3.13", + "version": "v3.3.15", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "0938408c4faa518d95230deabb5f595bf0de31b9" + "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/0938408c4faa518d95230deabb5f595bf0de31b9", - "reference": "0938408c4faa518d95230deabb5f595bf0de31b9", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7c80d81b5805589be151b85b0df785f0dc3269cf", + "reference": "7c80d81b5805589be151b85b0df785f0dc3269cf", "shasum": "" }, "require": { @@ -9745,33 +9920,33 @@ ], "description": "Symfony Yaml Component", "homepage": "https://symfony.com", - "time": "2017-11-10 18:26:04" + "time": "2018-01-03 07:37:11" }, { "name": "tijsverkoyen/css-to-inline-styles", - "version": "2.2.0", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", - "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b" + "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b", - "reference": "ab03919dfd85a74ae0372f8baf9f3c7d5c03b04b", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", + "reference": "0ed4a2ea4e0902dac0489e6436ebcd5bbcae9757", "shasum": "" }, "require": { - "php": "^5.5 || ^7", - "symfony/css-selector": "^2.7|~3.0" + "php": "^5.5 || ^7.0", + "symfony/css-selector": "^2.7 || ^3.0 || ^4.0" }, "require-dev": { - "phpunit/phpunit": "~4.8|5.1.*" + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { @@ -9792,7 +9967,7 @@ ], "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", - "time": "2016-09-20 12:50:39" + "time": "2017-11-27 11:13:29" }, { "name": "true/punycode", @@ -11744,16 +11919,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.4.11", + "version": "1.4.12", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", - "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/1ce90ba27c42e4e44e6d8458241466380b51fa16", + "reference": "1ce90ba27c42e4e44e6d8458241466380b51fa16", "shasum": "" }, "require": { @@ -11789,7 +11964,7 @@ "keywords": [ "tokenizer" ], - "time": "2017-02-27 10:12:30" + "time": "2017-12-04 08:55:13" }, { "name": "phpunit/phpunit", @@ -12338,16 +12513,16 @@ }, { "name": "symfony/browser-kit", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "179522b5f0b5e6d00bb60f38a4d6b29962e4b61b" + "reference": "490f27762705c8489bd042fe3e9377a191dba9b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/179522b5f0b5e6d00bb60f38a4d6b29962e4b61b", - "reference": "179522b5f0b5e6d00bb60f38a4d6b29962e4b61b", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/490f27762705c8489bd042fe3e9377a191dba9b4", + "reference": "490f27762705c8489bd042fe3e9377a191dba9b4", "shasum": "" }, "require": { @@ -12391,20 +12566,20 @@ ], "description": "Symfony BrowserKit Component", "homepage": "https://symfony.com", - "time": "2017-11-07 14:20:24" + "time": "2018-01-03 07:37:34" }, { "name": "symfony/dom-crawler", - "version": "v3.4.0", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "7bf68716e400997a291ad42c9f9fe7972e6656d2" + "reference": "09bd97b844b3151fab82f2fdd62db9c464b3910a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/7bf68716e400997a291ad42c9f9fe7972e6656d2", - "reference": "7bf68716e400997a291ad42c9f9fe7972e6656d2", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/09bd97b844b3151fab82f2fdd62db9c464b3910a", + "reference": "09bd97b844b3151fab82f2fdd62db9c464b3910a", "shasum": "" }, "require": { @@ -12447,7 +12622,7 @@ ], "description": "Symfony DomCrawler Component", "homepage": "https://symfony.com", - "time": "2017-11-05 16:10:10" + "time": "2018-01-03 07:37:34" }, { "name": "webmozart/assert", diff --git a/database/migrations/2013_11_05_180133_confide_setup_users_table.php b/database/migrations/2013_11_05_180133_confide_setup_users_table.php index f89e00e2f737..00da547759de 100644 --- a/database/migrations/2013_11_05_180133_confide_setup_users_table.php +++ b/database/migrations/2013_11_05_180133_confide_setup_users_table.php @@ -338,7 +338,6 @@ class ConfideSetupUsersTable extends Migration $t->timestamp('viewed_date')->nullable(); $t->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); - ; $t->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); $t->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); diff --git a/database/migrations/2018_01_10_073825_add_subscription_format.php b/database/migrations/2018_01_10_073825_add_subscription_format.php new file mode 100644 index 000000000000..24afac17a5d2 --- /dev/null +++ b/database/migrations/2018_01_10_073825_add_subscription_format.php @@ -0,0 +1,193 @@ +enum('format', ['JSON', 'UBL'])->default('JSON'); + }); + + Schema::table('accounts', function ($table) { + $table->boolean('ubl_email_attachment')->default(false); + }); + + Schema::table('account_email_settings', function ($table) { + $table->string('email_subject_proposal')->nullable(); + $table->text('email_template_proposal')->nullable(); + }); + + Schema::table('documents', function ($table) { + $table->boolean('is_proposal')->default(false); + $table->string('document_key')->nullable()->unique(); + }); + + Schema::table('invoices', function ($table) { + $table->decimal('discount', 13, 2)->change(); + }); + + Schema::table('invoice_items', function ($table) { + $table->decimal('discount', 13, 2)->change(); + }); + + Schema::create('proposal_categories', function ($table) { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + $table->boolean('is_deleted')->default(false); + + $table->string('name'); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::create('proposal_snippets', function ($table) { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + $table->boolean('is_deleted')->default(false); + + $table->unsignedInteger('proposal_category_id')->nullable(); + $table->string('name'); + $table->string('icon'); + $table->text('private_notes'); + + $table->mediumText('html'); + $table->mediumText('css'); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::create('proposal_templates', function ($table) { + $table->increments('id'); + $table->unsignedInteger('account_id')->nullable(); + $table->unsignedInteger('user_id')->nullable(); + $table->timestamps(); + $table->softDeletes(); + $table->boolean('is_deleted')->default(false); + $table->text('private_notes'); + + $table->string('name'); + $table->mediumText('html'); + $table->mediumText('css'); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::create('proposals', function ($table) { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('user_id'); + $table->timestamps(); + $table->softDeletes(); + $table->boolean('is_deleted')->default(false); + + $table->unsignedInteger('invoice_id')->index(); + $table->unsignedInteger('proposal_template_id')->nullable()->index(); + $table->text('private_notes'); + $table->mediumText('html'); + $table->mediumText('css'); + + $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade'); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade'); + $table->foreign('proposal_template_id')->references('id')->on('proposal_templates')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::create('proposal_invitations', function ($table) { + $table->increments('id'); + $table->unsignedInteger('account_id'); + $table->unsignedInteger('user_id'); + $table->unsignedInteger('contact_id'); + $table->unsignedInteger('proposal_id')->index(); + $table->string('invitation_key')->index()->unique(); + $table->timestamps(); + $table->softDeletes(); + + $table->timestamp('sent_date')->nullable(); + $table->timestamp('viewed_date')->nullable(); + $table->timestamp('opened_date')->nullable(); + $table->string('message_id')->nullable(); + $table->text('email_error')->nullable(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade'); + $table->foreign('proposal_id')->references('id')->on('proposals')->onDelete('cascade'); + + $table->unsignedInteger('public_id')->index(); + $table->unique(['account_id', 'public_id']); + }); + + Schema::create('lookup_proposal_invitations', function ($table) { + $table->increments('id'); + $table->unsignedInteger('lookup_account_id')->index(); + $table->string('invitation_key')->unique(); + $table->string('message_id')->nullable()->unique(); + + $table->foreign('lookup_account_id')->references('id')->on('lookup_accounts')->onDelete('cascade'); + }); + + DB::table('languages')->where('locale', '=', 'en_UK')->update(['locale' => 'en_GB']); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('subscriptions', function ($table) { + $table->dropColumn('format'); + }); + + Schema::table('accounts', function ($table) { + $table->dropColumn('ubl_email_attachment'); + }); + + Schema::table('account_email_settings', function ($table) { + $table->dropColumn('email_subject_proposal'); + $table->dropColumn('email_template_proposal'); + }); + + Schema::table('documents', function ($table) { + $table->dropColumn('is_proposal'); + $table->dropColumn('document_key'); + }); + + Schema::dropIfExists('lookup_proposal_invitations'); + Schema::dropIfExists('proposal_invitations'); + Schema::dropIfExists('proposals'); + Schema::dropIfExists('proposal_templates'); + Schema::dropIfExists('proposal_snippets'); + Schema::dropIfExists('proposal_categories'); + } +} diff --git a/database/seeds/CurrenciesSeeder.php b/database/seeds/CurrenciesSeeder.php index f291084989ec..18416e6dfe88 100644 --- a/database/seeds/CurrenciesSeeder.php +++ b/database/seeds/CurrenciesSeeder.php @@ -79,6 +79,9 @@ class CurrenciesSeeder extends Seeder ['name' => 'Peruvian Sol', 'code' => 'PEN', 'symbol' => 'S/ ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Botswana Pula', 'code' => 'BWP', 'symbol' => 'P', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ['name' => 'Hungarian Forint', 'code' => 'HUF', 'symbol' => 'Ft', 'precision' => '0', 'thousand_separator' => '.', 'decimal_separator' => ',', 'swap_currency_symbol' => true], + ['name' => 'Ugandan Shilling', 'code' => 'UGX', 'symbol' => 'USh ', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Barbadian Dollar', 'code' => 'BBD', 'symbol' => '$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], + ['name' => 'Brunei Dollar', 'code' => 'BND', 'symbol' => 'B$', 'precision' => '2', 'thousand_separator' => ',', 'decimal_separator' => '.'], ]; foreach ($currencies as $currency) { diff --git a/database/seeds/DatabaseSeeder.php b/database/seeds/DatabaseSeeder.php index 9ed4573353c0..2849d63436b1 100644 --- a/database/seeds/DatabaseSeeder.php +++ b/database/seeds/DatabaseSeeder.php @@ -27,6 +27,7 @@ class DatabaseSeeder extends Seeder $this->call('GatewayTypesSeeder'); $this->call('BanksSeeder'); $this->call('InvoiceStatusSeeder'); + $this->call('ProposalTemplatesSeeder'); $this->call('PaymentStatusSeeder'); $this->call('CurrenciesSeeder'); $this->call('DateFormatsSeeder'); diff --git a/database/seeds/LanguageSeeder.php b/database/seeds/LanguageSeeder.php index 955b75a9ea1f..0fa5e8c4d27d 100644 --- a/database/seeds/LanguageSeeder.php +++ b/database/seeds/LanguageSeeder.php @@ -31,7 +31,7 @@ class LanguageSeeder extends Seeder ['name' => 'Croatian', 'locale' => 'hr'], ['name' => 'Albanian', 'locale' => 'sq'], ['name' => 'Greek', 'locale' => 'el'], - ['name' => 'English - United Kingdom', 'locale' => 'en_UK'], + ['name' => 'English - United Kingdom', 'locale' => 'en_GB'], ['name' => 'Portuguese - Portugal', 'locale' => 'pt_PT'], ['name' => 'Slovenian', 'locale' => 'sl'], ['name' => 'Finnish', 'locale' => 'fi'], diff --git a/database/seeds/ProposalTemplatesSeeder.php b/database/seeds/ProposalTemplatesSeeder.php new file mode 100644 index 000000000000..f8e6eddbae29 --- /dev/null +++ b/database/seeds/ProposalTemplatesSeeder.php @@ -0,0 +1,44 @@ +whereNull('account_id')->first(); + + if (! $template) { + $template = new ProposalTemplate(); + $template->public_id = $i + 1; + $template->name = $design; + } + + $template->html = file_get_contents($htmlFileName); + $template->css = file_get_contents($cssFileName); + $template->save(); + } + } + } +} diff --git a/database/seeds/UpdateSeeder.php b/database/seeds/UpdateSeeder.php index 77d617603a33..6021f7f37a2b 100644 --- a/database/seeds/UpdateSeeder.php +++ b/database/seeds/UpdateSeeder.php @@ -21,6 +21,7 @@ class UpdateSeeder extends Seeder $this->call('CurrenciesSeeder'); $this->call('DateFormatsSeeder'); $this->call('InvoiceDesignsSeeder'); + $this->call('ProposalTemplatesSeeder'); $this->call('PaymentTermsSeeder'); $this->call('PaymentTypesSeeder'); $this->call('LanguageSeeder'); diff --git a/database/setup.sql b/database/setup.sql index 40b86abf294e..eecd25323af5 100644 --- a/database/setup.sql +++ b/database/setup.sql @@ -1,8 +1,8 @@ --- MySQL dump 10.13 Distrib 5.7.20, for Linux (x86_64) +-- MySQL dump 10.13 Distrib 5.7.21, for Linux (x86_64) -- -- Host: localhost Database: ninja -- ------------------------------------------------------ --- Server version 5.7.20-0ubuntu0.16.04.1 +-- Server version 5.7.21-0ubuntu0.16.04.1 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; @@ -19,7 +19,6 @@ -- Table structure for table `account_email_settings` -- -DROP TABLE IF EXISTS `account_email_settings`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `account_email_settings` ( @@ -50,6 +49,8 @@ CREATE TABLE `account_email_settings` ( `email_subject_reminder4` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `email_template_reminder4` text COLLATE utf8_unicode_ci, `frequency_id_reminder4` int(10) unsigned DEFAULT NULL, + `email_subject_proposal` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + `email_template_proposal` text COLLATE utf8_unicode_ci, 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 @@ -69,7 +70,6 @@ UNLOCK TABLES; -- Table structure for table `account_gateway_settings` -- -DROP TABLE IF EXISTS `account_gateway_settings`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `account_gateway_settings` ( @@ -109,7 +109,6 @@ UNLOCK TABLES; -- Table structure for table `account_gateway_tokens` -- -DROP TABLE IF EXISTS `account_gateway_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `account_gateway_tokens` ( @@ -150,7 +149,6 @@ UNLOCK TABLES; -- Table structure for table `account_gateways` -- -DROP TABLE IF EXISTS `account_gateways`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `account_gateways` ( @@ -192,7 +190,6 @@ UNLOCK TABLES; -- Table structure for table `account_tokens` -- -DROP TABLE IF EXISTS `account_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `account_tokens` ( @@ -228,7 +225,6 @@ UNLOCK TABLES; -- Table structure for table `accounts` -- -DROP TABLE IF EXISTS `accounts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `accounts` ( @@ -379,6 +375,7 @@ CREATE TABLE `accounts` ( `convert_products` tinyint(1) NOT NULL DEFAULT '0', `enable_reminder4` tinyint(1) NOT NULL DEFAULT '0', `signature_on_pdf` tinyint(1) NOT NULL DEFAULT '0', + `ubl_email_attachment` tinyint(1) NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `accounts_account_key_unique` (`account_key`), KEY `accounts_timezone_id_foreign` (`timezone_id`), @@ -417,7 +414,6 @@ UNLOCK TABLES; -- Table structure for table `activities` -- -DROP TABLE IF EXISTS `activities`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `activities` ( @@ -462,7 +458,6 @@ UNLOCK TABLES; -- Table structure for table `affiliates` -- -DROP TABLE IF EXISTS `affiliates`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `affiliates` ( @@ -493,7 +488,6 @@ UNLOCK TABLES; -- Table structure for table `bank_accounts` -- -DROP TABLE IF EXISTS `bank_accounts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `bank_accounts` ( @@ -532,7 +526,6 @@ UNLOCK TABLES; -- Table structure for table `bank_subaccounts` -- -DROP TABLE IF EXISTS `bank_subaccounts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `bank_subaccounts` ( @@ -570,7 +563,6 @@ UNLOCK TABLES; -- Table structure for table `banks` -- -DROP TABLE IF EXISTS `banks`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `banks` ( @@ -597,7 +589,6 @@ UNLOCK TABLES; -- Table structure for table `clients` -- -DROP TABLE IF EXISTS `clients`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `clients` ( @@ -679,7 +670,6 @@ UNLOCK TABLES; -- Table structure for table `companies` -- -DROP TABLE IF EXISTS `companies`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `companies` ( @@ -730,7 +720,6 @@ UNLOCK TABLES; -- Table structure for table `contacts` -- -DROP TABLE IF EXISTS `contacts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `contacts` ( @@ -779,7 +768,6 @@ UNLOCK TABLES; -- Table structure for table `countries` -- -DROP TABLE IF EXISTS `countries`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `countries` ( @@ -819,7 +807,6 @@ UNLOCK TABLES; -- Table structure for table `credits` -- -DROP TABLE IF EXISTS `credits`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `credits` ( @@ -863,7 +850,6 @@ UNLOCK TABLES; -- Table structure for table `currencies` -- -DROP TABLE IF EXISTS `currencies`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `currencies` ( @@ -877,7 +863,7 @@ CREATE TABLE `currencies` ( `swap_currency_symbol` tinyint(1) NOT NULL DEFAULT '0', `exchange_rate` decimal(13,4) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=70 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=InnoDB AUTO_INCREMENT=73 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -886,7 +872,7 @@ CREATE TABLE `currencies` ( LOCK TABLES `currencies` WRITE; /*!40000 ALTER TABLE `currencies` DISABLE KEYS */; -INSERT INTO `currencies` VALUES (1,'US Dollar','$','2',',','.','USD',0,NULL),(2,'British Pound','£','2',',','.','GBP',0,NULL),(3,'Euro','€','2','.',',','EUR',0,NULL),(4,'South African Rand','R','2','.',',','ZAR',0,NULL),(5,'Danish Krone','kr','2','.',',','DKK',1,NULL),(6,'Israeli Shekel','NIS ','2',',','.','ILS',0,NULL),(7,'Swedish Krona','kr','2','.',',','SEK',1,NULL),(8,'Kenyan Shilling','KSh ','2',',','.','KES',0,NULL),(9,'Canadian Dollar','C$','2',',','.','CAD',0,NULL),(10,'Philippine Peso','P ','2',',','.','PHP',0,NULL),(11,'Indian Rupee','Rs. ','2',',','.','INR',0,NULL),(12,'Australian Dollar','$','2',',','.','AUD',0,NULL),(13,'Singapore Dollar','','2',',','.','SGD',0,NULL),(14,'Norske Kroner','kr','2','.',',','NOK',1,NULL),(15,'New Zealand Dollar','$','2',',','.','NZD',0,NULL),(16,'Vietnamese Dong','','0','.',',','VND',0,NULL),(17,'Swiss Franc','','2','\'','.','CHF',0,NULL),(18,'Guatemalan Quetzal','Q','2',',','.','GTQ',0,NULL),(19,'Malaysian Ringgit','RM','2',',','.','MYR',0,NULL),(20,'Brazilian Real','R$','2','.',',','BRL',0,NULL),(21,'Thai Baht','','2',',','.','THB',0,NULL),(22,'Nigerian Naira','','2',',','.','NGN',0,NULL),(23,'Argentine Peso','$','2','.',',','ARS',0,NULL),(24,'Bangladeshi Taka','Tk','2',',','.','BDT',0,NULL),(25,'United Arab Emirates Dirham','DH ','2',',','.','AED',0,NULL),(26,'Hong Kong Dollar','','2',',','.','HKD',0,NULL),(27,'Indonesian Rupiah','Rp','2',',','.','IDR',0,NULL),(28,'Mexican Peso','$','2',',','.','MXN',0,NULL),(29,'Egyptian Pound','E£','2',',','.','EGP',0,NULL),(30,'Colombian Peso','$','2','.',',','COP',0,NULL),(31,'West African Franc','CFA ','2',',','.','XOF',0,NULL),(32,'Chinese Renminbi','RMB ','2',',','.','CNY',0,NULL),(33,'Rwandan Franc','RF ','2',',','.','RWF',0,NULL),(34,'Tanzanian Shilling','TSh ','2',',','.','TZS',0,NULL),(35,'Netherlands Antillean Guilder','','2','.',',','ANG',0,NULL),(36,'Trinidad and Tobago Dollar','TT$','2',',','.','TTD',0,NULL),(37,'East Caribbean Dollar','EC$','2',',','.','XCD',0,NULL),(38,'Ghanaian Cedi','','2',',','.','GHS',0,NULL),(39,'Bulgarian Lev','','2',' ','.','BGN',0,NULL),(40,'Aruban Florin','Afl. ','2',' ','.','AWG',0,NULL),(41,'Turkish Lira','TL ','2','.',',','TRY',0,NULL),(42,'Romanian New Leu','','2',',','.','RON',0,NULL),(43,'Croatian Kuna','kn','2','.',',','HRK',0,NULL),(44,'Saudi Riyal','','2',',','.','SAR',0,NULL),(45,'Japanese Yen','¥','0',',','.','JPY',0,NULL),(46,'Maldivian Rufiyaa','','2',',','.','MVR',0,NULL),(47,'Costa Rican Colón','','2',',','.','CRC',0,NULL),(48,'Pakistani Rupee','Rs ','0',',','.','PKR',0,NULL),(49,'Polish Zloty','zł','2',' ',',','PLN',1,NULL),(50,'Sri Lankan Rupee','LKR','2',',','.','LKR',1,NULL),(51,'Czech Koruna','Kč','2',' ',',','CZK',1,NULL),(52,'Uruguayan Peso','$','2','.',',','UYU',0,NULL),(53,'Namibian Dollar','$','2',',','.','NAD',0,NULL),(54,'Tunisian Dinar','','2',',','.','TND',0,NULL),(55,'Russian Ruble','','2',',','.','RUB',0,NULL),(56,'Mozambican Metical','MT','2','.',',','MZN',1,NULL),(57,'Omani Rial','','2',',','.','OMR',0,NULL),(58,'Ukrainian Hryvnia','','2',',','.','UAH',0,NULL),(59,'Macanese Pataca','MOP$','2',',','.','MOP',0,NULL),(60,'Taiwan New Dollar','NT$','2',',','.','TWD',0,NULL),(61,'Dominican Peso','RD$','2',',','.','DOP',0,NULL),(62,'Chilean Peso','$','0','.',',','CLP',0,NULL),(63,'Icelandic Króna','kr','2','.',',','ISK',1,NULL),(64,'Papua New Guinean Kina','K','2',',','.','PGK',0,NULL),(65,'Jordanian Dinar','','2',',','.','JOD',0,NULL),(66,'Myanmar Kyat','K','2',',','.','MMK',0,NULL),(67,'Peruvian Sol','S/ ','2',',','.','PEN',0,NULL),(68,'Botswana Pula','P','2',',','.','BWP',0,NULL),(69,'Hungarian Forint','Ft','0','.',',','HUF',1,NULL); +INSERT INTO `currencies` VALUES (1,'US Dollar','$','2',',','.','USD',0,NULL),(2,'British Pound','£','2',',','.','GBP',0,NULL),(3,'Euro','€','2','.',',','EUR',0,NULL),(4,'South African Rand','R','2','.',',','ZAR',0,NULL),(5,'Danish Krone','kr','2','.',',','DKK',1,NULL),(6,'Israeli Shekel','NIS ','2',',','.','ILS',0,NULL),(7,'Swedish Krona','kr','2','.',',','SEK',1,NULL),(8,'Kenyan Shilling','KSh ','2',',','.','KES',0,NULL),(9,'Canadian Dollar','C$','2',',','.','CAD',0,NULL),(10,'Philippine Peso','P ','2',',','.','PHP',0,NULL),(11,'Indian Rupee','Rs. ','2',',','.','INR',0,NULL),(12,'Australian Dollar','$','2',',','.','AUD',0,NULL),(13,'Singapore Dollar','','2',',','.','SGD',0,NULL),(14,'Norske Kroner','kr','2','.',',','NOK',1,NULL),(15,'New Zealand Dollar','$','2',',','.','NZD',0,NULL),(16,'Vietnamese Dong','','0','.',',','VND',0,NULL),(17,'Swiss Franc','','2','\'','.','CHF',0,NULL),(18,'Guatemalan Quetzal','Q','2',',','.','GTQ',0,NULL),(19,'Malaysian Ringgit','RM','2',',','.','MYR',0,NULL),(20,'Brazilian Real','R$','2','.',',','BRL',0,NULL),(21,'Thai Baht','','2',',','.','THB',0,NULL),(22,'Nigerian Naira','','2',',','.','NGN',0,NULL),(23,'Argentine Peso','$','2','.',',','ARS',0,NULL),(24,'Bangladeshi Taka','Tk','2',',','.','BDT',0,NULL),(25,'United Arab Emirates Dirham','DH ','2',',','.','AED',0,NULL),(26,'Hong Kong Dollar','','2',',','.','HKD',0,NULL),(27,'Indonesian Rupiah','Rp','2',',','.','IDR',0,NULL),(28,'Mexican Peso','$','2',',','.','MXN',0,NULL),(29,'Egyptian Pound','E£','2',',','.','EGP',0,NULL),(30,'Colombian Peso','$','2','.',',','COP',0,NULL),(31,'West African Franc','CFA ','2',',','.','XOF',0,NULL),(32,'Chinese Renminbi','RMB ','2',',','.','CNY',0,NULL),(33,'Rwandan Franc','RF ','2',',','.','RWF',0,NULL),(34,'Tanzanian Shilling','TSh ','2',',','.','TZS',0,NULL),(35,'Netherlands Antillean Guilder','','2','.',',','ANG',0,NULL),(36,'Trinidad and Tobago Dollar','TT$','2',',','.','TTD',0,NULL),(37,'East Caribbean Dollar','EC$','2',',','.','XCD',0,NULL),(38,'Ghanaian Cedi','','2',',','.','GHS',0,NULL),(39,'Bulgarian Lev','','2',' ','.','BGN',0,NULL),(40,'Aruban Florin','Afl. ','2',' ','.','AWG',0,NULL),(41,'Turkish Lira','TL ','2','.',',','TRY',0,NULL),(42,'Romanian New Leu','','2',',','.','RON',0,NULL),(43,'Croatian Kuna','kn','2','.',',','HRK',0,NULL),(44,'Saudi Riyal','','2',',','.','SAR',0,NULL),(45,'Japanese Yen','¥','0',',','.','JPY',0,NULL),(46,'Maldivian Rufiyaa','','2',',','.','MVR',0,NULL),(47,'Costa Rican Colón','','2',',','.','CRC',0,NULL),(48,'Pakistani Rupee','Rs ','0',',','.','PKR',0,NULL),(49,'Polish Zloty','zł','2',' ',',','PLN',1,NULL),(50,'Sri Lankan Rupee','LKR','2',',','.','LKR',1,NULL),(51,'Czech Koruna','Kč','2',' ',',','CZK',1,NULL),(52,'Uruguayan Peso','$','2','.',',','UYU',0,NULL),(53,'Namibian Dollar','$','2',',','.','NAD',0,NULL),(54,'Tunisian Dinar','','2',',','.','TND',0,NULL),(55,'Russian Ruble','','2',',','.','RUB',0,NULL),(56,'Mozambican Metical','MT','2','.',',','MZN',1,NULL),(57,'Omani Rial','','2',',','.','OMR',0,NULL),(58,'Ukrainian Hryvnia','','2',',','.','UAH',0,NULL),(59,'Macanese Pataca','MOP$','2',',','.','MOP',0,NULL),(60,'Taiwan New Dollar','NT$','2',',','.','TWD',0,NULL),(61,'Dominican Peso','RD$','2',',','.','DOP',0,NULL),(62,'Chilean Peso','$','0','.',',','CLP',0,NULL),(63,'Icelandic Króna','kr','2','.',',','ISK',1,NULL),(64,'Papua New Guinean Kina','K','2',',','.','PGK',0,NULL),(65,'Jordanian Dinar','','2',',','.','JOD',0,NULL),(66,'Myanmar Kyat','K','2',',','.','MMK',0,NULL),(67,'Peruvian Sol','S/ ','2',',','.','PEN',0,NULL),(68,'Botswana Pula','P','2',',','.','BWP',0,NULL),(69,'Hungarian Forint','Ft','0','.',',','HUF',1,NULL),(70,'Ugandan Shilling','USh ','2',',','.','UGX',0,NULL),(71,'Barbadian Dollar','$','2',',','.','BBD',0,NULL),(72,'Brunei Dollar','B$','2',',','.','BND',0,NULL); /*!40000 ALTER TABLE `currencies` ENABLE KEYS */; UNLOCK TABLES; @@ -894,7 +880,6 @@ UNLOCK TABLES; -- Table structure for table `date_formats` -- -DROP TABLE IF EXISTS `date_formats`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `date_formats` ( @@ -920,7 +905,6 @@ UNLOCK TABLES; -- Table structure for table `datetime_formats` -- -DROP TABLE IF EXISTS `datetime_formats`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `datetime_formats` ( @@ -945,7 +929,6 @@ UNLOCK TABLES; -- Table structure for table `db_servers` -- -DROP TABLE IF EXISTS `db_servers`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `db_servers` ( @@ -969,7 +952,6 @@ UNLOCK TABLES; -- Table structure for table `documents` -- -DROP TABLE IF EXISTS `documents`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `documents` ( @@ -991,8 +973,11 @@ CREATE TABLE `documents` ( `created_at` timestamp NULL DEFAULT NULL, `updated_at` timestamp NULL DEFAULT NULL, `is_default` tinyint(1) DEFAULT '0', + `is_proposal` tinyint(1) NOT NULL DEFAULT '0', + `document_key` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `documents_account_id_public_id_unique` (`account_id`,`public_id`), + UNIQUE KEY `documents_document_key_unique` (`document_key`), KEY `documents_user_id_foreign` (`user_id`), KEY `documents_invoice_id_foreign` (`invoice_id`), KEY `documents_expense_id_foreign` (`expense_id`), @@ -1016,7 +1001,6 @@ UNLOCK TABLES; -- Table structure for table `expense_categories` -- -DROP TABLE IF EXISTS `expense_categories`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `expense_categories` ( @@ -1052,7 +1036,6 @@ UNLOCK TABLES; -- Table structure for table `expenses` -- -DROP TABLE IF EXISTS `expenses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `expenses` ( @@ -1118,7 +1101,6 @@ UNLOCK TABLES; -- Table structure for table `failed_jobs` -- -DROP TABLE IF EXISTS `failed_jobs`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `failed_jobs` ( @@ -1144,7 +1126,6 @@ UNLOCK TABLES; -- Table structure for table `fonts` -- -DROP TABLE IF EXISTS `fonts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `fonts` ( @@ -1177,7 +1158,6 @@ UNLOCK TABLES; -- Table structure for table `frequencies` -- -DROP TABLE IF EXISTS `frequencies`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `frequencies` ( @@ -1202,7 +1182,6 @@ UNLOCK TABLES; -- Table structure for table `gateway_types` -- -DROP TABLE IF EXISTS `gateway_types`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `gateway_types` ( @@ -1227,7 +1206,6 @@ UNLOCK TABLES; -- Table structure for table `gateways` -- -DROP TABLE IF EXISTS `gateways`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `gateways` ( @@ -1255,7 +1233,7 @@ CREATE TABLE `gateways` ( LOCK TABLES `gateways` WRITE; /*!40000 ALTER TABLE `gateways` DISABLE KEYS */; -INSERT INTO `gateways` VALUES (1,'2018-01-08 16:45:21','2018-01-08 16:45:21','Authorize.Net AIM','AuthorizeNet_AIM',1,1,5,0,NULL,0,0),(2,'2018-01-08 16:45:21','2018-01-08 16:45:21','Authorize.Net SIM','AuthorizeNet_SIM',1,2,10000,0,NULL,0,0),(3,'2018-01-08 16:45:21','2018-01-08 16:45:21','CardSave','CardSave',1,1,10000,0,NULL,0,0),(4,'2018-01-08 16:45:21','2018-01-08 16:45:21','Eway Rapid','Eway_RapidShared',1,1,10000,0,NULL,1,0),(5,'2018-01-08 16:45:21','2018-01-08 16:45:21','FirstData Connect','FirstData_Connect',1,1,10000,0,NULL,0,0),(6,'2018-01-08 16:45:21','2018-01-08 16:45:21','GoCardless','GoCardless',1,2,10000,0,NULL,1,0),(7,'2018-01-08 16:45:21','2018-01-08 16:45:21','Migs ThreeParty','Migs_ThreeParty',1,1,10000,0,NULL,0,0),(8,'2018-01-08 16:45:21','2018-01-08 16:45:21','Migs TwoParty','Migs_TwoParty',1,1,10000,0,NULL,0,0),(9,'2018-01-08 16:45:21','2018-01-08 16:45:21','Mollie','Mollie',1,1,8,0,NULL,1,0),(10,'2018-01-08 16:45:21','2018-01-08 16:45:21','MultiSafepay','MultiSafepay',1,1,10000,0,NULL,0,0),(11,'2018-01-08 16:45:21','2018-01-08 16:45:21','Netaxept','Netaxept',1,1,10000,0,NULL,0,0),(12,'2018-01-08 16:45:21','2018-01-08 16:45:21','NetBanx','NetBanx',1,1,10000,0,NULL,0,0),(13,'2018-01-08 16:45:21','2018-01-08 16:45:21','PayFast','PayFast',1,1,10000,0,NULL,1,0),(14,'2018-01-08 16:45:21','2018-01-08 16:45:21','Payflow Pro','Payflow_Pro',1,1,10000,0,NULL,0,0),(15,'2018-01-08 16:45:21','2018-01-08 16:45:21','PaymentExpress PxPay','PaymentExpress_PxPay',1,1,10000,0,NULL,0,0),(16,'2018-01-08 16:45:21','2018-01-08 16:45:21','PaymentExpress PxPost','PaymentExpress_PxPost',1,1,10000,0,NULL,0,0),(17,'2018-01-08 16:45:21','2018-01-08 16:45:21','PayPal Express','PayPal_Express',1,1,4,0,NULL,1,0),(18,'2018-01-08 16:45:21','2018-01-08 16:45:21','PayPal Pro','PayPal_Pro',1,1,10000,0,NULL,0,0),(19,'2018-01-08 16:45:21','2018-01-08 16:45:21','Pin','Pin',1,1,10000,0,NULL,0,0),(20,'2018-01-08 16:45:21','2018-01-08 16:45:21','SagePay Direct','SagePay_Direct',1,1,10000,0,NULL,0,0),(21,'2018-01-08 16:45:21','2018-01-08 16:45:21','SagePay Server','SagePay_Server',1,1,10000,0,NULL,0,0),(22,'2018-01-08 16:45:21','2018-01-08 16:45:21','SecurePay DirectPost','SecurePay_DirectPost',1,1,10000,0,NULL,0,0),(23,'2018-01-08 16:45:21','2018-01-08 16:45:21','Stripe','Stripe',1,1,1,0,NULL,0,0),(24,'2018-01-08 16:45:21','2018-01-08 16:45:21','TargetPay Direct eBanking','TargetPay_Directebanking',1,1,10000,0,NULL,0,0),(25,'2018-01-08 16:45:21','2018-01-08 16:45:21','TargetPay Ideal','TargetPay_Ideal',1,1,10000,0,NULL,0,0),(26,'2018-01-08 16:45:21','2018-01-08 16:45:21','TargetPay Mr Cash','TargetPay_Mrcash',1,1,10000,0,NULL,0,0),(27,'2018-01-08 16:45:21','2018-01-08 16:45:21','TwoCheckout','TwoCheckout',1,1,10000,0,NULL,1,0),(28,'2018-01-08 16:45:21','2018-01-08 16:45:21','WorldPay','WorldPay',1,1,10000,0,NULL,0,0),(29,'2018-01-08 16:45:21','2018-01-08 16:45:21','BeanStream','BeanStream',1,2,10000,0,NULL,0,0),(30,'2018-01-08 16:45:21','2018-01-08 16:45:21','Psigate','Psigate',1,2,10000,0,NULL,0,0),(31,'2018-01-08 16:45:21','2018-01-08 16:45:21','moolah','AuthorizeNet_AIM',1,1,10000,0,NULL,0,0),(32,'2018-01-08 16:45:21','2018-01-08 16:45:21','Alipay','Alipay_Express',1,1,10000,0,NULL,0,0),(33,'2018-01-08 16:45:21','2018-01-08 16:45:21','Buckaroo','Buckaroo_CreditCard',1,1,10000,0,NULL,0,0),(34,'2018-01-08 16:45:21','2018-01-08 16:45:21','Coinbase','Coinbase',1,1,10000,0,NULL,0,0),(35,'2018-01-08 16:45:21','2018-01-08 16:45:21','DataCash','DataCash',1,1,10000,0,NULL,0,0),(36,'2018-01-08 16:45:21','2018-01-08 16:45:21','Neteller','Neteller',1,2,10000,0,NULL,0,0),(37,'2018-01-08 16:45:21','2018-01-08 16:45:21','Pacnet','Pacnet',1,1,10000,0,NULL,0,0),(38,'2018-01-08 16:45:21','2018-01-08 16:45:21','PaymentSense','PaymentSense',1,2,10000,0,NULL,0,0),(39,'2018-01-08 16:45:21','2018-01-08 16:45:21','Realex','Realex_Remote',1,1,10000,0,NULL,0,0),(40,'2018-01-08 16:45:21','2018-01-08 16:45:21','Sisow','Sisow',1,1,10000,0,NULL,0,0),(41,'2018-01-08 16:45:21','2018-01-08 16:45:21','Skrill','Skrill',1,1,10000,0,NULL,1,0),(42,'2018-01-08 16:45:21','2018-01-08 16:45:21','BitPay','BitPay',1,1,7,0,NULL,1,0),(43,'2018-01-08 16:45:21','2018-01-08 16:45:21','Dwolla','Dwolla',1,1,6,0,NULL,1,0),(44,'2018-01-08 16:45:21','2018-01-08 16:45:21','AGMS','Agms',1,1,10000,0,NULL,0,0),(45,'2018-01-08 16:45:21','2018-01-08 16:45:21','Barclays','BarclaysEpdq\\Essential',1,1,10000,0,NULL,0,0),(46,'2018-01-08 16:45:21','2018-01-08 16:45:21','Cardgate','Cardgate',1,1,10000,0,NULL,0,0),(47,'2018-01-08 16:45:21','2018-01-08 16:45:21','Checkout.com','CheckoutCom',1,1,10000,0,NULL,0,0),(48,'2018-01-08 16:45:21','2018-01-08 16:45:21','Creditcall','Creditcall',1,1,10000,0,NULL,0,0),(49,'2018-01-08 16:45:21','2018-01-08 16:45:21','Cybersource','Cybersource',1,1,10000,0,NULL,0,0),(50,'2018-01-08 16:45:21','2018-01-08 16:45:21','ecoPayz','Ecopayz',1,1,10000,0,NULL,0,0),(51,'2018-01-08 16:45:21','2018-01-08 16:45:21','Fasapay','Fasapay',1,1,10000,0,NULL,0,0),(52,'2018-01-08 16:45:21','2018-01-08 16:45:21','Komoju','Komoju',1,1,10000,0,NULL,0,0),(53,'2018-01-08 16:45:21','2018-01-08 16:45:21','Multicards','Multicards',1,1,10000,0,NULL,0,0),(54,'2018-01-08 16:45:21','2018-01-08 16:45:21','Pagar.Me','Pagarme',1,2,10000,0,NULL,0,0),(55,'2018-01-08 16:45:21','2018-01-08 16:45:21','Paysafecard','Paysafecard',1,1,10000,0,NULL,0,0),(56,'2018-01-08 16:45:21','2018-01-08 16:45:21','Paytrace','Paytrace_CreditCard',1,1,10000,0,NULL,0,0),(57,'2018-01-08 16:45:21','2018-01-08 16:45:21','Secure Trading','SecureTrading',1,1,10000,0,NULL,0,0),(58,'2018-01-08 16:45:21','2018-01-08 16:45:21','SecPay','SecPay',1,1,10000,0,NULL,0,0),(59,'2018-01-08 16:45:21','2018-01-08 16:45:21','WeChat Express','WeChat_Express',1,2,10000,0,NULL,0,0),(60,'2018-01-08 16:45:21','2018-01-08 16:45:21','WePay','WePay',1,1,3,0,NULL,0,0),(61,'2018-01-08 16:45:21','2018-01-08 16:45:21','Braintree','Braintree',1,1,3,0,NULL,0,0),(62,'2018-01-08 16:45:21','2018-01-08 16:45:21','Custom','Custom',1,1,20,0,NULL,1,0),(63,'2018-01-08 16:45:21','2018-01-08 16:45:21','FirstData Payeezy','FirstData_Payeezy',1,1,10000,0,NULL,0,0),(64,'2018-01-08 16:45:21','2018-01-08 16:45:21','GoCardless','GoCardlessV2\\Redirect',1,1,9,0,NULL,1,0),(65,'2018-01-08 16:45:21','2018-01-08 16:45:21','PagSeguro','PagSeguro',1,1,10000,0,NULL,0,0); +INSERT INTO `gateways` VALUES (1,'2018-02-21 16:58:00','2018-02-21 16:58:00','Authorize.Net AIM','AuthorizeNet_AIM',1,1,5,0,NULL,0,0),(2,'2018-02-21 16:58:00','2018-02-21 16:58:00','Authorize.Net SIM','AuthorizeNet_SIM',1,2,10000,0,NULL,0,0),(3,'2018-02-21 16:58:00','2018-02-21 16:58:00','CardSave','CardSave',1,1,10000,0,NULL,0,0),(4,'2018-02-21 16:58:00','2018-02-21 16:58:00','Eway Rapid','Eway_RapidShared',1,1,10000,0,NULL,1,0),(5,'2018-02-21 16:58:00','2018-02-21 16:58:00','FirstData Connect','FirstData_Connect',1,1,10000,0,NULL,0,0),(6,'2018-02-21 16:58:00','2018-02-21 16:58:00','GoCardless','GoCardless',1,2,10000,0,NULL,1,0),(7,'2018-02-21 16:58:00','2018-02-21 16:58:00','Migs ThreeParty','Migs_ThreeParty',1,1,10000,0,NULL,0,0),(8,'2018-02-21 16:58:00','2018-02-21 16:58:00','Migs TwoParty','Migs_TwoParty',1,1,10000,0,NULL,0,0),(9,'2018-02-21 16:58:00','2018-02-21 16:58:00','Mollie','Mollie',1,1,8,0,NULL,1,0),(10,'2018-02-21 16:58:00','2018-02-21 16:58:00','MultiSafepay','MultiSafepay',1,1,10000,0,NULL,0,0),(11,'2018-02-21 16:58:00','2018-02-21 16:58:00','Netaxept','Netaxept',1,1,10000,0,NULL,0,0),(12,'2018-02-21 16:58:00','2018-02-21 16:58:00','NetBanx','NetBanx',1,1,10000,0,NULL,0,0),(13,'2018-02-21 16:58:00','2018-02-21 16:58:00','PayFast','PayFast',1,1,10000,0,NULL,1,0),(14,'2018-02-21 16:58:00','2018-02-21 16:58:00','Payflow Pro','Payflow_Pro',1,1,10000,0,NULL,0,0),(15,'2018-02-21 16:58:00','2018-02-21 16:58:00','PaymentExpress PxPay','PaymentExpress_PxPay',1,1,10000,0,NULL,0,0),(16,'2018-02-21 16:58:00','2018-02-21 16:58:00','PaymentExpress PxPost','PaymentExpress_PxPost',1,1,10000,0,NULL,0,0),(17,'2018-02-21 16:58:00','2018-02-21 16:58:00','PayPal Express','PayPal_Express',1,1,4,0,NULL,1,0),(18,'2018-02-21 16:58:00','2018-02-21 16:58:00','PayPal Pro','PayPal_Pro',1,1,10000,0,NULL,0,0),(19,'2018-02-21 16:58:00','2018-02-21 16:58:00','Pin','Pin',1,1,10000,0,NULL,0,0),(20,'2018-02-21 16:58:00','2018-02-21 16:58:00','SagePay Direct','SagePay_Direct',1,1,10000,0,NULL,0,0),(21,'2018-02-21 16:58:00','2018-02-21 16:58:00','SagePay Server','SagePay_Server',1,1,10000,0,NULL,0,0),(22,'2018-02-21 16:58:00','2018-02-21 16:58:00','SecurePay DirectPost','SecurePay_DirectPost',1,1,10000,0,NULL,0,0),(23,'2018-02-21 16:58:00','2018-02-21 16:58:00','Stripe','Stripe',1,1,1,0,NULL,0,0),(24,'2018-02-21 16:58:00','2018-02-21 16:58:00','TargetPay Direct eBanking','TargetPay_Directebanking',1,1,10000,0,NULL,0,0),(25,'2018-02-21 16:58:00','2018-02-21 16:58:00','TargetPay Ideal','TargetPay_Ideal',1,1,10000,0,NULL,0,0),(26,'2018-02-21 16:58:00','2018-02-21 16:58:00','TargetPay Mr Cash','TargetPay_Mrcash',1,1,10000,0,NULL,0,0),(27,'2018-02-21 16:58:00','2018-02-21 16:58:00','TwoCheckout','TwoCheckout',1,1,10000,0,NULL,1,0),(28,'2018-02-21 16:58:00','2018-02-21 16:58:00','WorldPay','WorldPay',1,1,10000,0,NULL,0,0),(29,'2018-02-21 16:58:00','2018-02-21 16:58:00','BeanStream','BeanStream',1,2,10000,0,NULL,0,0),(30,'2018-02-21 16:58:00','2018-02-21 16:58:00','Psigate','Psigate',1,2,10000,0,NULL,0,0),(31,'2018-02-21 16:58:00','2018-02-21 16:58:00','moolah','AuthorizeNet_AIM',1,1,10000,0,NULL,0,0),(32,'2018-02-21 16:58:00','2018-02-21 16:58:00','Alipay','Alipay_Express',1,1,10000,0,NULL,0,0),(33,'2018-02-21 16:58:00','2018-02-21 16:58:00','Buckaroo','Buckaroo_CreditCard',1,1,10000,0,NULL,0,0),(34,'2018-02-21 16:58:00','2018-02-21 16:58:00','Coinbase','Coinbase',1,1,10000,0,NULL,0,0),(35,'2018-02-21 16:58:00','2018-02-21 16:58:00','DataCash','DataCash',1,1,10000,0,NULL,0,0),(36,'2018-02-21 16:58:00','2018-02-21 16:58:00','Neteller','Neteller',1,2,10000,0,NULL,0,0),(37,'2018-02-21 16:58:00','2018-02-21 16:58:00','Pacnet','Pacnet',1,1,10000,0,NULL,0,0),(38,'2018-02-21 16:58:00','2018-02-21 16:58:00','PaymentSense','PaymentSense',1,2,10000,0,NULL,0,0),(39,'2018-02-21 16:58:00','2018-02-21 16:58:00','Realex','Realex_Remote',1,1,10000,0,NULL,0,0),(40,'2018-02-21 16:58:00','2018-02-21 16:58:00','Sisow','Sisow',1,1,10000,0,NULL,0,0),(41,'2018-02-21 16:58:00','2018-02-21 16:58:00','Skrill','Skrill',1,1,10000,0,NULL,1,0),(42,'2018-02-21 16:58:00','2018-02-21 16:58:00','BitPay','BitPay',1,1,7,0,NULL,1,0),(43,'2018-02-21 16:58:00','2018-02-21 16:58:00','Dwolla','Dwolla',1,1,6,0,NULL,1,0),(44,'2018-02-21 16:58:00','2018-02-21 16:58:00','AGMS','Agms',1,1,10000,0,NULL,0,0),(45,'2018-02-21 16:58:00','2018-02-21 16:58:00','Barclays','BarclaysEpdq\\Essential',1,1,10000,0,NULL,0,0),(46,'2018-02-21 16:58:00','2018-02-21 16:58:00','Cardgate','Cardgate',1,1,10000,0,NULL,0,0),(47,'2018-02-21 16:58:00','2018-02-21 16:58:00','Checkout.com','CheckoutCom',1,1,10000,0,NULL,0,0),(48,'2018-02-21 16:58:00','2018-02-21 16:58:00','Creditcall','Creditcall',1,1,10000,0,NULL,0,0),(49,'2018-02-21 16:58:00','2018-02-21 16:58:00','Cybersource','Cybersource',1,1,10000,0,NULL,0,0),(50,'2018-02-21 16:58:00','2018-02-21 16:58:00','ecoPayz','Ecopayz',1,1,10000,0,NULL,0,0),(51,'2018-02-21 16:58:00','2018-02-21 16:58:00','Fasapay','Fasapay',1,1,10000,0,NULL,0,0),(52,'2018-02-21 16:58:00','2018-02-21 16:58:00','Komoju','Komoju',1,1,10000,0,NULL,0,0),(53,'2018-02-21 16:58:00','2018-02-21 16:58:00','Multicards','Multicards',1,2,10000,0,NULL,0,0),(54,'2018-02-21 16:58:00','2018-02-21 16:58:00','Pagar.Me','Pagarme',1,2,10000,0,NULL,0,0),(55,'2018-02-21 16:58:00','2018-02-21 16:58:00','Paysafecard','Paysafecard',1,1,10000,0,NULL,0,0),(56,'2018-02-21 16:58:00','2018-02-21 16:58:00','Paytrace','Paytrace_CreditCard',1,1,10000,0,NULL,0,0),(57,'2018-02-21 16:58:00','2018-02-21 16:58:00','Secure Trading','SecureTrading',1,1,10000,0,NULL,0,0),(58,'2018-02-21 16:58:00','2018-02-21 16:58:00','SecPay','SecPay',1,1,10000,0,NULL,0,0),(59,'2018-02-21 16:58:00','2018-02-21 16:58:00','WeChat Express','WeChat_Express',1,2,10000,0,NULL,0,0),(60,'2018-02-21 16:58:00','2018-02-21 16:58:00','WePay','WePay',1,1,3,0,NULL,0,0),(61,'2018-02-21 16:58:00','2018-02-21 16:58:00','Braintree','Braintree',1,1,3,0,NULL,0,0),(62,'2018-02-21 16:58:00','2018-02-21 16:58:00','Custom','Custom',1,1,20,0,NULL,1,0),(63,'2018-02-21 16:58:00','2018-02-21 16:58:00','FirstData Payeezy','FirstData_Payeezy',1,1,10000,0,NULL,0,0),(64,'2018-02-21 16:58:00','2018-02-21 16:58:00','GoCardless','GoCardlessV2\\Redirect',1,1,9,0,NULL,1,0),(65,'2018-02-21 16:58:00','2018-02-21 16:58:00','PagSeguro','PagSeguro',1,1,10000,0,NULL,0,0); /*!40000 ALTER TABLE `gateways` ENABLE KEYS */; UNLOCK TABLES; @@ -1263,7 +1241,6 @@ UNLOCK TABLES; -- Table structure for table `industries` -- -DROP TABLE IF EXISTS `industries`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `industries` ( @@ -1287,7 +1264,6 @@ UNLOCK TABLES; -- Table structure for table `invitations` -- -DROP TABLE IF EXISTS `invitations`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `invitations` ( @@ -1335,7 +1311,6 @@ UNLOCK TABLES; -- Table structure for table `invoice_designs` -- -DROP TABLE IF EXISTS `invoice_designs`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `invoice_designs` ( @@ -1361,7 +1336,6 @@ UNLOCK TABLES; -- Table structure for table `invoice_items` -- -DROP TABLE IF EXISTS `invoice_items`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `invoice_items` ( @@ -1376,7 +1350,7 @@ CREATE TABLE `invoice_items` ( `product_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `notes` text COLLATE utf8_unicode_ci NOT NULL, `cost` decimal(15,4) NOT NULL, - `qty` decimal(15,4) DEFAULT NULL, + `qty` decimal(15,4) DEFAULT '0.0000', `tax_name1` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `tax_rate1` decimal(13,3) DEFAULT NULL, `public_id` int(10) unsigned NOT NULL, @@ -1385,7 +1359,7 @@ CREATE TABLE `invoice_items` ( `tax_name2` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `tax_rate2` decimal(13,3) NOT NULL, `invoice_item_type_id` smallint(6) NOT NULL DEFAULT '1', - `discount` double(8,2) NOT NULL, + `discount` decimal(13,2) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `invoice_items_account_id_public_id_unique` (`account_id`,`public_id`), KEY `invoice_items_product_id_foreign` (`product_id`), @@ -1410,7 +1384,6 @@ UNLOCK TABLES; -- Table structure for table `invoice_statuses` -- -DROP TABLE IF EXISTS `invoice_statuses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `invoice_statuses` ( @@ -1434,7 +1407,6 @@ UNLOCK TABLES; -- Table structure for table `invoices` -- -DROP TABLE IF EXISTS `invoices`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `invoices` ( @@ -1447,7 +1419,7 @@ CREATE TABLE `invoices` ( `updated_at` timestamp NULL DEFAULT NULL, `deleted_at` timestamp NULL DEFAULT NULL, `invoice_number` varchar(255) COLLATE utf8_unicode_ci NOT NULL, - `discount` double(8,2) NOT NULL, + `discount` decimal(13,2) NOT NULL, `po_number` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `invoice_date` date DEFAULT NULL, `due_date` date DEFAULT NULL, @@ -1519,7 +1491,6 @@ UNLOCK TABLES; -- Table structure for table `jobs` -- -DROP TABLE IF EXISTS `jobs`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `jobs` ( @@ -1549,7 +1520,6 @@ UNLOCK TABLES; -- Table structure for table `languages` -- -DROP TABLE IF EXISTS `languages`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `languages` ( @@ -1566,7 +1536,7 @@ CREATE TABLE `languages` ( LOCK TABLES `languages` WRITE; /*!40000 ALTER TABLE `languages` DISABLE KEYS */; -INSERT INTO `languages` VALUES (1,'English','en'),(2,'Italian','it'),(3,'German','de'),(4,'French','fr'),(5,'Portuguese - Brazilian','pt_BR'),(6,'Dutch','nl'),(7,'Spanish','es'),(8,'Norwegian','nb_NO'),(9,'Danish','da'),(10,'Japanese','ja'),(11,'Swedish','sv'),(12,'Spanish - Spain','es_ES'),(13,'French - Canada','fr_CA'),(14,'Lithuanian','lt'),(15,'Polish','pl'),(16,'Czech','cs'),(17,'Croatian','hr'),(18,'Albanian','sq'),(19,'Greek','el'),(20,'English - United Kingdom','en_UK'),(21,'Portuguese - Portugal','pt_PT'),(22,'Slovenian','sl'),(23,'Finnish','fi'),(24,'Romanian','ro'),(25,'Turkish - Turkey','tr_TR'),(26,'Thai','th'); +INSERT INTO `languages` VALUES (1,'English','en'),(2,'Italian','it'),(3,'German','de'),(4,'French','fr'),(5,'Portuguese - Brazilian','pt_BR'),(6,'Dutch','nl'),(7,'Spanish','es'),(8,'Norwegian','nb_NO'),(9,'Danish','da'),(10,'Japanese','ja'),(11,'Swedish','sv'),(12,'Spanish - Spain','es_ES'),(13,'French - Canada','fr_CA'),(14,'Lithuanian','lt'),(15,'Polish','pl'),(16,'Czech','cs'),(17,'Croatian','hr'),(18,'Albanian','sq'),(19,'Greek','el'),(20,'English - United Kingdom','en_GB'),(21,'Portuguese - Portugal','pt_PT'),(22,'Slovenian','sl'),(23,'Finnish','fi'),(24,'Romanian','ro'),(25,'Turkish - Turkey','tr_TR'),(26,'Thai','th'); /*!40000 ALTER TABLE `languages` ENABLE KEYS */; UNLOCK TABLES; @@ -1574,7 +1544,6 @@ UNLOCK TABLES; -- Table structure for table `licenses` -- -DROP TABLE IF EXISTS `licenses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `licenses` ( @@ -1610,7 +1579,6 @@ UNLOCK TABLES; -- Table structure for table `lookup_account_tokens` -- -DROP TABLE IF EXISTS `lookup_account_tokens`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_account_tokens` ( @@ -1637,7 +1605,6 @@ UNLOCK TABLES; -- Table structure for table `lookup_accounts` -- -DROP TABLE IF EXISTS `lookup_accounts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_accounts` ( @@ -1666,7 +1633,6 @@ UNLOCK TABLES; -- Table structure for table `lookup_companies` -- -DROP TABLE IF EXISTS `lookup_companies`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_companies` ( @@ -1693,7 +1659,6 @@ UNLOCK TABLES; -- Table structure for table `lookup_contacts` -- -DROP TABLE IF EXISTS `lookup_contacts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_contacts` ( @@ -1720,7 +1685,6 @@ UNLOCK TABLES; -- Table structure for table `lookup_invitations` -- -DROP TABLE IF EXISTS `lookup_invitations`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_invitations` ( @@ -1745,11 +1709,38 @@ LOCK TABLES `lookup_invitations` WRITE; /*!40000 ALTER TABLE `lookup_invitations` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `lookup_proposal_invitations` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `lookup_proposal_invitations` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `lookup_account_id` int(10) unsigned NOT NULL, + `invitation_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `message_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `lookup_proposal_invitations_invitation_key_unique` (`invitation_key`), + UNIQUE KEY `lookup_proposal_invitations_message_id_unique` (`message_id`), + KEY `lookup_proposal_invitations_lookup_account_id_index` (`lookup_account_id`), + CONSTRAINT `lookup_proposal_invitations_lookup_account_id_foreign` FOREIGN KEY (`lookup_account_id`) REFERENCES `lookup_accounts` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `lookup_proposal_invitations` +-- + +LOCK TABLES `lookup_proposal_invitations` WRITE; +/*!40000 ALTER TABLE `lookup_proposal_invitations` DISABLE KEYS */; +/*!40000 ALTER TABLE `lookup_proposal_invitations` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `lookup_users` -- -DROP TABLE IF EXISTS `lookup_users`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `lookup_users` ( @@ -1785,7 +1776,6 @@ UNLOCK TABLES; -- Table structure for table `migrations` -- -DROP TABLE IF EXISTS `migrations`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `migrations` ( @@ -1793,7 +1783,7 @@ CREATE TABLE `migrations` ( `migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `batch` int(11) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=105 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=InnoDB AUTO_INCREMENT=106 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- @@ -1802,7 +1792,7 @@ CREATE TABLE `migrations` ( LOCK TABLES `migrations` WRITE; /*!40000 ALTER TABLE `migrations` DISABLE KEYS */; -INSERT INTO `migrations` VALUES (1,'2013_11_05_180133_confide_setup_users_table',1),(2,'2013_11_28_195703_setup_countries_table',1),(3,'2014_02_13_151500_add_cascase_drops',1),(4,'2014_02_19_151817_add_support_for_invoice_designs',1),(5,'2014_03_03_155556_add_phone_to_account',1),(6,'2014_03_19_201454_add_language_support',1),(7,'2014_03_20_200300_create_payment_libraries',1),(8,'2014_03_23_051736_enable_forcing_jspdf',1),(9,'2014_03_25_102200_add_sort_and_recommended_to_gateways',1),(10,'2014_04_03_191105_add_pro_plan',1),(11,'2014_04_17_100523_add_remember_token',1),(12,'2014_04_17_145108_add_custom_fields',1),(13,'2014_04_23_170909_add_products_settings',1),(14,'2014_04_29_174315_add_advanced_settings',1),(15,'2014_05_17_175626_add_quotes',1),(16,'2014_06_17_131940_add_accepted_credit_cards_to_account_gateways',1),(17,'2014_07_13_142654_one_click_install',1),(18,'2014_07_17_205900_support_hiding_quantity',1),(19,'2014_07_24_171214_add_zapier_support',1),(20,'2014_10_01_141248_add_company_vat_number',1),(21,'2014_10_05_141856_track_last_seen_message',1),(22,'2014_10_06_103529_add_timesheets',1),(23,'2014_10_06_195330_add_invoice_design_table',1),(24,'2014_10_13_054100_add_invoice_number_settings',1),(25,'2014_10_14_225227_add_danish_translation',1),(26,'2014_10_22_174452_add_affiliate_price',1),(27,'2014_10_30_184126_add_company_id_number',1),(28,'2014_11_04_200406_allow_null_client_currency',1),(29,'2014_12_03_154119_add_discount_type',1),(30,'2015_02_12_102940_add_email_templates',1),(31,'2015_02_17_131714_support_token_billing',1),(32,'2015_02_27_081836_add_invoice_footer',1),(33,'2015_03_03_140259_add_tokens',1),(34,'2015_03_09_151011_add_ip_to_activity',1),(35,'2015_03_15_174122_add_pdf_email_attachment_option',1),(36,'2015_03_30_100000_create_password_resets_table',1),(37,'2015_04_12_093447_add_sv_language',1),(38,'2015_04_13_100333_add_notify_approved',1),(39,'2015_04_16_122647_add_partial_amount_to_invoices',1),(40,'2015_05_21_184104_add_font_size',1),(41,'2015_05_27_121828_add_tasks',1),(42,'2015_05_27_170808_add_custom_invoice_labels',1),(43,'2015_06_09_134208_add_has_tasks_to_invoices',1),(44,'2015_06_14_093410_enable_resuming_tasks',1),(45,'2015_06_14_173025_multi_company_support',1),(46,'2015_07_07_160257_support_locking_account',1),(47,'2015_07_08_114333_simplify_tasks',1),(48,'2015_07_19_081332_add_custom_design',1),(49,'2015_07_27_183830_add_pdfmake_support',1),(50,'2015_08_13_084041_add_formats_to_datetime_formats_table',1),(51,'2015_09_04_080604_add_swap_postal_code',1),(52,'2015_09_07_135935_add_account_domain',1),(53,'2015_09_10_185135_add_reminder_emails',1),(54,'2015_10_07_135651_add_social_login',1),(55,'2015_10_21_075058_add_default_tax_rates',1),(56,'2015_10_21_185724_add_invoice_number_pattern',1),(57,'2015_10_27_180214_add_is_system_to_activities',1),(58,'2015_10_29_133747_add_default_quote_terms',1),(59,'2015_11_01_080417_encrypt_tokens',1),(60,'2015_11_03_181318_improve_currency_localization',1),(61,'2015_11_30_133206_add_email_designs',1),(62,'2015_12_27_154513_add_reminder_settings',1),(63,'2015_12_30_042035_add_client_view_css',1),(64,'2016_01_04_175228_create_vendors_table',1),(65,'2016_01_06_153144_add_invoice_font_support',1),(66,'2016_01_17_155725_add_quote_to_invoice_option',1),(67,'2016_01_18_195351_add_bank_accounts',1),(68,'2016_01_24_112646_add_bank_subaccounts',1),(69,'2016_01_27_173015_add_header_footer_option',1),(70,'2016_02_01_135956_add_source_currency_to_expenses',1),(71,'2016_02_25_152948_add_client_password',1),(72,'2016_02_28_081424_add_custom_invoice_fields',1),(73,'2016_03_14_066181_add_user_permissions',1),(74,'2016_03_14_214710_add_support_three_decimal_taxes',1),(75,'2016_03_22_168362_add_documents',1),(76,'2016_03_23_215049_support_multiple_tax_rates',1),(77,'2016_04_16_103943_enterprise_plan',1),(78,'2016_04_18_174135_add_page_size',1),(79,'2016_04_23_182223_payments_changes',1),(80,'2016_05_16_102925_add_swap_currency_symbol_to_currency',1),(81,'2016_05_18_085739_add_invoice_type_support',1),(82,'2016_05_24_164847_wepay_ach',1),(83,'2016_07_08_083802_support_new_pricing',1),(84,'2016_07_13_083821_add_buy_now_buttons',1),(85,'2016_08_10_184027_add_support_for_bots',1),(86,'2016_09_05_150625_create_gateway_types',1),(87,'2016_10_20_191150_add_expense_to_activities',1),(88,'2016_11_03_113316_add_invoice_signature',1),(89,'2016_11_03_161149_add_bluevine_fields',1),(90,'2016_11_28_092904_add_task_projects',1),(91,'2016_12_13_113955_add_pro_plan_discount',1),(92,'2017_01_01_214241_add_inclusive_taxes',1),(93,'2017_02_23_095934_add_custom_product_fields',1),(94,'2017_03_16_085702_add_gateway_fee_location',1),(95,'2017_04_16_101744_add_custom_contact_fields',1),(96,'2017_04_30_174702_add_multiple_database_support',1),(97,'2017_05_10_144928_add_oauth_to_lookups',1),(98,'2017_05_16_101715_add_default_note_to_client',1),(99,'2017_06_19_111515_update_dark_mode',1),(100,'2017_07_18_124150_add_late_fees',1),(101,'2017_08_14_085334_increase_precision',1),(102,'2017_10_17_083846_add_default_rates',1),(103,'2017_11_15_114422_add_subdomain_to_lookups',1),(104,'2017_12_13_074024_add_remember_2fa_token',1); +INSERT INTO `migrations` VALUES (1,'2013_11_05_180133_confide_setup_users_table',1),(2,'2013_11_28_195703_setup_countries_table',1),(3,'2014_02_13_151500_add_cascase_drops',1),(4,'2014_02_19_151817_add_support_for_invoice_designs',1),(5,'2014_03_03_155556_add_phone_to_account',1),(6,'2014_03_19_201454_add_language_support',1),(7,'2014_03_20_200300_create_payment_libraries',1),(8,'2014_03_23_051736_enable_forcing_jspdf',1),(9,'2014_03_25_102200_add_sort_and_recommended_to_gateways',1),(10,'2014_04_03_191105_add_pro_plan',1),(11,'2014_04_17_100523_add_remember_token',1),(12,'2014_04_17_145108_add_custom_fields',1),(13,'2014_04_23_170909_add_products_settings',1),(14,'2014_04_29_174315_add_advanced_settings',1),(15,'2014_05_17_175626_add_quotes',1),(16,'2014_06_17_131940_add_accepted_credit_cards_to_account_gateways',1),(17,'2014_07_13_142654_one_click_install',1),(18,'2014_07_17_205900_support_hiding_quantity',1),(19,'2014_07_24_171214_add_zapier_support',1),(20,'2014_10_01_141248_add_company_vat_number',1),(21,'2014_10_05_141856_track_last_seen_message',1),(22,'2014_10_06_103529_add_timesheets',1),(23,'2014_10_06_195330_add_invoice_design_table',1),(24,'2014_10_13_054100_add_invoice_number_settings',1),(25,'2014_10_14_225227_add_danish_translation',1),(26,'2014_10_22_174452_add_affiliate_price',1),(27,'2014_10_30_184126_add_company_id_number',1),(28,'2014_11_04_200406_allow_null_client_currency',1),(29,'2014_12_03_154119_add_discount_type',1),(30,'2015_02_12_102940_add_email_templates',1),(31,'2015_02_17_131714_support_token_billing',1),(32,'2015_02_27_081836_add_invoice_footer',1),(33,'2015_03_03_140259_add_tokens',1),(34,'2015_03_09_151011_add_ip_to_activity',1),(35,'2015_03_15_174122_add_pdf_email_attachment_option',1),(36,'2015_03_30_100000_create_password_resets_table',1),(37,'2015_04_12_093447_add_sv_language',1),(38,'2015_04_13_100333_add_notify_approved',1),(39,'2015_04_16_122647_add_partial_amount_to_invoices',1),(40,'2015_05_21_184104_add_font_size',1),(41,'2015_05_27_121828_add_tasks',1),(42,'2015_05_27_170808_add_custom_invoice_labels',1),(43,'2015_06_09_134208_add_has_tasks_to_invoices',1),(44,'2015_06_14_093410_enable_resuming_tasks',1),(45,'2015_06_14_173025_multi_company_support',1),(46,'2015_07_07_160257_support_locking_account',1),(47,'2015_07_08_114333_simplify_tasks',1),(48,'2015_07_19_081332_add_custom_design',1),(49,'2015_07_27_183830_add_pdfmake_support',1),(50,'2015_08_13_084041_add_formats_to_datetime_formats_table',1),(51,'2015_09_04_080604_add_swap_postal_code',1),(52,'2015_09_07_135935_add_account_domain',1),(53,'2015_09_10_185135_add_reminder_emails',1),(54,'2015_10_07_135651_add_social_login',1),(55,'2015_10_21_075058_add_default_tax_rates',1),(56,'2015_10_21_185724_add_invoice_number_pattern',1),(57,'2015_10_27_180214_add_is_system_to_activities',1),(58,'2015_10_29_133747_add_default_quote_terms',1),(59,'2015_11_01_080417_encrypt_tokens',1),(60,'2015_11_03_181318_improve_currency_localization',1),(61,'2015_11_30_133206_add_email_designs',1),(62,'2015_12_27_154513_add_reminder_settings',1),(63,'2015_12_30_042035_add_client_view_css',1),(64,'2016_01_04_175228_create_vendors_table',1),(65,'2016_01_06_153144_add_invoice_font_support',1),(66,'2016_01_17_155725_add_quote_to_invoice_option',1),(67,'2016_01_18_195351_add_bank_accounts',1),(68,'2016_01_24_112646_add_bank_subaccounts',1),(69,'2016_01_27_173015_add_header_footer_option',1),(70,'2016_02_01_135956_add_source_currency_to_expenses',1),(71,'2016_02_25_152948_add_client_password',1),(72,'2016_02_28_081424_add_custom_invoice_fields',1),(73,'2016_03_14_066181_add_user_permissions',1),(74,'2016_03_14_214710_add_support_three_decimal_taxes',1),(75,'2016_03_22_168362_add_documents',1),(76,'2016_03_23_215049_support_multiple_tax_rates',1),(77,'2016_04_16_103943_enterprise_plan',1),(78,'2016_04_18_174135_add_page_size',1),(79,'2016_04_23_182223_payments_changes',1),(80,'2016_05_16_102925_add_swap_currency_symbol_to_currency',1),(81,'2016_05_18_085739_add_invoice_type_support',1),(82,'2016_05_24_164847_wepay_ach',1),(83,'2016_07_08_083802_support_new_pricing',1),(84,'2016_07_13_083821_add_buy_now_buttons',1),(85,'2016_08_10_184027_add_support_for_bots',1),(86,'2016_09_05_150625_create_gateway_types',1),(87,'2016_10_20_191150_add_expense_to_activities',1),(88,'2016_11_03_113316_add_invoice_signature',1),(89,'2016_11_03_161149_add_bluevine_fields',1),(90,'2016_11_28_092904_add_task_projects',1),(91,'2016_12_13_113955_add_pro_plan_discount',1),(92,'2017_01_01_214241_add_inclusive_taxes',1),(93,'2017_02_23_095934_add_custom_product_fields',1),(94,'2017_03_16_085702_add_gateway_fee_location',1),(95,'2017_04_16_101744_add_custom_contact_fields',1),(96,'2017_04_30_174702_add_multiple_database_support',1),(97,'2017_05_10_144928_add_oauth_to_lookups',1),(98,'2017_05_16_101715_add_default_note_to_client',1),(99,'2017_06_19_111515_update_dark_mode',1),(100,'2017_07_18_124150_add_late_fees',1),(101,'2017_08_14_085334_increase_precision',1),(102,'2017_10_17_083846_add_default_rates',1),(103,'2017_11_15_114422_add_subdomain_to_lookups',1),(104,'2017_12_13_074024_add_remember_2fa_token',1),(105,'2018_01_10_073825_add_subscription_format',1); /*!40000 ALTER TABLE `migrations` ENABLE KEYS */; UNLOCK TABLES; @@ -1810,7 +1800,6 @@ UNLOCK TABLES; -- Table structure for table `password_resets` -- -DROP TABLE IF EXISTS `password_resets`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `password_resets` ( @@ -1834,7 +1823,6 @@ UNLOCK TABLES; -- Table structure for table `payment_libraries` -- -DROP TABLE IF EXISTS `payment_libraries`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payment_libraries` ( @@ -1853,7 +1841,7 @@ CREATE TABLE `payment_libraries` ( LOCK TABLES `payment_libraries` WRITE; /*!40000 ALTER TABLE `payment_libraries` DISABLE KEYS */; -INSERT INTO `payment_libraries` VALUES (1,'2018-01-08 16:45:19','2018-01-08 16:45:19','Omnipay',1),(2,'2018-01-08 16:45:19','2018-01-08 16:45:19','PHP-Payments [Deprecated]',1); +INSERT INTO `payment_libraries` VALUES (1,'2018-02-21 16:57:58','2018-02-21 16:57:58','Omnipay',1),(2,'2018-02-21 16:57:58','2018-02-21 16:57:58','PHP-Payments [Deprecated]',1); /*!40000 ALTER TABLE `payment_libraries` ENABLE KEYS */; UNLOCK TABLES; @@ -1861,7 +1849,6 @@ UNLOCK TABLES; -- Table structure for table `payment_methods` -- -DROP TABLE IF EXISTS `payment_methods`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payment_methods` ( @@ -1914,7 +1901,6 @@ UNLOCK TABLES; -- Table structure for table `payment_statuses` -- -DROP TABLE IF EXISTS `payment_statuses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payment_statuses` ( @@ -1938,7 +1924,6 @@ UNLOCK TABLES; -- Table structure for table `payment_terms` -- -DROP TABLE IF EXISTS `payment_terms`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payment_terms` ( @@ -1963,7 +1948,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','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,1),(2,10,'Net 10','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,2),(3,14,'Net 14','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,3),(4,15,'Net 15','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,4),(5,30,'Net 30','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,5),(6,60,'Net 60','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,6),(7,90,'Net 90','2018-01-08 16:45:19','2018-01-08 16:45:19',NULL,0,0,7); +INSERT INTO `payment_terms` VALUES (1,7,'Net 7','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,1),(2,10,'Net 10','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,2),(3,14,'Net 14','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,3),(4,15,'Net 15','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,4),(5,30,'Net 30','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,5),(6,60,'Net 60','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,6),(7,90,'Net 90','2018-02-21 16:57:58','2018-02-21 16:57:58',NULL,0,0,7); /*!40000 ALTER TABLE `payment_terms` ENABLE KEYS */; UNLOCK TABLES; @@ -1971,7 +1956,6 @@ UNLOCK TABLES; -- Table structure for table `payment_types` -- -DROP TABLE IF EXISTS `payment_types`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payment_types` ( @@ -1998,7 +1982,6 @@ UNLOCK TABLES; -- Table structure for table `payments` -- -DROP TABLE IF EXISTS `payments`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `payments` ( @@ -2071,7 +2054,6 @@ UNLOCK TABLES; -- Table structure for table `products` -- -DROP TABLE IF EXISTS `products`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `products` ( @@ -2084,7 +2066,7 @@ CREATE TABLE `products` ( `product_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `notes` text COLLATE utf8_unicode_ci NOT NULL, `cost` decimal(15,4) NOT NULL, - `qty` decimal(15,4) DEFAULT NULL, + `qty` decimal(15,4) DEFAULT '0.0000', `public_id` int(10) unsigned NOT NULL, `is_deleted` tinyint(1) NOT NULL DEFAULT '0', `custom_value1` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, @@ -2115,7 +2097,6 @@ UNLOCK TABLES; -- Table structure for table `projects` -- -DROP TABLE IF EXISTS `projects`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `projects` ( @@ -2154,11 +2135,206 @@ LOCK TABLES `projects` WRITE; /*!40000 ALTER TABLE `projects` ENABLE KEYS */; UNLOCK TABLES; +-- +-- Table structure for table `proposal_categories` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proposal_categories` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `account_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `public_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `proposal_categories_account_id_public_id_unique` (`account_id`,`public_id`), + KEY `proposal_categories_user_id_foreign` (`user_id`), + KEY `proposal_categories_public_id_index` (`public_id`), + CONSTRAINT `proposal_categories_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposal_categories_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `proposal_categories` +-- + +LOCK TABLES `proposal_categories` WRITE; +/*!40000 ALTER TABLE `proposal_categories` DISABLE KEYS */; +/*!40000 ALTER TABLE `proposal_categories` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `proposal_invitations` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proposal_invitations` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `account_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `contact_id` int(10) unsigned NOT NULL, + `proposal_id` int(10) unsigned NOT NULL, + `invitation_key` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `sent_date` timestamp NULL DEFAULT NULL, + `viewed_date` timestamp NULL DEFAULT NULL, + `opened_date` timestamp NULL DEFAULT NULL, + `message_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + `email_error` text COLLATE utf8_unicode_ci, + `public_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `proposal_invitations_account_id_public_id_unique` (`account_id`,`public_id`), + UNIQUE KEY `proposal_invitations_invitation_key_unique` (`invitation_key`), + KEY `proposal_invitations_user_id_foreign` (`user_id`), + KEY `proposal_invitations_contact_id_foreign` (`contact_id`), + KEY `proposal_invitations_proposal_id_index` (`proposal_id`), + KEY `proposal_invitations_public_id_index` (`public_id`), + CONSTRAINT `proposal_invitations_contact_id_foreign` FOREIGN KEY (`contact_id`) REFERENCES `contacts` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposal_invitations_proposal_id_foreign` FOREIGN KEY (`proposal_id`) REFERENCES `proposals` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposal_invitations_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `proposal_invitations` +-- + +LOCK TABLES `proposal_invitations` WRITE; +/*!40000 ALTER TABLE `proposal_invitations` DISABLE KEYS */; +/*!40000 ALTER TABLE `proposal_invitations` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `proposal_snippets` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proposal_snippets` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `account_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `proposal_category_id` int(10) unsigned DEFAULT NULL, + `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `icon` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `private_notes` text COLLATE utf8_unicode_ci NOT NULL, + `html` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `css` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `public_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `proposal_snippets_account_id_public_id_unique` (`account_id`,`public_id`), + KEY `proposal_snippets_user_id_foreign` (`user_id`), + KEY `proposal_snippets_public_id_index` (`public_id`), + CONSTRAINT `proposal_snippets_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposal_snippets_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `proposal_snippets` +-- + +LOCK TABLES `proposal_snippets` WRITE; +/*!40000 ALTER TABLE `proposal_snippets` DISABLE KEYS */; +/*!40000 ALTER TABLE `proposal_snippets` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `proposal_templates` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proposal_templates` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `account_id` int(10) unsigned DEFAULT NULL, + `user_id` int(10) unsigned DEFAULT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `private_notes` text COLLATE utf8_unicode_ci NOT NULL, + `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, + `html` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `css` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `public_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `proposal_templates_account_id_public_id_unique` (`account_id`,`public_id`), + KEY `proposal_templates_user_id_foreign` (`user_id`), + KEY `proposal_templates_public_id_index` (`public_id`), + CONSTRAINT `proposal_templates_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposal_templates_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `proposal_templates` +-- + +LOCK TABLES `proposal_templates` WRITE; +/*!40000 ALTER TABLE `proposal_templates` DISABLE KEYS */; +/*!40000 ALTER TABLE `proposal_templates` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `proposals` +-- + +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `proposals` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `account_id` int(10) unsigned NOT NULL, + `user_id` int(10) unsigned NOT NULL, + `created_at` timestamp NULL DEFAULT NULL, + `updated_at` timestamp NULL DEFAULT NULL, + `deleted_at` timestamp NULL DEFAULT NULL, + `is_deleted` tinyint(1) NOT NULL DEFAULT '0', + `invoice_id` int(10) unsigned NOT NULL, + `proposal_template_id` int(10) unsigned DEFAULT NULL, + `private_notes` text COLLATE utf8_unicode_ci NOT NULL, + `html` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `css` mediumtext COLLATE utf8_unicode_ci NOT NULL, + `public_id` int(10) unsigned NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `proposals_account_id_public_id_unique` (`account_id`,`public_id`), + KEY `proposals_user_id_foreign` (`user_id`), + KEY `proposals_invoice_id_index` (`invoice_id`), + KEY `proposals_proposal_template_id_index` (`proposal_template_id`), + KEY `proposals_public_id_index` (`public_id`), + CONSTRAINT `proposals_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposals_invoice_id_foreign` FOREIGN KEY (`invoice_id`) REFERENCES `invoices` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposals_proposal_template_id_foreign` FOREIGN KEY (`proposal_template_id`) REFERENCES `proposal_templates` (`id`) ON DELETE CASCADE, + CONSTRAINT `proposals_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `proposals` +-- + +LOCK TABLES `proposals` WRITE; +/*!40000 ALTER TABLE `proposals` DISABLE KEYS */; +/*!40000 ALTER TABLE `proposals` ENABLE KEYS */; +UNLOCK TABLES; + -- -- Table structure for table `recurring_expenses` -- -DROP TABLE IF EXISTS `recurring_expenses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `recurring_expenses` ( @@ -2216,7 +2392,6 @@ UNLOCK TABLES; -- Table structure for table `scheduled_reports` -- -DROP TABLE IF EXISTS `scheduled_reports`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `scheduled_reports` ( @@ -2252,7 +2427,6 @@ UNLOCK TABLES; -- Table structure for table `security_codes` -- -DROP TABLE IF EXISTS `security_codes`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `security_codes` ( @@ -2288,7 +2462,6 @@ UNLOCK TABLES; -- Table structure for table `sizes` -- -DROP TABLE IF EXISTS `sizes`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `sizes` ( @@ -2312,7 +2485,6 @@ UNLOCK TABLES; -- Table structure for table `subscriptions` -- -DROP TABLE IF EXISTS `subscriptions`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `subscriptions` ( @@ -2325,6 +2497,7 @@ CREATE TABLE `subscriptions` ( `target_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL, `public_id` int(10) unsigned DEFAULT NULL, `user_id` int(10) unsigned DEFAULT NULL, + `format` enum('JSON','UBL') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'JSON', PRIMARY KEY (`id`), UNIQUE KEY `subscriptions_account_id_public_id_unique` (`account_id`,`public_id`), CONSTRAINT `subscriptions_account_id_foreign` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE @@ -2344,7 +2517,6 @@ UNLOCK TABLES; -- Table structure for table `task_statuses` -- -DROP TABLE IF EXISTS `task_statuses`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `task_statuses` ( @@ -2380,7 +2552,6 @@ UNLOCK TABLES; -- Table structure for table `tasks` -- -DROP TABLE IF EXISTS `tasks`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `tasks` ( @@ -2431,7 +2602,6 @@ UNLOCK TABLES; -- Table structure for table `tax_rates` -- -DROP TABLE IF EXISTS `tax_rates`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `tax_rates` ( @@ -2467,7 +2637,6 @@ UNLOCK TABLES; -- Table structure for table `themes` -- -DROP TABLE IF EXISTS `themes`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `themes` ( @@ -2491,7 +2660,6 @@ UNLOCK TABLES; -- Table structure for table `timezones` -- -DROP TABLE IF EXISTS `timezones`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `timezones` ( @@ -2516,7 +2684,6 @@ UNLOCK TABLES; -- Table structure for table `user_accounts` -- -DROP TABLE IF EXISTS `user_accounts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `user_accounts` ( @@ -2553,7 +2720,6 @@ UNLOCK TABLES; -- Table structure for table `users` -- -DROP TABLE IF EXISTS `users`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `users` ( @@ -2611,7 +2777,6 @@ UNLOCK TABLES; -- Table structure for table `vendor_contacts` -- -DROP TABLE IF EXISTS `vendor_contacts`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `vendor_contacts` ( @@ -2651,7 +2816,6 @@ UNLOCK TABLES; -- Table structure for table `vendors` -- -DROP TABLE IF EXISTS `vendors`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `vendors` ( @@ -2707,4 +2871,4 @@ UNLOCK TABLES; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2018-01-08 20:45:23 +-- Dump completed on 2018-02-21 20:58:03 diff --git a/docs/conf.py b/docs/conf.py index 51ef4dc653cd..a2c229169ced 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'4.1' +version = u'4.2' # The full version, including alpha/beta/rc tags. -release = u'4.1.5' +release = u'4.2.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 72948c47d6dc..20928a184c74 100644 --- a/docs/configure.rst +++ b/docs/configure.rst @@ -66,9 +66,11 @@ Troubleshooting - To determine the path you can run ``which phantomjs`` from the command line. - 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 the link in the error and then run ``phantomjs test.pjs``. +- You may need to add an entry in the /etc/hosts file to resolve the domain name. - 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. +- If you installed PhantomJS using APT `these steps `_ may help. Custom Fonts """""""""""" diff --git a/docs/developer_guide.rst b/docs/developer_guide.rst index 155e4e66fcb6..1e74b8657c85 100644 --- a/docs/developer_guide.rst +++ b/docs/developer_guide.rst @@ -44,5 +44,10 @@ To run the `Codeception `_ tests you’ll need to insta - Create config file: ``cp tests/_bootstrap.php.default tests/_bootstrap.php`` - Create test user: ``php artisan db:seed --class=UserTableSeeder`` +- edit the following files, replacing ``www.ninja.test:8000`` with your local test domain: + - /.travis.ylm + - /app/Libraries/Utils.php + - /tests/acceptance.suite.yml + - /tests/functional.suite.yml - Start the PhantomJS web server: ``phantomjs --webdriver=4444`` - Run the tests: ``sudo ./vendor/codeception/codeception/codecept run --debug`` diff --git a/docs/email_settings.rst b/docs/email_settings.rst index 697036d48e06..3af26a71197c 100644 --- a/docs/email_settings.rst +++ b/docs/email_settings.rst @@ -5,20 +5,30 @@ Email communication with your clients is an important part of the Invoice Ninja With the Email Settings feature, you can specify certain settings and designs for the notification emails your clients receive from your Invoice Ninja account. -The Email Settings page includes two sections: **Email Settings** and **Email Designs**. +The Email Settings page includes three sections: Email Settings, Email Designs and Email Signature. Email Settings """""""""""""" +Reply-To Email: Specify the email address your clients will reply to. (This is the email address that will automatically come up when your clients click "Reply" to your Invoice Ninja emails.) -- **Attach PDFs**: Want to be able to attach PDF files to your emails? Check the Enable box. +BCC Email: If you want to send a copy of your client emails privately to another email address, enter it here. (Your clients won't see it). -- **Invoice Link**: When you email an invoice to a client, the invoice is viewable via a web link that is embedded in the notification email. The default link uses a URL from the Invoice Ninja site. If you wish to change the link to your own website or another subdomain, check the relevant box and enter the URL details. +- **Attach PDFs**: Want the capability to attach PDF files to your emails? Check the Enable box. + +- **Attach documents**: Want the capability to attach documents to your emails? Check the Enable box. Email Design """""""""""" - **Email Style**: You can make your emails look more professional by choosing a design layout. Select the desired style by opening the drop-down menu. Available styles are Plain (regular email layout), Light (graphical layout featuring light border) and Dark (graphical layout featuring dark border). To preview the different styles, click the question mark icon at the right end of the field. -- **Enable markup**: Want to give your clients the convenient option to pay you online with a direct link from the invoice notification email? Check Enable markup to add a payment link to the invoice email. Then, your clients can click through to submit an online payment. +- **Enable markup**: Want to give your clients the convenient option to pay you online with a direct link from the invoice notification email? Check Enable markup to add a payment link, or any other call to action, to the invoice email. Then, your clients can click through to submit an online payment. + +Email Signature +""""""""""""""" + +Customize your email signature by entering free text in the box. Then format and customize the design of your email signature with the formatting toolbar. You can change the font, size or emphasis, underline, add bullets, hyperlinks and much more. + +Prefer to design your own email signature in raw HTML? Click the gray Raw button at the bottom right of the free text box. Then enter your HTML and click Update. Finished customizing your email settings? Click the green Save button to apply the new settings. diff --git a/docs/install.rst b/docs/install.rst index cf4955fded75..44a56c35136f 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -8,16 +8,20 @@ Thanks for taking the time to setup Invoice Ninja. Detailed Guides ^^^^^^^^^^^^^^^ +- Ubuntu and Nginx: `websiteforstudents.com `_ + - Ubuntu and Apache: `technerdservices.com `_ - Debian and Nginx: `rosehosting.com `_ -- CentOS, Nginx, MariaDB and PHP 7: `thishosting.rocks `_ +- CentOS and Nginx: `thishosting.rocks `_ Automated Installers ^^^^^^^^^^^^^^^^^^^^ -- Dockerfile: `github.com/invoiceninja/dockerfiles `_ +- Dockerfile: `github.com `_ + +- Cloudron: `cloudron.io `_ - Softaculous: `softaculous.com `_ @@ -70,6 +74,13 @@ Once you can access the site the initial setup screen will enable you to configu .. Tip:: To remove public/ from the URL map the webroot to the /public folder, alternatively you can uncomment ``RewriteRule ^(.*)$ public/$1 [L]`` in the .htaccess file. +Step 5: Enable auto updates +""""""""""""""""""""""""""" + +Use this `shell script `_ to automate the update process. + +You can run it as a daily cron to automatically keep your app up to date. + Troubleshooting ^^^^^^^^^^^^^^^ @@ -80,4 +91,4 @@ Troubleshooting - Running ``composer install`` and ``composer dump-autoload`` can sometimes help with composer problems. - If you’re using a subdomain. ie, invoice.mycompany.com You will need to add ``RewriteBase /`` to public/.htaccess otherwise it may fail with ``Request exceeded the limit of 10 internal redirects due to probable configuration error.`` messages in the logs. - Composer install error: ``Fatal error: Allowed memory size of...`` Try the following: ``php -d memory_limit=-1 /usr/local/bin/composer install`` -- PHP Fatal error: ``Call to undefined method Illuminate\Support\Facades\Session::get()`` try deleting bootstrap/cache/services.php +- PHP Fatal error: ``Call to undefined method Illuminate\Support\Facades\Session::get()`` try deleting bootstrap/cache/services.php. If the file doesn't exist the steps `https://stackoverflow.com/a/37266353/497368 `_ may help. diff --git a/docs/templates_and_reminders.rst b/docs/templates_and_reminders.rst index 16a26c5e6123..ed5bd896478b 100644 --- a/docs/templates_and_reminders.rst +++ b/docs/templates_and_reminders.rst @@ -6,29 +6,31 @@ There are a few different emails your customers receive from you via the Invoice Email Templates """"""""""""""" -Invoice Email / Quote Email / Payment Email -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You can create separate templates for invoice emails, quote emails and payment emails. To do so, click the relevant tab. The settings you choose will apply for that specific email. -- **Subject Customize**: the subject line of your invoice/quote/payment emails by entering the desired text. You can also enter variables according to your preference, such as invoice number, company name, due date and many more. Click the question mark icon at the right side of the Subject field to view a list of available variables. To reset your entry, click the Reset link just above the question mark icon. +- **Subject**: Customize the subject line of your invoice/quote/payment emails by entering the desired text. You can also enter variables according to your preference, such as invoice number, company name, due date and many more. Click the question mark icon at the right side of the Subject field to view a list of available variables. To reset your entry, click the Reset link just above the question mark icon. - **Body**: Customize the email body text by entering the desired text. You can also enter variables according to your preference. Click the question mark icon at the right side of the Subject field to view a list of available variables. To reset your entry, click the Reset link just above the right hand side of the body text box. - **Toolbar**: Immediately below the body text box, there is a bar featuring all the formatting tools you need to customize your invoice email, including font style, font size, bold/italics/underline, strikethrough, font color, background color, numbering, bulleting, alignment and hyperlinks. +- **Raw**: You can customize your invoice/quote/payment emails via raw HTML. Click the gray Raw button at the bottom right of the section. A window will open. Enter your HTML code. When you're done, click Update. +- **Preview**: Want to view the email exactly as your client will see it? Preview your invoice/quote/payment email in a separate window at any time by clicking the blue Preview button. -.. TIP:: Any changes you make to your email settings will instantly appear in the preview at the right hand side of the page. See how your email template will look as you are creating it, so you can get it just right. +.. TIP: Any changes you make to your email settings will instantly appear in the preview at the right hand side of the page. See how your email template will look as you are creating it, so you can get it just right. Reminder Emails """"""""""""""" Sometimes, your clients need a friendly reminder about their outstanding payments. Invoice Ninja enables up to 3 reminder emails, and you can totally customize the email content and delivery schedule according to your preference. -First Reminder / Second Reminder / Third Reminder -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To activate the reminder function, check the Enable box of the First Reminder tab. (TIP: To activate the second and third reminder emails, you'll need to enable them separately. Open the relevant tab and check the Enable box.) - -Schedule Define the schedule for the reminder email by selecting values for the three schedule boxes: the number of days after/ days before the due date/ invoice date. The reminder will be sent according to the values you select in these three fields. +You can create separate templates for the first, second and third reminder emails. To do so, click the relevant tab. The settings you choose will apply for that specific reminder email. +- **Schedule**: Define the schedule for the reminder email by selecting values for the three schedule boxes: the number of days after/ days before the due date/ invoice date. The reminder will be sent according to the values you select in these three fields. +- **Send Email**: If you want the reminder email to be sent automatically according to your defined schedule, check the Enable box. If you do not check Enable, no reminder email will be sent. +- **Late Fee Amount**: Specify a late fee amount to add to the invoice for overdue payments. You can add a different amount for each reminder email (i.e. you may want to increase the late fee with each late reminder email.) +- **Late Fee Percent**: Specify the late fee as a percentage of the invoice amount. - **Subject**: Customize the subject line of your reminder email by entering the desired text. You can also enter variables according to your preference, such as invoice number, company name, due date and many more. Click the question mark icon at the right side of the Subject field to view a list of available variables. To reset your entry, click the Reset link just above the question mark icon. - **Body**: Customize the email body text by entering the desired text. You can also enter variables according to your preference. Click the question mark icon at the right side of the Subject field to view a list of available variables. To reset your entry, click the Reset link just above the right hand side of the body text box. - **Toolbar**: Immediately below the body text box, there is a bar featuring all the formatting tools you need to customize your reminder email, including font style, font size, bold/italics/underline, strikethrough, font color, background color, numbering, bulleting, alignment and hyperlinks. +- **Raw**: You can customize your reminder email via raw HTML. Click the gray Raw button at the bottom right of the section. A window will open. Enter your HTML code. When you're done, click Update. +- **Preview**: Want to view the reminder email exactly as your client will see it? Preview your reminder email in a separate window at any time by clicking the blue Preview button. .. TIP:: Any changes you make to your reminder email settings will instantly appear in the preview at the right hand side of the page. See how your reminder email template will look as you are creating it, so you can get it just right. diff --git a/docs/update.rst b/docs/update.rst index 7c4419f31b0e..3bd00eb9c4cd 100644 --- a/docs/update.rst +++ b/docs/update.rst @@ -7,13 +7,13 @@ To update the app you just need to copy over the latest code. The app tracks the https://download.invoiceninja.com +If you have trouble updating you can manually load /update to check for errors. + .. TIP:: We recommend using this `shell script `_ to automate the update process, run it as a daily cron to automatically keep your app up to date. If you're moving servers make sure to copy over the .env file. -If the auto-update fails you can manually run the update with the following commands. Once completed add ``?clear_cache=true`` to the end of the URL to clear the application cache. - -A common error with shared hosting is "open_basedir restriction in effect", if you see this you'll need to either temporarily modify your open_basedir settings or run the update from the command line. +You can manually run the update with the following commands. Once completed add ``?clear_cache=true`` to the end of the URL to clear the application cache. .. code-block:: shell @@ -22,6 +22,8 @@ A common error with shared hosting is "open_basedir restriction in effect", if y php artisan migrate php artisan db:seed --class=UpdateSeeder +A common error with shared hosting is "open_basedir restriction in effect", if you see this you'll need to either temporarily modify your open_basedir settings or run the update from the command line. + .. NOTE:: If you've downloaded the code from GitHub you also need to run ``composer install`` .. TIP:: You can see the detailed changes for each release on our `GitHub release notes `_. diff --git a/gulpfile.js b/gulpfile.js index 2052565cbb01..87fdc04d2dc3 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -67,6 +67,11 @@ elixir(function(mix) { bowerDir + '/bootstrap-daterangepicker/daterangepicker.css' ], 'public/css/daterangepicker.css'); + mix.styles([ + bowerDir + '/grapesjs/dist/css/grapes.min.css', + //'grapesjs-preset-newsletter.css', + ], 'public/css/grapesjs.css'); + mix.styles([ bowerDir + '/jt.timepicker/jquery.timepicker.css' ], 'public/css/jquery.timepicker.css'); @@ -103,6 +108,12 @@ elixir(function(mix) { bowerDir + '/bootstrap-daterangepicker/daterangepicker.js' ], 'public/js/daterangepicker.min.js'); + mix.scripts([ + bowerDir + '/grapesjs/dist/grapes.js', + 'grapesjs-blocks-basic.min.js', + 'grapesjs-preset-newsletter.min.js', + ], 'public/js/grapesjs.min.js'); + mix.scripts([ bowerDir + '/jt.timepicker/jquery.timepicker.js' ], 'public/js/jquery.timepicker.js'); @@ -125,6 +136,7 @@ elixir(function(mix) { bowerDir + '/tablesorter/dist/js/widgets/widget-grouping.min.js', bowerDir + '/tablesorter/dist/js/widgets/widget-uitheme.min.js', bowerDir + '/tablesorter/dist/js/widgets/widget-filter.min.js', + bowerDir + '/tablesorter/dist/js/widgets/widget-columnSelector.min.js', ], 'public/js/tablesorter.min.js'); mix.scripts([ diff --git a/public/built.js b/public/built.js index e6becc70370e..6646bc63da84 100644 --- a/public/built.js +++ b/public/built.js @@ -1,28 +1,28 @@ -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));if(refreshTimer=null,t=calculateAmounts(t),parseInt(t.account.signature_on_pdf)&&(t=convertSignature(t)),!t)return!1;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=_.escape(n),n=n.replace(new RegExp("("+e+")","ig"),function(t,n){return n?""+n+"":e}),n.replace(new RegExp("\n","g"),"
    ")}function inIframe(){try{return window.self!==window.top}catch(t){return!0}}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 formatAddress(t,e,n,i){var o="";return i?(o+=n?n+" ":"",o+=t?t:"",o+=t&&e?", ":t?" ":"",o+=e):(o+=t?t:"",o+=t&&e?", ":e?" ":"",o+=e+" "+n),o}function concatStrings(){for(var t="",e=[],n=0;n1?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 getPrecision(t){return roundToPrecision(t,3)!=t?4:roundToPrecision(t,2)!=t?3:2}function roundSignificant(t,e){var n=getPrecision(t),i=roundToPrecision(t,n)||0;return e?i.toFixed(n):i}function roundToTwo(t,e){var n=roundToPrecision(t,2)||0;return e?n.toFixed(2):n}function roundToFour(t,e){var n=roundToPrecision(t,4)||0;return e?n.toFixed(4):n}function roundToPrecision(t,e){var n=t<0;return n&&(t*=-1),t=+(Math.round(t+"e+"+e)+"e-"+e),n&&(t*=-1),t}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 brewerColor(t){var e=["#1c9f77","#d95d02","#716cb1","#e62a8b","#5fa213","#e6aa04","#a87821","#676767"],t=(t-1)%e.length;return e[t]}function formatXml(t){var e="",n=/(>)(<)(\/*)/g;t=t.replace(n,"$1\r\n$2$3");var i=0;return jQuery.each(t.split("\r\n"),function(t,n){var o=0;n.match(/.+<\/\w[^>]*>$/)?o=0:n.match(/^<\/\w/)?0!=i&&(i-=1):o=n.match(/^<\w[^>]*[^\/]>.*$/)?1:0;for(var a="",s=0;s0&&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(ht.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 d(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 h(){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!==zt?t.getElementsByTagName(e||"*"):typeof t.querySelectorAll!==zt?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 _(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 N(t,e){if(e in t)return e;for(var n=e.charAt(0).toUpperCase()+e.slice(1),i=e,o=he.length;o--;)if(e=he[o]+n,e in t)return e;return i}function O(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(;a_.cacheLength&&delete t[e.shift()],t[n+" "]=i}var e=[];return t}function i(t){return t[P]=!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--;)_.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 d(){}function h(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]=d))}}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=_.relative[t[0].type],s=a||_.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!==O)||((e=n).nodeType?c(t,n,i):l(t,n,i));return e=null,o}];r1&&f(u),r>1&&h(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,d,h,p=0,f="0",m=i&&[],b=[],v=O,M=i||a&&_.find.TAG("*",l),y=R+=null==v?1:Math.random()||.1,A=M.length;for(l&&(O=s!==D&&s);f!==A&&null!=(u=M[f]);f++){if(a&&u){for(d=0;h=t[d++];)if(h(u,s,r)){c.push(u);break}l&&(R=y)}o&&((u=!h&&u)&&p--,i&&m.push(u))}if(p+=f,o&&f!==p){for(d=0;h=n[d++];)h(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,O=v),m};return o?i(s):s}var y,A,_,z,T,w,C,N,O,S,x,L,D,k,q,W,E,B,I,P="sizzle"+1*new Date,X=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+"*"),dt=new RegExp("="+nt+"*([^\\]'\"]*?)"+nt+"*\\]","g"),ht=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"),_t=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)},zt=function(){L()};try{Q.apply(J=Z.call(X.childNodes),X.childNodes),J[X.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:X;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",zt,!1):n.attachEvent&&n.attachEvent("onunload",zt)),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=P,!i.getElementsByName||!i.getElementsByName(P).length}),A.getById?(_.find.ID=function(t,e){if("undefined"!=typeof e.getElementById&&q){var n=e.getElementById(t);return n&&n.parentNode?[n]:[]}},_.filter.ID=function(t){var e=t.replace(At,_t);return function(t){return t.getAttribute("id")===e}}):(delete _.find.ID,_.filter.ID=function(t){var e=t.replace(At,_t);return function(t){var n="undefined"!=typeof t.getAttributeNode&&t.getAttributeNode("id");return n&&n.value===e}}),_.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},_.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~="+P+"-]").length||W.push("~="),t.querySelectorAll(":checked").length||W.push(":checked"),t.querySelectorAll("a#"+P+"+*").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===X&&I(X,t)?-1:e===i||e.ownerDocument===X&&I(X,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]===X?-1:l[o]===X?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(dt,"='$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=_.attrHandle[e.toLowerCase()],i=n&&Y.call(_.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},z=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+=z(t)}else if(3===o||4===o)return t.nodeValue}else for(;e=t[i++];)n+=z(e);return n},_=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,_t),t[3]=(t[3]||t[4]||t[5]||"").replace(At,_t),"~="===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&&ht.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,_t).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,d,h,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(d=e;d=d[m];)if(r?d.nodeName.toLowerCase()===b:1===d.nodeType)return!1;f=m="only"===t&&!f&&"nextSibling"}return!0}if(f=[s?g.firstChild:g.lastChild],s&&v){for(u=g[P]||(g[P]={}),l=u[t]||[],p=l[0]===R&&l[1],h=l[0]===R&&l[2],d=p&&g.childNodes[p];d=++p&&d&&d[m]||(h=p=0)||f.pop();)if(1===d.nodeType&&++h&&d===e){u[t]=[R,p,h];break}}else if(v&&(l=(e[P]||(e[P]={}))[t])&&l[0]===R)h=l[1];else for(;(d=++p&&d&&d[m]||(h=p=0)||f.pop())&&((r?d.nodeName.toLowerCase()!==b:1!==d.nodeType)||!++h||(v&&((d[P]||(d[P]={}))[t]=[R,h]),d!==e)););return h-=o,h===i||h%i===0&&h/i>=0}}},PSEUDO:function(t,n){var o,a=_.pseudos[t]||_.setFilters[t.toLowerCase()]||e.error("unsupported pseudo: "+t);return a[P]?a(n):a.length>1?(o=[t,t,"",n],_.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[P]?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,_t),function(e){return(e.textContent||e.innerText||z(e)).indexOf(t)>-1}}),lang:i(function(t){return pt.test(t||"")||e.error("unsupported lang: "+t),t=t.replace(At,_t).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!_.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&&_.relative[a[1].type]){if(e=(_.find.ID(s.matches[0].replace(At,_t),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],!_.relative[r=s.type]);)if((c=_.find[r])&&(i=c(s.matches[0].replace(At,_t),Mt.test(a[0].type)&&u(e.parentNode)||e))){if(a.splice(o,1),t=i.length&&h(a),!t)return Q.apply(n,i),n;break}}return(l||C(t,d))(i,e,!q,n,Mt.test(t)&&u(e.parentNode)||e),n},A.sortStable=P.split("").sort($).join("")===P,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,dt=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,ht=/^.[^:#\[\.,]*$/;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)),dt.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||d.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 d.fireWith(this,arguments),this},fired:function(){return!!i}};return d},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 _t,zt="undefined";for(_t in ot(nt))break;nt.ownLast="0"!==_t,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!==zt&&(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 d(t,e)},_data:function(t,e,n){return u(t,e,n,!0)},_removeData:function(t,e){return d(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,d,h,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===zt||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]||{},d=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),(h=s[p])||(h=s[p]=[],h.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,d),d.handler.guid||(d.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,d):h.push(d),ot.event.global[p]=!0);t=null}},remove:function(t,e,n,i,o){var a,s,r,c,l,u,d,h,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(d=ot.event.special[p]||{},p=(i?d.delegateType:d.bindType)||p,h=u[p]||[],r=r[2]&&new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"),c=a=h.length;a--;)s=h[a],!o&&m!==s.origType||n&&n.guid!==s.guid||r&&!r.test(s.namespace)||i&&i!==s.selector&&("**"!==i||!s.selector)||(h.splice(a,1),s.selector&&h.delegateCount--,d.remove&&d.remove.call(t,s));c&&!h.length&&(d.teardown&&d.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,d,h=[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)h.push(r),u=r;u===(i.ownerDocument||ft)&&h.push(u.defaultView||u.parentWindow||t)}for(d=0;(r=h[d++])&&!e.isPropagationStopped();)e.type=d>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(h.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"),Pt=/^\s+/,Xt=/<(?!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]&&z(o,i[s]);if(e)if(n)for(r=r||g(t),i=i||g(a),s=0;null!=(o=r[s]);s++)_(o,i[s]);else _(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,d=t.length,h=m(e),p=[],f=0;f")+u[2],o=u[0];o--;)r=r.lastChild;if(!nt.leadingWhitespace&&Pt.test(a)&&p.push(e.createTextNode(Pt.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=h.lastChild}else p.push(e.createTextNode(a));for(r&&h.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(h.appendChild(a),"script"),s&&A(r),n))for(o=0;a=r[o++];)$t.test(a.type||"")&&n.push(a);return r=null,h},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!==zt?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||!Pt.test(t))&&!Jt[(Rt.exec(t)||["",""])[1].toLowerCase()]){t=t.replace(Xt,"<$1>");try{for(;n1&&"string"==typeof h&&!nt.checkClone&&Ut.test(h))return this.each(function(n){var i=u.eq(n);p&&(t[0]=h.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"},de={letterSpacing:"0",fontWeight:"400"},he=["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]=N(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]=N(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 de&&(a=de[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+Nt[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 O(this,!0)},hide:function(){return O(this)},toggle:function(t){return"boolean"==typeof t?t?this.show():this.hide():this.each(function(){Ot(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,_e,ze=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===zt?ot.prop(t,e,n):(1===a&&ot.isXMLDoc(t)||(e=e.toLowerCase(),i=ot.attrHooks[e]||(ot.expr.match.bool.test(e)?_e: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}}}}}),_e={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=ze[e]||ot.find.attr;ze[e]=Ce&&we||!Te.test(e)?function(t,e,i){var o,a;return i||(a=ze[e],ze[e]=o,o=null!=n(t,e,i)?e.toLowerCase():null,ze[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}},ze.id=ze.name=ze.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 Ne=/^(?:input|select|textarea|button|object)$/i,Oe=/^(?: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):Ne.test(t.nodeName)||Oe.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!==zt&&"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):$/,Pe=/^(?:GET|HEAD)$/,Xe=/^\/\//,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:P(Fe),ajaxTransport:P(He),ajax:function(t,e){function n(t,e,n,i){var o,u,b,v,y,_=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(d,A,n)),v=H(d,v,A,o),o?(d.ifModified&&(y=A.getResponseHeader("Last-Modified"),y&&(ot.lastModified[a]=y),y=A.getResponseHeader("etag"),y&&(ot.etag[a]=y)),204===t||"HEAD"===d.type?_="nocontent":304===t?_="notmodified":(_=v.state,u=v.data,b=v.error,o=!b)):(b=_,!t&&_||(_="error",t<0&&(t=0))),A.status=t,A.statusText=(e||_)+"",o?f.resolveWith(h,[u,_,A]):f.rejectWith(h,[A,_,b]),A.statusCode(g),g=void 0,c&&p.trigger(o?"ajaxSuccess":"ajaxError",[A,d,o?u:b]),m.fireWith(h,[A,_]),c&&(p.trigger("ajaxComplete",[A,d]),--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,d=ot.ajaxSetup({},e),h=d.context||d,p=d.context&&(h.nodeType||h.jquery)?ot(h):ot.event,f=ot.Deferred(),m=ot.Callbacks("once memory"),g=d.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||(d.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,d.url=((t||d.url||qe)+"").replace(We,"").replace(Xe,ke[1]+"//"),d.type=e.method||e.type||d.method||d.type,d.dataTypes=ot.trim(d.dataType||"*").toLowerCase().match(Mt)||[""],null==d.crossDomain&&(i=Re.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===ke[1]&&i[2]===ke[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(ke[3]||("http:"===ke[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=ot.param(d.data,d.traditional)),X(Fe,d,e,A),2===M)return A;c=ot.event&&d.global,c&&0===ot.active++&&ot.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Pe.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(Le.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Ee.test(a)?a.replace(Ee,"$1_="+xe++):a+(Le.test(a)?"&":"?")+"_="+xe++)),d.ifModified&&(ot.lastModified[a]&&A.setRequestHeader("If-Modified-Since",ot.lastModified[a]),ot.etag[a]&&A.setRequestHeader("If-None-Match",ot.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||e.contentType)&&A.setRequestHeader("Content-Type",d.contentType),A.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+je+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)A.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(h,A,d)===!1||2===M))return A.abort();y="abort";for(o in{success:1,error:1,complete:1})A[o](d[o]);if(l=X(He,d,e,A)){A.readyState=1,c&&p.trigger("ajaxSend",[A,d]),d.async&&d.timeout>0&&(r=setTimeout(function(){A.abort("timeout")},d.timeout));try{M=1,l.send(b,n)}catch(_){if(!(M<2))throw _;n(-1,_)}}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=dt.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"),d=ot(t),h={};"static"===u&&(t.style.position="relative"),r=d.offset(),a=ot.css(t,"top"),c=ot.css(t,"left"),l=("absolute"===u||"fixed"===u)&&ot.inArray("auto",[a,c])>-1,l?(i=d.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&&(h.top=e.top-r.top+s),null!=e.left&&(h.left=e.left-r.left+o),"using"in e?e.using.call(t,h):d.css(h)}},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!==zt&&(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===zt&&(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;a1?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=_.escape(n),n=n.replace(new RegExp("("+e+")","ig"),function(t,n){return n?""+n+"":e}),n.replace(new RegExp("\n","g"),"
    ")}function inIframe(){try{return window.self!==window.top}catch(t){return!0}}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 formatAddress(t,e,n,i){var o="";return i?(o+=n?n+" ":"",o+=t?t:"",o+=t&&e?", ":t?" ":"",o+=e):(o+=t?t:"",o+=t&&e?", ":e?" ":"",o+=e+" "+n),o}function concatStrings(){for(var t="",e=[],n=0;n1?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 getPrecision(t){return roundToPrecision(t,3)!=t?4:roundToPrecision(t,2)!=t?3:2}function roundSignificant(t,e){var n=getPrecision(t),i=roundToPrecision(t,n)||0;return e?i.toFixed(n):i}function roundToTwo(t,e){var n=roundToPrecision(t,2)||0;return e?n.toFixed(2):n}function roundToFour(t,e){var n=roundToPrecision(t,4)||0;return e?n.toFixed(4):n}function roundToPrecision(t,e){var n=t<0;return n&&(t*=-1),t=+(Math.round(t+"e+"+e)+"e-"+e),n&&(t*=-1),t}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 brewerColor(t){var e=["#1c9f77","#d95d02","#716cb1","#e62a8b","#5fa213","#e6aa04","#a87821","#676767"],t=(t-1)%e.length;return e[t]}function formatXml(t){var e="",n=/(>)(<)(\/*)/g;t=t.replace(n,"$1\r\n$2$3");var i=0;return jQuery.each(t.split("\r\n"),function(t,n){var o=0;n.match(/.+<\/\w[^>]*>$/)?o=0:n.match(/^<\/\w/)?0!=i&&(i-=1):o=n.match(/^<\w[^>]*[^\/]>.*$/)?1:0;for(var a="",s=0;s0&&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(ht.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]=J.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 d(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 h(){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!==zt?t.getElementsByTagName(e||"*"):typeof t.querySelectorAll!==zt?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 _(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 N(t,e){if(e in t)return e;for(var n=e.charAt(0).toUpperCase()+e.slice(1),i=e,o=he.length;o--;)if(e=he[o]+n,e in t)return e;return i}function O(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(;a_.cacheLength&&delete t[e.shift()],t[n+" "]=i}var e=[];return t}function i(t){return t[P]=!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--;)_.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 d(){}function h(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]=d))}}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=_.relative[t[0].type],s=a||_.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!==O)||((e=n).nodeType?c(t,n,i):l(t,n,i));return e=null,o}];r1&&f(u),r>1&&h(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,d,h,p=0,f="0",m=i&&[],b=[],v=O,M=i||a&&_.find.TAG("*",l),y=R+=null==v?1:Math.random()||.1,A=M.length;for(l&&(O=s!==D&&s);f!==A&&null!=(u=M[f]);f++){if(a&&u){for(d=0;h=t[d++];)if(h(u,s,r)){c.push(u);break}l&&(R=y)}o&&((u=!h&&u)&&p--,i&&m.push(u))}if(p+=f,o&&f!==p){for(d=0;h=n[d++];)h(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,O=v),m};return o?i(s):s}var y,A,_,z,T,w,C,N,O,S,x,L,D,k,q,W,E,B,I,P="sizzle"+1*new Date,X=t.document,R=0,F=0,H=n(),j=n(),U=n(),$=function(t,e){return t===e&&(x=!0),0},V=1<<31,J={}.hasOwnProperty,Y=[],K=Y.pop,G=Y.push,Q=Y.push,Z=Y.slice,tt=function(t,e){for(var n=0,i=t.length;n+~]|"+nt+")"+nt+"*"),dt=new RegExp("="+nt+"*([^\\]'\"]*?)"+nt+"*\\]","g"),ht=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"),_t=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)},zt=function(){L()};try{Q.apply(Y=Z.call(X.childNodes),X.childNodes),Y[X.childNodes.length].nodeType}catch(Tt){Q={apply:Y.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:X;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",zt,!1):n.attachEvent&&n.attachEvent("onunload",zt)),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=P,!i.getElementsByName||!i.getElementsByName(P).length}),A.getById?(_.find.ID=function(t,e){if("undefined"!=typeof e.getElementById&&q){var n=e.getElementById(t);return n&&n.parentNode?[n]:[]}},_.filter.ID=function(t){var e=t.replace(At,_t);return function(t){return t.getAttribute("id")===e}}):(delete _.find.ID,_.filter.ID=function(t){var e=t.replace(At,_t);return function(t){var n="undefined"!=typeof t.getAttributeNode&&t.getAttributeNode("id");return n&&n.value===e}}),_.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},_.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~="+P+"-]").length||W.push("~="),t.querySelectorAll(":checked").length||W.push(":checked"),t.querySelectorAll("a#"+P+"+*").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===X&&I(X,t)?-1:e===i||e.ownerDocument===X&&I(X,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]===X?-1:l[o]===X?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(dt,"='$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=_.attrHandle[e.toLowerCase()],i=n&&J.call(_.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},z=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+=z(t)}else if(3===o||4===o)return t.nodeValue}else for(;e=t[i++];)n+=z(e);return n},_=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,_t),t[3]=(t[3]||t[4]||t[5]||"").replace(At,_t),"~="===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&&ht.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,_t).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,d,h,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(d=e;d=d[m];)if(r?d.nodeName.toLowerCase()===b:1===d.nodeType)return!1;f=m="only"===t&&!f&&"nextSibling"}return!0}if(f=[s?g.firstChild:g.lastChild],s&&v){for(u=g[P]||(g[P]={}),l=u[t]||[],p=l[0]===R&&l[1],h=l[0]===R&&l[2],d=p&&g.childNodes[p];d=++p&&d&&d[m]||(h=p=0)||f.pop();)if(1===d.nodeType&&++h&&d===e){u[t]=[R,p,h];break}}else if(v&&(l=(e[P]||(e[P]={}))[t])&&l[0]===R)h=l[1];else for(;(d=++p&&d&&d[m]||(h=p=0)||f.pop())&&((r?d.nodeName.toLowerCase()!==b:1!==d.nodeType)||!++h||(v&&((d[P]||(d[P]={}))[t]=[R,h]),d!==e)););return h-=o,h===i||h%i===0&&h/i>=0}}},PSEUDO:function(t,n){var o,a=_.pseudos[t]||_.setFilters[t.toLowerCase()]||e.error("unsupported pseudo: "+t);return a[P]?a(n):a.length>1?(o=[t,t,"",n],_.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[P]?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,_t),function(e){return(e.textContent||e.innerText||z(e)).indexOf(t)>-1}}),lang:i(function(t){return pt.test(t||"")||e.error("unsupported lang: "+t),t=t.replace(At,_t).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!_.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&&_.relative[a[1].type]){if(e=(_.find.ID(s.matches[0].replace(At,_t),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],!_.relative[r=s.type]);)if((c=_.find[r])&&(i=c(s.matches[0].replace(At,_t),Mt.test(a[0].type)&&u(e.parentNode)||e))){if(a.splice(o,1),t=i.length&&h(a),!t)return Q.apply(n,i),n;break}}return(l||C(t,d))(i,e,!q,n,Mt.test(t)&&u(e.parentNode)||e),n},A.sortStable=P.split("").sort($).join("")===P,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,dt=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,ht=/^.[^:#\[\.,]*$/;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)),dt.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||d.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 d.fireWith(this,arguments),this},fired:function(){return!!i}};return d},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=Y.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?Y.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 _t,zt="undefined";for(_t in ot(nt))break;nt.ownLast="0"!==_t,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!==zt&&(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 d(t,e)},_data:function(t,e,n){return u(t,e,n,!0)},_removeData:function(t,e){return d(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,d,h,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===zt||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]||{},d=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),(h=s[p])||(h=s[p]=[],h.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,d),d.handler.guid||(d.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,d):h.push(d),ot.event.global[p]=!0);t=null}},remove:function(t,e,n,i,o){var a,s,r,c,l,u,d,h,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(d=ot.event.special[p]||{},p=(i?d.delegateType:d.bindType)||p,h=u[p]||[],r=r[2]&&new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"),c=a=h.length;a--;)s=h[a],!o&&m!==s.origType||n&&n.guid!==s.guid||r&&!r.test(s.namespace)||i&&i!==s.selector&&("**"!==i||!s.selector)||(h.splice(a,1),s.selector&&h.delegateCount--,d.remove&&d.remove.call(t,s));c&&!h.length&&(d.teardown&&d.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,d,h=[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)h.push(r),u=r;u===(i.ownerDocument||ft)&&h.push(u.defaultView||u.parentWindow||t)}for(d=0;(r=h[d++])&&!e.isPropagationStopped();)e.type=d>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(h.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=Y.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"),Pt=/^\s+/,Xt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Rt=/<([\w:]+)/,Ft=/\s*$/g,Yt={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"));Yt.optgroup=Yt.option,Yt.tbody=Yt.tfoot=Yt.colgroup=Yt.caption=Yt.thead,Yt.th=Yt.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]&&z(o,i[s]);if(e)if(n)for(r=r||g(t),i=i||g(a),s=0;null!=(o=r[s]);s++)_(o,i[s]);else _(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,d=t.length,h=m(e),p=[],f=0;f")+u[2],o=u[0];o--;)r=r.lastChild;if(!nt.leadingWhitespace&&Pt.test(a)&&p.push(e.createTextNode(Pt.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=h.lastChild}else p.push(e.createTextNode(a));for(r&&h.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(h.appendChild(a),"script"),s&&A(r),n))for(o=0;a=r[o++];)$t.test(a.type||"")&&n.push(a);return r=null,h},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!==zt?n.removeAttribute(r):n[r]=null,J.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||!Pt.test(t))&&!Yt[(Rt.exec(t)||["",""])[1].toLowerCase()]){t=t.replace(Xt,"<$1>");try{for(;n1&&"string"==typeof h&&!nt.checkClone&&Ut.test(h))return this.each(function(n){var i=u.eq(n);p&&(t[0]=h.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"},de={letterSpacing:"0",fontWeight:"400"},he=["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]=N(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]=N(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 de&&(a=de[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+Nt[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 O(this,!0)},hide:function(){return O(this)},toggle:function(t){return"boolean"==typeof t?t?this.show():this.hide():this.each(function(){Ot(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,_e,ze=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===zt?ot.prop(t,e,n):(1===a&&ot.isXMLDoc(t)||(e=e.toLowerCase(),i=ot.attrHooks[e]||(ot.expr.match.bool.test(e)?_e: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}}}}}),_e={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=ze[e]||ot.find.attr;ze[e]=Ce&&we||!Te.test(e)?function(t,e,i){var o,a;return i||(a=ze[e],ze[e]=o,o=null!=n(t,e,i)?e.toLowerCase():null,ze[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}},ze.id=ze.name=ze.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 Ne=/^(?:input|select|textarea|button|object)$/i,Oe=/^(?: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):Ne.test(t.nodeName)||Oe.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!==zt&&"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):$/,Pe=/^(?:GET|HEAD)$/,Xe=/^\/\//,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:P(Fe),ajaxTransport:P(He),ajax:function(t,e){function n(t,e,n,i){var o,u,b,v,y,_=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(d,A,n)),v=H(d,v,A,o),o?(d.ifModified&&(y=A.getResponseHeader("Last-Modified"),y&&(ot.lastModified[a]=y),y=A.getResponseHeader("etag"),y&&(ot.etag[a]=y)),204===t||"HEAD"===d.type?_="nocontent":304===t?_="notmodified":(_=v.state,u=v.data,b=v.error,o=!b)):(b=_,!t&&_||(_="error",t<0&&(t=0))),A.status=t,A.statusText=(e||_)+"",o?f.resolveWith(h,[u,_,A]):f.rejectWith(h,[A,_,b]),A.statusCode(g),g=void 0,c&&p.trigger(o?"ajaxSuccess":"ajaxError",[A,d,o?u:b]),m.fireWith(h,[A,_]),c&&(p.trigger("ajaxComplete",[A,d]),--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,d=ot.ajaxSetup({},e),h=d.context||d,p=d.context&&(h.nodeType||h.jquery)?ot(h):ot.event,f=ot.Deferred(),m=ot.Callbacks("once memory"),g=d.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||(d.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,d.url=((t||d.url||qe)+"").replace(We,"").replace(Xe,ke[1]+"//"),d.type=e.method||e.type||d.method||d.type,d.dataTypes=ot.trim(d.dataType||"*").toLowerCase().match(Mt)||[""],null==d.crossDomain&&(i=Re.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===ke[1]&&i[2]===ke[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(ke[3]||("http:"===ke[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=ot.param(d.data,d.traditional)),X(Fe,d,e,A),2===M)return A;c=ot.event&&d.global,c&&0===ot.active++&&ot.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Pe.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(Le.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Ee.test(a)?a.replace(Ee,"$1_="+xe++):a+(Le.test(a)?"&":"?")+"_="+xe++)),d.ifModified&&(ot.lastModified[a]&&A.setRequestHeader("If-Modified-Since",ot.lastModified[a]),ot.etag[a]&&A.setRequestHeader("If-None-Match",ot.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||e.contentType)&&A.setRequestHeader("Content-Type",d.contentType),A.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+je+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)A.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(h,A,d)===!1||2===M))return A.abort();y="abort";for(o in{success:1,error:1,complete:1})A[o](d[o]);if(l=X(He,d,e,A)){A.readyState=1,c&&p.trigger("ajaxSend",[A,d]),d.async&&d.timeout>0&&(r=setTimeout(function(){A.abort("timeout")},d.timeout));try{M=1,l.send(b,n)}catch(_){if(!(M<2))throw _;n(-1,_)}}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=/\[\]$/,Je=/\r?\n/g,Ye=/^(?: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)&&!Ye.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(Je,"\r\n")}}):{name:e.name,value:n.replace(Je,"\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=dt.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"),d=ot(t),h={};"static"===u&&(t.style.position="relative"),r=d.offset(),a=ot.css(t,"top"),c=ot.css(t,"left"),l=("absolute"===u||"fixed"===u)&&ot.inArray("auto",[a,c])>-1,l?(i=d.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&&(h.top=e.top-r.top+s),null!=e.left&&(h.left=e.left-r.left+o),"using"in e?e.using.call(t,h):d.css(h)}},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!==zt&&(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===zt&&(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/,d=/[\+\-]\d+(\.[\d]+)?%?/,h=/^\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(N,{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,d=l+e.collisionWidth-s-c,h="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+h+p+f+e.collisionWidth-s-a,(n<0||n0&&(i=t.left-e.collisionPosition.marginLeft+h+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>d&&(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("
    ");var r=t("a",n),c=r[0],l=r[1],u=r[2],d=r[3];e.oApi._fnBindAction(c,{action:"first"},s),e.oApi._fnBindAction(l,{action:"previous"},s),e.oApi._fnBindAction(u,{action:"next"},s),e.oApi._fnBindAction(d,{action:"last"},s),e.aanFeatures.p||(n.id=e.sTableId+"_paginate",c.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",u.id=e.sTableId+"_next",d.id=e.sTableId+"_last")},fnUpdate:function(e,n){if(e.aanFeatures.p){var i,o,a,s,r,c=e.oInstance.fnPagingInfo(),l=t.fn.dataTableExt.oPagination.iFullNumbersShowPages,u=Math.floor(l/2),d=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),h=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,p="",f=(e.oClasses,e.aanFeatures.p);for(e._iDisplayLength===-1?(i=1,o=1,h=1):d=d-u?(i=d-l+1,o=d):(i=h-Math.ceil(l/2)+1,o=i+l-1),a=i;a<=o;a++)p+=h!==a?'
  • '+e.fnFormatNumber(a)+"
  • ":'
  • '+e.fnFormatNumber(a)+"
  • ";for(a=0,s=f.length;a",o[0];);return 4d.a.l(e,t[n])&&e.push(t[n]);return e},ya:function(t,e){t=t||[];for(var n=[],i=0,o=t.length;ii?n&&t.push(e):n||t.splice(i,1)},na:l,extend:r,ra:c,sa:l?c:r,A:s,Oa:function(t,e){if(!t)return t;var n,i={};for(n in t)t.hasOwnProperty(n)&&(i[n]=e(t[n],n,t));return i},Fa:function(t){for(;t.firstChild;)d.removeNode(t.firstChild)},ec:function(t){t=d.a.R(t);for(var e=n.createElement("div"),i=0,o=t.length;if?t.setAttribute("selected",e):t.selected=e},ta:function(e){return null===e||e===t?"":e.trim?e.trim():e.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},oc:function(t,e){for(var n=[],i=(t||"").split(e),o=0,a=i.length;ot.length)&&t.substring(0,e.length)===e},Sb:function(t,e){if(t===e)return!0;if(11===t.nodeType)return!1;if(e.contains)return e.contains(3===t.nodeType?t.parentNode:t);if(e.compareDocumentPosition)return 16==(16&e.compareDocumentPosition(t));for(;t&&t!=e;)t=t.parentNode;return!!t},Ea:function(t){return d.a.Sb(t,t.ownerDocument.documentElement)},eb:function(t){return!!d.a.hb(t,d.a.Ea)},B:function(t){return t&&t.tagName&&t.tagName.toLowerCase()},q:function(t,e,n){var i=f&&p[e];if(!i&&o)o(t).bind(e,n);else if(i||"function"!=typeof t.addEventListener){if("undefined"==typeof t.attachEvent)throw Error("Browser doesn't support addEventListener or attachEvent");var a=function(e){n.call(t,e)},s="on"+e;t.attachEvent(s,a),d.a.u.ja(t,function(){t.detachEvent(s,a)})}else t.addEventListener(e,n,!1)},ha:function(t,i){if(!t||!t.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var a;if("input"===d.a.B(t)&&t.type&&"click"==i.toLowerCase()?(a=t.type,a="checkbox"==a||"radio"==a):a=!1,o&&!a)o(t).trigger(i);else if("function"==typeof n.createEvent){if("function"!=typeof t.dispatchEvent)throw Error("The supplied element doesn't support dispatchEvent");a=n.createEvent(h[i]||"HTMLEvents"),a.initEvent(i,!0,!0,e,0,0,0,0,0,!1,!1,!1,!1,0,t),t.dispatchEvent(a)}else if(a&&t.click)t.click();else{if("undefined"==typeof t.fireEvent)throw Error("Browser doesn't support triggering events");t.fireEvent("on"+i)}},c:function(t){return d.v(t)?t():t},Sa:function(t){return d.v(t)?t.o():t},ua:function(t,e,n){if(e){var i=/\S+/g,o=t.className.match(i)||[];d.a.r(e.match(i),function(t){d.a.Y(o,t,n)}),t.className=o.join(" ")}},Xa:function(e,n){var i=d.a.c(n);null!==i&&i!==t||(i="");var o=d.e.firstChild(e);!o||3!=o.nodeType||d.e.nextSibling(o)?d.e.U(e,[e.ownerDocument.createTextNode(i)]):o.data=i,d.a.Vb(e)},Cb:function(t,e){if(t.name=e,7>=f)try{t.mergeAttributes(n.createElement(""),!1)}catch(i){}},Vb:function(t){9<=f&&(t=1==t.nodeType?t:t.parentNode,t.style&&(t.style.zoom=t.style.zoom))},Tb:function(t){if(f){var e=t.style.width;t.style.width=0,t.style.width=e}},ic:function(t,e){t=d.a.c(t),e=d.a.c(e);for(var n=[],i=t;i<=e;i++)n.push(i);return n},R:function(t){for(var e=[],n=0,i=t.length;n=t-i&&"bottom"},n.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(n.RESET).addClass("affix");var t=this.$target.scrollTop(),e=this.$element.offset();return this.pinnedOffset=e.top-t},n.prototype.checkPositionWithEventLoop=function(){setTimeout(t.proxy(this.checkPosition,this),1)},n.prototype.checkPosition=function(){if(this.$element.is(":visible")){var e=this.$element.height(),i=this.options.offset,o=i.top,a=i.bottom,s=t("body").height();"object"!=typeof i&&(a=o=i),"function"==typeof o&&(o=i.top(this.$element)),"function"==typeof a&&(a=i.bottom(this.$element));var r=this.getState(s,e,o,a);if(this.affixed!=r){null!=this.unpin&&this.$element.css("top","");var c="affix"+(r?"-"+r:""),l=t.Event(c+".bs.affix");if(this.$element.trigger(l),l.isDefaultPrevented())return;this.affixed=r,this.unpin="bottom"==r?this.getPinnedOffset():null,this.$element.removeClass(n.RESET).addClass(c).trigger(c.replace("affix","affixed")+".bs.affix")}"bottom"==r&&this.$element.offset({top:s-e-a})}};var i=t.fn.affix;t.fn.affix=e,t.fn.affix.Constructor=n,t.fn.affix.noConflict=function(){return t.fn.affix=i,this},t(window).on("load",function(){t('[data-spy="affix"]').each(function(){var n=t(this),i=n.data();i.offset=i.offset||{},null!=i.offsetBottom&&(i.offset.bottom=i.offsetBottom),null!=i.offsetTop&&(i.offset.top=i.offsetTop),e.call(n,i)})})}(jQuery),function(t,e,n){!function(t){"use strict";"function"==typeof define&&define.amd?define("datatables",["jquery"],t):"object"==typeof exports?t(require("jquery")):jQuery&&!jQuery.fn.dataTable&&t(jQuery)}(function(i){"use strict";function o(t){var e,n,a="a aa ai ao as b fn i m o s ",s={};i.each(t,function(i,r){e=i.match(/^([^A-Z]+?)([A-Z])/),e&&a.indexOf(e[1]+" ")!==-1&&(n=i.replace(e[0],e[2].toLowerCase()),s[n]=i,"o"===e[1]&&o(t[i]))}),t._hungarianMap=s}function a(t,e,s){t._hungarianMap||o(t);var r;i.each(e,function(o,c){r=t._hungarianMap[o],r===n||!s&&e[r]!==n||("o"===r.charAt(0)?(e[r]||(e[r]={}),i.extend(!0,e[r],e[o]),a(t[r],e[r],s)):e[r]=e[o])})}function s(t){var e=Jt.defaults.oLanguage,n=t.sZeroRecords;!t.sEmptyTable&&n&&"No data available in table"===e.sEmptyTable&&Bt(t,t,"sZeroRecords","sEmptyTable"),!t.sLoadingRecords&&n&&"Loading..."===e.sLoadingRecords&&Bt(t,t,"sZeroRecords","sLoadingRecords"),t.sInfoThousands&&(t.sThousands=t.sInfoThousands);var i=t.sDecimal;i&&$t(i)}function r(t){ve(t,"ordering","bSort"),ve(t,"orderMulti","bSortMulti"),ve(t,"orderClasses","bSortClasses"),ve(t,"orderCellsTop","bSortCellsTop"),ve(t,"order","aaSorting"),ve(t,"orderFixed","aaSortingFixed"),ve(t,"paging","bPaginate"),ve(t,"pagingType","sPaginationType"),ve(t,"pageLength","iDisplayLength"),ve(t,"searching","bFilter");var e=t.aoSearchCols;if(e)for(var n=0,i=e.length;n").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(i("
    ").css({position:"absolute",top:1,left:1,width:100,overflow:"scroll"}).append(i('
    ').css({width:"100%",height:10}))).appendTo("body"),o=n.find(".test");e.bScrollOversize=100===o[0].offsetWidth,e.bScrollbarLeft=1!==o.offset().left,n.remove()}function u(t,e,i,o,a,s){var r,c=o,l=!1;for(i!==n&&(r=i,l=!0);c!==a;)t.hasOwnProperty(c)&&(r=l?e(r,t[c],c,t):t[c],l=!0,c+=s);return r}function d(t,n){var o=Jt.defaults.column,a=t.aoColumns.length,s=i.extend({},Jt.models.oColumn,o,{nTh:n?n:e.createElement("th"),sTitle:o.sTitle?o.sTitle:n?n.innerHTML:"",aDataSort:o.aDataSort?o.aDataSort:[a],mData:o.mData?o.mData:a,idx:a});t.aoColumns.push(s);var r=t.aoPreSearchCols;r[a]=i.extend({},Jt.models.oSearch,r[a]),h(t,a,null)}function h(t,e,o){var s=t.aoColumns[e],r=t.oClasses,l=i(s.nTh);if(!s.sWidthOrig){s.sWidthOrig=l.attr("width")||null;var u=(l.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);u&&(s.sWidthOrig=u[1])}o!==n&&null!==o&&(c(o),a(Jt.defaults.column,o),o.mDataProp===n||o.mData||(o.mData=o.mDataProp),o.sType&&(s._sManualType=o.sType),o.className&&!o.sClass&&(o.sClass=o.className),i.extend(s,o),Bt(s,o,"sWidth","sWidthOrig"),"number"==typeof o.iDataSort&&(s.aDataSort=[o.iDataSort]),Bt(s,o,"aDataSort"));var d=s.mData,h=N(d),p=s.mRender?N(s.mRender):null,f=function(t){return"string"==typeof t&&t.indexOf("@")!==-1};s._bAttrSrc=i.isPlainObject(d)&&(f(d.sort)||f(d.type)||f(d.filter)),s.fnGetData=function(t,e,i){var o=h(t,e,n,i);return p&&e?p(o,e,t,i):o},s.fnSetData=function(t,e,n){return O(d)(t,e,n)},"number"!=typeof d&&(t._rowReadObject=!0),t.oFeatures.bSort||(s.bSortable=!1,l.addClass(r.sSortableNone));var m=i.inArray("asc",s.asSorting)!==-1,g=i.inArray("desc",s.asSorting)!==-1;s.bSortable&&(m||g)?m&&!g?(s.sSortingClass=r.sSortableAsc,s.sSortingClassJUI=r.sSortJUIAscAllowed):!m&&g?(s.sSortingClass=r.sSortableDesc,s.sSortingClassJUI=r.sSortJUIDescAllowed):(s.sSortingClass=r.sSortable,s.sSortingClassJUI=r.sSortJUI):(s.sSortingClass=r.sSortableNone,s.sSortingClassJUI="")}function p(t){if(t.oFeatures.bAutoWidth!==!1){var e=t.aoColumns;vt(t);for(var n=0,i=e.length;n=0;s--){p=e[s];var m=p.targets!==n?p.targets:p.aTargets;for(i.isArray(m)||(m=[m]),c=0,l=m.length;c=0){for(;f.length<=m[c];)d(t);a(m[c],p)}else if("number"==typeof m[c]&&m[c]<0)a(f.length+m[c],p);else if("string"==typeof m[c])for(u=0,h=f.length;ue&&t[a]--;o!=-1&&i===n&&t.splice(o,1)}function D(t,e,i,o){var a,s,r=t.aoData[e],c=function(n,i){for(;n.childNodes.length;)n.removeChild(n.firstChild);n.innerHTML=T(t,e,i,"display")};if("dom"!==i&&(i&&"auto"!==i||"dom"!==r.src)){var l=r.anCells;if(l)if(o!==n)c(l[o],o);else for(a=0,s=l.length;a").appendTo(r)),e=0,n=d.length;etr").attr("role","row"),i(r).find(">tr>th, >tr>td").addClass(u.sHeaderTH),i(c).find(">tr>th, >tr>td").addClass(u.sFooterTH),null!==c){var h=t.aoFooter[0];for(e=0,n=h.length;e=0;r--)t.aoColumns[r].bVisible||o||f[a].splice(r,1);m.push([])}for(a=0,s=f.length;a=t.fnRecordsDisplay()?0:l,t.iInitDisplayStart=-1);var h=t._iDisplayStart,p=t.fnDisplayEnd();if(t.bDeferLoading)t.bDeferLoading=!1,t.iDraw++,ft(t,!1);else if(u){if(!t.bDestroying&&!j(t))return}else t.iDraw++;if(0!==d.length)for(var f=u?0:h,m=u?t.aoData.length:p,b=f;b",{"class":r?s[0]:""}).append(i("",{valign:"top",colSpan:g(t),"class":t.oClasses.sRowEmpty}).html(_))[0]}Rt(t,"aoHeaderCallback","header",[i(t.nTHead).children("tr")[0],S(t),h,p,d]),Rt(t,"aoFooterCallback","footer",[i(t.nTFoot).children("tr")[0],S(t),h,p,d]);var z=i(t.nTBody);z.children().detach(),z.append(i(o)),Rt(t,"aoDrawCallback","draw",[t]),t.bSorted=!1,t.bFiltered=!1,t.bDrawing=!1}function P(t,e){var n=t.oFeatures,i=n.bSort,o=n.bFilter;i&&Nt(t),o?Y(t,t.oPreviousSearch):t.aiDisplay=t.aiDisplayMaster.slice(),e!==!0&&(t._iDisplayStart=0),t._drawHold=e,I(t),t._drawHold=!1}function X(t){var e=t.oClasses,n=i(t.nTable),o=i("
    ").insertBefore(n),a=t.oFeatures,s=i("
    ",{id:t.sTableId+"_wrapper","class":e.sWrapper+(t.nTFoot?"":" "+e.sNoFooter)});t.nHolding=o[0],t.nTableWrapper=s[0],t.nTableReinsertBefore=t.nTable.nextSibling;for(var r,c,l,u,d,h,p=t.sDom.split(""),f=0;f")[0],u=p[f+1],"'"==u||'"'==u){for(d="",h=2;p[f+h]!=u;)d+=p[f+h],h++;if("H"==d?d=e.sJUIHeader:"F"==d&&(d=e.sJUIFooter),d.indexOf(".")!=-1){var m=d.split(".");l.id=m[0].substr(1,m[0].length-1),l.className=m[1]}else"#"==d.charAt(0)?l.id=d.substr(1,d.length-1):l.className=d;f+=h}s.append(l),s=i(l)}else if(">"==c)s=s.parent();else if("l"==c&&a.bPaginate&&a.bLengthChange)r=ut(t);else if("f"==c&&a.bFilter)r=J(t);else if("r"==c&&a.bProcessing)r=pt(t);else if("t"==c)r=mt(t);else if("i"==c&&a.bInfo)r=ot(t);else if("p"==c&&a.bPaginate)r=dt(t);else if(0!==Jt.ext.feature.length)for(var g=Jt.ext.feature,b=0,v=g.length;b',l=a.sSearch;l=l.match(/_INPUT_/)?l.replace("_INPUT_",c):l+c;var u=i("
    ",{id:r.f?null:o+"_filter","class":n.sFilter}).append(i("
    ").addClass(e.sLength);return t.aanFeatures.l||(d[0].id=n+"_length"),d.children().append(t.oLanguage.sLengthMenu.replace("_MENU_",c[0].outerHTML)),i("select",d).val(t._iDisplayLength).bind("change.DT",function(e){lt(t,i(this).val()),I(t)}),i(t.nTable).bind("length.dt.DT",function(e,n,o){t===n&&i("select",d).val(o)}),d[0]}function dt(t){var e=t.sPaginationType,n=Jt.ext.pager[e],o="function"==typeof n,a=function(t){I(t)},s=i("
    ").addClass(t.oClasses.sPaging+e)[0],r=t.aanFeatures;return o||n.fnInit(t,s,a),r.p||(s.id=t.sTableId+"_paginate",t.aoDrawCallback.push({fn:function(t){if(o){var e,i,s=t._iDisplayStart,c=t._iDisplayLength,l=t.fnRecordsDisplay(),u=c===-1,d=u?0:Math.ceil(s/c),h=u?1:Math.ceil(l/c),p=n(d,h);for(e=0,i=r.p.length;ea&&(i=0)):"first"==e?i=0:"previous"==e?(i=o>=0?i-o:0,i<0&&(i=0)):"next"==e?i+o",{id:t.aanFeatures.r?null:t.sTableId+"_processing","class":t.oClasses.sProcessing}).html(t.oLanguage.sProcessing).insertBefore(t.nTable)[0]}function ft(t,e){t.oFeatures.bProcessing&&i(t.aanFeatures.r).css("display",e?"block":"none"),Rt(t,null,"processing",[t,e])}function mt(t){var e=i(t.nTable);e.attr("role","grid");var n=t.oScroll;if(""===n.sX&&""===n.sY)return t.nTable;var o=n.sX,a=n.sY,s=t.oClasses,r=e.children("caption"),c=r.length?r[0]._captionSide:null,l=i(e[0].cloneNode(!1)),u=i(e[0].cloneNode(!1)),d=e.children("tfoot"),h="
    ",p=function(t){return t?Tt(t):null};n.sX&&"100%"===e.attr("width")&&e.removeAttr("width"),d.length||(d=null);var f=i(h,{"class":s.sScrollWrapper}).append(i(h,{"class":s.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:o?p(o):"100%"}).append(i(h,{"class":s.sScrollHeadInner}).css({"box-sizing":"content-box",width:n.sXInner||"100%"}).append(l.removeAttr("id").css("margin-left",0).append("top"===c?r:null).append(e.children("thead"))))).append(i(h,{"class":s.sScrollBody}).css({overflow:"auto",height:p(a),width:p(o)}).append(e));d&&f.append(i(h,{"class":s.sScrollFoot}).css({overflow:"hidden",border:0,width:o?p(o):"100%"}).append(i(h,{"class":s.sScrollFootInner}).append(u.removeAttr("id").css("margin-left",0).append("bottom"===c?r:null).append(e.children("tfoot")))));var m=f.children(),g=m[0],b=m[1],v=d?m[2]:null;return o&&i(b).scroll(function(t){var e=this.scrollLeft;g.scrollLeft=e,d&&(v.scrollLeft=e)}),t.nScrollHead=g,t.nScrollBody=b,t.nScrollFoot=v,t.aoDrawCallback.push({fn:gt,sName:"scrolling"}),f[0]}function gt(t){var e,n,o,a,s,r,c,l,u,d=t.oScroll,h=d.sX,p=d.sXInner,m=d.sY,g=d.iBarWidth,b=i(t.nScrollHead),v=b[0].style,M=b.children("div"),y=M[0].style,A=M.children("table"),_=t.nScrollBody,z=i(_),T=_.style,w=i(t.nScrollFoot),C=w.children("div"),N=C.children("table"),O=i(t.nTHead),S=i(t.nTable),x=S[0],L=x.style,D=t.nTFoot?i(t.nTFoot):null,k=t.oBrowser,q=k.bScrollOversize,W=[],E=[],B=[],I=function(t){var e=t.style;e.paddingTop="0",e.paddingBottom="0",e.borderTopWidth="0",e.borderBottomWidth="0",e.height=0};if(S.children("thead, tfoot").remove(),s=O.clone().prependTo(S),e=O.find("tr"),o=s.find("tr"),s.find("th, td").removeAttr("tabindex"),D&&(r=D.clone().prependTo(S),n=D.find("tr"),a=r.find("tr")),h||(T.width="100%",b[0].style.width="100%"),i.each(F(t,s),function(e,n){c=f(t,e),n.style.width=t.aoColumns[c].sWidth}),D&&bt(function(t){t.style.width=""},a),d.bCollapse&&""!==m&&(T.height=z[0].offsetHeight+O[0].offsetHeight+"px"),u=S.outerWidth(),""===h?(L.width="100%",q&&(S.find("tbody").height()>_.offsetHeight||"scroll"==z.css("overflow-y"))&&(L.width=Tt(S.outerWidth()-g))):""!==p?L.width=Tt(p):u==z.width()&&z.height()u-g&&(L.width=Tt(u))):L.width=Tt(u),u=S.outerWidth(),bt(I,o),bt(function(t){B.push(t.innerHTML),W.push(Tt(i(t).css("width")))},o),bt(function(t,e){t.style.width=W[e]},e),i(o).height(0),D&&(bt(I,a),bt(function(t){E.push(Tt(i(t).css("width")))},a),bt(function(t,e){t.style.width=E[e]},n),i(a).height(0)),bt(function(t,e){t.innerHTML='
    '+B[e]+"
    ",t.style.width=W[e]},o),D&&bt(function(t,e){t.innerHTML="",t.style.width=E[e]},a),S.outerWidth()_.offsetHeight||"scroll"==z.css("overflow-y")?u+g:u,q&&(_.scrollHeight>_.offsetHeight||"scroll"==z.css("overflow-y"))&&(L.width=Tt(l-g)),""!==h&&""===p||Et(t,1,"Possible column misalignment",6)):l="100%",T.width=Tt(l),v.width=Tt(l),D&&(t.nScrollFoot.style.width=Tt(l)),m||q&&(T.height=Tt(x.offsetHeight+g)),m&&d.bCollapse){T.height=Tt(m);var P=h&&x.offsetWidth>_.offsetWidth?g:0;x.offsetHeight<_.offsetHeight&&(T.height=Tt(x.offsetHeight+P))}var X=S.outerWidth();A[0].style.width=Tt(X),y.width=Tt(X);var R=S.height()>_.clientHeight||"scroll"==z.css("overflow-y"),H="padding"+(k.bScrollbarLeft?"Left":"Right");y[H]=R?g+"px":"0px",D&&(N[0].style.width=Tt(X),C[0].style.width=Tt(X),C[0].style[H]=R?g+"px":"0px"),z.scroll(),!t.bSorted&&!t.bFiltered||t._drawHold||(_.scrollTop=0)}function bt(t,e,n){for(var i,o,a=0,s=0,r=e.length;s"));z.find("tfoot th, tfoot td").css("width","");var T=z.find("tbody tr");for(M=F(e,z.find("thead")[0]),n=0;n").css("width",Tt(t)).appendTo(n||e.body),a=o[0].offsetWidth; +return o.remove(),a}function At(t,e){var n=t.oScroll;if(n.sX||n.sY){var o=n.sX?0:n.iBarWidth;e.style.width=Tt(i(e).outerWidth()-o)}}function _t(t,e){var n=zt(t,e);if(n<0)return null;var o=t.aoData[n];return o.nTr?o.anCells[e]:i("").html(T(t,n,e,"display"))[0]}function zt(t,e){for(var n,i=-1,o=-1,a=0,s=t.aoData.length;ai&&(i=n.length,o=a);return o}function Tt(t){return null===t?"0px":"number"==typeof t?t<0?"0px":t+"px":t.match(/\d$/)?t+"px":t}function wt(){if(!Jt.__scrollbarWidth){var t=i("

    ").css({width:"100%",height:200,padding:0})[0],e=i("

    ").css({position:"absolute",top:0,left:0,width:200,height:150,padding:0,overflow:"hidden",visibility:"hidden"}).append(t).appendTo("body"),n=t.offsetWidth;e.css("overflow","scroll");var o=t.offsetWidth;n===o&&(o=e[0].clientWidth),e.remove(),Jt.__scrollbarWidth=n-o}return Jt.__scrollbarWidth}function Ct(t){var e,o,a,s,r,c,l,u=[],d=t.aoColumns,h=t.aaSortingFixed,p=i.isPlainObject(h),f=[],m=function(t){t.length&&!i.isArray(t[0])?f.push(t):f.push.apply(f,t)};for(i.isArray(h)&&m(h),p&&h.pre&&m(h.pre),m(t.aaSorting),p&&h.post&&m(h.post),e=0;ei?1:0,0!==r)return"asc"===l.dir?r:-r;return n=s[t],i=s[e],ni?1:0}):u.sort(function(t,e){var n,i,o,l,u,d,h=a.length,p=c[t]._aSortData,f=c[e]._aSortData;for(o=0;oi?1:0})}t.bSorted=!0}function Ot(t){for(var e,n,i=t.aoColumns,o=Ct(t),a=t.oLanguage.oAria,s=0,r=i.length;s/g,""),d=c.nTh;d.removeAttribute("aria-sort"),c.bSortable?(o.length>0&&o[0].col==s?(d.setAttribute("aria-sort","asc"==o[0].dir?"ascending":"descending"),n=l[o[0].index+1]||l[0]):n=l[0],e=u+("asc"===n?a.sSortAscending:a.sSortDescending)):e=u,d.setAttribute("aria-label",e)}}function St(t,e,o,a){var s,r=t.aoColumns[e],c=t.aaSorting,l=r.asSorting,u=function(t,e){var o=t._idx;return o===n&&(o=i.inArray(t[1],l)),o+10&&s.time<+new Date-1e3*c)&&a.length===s.columns.length){for(t.oLoadedState=i.extend(!0,{},s),t._iDisplayStart=s.start,t.iInitDisplayStart=s.start,t._iDisplayLength=s.length,t.aaSorting=[],i.each(s.order,function(e,n){t.aaSorting.push(n[0]>=a.length?[0,n[1]]:n)}),i.extend(t.oPreviousSearch,it(s.search)),n=0,o=s.columns.length;n=n&&(e=n-i),e-=e%i,(i===-1||e<0)&&(e=0),t._iDisplayStart=e}function Ht(t,e){var n=t.renderer,o=Jt.ext.renderer[e];return i.isPlainObject(n)&&n[e]?o[n[e]]||o._:"string"==typeof n?o[n]||o._:o._}function jt(t){return t.oFeatures.bServerSide?"ssp":t.ajax||t.sAjaxSource?"ajax":"dom"}function Ut(t,e){var n=[],i=$e.numbers_length,o=Math.floor(i/2);return e<=i?n=fe(0,e):t<=o?(n=fe(0,i-2),n.push("ellipsis"),n.push(e-1)):t>=e-1-o?(n=fe(e-(i-2),e),n.splice(0,0,"ellipsis"),n.splice(0,0,0)):(n=fe(t-1,t+2),n.push("ellipsis"),n.push(e-1),n.splice(0,0,"ellipsis"),n.splice(0,0,0)),n.DT_el="span",n}function $t(t){i.each({num:function(e){return Ve(e,t)},"num-fmt":function(e){return Ve(e,t,ae)},"html-num":function(e){return Ve(e,t,ee)},"html-num-fmt":function(e){return Ve(e,t,ee,ae)}},function(e,n){Yt.type.order[e+t+"-pre"]=n,e.match(/^html\-/)&&(Yt.type.search[e+t]=Yt.type.search.html)})}function Vt(t){return function(){var e=[Wt(this[Jt.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return Jt.ext.internal[t].apply(this,e)}}var Jt,Yt,Kt,Gt,Qt,Zt={},te=/[\r\n]/g,ee=/<.*?>/g,ne=/^[\w\+\-]/,ie=/[\w\+\-]$/,oe=new RegExp("(\\"+["/",".","*","+","?","|","(",")","[","]","{","}","\\","$","^","-"].join("|\\")+")","g"),ae=/[',$£€¥%\u2009\u202F]/g,se=function(t){return!t||t===!0||"-"===t},re=function(t){var e=parseInt(t,10);return!isNaN(e)&&isFinite(t)?e:null},ce=function(t,e){return Zt[e]||(Zt[e]=new RegExp(tt(e),"g")),"string"==typeof t&&"."!==e?t.replace(/\./g,"").replace(Zt[e],"."):t},le=function(t,e,n){var i="string"==typeof t;return e&&i&&(t=ce(t,e)),n&&i&&(t=t.replace(ae,"")),se(t)||!isNaN(parseFloat(t))&&isFinite(t)},ue=function(t){return se(t)||"string"==typeof t},de=function(t,e,n){if(se(t))return!0;var i=ue(t);return i?!!le(ge(t),e,n)||null:null},he=function(t,e,i){var o=[],a=0,s=t.length;if(i!==n)for(;a")[0],_e=Ae.textContent!==n,ze=/<.*?>/g;Jt=function(t){this.$=function(t,e){return this.api(!0).$(t,e)},this._=function(t,e){return this.api(!0).rows(t,e).data()},this.api=function(t){return new Kt(t?Wt(this[Yt.iApiIndex]):this)},this.fnAddData=function(t,e){var o=this.api(!0),a=i.isArray(t)&&(i.isArray(t[0])||i.isPlainObject(t[0]))?o.rows.add(t):o.row.add(t);return(e===n||e)&&o.draw(),a.flatten().toArray()},this.fnAdjustColumnSizing=function(t){var e=this.api(!0).columns.adjust(),i=e.settings()[0],o=i.oScroll;t===n||t?e.draw(!1):""===o.sX&&""===o.sY||gt(i)},this.fnClearTable=function(t){var e=this.api(!0).clear();(t===n||t)&&e.draw()},this.fnClose=function(t){this.api(!0).row(t).child.hide()},this.fnDeleteRow=function(t,e,i){var o=this.api(!0),a=o.rows(t),s=a.settings()[0],r=s.aoData[a[0][0]];return a.remove(),e&&e.call(this,s,r),(i===n||i)&&o.draw(),r},this.fnDestroy=function(t){this.api(!0).destroy(t)},this.fnDraw=function(t){this.api(!0).draw(!t)},this.fnFilter=function(t,e,i,o,a,s){var r=this.api(!0);null===e||e===n?r.search(t,i,o,s):r.column(e).search(t,i,o,s),r.draw()},this.fnGetData=function(t,e){var i=this.api(!0);if(t!==n){var o=t.nodeName?t.nodeName.toLowerCase():"";return e!==n||"td"==o||"th"==o?i.cell(t,e).data():i.row(t).data()||null}return i.data().toArray()},this.fnGetNodes=function(t){var e=this.api(!0);return t!==n?e.row(t).node():e.rows().nodes().flatten().toArray()},this.fnGetPosition=function(t){var e=this.api(!0),n=t.nodeName.toUpperCase();if("TR"==n)return e.row(t).index();if("TD"==n||"TH"==n){var i=e.cell(t).index();return[i.row,i.columnVisible,i.column]}return null},this.fnIsOpen=function(t){return this.api(!0).row(t).child.isShown()},this.fnOpen=function(t,e,n){return this.api(!0).row(t).child(e,n).show().child()[0]},this.fnPageChange=function(t,e){var i=this.api(!0).page(t);(e===n||e)&&i.draw(!1)},this.fnSetColumnVis=function(t,e,i){var o=this.api(!0).column(t).visible(e);(i===n||i)&&o.columns.adjust().draw()},this.fnSettings=function(){return Wt(this[Yt.iApiIndex])},this.fnSort=function(t){this.api(!0).order(t).draw()},this.fnSortListener=function(t,e,n){this.api(!0).order.listener(t,e,n)},this.fnUpdate=function(t,e,i,o,a){var s=this.api(!0);return i===n||null===i?s.row(e).data(t):s.cell(e,i).data(t),(a===n||a)&&s.columns.adjust(),(o===n||o)&&s.draw(),0},this.fnVersionCheck=Yt.fnVersionCheck;var e=this,o=t===n,u=this.length;o&&(t={}),this.oApi=this.internal=Yt.internal;for(var p in Jt.ext.internal)p&&(this[p]=Vt(p));return this.each(function(){var p,f={},m=u>1?It(f,t,!0):t,g=0,b=this.getAttribute("id"),v=!1,_=Jt.defaults;if("table"!=this.nodeName.toLowerCase())return void Et(null,0,"Non-table node initialisation ("+this.nodeName+")",2);r(_),c(_.column),a(_,_,!0),a(_.column,_.column,!0),a(_,m);var z=Jt.settings;for(g=0,p=z.length;gt<"F"ip>'),C.renderer?i.isPlainObject(C.renderer)&&!C.renderer.header&&(C.renderer.header="jqueryui"):C.renderer="jqueryui"):i.extend(N,Jt.ext.classes,m.oClasses),i(this).addClass(N.sTable),""===C.oScroll.sX&&""===C.oScroll.sY||(C.oScroll.iBarWidth=wt()),C.oScroll.sX===!0&&(C.oScroll.sX="100%"),C.iInitDisplayStart===n&&(C.iInitDisplayStart=m.iDisplayStart,C._iDisplayStart=m.iDisplayStart),null!==m.iDeferLoading){C.bDeferLoading=!0;var O=i.isArray(m.iDeferLoading);C._iRecordsDisplay=O?m.iDeferLoading[0]:m.iDeferLoading,C._iRecordsTotal=O?m.iDeferLoading[1]:m.iDeferLoading}var S=C.oLanguage;i.extend(!0,S,m.oLanguage),""!==S.sUrl&&(i.ajax({dataType:"json",url:S.sUrl,success:function(t){s(t),a(_.oLanguage,t),i.extend(!0,S,t),rt(C)},error:function(){rt(C)}}),v=!0),null===m.asStripeClasses&&(C.asStripeClasses=[N.sStripeOdd,N.sStripeEven]);var x=C.asStripeClasses,L=i("tbody tr:eq(0)",this);i.inArray(!0,i.map(x,function(t,e){return L.hasClass(t)}))!==-1&&(i("tbody tr",this).removeClass(x.join(" ")),C.asDestroyStripes=x.slice());var D,q=[],W=this.getElementsByTagName("thead");if(0!==W.length&&(R(C.aoHeader,W[0]),q=F(C)),null===m.aoColumns)for(D=[],g=0,p=q.length;g").appendTo(this)),C.nTHead=X[0];var H=i(this).children("tbody");0===H.length&&(H=i("").appendTo(this)),C.nTBody=H[0];var j=i(this).children("tfoot");if(0===j.length&&P.length>0&&(""!==C.oScroll.sX||""!==C.oScroll.sY)&&(j=i("").appendTo(this)),0===j.length||0===j.children().length?i(this).addClass(N.sNoFooter):j.length>0&&(C.nTFoot=j[0],R(C.aoFooter,C.nTFoot)),m.aaData)for(g=0;gt?new Kt(e[t],this[t]):null},filter:function(t){var e=[];if(we.filter)e=we.filter.call(this,t,this);else for(var n=0,i=this.length;n0)return t[0].json}),Gt("ajax.params()",function(){var t=this.context;if(t.length>0)return t[0].oAjaxData}),Gt("ajax.reload()",function(t,e){return this.iterator("table",function(n){Oe(n,e===!1,t)})}),Gt("ajax.url()",function(t){var e=this.context;return t===n?0===e.length?n:(e=e[0],e.ajax?i.isPlainObject(e.ajax)?e.ajax.url:e.ajax:e.sAjaxSource):this.iterator("table",function(e){i.isPlainObject(e.ajax)?e.ajax.url=t:e.ajax=t})}),Gt("ajax.url().load()",function(t,e){return this.iterator("table",function(n){Oe(n,e===!1,t)})});var Se=function(t,e){var o,a,s,r,c,l,u=[],d=typeof t;for(t&&"string"!==d&&"function"!==d&&t.length!==n||(t=[t]),s=0,r=t.length;s0)return t[0]=t[e],t.length=1,t.context=[t.context[e]],t;return t.length=0,t},De=function(t,e){var n,o,a,s=[],r=t.aiDisplay,c=t.aiDisplayMaster,l=e.search,u=e.order,d=e.page;if("ssp"==jt(t))return"removed"===l?[]:fe(0,c.length);if("current"==d)for(n=t._iDisplayStart,o=t.fnDisplayEnd();n=0&&"applied"==l)&&s.push(n));return s},ke=function(t,e,n){return Se(e,function(e){var o=re(e);if(null!==o&&!n)return[o];var a=De(t,n);if(null!==o&&i.inArray(o,a)!==-1)return[o];if(!e)return a;if("function"==typeof e)return i.map(a,function(n){var i=t.aoData[n];return e(n,i._aData,i.nTr)?n:null});var s=me(pe(t.aoData,a,"nTr"));return e.nodeName&&i.inArray(e,s)!==-1?[e._DT_RowIndex]:i(s).filter(e).map(function(){return this._DT_RowIndex}).toArray()})};Gt("rows()",function(t,e){t===n?t="":i.isPlainObject(t)&&(e=t,t=""),e=xe(e);var o=this.iterator("table",function(n){return ke(n,t,e)},1);return o.selector.rows=t,o.selector.opts=e,o}),Gt("rows().nodes()",function(){return this.iterator("row",function(t,e){return t.aoData[e].nTr||n},1)}),Gt("rows().data()",function(){return this.iterator(!0,"rows",function(t,e){return pe(t.aoData,e,"_aData")},1)}),Qt("rows().cache()","row().cache()",function(t){return this.iterator("row",function(e,n){var i=e.aoData[n];return"search"===t?i._aFilterData:i._aSortData},1)}),Qt("rows().invalidate()","row().invalidate()",function(t){return this.iterator("row",function(e,n){D(e,n,t)})}),Qt("rows().indexes()","row().index()",function(){return this.iterator("row",function(t,e){return e},1)}),Qt("rows().remove()","row().remove()",function(){var t=this;return this.iterator("row",function(e,n,o){var a=e.aoData;a.splice(n,1);for(var s=0,r=a.length;s").addClass(n);i("td",o).addClass(n).html(e)[0].colSpan=g(t),a.push(o[0])}};if(i.isArray(n)||n instanceof i)for(var r=0,c=n.length;r0&&(e.on(i,function(n,i){t===i&&e.rows({page:"current"}).eq(0).each(function(t){var e=s[t];e._detailsShow&&e._details.insertAfter(e.nTr)})}),e.on(o,function(e,n,i,o){if(t===n)for(var a,r=g(n),c=0,l=s.length;c=0?r:o.length+r];if("function"==typeof e){var c=De(t,n);return i.map(o,function(n,i){return e(i,Fe(t,i,0,0,c),s[i])?i:null})}var l="string"==typeof e?e.match(Re):"";if(!l)return i(s).filter(e).map(function(){return i.inArray(this,s)}).toArray();switch(l[2]){case"visIdx":case"visible":var u=parseInt(l[1],10);if(u<0){var d=i.map(o,function(t,e){return t.bVisible?e:null});return[d[d.length+u]]}return[f(t,u)];case"name":return i.map(a,function(t,e){return t===l[1]?e:null})}})},je=function(t,e,o,a){var s,r,c,l,u=t.aoColumns,d=u[e],h=t.aoData;if(o===n)return d.bVisible;if(d.bVisible!==o){if(o){var f=i.inArray(!0,he(u,"bVisible"),e+1);for(r=0,c=h.length;rn;return!0},Jt.isDataTable=Jt.fnIsDataTable=function(t){var e=i(t).get(0),n=!1;return i.each(Jt.settings,function(t,i){i.nTable!==e&&i.nScrollHead!==e&&i.nScrollFoot!==e||(n=!0)}),n},Jt.tables=Jt.fnTables=function(t){return i.map(Jt.settings,function(e){if(!t||t&&i(e.nTable).is(":visible"))return e.nTable})},Jt.util={throttle:Mt,escapeRegex:tt},Jt.camelToHungarian=a,Gt("$()",function(t,e){var n=this.rows(e).nodes(),o=i(n);return i([].concat(o.filter(t).toArray(),o.find(t).toArray()))}),i.each(["on","one","off"],function(t,e){Gt(e+"()",function(){var t=Array.prototype.slice.call(arguments);t[0].match(/\.dt\b/)||(t[0]+=".dt");var n=i(this.tables().nodes());return n[e].apply(n,t),this})}),Gt("clear()",function(){return this.iterator("table",function(t){x(t)})}),Gt("settings()",function(){return new Kt(this.context,this.context)}),Gt("data()",function(){return this.iterator("table",function(t){return he(t.aoData,"_aData")}).flatten()}),Gt("destroy()",function(e){return e=e||!1,this.iterator("table",function(n){var o,a=n.nTableWrapper.parentNode,s=n.oClasses,r=n.nTable,c=n.nTBody,l=n.nTHead,u=n.nTFoot,d=i(r),h=i(c),p=i(n.nTableWrapper),f=i.map(n.aoData,function(t){return t.nTr});n.bDestroying=!0,Rt(n,"aoDestroyCallback","destroy",[n]),e||new Kt(n).columns().visible(!0),p.unbind(".DT").find(":not(tbody *)").unbind(".DT"),i(t).unbind(".DT-"+n.sInstance),r!=l.parentNode&&(d.children("thead").detach(),d.append(l)),u&&r!=u.parentNode&&(d.children("tfoot").detach(),d.append(u)),d.detach(),p.detach(),n.aaSorting=[],n.aaSortingFixed=[],Lt(n),i(f).removeClass(n.asStripeClasses.join(" ")),i("th, td",l).removeClass(s.sSortable+" "+s.sSortableAsc+" "+s.sSortableDesc+" "+s.sSortableNone),n.bJUI&&(i("th span."+s.sSortIcon+", td span."+s.sSortIcon,l).detach(),i("th, td",l).each(function(){var t=i("div."+s.sSortJUIWrapper,this);i(this).append(t.contents()),t.detach()})),!e&&a&&a.insertBefore(r,n.nTableReinsertBefore),h.children().detach(),h.append(f),d.css("width",n.sDestroyWidth).removeClass(s.sTable),o=n.asDestroyStripes.length,o&&h.children().each(function(t){i(this).addClass(n.asDestroyStripes[t%o])});var m=i.inArray(n,Jt.settings);m!==-1&&Jt.settings.splice(m,1)})}),Jt.version="1.10.4",Jt.settings=[],Jt.models={},Jt.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0},Jt.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null},Jt.models.oColumn={idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null},Jt.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(t){return t.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(t){try{return JSON.parse((t.iStateDuration===-1?sessionStorage:localStorage).getItem("DataTables_"+t.sInstance+"_"+location.pathname))}catch(e){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(t,e){try{(t.iStateDuration===-1?sessionStorage:localStorage).setItem("DataTables_"+t.sInstance+"_"+location.pathname,JSON.stringify(e))}catch(n){}},fnStateSaveParams:null,iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:i.extend({},Jt.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null},o(Jt.defaults),Jt.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null},o(Jt.defaults.column),Jt.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:n,oAjaxData:n,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,_iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==jt(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==jt(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var t=this._iDisplayLength,e=this._iDisplayStart,n=e+t,i=this.aiDisplay.length,o=this.oFeatures,a=o.bPaginate;return o.bServerSide?a===!1||t===-1?e+i:Math.min(e+t,this._iRecordsDisplay):!a||n>i||t===-1?i:n},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}},Jt.ext=Yt={classes:{},errMode:"alert",feature:[],search:[],internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:Jt.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:Jt.version},i.extend(Yt,{afnFiltering:Yt.search,aTypes:Yt.type.detect,ofnSearch:Yt.type.search,oSort:Yt.type.order,afnSortData:Yt.order,aoFeatures:Yt.feature,oApi:Yt.internal,oStdClasses:Yt.classes,oPagination:Yt.pager}),i.extend(Jt.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""}),function(){var t="";t="";var e=t+"ui-state-default",n=t+"css_right ui-icon ui-icon-",o=t+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";i.extend(Jt.ext.oJUIClasses,Jt.ext.classes,{sPageButton:"fg-button ui-button "+e,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",sSortAsc:e+" sorting_asc",sSortDesc:e+" sorting_desc",sSortable:e+" sorting",sSortableAsc:e+" sorting_asc_disabled",sSortableDesc:e+" sorting_desc_disabled",sSortableNone:e+" sorting_disabled",sSortJUIAsc:n+"triangle-1-n",sSortJUIDesc:n+"triangle-1-s",sSortJUI:n+"carat-2-n-s",sSortJUIAscAllowed:n+"carat-1-n",sSortJUIDescAllowed:n+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+e,sScrollFoot:"dataTables_scrollFoot "+e,sHeaderTH:e,sFooterTH:e,sJUIHeader:o+" ui-corner-tl ui-corner-tr",sJUIFooter:o+" ui-corner-bl ui-corner-br"})}();var $e=Jt.ext.pager;i.extend($e,{simple:function(t,e){return["previous","next"]},full:function(t,e){return["first","previous","next","last"]},simple_numbers:function(t,e){return["previous",Ut(t,e),"next"]},full_numbers:function(t,e){return["first","previous",Ut(t,e),"next","last"]},_numbers:Ut,numbers_length:7}),i.extend(!0,Jt.ext.renderer,{pageButton:{_:function(t,n,o,a,s,r){var c,l,u=t.oClasses,d=t.oLanguage.oPaginate,h=0,p=function(e,n){var a,f,m,g,b=function(e){ht(t,e.data.action,!0)};for(a=0,f=n.length;a").appendTo(e);p(v,g)}else{switch(c="",l="",g){case"ellipsis":e.append("");break;case"first":c=d.sFirst,l=g+(s>0?"":" "+u.sPageButtonDisabled);break;case"previous":c=d.sPrevious,l=g+(s>0?"":" "+u.sPageButtonDisabled);break;case"next":c=d.sNext,l=g+(s",{"class":u.sPageButton+" "+l,"aria-controls":t.sTableId,"data-dt-idx":h,tabindex:t.iTabIndex,id:0===o&&"string"==typeof g?t.sTableId+"_"+g:null}).html(c).appendTo(e),Pt(m,{action:g},b),h++)}};try{var f=i(e.activeElement).data("dt-idx");p(i(n).empty(),a),null!==f&&i(n).find("[data-dt-idx="+f+"]").focus()}catch(m){}}}}),i.extend(Jt.ext.type.detect,[function(t,e){var n=e.oLanguage.sDecimal;return le(t,n)?"num"+n:null},function(t,e){if(t&&!(t instanceof Date)&&(!ne.test(t)||!ie.test(t)))return null;var n=Date.parse(t);return null!==n&&!isNaN(n)||se(t)?"date":null},function(t,e){var n=e.oLanguage.sDecimal;return le(t,n,!0)?"num-fmt"+n:null},function(t,e){var n=e.oLanguage.sDecimal;return de(t,n)?"html-num"+n:null},function(t,e){var n=e.oLanguage.sDecimal;return de(t,n,!0)?"html-num-fmt"+n:null},function(t,e){return se(t)||"string"==typeof t&&t.indexOf("<")!==-1?"html":null}]),i.extend(Jt.ext.type.search,{html:function(t){return se(t)?t:"string"==typeof t?t.replace(te," ").replace(ee,""):""},string:function(t){return se(t)?t:"string"==typeof t?t.replace(te," "):t}});var Ve=function(t,e,n,i){return 0===t||t&&"-"!==t?(e&&(t=ce(t,e)),t.replace&&(n&&(t=t.replace(n,"")),i&&(t=t.replace(i,""))),1*t):-(1/0)};return i.extend(Yt.type.order,{"date-pre":function(t){return Date.parse(t)||0},"html-pre":function(t){return se(t)?"":t.replace?t.replace(/<.*?>/g,"").toLowerCase():t+""},"string-pre":function(t){return se(t)?"":"string"==typeof t?t.toLowerCase():t.toString?t.toString():""},"string-asc":function(t,e){return te?1:0},"string-desc":function(t,e){return te?-1:0}}),$t(""),i.extend(!0,Jt.ext.renderer,{header:{_:function(t,e,n,o){i(t.nTable).on("order.dt.DT",function(i,a,s,r){if(t===a){var c=n.idx;e.removeClass(n.sSortingClass+" "+o.sSortAsc+" "+o.sSortDesc).addClass("asc"==r[c]?o.sSortAsc:"desc"==r[c]?o.sSortDesc:n.sSortingClass)}})},jqueryui:function(t,e,n,o){i("
    ").addClass(o.sSortJUIWrapper).append(e.contents()).append(i("").addClass(o.sSortIcon+" "+n.sSortingClassJUI)).appendTo(e),i(t.nTable).on("order.dt.DT",function(i,a,s,r){if(t===a){var c=n.idx;e.removeClass(o.sSortAsc+" "+o.sSortDesc).addClass("asc"==r[c]?o.sSortAsc:"desc"==r[c]?o.sSortDesc:n.sSortingClass),e.find("span."+o.sSortIcon).removeClass(o.sSortJUIAsc+" "+o.sSortJUIDesc+" "+o.sSortJUI+" "+o.sSortJUIAscAllowed+" "+o.sSortJUIDescAllowed).addClass("asc"==r[c]?o.sSortJUIAsc:"desc"==r[c]?o.sSortJUIDesc:n.sSortingClassJUI)}})}}}),Jt.render={number:function(t,e,n,i){return{display:function(o){var a=o<0?"-":"";o=Math.abs(parseFloat(o));var s=parseInt(o,10),r=n?e+(o-s).toFixed(n).substring(2):"";return a+(i||"")+s.toString().replace(/\B(?=(\d{3})+(?!\d))/g,t)+r}}}},i.extend(Jt.ext.internal,{_fnExternApiFunc:Vt,_fnBuildAjax:H,_fnAjaxUpdate:j,_fnAjaxParameters:U,_fnAjaxUpdateDraw:$,_fnAjaxDataSrc:V,_fnAddColumn:d,_fnColumnOptions:h,_fnAdjustColumnSizing:p,_fnVisibleToColumnIndex:f,_fnColumnIndexToVisible:m,_fnVisbleColumns:g,_fnGetColumns:b,_fnColumnTypes:v,_fnApplyColumnDefs:M,_fnHungarianMap:o,_fnCamelToHungarian:a,_fnLanguageCompat:s,_fnBrowserDetect:l,_fnAddData:y,_fnAddTr:A,_fnNodeToDataIndex:_,_fnNodeToColumnIndex:z,_fnGetCellData:T,_fnSetCellData:w,_fnSplitObjNotation:C,_fnGetObjectDataFn:N,_fnSetObjectDataFn:O,_fnGetDataMaster:S,_fnClearTable:x,_fnDeleteIndex:L,_fnInvalidate:D,_fnGetRowElements:k,_fnCreateTr:q,_fnBuildHead:E,_fnDrawHead:B,_fnDraw:I,_fnReDraw:P,_fnAddOptionsHtml:X,_fnDetectHeader:R,_fnGetUniqueThs:F,_fnFeatureHtmlFilter:J,_fnFilterComplete:Y,_fnFilterCustom:K,_fnFilterColumn:G,_fnFilter:Q,_fnFilterCreateSearch:Z,_fnEscapeRegex:tt,_fnFilterData:et,_fnFeatureHtmlInfo:ot,_fnUpdateInfo:at,_fnInfoMacros:st,_fnInitialise:rt,_fnInitComplete:ct,_fnLengthChange:lt,_fnFeatureHtmlLength:ut,_fnFeatureHtmlPaginate:dt,_fnPageChange:ht,_fnFeatureHtmlProcessing:pt,_fnProcessingDisplay:ft,_fnFeatureHtmlTable:mt,_fnScrollDraw:gt,_fnApplyToChildren:bt,_fnCalculateColumnWidths:vt,_fnThrottle:Mt,_fnConvertToWidth:yt,_fnScrollingWidthAdjust:At,_fnGetWidestNode:_t,_fnGetMaxLenString:zt,_fnStringToCss:Tt,_fnScrollBarWidth:wt,_fnSortFlatten:Ct,_fnSort:Nt,_fnSortAria:Ot,_fnSortListener:St,_fnSortAttachListener:xt,_fnSortingClasses:Lt,_fnSortData:Dt,_fnSaveState:kt,_fnLoadState:qt,_fnSettingsFromNode:Wt,_fnLog:Et,_fnMap:Bt,_fnBindAction:Pt,_fnCallbackReg:Xt,_fnCallbackFire:Rt,_fnLengthOverflow:Ft,_fnRenderer:Ht,_fnDataSource:jt,_fnRowAttributes:W,_fnCalculateEnd:function(){}}),i.fn.dataTable=Jt,i.fn.dataTableSettings=Jt.settings,i.fn.dataTableExt=Jt.ext,i.fn.DataTable=function(t){return i(this).dataTable(t).api()},i.each(Jt,function(t,e){i.fn.DataTable[t]=e}),i.fn.dataTable})}(window,document),function(t){"function"==typeof define&&define.amd?define(["jquery","datatables"],t):t(jQuery)}(function(t){t.extend(!0,t.fn.dataTable.defaults,{sDom:"<'row'<'col-sm-12'<'pull-right'f><'pull-left'l>r<'clearfix'>>>t<'row'<'col-sm-12'<'pull-left'i><'pull-right'p><'clearfix'>>>",sPaginationType:"bs_normal",oLanguage:{sIconClassFirst:"glyphicon glyphicon-backward",sIconClassLast:"glyphicon glyphicon-forward",sIconClassPrevious:"glyphicon glyphicon-chevron-left",sIconClassNext:"glyphicon glyphicon-chevron-right"}}),t.extend(t.fn.dataTableExt.oStdClasses,{sWrapper:"dataTables_wrapper form-inline"}),t.fn.dataTableExt.oApi.fnPagingInfo=function(t){return{iStart:t._iDisplayStart,iEnd:t.fnDisplayEnd(),iLength:t._iDisplayLength,iTotal:t.fnRecordsTotal(),iFilteredTotal:t.fnRecordsDisplay(),iPage:t._iDisplayLength===-1?0:Math.ceil(t._iDisplayStart/t._iDisplayLength),iTotalPages:t._iDisplayLength===-1?0:Math.ceil(t.fnRecordsDisplay()/t._iDisplayLength)}},t.extend(t.fn.dataTableExt.oPagination,{bs_normal:{fnInit:function(e,n,i){var o=e.oLanguage.oPaginate,a=function(t){t.preventDefault(),e.oApi._fnPageChange(e,t.data.action)&&i(e)};t(n).append('');var s=t("a",n);t(s[0]).bind("click.DT",{action:"previous"},a),t(s[1]).bind("click.DT",{action:"next"},a)},fnUpdate:function(e,n){var i,o,a,s,r,c,l=5,u=e.oInstance.fnPagingInfo(),d=e.aanFeatures.p,h=Math.floor(l/2);for(u.iTotalPages=u.iTotalPages-h?(r=u.iTotalPages-l+1,c=u.iTotalPages):(r=u.iPage-h+1,c=r+l-1),i=0,o=d.length;i'+a+"").insertBefore(t("li:last",d[i])[0]).bind("click",function(i){i.preventDefault(),e.oApi._fnPageChange(e,parseInt(t("a",this).text(),10)-1)&&n(e)});0===u.iPage?t("li:first",d[i]).addClass("disabled"):t("li:first",d[i]).removeClass("disabled"),u.iPage===u.iTotalPages-1||0===u.iTotalPages?t("li:last",d[i]).addClass("disabled"):t("li:last",d[i]).removeClass("disabled")}}},bs_two_button:{fnInit:function(e,n,i){var o=e.oLanguage.oPaginate,a=(e.oClasses,function(t){e.oApi._fnPageChange(e,t.data.action)&&i(e)}),s='';t(n).append(s);var r=t("a",n),c=r[0],l=r[1];e.oApi._fnBindAction(c,{action:"previous"},a),e.oApi._fnBindAction(l,{action:"next"},a),e.aanFeatures.p||(n.id=e.sTableId+"_paginate",c.id=e.sTableId+"_previous",l.id=e.sTableId+"_next",c.setAttribute("aria-controls",e.sTableId),l.setAttribute("aria-controls",e.sTableId))},fnUpdate:function(e,n){if(e.aanFeatures.p)for(var i=e.oInstance.fnPagingInfo(),o=(e.oClasses,e.aanFeatures.p),a=0,s=o.length;a
  •  '+o.sFirst+'
  •  '+o.sPrevious+'
  • '+o.sNext+' 
  • '+o.sLast+' 
  • ');var r=t("a",n),c=r[0],l=r[1],u=r[2],d=r[3];e.oApi._fnBindAction(c,{action:"first"},s),e.oApi._fnBindAction(l,{action:"previous"},s),e.oApi._fnBindAction(u,{action:"next"},s),e.oApi._fnBindAction(d,{action:"last"},s),e.aanFeatures.p||(n.id=e.sTableId+"_paginate",c.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",u.id=e.sTableId+"_next",d.id=e.sTableId+"_last")},fnUpdate:function(e,n){if(e.aanFeatures.p)for(var i=e.oInstance.fnPagingInfo(),o=(e.oClasses,e.aanFeatures.p),a=0,s=o.length;a
  • '+o.sFirst+'
  • '+o.sPrevious+'
  • '+o.sNext+'
  • '+o.sLast+"
  • ");var r=t("a",n),c=r[0],l=r[1],u=r[2],d=r[3];e.oApi._fnBindAction(c,{action:"first"},s),e.oApi._fnBindAction(l,{action:"previous"},s),e.oApi._fnBindAction(u,{action:"next"},s),e.oApi._fnBindAction(d,{action:"last"},s),e.aanFeatures.p||(n.id=e.sTableId+"_paginate",c.id=e.sTableId+"_first",l.id=e.sTableId+"_previous",u.id=e.sTableId+"_next",d.id=e.sTableId+"_last")},fnUpdate:function(e,n){if(e.aanFeatures.p){var i,o,a,s,r,c=e.oInstance.fnPagingInfo(),l=t.fn.dataTableExt.oPagination.iFullNumbersShowPages,u=Math.floor(l/2),d=Math.ceil(e.fnRecordsDisplay()/e._iDisplayLength),h=Math.ceil(e._iDisplayStart/e._iDisplayLength)+1,p="",f=(e.oClasses,e.aanFeatures.p);for(e._iDisplayLength===-1?(i=1,o=1,h=1):d=d-u?(i=d-l+1,o=d):(i=h-Math.ceil(l/2)+1,o=i+l-1),a=i;a<=o;a++)p+=h!==a?'
  • '+e.fnFormatNumber(a)+"
  • ":'
  • '+e.fnFormatNumber(a)+"
  • ";for(a=0,s=f.length;a",o[0];);return 4d.a.l(e,t[n])&&e.push(t[n]);return e},ya:function(t,e){t=t||[];for(var n=[],i=0,o=t.length;ii?n&&t.push(e):n||t.splice(i,1)},na:l,extend:r,ra:c,sa:l?c:r,A:s,Oa:function(t,e){if(!t)return t;var n,i={};for(n in t)t.hasOwnProperty(n)&&(i[n]=e(t[n],n,t));return i},Fa:function(t){for(;t.firstChild;)d.removeNode(t.firstChild)},ec:function(t){t=d.a.R(t);for(var e=n.createElement("div"),i=0,o=t.length;if?t.setAttribute("selected",e):t.selected=e},ta:function(e){return null===e||e===t?"":e.trim?e.trim():e.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},oc:function(t,e){for(var n=[],i=(t||"").split(e),o=0,a=i.length;ot.length)&&t.substring(0,e.length)===e},Sb:function(t,e){if(t===e)return!0;if(11===t.nodeType)return!1;if(e.contains)return e.contains(3===t.nodeType?t.parentNode:t);if(e.compareDocumentPosition)return 16==(16&e.compareDocumentPosition(t));for(;t&&t!=e;)t=t.parentNode;return!!t},Ea:function(t){return d.a.Sb(t,t.ownerDocument.documentElement)},eb:function(t){return!!d.a.hb(t,d.a.Ea)},B:function(t){return t&&t.tagName&&t.tagName.toLowerCase()},q:function(t,e,n){var i=f&&p[e];if(!i&&o)o(t).bind(e,n);else if(i||"function"!=typeof t.addEventListener){if("undefined"==typeof t.attachEvent)throw Error("Browser doesn't support addEventListener or attachEvent");var a=function(e){n.call(t,e)},s="on"+e;t.attachEvent(s,a),d.a.u.ja(t,function(){t.detachEvent(s,a)})}else t.addEventListener(e,n,!1)},ha:function(t,i){if(!t||!t.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var a;if("input"===d.a.B(t)&&t.type&&"click"==i.toLowerCase()?(a=t.type,a="checkbox"==a||"radio"==a):a=!1,o&&!a)o(t).trigger(i);else if("function"==typeof n.createEvent){if("function"!=typeof t.dispatchEvent)throw Error("The supplied element doesn't support dispatchEvent");a=n.createEvent(h[i]||"HTMLEvents"),a.initEvent(i,!0,!0,e,0,0,0,0,0,!1,!1,!1,!1,0,t),t.dispatchEvent(a)}else if(a&&t.click)t.click();else{if("undefined"==typeof t.fireEvent)throw Error("Browser doesn't support triggering events");t.fireEvent("on"+i)}},c:function(t){return d.v(t)?t():t},Sa:function(t){return d.v(t)?t.o():t},ua:function(t,e,n){if(e){var i=/\S+/g,o=t.className.match(i)||[];d.a.r(e.match(i),function(t){d.a.Y(o,t,n)}),t.className=o.join(" ")}},Xa:function(e,n){var i=d.a.c(n);null!==i&&i!==t||(i="");var o=d.e.firstChild(e);!o||3!=o.nodeType||d.e.nextSibling(o)?d.e.U(e,[e.ownerDocument.createTextNode(i)]):o.data=i,d.a.Vb(e)},Cb:function(t,e){if(t.name=e,7>=f)try{t.mergeAttributes(n.createElement(""),!1)}catch(i){}},Vb:function(t){9<=f&&(t=1==t.nodeType?t:t.parentNode,t.style&&(t.style.zoom=t.style.zoom))},Tb:function(t){if(f){var e=t.style.width;t.style.width=0,t.style.width=e}},ic:function(t,e){t=d.a.c(t),e=d.a.c(e);for(var n=[],i=t;i<=e;i++)n.push(i);return n},R:function(t){for(var e=[],n=0,i=t.length;n",""]||!a.indexOf("",""]||(!a.indexOf("",""]||[0,"",""],t="ignored
    "+a[1]+t+a[2]+"
    ","function"==typeof e.innerShiv?i.appendChild(e.innerShiv(t)):i.innerHTML=t;a[0]--;)i=i.lastChild;i=d.a.R(i.lastChild.childNodes)}return i},d.a.Va=function(e,n){if(d.a.Fa(e),n=d.a.c(n),null!==n&&n!==t)if("string"!=typeof n&&(n=n.toString()),o)o(e).html(n);else for(var i=d.a.Qa(n),a=0;a"},Hb:function(e,i){var o=n[e];if(o===t)throw Error("Couldn't find any memo with ID "+e+". Perhaps it's already been unmemoized.");try{return o.apply(null,i||[]),!0}finally{delete n[e]}},Ib:function(t,n){var i=[];e(t,i);for(var o=0,a=i.length;oa[0]?c+a[0]:a[0]),c);for(var c=1===l?c:Math.min(e+(a[1]||0),c),l=e+l-2,u=Math.max(c,l),h=[],p=[],f=2;ee;e++)t=t();return t})},d.toJSON=function(t,e,n){return t=d.Gb(t),d.a.Ya(t,e,n)},i.prototype={save:function(t,e){var n=d.a.l(this.keys,t);0<=n?this.ab[n]=e:(this.keys.push(t),this.ab.push(e))},get:function(e){return e=d.a.l(this.keys,e),0<=e?this.ab[e]:t}}}(),d.b("toJS",d.Gb),d.b("toJSON",d.toJSON),function(){d.i={p:function(e){switch(d.a.B(e)){case"option":return!0===e.__ko__hasDomDataOptionValue__?d.a.f.get(e,d.d.options.Pa):7>=d.a.oa?e.getAttributeNode("value")&&e.getAttributeNode("value").specified?e.value:e.text:e.value;case"select":return 0<=e.selectedIndex?d.i.p(e.options[e.selectedIndex]):t;default:return e.value}},X:function(e,n,i){switch(d.a.B(e)){case"option":switch(typeof n){case"string":d.a.f.set(e,d.d.options.Pa,t),"__ko__hasDomDataOptionValue__"in e&&delete e.__ko__hasDomDataOptionValue__,e.value=n;break;default:d.a.f.set(e,d.d.options.Pa,n),e.__ko__hasDomDataOptionValue__=!0,e.value="number"==typeof n?n:""}break;case"select":""!==n&&null!==n||(n=t);for(var o,a=-1,s=0,r=e.options.length;s=c){e&&s.push(n?{key:e,value:n.join("")}:{unknown:e}),e=n=c=0;continue}}else if(58===h){if(!n)continue}else if(47===h&&u&&1"===n.createComment("test").text,s=a?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,r=a?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,c={ul:!0,ol:!0};d.e={Q:{},childNodes:function(e){return t(e)?i(e):e.childNodes},da:function(e){if(t(e)){e=d.e.childNodes(e);for(var n=0,i=e.length;n=d.a.oa&&n in g?(n=g[n],o?e.removeAttribute(n):e[n]=i):o||e.setAttribute(n,i.toString()),"name"===n&&d.a.Cb(e,o?"":i.toString())})}},function(){d.d.checked={after:["value","attr"],init:function(e,n,i){function o(){return i.has("checkedValue")?d.a.c(i.get("checkedValue")):e.value}function a(){var t=e.checked,a=h?o():t;if(!d.ca.pa()&&(!c||t)){var s=d.k.t(n);l?u!==a?(t&&(d.a.Y(s,a,!0),d.a.Y(s,u,!1)),u=a):d.a.Y(s,a,t):d.g.va(s,i,"checked",a,!0)}}function s(){var t=d.a.c(n());e.checked=l?0<=d.a.l(t,o()):r?t:o()===t}var r="checkbox"==e.type,c="radio"==e.type;if(r||c){var l=r&&d.a.c(n())instanceof Array,u=l?o():t,h=c||l;c&&!e.name&&d.d.uniqueName.init(e,function(){return!0}),d.ba(a,null,{G:e}),d.a.q(e,"click",a),d.ba(s,null,{G:e})}}},d.g.W.checked=!0,d.d.checkedValue={update:function(t,e){t.value=d.a.c(e())}}}(),d.d.css={update:function(t,e){var n=d.a.c(e());"object"==typeof n?d.a.A(n,function(e,n){n=d.a.c(n),d.a.ua(t,e,n)}):(n=String(n||""),d.a.ua(t,t.__ko__cssValue,!1),t.__ko__cssValue=n,d.a.ua(t,n,!0))}},d.d.enable={update:function(t,e){var n=d.a.c(e());n&&t.disabled?t.removeAttribute("disabled"):n||t.disabled||(t.disabled=!0)}},d.d.disable={update:function(t,e){d.d.enable.update(t,function(){return!d.a.c(e())})}},d.d.event={init:function(t,e,n,i,o){var a=e()||{};d.a.A(a,function(a){"string"==typeof a&&d.a.q(t,a,function(t){var s,r=e()[a];if(r){try{var c=d.a.R(arguments);i=o.$data,c.unshift(i),s=r.apply(i,c)}finally{!0!==s&&(t.preventDefault?t.preventDefault():t.returnValue=!1)}!1===n.get(a+"Bubble")&&(t.cancelBubble=!0,t.stopPropagation&&t.stopPropagation())}})})}},d.d.foreach={vb:function(t){return function(){var e=t(),n=d.a.Sa(e);return n&&"number"!=typeof n.length?(d.a.c(e),{foreach:n.data,as:n.as,includeDestroyed:n.includeDestroyed,afterAdd:n.afterAdd,beforeRemove:n.beforeRemove,afterRender:n.afterRender,beforeMove:n.beforeMove,afterMove:n.afterMove,templateEngine:d.K.Ja}):{foreach:e,templateEngine:d.K.Ja}}},init:function(t,e){return d.d.template.init(t,d.d.foreach.vb(e))},update:function(t,e,n,i,o){return d.d.template.update(t,d.d.foreach.vb(e),n,i,o)}},d.g.aa.foreach=!1,d.e.Q.foreach=!0,d.d.hasfocus={init:function(t,e,n){function i(i){t.__ko_hasfocusUpdating=!0;var o=t.ownerDocument;if("activeElement"in o){var a;try{a=o.activeElement}catch(s){a=o.body}i=a===t}o=e(),d.g.va(o,n,"hasfocus",i,!0),t.__ko_hasfocusLastValue=i,t.__ko_hasfocusUpdating=!1}var o=i.bind(null,!0),a=i.bind(null,!1);d.a.q(t,"focus",o),d.a.q(t,"focusin",o),d.a.q(t,"blur",a),d.a.q(t,"focusout",a)},update:function(t,e){var n=!!d.a.c(e());t.__ko_hasfocusUpdating||t.__ko_hasfocusLastValue===n||(n?t.focus():t.blur(),d.k.t(d.a.ha,null,[t,n?"focusin":"focusout"]))}},d.g.W.hasfocus=!0,d.d.hasFocus=d.d.hasfocus,d.g.W.hasFocus=!0,d.d.html={init:function(){return{controlsDescendantBindings:!0}},update:function(t,e){d.a.Va(t,e())}},u("if"),u("ifnot",!1,!0),u("with",!0,!1,function(t,e){return t.createChildContext(e)});var b={};d.d.options={init:function(t){if("select"!==d.a.B(t))throw Error("options binding applies only to SELECT elements");for(;0","#comment",o)})},Mb:function(t,e){return d.w.Na(function(n,i){var o=n.nextSibling;o&&o.nodeName.toLowerCase()===e&&d.xa(o,t,i)})}}}(),d.b("__tr_ambtns",d.Za.Mb),function(){d.n={},d.n.j=function(t){this.j=t},d.n.j.prototype.text=function(){var t=d.a.B(this.j),t="script"===t?"text":"textarea"===t?"value":"innerHTML";if(0==arguments.length)return this.j[t];var e=arguments[0];"innerHTML"===t?d.a.Va(this.j,e):this.j[t]=e};var e=d.a.f.L()+"_";d.n.j.prototype.data=function(t){return 1===arguments.length?d.a.f.get(this.j,e+t):void d.a.f.set(this.j,e+t,arguments[1])};var n=d.a.f.L();d.n.Z=function(t){this.j=t},d.n.Z.prototype=new d.n.j,d.n.Z.prototype.text=function(){if(0==arguments.length){var e=d.a.f.get(this.j,n)||{};return e.$a===t&&e.Ba&&(e.$a=e.Ba.innerHTML),e.$a}d.a.f.set(this.j,n,{$a:arguments[0]})},d.n.j.prototype.nodes=function(){return 0==arguments.length?(d.a.f.get(this.j,n)||{}).Ba:void d.a.f.set(this.j,n,{Ba:arguments[0]})},d.b("templateSources",d.n),d.b("templateSources.domElement",d.n.j),d.b("templateSources.anonymousTemplate",d.n.Z)}(),function(){function e(t,e,n){var i;for(e=d.e.nextSibling(e);t&&(i=t)!==e;)t=d.e.nextSibling(i),n(i,t)}function n(t,n){if(t.length){var i=t[0],o=t[t.length-1],a=i.parentNode,s=d.J.instance,r=s.preprocessNode;if(r){if(e(i,o,function(t,e){var n=t.previousSibling,a=r.call(s,t);a&&(t===i&&(i=a[0]||e),t===o&&(o=a[a.length-1]||n))}),t.length=0,!i)return;i===o?t.push(i):(t.push(i,o),d.a.ea(t,a))}e(i,o,function(t){1!==t.nodeType&&8!==t.nodeType||d.fb(n,t)}),e(i,o,function(t){1!==t.nodeType&&8!==t.nodeType||d.w.Ib(t,[n])}),d.a.ea(t,a)}}function i(t){return t.nodeType?t:0d.a.oa?0:t.nodes)?t.nodes():null;return e?d.a.R(e.cloneNode(!0).childNodes):(t=t.text(),d.a.Qa(t))},d.K.Ja=new d.K,d.Wa(d.K.Ja),d.b("nativeTemplateEngine",d.K),function(){d.La=function(){var t=this.ac=function(){if(!o||!o.tmpl)return 0;try{if(0<=o.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(t){}return 1}();this.renderTemplateSource=function(e,i,a){if(a=a||{},2>t)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var s=e.data("precompiled");return s||(s=e.text()||"",s=o.template(null,"{{ko_with $item.koBindingContext}}"+s+"{{/ko_with}}"),e.data("precompiled",s)),e=[i.$data],i=o.extend({koBindingContext:i},a.templateOptions),i=o.tmpl(s,e,i),i.appendTo(n.createElement("div")),o.fragments={},i},this.createJavaScriptEvaluatorBlock=function(t){return"{{ko_code ((function() { return "+t+" })()) }}"},this.addTemplate=function(t,e){n.write("")},0=0&&(u&&(u.splice(m,1),t.processAllDeferredBindingUpdates&&t.processAllDeferredBindingUpdates()),p.splice(g,0,A)),l(v,n,null),t.processAllDeferredBindingUpdates&&t.processAllDeferredBindingUpdates(),T.afterMove&&T.afterMove.call(this,b,s,r)}y&&y.apply(this,arguments)},connectWith:!!T.connectClass&&"."+T.connectClass})),void 0!==T.isEnabled&&t.computed({read:function(){A.sortable(r(T.isEnabled)?"enable":"disable")},disposeWhenNodeIsRemoved:u})},0);return t.utils.domNodeDisposal.addDisposeCallback(u,function(){(A.data("ui-sortable")||A.data("sortable"))&&A.sortable("destroy"),clearTimeout(w)}),{controlsDescendantBindings:!0}},update:function(e,n,i,a,s){var r=p(n,"foreach");l(e,o,r.foreach),t.bindingHandlers.template.update(e,function(){return r},i,a,s)},connectClass:"ko_container",allowDrop:!0,afterMove:null,beforeMove:null,options:{}},t.bindingHandlers.draggable={init:function(n,i,o,a,c){var u=r(i())||{},d=u.options||{},h=t.utils.extend({},t.bindingHandlers.draggable.options),f=p(i,"data"),m=u.connectClass||t.bindingHandlers.draggable.connectClass,g=void 0!==u.isEnabled?u.isEnabled:t.bindingHandlers.draggable.isEnabled;return u="data"in u?u.data:u,l(n,s,u),t.utils.extend(h,d),h.connectToSortable=!!m&&"."+m,e(n).draggable(h),void 0!==g&&t.computed({read:function(){e(n).draggable(r(g)?"enable":"disable")},disposeWhenNodeIsRemoved:n}),t.bindingHandlers.template.init(n,function(){return f},o,a,c)},update:function(e,n,i,o,a){var s=p(n,"data");return t.bindingHandlers.template.update(e,function(){return s},i,o,a)},connectClass:t.bindingHandlers.sortable.connectClass,options:{helper:"clone"}}}),function(){var t=this,e=t._,n=Array.prototype,i=Object.prototype,o=Function.prototype,a=n.push,s=n.slice,r=n.concat,c=i.toString,l=i.hasOwnProperty,u=Array.isArray,d=Object.keys,h=o.bind,p=function(t){return t instanceof p?t:this instanceof p?void(this._wrapped=t):new p(t)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=p),exports._=p):t._=p,p.VERSION="1.7.0";var f=function(t,e,n){if(void 0===e)return t;switch(null==n?3:n){case 1:return function(n){return t.call(e,n)};case 2:return function(n,i){return t.call(e,n,i)};case 3:return function(n,i,o){return t.call(e,n,i,o)};case 4:return function(n,i,o,a){return t.call(e,n,i,o,a)}}return function(){return t.apply(e,arguments)}};p.iteratee=function(t,e,n){return null==t?p.identity:p.isFunction(t)?f(t,e,n):p.isObject(t)?p.matches(t):p.property(t)},p.each=p.forEach=function(t,e,n){if(null==t)return t;e=f(e,n);var i,o=t.length;if(o===+o)for(i=0;i=0)},p.invoke=function(t,e){var n=s.call(arguments,2),i=p.isFunction(e);return p.map(t,function(t){return(i?e:t[e]).apply(t,n)})},p.pluck=function(t,e){return p.map(t,p.property(e))},p.where=function(t,e){return p.filter(t,p.matches(e))},p.findWhere=function(t,e){return p.find(t,p.matches(e))},p.max=function(t,e,n){var i,o,a=-(1/0),s=-(1/0);if(null==e&&null!=t){t=t.length===+t.length?t:p.values(t);for(var r=0,c=t.length;ra&&(a=i)}else e=p.iteratee(e,n),p.each(t,function(t,n,i){o=e(t,n,i),(o>s||o===-(1/0)&&a===-(1/0))&&(a=t,s=o)});return a},p.min=function(t,e,n){var i,o,a=1/0,s=1/0;if(null==e&&null!=t){t=t.length===+t.length?t:p.values(t);for(var r=0,c=t.length;ri||void 0===n)return 1;if(n>>1;n(t[r])=0;)if(t[i]===e)return i;return-1},p.range=function(t,e,n){arguments.length<=1&&(e=t||0,t=0),n=n||1;for(var i=Math.max(Math.ceil((e-t)/n),0),o=Array(i),a=0;ae?(clearTimeout(s),s=null,r=l,a=t.apply(i,o),s||(i=o=null)):s||n.trailing===!1||(s=setTimeout(c,u)),a}},p.debounce=function(t,e,n){var i,o,a,s,r,c=function(){var l=p.now()-s;l0?i=setTimeout(c,e-l):(i=null,n||(r=t.apply(a,o),i||(a=o=null)))};return function(){a=this,o=arguments,s=p.now();var l=n&&!i;return i||(i=setTimeout(c,e)),l&&(r=t.apply(a,o),a=o=null),r}},p.wrap=function(t,e){return p.partial(e,t)},p.negate=function(t){return function(){return!t.apply(this,arguments)}},p.compose=function(){var t=arguments,e=t.length-1;return function(){for(var n=e,i=t[e].apply(this,arguments);n--;)i=t[n].call(this,i);return i}},p.after=function(t,e){return function(){if(--t<1)return e.apply(this,arguments)}},p.before=function(t,e){var n;return function(){return--t>0?n=e.apply(this,arguments):e=null,n}},p.once=p.partial(p.before,2),p.keys=function(t){if(!p.isObject(t))return[];if(d)return d(t);var e=[];for(var n in t)p.has(t,n)&&e.push(n);return e},p.values=function(t){for(var e=p.keys(t),n=e.length,i=Array(n),o=0;o":">",'"':""","'":"'","`":"`"},A=p.invert(y),_=function(t){var e=function(e){return t[e]},n="(?:"+p.keys(t).join("|")+")",i=RegExp(n),o=RegExp(n,"g");return function(t){return t=null==t?"":""+t,i.test(t)?t.replace(o,e):t}};p.escape=_(y),p.unescape=_(A),p.result=function(t,e){if(null!=t){var n=t[e];return p.isFunction(n)?t[e]():n}};var z=0;p.uniqueId=function(t){var e=++z+"";return t?t+e:e},p.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var T=/(.)^/,w={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},C=/\\|'|\r|\n|\u2028|\u2029/g,N=function(t){return"\\"+w[t]};p.template=function(t,e,n){!e&&n&&(e=n),e=p.defaults({},e,p.templateSettings);var i=RegExp([(e.escape||T).source,(e.interpolate||T).source,(e.evaluate||T).source].join("|")+"|$","g"),o=0,a="__p+='";t.replace(i,function(e,n,i,s,r){return a+=t.slice(o,r).replace(C,N),o=r+e.length,n?a+="'+\n((__t=("+n+"))==null?'':_.escape(__t))+\n'":i?a+="'+\n((__t=("+i+"))==null?'':__t)+\n'":s&&(a+="';\n"+s+"\n__p+='"),e}),a+="';\n",e.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{var s=new Function(e.variable||"obj","_",a)}catch(r){throw r.source=a,r}var c=function(t){return s.call(this,t,p)},l=e.variable||"obj";return c.source="function("+l+"){\n"+a+"}",c},p.chain=function(t){var e=p(t);return e._chain=!0,e};var O=function(t){return this._chain?p(t).chain():t};p.mixin=function(t){p.each(p.functions(t),function(e){var n=p[e]=t[e];p.prototype[e]=function(){var t=[this._wrapped];return a.apply(t,arguments),O.call(this,n.apply(p,t))}})},p.mixin(p),p.each(["pop","push","reverse","shift","sort","splice","unshift"],function(t){var e=n[t];p.prototype[t]=function(){var n=this._wrapped;return e.apply(n,arguments),"shift"!==t&&"splice"!==t||0!==n.length||delete n[0],O.call(this,n)}}),p.each(["concat","join","slice"],function(t){var e=n[t];p.prototype[t]=function(){return O.call(this,e.apply(this._wrapped,arguments))}}),p.prototype.value=function(){return this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return p})}.call(this),function(t,e){function n(){return new Date(Date.UTC.apply(Date,arguments))}function i(){var t=new Date;return n(t.getFullYear(),t.getMonth(),t.getDate())}function o(t,e){return t.getUTCFullYear()===e.getUTCFullYear()&&t.getUTCMonth()===e.getUTCMonth()&&t.getUTCDate()===e.getUTCDate()}function a(t){return function(){return this[t].apply(this,arguments)}}function s(e,n){function i(t,e){return e.toLowerCase()}var o,a=t(e).data(),s={},r=new RegExp("^"+n.toLowerCase()+"([A-Z])");n=new RegExp("^"+n.toLowerCase());for(var c in a)n.test(c)&&(o=c.replace(r,i),s[o]=a[c]);return s}function r(e){var n={};if(m[e]||(e=e.split("-")[0],m[e])){var i=m[e];return t.each(f,function(t,e){e in i&&(n[e]=i[e])}),n}}var c=function(){var e={get:function(t){return this.slice(t)[0]},contains:function(t){for(var e=t&&t.valueOf(),n=0,i=this.length;no?(this.picker.addClass("datepicker-orient-right"),p=u.left+h-e):this.picker.addClass("datepicker-orient-left");var m,g,b=this.o.orientation.y;if("auto"===b&&(m=-s+f-n,g=s+a-(f+d+n),b=Math.max(m,g)===g?"top":"bottom"),this.picker.addClass("datepicker-orient-"+b),"top"===b?f+=d:f-=n+parseInt(this.picker.css("padding-top")),this.o.rtl){var v=o-(p+h);this.picker.css({top:f,right:v,zIndex:l})}else this.picker.css({top:f,left:p,zIndex:l});return this},_allow_update:!0,update:function(){if(!this._allow_update)return this;var e=this.dates.copy(),n=[],i=!1;return arguments.length?(t.each(arguments,t.proxy(function(t,e){e instanceof Date&&(e=this._local_to_utc(e)),n.push(e)},this)),i=!0):(n=this.isInput?this.element.val():this.element.data("date")||this.element.find("input").val(),n=n&&this.o.multidate?n.split(this.o.multidateSeparator):[n],delete this.element.data().date),n=t.map(n,t.proxy(function(t){return g.parseDate(t,this.o.format,this.o.language)},this)),n=t.grep(n,t.proxy(function(t){return tthis.o.endDate||!t},this),!0),this.dates.replace(n),this.dates.length?this.viewDate=new Date(this.dates.get(-1)):this.viewDatethis.o.endDate&&(this.viewDate=new Date(this.o.endDate)),i?this.setValue():n.length&&String(e)!==String(this.dates)&&this._trigger("changeDate"),!this.dates.length&&e.length&&this._trigger("clearDate"),this.fill(),this},fillDow:function(){var t=this.o.weekStart,e="";if(this.o.calendarWeeks){this.picker.find(".datepicker-days thead tr:first-child .datepicker-switch").attr("colspan",function(t,e){return parseInt(e)+1});var n=' ';e+=n}for(;t'+m[this.o.language].daysMin[t++%7]+"";e+="",this.picker.find(".datepicker-days thead").append(e)},fillMonths:function(){for(var t="",e=0;e<12;)t+=''+m[this.o.language].monthsShort[e++]+"";this.picker.find(".datepicker-months td").html(t)},setRange:function(e){e&&e.length?this.range=t.map(e,function(t){return t.valueOf()}):delete this.range,this.fill()},getClassNames:function(e){var n=[],i=this.viewDate.getUTCFullYear(),a=this.viewDate.getUTCMonth(),s=new Date;return e.getUTCFullYear()i||e.getUTCFullYear()===i&&e.getUTCMonth()>a)&&n.push("new"),this.focusDate&&e.valueOf()===this.focusDate.valueOf()&&n.push("focused"),this.o.todayHighlight&&e.getUTCFullYear()===s.getFullYear()&&e.getUTCMonth()===s.getMonth()&&e.getUTCDate()===s.getDate()&&n.push("today"),this.dates.contains(e)!==-1&&n.push("active"),(e.valueOf()this.o.endDate||t.inArray(e.getUTCDay(),this.o.daysOfWeekDisabled)!==-1)&&n.push("disabled"),this.o.datesDisabled.length>0&&t.grep(this.o.datesDisabled,function(t){return o(e,t)}).length>0&&n.push("disabled","disabled-date"),this.range&&(e>this.range[0]&&e"),this.o.calendarWeeks)){var y=new Date(+p+(this.o.weekStart-p.getUTCDay()-7)%7*864e5),A=new Date(Number(y)+(11-y.getUTCDay())%7*864e5),_=new Date(Number(_=n(A.getUTCFullYear(),0,1))+(11-_.getUTCDay())%7*864e5),z=(A-_)/864e5/7+1;M.push(''+z+"")}if(v=this.getClassNames(p),v.push("day"),this.o.beforeShowDay!==t.noop){var T=this.o.beforeShowDay(this._utc_to_local(p));T===e?T={}:"boolean"==typeof T?T={enabled:T}:"string"==typeof T&&(T={classes:T}),T.enabled===!1&&v.push("disabled"),T.classes&&(v=v.concat(T.classes.split(/\s+/))),T.tooltip&&(i=T.tooltip)}v=t.unique(v),M.push('"+p.getUTCDate()+""),i=null,p.getUTCDay()===this.o.weekEnd&&M.push(""),p.setUTCDate(p.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(M.join(""));var w=this.picker.find(".datepicker-months").find("th:eq(1)").text(a).end().find("span").removeClass("active");if(t.each(this.dates,function(t,e){e.getUTCFullYear()===a&&w.eq(e.getUTCMonth()).addClass("active")}),(al)&&w.addClass("disabled"),a===r&&w.slice(0,c).addClass("disabled"),a===l&&w.slice(u+1).addClass("disabled"),this.o.beforeShowMonth!==t.noop){var C=this;t.each(w,function(e,n){if(!t(n).hasClass("disabled")){var i=new Date(a,e,1),o=C.o.beforeShowMonth(i);o===!1&&t(n).addClass("disabled")}})}M="",a=10*parseInt(a/10,10);var N=this.picker.find(".datepicker-years").find("th:eq(1)").text(a+"-"+(a+9)).end().find("td");a-=1;for(var O,S=t.map(this.dates,function(t){return t.getUTCFullYear()}),x=-1;x<11;x++)O=["year"],x===-1?O.push("old"):10===x&&O.push("new"),t.inArray(a,S)!==-1&&O.push("active"),(al)&&O.push("disabled"),M+=''+a+"",a+=1;N.html(M)}},updateNavArrows:function(){if(this._allow_update){var t=new Date(this.viewDate),e=t.getUTCFullYear(),n=t.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-(1/0)&&e<=this.o.startDate.getUTCFullYear()&&n<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.o.endDate!==1/0&&e>=this.o.endDate.getUTCFullYear()&&n>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-(1/0)&&e<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),this.o.endDate!==1/0&&e>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}}},click:function(e){e.preventDefault();var i,o,a,s=t(e.target).closest("span, td, th");if(1===s.length)switch(s[0].nodeName.toLowerCase()){case"th":switch(s[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var r=g.modes[this.viewMode].navStep*("prev"===s[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,r),this._trigger("changeMonth",this.viewDate);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,r),1===this.viewMode&&this._trigger("changeYear",this.viewDate)}this.fill();break;case"today":var c=new Date;c=n(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0),this.showMode(-2);var l="linked"===this.o.todayBtn?null:"view";this._setDate(c,l);break;case"clear":this.clearDates()}break;case"span":s.hasClass("disabled")||(this.viewDate.setUTCDate(1),s.hasClass("month")?(a=1,o=s.parent().find("span").index(s),i=this.viewDate.getUTCFullYear(),this.viewDate.setUTCMonth(o),this._trigger("changeMonth",this.viewDate),1===this.o.minViewMode&&this._setDate(n(i,o,a))):(a=1,o=0,i=parseInt(s.text(),10)||0,this.viewDate.setUTCFullYear(i),this._trigger("changeYear",this.viewDate),2===this.o.minViewMode&&this._setDate(n(i,o,a))),this.showMode(-1),this.fill());break;case"td":s.hasClass("day")&&!s.hasClass("disabled")&&(a=parseInt(s.text(),10)||1,i=this.viewDate.getUTCFullYear(),o=this.viewDate.getUTCMonth(),s.hasClass("old")?0===o?(o=11,i-=1):o-=1:s.hasClass("new")&&(11===o?(o=0,i+=1):o+=1),this._setDate(n(i,o,a)))}this.picker.is(":visible")&&this._focused_from&&t(this._focused_from).focus(),delete this._focused_from},_toggle_multidate:function(t){var e=this.dates.contains(t);if(t||this.dates.clear(),e!==-1?(this.o.multidate===!0||this.o.multidate>1||this.o.toggleActive)&&this.dates.remove(e):this.o.multidate===!1?(this.dates.clear(),this.dates.push(t)):this.dates.push(t),"number"==typeof this.o.multidate)for(;this.dates.length>this.o.multidate;)this.dates.remove(0)},_setDate:function(t,e){e&&"date"!==e||this._toggle_multidate(t&&new Date(t)),e&&"view"!==e||(this.viewDate=t&&new Date(t)),this.fill(),this.setValue(),e&&"view"===e||this._trigger("changeDate");var n;this.isInput?n=this.element:this.component&&(n=this.element.find("input")),n&&n.change(),!this.o.autoclose||e&&"date"!==e||this.hide()},moveMonth:function(t,n){if(!t)return e;if(!n)return t;var i,o,a=new Date(t.valueOf()),s=a.getUTCDate(),r=a.getUTCMonth(),c=Math.abs(n);if(n=n>0?1:-1,1===c)o=n===-1?function(){return a.getUTCMonth()===r}:function(){return a.getUTCMonth()!==i},i=r+n,a.setUTCMonth(i),(i<0||i>11)&&(i=(i+12)%12);else{for(var l=0;l=this.o.startDate&&t<=this.o.endDate},keydown:function(t){if(!this.picker.is(":visible"))return void(27===t.keyCode&&this.show());var e,n,o,a=!1,s=this.focusDate||this.viewDate;switch(t.keyCode){case 27:this.focusDate?(this.focusDate=null,this.viewDate=this.dates.get(-1)||this.viewDate,this.fill()):this.hide(),t.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;e=37===t.keyCode?-1:1,t.ctrlKey?(n=this.moveYear(this.dates.get(-1)||i(),e),o=this.moveYear(s,e),this._trigger("changeYear",this.viewDate)):t.shiftKey?(n=this.moveMonth(this.dates.get(-1)||i(),e),o=this.moveMonth(s,e),this._trigger("changeMonth",this.viewDate)):(n=new Date(this.dates.get(-1)||i()),n.setUTCDate(n.getUTCDate()+e),o=new Date(s),o.setUTCDate(s.getUTCDate()+e)),this.dateWithinRange(o)&&(this.focusDate=this.viewDate=o,this.setValue(),this.fill(),t.preventDefault());break;case 38:case 40:if(!this.o.keyboardNavigation)break;e=38===t.keyCode?-1:1,t.ctrlKey?(n=this.moveYear(this.dates.get(-1)||i(),e),o=this.moveYear(s,e),this._trigger("changeYear",this.viewDate)):t.shiftKey?(n=this.moveMonth(this.dates.get(-1)||i(),e),o=this.moveMonth(s,e),this._trigger("changeMonth",this.viewDate)):(n=new Date(this.dates.get(-1)||i()),n.setUTCDate(n.getUTCDate()+7*e),o=new Date(s),o.setUTCDate(s.getUTCDate()+7*e)),this.dateWithinRange(o)&&(this.focusDate=this.viewDate=o,this.setValue(),this.fill(),t.preventDefault());break;case 32:break;case 13:s=this.focusDate||this.dates.get(-1)||this.viewDate,this.o.keyboardNavigation&&(this._toggle_multidate(s),a=!0),this.focusDate=null,this.viewDate=this.dates.get(-1)||this.viewDate,this.setValue(),this.fill(),this.picker.is(":visible")&&(t.preventDefault(),"function"==typeof t.stopPropagation?t.stopPropagation():t.cancelBubble=!0,this.o.autoclose&&this.hide());break;case 9:this.focusDate=null,this.viewDate=this.dates.get(-1)||this.viewDate,this.fill(),this.hide()}if(a){this.dates.length?this._trigger("changeDate"):this._trigger("clearDate");var r;this.isInput?r=this.element:this.component&&(r=this.element.find("input")),r&&r.change()}},showMode:function(t){t&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+t))),this.picker.children("div").hide().filter(".datepicker-"+g.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()}};var u=function(e,n){this.element=t(e),this.inputs=t.map(n.inputs,function(t){return t.jquery?t[0]:t}),delete n.inputs,h.call(t(this.inputs),n).bind("changeDate",t.proxy(this.dateUpdated,this)),this.pickers=t.map(this.inputs,function(e){return t(e).data("datepicker")}),this.updateDates()};u.prototype={updateDates:function(){this.dates=t.map(this.pickers,function(t){return t.getUTCDate()}),this.updateRanges()},updateRanges:function(){var e=t.map(this.dates,function(t){return t.valueOf()});t.each(this.pickers,function(t,n){n.setRange(e)})},dateUpdated:function(e){if(!this.updating){this.updating=!0;var n=t(e.target).data("datepicker"),i=n.getUTCDate(),o=t.inArray(e.target,this.inputs),a=o-1,s=o+1,r=this.inputs.length;if(o!==-1){if(t.each(this.pickers,function(t,e){e.getUTCDate()||e.setUTCDate(i)}),i=0&&ithis.dates[s])for(;sthis.dates[s];)this.pickers[s++].setUTCDate(i);this.updateDates(),delete this.updating}}},remove:function(){t.map(this.pickers,function(t){t.remove()}),delete this.element.data().datepicker}};var d=t.fn.datepicker,h=function(n){var i=Array.apply(null,arguments);i.shift();var o;return this.each(function(){var a=t(this),c=a.data("datepicker"),d="object"==typeof n&&n;if(!c){var h=s(this,"date"),f=t.extend({},p,h,d),m=r(f.language),g=t.extend({},p,m,h,d);if(a.hasClass("input-daterange")||g.inputs){var b={inputs:g.inputs||a.find("input").toArray()};a.data("datepicker",c=new u(this,t.extend(g,b)))}else a.data("datepicker",c=new l(this,g))}if("string"==typeof n&&"function"==typeof c[n]&&(o=c[n].apply(c,i),o!==e))return!1}),o!==e?o:this};t.fn.datepicker=h;var p=t.fn.datepicker.defaults={autoclose:!1,beforeShowDay:t.noop,beforeShowMonth:t.noop,calendarWeeks:!1,clearBtn:!1,toggleActive:!1,daysOfWeekDisabled:[],datesDisabled:[],endDate:1/0,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,multidate:!1,multidateSeparator:",",orientation:"auto",rtl:!1,startDate:-(1/0),startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0,disableTouchKeyboard:!1,enableOnReadonly:!0,container:"body"},f=t.fn.datepicker.locale_opts=["format","rtl","weekStart"];t.fn.datepicker.Constructor=l;var m=t.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},g={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(t){return t%4===0&&t%100!==0||t%400===0},getDaysInMonth:function(t,e){return[31,g.isLeapYear(t)?29:28,31,30,31,30,31,31,30,31,30,31][e]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(t){var e=t.replace(this.validParts,"\0").split("\0"),n=t.match(this.validParts);if(!e||!e.length||!n||0===n.length)throw new Error("Invalid date format.");return{separators:e,parts:n}},parseDate:function(i,o,a){function s(){var t=this.slice(0,h[u].length),e=h[u].slice(0,t.length);return t.toLowerCase()===e.toLowerCase()}if(!i)return e;if(i instanceof Date)return i;"string"==typeof o&&(o=g.parseFormat(o));var r,c,u,d=/([\-+]\d+)([dmwy])/,h=i.match(/([\-+]\d+)([dmwy])/g);if(/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(i)){ for(i=new Date,u=0;u«»',contTemplate:'',footTemplate:''};g.template='
    '+g.headTemplate+""+g.footTemplate+'
    '+g.headTemplate+g.contTemplate+g.footTemplate+'
    '+g.headTemplate+g.contTemplate+g.footTemplate+"
    ",t.fn.datepicker.DPGlobal=g,t.fn.datepicker.noConflict=function(){return t.fn.datepicker=d,this},t.fn.datepicker.version="1.4.0",t(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(e){var n=t(this);n.data("datepicker")||(e.preventDefault(),h.call(n,"show"))}),t(function(){h.call(t('[data-provide="datepicker-inline"]'))})}(window.jQuery),!function(t){t.fn.datepicker.dates.de={days:["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag"],daysShort:["Son","Mon","Die","Mit","Don","Fre","Sam","Son"],daysMin:["So","Mo","Di","Mi","Do","Fr","Sa","So"],months:["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"],monthsShort:["Jan","Feb","Mär","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Dez"],today:"Heute",clear:"Löschen",weekStart:1,format:"dd.mm.yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.da={days:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag","Søndag"],daysShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør","Søn"],daysMin:["Sø","Ma","Ti","On","To","Fr","Lø","Sø"],months:["Januar","Februar","Marts","April","Maj","Juni","Juli","August","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],today:"I Dag",clear:"Nulstil"}}(jQuery),!function(t){t.fn.datepicker.dates["pt-BR"]={days:["Domingo","Segunda","Terça","Quarta","Quinta","Sexta","Sábado","Domingo"],daysShort:["Dom","Seg","Ter","Qua","Qui","Sex","Sáb","Dom"],daysMin:["Do","Se","Te","Qu","Qu","Se","Sa","Do"],months:["Janeiro","Fevereiro","Março","Abril","Maio","Junho","Julho","Agosto","Setembro","Outubro","Novembro","Dezembro"],monthsShort:["Jan","Fev","Mar","Abr","Mai","Jun","Jul","Ago","Set","Out","Nov","Dez"],today:"Hoje",clear:"Limpar"}}(jQuery),!function(t){t.fn.datepicker.dates.nl={days:["zondag","maandag","dinsdag","woensdag","donderdag","vrijdag","zaterdag","zondag"],daysShort:["zo","ma","di","wo","do","vr","za","zo"],daysMin:["zo","ma","di","wo","do","vr","za","zo"],months:["januari","februari","maart","april","mei","juni","juli","augustus","september","oktober","november","december"],monthsShort:["jan","feb","mrt","apr","mei","jun","jul","aug","sep","okt","nov","dec"],today:"Vandaag",clear:"Wissen",weekStart:1,format:"dd-mm-yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.fr={days:["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"],daysShort:["dim.","lun.","mar.","mer.","jeu.","ven.","sam.","dim."],daysMin:["d","l","ma","me","j","v","s","d"],months:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"],monthsShort:["janv.","févr.","mars","avril","mai","juin","juil.","août","sept.","oct.","nov.","déc."],today:"Aujourd'hui",clear:"Effacer",weekStart:1,format:"dd/mm/yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.it={days:["Domenica","Lunedì","Martedì","Mercoledì","Giovedì","Venerdì","Sabato","Domenica"],daysShort:["Dom","Lun","Mar","Mer","Gio","Ven","Sab","Dom"],daysMin:["Do","Lu","Ma","Me","Gi","Ve","Sa","Do"],months:["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],monthsShort:["Gen","Feb","Mar","Apr","Mag","Giu","Lug","Ago","Set","Ott","Nov","Dic"],today:"Oggi",clear:"Cancella",weekStart:1,format:"dd/mm/yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.lt={days:["Sekmadienis","Pirmadienis","Antradienis","Trečiadienis","Ketvirtadienis","Penktadienis","Šeštadienis","Sekmadienis"],daysShort:["S","Pr","A","T","K","Pn","Š","S"],daysMin:["Sk","Pr","An","Tr","Ke","Pn","Št","Sk"],months:["Sausis","Vasaris","Kovas","Balandis","Gegužė","Birželis","Liepa","Rugpjūtis","Rugsėjis","Spalis","Lapkritis","Gruodis"],monthsShort:["Sau","Vas","Kov","Bal","Geg","Bir","Lie","Rugp","Rugs","Spa","Lap","Gru"],today:"Šiandien",weekStart:1}}(jQuery),!function(t){t.fn.datepicker.dates.no={days:["Søndag","Mandag","Tirsdag","Onsdag","Torsdag","Fredag","Lørdag"],daysShort:["Søn","Man","Tir","Ons","Tor","Fre","Lør"],daysMin:["Sø","Ma","Ti","On","To","Fr","Lø"],months:["Januar","Februar","Mars","April","Mai","Juni","Juli","August","September","Oktober","November","Desember"],monthsShort:["Jan","Feb","Mar","Apr","Mai","Jun","Jul","Aug","Sep","Okt","Nov","Des"],today:"I dag",clear:"Nullstill",weekStart:1,format:"dd.mm.yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.es={days:["Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado","Domingo"],daysShort:["Dom","Lun","Mar","Mié","Jue","Vie","Sáb","Dom"],daysMin:["Do","Lu","Ma","Mi","Ju","Vi","Sa","Do"],months:["Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"],monthsShort:["Ene","Feb","Mar","Abr","May","Jun","Jul","Ago","Sep","Oct","Nov","Dic"],today:"Hoy",clear:"Borrar",weekStart:1,format:"dd/mm/yyyy"}}(jQuery),!function(t){t.fn.datepicker.dates.sv={days:["Söndag","Måndag","Tisdag","Onsdag","Torsdag","Fredag","Lördag","Söndag"],daysShort:["Sön","Mån","Tis","Ons","Tor","Fre","Lör","Sön"],daysMin:["Sö","Må","Ti","On","To","Fr","Lö","Sö"],months:["Januari","Februari","Mars","April","Maj","Juni","Juli","Augusti","September","Oktober","November","December"],monthsShort:["Jan","Feb","Mar","Apr","Maj","Jun","Jul","Aug","Sep","Okt","Nov","Dec"],today:"Idag",format:"yyyy-mm-dd",weekStart:1,clear:"Rensa"}}(jQuery),function(){var t,e,n,i,o,a,s,r,c=[].slice,l={}.hasOwnProperty,u=function(t,e){function n(){this.constructor=t}for(var i in e)l.call(e,i)&&(t[i]=e[i]);return n.prototype=e.prototype,t.prototype=new n,t.__super__=e.prototype,t};s=function(){},e=function(){function t(){}return t.prototype.addEventListener=t.prototype.on,t.prototype.on=function(t,e){return this._callbacks=this._callbacks||{},this._callbacks[t]||(this._callbacks[t]=[]),this._callbacks[t].push(e),this},t.prototype.emit=function(){var t,e,n,i,o,a;if(i=arguments[0],t=2<=arguments.length?c.call(arguments,1):[],this._callbacks=this._callbacks||{},n=this._callbacks[i])for(o=0,a=n.length;o
    '),this.element.appendChild(e)),i=e.getElementsByTagName("span")[0],i&&(null!=i.textContent?i.textContent=this.options.dictFallbackMessage:null!=i.innerText&&(i.innerText=this.options.dictFallbackMessage)),this.element.appendChild(this.getFallbackForm())},resize:function(t){var e,n,i;return e={srcX:0,srcY:0,srcWidth:t.width,srcHeight:t.height},n=t.width/t.height,e.optWidth=this.options.thumbnailWidth,e.optHeight=this.options.thumbnailHeight,null==e.optWidth&&null==e.optHeight?(e.optWidth=e.srcWidth,e.optHeight=e.srcHeight):null==e.optWidth?e.optWidth=n*e.optHeight:null==e.optHeight&&(e.optHeight=1/n*e.optWidth),i=e.optWidth/e.optHeight,t.heighti?(e.srcHeight=t.height,e.srcWidth=e.srcHeight*i):(e.srcWidth=t.width,e.srcHeight=e.srcWidth/i),e.srcX=(t.width-e.srcWidth)/2,e.srcY=(t.height-e.srcHeight)/2,e},drop:function(t){return this.element.classList.remove("dz-drag-hover")},dragstart:s,dragend:function(t){return this.element.classList.remove("dz-drag-hover")},dragenter:function(t){return this.element.classList.add("dz-drag-hover")},dragover:function(t){return this.element.classList.add("dz-drag-hover")},dragleave:function(t){return this.element.classList.remove("dz-drag-hover")},paste:s,reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(t){var e,i,o,a,s,r,c,l,u,d,h,p,f;if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer){for(t.previewElement=n.createElement(this.options.previewTemplate.trim()),t.previewTemplate=t.previewElement,this.previewsContainer.appendChild(t.previewElement),d=t.previewElement.querySelectorAll("[data-dz-name]"),a=0,c=d.length;a'+this.options.dictRemoveFile+""),t.previewElement.appendChild(t._removeLink)),i=function(e){return function(i){return i.preventDefault(),i.stopPropagation(),t.status===n.UPLOADING?n.confirm(e.options.dictCancelUploadConfirmation,function(){return e.removeFile(t)}):e.options.dictRemoveFileConfirmation?n.confirm(e.options.dictRemoveFileConfirmation,function(){return e.removeFile(t)}):e.removeFile(t)}}(this),p=t.previewElement.querySelectorAll("[data-dz-remove]"),f=[],r=0,u=p.length;r\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n \n Check\n \n \n \n \n \n
    \n
    \n \n Error\n \n \n \n \n \n \n \n
    \n
    '},i=function(){var t,e,n,i,o,a,s;for(i=arguments[0],n=2<=arguments.length?c.call(arguments,1):[],a=0,s=n.length;a'+this.options.dictDefaultMessage+"
    ")),this.clickableElements.length&&(i=function(t){return function(){return t.hiddenFileInput&&t.hiddenFileInput.parentNode.removeChild(t.hiddenFileInput),t.hiddenFileInput=document.createElement("input"),t.hiddenFileInput.setAttribute("type","file"),(null==t.options.maxFiles||t.options.maxFiles>1)&&t.hiddenFileInput.setAttribute("multiple","multiple"),t.hiddenFileInput.className="dz-hidden-input",null!=t.options.acceptedFiles&&t.hiddenFileInput.setAttribute("accept",t.options.acceptedFiles),null!=t.options.capture&&t.hiddenFileInput.setAttribute("capture",t.options.capture),t.hiddenFileInput.style.visibility="hidden",t.hiddenFileInput.style.position="absolute",t.hiddenFileInput.style.top="0",t.hiddenFileInput.style.left="0",t.hiddenFileInput.style.height="0",t.hiddenFileInput.style.width="0",document.querySelector(t.options.hiddenInputContainer).appendChild(t.hiddenFileInput),t.hiddenFileInput.addEventListener("change",function(){var e,n,o,a;if(n=t.hiddenFileInput.files,n.length)for(o=0,a=n.length;o',this.options.dictFallbackText&&(i+="

    "+this.options.dictFallbackText+"

    "),i+='
    ',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(_,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 d;return d=o(e),t.drawImage(e,n,i,a,s,r,c,l,u/d)},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(d){}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