diff --git a/app/Console/Commands/ChargeRenewalInvoices.php b/app/Console/Commands/ChargeRenewalInvoices.php index 6ccdd59b4..2a33e6b73 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 28f994a86..479c780ae 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 f37de078b..7caf1944f 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 c6d921424..f53e1f6ac 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 65c87bb5d..533f14d3c 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 9e3a5640e..480b2dfab 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 ce661153f..dcd1bcc2e 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 048eaddf7..145464efe 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 f43e8fafa..99b6c0a82 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 11017db15..03f5e1429 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 000000000..ef0a1a2a9 --- /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 54df4167e..bdaf103dd 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 dc6c335cc..91184eb68 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 f1b3041de..c86bb1aef 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 559840caa..5a112b9ba 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 f095ce9d1..cb0b6ed3d 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 eb2e6d8cc..f99fc56e3 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 8b0bdba22..7295e9312 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 35956179e..5b59a5b38 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 80abe6b2c..7911d8127 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 c264320a0..d7fdc8c8c 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 70dfbb132..511c10cfa 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 92e04ecd7..a47e1a62f 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 000000000..1dd19ab9f --- /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 d87ea2713..0ca7eb647 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 1d6f93109..d69b9f150 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 28a544cb3..4ed2ea0c0 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 eb2d5d067..e29c173c9 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 1510325c8..84e5666cf 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 01594fa5a..690c6086c 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 520551578..c74f705f3 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 852f0f7bc..f45667893 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 7b8ad7081..e7da8b536 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 000000000..ef11a64e1 --- /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 000000000..18259c442 --- /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 000000000..9b5fa1a84 --- /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 000000000..c0bcd03c4 --- /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 000000000..846466e4a --- /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 27eed69b6..06b363297 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 0fc43d994..6b2ee1e90 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 82d4d2fcb..adb97de56 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 b493c784d..f00be58d7 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 f4f5ac3a2..384bd48a9 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 310ebaaf6..7bd19386d 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 c233ac7e7..852bef8ab 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 b01f68e9b..6f8546376 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 6f96aee3b..f4cd6e23d 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 000000000..44002ecf9 --- /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 000000000..3a11ddd73 --- /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 000000000..1c1c0fd59 --- /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 000000000..b54d976e0 --- /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 000000000..faebe4a15 --- /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 37734f183..92b3533dd 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 000000000..adb224eb4 --- /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 000000000..07d83fe9f --- /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 07f39406e..a3bc5f9ab 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 000000000..022a65087 --- /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 000000000..8e106e045 --- /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 000000000..052d4e7a0 --- /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 000000000..68cfde293 --- /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 000000000..e491b52d6 --- /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 000000000..c19abc511 --- /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 4304e3cc2..2fd37b971 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 1151d70c7..a43a3f0a9 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 104637268..effa021b9 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 1b42f1bbe..3fc7b5957 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 63734d218..b9782b6da 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 6464043d6..3de931825 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 83d6253a7..33126f865 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 9eee52320..3fd5380f4 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 f1910ab2f..3413812ea 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 769e007da..bb610d4de 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 86c0de60e..184a15fba 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 e94912771..19865151c 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 a5757ad74..535ec60de 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 7d992d6c9..de128945a 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 2f20a8f8a..4a7394454 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 e10719ff2..ca6d7747f 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 90de300f5..a1d03ee35 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 e830e56a0..d922d641e 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 1dc81d2c3..34c92288a 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 76d395efd..8fa8a23b7 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 9e7334ede..a9f5ea0d3 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 c30b16037..6d96e7201 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 000000000..cd5b348db --- /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 ca632d655..455f75bc9 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 000000000..37ffe27b2 --- /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 000000000..2efda4258 --- /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 000000000..0bfc6c1cc --- /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 000000000..b53720db9 --- /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 000000000..1bd221ce9 --- /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 04703e916..8eb8b6c6f 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 ad29cd07a..130195ee1 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 43a24cc6f..d6b01e2a6 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 000000000..098c65cf5 --- /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 d71512120..e6961dadf 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 e1a5556a8..6162bffef 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 1dd933396..4f4a7112d 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 56b7bea19..3c6f31327 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 e427ed5e1..a97df299b 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 02fd80845..08e55549e 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 620366c21..e489c89a7 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 801fb52a9..3cba7faf4 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 193207f9d..e0be4b78c 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 d5a3aba10..33c691806 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 000000000..53d44b850 --- /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 000000000..596f28f7a --- /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 000000000..7e97c2a83 --- /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 000000000..9b18798bb --- /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 e8a131159..78a6fdb7d 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 df434b119..2f4555da7 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 d83d9a501..c07cac012 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 e019c899b..c4a5814af 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 e42308b0b..7a29cc065 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 b64ade053..4d1c5299f 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 22e146e2c..cdfde4b8f 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 6647f56d5..50dbb8727 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 aac226b3f..26cd5165d 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 6b5d130b6..9cd34e945 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 8e414fff0..c20ee7b8e 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 901d2a307..2be1c5b83 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 0b3904c1d..f95082322 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 2296cb5ac..5ed162b51 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 3bc6ab030..17f08a323 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 fda0104bf..2cac47973 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 0411df7a5..e7a0acf92 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 07ffa8789..e3c0177c7 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 000000000..eca4e906d --- /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 000000000..fd94da49f --- /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 701147b15..a96f0e4ca 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 2aaac5188..cf4e9dce9 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 dc0ec6381..0b4a3ada5 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 befde9b3b..a51e0c6c2 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 000000000..6ba311c38 --- /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 c87408731..bfa195034 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 788b33908..85c915d8a 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 54b5353e9..51be25981 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 53d201f18..13dd355b8 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 d0a9c7c96..9ccc7ea03 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 cd16ed49b..fd2372d96 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 704bc4820..fbc1e2152 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 b19e871c8..9419af24b 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 7fad4c6e1..f40051340 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 9ec579aed..236f340e1 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 450d48f2b..e470348a3 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 e9e9cc66e..d46bac6fa 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 78212cef6..86f9cfed5 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 000000000..734977bcf --- /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 000000000..6e7bf01a0 --- /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 000000000..5a413815c --- /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 000000000..9470a98d3 --- /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 b4687f8b1..e59af6999 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 000000000..57fc1304e --- /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 dbff6390a..ad049b183 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 000000000..4d89178ea --- /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 97714c29f..bbc80083e 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 ef2512c79..8978f2ac0 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 3f9723c93..5a501e891 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 4738e0eaf..245741caa 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 b8508f6f3..7c927660b 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 00eec4ddf..386755926 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 000000000..5fff79695 --- /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 000000000..eb7542738 --- /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 000000000..981ac8c34 --- /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 000000000..c367051b0 --- /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 e98cfff39..8ed901d40 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 5b9c049bb..f8330738a 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 b5e503950..b7d93290c 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 a83703eb2..7370febc3 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 f89e00e2f..00da54775 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 000000000..24afac17a --- /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 f29108498..18416e6df 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 9ed457335..2849d6343 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 955b75a9e..0fa5e8c4d 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 000000000..f8e6eddba --- /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 77d617603..6021f7f37 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 40b86abf2..eecd25323 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 51ef4dc65..a2c229169 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 72948c47d..20928a184 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 155e4e66f..1e74b8657 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 697036d48..3af26a711 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 cf4955fde..44a56c351 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 16a26c5e6..ed5bd8964 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 7c4419f31..3bd00eb9c 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 2052565cb..87fdc04d2 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 e6becc703..6646bc63d 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