mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 23:37:33 -05:00 
			
		
		
		
	Merge branch 'release-2.6.9'
Conflicts: app/Http/routes.php app/Ninja/PaymentDrivers/BasePaymentDriver.php composer.lock resources/lang/en/texts.php resources/views/reports/chart_builder.blade.php
This commit is contained in:
		
						commit
						c7c253fbd8
					
				@ -1,7 +1,7 @@
 | 
			
		||||
APP_ENV=production
 | 
			
		||||
APP_DEBUG=false
 | 
			
		||||
APP_URL=http://ninja.dev
 | 
			
		||||
APP_KEY=SomeRandomString
 | 
			
		||||
APP_KEY=SomeRandomStringSomeRandomString
 | 
			
		||||
APP_CIPHER=AES-256-CBC
 | 
			
		||||
 | 
			
		||||
DB_TYPE=mysql
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@ -1,3 +1,8 @@
 | 
			
		||||
* text=auto
 | 
			
		||||
*.css linguist-vendored
 | 
			
		||||
*.less linguist-vendored
 | 
			
		||||
.gitattributes export-ignore
 | 
			
		||||
.gitignore export-ignore
 | 
			
		||||
.codeclimate.yml export-ignore
 | 
			
		||||
.travis.yml export-ignore
 | 
			
		||||
.styleci.yml export-ignore
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,7 @@ before_install:
 | 
			
		||||
  - if [ -n "$GH_TOKEN" ]; then composer config github-oauth.github.com ${GH_TOKEN}; fi;
 | 
			
		||||
  - composer self-update && composer -V
 | 
			
		||||
#  - export USE_ZEND_ALLOC=0
 | 
			
		||||
  - rvm use 1.9.3 --install --fuzzy
 | 
			
		||||
 | 
			
		||||
install:
 | 
			
		||||
  # install Composer dependencies
 | 
			
		||||
 | 
			
		||||
@ -2,8 +2,15 @@
 | 
			
		||||
All notable changes to this project will be documented in this file.
 | 
			
		||||
This project adheres to [Semantic Versioning](http://semver.org/).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## [Unreleased]
 | 
			
		||||
 | 
			
		||||
### Changed
 | 
			
		||||
- Auto billing uses credits if they exist
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## [2.6.4] - 2016-07-19
 | 
			
		||||
 | 
			
		||||
### Added
 | 
			
		||||
- Added 'Buy Now' buttons
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@ Thanks for your contributions!
 | 
			
		||||
 * Make your changes and commit
 | 
			
		||||
 * Check if your branch is still in sync with the repositorys **`develop`** branch
 | 
			
		||||
   * _Read:_ [Syncing a fork](https://help.github.com/articles/syncing-a-fork/)
 | 
			
		||||
   * _Also read:_ [How to rebase a pull request](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request)
 | 
			
		||||
   * _Also read:_ [How to rebase a pull request](https://github.com/edx/edx-platform/wiki/How-to-Rebase-a-Pull-Request) 
 | 
			
		||||
 * Push your branch and create a PR against the Invoice Ninja **`develop`** branch
 | 
			
		||||
 * Update the [Changelog](CHANGELOG.md)
 | 
			
		||||
 | 
			
		||||
@ -21,7 +21,7 @@ To make the contribution process nice and easy for anyone, please follow some ru
 | 
			
		||||
to give a more detailed explanation.
 | 
			
		||||
 * Only one feature/bugfix per issue. If you want to submit more, create multiple issues.
 | 
			
		||||
 * Only one feature/bugfix per PR(pull request). Split more changes into multiple PRs.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
#### Coding Style
 | 
			
		||||
Try to follow the [PSR-2 guidlines](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,7 @@ _Example styling:_
 | 
			
		||||
```php
 | 
			
		||||
/**
 | 
			
		||||
 * Gets a preview of the email
 | 
			
		||||
 *
 | 
			
		||||
 * 
 | 
			
		||||
 * @param TemplateService $templateService
 | 
			
		||||
 *
 | 
			
		||||
 * @return \Illuminate\Http\Response
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										30
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Gruntfile.js
									
									
									
									
									
								
							@ -4,12 +4,12 @@ module.exports = function(grunt) {
 | 
			
		||||
    pkg: grunt.file.readJSON('package.json'),
 | 
			
		||||
    dump_dir: (function() {
 | 
			
		||||
      var out = {};
 | 
			
		||||
      
 | 
			
		||||
 | 
			
		||||
      grunt.file.expand({ filter: 'isDirectory'}, 'public/fonts/invoice-fonts/*').forEach(function(path) {
 | 
			
		||||
        var fontName = /[^/]*$/.exec(path)[0],
 | 
			
		||||
            files = {},
 | 
			
		||||
            license='';
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // Add license text
 | 
			
		||||
        grunt.file.expand({ filter: 'isFile'}, path+'/*.txt').forEach(function(path) {
 | 
			
		||||
            var licenseText = grunt.file.read(path);
 | 
			
		||||
@ -19,10 +19,10 @@ module.exports = function(grunt) {
 | 
			
		||||
 | 
			
		||||
            license += "/*\n"+licenseText+"\n*/";
 | 
			
		||||
        });
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
        // Create files list
 | 
			
		||||
        files['public/js/vfs_fonts/'+fontName+'.js'] = [path+'/*.ttf'];
 | 
			
		||||
          
 | 
			
		||||
 | 
			
		||||
        out[fontName] = {
 | 
			
		||||
          options: {
 | 
			
		||||
            pre: license+'window.ninjaFontVfs=window.ninjaFontVfs||{};window.ninjaFontVfs.'+fontName+'=',
 | 
			
		||||
@ -30,8 +30,8 @@ module.exports = function(grunt) {
 | 
			
		||||
          },
 | 
			
		||||
          files: files
 | 
			
		||||
        };
 | 
			
		||||
      });      
 | 
			
		||||
         
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      // Return the computed object
 | 
			
		||||
      return out;
 | 
			
		||||
    }()),
 | 
			
		||||
@ -104,8 +104,8 @@ module.exports = function(grunt) {
 | 
			
		||||
          'public/vendor/moment-timezone/builds/moment-timezone-with-data.min.js',
 | 
			
		||||
          'public/vendor/stacktrace-js/dist/stacktrace-with-polyfills.min.js',
 | 
			
		||||
          'public/vendor/fuse.js/src/fuse.min.js',
 | 
			
		||||
          'public/vendor/sweetalert/dist/sweetalert.min.js',
 | 
			
		||||
          //'public/vendor/moment-duration-format/lib/moment-duration-format.js',
 | 
			
		||||
          //'public/vendor/handsontable/dist/jquery.handsontable.full.min.js',
 | 
			
		||||
          //'public/vendor/pdfmake/build/pdfmake.min.js',
 | 
			
		||||
          //'public/vendor/pdfmake/build/vfs_fonts.js',
 | 
			
		||||
          //'public/js/vfs_fonts.js',
 | 
			
		||||
@ -116,14 +116,12 @@ module.exports = function(grunt) {
 | 
			
		||||
        dest: 'public/built.js',
 | 
			
		||||
        nonull: true
 | 
			
		||||
      },
 | 
			
		||||
      js_public: {
 | 
			
		||||
      /*js_public: {
 | 
			
		||||
        src: [
 | 
			
		||||
        /*
 | 
			
		||||
          'public/js/simpleexpand.js',
 | 
			
		||||
          'public/js/valign.js',
 | 
			
		||||
          'public/js/bootstrap.min.js',
 | 
			
		||||
          'public/js/simpleexpand.js',
 | 
			
		||||
        */
 | 
			
		||||
          'public/vendor/bootstrap/dist/js/bootstrap.min.js',
 | 
			
		||||
          'public/js/bootstrap-combobox.js',
 | 
			
		||||
 | 
			
		||||
@ -142,7 +140,7 @@ module.exports = function(grunt) {
 | 
			
		||||
          'public/vendor/spectrum/spectrum.css',
 | 
			
		||||
          'public/css/bootstrap-combobox.css',
 | 
			
		||||
          'public/css/typeahead.js-bootstrap.css',
 | 
			
		||||
          //'public/vendor/handsontable/dist/jquery.handsontable.full.css',
 | 
			
		||||
          'public/vendor/sweetalert/dist/sweetalert.css',
 | 
			
		||||
          'public/css/style.css',
 | 
			
		||||
        ],
 | 
			
		||||
        dest: 'public/css/built.css',
 | 
			
		||||
@ -150,8 +148,8 @@ module.exports = function(grunt) {
 | 
			
		||||
        options: {
 | 
			
		||||
            process: false
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      css_public: {
 | 
			
		||||
      },*/
 | 
			
		||||
      /*css_public: {
 | 
			
		||||
        src: [
 | 
			
		||||
          'public/vendor/bootstrap/dist/css/bootstrap.min.css',
 | 
			
		||||
          'public/vendor/font-awesome/css/font-awesome.min.css',
 | 
			
		||||
@ -165,8 +163,8 @@ module.exports = function(grunt) {
 | 
			
		||||
        options: {
 | 
			
		||||
            process: false
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      js_pdf: {
 | 
			
		||||
      },*/
 | 
			
		||||
      /*js_pdf: {
 | 
			
		||||
        src: [
 | 
			
		||||
          'public/js/pdf_viewer.js',
 | 
			
		||||
          'public/js/compatibility.js',
 | 
			
		||||
@ -175,7 +173,7 @@ module.exports = function(grunt) {
 | 
			
		||||
        ],
 | 
			
		||||
        dest: 'public/pdf.built.js',
 | 
			
		||||
        nonull: true
 | 
			
		||||
      }
 | 
			
		||||
      }*/
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
# Invoice Ninja
 | 
			
		||||
 | 
			
		||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
 | 
			
		||||
[](https://travis-ci.org/invoiceninja/invoiceninja)
 | 
			
		||||
[](https://gitter.im/hillelcoren/invoice-ninja?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 | 
			
		||||
 | 
			
		||||
## [Hosted](https://www.invoiceninja.com) | [Self-hosted](https://invoiceninja.org)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								app/Console/Commands/ResetInvoiceSchemaCounter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								app/Console/Commands/ResetInvoiceSchemaCounter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Console\Commands;
 | 
			
		||||
 | 
			
		||||
use App\Models\Account;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use Carbon\Carbon;
 | 
			
		||||
use Illuminate\Console\Command;
 | 
			
		||||
 | 
			
		||||
class ResetInvoiceSchemaCounter extends Command
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * The name and signature of the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $signature = 'ninja:reset-invoice-schema-counter
 | 
			
		||||
                            {account? : The ID of the account}
 | 
			
		||||
                            {--force : Force setting the counter back to "1", regardless if the year changed}';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The console command description.
 | 
			
		||||
     *
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $description = 'Reset the invoice schema counter at the turn of the year.';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var Invoice
 | 
			
		||||
     */
 | 
			
		||||
    protected $invoice;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a new command instance.
 | 
			
		||||
     *
 | 
			
		||||
     * @param Invoice $invoice
 | 
			
		||||
     */
 | 
			
		||||
    public function __construct(Invoice $invoice)
 | 
			
		||||
    {
 | 
			
		||||
        parent::__construct();
 | 
			
		||||
        $this->invoice = $invoice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Execute the console command.
 | 
			
		||||
     *
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function handle()
 | 
			
		||||
    {
 | 
			
		||||
        $force = $this->option('force');
 | 
			
		||||
        $account = $this->argument('account');
 | 
			
		||||
 | 
			
		||||
        $accounts = null;
 | 
			
		||||
 | 
			
		||||
        if ($account) {
 | 
			
		||||
            $accounts = Account::find($account)->get();
 | 
			
		||||
        } else {
 | 
			
		||||
            $accounts = Account::all();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $latestInvoice = $this->invoice->latest()->first();
 | 
			
		||||
        $invoiceYear = Carbon::parse($latestInvoice->created_at)->year;
 | 
			
		||||
 | 
			
		||||
        if(Carbon::now()->year > $invoiceYear || $force) {
 | 
			
		||||
            $accounts->transform(function ($a) {
 | 
			
		||||
                /** @var Account $a */
 | 
			
		||||
                $a->invoice_number_counter = 1;
 | 
			
		||||
                $a->update();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            $this->info('The counter has been resetted successfully for '.$accounts->count().' account(s).');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -21,8 +21,8 @@ class Kernel extends ConsoleKernel
 | 
			
		||||
        'App\Console\Commands\SendRenewalInvoices',
 | 
			
		||||
        'App\Console\Commands\ChargeRenewalInvoices',
 | 
			
		||||
        'App\Console\Commands\SendReminders',
 | 
			
		||||
        'App\Console\Commands\TestOFX',
 | 
			
		||||
        'App\Console\Commands\GenerateResources',
 | 
			
		||||
        'App\Console\Commands\TestOFX',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -1461,6 +1461,7 @@ class AccountController extends BaseController
 | 
			
		||||
            return trans('texts.create_invoice_for_sample');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /** @var \App\Models\Account $account */
 | 
			
		||||
        $account = Auth::user()->account;
 | 
			
		||||
        $invitation = $invoice->invitations->first();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,8 @@ class AccountGatewayController extends BaseController
 | 
			
		||||
        $data['hiddenFields'] = Gateway::$hiddenFields;
 | 
			
		||||
        $data['selectGateways'] = Gateway::where('id', '=', $accountGateway->gateway_id)->get();
 | 
			
		||||
 | 
			
		||||
        $this->testGateway($accountGateway);
 | 
			
		||||
 | 
			
		||||
        return View::make('accounts.account_gateway', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -307,7 +309,7 @@ class AccountGatewayController extends BaseController
 | 
			
		||||
                $account->account_gateways()->save($accountGateway);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(isset($wepayResponse)) {
 | 
			
		||||
            if (isset($wepayResponse)) {
 | 
			
		||||
                return $wepayResponse;
 | 
			
		||||
            } else {
 | 
			
		||||
                if ($accountGatewayPublicId) {
 | 
			
		||||
@ -322,6 +324,16 @@ class AccountGatewayController extends BaseController
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function testGateway($accountGateway)
 | 
			
		||||
    {
 | 
			
		||||
        $paymentDriver = $accountGateway->paymentDriver();
 | 
			
		||||
        $result = $paymentDriver->isValid();
 | 
			
		||||
 | 
			
		||||
        if ($result !== true) {
 | 
			
		||||
            Session::flash('error', $result . ' - ' . trans('texts.gateway_config_error'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function getWePayUpdateUri($accountGateway)
 | 
			
		||||
    {
 | 
			
		||||
        if ($accountGateway->gateway_id != GATEWAY_WEPAY) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										323
									
								
								app/Http/Controllers/BotController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										323
									
								
								app/Http/Controllers/BotController.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,323 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Http\Controllers;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use DB;
 | 
			
		||||
use Utils;
 | 
			
		||||
use Cache;
 | 
			
		||||
use Input;
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Libraries\Skype\SkypeResponse;
 | 
			
		||||
use App\Libraries\CurlUtils;
 | 
			
		||||
use App\Models\User;
 | 
			
		||||
use App\Models\SecurityCode;
 | 
			
		||||
use App\Ninja\Intents\BaseIntent;
 | 
			
		||||
use App\Ninja\Mailers\UserMailer;
 | 
			
		||||
 | 
			
		||||
class BotController extends Controller
 | 
			
		||||
{
 | 
			
		||||
    protected $userMailer;
 | 
			
		||||
 | 
			
		||||
    public function __construct(UserMailer $userMailer)
 | 
			
		||||
    {
 | 
			
		||||
        $this->userMailer = $userMailer;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handleMessage($platform)
 | 
			
		||||
    {
 | 
			
		||||
        $input = Input::all();
 | 
			
		||||
        $botUserId = $input['from']['id'];
 | 
			
		||||
 | 
			
		||||
        if ( ! $token = $this->authenticate($input)) {
 | 
			
		||||
            return SkypeResponse::message(trans('texts.not_authorized'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            if ($input['type'] === 'contactRelationUpdate') {
 | 
			
		||||
                // brand new user, ask for their email
 | 
			
		||||
                if ($input['action'] === 'add') {
 | 
			
		||||
                    $response = SkypeResponse::message(trans('texts.bot_get_email'));
 | 
			
		||||
                    $state = BOT_STATE_GET_EMAIL;
 | 
			
		||||
                } elseif ($input['action'] === 'remove') {
 | 
			
		||||
                    $this->removeBot($botUserId);
 | 
			
		||||
                    $this->saveState($token, false);
 | 
			
		||||
                    return RESULT_SUCCESS;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                $state = $this->loadState($token);
 | 
			
		||||
                $text = strip_tags($input['text']);
 | 
			
		||||
 | 
			
		||||
                // user gaves us their email
 | 
			
		||||
                if ($state === BOT_STATE_GET_EMAIL) {
 | 
			
		||||
                    if ($this->validateEmail($text, $botUserId)) {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.bot_get_code'));
 | 
			
		||||
                        $state = BOT_STATE_GET_CODE;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.email_not_found', ['email' => $text]));
 | 
			
		||||
                    }
 | 
			
		||||
                // user sent the scurity code
 | 
			
		||||
                } elseif ($state === BOT_STATE_GET_CODE) {
 | 
			
		||||
                    if ($this->validateCode($text, $botUserId)) {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.bot_welcome') . trans('texts.bot_help_message'));
 | 
			
		||||
                        $state = BOT_STATE_READY;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.invalid_code'));
 | 
			
		||||
                    }
 | 
			
		||||
                // regular chat message
 | 
			
		||||
                } else {
 | 
			
		||||
                    if ($message === 'help') {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.bot_help_message'));
 | 
			
		||||
                    } elseif ($message == 'status') {
 | 
			
		||||
                        $response = SkypeResponse::message(trans('texts.intent_not_supported'));
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if ( ! $user = User::whereBotUserId($botUserId)->with('account')->first()) {
 | 
			
		||||
                            return SkypeResponse::message(trans('texts.not_authorized'));
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        Auth::onceUsingId($user->id);
 | 
			
		||||
                        $user->account->loadLocalizationSettings();
 | 
			
		||||
 | 
			
		||||
                        $data = $this->parseMessage($text);
 | 
			
		||||
                        $intent = BaseIntent::createIntent($state, $data);
 | 
			
		||||
                        $response = $intent->process();
 | 
			
		||||
                        $state = $intent->getState();
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $this->saveState($token, $state);
 | 
			
		||||
        } catch (Exception $exception) {
 | 
			
		||||
            $response = SkypeResponse::message($exception->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->sendResponse($token, $botUserId, $response);
 | 
			
		||||
 | 
			
		||||
        return RESULT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function authenticate($input)
 | 
			
		||||
    {
 | 
			
		||||
        $headers = getallheaders();
 | 
			
		||||
        $token = isset($headers['Authorization']) ? $headers['Authorization'] : false;
 | 
			
		||||
 | 
			
		||||
        if (Utils::isNinjaDev()) {
 | 
			
		||||
            // skip validation for testing
 | 
			
		||||
        } elseif ( ! $this->validateToken($token)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($token = Cache::get('msbot_token')) {
 | 
			
		||||
            return $token;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $clientId = env('MSBOT_CLIENT_ID');
 | 
			
		||||
        $clientSecret = env('MSBOT_CLIENT_SECRET');
 | 
			
		||||
        $scope = 'https://graph.microsoft.com/.default';
 | 
			
		||||
 | 
			
		||||
        $data = sprintf('grant_type=client_credentials&client_id=%s&client_secret=%s&scope=%s', $clientId, $clientSecret, $scope);
 | 
			
		||||
 | 
			
		||||
        $response = CurlUtils::post(MSBOT_LOGIN_URL, $data);
 | 
			
		||||
        $response = json_decode($response);
 | 
			
		||||
 | 
			
		||||
        $expires = ($response->expires_in / 60) - 5;
 | 
			
		||||
        Cache::put('msbot_token', $response->access_token, $expires);
 | 
			
		||||
 | 
			
		||||
        return $response->access_token;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function loadState($token)
 | 
			
		||||
    {
 | 
			
		||||
        $url = sprintf('%s/botstate/skype/conversations/%s', MSBOT_STATE_URL, '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts');
 | 
			
		||||
 | 
			
		||||
        $headers = [
 | 
			
		||||
            'Authorization: Bearer ' . $token
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $response = CurlUtils::get($url, $headers);
 | 
			
		||||
        $data = json_decode($response);
 | 
			
		||||
 | 
			
		||||
        return json_decode($data->data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function parseMessage($message)
 | 
			
		||||
    {
 | 
			
		||||
        $appId = env('MSBOT_LUIS_APP_ID');
 | 
			
		||||
        $subKey = env('MSBOT_LUIS_SUBSCRIPTION_KEY');
 | 
			
		||||
        $message = rawurlencode($message);
 | 
			
		||||
 | 
			
		||||
        $url = sprintf('%s?id=%s&subscription-key=%s&q=%s', MSBOT_LUIS_URL, $appId, $subKey, $message);
 | 
			
		||||
        $data = file_get_contents($url);
 | 
			
		||||
        $data = json_decode($data);
 | 
			
		||||
 | 
			
		||||
        return $data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function saveState($token, $data)
 | 
			
		||||
    {
 | 
			
		||||
        $url = sprintf('%s/botstate/skype/conversations/%s', MSBOT_STATE_URL, '29:1C-OsU7OWBEDOYJhQUsDkYHmycOwOq9QOg5FVTwRX9ts');
 | 
			
		||||
 | 
			
		||||
        $headers = [
 | 
			
		||||
            'Authorization: Bearer ' . $token,
 | 
			
		||||
            'Content-Type: application/json',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        //echo "STATE<pre>" . htmlentities(json_encode($data), JSON_PRETTY_PRINT) . "</pre>";
 | 
			
		||||
 | 
			
		||||
        $data = '{ eTag: "*", data: "' . addslashes(json_encode($data)) . '" }';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        CurlUtils::post($url, $data, $headers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function sendResponse($token, $to, $message)
 | 
			
		||||
    {
 | 
			
		||||
        $url = sprintf('%s/conversations/%s/activities/', SKYPE_API_URL, $to);
 | 
			
		||||
 | 
			
		||||
        $headers = [
 | 
			
		||||
            'Authorization: Bearer ' . $token,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        //echo "<pre>" . htmlentities(json_encode(json_decode($message), JSON_PRETTY_PRINT)) . "</pre>";
 | 
			
		||||
 | 
			
		||||
        $response = CurlUtils::post($url, $message, $headers);
 | 
			
		||||
 | 
			
		||||
        //var_dump($response);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function validateEmail($email, $botUserId)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $email || ! $botUserId) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // delete any expired codes
 | 
			
		||||
        SecurityCode::whereBotUserId($botUserId)
 | 
			
		||||
                    ->where('created_at', '<', DB::raw('now() - INTERVAL 10 MINUTE'))
 | 
			
		||||
                    ->delete();
 | 
			
		||||
 | 
			
		||||
        if (SecurityCode::whereBotUserId($botUserId)->first()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = User::whereEmail($email)
 | 
			
		||||
                    ->whereNull('bot_user_id')
 | 
			
		||||
                    ->first();
 | 
			
		||||
 | 
			
		||||
        if ( ! $user) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $code = new SecurityCode();
 | 
			
		||||
        $code->user_id = $user->id;
 | 
			
		||||
        $code->account_id = $user->account_id;
 | 
			
		||||
        $code->code = mt_rand(100000, 999999);
 | 
			
		||||
        $code->bot_user_id = $botUserId;
 | 
			
		||||
        $code->save();
 | 
			
		||||
 | 
			
		||||
        $this->userMailer->sendSecurityCode($user, $code->code);
 | 
			
		||||
 | 
			
		||||
        return $code->code;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function validateCode($input, $botUserId)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $input || ! $botUserId) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $code = SecurityCode::whereBotUserId($botUserId)
 | 
			
		||||
                    ->where('created_at', '>', DB::raw('now() - INTERVAL 10 MINUTE'))
 | 
			
		||||
                    ->where('attempts', '<', 5)
 | 
			
		||||
                    ->first();
 | 
			
		||||
 | 
			
		||||
        if ( ! $code) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ( ! hash_equals($code->code, $input)) {
 | 
			
		||||
            $code->attempts += 1;
 | 
			
		||||
            $code->save();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $user = User::find($code->user_id);
 | 
			
		||||
        $user->bot_user_id = $code->bot_user_id;
 | 
			
		||||
        $user->save();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function removeBot($botUserId)
 | 
			
		||||
    {
 | 
			
		||||
        $user = User::whereBotUserId($botUserId)->first();
 | 
			
		||||
        $user->bot_user_id = null;
 | 
			
		||||
        $user->save();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function validateToken($token)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $token) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // https://blogs.msdn.microsoft.com/tsmatsuz/2016/07/12/developing-skype-bot/
 | 
			
		||||
        // 0:Invalid, 1:Valid
 | 
			
		||||
        $token_valid = 0;
 | 
			
		||||
 | 
			
		||||
        // 1 separate token by dot (.)
 | 
			
		||||
        $token_arr = explode('.', $token);
 | 
			
		||||
        $headers_enc = $token_arr[0];
 | 
			
		||||
        $claims_enc = $token_arr[1];
 | 
			
		||||
        $sig_enc = $token_arr[2];
 | 
			
		||||
 | 
			
		||||
        // 2 base 64 url decoding
 | 
			
		||||
        $headers_arr = json_decode($this->base64_url_decode($headers_enc), TRUE);
 | 
			
		||||
        $claims_arr = json_decode($this->base64_url_decode($claims_enc), TRUE);
 | 
			
		||||
        $sig = $this->base64_url_decode($sig_enc);
 | 
			
		||||
 | 
			
		||||
        // 3 get key list
 | 
			
		||||
        $keylist = file_get_contents('https://api.aps.skype.com/v1/keys');
 | 
			
		||||
        $keylist_arr = json_decode($keylist, TRUE);
 | 
			
		||||
        foreach($keylist_arr['keys'] as $key => $value) {
 | 
			
		||||
 | 
			
		||||
            // 4 select one key (which matches)
 | 
			
		||||
            if($value['kid'] == $headers_arr['kid']) {
 | 
			
		||||
 | 
			
		||||
                // 5 get public key from key info
 | 
			
		||||
                $cert_txt = '-----BEGIN CERTIFICATE-----' . "\n" . chunk_split($value['x5c'][0], 64) . '-----END CERTIFICATE-----';
 | 
			
		||||
                $cert_obj = openssl_x509_read($cert_txt);
 | 
			
		||||
                $pkey_obj = openssl_pkey_get_public($cert_obj);
 | 
			
		||||
                $pkey_arr = openssl_pkey_get_details($pkey_obj);
 | 
			
		||||
                $pkey_txt = $pkey_arr['key'];
 | 
			
		||||
 | 
			
		||||
                // 6 verify signature
 | 
			
		||||
                $token_valid = openssl_verify($headers_enc . '.' . $claims_enc, $sig, $pkey_txt, OPENSSL_ALGO_SHA256);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // 7 show result
 | 
			
		||||
        return ($token_valid == 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private function base64_url_decode($arg) {
 | 
			
		||||
        $res = $arg;
 | 
			
		||||
        $res = str_replace('-', '+', $res);
 | 
			
		||||
        $res = str_replace('_', '/', $res);
 | 
			
		||||
        switch (strlen($res) % 4) {
 | 
			
		||||
            case 0:
 | 
			
		||||
                break;
 | 
			
		||||
            case 2:
 | 
			
		||||
                $res .= "==";
 | 
			
		||||
                break;
 | 
			
		||||
            case 3:
 | 
			
		||||
                $res .= "=";
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        $res = base64_decode($res);
 | 
			
		||||
        return $res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -62,7 +62,7 @@ class CreditController extends BaseController
 | 
			
		||||
            'method' => 'POST',
 | 
			
		||||
            'url' => 'credits',
 | 
			
		||||
            'title' => trans('texts.new_credit'),
 | 
			
		||||
            'clients' => Client::scope()->with('contacts')->orderBy('name')->get(),
 | 
			
		||||
            'clients' => Client::scope()->with('contacts')->orderBy('name')->get(), 
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return View::make('credits.edit', $data);
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,10 @@ class DocumentAPIController extends BaseAPIController
 | 
			
		||||
    {
 | 
			
		||||
        $document = $request->entity();
 | 
			
		||||
 | 
			
		||||
        return DocumentController::getDownloadResponse($document);
 | 
			
		||||
        if(array_key_exists($document->type, Document::$types))
 | 
			
		||||
            return DocumentController::getDownloadResponse($document);
 | 
			
		||||
        else
 | 
			
		||||
            return $this->errorResponse(['error'=>'Invalid mime type'],400);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -611,4 +611,15 @@ class InvoiceController extends BaseController
 | 
			
		||||
 | 
			
		||||
        return View::make('invoices.history', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function checkInvoiceNumber($invoiceNumber)
 | 
			
		||||
    {
 | 
			
		||||
        $count = Invoice::scope()
 | 
			
		||||
                    ->whereInvoiceNumber($invoiceNumber)
 | 
			
		||||
                    ->withTrashed()
 | 
			
		||||
                    ->count();
 | 
			
		||||
 | 
			
		||||
        return $count ? RESULT_FAILURE : RESULT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -130,8 +130,9 @@ class OnlinePaymentController extends BaseController
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            $paymentDriver->completeOffsitePurchase(Input::all());
 | 
			
		||||
            Session::flash('message', trans('texts.applied_payment'));
 | 
			
		||||
            if ($paymentDriver->completeOffsitePurchase(Input::all())) {
 | 
			
		||||
                Session::flash('message', trans('texts.applied_payment'));
 | 
			
		||||
            }
 | 
			
		||||
            return redirect()->to('view/' . $invitation->invitation_key);
 | 
			
		||||
        } catch (Exception $exception) {
 | 
			
		||||
            return $this->error($paymentDriver, $exception);
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,10 @@ class CreateInvoiceAPIRequest extends InvoiceRequest
 | 
			
		||||
            'invoice_items' => 'valid_invoice_items',
 | 
			
		||||
            'invoice_number' => 'unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
 | 
			
		||||
            'discount' => 'positive',
 | 
			
		||||
            'invoice_date' => 'date',
 | 
			
		||||
            'due_date' => 'date',
 | 
			
		||||
            'start_date' => 'date',
 | 
			
		||||
            'end_date' => 'date',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,10 @@ class CreateInvoiceRequest extends InvoiceRequest
 | 
			
		||||
            'invoice_items' => 'valid_invoice_items',
 | 
			
		||||
            'invoice_number' => 'required|unique:invoices,invoice_number,,id,account_id,' . $this->user()->account_id,
 | 
			
		||||
            'discount' => 'positive',
 | 
			
		||||
            'invoice_date' => 'date',
 | 
			
		||||
            'due_date' => 'date',
 | 
			
		||||
            'start_date' => 'date',
 | 
			
		||||
            'end_date' => 'date',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        /* There's a problem parsing the dates
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,11 @@ class EntityRequest extends Request {
 | 
			
		||||
        return $this->entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setEntity($entity)
 | 
			
		||||
    {
 | 
			
		||||
        $this->entity = $entity;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function authorize()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->entity()) {
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,10 @@ class UpdateInvoiceAPIRequest extends InvoiceRequest
 | 
			
		||||
            'invoice_items' => 'valid_invoice_items',
 | 
			
		||||
            'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
 | 
			
		||||
            'discount' => 'positive',
 | 
			
		||||
            'invoice_date' => 'date',
 | 
			
		||||
            'due_date' => 'date',
 | 
			
		||||
            'start_date' => 'date',
 | 
			
		||||
            'end_date' => 'date',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        return $rules;
 | 
			
		||||
 | 
			
		||||
@ -20,12 +20,16 @@ class UpdateInvoiceRequest extends InvoiceRequest
 | 
			
		||||
    public function rules()
 | 
			
		||||
    {
 | 
			
		||||
        $invoiceId = $this->entity()->id;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        $rules = [
 | 
			
		||||
            'client.contacts' => 'valid_contacts',
 | 
			
		||||
            'invoice_items' => 'valid_invoice_items',
 | 
			
		||||
            'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
 | 
			
		||||
            'discount' => 'positive',
 | 
			
		||||
            'invoice_date' => 'date',
 | 
			
		||||
            'due_date' => 'date',
 | 
			
		||||
            'start_date' => 'date',
 | 
			
		||||
            'end_date' => 'date',
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        /* There's a problem parsing the dates
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								app/Http/ViewComposers/AppLanguageComposer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								app/Http/ViewComposers/AppLanguageComposer.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,37 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
namespace App\Http\ViewComposers;
 | 
			
		||||
 | 
			
		||||
use Illuminate\View\View;
 | 
			
		||||
 | 
			
		||||
class AppLanguageComposer
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Bind data to the view.
 | 
			
		||||
     *
 | 
			
		||||
     * @param  View  $view
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function compose(View $view)
 | 
			
		||||
    {
 | 
			
		||||
        $view->with('appLanguage', $this->getLanguage());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the language from the current locale
 | 
			
		||||
     *
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
    private function getLanguage()
 | 
			
		||||
    {
 | 
			
		||||
        $code = app()->getLocale();
 | 
			
		||||
 | 
			
		||||
        if(preg_match('/_/', $code)) {
 | 
			
		||||
            $codes = explode('_', $code);
 | 
			
		||||
            $code = $codes[0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $code;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -85,6 +85,7 @@ Route::match(['GET', 'POST'], '/buy_now/{gateway_type?}', 'OnlinePaymentControll
 | 
			
		||||
 | 
			
		||||
Route::post('/hook/email_bounced', 'AppController@emailBounced');
 | 
			
		||||
Route::post('/hook/email_opened', 'AppController@emailOpened');
 | 
			
		||||
Route::post('/hook/bot/{platform?}', 'BotController@handleMessage');
 | 
			
		||||
Route::post('/payment_hook/{accountKey}/{gatewayId}', 'OnlinePaymentController@handlePaymentWebhook');
 | 
			
		||||
 | 
			
		||||
// Laravel auth routes
 | 
			
		||||
@ -125,7 +126,8 @@ Route::group(['middleware' => 'auth:user'], function() {
 | 
			
		||||
    Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
 | 
			
		||||
    Route::get('hide_message', 'HomeController@hideMessage');
 | 
			
		||||
    Route::get('force_inline_pdf', 'UserController@forcePDFJS');
 | 
			
		||||
    Route::get('account/getSearchData', ['as' => 'getSearchData', 'uses' => 'AccountController@getSearchData']);
 | 
			
		||||
    Route::get('account/get_search_data', ['as' => 'get_search_data', 'uses' => 'AccountController@getSearchData']);
 | 
			
		||||
    Route::get('check_invoice_number/{invoice_number}', 'InvoiceController@checkInvoiceNumber');
 | 
			
		||||
 | 
			
		||||
    Route::get('settings/user_details', 'AccountController@showUserDetails');
 | 
			
		||||
    Route::post('settings/user_details', 'AccountController@saveUserDetails');
 | 
			
		||||
@ -351,7 +353,7 @@ if (!defined('CONTACT_EMAIL')) {
 | 
			
		||||
    define('ENTITY_CONTACT', 'contact');
 | 
			
		||||
    define('ENTITY_INVOICE', 'invoice');
 | 
			
		||||
    define('ENTITY_DOCUMENT', 'document');
 | 
			
		||||
    define('ENTITY_INVOICE_ITEMS', 'invoice_items');
 | 
			
		||||
    define('ENTITY_INVOICE_ITEM', 'invoice_item');
 | 
			
		||||
    define('ENTITY_INVITATION', 'invitation');
 | 
			
		||||
    define('ENTITY_RECURRING_INVOICE', 'recurring_invoice');
 | 
			
		||||
    define('ENTITY_PAYMENT', 'payment');
 | 
			
		||||
@ -608,7 +610,7 @@ if (!defined('CONTACT_EMAIL')) {
 | 
			
		||||
    define('NINJA_WEB_URL', env('NINJA_WEB_URL', 'https://www.invoiceninja.com'));
 | 
			
		||||
    define('NINJA_APP_URL', env('NINJA_APP_URL', 'https://app.invoiceninja.com'));
 | 
			
		||||
    define('NINJA_DATE', '2000-01-01');
 | 
			
		||||
    define('NINJA_VERSION', '2.6.8' . env('NINJA_VERSION_SUFFIX'));
 | 
			
		||||
    define('NINJA_VERSION', '2.6.9' . 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'));
 | 
			
		||||
@ -626,6 +628,11 @@ if (!defined('CONTACT_EMAIL')) {
 | 
			
		||||
    define('OFX_HOME_URL', env('OFX_HOME_URL', 'http://www.ofxhome.com/index.php/home/directory/all'));
 | 
			
		||||
    define('GOOGLE_ANALYITCS_URL', env('GOOGLE_ANALYITCS_URL', 'https://www.google-analytics.com/collect'));
 | 
			
		||||
 | 
			
		||||
    define('MSBOT_LOGIN_URL', 'https://login.microsoftonline.com/common/oauth2/v2.0/token');
 | 
			
		||||
    define('MSBOT_LUIS_URL', 'https://api.projectoxford.ai/luis/v1/application');
 | 
			
		||||
    define('SKYPE_API_URL', 'https://apis.skype.com/v3');
 | 
			
		||||
    define('MSBOT_STATE_URL', 'https://state.botframework.com/v3');
 | 
			
		||||
 | 
			
		||||
    define('BLANK_IMAGE', 'data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=');
 | 
			
		||||
 | 
			
		||||
    define('COUNT_FREE_DESIGNS', 4);
 | 
			
		||||
@ -790,6 +797,25 @@ if (!defined('CONTACT_EMAIL')) {
 | 
			
		||||
    define('WEPAY_APP_FEE_MULTIPLIER', env('WEPAY_APP_FEE_MULTIPLIER', 0.002));
 | 
			
		||||
    define('WEPAY_APP_FEE_FIXED', env('WEPAY_APP_FEE_MULTIPLIER', 0.00));
 | 
			
		||||
 | 
			
		||||
    define('SKYPE_CARD_RECEIPT', 'message/card.receipt');
 | 
			
		||||
    define('SKYPE_CARD_CAROUSEL', 'message/card.carousel');
 | 
			
		||||
    define('SKYPE_CARD_HERO', '');
 | 
			
		||||
 | 
			
		||||
    define('BOT_STATE_GET_EMAIL', 'get_email');
 | 
			
		||||
    define('BOT_STATE_GET_CODE', 'get_code');
 | 
			
		||||
    define('BOT_STATE_READY', 'ready');
 | 
			
		||||
    define('SIMILAR_MIN_THRESHOLD', 50);
 | 
			
		||||
 | 
			
		||||
    // https://docs.botframework.com/en-us/csharp/builder/sdkreference/attachments.html
 | 
			
		||||
    define('SKYPE_BUTTON_OPEN_URL', 'openUrl');
 | 
			
		||||
    define('SKYPE_BUTTON_IM_BACK', 'imBack');
 | 
			
		||||
    define('SKYPE_BUTTON_POST_BACK', 'postBack');
 | 
			
		||||
    define('SKYPE_BUTTON_CALL', 'call'); // "tel:123123123123"
 | 
			
		||||
    define('SKYPE_BUTTON_PLAY_AUDIO', 'playAudio');
 | 
			
		||||
    define('SKYPE_BUTTON_PLAY_VIDEO', 'playVideo');
 | 
			
		||||
    define('SKYPE_BUTTON_SHOW_IMAGE', 'showImage');
 | 
			
		||||
    define('SKYPE_BUTTON_DOWNLOAD_FILE', 'downloadFile');
 | 
			
		||||
 | 
			
		||||
    $creditCards = [
 | 
			
		||||
                1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
 | 
			
		||||
                2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										36
									
								
								app/Libraries/CurlUtils.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/Libraries/CurlUtils.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
<?php namespace App\Libraries;
 | 
			
		||||
 | 
			
		||||
class CurlUtils
 | 
			
		||||
{
 | 
			
		||||
    public static function post($url, $data, $headers = false)
 | 
			
		||||
    {
 | 
			
		||||
        return self::exec('POST', $url, $data, $headers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function get($url, $headers = false)
 | 
			
		||||
    {
 | 
			
		||||
        return self::exec('GET', $url, null, $headers);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function exec($method, $url, $data, $headers = false)
 | 
			
		||||
    {
 | 
			
		||||
        $curl = curl_init();
 | 
			
		||||
 | 
			
		||||
        $opts = [
 | 
			
		||||
            CURLOPT_URL => $url,
 | 
			
		||||
            CURLOPT_RETURNTRANSFER => true,
 | 
			
		||||
            CURLOPT_POST => $method,
 | 
			
		||||
            CURLOPT_HTTPHEADER => $headers ?: [],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($data) {
 | 
			
		||||
            $opts[CURLOPT_POSTFIELDS] = $data;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        curl_setopt_array($curl, $opts);
 | 
			
		||||
        $response = curl_exec($curl);
 | 
			
		||||
        curl_close($curl);
 | 
			
		||||
 | 
			
		||||
        return $response;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								app/Libraries/Skype/ButtonCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/Libraries/Skype/ButtonCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
class ButtonCard
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($type, $title, $value, $url = false)
 | 
			
		||||
    {
 | 
			
		||||
        $this->type = $type;
 | 
			
		||||
        $this->title = $title;
 | 
			
		||||
        $this->value = $value;
 | 
			
		||||
        $this->image = $url;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								app/Libraries/Skype/CarouselCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/Libraries/Skype/CarouselCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
class CarouselCard
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->contentType = 'application/vnd.microsoft.card.carousel';
 | 
			
		||||
        $this->attachments = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addAttachment($attachment)
 | 
			
		||||
    {
 | 
			
		||||
        $this->attachments[] = $attachment;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								app/Libraries/Skype/HeroCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/Libraries/Skype/HeroCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class HeroCard
 | 
			
		||||
{
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        $this->contentType = 'application/vnd.microsoft.card.hero';
 | 
			
		||||
        $this->content = new stdClass;
 | 
			
		||||
        $this->content->buttons = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setTitle($title)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->title = $title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setSubitle($subtitle)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->subtitle = $subtitle;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setText($text)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->text = $text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addButton($type, $title, $value, $url = false)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->buttons[] = new ButtonCard($type, $title, $value, $url);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								app/Libraries/Skype/InvoiceCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								app/Libraries/Skype/InvoiceCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
use HTML;
 | 
			
		||||
use stdClass;
 | 
			
		||||
 | 
			
		||||
class InvoiceCard
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($invoice)
 | 
			
		||||
    {
 | 
			
		||||
        $this->contentType = 'application/vnd.microsoft.card.receipt';
 | 
			
		||||
        $this->content = new stdClass;
 | 
			
		||||
        $this->content->facts = [];
 | 
			
		||||
        $this->content->items = [];
 | 
			
		||||
        $this->content->buttons = [];
 | 
			
		||||
 | 
			
		||||
        $this->setTitle('test');
 | 
			
		||||
 | 
			
		||||
        $this->setTitle(trans('texts.invoice_for_client', [
 | 
			
		||||
            'invoice' => link_to($invoice->getRoute(), $invoice->invoice_number),
 | 
			
		||||
            'client' => link_to($invoice->client->getRoute(), $invoice->client->getDisplayName())
 | 
			
		||||
        ]));
 | 
			
		||||
 | 
			
		||||
        $this->addFact(trans('texts.email'), HTML::mailto($invoice->client->contacts[0]->email)->toHtml());
 | 
			
		||||
 | 
			
		||||
        if ($invoice->due_date) {
 | 
			
		||||
            $this->addFact($invoice->present()->dueDateLabel, $invoice->present()->due_date);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($invoice->po_number) {
 | 
			
		||||
            $this->addFact(trans('texts.po_number'), $invoice->po_number);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($invoice->discount) {
 | 
			
		||||
            $this->addFact(trans('texts.discount'), $invoice->present()->discount);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($invoice->invoice_items as $item) {
 | 
			
		||||
            $this->addItem($item, $invoice->account);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->setTotal($invoice->present()->requestedAmount);
 | 
			
		||||
 | 
			
		||||
        if (floatval($invoice->amount)) {
 | 
			
		||||
            $this->addButton(SKYPE_BUTTON_OPEN_URL, trans('texts.download_pdf'), $invoice->getInvitationLink('view', true));
 | 
			
		||||
            $this->addButton(SKYPE_BUTTON_IM_BACK, trans('texts.email_invoice'), trans('texts.email_invoice'));
 | 
			
		||||
        } else {
 | 
			
		||||
            $this->addButton(SKYPE_BUTTON_IM_BACK, trans('texts.list_products'), trans('texts.list_products'));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setTitle($title)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->title = $title;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setTotal($value)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->total = $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addFact($key, $value)
 | 
			
		||||
    {
 | 
			
		||||
        $fact = new stdClass;
 | 
			
		||||
        $fact->key = $key;
 | 
			
		||||
        $fact->value = $value;
 | 
			
		||||
 | 
			
		||||
        $this->content->facts[] = $fact;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addItem($item, $account)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->items[] = new InvoiceItemCard($item, $account);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addButton($type, $title, $value, $url = false)
 | 
			
		||||
    {
 | 
			
		||||
        $this->content->buttons[] = new ButtonCard($type, $title, $value, $url);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								app/Libraries/Skype/InvoiceItemCard.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								app/Libraries/Skype/InvoiceItemCard.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
class InvoiceItemCard
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($invoiceItem, $account)
 | 
			
		||||
    {
 | 
			
		||||
        $this->title = intval($invoiceItem->qty) . ' ' . $invoiceItem->product_key;
 | 
			
		||||
        $this->subtitle = $invoiceItem->notes;
 | 
			
		||||
        $this->quantity = $invoiceItem->qty;
 | 
			
		||||
        $this->price = $account->formatMoney($invoiceItem->cost);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								app/Libraries/Skype/SkypeResponse.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								app/Libraries/Skype/SkypeResponse.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
<?php namespace App\Libraries\Skype;
 | 
			
		||||
 | 
			
		||||
class SkypeResponse
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($type)
 | 
			
		||||
    {
 | 
			
		||||
        $this->type = $type;
 | 
			
		||||
        $this->attachments = [];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function message($message)
 | 
			
		||||
    {
 | 
			
		||||
        $instance = new self('message/text');
 | 
			
		||||
        $instance->setText($message);
 | 
			
		||||
 | 
			
		||||
        return json_encode($instance);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setText($text)
 | 
			
		||||
    {
 | 
			
		||||
        $this->text = $text;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function addAttachment($attachment)
 | 
			
		||||
    {
 | 
			
		||||
        $this->attachments[] = $attachment;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
use Auth;
 | 
			
		||||
use Eloquent;
 | 
			
		||||
use Utils;
 | 
			
		||||
use Validator;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class EntityModel
 | 
			
		||||
@ -86,6 +87,11 @@ class EntityModel extends Eloquent
 | 
			
		||||
        return '[' . $this->getEntityType().':'.$this->public_id.':'.$this->getDisplayName() . ']';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function entityKey()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->public_id . ':' . $this->getEntityType();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
    public function getEntityType()
 | 
			
		||||
    {
 | 
			
		||||
@ -190,4 +196,37 @@ class EntityModel extends Eloquent
 | 
			
		||||
        $name = $parts[count($parts)-1];
 | 
			
		||||
        return strtolower($name) . '_id';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param $data
 | 
			
		||||
     * @param $entityType
 | 
			
		||||
     * @return bool|string
 | 
			
		||||
     */
 | 
			
		||||
    public static function validate($data, $entityType, $entity = false)
 | 
			
		||||
    {
 | 
			
		||||
        // Use the API request if it exists
 | 
			
		||||
        $action = $entity ? 'update' : 'create';
 | 
			
		||||
        $requestClass = sprintf('App\\Http\\Requests\\%s%sAPIRequest', ucwords($action), ucwords($entityType));
 | 
			
		||||
        if ( ! class_exists($requestClass)) {
 | 
			
		||||
            $requestClass = sprintf('App\\Http\\Requests\\%s%sRequest', ucwords($action), ucwords($entityType));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $request = new $requestClass();
 | 
			
		||||
        $request->setUserResolver(function() { return Auth::user(); });
 | 
			
		||||
        $request->setEntity($entity);
 | 
			
		||||
        $request->replace($data);
 | 
			
		||||
 | 
			
		||||
        if ( ! $request->authorize()) {
 | 
			
		||||
            return trans('texts.not_allowed');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $request->rules());
 | 
			
		||||
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
            return $validator->messages()->first();
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -516,6 +516,15 @@ class Invoice extends EntityModel implements BalanceAffecting
 | 
			
		||||
        return self::calcLink($this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getInvitationLink($type = 'view', $forceOnsite = false)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! $this->relationLoaded('invitations')) {
 | 
			
		||||
            $this->load('invitations');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->invitations[0]->getLink($type, $forceOnsite);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,14 @@ use Illuminate\Database\Eloquent\SoftDeletes;
 | 
			
		||||
 */
 | 
			
		||||
class InvoiceItem extends EntityModel
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @return mixed
 | 
			
		||||
     */
 | 
			
		||||
    public function getEntityType()
 | 
			
		||||
    {
 | 
			
		||||
        return ENTITY_INVOICE_ITEM;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    use SoftDeletes;
 | 
			
		||||
    /**
 | 
			
		||||
     * @var array
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
<?php namespace App\Models;
 | 
			
		||||
 | 
			
		||||
use Laracasts\Presenter\PresentableTrait;
 | 
			
		||||
use Illuminate\Database\Eloquent\SoftDeletes;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -7,12 +8,18 @@ use Illuminate\Database\Eloquent\SoftDeletes;
 | 
			
		||||
 */
 | 
			
		||||
class Product extends EntityModel
 | 
			
		||||
{
 | 
			
		||||
    use PresentableTrait;
 | 
			
		||||
    use SoftDeletes;
 | 
			
		||||
    /**
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
    protected $dates = ['deleted_at'];
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var string
 | 
			
		||||
     */
 | 
			
		||||
    protected $presenter = 'App\Ninja\Presenters\ProductPresenter';
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var array
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								app/Models/SecurityCode.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/Models/SecurityCode.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php namespace App\Models;
 | 
			
		||||
 | 
			
		||||
use Eloquent;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class DatetimeFormat
 | 
			
		||||
 */
 | 
			
		||||
class SecurityCode extends Eloquent
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @var bool
 | 
			
		||||
     */
 | 
			
		||||
    public $timestamps = false;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										227
									
								
								app/Ninja/Intents/BaseIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								app/Ninja/Intents/BaseIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,227 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use stdClass;
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Libraries\CurlUtils;
 | 
			
		||||
use App\Libraries\Skype\SkypeResponse;
 | 
			
		||||
 | 
			
		||||
class BaseIntent
 | 
			
		||||
{
 | 
			
		||||
    protected $state;
 | 
			
		||||
    protected $parameters;
 | 
			
		||||
    protected $fieldMap = [];
 | 
			
		||||
 | 
			
		||||
    public function __construct($state, $data)
 | 
			
		||||
    {
 | 
			
		||||
        //if (true) {
 | 
			
		||||
        if ( ! $state || is_string($state)) {
 | 
			
		||||
            $state = new stdClass;
 | 
			
		||||
            foreach (['current', 'previous'] as $reference) {
 | 
			
		||||
                $state->$reference = new stdClass;
 | 
			
		||||
                $state->$reference->entityType = false;
 | 
			
		||||
                foreach ([ENTITY_INVOICE, ENTITY_CLIENT, ENTITY_INVOICE_ITEM] as $entityType) {
 | 
			
		||||
                    $state->$reference->$entityType = [];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $this->state = $state;
 | 
			
		||||
        $this->data = $data;
 | 
			
		||||
 | 
			
		||||
        //var_dump($state);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function createIntent($state, $data)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! count($data->intents)) {
 | 
			
		||||
            throw new Exception(trans('texts.intent_not_found'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $intent = $data->intents[0]->intent;
 | 
			
		||||
        $entityType = false;
 | 
			
		||||
 | 
			
		||||
        foreach ($data->entities as $entity) {
 | 
			
		||||
            if ($entity->type === 'EntityType') {
 | 
			
		||||
                $entityType = $entity->entity;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ( ! $entityType) {
 | 
			
		||||
            $entityType = $state->current->entityType;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $entityType = ucwords(strtolower($entityType));
 | 
			
		||||
        $intent = str_replace('Entity', $entityType, $intent);
 | 
			
		||||
        $className = "App\\Ninja\\Intents\\{$intent}Intent";
 | 
			
		||||
 | 
			
		||||
        //echo "Intent: $intent<p>";
 | 
			
		||||
 | 
			
		||||
        if ( ! class_exists($className)) {
 | 
			
		||||
            throw new Exception(trans('texts.intent_not_supported'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (new $className($state, $data));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        // do nothing by default
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStateEntities($entityType, $entities)
 | 
			
		||||
    {
 | 
			
		||||
        if ( ! is_array($entities)) {
 | 
			
		||||
            $entities = [$entities];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $state = $this->state;
 | 
			
		||||
 | 
			
		||||
        $state->previous->$entityType = $state->current->$entityType;
 | 
			
		||||
        $state->current->$entityType = $entities;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function setStateEntityType($entityType)
 | 
			
		||||
    {
 | 
			
		||||
        $state = $this->state;
 | 
			
		||||
 | 
			
		||||
        if ($state->current->entityType == $entityType) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $state->previous->entityType = $state->current->entityType;
 | 
			
		||||
        $state->current->entityType = $entityType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function stateEntities($entityType)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->state->current->$entityType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function stateEntity($entityType)
 | 
			
		||||
    {
 | 
			
		||||
        $entities = $this->state->current->$entityType;
 | 
			
		||||
 | 
			
		||||
        return count($entities) ? $entities[0] : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function previousStateEntities($entityType)
 | 
			
		||||
    {
 | 
			
		||||
        return $this->state->previous->$entityType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function stateEntityType()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->state->current->entityType;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public function getState()
 | 
			
		||||
    {
 | 
			
		||||
        return $this->state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function requestClient()
 | 
			
		||||
    {
 | 
			
		||||
        $clientRepo = app('App\Ninja\Repositories\ClientRepository');
 | 
			
		||||
        $client = false;
 | 
			
		||||
 | 
			
		||||
        foreach ($this->data->entities as $param) {
 | 
			
		||||
            if ($param->type == 'Name') {
 | 
			
		||||
                $client = $clientRepo->findPhonetically($param->entity);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function requestFields()
 | 
			
		||||
    {
 | 
			
		||||
        $data = [];
 | 
			
		||||
 | 
			
		||||
        if ( ! isset($this->data->compositeEntities)) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($this->data->compositeEntities as $compositeEntity) {
 | 
			
		||||
            if ($compositeEntity->parentType != 'FieldValuePair') {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $field = false;
 | 
			
		||||
            $value = false;
 | 
			
		||||
 | 
			
		||||
            foreach ($compositeEntity->children as $child) {
 | 
			
		||||
                if ($child->type == 'Field') {
 | 
			
		||||
                    $field = $child->value;;
 | 
			
		||||
                } elseif ($child->type == 'Value') {
 | 
			
		||||
                    $value = $child->value;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($field && $value) {
 | 
			
		||||
                $field = $this->processField($field);
 | 
			
		||||
                $value = $this->processValue($value);
 | 
			
		||||
 | 
			
		||||
                $data[$field] = $value;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($this->fieldMap as $key => $value) {
 | 
			
		||||
            if (isset($data[$key])) {
 | 
			
		||||
                $data[$value] = $data[$key];
 | 
			
		||||
                unset($data[$key]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function processField($field)
 | 
			
		||||
    {
 | 
			
		||||
        $field = str_replace(' ', '_', $field);
 | 
			
		||||
 | 
			
		||||
        if (strpos($field, 'date') !== false) {
 | 
			
		||||
            $field .= '_sql';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $field;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function processValue($value)
 | 
			
		||||
    {
 | 
			
		||||
        // look for LUIS pre-built entity matches
 | 
			
		||||
        foreach ($this->data->entities as $entity) {
 | 
			
		||||
            if ($entity->entity === $value) {
 | 
			
		||||
                if ($entity->type == 'builtin.datetime.date') {
 | 
			
		||||
                    $value = $entity->resolution->date;
 | 
			
		||||
                    $value = str_replace('XXXX', date('Y'), $value);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function createResponse($type, $content)
 | 
			
		||||
    {
 | 
			
		||||
        $response = new SkypeResponse($type);
 | 
			
		||||
 | 
			
		||||
        if (is_string($content)) {
 | 
			
		||||
            $response->setText($content);
 | 
			
		||||
        } else {
 | 
			
		||||
            if ($content instanceof \Illuminate\Database\Eloquent\Collection) {
 | 
			
		||||
                // do nothing
 | 
			
		||||
            } elseif ( ! is_array($content)) {
 | 
			
		||||
                $content = [$content];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            foreach ($content as $item) {
 | 
			
		||||
                $response->addAttachment($item);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return json_encode($response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										44
									
								
								app/Ninja/Intents/CreateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								app/Ninja/Intents/CreateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Models\EntityModel;
 | 
			
		||||
 | 
			
		||||
class CreateInvoiceIntent extends InvoiceIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $client = $this->requestClient();
 | 
			
		||||
        $invoiceItems = $this->requestInvoiceItems();
 | 
			
		||||
 | 
			
		||||
        if ( ! $client) {
 | 
			
		||||
            throw new Exception(trans('texts.client_not_found'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $data = array_merge($this->requestFields(), [
 | 
			
		||||
            'client_id' => $client->id,
 | 
			
		||||
            'invoice_items' => $invoiceItems,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        //var_dump($data);
 | 
			
		||||
 | 
			
		||||
        $valid = EntityModel::validate($data, ENTITY_INVOICE);
 | 
			
		||||
 | 
			
		||||
        if ($valid !== true) {
 | 
			
		||||
            throw new Exception($valid);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoiceService = app('App\Services\InvoiceService');
 | 
			
		||||
        $invoice = $invoiceService->save($data);
 | 
			
		||||
 | 
			
		||||
        $invoiceItemIds = array_map(function($item) {
 | 
			
		||||
            return $item['public_id'];
 | 
			
		||||
        }, $invoice->invoice_items->toArray());
 | 
			
		||||
 | 
			
		||||
        $this->setStateEntityType(ENTITY_INVOICE);
 | 
			
		||||
        $this->setStateEntities(ENTITY_CLIENT, $client->public_id);
 | 
			
		||||
        $this->setStateEntities(ENTITY_INVOICE, $invoice->public_id);
 | 
			
		||||
        $this->setStateEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
 | 
			
		||||
 | 
			
		||||
        return $this->createResponse(SKYPE_CARD_RECEIPT, $invoice->present()->skypeBot);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								app/Ninja/Intents/DownloadInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/Ninja/Intents/DownloadInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use App\Models\EntityModel;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Libraries\Skype\SkypeResponse;
 | 
			
		||||
 | 
			
		||||
class DownloadInvoiceIntent extends InvoiceIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->invoice();
 | 
			
		||||
 | 
			
		||||
        $message = trans('texts.' . $invoice->getEntityType()) . ' ' . $invoice->invoice_number;
 | 
			
		||||
        $message = link_to('/download/' . $invoice->invitations[0]->invitation_key, $message);
 | 
			
		||||
 | 
			
		||||
        return SkypeResponse::message($message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								app/Ninja/Intents/EmailInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/Ninja/Intents/EmailInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Models\EntityModel;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
use App\Libraries\Skype\SkypeResponse;
 | 
			
		||||
 | 
			
		||||
class EmailInvoiceIntent extends InvoiceIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->stateInvoice();
 | 
			
		||||
 | 
			
		||||
        if ( ! Auth::user()->can('edit', $invoice)) {
 | 
			
		||||
            throw new Exception(trans('texts.not_allowed'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $contactMailer = app('App\Ninja\Mailers\ContactMailer');
 | 
			
		||||
        $contactMailer->sendInvoice($invoice);
 | 
			
		||||
 | 
			
		||||
        $message = trans('texts.bot_emailed_' . $invoice->getEntityType());
 | 
			
		||||
 | 
			
		||||
        if (Auth::user()->notify_viewed) {
 | 
			
		||||
            $message .= '<br/>' . trans('texts.bot_emailed_notify_viewed');
 | 
			
		||||
        } elseif (Auth::user()->notify_paid) {
 | 
			
		||||
            $message .= '<br/>' . trans('texts.bot_emailed_notify_paid');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return SkypeResponse::message($message);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								app/Ninja/Intents/InvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								app/Ninja/Intents/InvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
 | 
			
		||||
class InvoiceIntent extends BaseIntent
 | 
			
		||||
{
 | 
			
		||||
    protected $fieldMap = [
 | 
			
		||||
        'deposit' => 'partial',
 | 
			
		||||
        'due' => 'due_date',
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    public function __construct($state, $data)
 | 
			
		||||
    {
 | 
			
		||||
        $this->invoiceRepo = app('App\Ninja\Repositories\InvoiceRepository');
 | 
			
		||||
 | 
			
		||||
        parent::__construct($state, $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function stateInvoice()
 | 
			
		||||
    {
 | 
			
		||||
        $invoiceId = $this->stateEntity(ENTITY_INVOICE);
 | 
			
		||||
 | 
			
		||||
        if ( ! $invoiceId) {
 | 
			
		||||
            throw new Exception(trans('texts.intent_not_supported'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoice = Invoice::scope($invoiceId)->first();
 | 
			
		||||
 | 
			
		||||
        if ( ! $invoice) {
 | 
			
		||||
            throw new Exception(trans('texts.intent_not_supported'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ( ! Auth::user()->can('view', $invoice)) {
 | 
			
		||||
            throw new Exception(trans('texts.not_allowed'));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $invoice;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function requestInvoiceItems()
 | 
			
		||||
    {
 | 
			
		||||
        $productRepo = app('App\Ninja\Repositories\ProductRepository');
 | 
			
		||||
 | 
			
		||||
        $invoiceItems = [];
 | 
			
		||||
 | 
			
		||||
        if ( ! isset($this->data->compositeEntities) || ! count($this->data->compositeEntities)) {
 | 
			
		||||
            return [];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach ($this->data->compositeEntities as $entity) {
 | 
			
		||||
            if ($entity->parentType == 'InvoiceItem') {
 | 
			
		||||
                $product = false;
 | 
			
		||||
                $qty = 1;
 | 
			
		||||
                foreach ($entity->children as $child) {
 | 
			
		||||
                    if ($child->type == 'Product') {
 | 
			
		||||
                        $product = $productRepo->findPhonetically($child->value);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        $qty = $child->value;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if ($product) {
 | 
			
		||||
                    $item['qty'] = $qty;
 | 
			
		||||
                    $item['product_key'] = $product->product_key;
 | 
			
		||||
                    $item['cost'] = $product->cost;
 | 
			
		||||
                    $item['notes'] = $product->notes;
 | 
			
		||||
 | 
			
		||||
                    if ($taxRate = $product->default_tax_rate) {
 | 
			
		||||
                        $item['tax_name1'] = $taxRate->name;
 | 
			
		||||
                        $item['tax_rate1'] = $taxRate->rate;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    $invoiceItems[] = $item;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
        if ( ! count($invoiceItems)) {
 | 
			
		||||
            foreach ($this->data->entities as $param) {
 | 
			
		||||
                if ($param->type == 'Product') {
 | 
			
		||||
                    $product = $productRepo->findPhonetically($param->entity);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        return $invoiceItems;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								app/Ninja/Intents/ListProductsIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								app/Ninja/Intents/ListProductsIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Models\Product;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ListProductsIntent extends ProductIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $account = Auth::user()->account;
 | 
			
		||||
        $products = Product::scope()
 | 
			
		||||
            ->orderBy('product_key')
 | 
			
		||||
            ->limit(10)
 | 
			
		||||
            ->get()
 | 
			
		||||
            ->transform(function($item, $key) use ($account) {
 | 
			
		||||
                $card = $item->present()->skypeBot($account);
 | 
			
		||||
                if ($this->stateEntity(ENTITY_INVOICE)) {
 | 
			
		||||
                    $card->addButton('imBack', trans('texts.add_to_invoice'), trans('texts.add_product_to_invoice', ['product' => $item->product_key]));
 | 
			
		||||
                }
 | 
			
		||||
                return $card;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return $this->createResponse(SKYPE_CARD_CAROUSEL, $products);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								app/Ninja/Intents/ProductIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/Ninja/Intents/ProductIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Auth;
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProductIntent extends BaseIntent
 | 
			
		||||
{
 | 
			
		||||
    public function __construct($state, $data)
 | 
			
		||||
    {
 | 
			
		||||
        $this->productRepo = app('App\Ninja\Repositories\ProductRepository');
 | 
			
		||||
 | 
			
		||||
        parent::__construct($state, $data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								app/Ninja/Intents/UpdateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								app/Ninja/Intents/UpdateInvoiceIntent.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,54 @@
 | 
			
		||||
<?php namespace App\Ninja\Intents;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use App\Models\EntityModel;
 | 
			
		||||
use App\Models\Invoice;
 | 
			
		||||
 | 
			
		||||
class UpdateInvoiceIntent extends InvoiceIntent
 | 
			
		||||
{
 | 
			
		||||
    public function process()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->stateInvoice();
 | 
			
		||||
        $invoiceItems = $this->requestInvoiceItems();
 | 
			
		||||
 | 
			
		||||
        $data = array_merge($this->requestFields(), [
 | 
			
		||||
            'public_id' => $invoice->public_id,
 | 
			
		||||
            'invoice_items' => array_merge($invoice->invoice_items->toArray(), $invoiceItems),
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        // map the cost and qty fields to the invoice items
 | 
			
		||||
        if (isset($data['cost']) || isset($data['quantity'])) {
 | 
			
		||||
            foreach ($data['invoice_items'] as $key => $item) {
 | 
			
		||||
                // if it's new or we recently created it
 | 
			
		||||
                if (empty($item['public_id']) || in_array($item['public_id'], $this->entities(ENTITY_INVOICE_ITEM))) {
 | 
			
		||||
                    $data['invoice_items'][$key]['cost'] = isset($data['cost']) ? $data['cost'] : $item['cost'];
 | 
			
		||||
                    $data['invoice_items'][$key]['qty'] = isset($data['quantity']) ? $data['quantity'] : $item['qty'];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //var_dump($data);
 | 
			
		||||
 | 
			
		||||
        $valid = EntityModel::validate($data, ENTITY_INVOICE, $invoice);
 | 
			
		||||
 | 
			
		||||
        if ($valid !== true) {
 | 
			
		||||
            throw new Exception($valid);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $invoice = $this->invoiceRepo->save($data, $invoice);
 | 
			
		||||
 | 
			
		||||
        $invoiceItems = array_slice($invoice->invoice_items->toArray(), count($invoiceItems) * -1);
 | 
			
		||||
        $invoiceItemIds = array_map(function($item) {
 | 
			
		||||
            return $item['public_id'];
 | 
			
		||||
        }, $invoiceItems);
 | 
			
		||||
 | 
			
		||||
        $this->setStateEntities(ENTITY_INVOICE_ITEM, $invoiceItemIds);
 | 
			
		||||
 | 
			
		||||
        $response = $invoice
 | 
			
		||||
            ->load('invoice_items')
 | 
			
		||||
            ->present()
 | 
			
		||||
            ->skypeBot;
 | 
			
		||||
 | 
			
		||||
        return $this->createResponse(SKYPE_CARD_RECEIPT, $response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -109,4 +109,20 @@ class UserMailer extends Mailer
 | 
			
		||||
 | 
			
		||||
        $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function sendSecurityCode($user, $code)
 | 
			
		||||
    {
 | 
			
		||||
        if (!$user->email) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $subject = trans('texts.security_code_email_subject');
 | 
			
		||||
        $view = 'security_code';
 | 
			
		||||
        $data = [
 | 
			
		||||
            'userName' => $user->getDisplayName(),
 | 
			
		||||
            'code' => $code,
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        $this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,11 @@ class BasePaymentDriver
 | 
			
		||||
        return $this->accountGateway->gateway_id == $gatewayId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isValid()
 | 
			
		||||
    {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // optionally pass a paymentMethod to determine the type from the token
 | 
			
		||||
    protected function isGatewayType($gatewayType, $paymentMethod = false)
 | 
			
		||||
    {
 | 
			
		||||
@ -535,6 +540,15 @@ class BasePaymentDriver
 | 
			
		||||
        $paymentMethod->setRelation('account_gateway_token', $customer);
 | 
			
		||||
        $paymentMethod = $this->creatingPaymentMethod($paymentMethod);
 | 
			
		||||
 | 
			
		||||
        // archive the old payment method
 | 
			
		||||
        $oldPaymentMethod = PaymentMethod::clientId($this->client()->id)
 | 
			
		||||
            ->wherePaymentTypeId($paymentMethod->payment_type_id)
 | 
			
		||||
            ->first();
 | 
			
		||||
 | 
			
		||||
        if ($oldPaymentMethod) {
 | 
			
		||||
            $oldPaymentMethod->delete();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($paymentMethod) {
 | 
			
		||||
            $paymentMethod->save();
 | 
			
		||||
        }
 | 
			
		||||
@ -753,7 +767,7 @@ class BasePaymentDriver
 | 
			
		||||
            } elseif ($paymentMethod->payment_type_id == PAYMENT_TYPE_PAYPAL) {
 | 
			
		||||
                $label = 'PayPal: ' . $paymentMethod->email;
 | 
			
		||||
            } else {
 | 
			
		||||
                $label = trans('texts.use_card_on_file');
 | 
			
		||||
                $label = trans('texts.payment_type_on_file', ['type' => $paymentMethod->payment_type->name]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $links[] = [
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
<?php namespace App\Ninja\PaymentDrivers;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
 | 
			
		||||
class MolliePaymentDriver extends BasePaymentDriver
 | 
			
		||||
{
 | 
			
		||||
    public function completeOffsitePurchase($input)
 | 
			
		||||
@ -10,6 +12,12 @@ class MolliePaymentDriver extends BasePaymentDriver
 | 
			
		||||
 | 
			
		||||
        $response = $this->gateway()->fetchTransaction($details)->send();
 | 
			
		||||
 | 
			
		||||
        if ($response->isCancelled()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } elseif ( ! $response->isSuccessful()) {
 | 
			
		||||
            throw new Exception($response->getMessage());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $this->createPayment($response->getTransactionReference());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,21 @@ class StripePaymentDriver extends BasePaymentDriver
 | 
			
		||||
        return $rules;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function isValid()
 | 
			
		||||
    {
 | 
			
		||||
        $result = $this->makeStripeCall(
 | 
			
		||||
            'GET',
 | 
			
		||||
            'charges',
 | 
			
		||||
            'limit=1'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (array_get($result, 'object') == 'list') {
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            return $result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function checkCustomerExists($customer)
 | 
			
		||||
    {
 | 
			
		||||
        $response = $this->gateway()
 | 
			
		||||
@ -347,15 +362,15 @@ class StripePaymentDriver extends BasePaymentDriver
 | 
			
		||||
        $eventDetails = $this->makeStripeCall('GET', 'events/'.$eventId);
 | 
			
		||||
 | 
			
		||||
        if (is_string($eventDetails) || !$eventDetails) {
 | 
			
		||||
            throw new Exception('Could not get event details');
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($eventType != $eventDetails['type']) {
 | 
			
		||||
            throw new Exception('Event type mismatch');
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!$eventDetails['pending_webhooks']) {
 | 
			
		||||
            throw new Exception('This is not a pending event');
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($eventType == 'charge.failed' || $eventType == 'charge.succeeded' || $eventType == 'charge.refunded') {
 | 
			
		||||
@ -365,7 +380,7 @@ class StripePaymentDriver extends BasePaymentDriver
 | 
			
		||||
            $payment = Payment::scope(false, $accountId)->where('transaction_reference', '=', $transactionRef)->first();
 | 
			
		||||
 | 
			
		||||
            if (!$payment) {
 | 
			
		||||
                throw new Exception('Unknown payment');
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if ($eventType == 'charge.failed') {
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,22 @@ class ClientPresenter extends EntityPresenter {
 | 
			
		||||
        return $this->entity->country ? $this->entity->country->name : '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function balance()
 | 
			
		||||
    {
 | 
			
		||||
        $client = $this->entity;
 | 
			
		||||
        $account = $client->account;
 | 
			
		||||
 | 
			
		||||
        return $account->formatMoney($client->balance, $client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function paid_to_date()
 | 
			
		||||
    {
 | 
			
		||||
        $client = $this->entity;
 | 
			
		||||
        $account = $client->account;
 | 
			
		||||
 | 
			
		||||
        return $account->formatMoney($client->paid_to_date, $client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function status()
 | 
			
		||||
    {
 | 
			
		||||
        $class = $text = '';
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,6 @@ use Laracasts\Presenter\Presenter;
 | 
			
		||||
 | 
			
		||||
class EntityPresenter extends Presenter
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return string
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
<?php namespace App\Ninja\Presenters;
 | 
			
		||||
 | 
			
		||||
use Utils;
 | 
			
		||||
use App\Libraries\Skype\InvoiceCard;
 | 
			
		||||
 | 
			
		||||
class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
 | 
			
		||||
@ -14,6 +15,22 @@ class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
        return $this->entity->user->getDisplayName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function amount()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->entity;
 | 
			
		||||
        $account = $invoice->account;
 | 
			
		||||
 | 
			
		||||
        return $account->formatMoney($invoice->amount, $invoice->client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function requestedAmount()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->entity;
 | 
			
		||||
        $account = $invoice->account;
 | 
			
		||||
 | 
			
		||||
        return $account->formatMoney($invoice->getRequestedAmount(), $invoice->client);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function balanceDueLabel()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->entity->partial > 0) {
 | 
			
		||||
@ -25,6 +42,26 @@ class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function dueDateLabel()
 | 
			
		||||
    {
 | 
			
		||||
        if ($this->entity->isType(INVOICE_TYPE_STANDARD)) {
 | 
			
		||||
            return trans('texts.due_date');
 | 
			
		||||
        } else {
 | 
			
		||||
            return trans('texts.valid_until');
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function discount()
 | 
			
		||||
    {
 | 
			
		||||
        $invoice = $this->entity;
 | 
			
		||||
 | 
			
		||||
        if ($invoice->is_amount_discount) {
 | 
			
		||||
            return $invoice->account->formatMoney($invoice->discount);
 | 
			
		||||
        } else {
 | 
			
		||||
            return $invoice->discount . '%';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // https://schema.org/PaymentStatusType
 | 
			
		||||
    public function paymentStatus()
 | 
			
		||||
    {
 | 
			
		||||
@ -99,4 +136,9 @@ class InvoicePresenter extends EntityPresenter {
 | 
			
		||||
 | 
			
		||||
        return trans('texts.auto_bill_notification', $data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function skypeBot()
 | 
			
		||||
    {
 | 
			
		||||
        return new InvoiceCard($this->entity);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										20
									
								
								app/Ninja/Presenters/ProductPresenter.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/Ninja/Presenters/ProductPresenter.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
<?php namespace App\Ninja\Presenters;
 | 
			
		||||
 | 
			
		||||
use App\Libraries\Skype\HeroCard;
 | 
			
		||||
 | 
			
		||||
class ProductPresenter extends EntityPresenter
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    public function skypeBot($account)
 | 
			
		||||
    {
 | 
			
		||||
        $product = $this->entity;
 | 
			
		||||
 | 
			
		||||
        $card = new HeroCard();
 | 
			
		||||
        $card->setTitle($product->product_key);
 | 
			
		||||
        $card->setSubitle($account->formatMoney($product->cost));
 | 
			
		||||
        $card->setText($product->notes);
 | 
			
		||||
 | 
			
		||||
        return $card;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -132,4 +132,47 @@ class ClientRepository extends BaseRepository
 | 
			
		||||
 | 
			
		||||
        return $client;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findPhonetically($clientName)
 | 
			
		||||
    {
 | 
			
		||||
        $clientNameMeta = metaphone($clientName);
 | 
			
		||||
 | 
			
		||||
        $map = [];
 | 
			
		||||
        $max = SIMILAR_MIN_THRESHOLD;
 | 
			
		||||
        $clientId = 0;
 | 
			
		||||
 | 
			
		||||
        $clients = Client::scope()->get(['id', 'name', 'public_id']);
 | 
			
		||||
 | 
			
		||||
        foreach ($clients as $client) {
 | 
			
		||||
            if ( ! $client->name) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $map[$client->id] = $client;
 | 
			
		||||
            $similar = similar_text($clientNameMeta, metaphone($client->name), $percent);
 | 
			
		||||
 | 
			
		||||
            if ($percent > $max) {
 | 
			
		||||
                $clientId = $client->id;
 | 
			
		||||
                $max = $percent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $contacts = Contact::scope()->get(['client_id', 'first_name', 'last_name', 'public_id']);
 | 
			
		||||
 | 
			
		||||
        foreach ($contacts as $contact) {
 | 
			
		||||
            if ( ! $contact->getFullName() || ! isset($map[$contact->client_id])) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $similar = similar_text($clientNameMeta, metaphone($contact->getFullName()), $percent);
 | 
			
		||||
 | 
			
		||||
            if ($percent > $max) {
 | 
			
		||||
                $clientId = $contact->client_id;
 | 
			
		||||
                $max = $percent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ($clientId && isset($map[$clientId])) ? $map[$clientId] : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -262,6 +262,7 @@ class InvoiceRepository extends BaseRepository
 | 
			
		||||
 | 
			
		||||
        if ($invoice) {
 | 
			
		||||
            // do nothing
 | 
			
		||||
            $entityType = $invoice->getEntityType();
 | 
			
		||||
        } elseif ($isNew) {
 | 
			
		||||
            $entityType = ENTITY_INVOICE;
 | 
			
		||||
            if (isset($data['is_recurring']) && filter_var($data['is_recurring'], FILTER_VALIDATE_BOOLEAN)) {
 | 
			
		||||
@ -270,6 +271,7 @@ class InvoiceRepository extends BaseRepository
 | 
			
		||||
                $entityType = ENTITY_QUOTE;
 | 
			
		||||
            }
 | 
			
		||||
            $invoice = $account->createInvoice($entityType, $data['client_id']);
 | 
			
		||||
            $invoice->invoice_date = date_create()->format('Y-m-d');
 | 
			
		||||
            if (isset($data['has_tasks']) && filter_var($data['has_tasks'], FILTER_VALIDATE_BOOLEAN)) {
 | 
			
		||||
                $invoice->has_tasks = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -56,4 +56,34 @@ class ProductRepository extends BaseRepository
 | 
			
		||||
        return $product;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function findPhonetically($productName)
 | 
			
		||||
    {
 | 
			
		||||
        $productNameMeta = metaphone($productName);
 | 
			
		||||
 | 
			
		||||
        $map = [];
 | 
			
		||||
        $max = SIMILAR_MIN_THRESHOLD;
 | 
			
		||||
        $productId = 0;
 | 
			
		||||
 | 
			
		||||
        $products = Product::scope()
 | 
			
		||||
                        ->with('default_tax_rate')
 | 
			
		||||
                        ->get();
 | 
			
		||||
 | 
			
		||||
        foreach ($products as $product) {
 | 
			
		||||
            if ( ! $product->product_key) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            $map[$product->id] = $product;
 | 
			
		||||
            $similar = similar_text($productNameMeta, metaphone($product->product_key), $percent);
 | 
			
		||||
 | 
			
		||||
            if ($percent > $max) {
 | 
			
		||||
                $productId = $product->id;
 | 
			
		||||
                $max = $percent;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return ($productId && isset($map[$productId])) ? $map[$productId] : null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -40,7 +40,7 @@ class InvoiceTransformer extends EntityTransformer
 | 
			
		||||
    public function includeInvoiceItems(Invoice $invoice)
 | 
			
		||||
    {
 | 
			
		||||
        $transformer = new InvoiceItemTransformer($this->account, $this->serializer);
 | 
			
		||||
        return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEMS);
 | 
			
		||||
        return $this->includeCollection($invoice->invoice_items, $transformer, ENTITY_INVOICE_ITEM);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function includeInvitations(Invoice $invoice)
 | 
			
		||||
 | 
			
		||||
@ -29,4 +29,4 @@ class UserTransformer extends EntityTransformer
 | 
			
		||||
            'permissions' => (int) $user->getOriginal('permissions'),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@ -45,7 +45,7 @@ class EntityPolicy
 | 
			
		||||
     * @param $ownerUserId
 | 
			
		||||
     * @return bool
 | 
			
		||||
     */
 | 
			
		||||
    public static function viewByOwner(User$user, $ownerUserId) {
 | 
			
		||||
    public static function viewByOwner(User $user, $ownerUserId) {
 | 
			
		||||
        return $user->hasPermission('view_all') || $user->id == $ownerUserId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,11 @@ class ComposerServiceProvider extends ServiceProvider
 | 
			
		||||
            ['accounts.details', 'clients.edit', 'payments.edit', 'invoices.edit', 'accounts.localization'],
 | 
			
		||||
            'App\Http\ViewComposers\TranslationComposer'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        view()->composer(
 | 
			
		||||
             ['header', 'tasks.edit'],
 | 
			
		||||
             'App\Http\ViewComposers\AppLanguageComposer'
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@ -28,4 +33,4 @@ class ComposerServiceProvider extends ServiceProvider
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ class BaseService
 | 
			
		||||
        $entities = $this->getRepo()->findByPublicIdsWithTrashed($ids);
 | 
			
		||||
 | 
			
		||||
        foreach ($entities as $entity) {
 | 
			
		||||
            if(Auth::user()->can('edit', $entity)){
 | 
			
		||||
            if (Auth::user()->can('edit', $entity)) {
 | 
			
		||||
                $this->getRepo()->$action($entity);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,6 @@ use Auth;
 | 
			
		||||
use Utils;
 | 
			
		||||
use parsecsv;
 | 
			
		||||
use Session;
 | 
			
		||||
use Validator;
 | 
			
		||||
use League\Fractal\Manager;
 | 
			
		||||
use App\Ninja\Repositories\ContactRepository;
 | 
			
		||||
use App\Ninja\Repositories\ClientRepository;
 | 
			
		||||
@ -141,7 +140,7 @@ class ImportService
 | 
			
		||||
 | 
			
		||||
        foreach ($json['clients'] as $jsonClient) {
 | 
			
		||||
 | 
			
		||||
            if ($this->validate($jsonClient, ENTITY_CLIENT) === true) {
 | 
			
		||||
            if (EntityModel::validate($jsonClient, ENTITY_CLIENT) === true) {
 | 
			
		||||
                $client = $this->clientRepo->save($jsonClient);
 | 
			
		||||
                $this->addSuccess($client);
 | 
			
		||||
            } else {
 | 
			
		||||
@ -151,7 +150,7 @@ class ImportService
 | 
			
		||||
 | 
			
		||||
            foreach ($jsonClient['invoices'] as $jsonInvoice) {
 | 
			
		||||
                $jsonInvoice['client_id'] = $client->id;
 | 
			
		||||
                if ($this->validate($jsonInvoice, ENTITY_INVOICE) === true) {
 | 
			
		||||
                if (EntityModel::validate($jsonInvoice, ENTITY_INVOICE) === true) {
 | 
			
		||||
                    $invoice = $this->invoiceRepo->save($jsonInvoice);
 | 
			
		||||
                    $this->addSuccess($invoice);
 | 
			
		||||
                } else {
 | 
			
		||||
@ -162,7 +161,7 @@ class ImportService
 | 
			
		||||
                foreach ($jsonInvoice['payments'] as $jsonPayment) {
 | 
			
		||||
                    $jsonPayment['client_id'] = $jsonPayment['client'] = $client->id; // TODO: change to client_id once views are updated
 | 
			
		||||
                    $jsonPayment['invoice_id'] = $jsonPayment['invoice'] = $invoice->id; // TODO: change to invoice_id once views are updated
 | 
			
		||||
                    if ($this->validate($jsonPayment, ENTITY_PAYMENT) === true) {
 | 
			
		||||
                    if (EntityModel::validate($jsonPayment, ENTITY_PAYMENT) === true) {
 | 
			
		||||
                        $payment = $this->paymentRepo->save($jsonPayment);
 | 
			
		||||
                        $this->addSuccess($payment);
 | 
			
		||||
                    } else {
 | 
			
		||||
@ -280,7 +279,7 @@ class ImportService
 | 
			
		||||
            $data['invoice_number'] = $account->getNextInvoiceNumber($invoice);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($this->validate($data, $entityType) !== true) {
 | 
			
		||||
        if (EntityModel::validate($data, $entityType) !== true) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -396,26 +395,6 @@ class ImportService
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param $data
 | 
			
		||||
     * @param $entityType
 | 
			
		||||
     * @return bool|string
 | 
			
		||||
     */
 | 
			
		||||
    private function validate($data, $entityType)
 | 
			
		||||
    {
 | 
			
		||||
        $requestClass = 'App\\Http\\Requests\\Create' . ucwords($entityType) . 'Request';
 | 
			
		||||
        $request = new $requestClass();
 | 
			
		||||
        $request->setUserResolver(function() { return Auth::user(); });
 | 
			
		||||
        $request->replace($data);
 | 
			
		||||
 | 
			
		||||
        $validator = Validator::make($data, $request->rules());
 | 
			
		||||
 | 
			
		||||
        if ($validator->fails()) {
 | 
			
		||||
            return $validator->messages()->first();
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @param array $files
 | 
			
		||||
 | 
			
		||||
@ -57,6 +57,21 @@ class PaymentService extends BaseService
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ($credits = $client->credits->sum('balance')) {
 | 
			
		||||
            $balance = $invoice->balance;
 | 
			
		||||
            $amount = min($credits, $balance);
 | 
			
		||||
            $data = [
 | 
			
		||||
                'payment_type_id' => PAYMENT_TYPE_CREDIT,
 | 
			
		||||
                'invoice_id' => $invoice->id,
 | 
			
		||||
                'client_id' => $client->id,
 | 
			
		||||
                'amount' => $amount,
 | 
			
		||||
            ];
 | 
			
		||||
            $payment = $this->paymentRepo->save($data);
 | 
			
		||||
            if ($amount == $balance) {
 | 
			
		||||
                return $payment;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $paymentDriver = $account->paymentDriver($invitation, GATEWAY_TYPE_TOKEN);
 | 
			
		||||
 | 
			
		||||
        if ( ! $paymentDriver) {
 | 
			
		||||
 | 
			
		||||
@ -154,4 +154,4 @@ class PushService
 | 
			
		||||
        else
 | 
			
		||||
            return trans('texts.notification_invoice_viewed_subject', ['invoice' => $invoice->invoice_number, 'client' => $invoice->client->name]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "jquery": "1.11.3",
 | 
			
		||||
    "bootstrap": "3.3.1",
 | 
			
		||||
    "bootstrap-combobox": "1.1.5",
 | 
			
		||||
    "jquery-ui": "1.11.2",
 | 
			
		||||
    "datatables": "1.10.4",
 | 
			
		||||
    "datatables-bootstrap3": "*",
 | 
			
		||||
@ -27,7 +28,8 @@
 | 
			
		||||
    "datetimepicker": "~2.4.5",
 | 
			
		||||
    "stacktrace-js": "~1.0.1",
 | 
			
		||||
    "fuse.js": "~2.0.2",
 | 
			
		||||
    "dropzone": "~4.3.0"
 | 
			
		||||
    "dropzone": "~4.3.0",
 | 
			
		||||
    "sweetalert": "~1.1.3"
 | 
			
		||||
  },
 | 
			
		||||
  "resolutions": {
 | 
			
		||||
    "jquery": "~1.11"
 | 
			
		||||
 | 
			
		||||
@ -13,6 +13,10 @@
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "require": {
 | 
			
		||||
        "php": ">=5.5.9",
 | 
			
		||||
        "ext-mcrypt": "*",
 | 
			
		||||
        "ext-gmp": "*",
 | 
			
		||||
        "ext-gd": "*",
 | 
			
		||||
        "turbo124/laravel-push-notification": "dev-laravel5",
 | 
			
		||||
        "omnipay/mollie": "dev-master#22956c1a62a9662afa5f5d119723b413770ac525",
 | 
			
		||||
        "omnipay/2checkout": "dev-master#e9c079c2dde0d7ba461903b3b7bd5caf6dee1248",
 | 
			
		||||
 | 
			
		||||
@ -17,16 +17,16 @@ class AddPageSize extends Migration
 | 
			
		||||
            $table->boolean('live_preview')->default(true);
 | 
			
		||||
            $table->smallInteger('invoice_number_padding')->default(4);
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Schema::table('fonts', function ($table) {
 | 
			
		||||
            $table->dropColumn('is_early_access');
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Schema::create('expense_categories', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->increments('id');
 | 
			
		||||
            $table->unsignedInteger('user_id');
 | 
			
		||||
            $table->unsignedInteger('account_id')->index();            
 | 
			
		||||
            $table->unsignedInteger('account_id')->index();
 | 
			
		||||
            $table->timestamps();
 | 
			
		||||
            $table->softDeletes();
 | 
			
		||||
 | 
			
		||||
@ -34,15 +34,14 @@ class AddPageSize extends Migration
 | 
			
		||||
 | 
			
		||||
            $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( array('account_id','public_id') );
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Schema::table('expenses', function ($table) {
 | 
			
		||||
            $table->unsignedInteger('expense_category_id')->nullable()->index();
 | 
			
		||||
            
 | 
			
		||||
            $table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');
 | 
			
		||||
            //$table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -62,12 +61,12 @@ class AddPageSize extends Migration
 | 
			
		||||
        Schema::table('fonts', function ($table) {
 | 
			
		||||
            $table->boolean('is_early_access');
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Schema::table('expenses', function ($table) {
 | 
			
		||||
            $table->dropForeign('expenses_expense_category_id_foreign');
 | 
			
		||||
            $table->dropColumn('expense_category_id');
 | 
			
		||||
        });
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        Schema::dropIfExists('expense_categories');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -88,7 +88,7 @@ class PaymentsChanges extends Migration
 | 
			
		||||
            $table->string('email')->nullable();
 | 
			
		||||
 | 
			
		||||
            $table->unsignedInteger('payment_method_id')->nullable();
 | 
			
		||||
            $table->foreign('payment_method_id')->references('id')->on('payment_methods');
 | 
			
		||||
            //$table->foreign('payment_method_id')->references('id')->on('payment_methods');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('invoices', function($table)
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,72 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Schema\Blueprint;
 | 
			
		||||
use Illuminate\Database\Migrations\Migration;
 | 
			
		||||
 | 
			
		||||
class AddSupportForBots extends Migration
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * Run the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function up()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::create('security_codes', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->increments('id');
 | 
			
		||||
            $table->unsignedInteger('account_id')->index();
 | 
			
		||||
            $table->unsignedInteger('user_id')->nullable();
 | 
			
		||||
            $table->unsignedInteger('contact_id')->nullable();
 | 
			
		||||
            $table->smallInteger('attempts');
 | 
			
		||||
            $table->string('code')->nullable();
 | 
			
		||||
            $table->string('bot_user_id')->unique();
 | 
			
		||||
            $table->timestamp('created_at')->useCurrent();
 | 
			
		||||
 | 
			
		||||
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
 | 
			
		||||
            $table->foreign('contact_id')->references('id')->on('contacts')->onDelete('cascade');
 | 
			
		||||
            $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('users', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->string('bot_user_id')->nullable();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('contacts', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->string('bot_user_id')->nullable();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('accounts', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->boolean('include_item_taxes_inline')->default(false);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Reverse the migrations.
 | 
			
		||||
     *
 | 
			
		||||
     * @return void
 | 
			
		||||
     */
 | 
			
		||||
    public function down()
 | 
			
		||||
    {
 | 
			
		||||
        Schema::dropIfExists('security_codes');
 | 
			
		||||
 | 
			
		||||
        Schema::table('users', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->dropColumn('bot_user_id');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('contacts', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->dropColumn('bot_user_id');
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Schema::table('accounts', function($table)
 | 
			
		||||
        {
 | 
			
		||||
            $table->dropColumn('include_item_taxes_inline');
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -55,7 +55,7 @@ class DateFormatsSeeder extends Seeder
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        foreach ($formats as $format) {
 | 
			
		||||
            $record = DatetimeFormat::whereFormat($format['format'])->first();
 | 
			
		||||
            $record = DatetimeFormat::whereRaw("BINARY `format`= ?", array($format['format']))->first();
 | 
			
		||||
            if ($record) {
 | 
			
		||||
                $record->format_moment = $format['format_moment'];
 | 
			
		||||
                $record->save();
 | 
			
		||||
 | 
			
		||||
@ -33,5 +33,5 @@ class PaymentStatusSeeder extends Seeder
 | 
			
		||||
                PaymentStatus::create($status);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }   
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										100
									
								
								gulpfile.js
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								gulpfile.js
									
									
									
									
									
								
							@ -1,16 +1,96 @@
 | 
			
		||||
var elixir = require('laravel-elixir');
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 |--------------------------------------------------------------------------
 | 
			
		||||
 | Elixir Asset Management
 | 
			
		||||
 |--------------------------------------------------------------------------
 | 
			
		||||
 |
 | 
			
		||||
 | Elixir provides a clean, fluent API for defining some basic Gulp tasks
 | 
			
		||||
 | for your Laravel application. By default, we are compiling the Less
 | 
			
		||||
 | file for our application, as well as publishing vendor resources.
 | 
			
		||||
 |
 | 
			
		||||
/**
 | 
			
		||||
 * Set Elixir Source Maps
 | 
			
		||||
 *
 | 
			
		||||
 * @type {boolean}
 | 
			
		||||
 */
 | 
			
		||||
elixir.config.sourcemaps = true;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configuring assets path.
 | 
			
		||||
 * Explicitly setting it to empty, as we're not using Laravels resources/assets folder
 | 
			
		||||
 *
 | 
			
		||||
 * @type {string}
 | 
			
		||||
 */
 | 
			
		||||
elixir.config.assetsPath = '';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configuring Javascript assets path.
 | 
			
		||||
 * Explicitly setting it to empty, as we're not using Laravels resources/assets/js folder
 | 
			
		||||
 *
 | 
			
		||||
 * @type {string}
 | 
			
		||||
 */
 | 
			
		||||
elixir.config.js.folder = '';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Configuring CSS assets path.
 | 
			
		||||
 * Explicitly setting it to empty, as we're not using Laravels resources/assets/css folder
 | 
			
		||||
 *
 | 
			
		||||
 * @type {string}
 | 
			
		||||
 */
 | 
			
		||||
elixir.config.css.folder = '';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove all CSS comments
 | 
			
		||||
 *
 | 
			
		||||
 * @type {{discardComments: {removeAll: boolean}}}
 | 
			
		||||
 */
 | 
			
		||||
elixir.config.css.minifier.pluginOptions = {
 | 
			
		||||
    discardComments: {
 | 
			
		||||
        removeAll: true
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Directory for bower source files.
 | 
			
		||||
 * If changing this, please also see .bowerrc
 | 
			
		||||
 *
 | 
			
		||||
 * @type {string}
 | 
			
		||||
 */
 | 
			
		||||
var bowerDir = 'public/vendor';
 | 
			
		||||
 | 
			
		||||
elixir(function(mix) {
 | 
			
		||||
    mix.less('app.less');
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * CSS configuration
 | 
			
		||||
     */
 | 
			
		||||
    mix.styles([
 | 
			
		||||
        bowerDir + '/bootstrap/dist/css/bootstrap.css',
 | 
			
		||||
        bowerDir + '/font-awesome/css/font-awesome.css',
 | 
			
		||||
        bowerDir + '/datatables/media/css/jquery.dataTables.css',
 | 
			
		||||
        bowerDir + '/datatables-bootstrap3/BS3/assets/css/datatables.css',
 | 
			
		||||
        'public/css/bootstrap-combobox.css',
 | 
			
		||||
        'public/css/public.style.css'
 | 
			
		||||
    ], 'public/css/built.public.css');
 | 
			
		||||
 | 
			
		||||
    mix.styles([
 | 
			
		||||
        bowerDir + '/bootstrap/dist/css/bootstrap.css',
 | 
			
		||||
        bowerDir + '/bootstrap-datepicker/dist/css/bootstrap-datepicker3.css',
 | 
			
		||||
        bowerDir + '/datatables/media/css/jquery.dataTables.css',
 | 
			
		||||
        bowerDir + '/datatables-bootstrap3/BS3/assets/css/datatables.css',
 | 
			
		||||
        bowerDir + '/font-awesome/css/font-awesome.css',
 | 
			
		||||
        bowerDir + '/dropzone/dist/dropzone.css',
 | 
			
		||||
        bowerDir + '/spectrum/spectrum.css',
 | 
			
		||||
        bowerDir + '/sweetalert/dist/sweetalert.css',
 | 
			
		||||
        'public/css/bootstrap-combobox.css',
 | 
			
		||||
        'public/css/typeahead.js-bootstrap.css',
 | 
			
		||||
        'public/css/style.css'
 | 
			
		||||
    ], 'public/css/built.css');
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * JS configuration
 | 
			
		||||
     */
 | 
			
		||||
    mix.scripts(['resources/assets/js/Chart.js'], 'public/js/Chart.min.js')
 | 
			
		||||
        .scripts(['resources/assets/js/d3.js'], 'public/js/d3.min.js');
 | 
			
		||||
 | 
			
		||||
    mix.scripts([
 | 
			
		||||
        'public/js/pdf_viewer.js',
 | 
			
		||||
        'public/js/compatibility.js',
 | 
			
		||||
        //'public/js/pdfmake.min.js',
 | 
			
		||||
        'public/js/pdfmake.js',
 | 
			
		||||
        'public/js/vfs.js'
 | 
			
		||||
    ], 'public/pdf.built.js');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
    "grunt-contrib-uglify": "~0.2.2",
 | 
			
		||||
    "grunt-dump-dir": "^0.1.2",
 | 
			
		||||
    "gulp": "^3.8.8",
 | 
			
		||||
    "laravel-elixir": "*"
 | 
			
		||||
    "laravel-elixir": "^6.0.0"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "grunt-dump-dir": "^0.1.2"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/android-chrome-192x192.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/android-chrome-192x192.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 12 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/android-chrome-512x512.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								public/android-chrome-512x512.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 35 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 12 KiB  | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/built.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/built.js.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										3
									
								
								public/css/app.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								public/css/app.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/app.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/app.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/bootstrap.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/bootstrap.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										3235
									
								
								public/css/built.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3235
									
								
								public/css/built.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/built.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/built.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										21
									
								
								public/css/built.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								public/css/built.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/built.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/built.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										971
									
								
								public/css/built.public.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										971
									
								
								public/css/built.public.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/built.public.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/built.public.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										14
									
								
								public/css/built.public.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								public/css/built.public.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/built.public.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/built.public.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/css/customCss.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								public/css/customCss.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
.customContainer{padding:40px 0;margin:0!important;background:-webkit-linear-gradient(#f5f5f5,#fff)}.customFontHead{font-size:20px;text-align:center}.customTextBorder{border-bottom:1px solid #c3c1c1;padding-bottom:5%;margin-bottom:5%}.customSubMenu{margin-left:2%}.customMenuOne{padding-left:5px;padding-right:5px}.shiftLeft{float:left}.customMenuDiv{padding-bottom:30px;float:left;width:100%}
 | 
			
		||||
/*# sourceMappingURL=customCss.min.css.map */
 | 
			
		||||
							
								
								
									
										1
									
								
								public/css/customCss.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/customCss.min.css.map
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"sources":["customCss.css"],"names":[],"mappings":"AAAA,iBACA,eAAA,AACA,mBAAA,AACA,gDAAA,CACA,AACA,gBACA,eAAA,AACA,iBAAA,CACA,AACA,kBACA,gCAAA,AACA,kBAAA,AACA,gBAAA,CACA,AACA,eACA,cAAA,CACA,AACA,eACA,iBAAA,AACA,iBAAA,CACA,AACA,WACA,UAAA,CACA,AACA,eACA,oBAAA,AACA,WAAA,AACA,UAAA,CACA","file":"customCss.min.css","sourcesContent":[".customContainer{\n\tpadding: 40px 0;\n\tmargin: 0px 0 !important;\n\tbackground: -webkit-linear-gradient(rgb(245, 245, 245), white);\n}\t\n.customFontHead{\n\tfont-size: 20px;\n\ttext-align: center;\n}\t\n.customTextBorder{\n\tborder-bottom: 1px solid rgb(195, 193, 193);\n\tpadding-bottom: 5%;\n\tmargin-bottom: 5%;\n}\n.customSubMenu{\n\tmargin-left: 2%;\n}\n.customMenuOne{\n\tpadding-left: 5px;\n\tpadding-right: 5px;\n}\n.shiftLeft{\n\tfloat: left;\n}\n.customMenuDiv{\n\tpadding-bottom: 30px;\n\tfloat: left;\n\twidth: 100%;\n}"],"sourceRoot":"/source/"}
 | 
			
		||||
							
								
								
									
										893
									
								
								public/css/img/jsoneditor-icons.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										893
									
								
								public/css/img/jsoneditor-icons.svg
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,893 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="216"
 | 
			
		||||
   height="144"
 | 
			
		||||
   id="svg4136"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   inkscape:version="0.91 r"
 | 
			
		||||
   sodipodi:docname="jsoneditor-icons.svg">
 | 
			
		||||
  <title
 | 
			
		||||
     id="title6512">JSON Editor Icons</title>
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata4148">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title>JSON Editor Icons</dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs4146" />
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1"
 | 
			
		||||
     objecttolerance="10"
 | 
			
		||||
     gridtolerance="10"
 | 
			
		||||
     guidetolerance="10"
 | 
			
		||||
     inkscape:pageopacity="0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:window-width="1920"
 | 
			
		||||
     inkscape:window-height="1028"
 | 
			
		||||
     id="namedview4144"
 | 
			
		||||
     showgrid="true"
 | 
			
		||||
     inkscape:zoom="4"
 | 
			
		||||
     inkscape:cx="97.217248"
 | 
			
		||||
     inkscape:cy="59.950227"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="0"
 | 
			
		||||
     inkscape:window-maximized="1"
 | 
			
		||||
     inkscape:current-layer="svg4136"
 | 
			
		||||
     showguides="false"
 | 
			
		||||
     borderlayer="false"
 | 
			
		||||
     inkscape:showpageshadow="true"
 | 
			
		||||
     showborder="true">
 | 
			
		||||
    <inkscape:grid
 | 
			
		||||
       type="xygrid"
 | 
			
		||||
       id="grid4640"
 | 
			
		||||
       empspacing="24" />
 | 
			
		||||
  </sodipodi:namedview>
 | 
			
		||||
  <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
 | 
			
		||||
  <g
 | 
			
		||||
     id="g4394">
 | 
			
		||||
    <rect
 | 
			
		||||
       x="4"
 | 
			
		||||
       y="4"
 | 
			
		||||
       width="16"
 | 
			
		||||
       height="16"
 | 
			
		||||
       id="svg_1"
 | 
			
		||||
       style="fill:#1aae1c;fill-opacity:1;stroke:none;stroke-width:0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0"
 | 
			
		||||
       x="28.000006"
 | 
			
		||||
       y="3.999995"
 | 
			
		||||
       width="16"
 | 
			
		||||
       height="16"
 | 
			
		||||
       id="svg_1-7" />
 | 
			
		||||
    <rect
 | 
			
		||||
       id="rect4165"
 | 
			
		||||
       height="16"
 | 
			
		||||
       width="16"
 | 
			
		||||
       y="3.999995"
 | 
			
		||||
       x="52.000004"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       x="172.00002"
 | 
			
		||||
       y="3.9999852"
 | 
			
		||||
       width="16"
 | 
			
		||||
       height="16"
 | 
			
		||||
       id="rect4175" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       x="196"
 | 
			
		||||
       y="3.999995"
 | 
			
		||||
       width="16"
 | 
			
		||||
       height="16"
 | 
			
		||||
       id="rect4175-3" />
 | 
			
		||||
    <g
 | 
			
		||||
       style="stroke:none"
 | 
			
		||||
       id="g4299">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
         id="svg_1-1"
 | 
			
		||||
         height="1.9999986"
 | 
			
		||||
         width="9.9999924"
 | 
			
		||||
         y="10.999998"
 | 
			
		||||
         x="7.0000048" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
         id="svg_1-1-1"
 | 
			
		||||
         height="9.9999838"
 | 
			
		||||
         width="1.9999955"
 | 
			
		||||
         y="7.0000114"
 | 
			
		||||
         x="11.000005" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       style="stroke:none"
 | 
			
		||||
       transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,12.000001)"
 | 
			
		||||
       id="g4299-3">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
         id="svg_1-1-0"
 | 
			
		||||
         height="1.9999986"
 | 
			
		||||
         width="9.9999924"
 | 
			
		||||
         y="10.999998"
 | 
			
		||||
         x="7.0000048" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
         id="svg_1-1-1-9"
 | 
			
		||||
         height="9.9999838"
 | 
			
		||||
         width="1.9999955"
 | 
			
		||||
         y="7.0000114"
 | 
			
		||||
         x="11.000005" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
       x="55.000004"
 | 
			
		||||
       y="7.0000048"
 | 
			
		||||
       width="6.9999909"
 | 
			
		||||
       height="6.9999905"
 | 
			
		||||
       id="svg_1-7-5" />
 | 
			
		||||
    <rect
 | 
			
		||||
       id="rect4354"
 | 
			
		||||
       height="6.9999905"
 | 
			
		||||
       width="6.9999909"
 | 
			
		||||
       y="10.00001"
 | 
			
		||||
       x="58"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#3c80df;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
 | 
			
		||||
       x="58.000004"
 | 
			
		||||
       y="10.000005"
 | 
			
		||||
       width="6.9999909"
 | 
			
		||||
       height="6.9999905"
 | 
			
		||||
       id="svg_1-7-5-7" />
 | 
			
		||||
    <g
 | 
			
		||||
       id="g4378">
 | 
			
		||||
      <rect
 | 
			
		||||
         id="svg_1-7-5-3"
 | 
			
		||||
         height="1.9999965"
 | 
			
		||||
         width="7.9999909"
 | 
			
		||||
         y="10.999999"
 | 
			
		||||
         x="198"
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
         x="198"
 | 
			
		||||
         y="7.0000005"
 | 
			
		||||
         width="11.999995"
 | 
			
		||||
         height="1.9999946"
 | 
			
		||||
         id="rect4374" />
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
         x="198"
 | 
			
		||||
         y="14.999996"
 | 
			
		||||
         width="3.9999928"
 | 
			
		||||
         height="1.9999995"
 | 
			
		||||
         id="rect4376" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <g
 | 
			
		||||
       id="g4383"
 | 
			
		||||
       transform="matrix(1,0,0,-1,-23.999995,23.999995)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
         x="198"
 | 
			
		||||
         y="10.999999"
 | 
			
		||||
         width="7.9999909"
 | 
			
		||||
         height="1.9999965"
 | 
			
		||||
         id="rect4385" />
 | 
			
		||||
      <rect
 | 
			
		||||
         id="rect4387"
 | 
			
		||||
         height="1.9999946"
 | 
			
		||||
         width="11.999995"
 | 
			
		||||
         y="7.0000005"
 | 
			
		||||
         x="198"
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
      <rect
 | 
			
		||||
         id="rect4389"
 | 
			
		||||
         height="1.9999995"
 | 
			
		||||
         width="3.9999928"
 | 
			
		||||
         y="14.999996"
 | 
			
		||||
         x="198"
 | 
			
		||||
         style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
    </g>
 | 
			
		||||
    <rect
 | 
			
		||||
       y="3.9999199"
 | 
			
		||||
       x="76"
 | 
			
		||||
       height="16"
 | 
			
		||||
       width="16"
 | 
			
		||||
       id="rect3754-4"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:nodetypes="cccccccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path4351"
 | 
			
		||||
       d="m 85.10447,6.0157384 -0.0156,1.4063 c 3.02669,-0.2402 0.33008,3.6507996 2.48438,4.5780996 -2.18694,1.0938 0.49191,4.9069 -2.45313,4.5781 l -0.0156,1.4219 c 5.70828,0.559 1.03264,-5.1005 4.70313,-5.2656 l 0,-1.4063 c -3.61303,-0.027 1.11893,-5.7069996 -4.70313,-5.3124996 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:nodetypes="cccccccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path4351-9"
 | 
			
		||||
       d="m 82.78125,5.9984384 0.0156,1.4063 c -3.02668,-0.2402 -0.33007,3.6506996 -2.48437,4.5780996 2.18694,1.0938 -0.49192,4.9069 2.45312,4.5781 l 0.0156,1.4219 c -5.70827,0.559 -1.03263,-5.1004 -4.70312,-5.2656 l 0,-1.4063 c 3.61303,-0.027 -1.11894,-5.7070996 4.70312,-5.3124996 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="3.9999199"
 | 
			
		||||
       x="100"
 | 
			
		||||
       height="16"
 | 
			
		||||
       width="16"
 | 
			
		||||
       id="rect3754-25"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path2987"
 | 
			
		||||
       d="m 103.719,5.6719384 0,12.7187996 3.03125,0 0,-1.5313 -1.34375,0 0,-9.6249996 1.375,0 0,-1.5625 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path2987-1"
 | 
			
		||||
       d="m 112.2185,5.6721984 0,12.7187996 -3.03125,0 0,-1.5313 1.34375,0 0,-9.6249996 -1.375,0 0,-1.5625 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="3.9999199"
 | 
			
		||||
       x="124"
 | 
			
		||||
       height="16"
 | 
			
		||||
       width="16"
 | 
			
		||||
       id="rect3754-73"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:nodetypes="ccccccccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path3780"
 | 
			
		||||
       d="m 126.2824,17.602938 1.78957,0 1.14143,-2.8641 5.65364,0 1.14856,2.8641 1.76565,0 -4.78687,-11.1610996 -1.91903,0 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path3782"
 | 
			
		||||
       d="m 129.72704,13.478838 4.60852,0.01 -2.30426,-5.5497996 z"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <rect
 | 
			
		||||
       y="3.9999199"
 | 
			
		||||
       x="148"
 | 
			
		||||
       height="16"
 | 
			
		||||
       width="16"
 | 
			
		||||
       id="rect3754-35"
 | 
			
		||||
       style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:nodetypes="ccccccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path5008-2"
 | 
			
		||||
       d="m 156.47655,5.8917384 0,2.1797 0.46093,2.3983996 1.82813,0 0.39844,-2.3983996 0,-2.1797 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none" />
 | 
			
		||||
    <path
 | 
			
		||||
       sodipodi:nodetypes="ccccccc"
 | 
			
		||||
       inkscape:connector-curvature="0"
 | 
			
		||||
       id="path5008-2-8"
 | 
			
		||||
       d="m 152.51561,5.8906384 0,2.1797 0.46094,2.3983996 1.82812,0 0.39844,-2.3983996 0,-2.1797 z"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <rect
 | 
			
		||||
     x="4"
 | 
			
		||||
     y="27.999994"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     id="rect4432"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
     x="28.000006"
 | 
			
		||||
     y="27.99999"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     id="rect4434" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4436"
 | 
			
		||||
     height="16"
 | 
			
		||||
     width="16"
 | 
			
		||||
     y="27.99999"
 | 
			
		||||
     x="52.000004"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
 | 
			
		||||
     x="172.00002"
 | 
			
		||||
     y="27.999981"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     id="rect4446" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
 | 
			
		||||
     x="196"
 | 
			
		||||
     y="27.99999"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     id="rect4448" />
 | 
			
		||||
  <g
 | 
			
		||||
     id="g4466"
 | 
			
		||||
     style="stroke:none"
 | 
			
		||||
     transform="translate(0,23.999995)">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       id="rect4468"
 | 
			
		||||
       height="1.9999986"
 | 
			
		||||
       width="9.9999924"
 | 
			
		||||
       y="10.999998"
 | 
			
		||||
       x="7.0000048" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       id="rect4470"
 | 
			
		||||
       height="9.9999838"
 | 
			
		||||
       width="1.9999955"
 | 
			
		||||
       y="7.0000114"
 | 
			
		||||
       x="11.000005" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <g
 | 
			
		||||
     transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,35.999996)"
 | 
			
		||||
     id="g4472"
 | 
			
		||||
     style="stroke:none">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       id="rect4474"
 | 
			
		||||
       height="1.9999986"
 | 
			
		||||
       width="9.9999924"
 | 
			
		||||
       y="10.999998"
 | 
			
		||||
       x="7.0000048" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
 | 
			
		||||
       id="rect4476"
 | 
			
		||||
       height="9.9999838"
 | 
			
		||||
       width="1.9999955"
 | 
			
		||||
       y="7.0000114"
 | 
			
		||||
       x="11.000005" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
     x="55.000004"
 | 
			
		||||
     y="31"
 | 
			
		||||
     width="6.9999909"
 | 
			
		||||
     height="6.9999905"
 | 
			
		||||
     id="rect4478" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4480"
 | 
			
		||||
     height="6.9999905"
 | 
			
		||||
     width="6.9999909"
 | 
			
		||||
     y="34.000008"
 | 
			
		||||
     x="58"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     x="58.000004"
 | 
			
		||||
     y="34.000004"
 | 
			
		||||
     width="6.9999909"
 | 
			
		||||
     height="6.9999905"
 | 
			
		||||
     id="rect4482" />
 | 
			
		||||
  <g
 | 
			
		||||
     id="g4484"
 | 
			
		||||
     transform="translate(0,23.999995)">
 | 
			
		||||
    <rect
 | 
			
		||||
       id="rect4486"
 | 
			
		||||
       height="1.9999965"
 | 
			
		||||
       width="7.9999909"
 | 
			
		||||
       y="10.999999"
 | 
			
		||||
       x="198"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
       x="198"
 | 
			
		||||
       y="7.0000005"
 | 
			
		||||
       width="11.999995"
 | 
			
		||||
       height="1.9999946"
 | 
			
		||||
       id="rect4488" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
       x="198"
 | 
			
		||||
       y="14.999996"
 | 
			
		||||
       width="3.9999928"
 | 
			
		||||
       height="1.9999995"
 | 
			
		||||
       id="rect4490" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <g
 | 
			
		||||
     id="g4492"
 | 
			
		||||
     transform="matrix(1,0,0,-1,-23.999995,47.99999)">
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
 | 
			
		||||
       x="198"
 | 
			
		||||
       y="10.999999"
 | 
			
		||||
       width="7.9999909"
 | 
			
		||||
       height="1.9999965"
 | 
			
		||||
       id="rect4494" />
 | 
			
		||||
    <rect
 | 
			
		||||
       id="rect4496"
 | 
			
		||||
       height="1.9999946"
 | 
			
		||||
       width="11.999995"
 | 
			
		||||
       y="7.0000005"
 | 
			
		||||
       x="198"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
    <rect
 | 
			
		||||
       id="rect4498"
 | 
			
		||||
       height="1.9999995"
 | 
			
		||||
       width="3.9999928"
 | 
			
		||||
       y="14.999996"
 | 
			
		||||
       x="198"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
 | 
			
		||||
  </g>
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none"
 | 
			
		||||
     id="rect3754-8"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     x="76"
 | 
			
		||||
     y="27.99992" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="m 85.10448,30.015537 -0.0156,1.4063 c 3.02668,-0.2402 0.33007,3.6508 2.48438,4.5781 -2.18695,1.0938 0.49191,4.90688 -2.45313,4.57808 l -0.0156,1.4219 c 5.70827,0.559 1.03263,-5.10048 4.70313,-5.26558 l 0,-1.4063 c -3.61304,-0.027 1.11893,-5.707 -4.70313,-5.3125 z"
 | 
			
		||||
     id="path4351-1"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccccccc" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="m 82.78126,29.998237 0.0156,1.4063 c -3.02668,-0.2402 -0.33008,3.6507 -2.48438,4.5781 2.18694,1.0938 -0.49191,4.90688 2.45313,4.57808 l 0.0156,1.4219 c -5.70828,0.559 -1.03264,-5.10038 -4.70313,-5.26558 l 0,-1.4063 c 3.61303,-0.027 -1.11893,-5.7071 4.70313,-5.3125 z"
 | 
			
		||||
     id="path4351-9-5"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccccccc" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none"
 | 
			
		||||
     id="rect3754-65"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     x="100"
 | 
			
		||||
     y="27.99992" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 103.719,29.671937 0,12.71878 3.03125,0 0,-1.5313 -1.34375,0 0,-9.62498 1.375,0 0,-1.5625 z"
 | 
			
		||||
     id="path2987-8"
 | 
			
		||||
     inkscape:connector-curvature="0" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 112.2185,29.671937 0,12.71878 -3.03125,0 0,-1.5313 1.34375,0 0,-9.62498 -1.375,0 0,-1.5625 z"
 | 
			
		||||
     id="path2987-1-9"
 | 
			
		||||
     inkscape:connector-curvature="0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none"
 | 
			
		||||
     id="rect3754-92"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     x="124"
 | 
			
		||||
     y="27.99992" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 126.2824,41.602917 1.78957,0 1.14143,-2.86408 5.65364,0 1.14856,2.86408 1.76565,0 -4.78687,-11.16108 -1.91902,0 z"
 | 
			
		||||
     id="path3780-9"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="ccccccccc" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 129.72704,37.478837 4.60852,0.01 -2.30426,-5.5498 z"
 | 
			
		||||
     id="path3782-2"
 | 
			
		||||
     inkscape:connector-curvature="0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none"
 | 
			
		||||
     id="rect3754-47"
 | 
			
		||||
     width="16"
 | 
			
		||||
     height="16"
 | 
			
		||||
     x="148"
 | 
			
		||||
     y="27.99992" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 156.47656,29.891737 0,2.1797 0.46093,2.3984 1.82813,0 0.39844,-2.3984 0,-2.1797 z"
 | 
			
		||||
     id="path5008-2-1"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="ccccccc" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:1;stroke:none"
 | 
			
		||||
     d="m 152.51562,29.890637 0,2.1797 0.46094,2.3984 1.82812,0 0.39844,-2.3984 0,-2.1797 z"
 | 
			
		||||
     id="path5008-2-8-8"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="ccccccc" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="svg_1-7-2"
 | 
			
		||||
     height="1.9999961"
 | 
			
		||||
     width="11.999996"
 | 
			
		||||
     y="64"
 | 
			
		||||
     x="54"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="svg_1-7-2-2"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="52"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     y="52"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4561" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     y="58"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4563" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4565"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="58"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4567"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="64"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     y="64"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4569" />
 | 
			
		||||
  <circle
 | 
			
		||||
     style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     id="path4571"
 | 
			
		||||
     cx="110.06081"
 | 
			
		||||
     cy="57.939209"
 | 
			
		||||
     r="4.7438836" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="116.64566"
 | 
			
		||||
     y="-31.79752"
 | 
			
		||||
     width="4.229713"
 | 
			
		||||
     height="6.4053884"
 | 
			
		||||
     id="rect4563-2"
 | 
			
		||||
     transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="M 125,56 138.77027,56.095 132,64 Z"
 | 
			
		||||
     id="path4613"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccc" />
 | 
			
		||||
  <path
 | 
			
		||||
     sodipodi:nodetypes="cccc"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     id="path4615"
 | 
			
		||||
     d="M 149,64 162.77027,63.905 156,56 Z"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="54"
 | 
			
		||||
     y="53"
 | 
			
		||||
     width="11.999996"
 | 
			
		||||
     height="1.9999961"
 | 
			
		||||
     id="rect4638" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="svg_1-7-2-24"
 | 
			
		||||
     height="1.9999957"
 | 
			
		||||
     width="12.99999"
 | 
			
		||||
     y="-56"
 | 
			
		||||
     x="53"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     transform="matrix(0,1,-1,0,0,0)" />
 | 
			
		||||
  <rect
 | 
			
		||||
     transform="matrix(0,1,-1,0,0,0)"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
 | 
			
		||||
     x="53"
 | 
			
		||||
     y="-66"
 | 
			
		||||
     width="12.99999"
 | 
			
		||||
     height="1.9999957"
 | 
			
		||||
     id="rect4657" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4659"
 | 
			
		||||
     height="0.99999291"
 | 
			
		||||
     width="11.999999"
 | 
			
		||||
     y="57"
 | 
			
		||||
     x="54"
 | 
			
		||||
     style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="54"
 | 
			
		||||
     y="88.000122"
 | 
			
		||||
     width="11.999996"
 | 
			
		||||
     height="1.9999961"
 | 
			
		||||
     id="rect4661" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     y="76.000122"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4663" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4665"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="76.000122"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4667"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="82.000122"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     y="82.000122"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4669" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="80.000008"
 | 
			
		||||
     y="88.000122"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     id="rect4671" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4673"
 | 
			
		||||
     height="2.9999905"
 | 
			
		||||
     width="2.9999907"
 | 
			
		||||
     y="88.000122"
 | 
			
		||||
     x="85.000008"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
 | 
			
		||||
  <circle
 | 
			
		||||
     r="4.7438836"
 | 
			
		||||
     cy="81.939331"
 | 
			
		||||
     cx="110.06081"
 | 
			
		||||
     id="circle4675"
 | 
			
		||||
     style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
  <rect
 | 
			
		||||
     transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
 | 
			
		||||
     id="rect4677"
 | 
			
		||||
     height="6.4053884"
 | 
			
		||||
     width="4.229713"
 | 
			
		||||
     y="-14.826816"
 | 
			
		||||
     x="133.6163"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-opacity:1" />
 | 
			
		||||
  <path
 | 
			
		||||
     sodipodi:nodetypes="cccc"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     id="path4679"
 | 
			
		||||
     d="m 125,80.000005 13.77027,0.09499 L 132,87.999992 Z"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="M 149,88.0002 162.77027,87.9052 156,80.0002 Z"
 | 
			
		||||
     id="path4681"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccc" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4683"
 | 
			
		||||
     height="1.9999961"
 | 
			
		||||
     width="11.999996"
 | 
			
		||||
     y="77.000122"
 | 
			
		||||
     x="54"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
 | 
			
		||||
  <rect
 | 
			
		||||
     transform="matrix(0,1,-1,0,0,0)"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="77.000122"
 | 
			
		||||
     y="-56"
 | 
			
		||||
     width="12.99999"
 | 
			
		||||
     height="1.9999957"
 | 
			
		||||
     id="rect4685" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4687"
 | 
			
		||||
     height="1.9999957"
 | 
			
		||||
     width="12.99999"
 | 
			
		||||
     y="-66"
 | 
			
		||||
     x="77.000122"
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     transform="matrix(0,1,-1,0,0,0)" />
 | 
			
		||||
  <rect
 | 
			
		||||
     style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
 | 
			
		||||
     x="54"
 | 
			
		||||
     y="81.000122"
 | 
			
		||||
     width="11.999999"
 | 
			
		||||
     height="0.99999291"
 | 
			
		||||
     id="rect4689" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-1"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="15.99999"
 | 
			
		||||
     y="101"
 | 
			
		||||
     x="76.000008"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-0"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="15.99999"
 | 
			
		||||
     y="105"
 | 
			
		||||
     x="76.000008"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-7"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="9"
 | 
			
		||||
     y="109"
 | 
			
		||||
     x="76.000008"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-1-1"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="12"
 | 
			
		||||
     y="125"
 | 
			
		||||
     x="76.000008"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-1-1-4"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="10"
 | 
			
		||||
     y="137"
 | 
			
		||||
     x="76.000008"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-1-1-4-4"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="10"
 | 
			
		||||
     y="129"
 | 
			
		||||
     x="82"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <rect
 | 
			
		||||
     id="rect4761-1-1-4-4-3"
 | 
			
		||||
     height="1.9999945"
 | 
			
		||||
     width="9"
 | 
			
		||||
     y="133"
 | 
			
		||||
     x="82"
 | 
			
		||||
     style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
     d="m 36.398438,100.0254 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,100.5991 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1452 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533865,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550756,0 6.710442,-2.4113 7.650391,-5.9414 0.939949,-3.5301 -0.618463,-7.2736 -3.710938,-9.0703 -1.159678,-0.6738 -2.431087,-1.0231 -3.701171,-1.0625 z"
 | 
			
		||||
     id="path4138" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
     d="m 59.722656,99.9629 c -1.270084,0.039 -2.541493,0.3887 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5402 -3.710937,9.0703 0.939949,3.5301 4.09768,5.9414 7.648437,5.9414 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4056 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
 | 
			
		||||
     id="path4138-1" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     d="m 10.5,100 0,2 -2.4999996,0 L 12,107 l 4,-5 -2.5,0 0,-2 -3,0 z"
 | 
			
		||||
     id="path3055-0-77" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="m 4.9850574,108.015 14.0298856,-0.03"
 | 
			
		||||
     id="path5244-5-0-5"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cc" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
     d="m 4.9849874,132.015 14.0298866,-0.03"
 | 
			
		||||
     id="path5244-5-0-5-8"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cc" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
     d="m 36.398438,123.9629 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,124.5366 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1453 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533864,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550757,0 6.710442,-2.4093 7.650391,-5.9394 0.939949,-3.5301 -0.618463,-7.2756 -3.710938,-9.0723 -1.159678,-0.6737 -2.431087,-1.0231 -3.701171,-1.0625 z"
 | 
			
		||||
     id="path4138-12" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
 | 
			
		||||
     d="m 59.722656,123.9629 c -1.270084,0.039 -2.541493,0.3888 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5422 -3.710937,9.0723 0.939949,3.5301 4.09768,5.9394 7.648437,5.9394 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4055 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
 | 
			
		||||
     id="path4138-1-3" />
 | 
			
		||||
  <path
 | 
			
		||||
     id="path6191"
 | 
			
		||||
     d="m 10.5,116 0,-2 -2.4999996,0 L 12,109 l 4,5 -2.5,0 0,2 -3,0 z"
 | 
			
		||||
     style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     inkscape:connector-curvature="0" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     d="m 10.5,129 0,-2 -2.4999996,0 L 12,122 l 4,5 -2.5,0 0,2 -3,0 z"
 | 
			
		||||
     id="path6193" />
 | 
			
		||||
  <path
 | 
			
		||||
     id="path6195"
 | 
			
		||||
     d="m 10.5,135 0,2 -2.4999996,0 L 12,142 l 4,-5 -2.5,0 0,-2 -3,0 z"
 | 
			
		||||
     style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     inkscape:connector-curvature="0" />
 | 
			
		||||
  <path
 | 
			
		||||
     sodipodi:type="star"
 | 
			
		||||
     style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     id="path4500"
 | 
			
		||||
     sodipodi:sides="3"
 | 
			
		||||
     sodipodi:cx="11.55581"
 | 
			
		||||
     sodipodi:cy="60.073242"
 | 
			
		||||
     sodipodi:r1="5.1116104"
 | 
			
		||||
     sodipodi:r2="2.5558052"
 | 
			
		||||
     sodipodi:arg1="0"
 | 
			
		||||
     sodipodi:arg2="1.0471976"
 | 
			
		||||
     inkscape:flatsided="false"
 | 
			
		||||
     inkscape:rounded="0"
 | 
			
		||||
     inkscape:randomized="0"
 | 
			
		||||
     d="m 16.66742,60.073242 -3.833708,2.213392 -3.8337072,2.213393 0,-4.426785 0,-4.426784 3.8337082,2.213392 z"
 | 
			
		||||
     inkscape:transform-center-x="-1.2779026" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:transform-center-x="1.277902"
 | 
			
		||||
     d="m -31.500004,60.073242 -3.833708,2.213392 -3.833707,2.213393 0,-4.426785 0,-4.426784 3.833707,2.213392 z"
 | 
			
		||||
     inkscape:randomized="0"
 | 
			
		||||
     inkscape:rounded="0"
 | 
			
		||||
     inkscape:flatsided="false"
 | 
			
		||||
     sodipodi:arg2="1.0471976"
 | 
			
		||||
     sodipodi:arg1="0"
 | 
			
		||||
     sodipodi:r2="2.5558052"
 | 
			
		||||
     sodipodi:r1="5.1116104"
 | 
			
		||||
     sodipodi:cy="60.073242"
 | 
			
		||||
     sodipodi:cx="-36.611614"
 | 
			
		||||
     sodipodi:sides="3"
 | 
			
		||||
     id="path4502"
 | 
			
		||||
     style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     sodipodi:type="star"
 | 
			
		||||
     transform="scale(-1,1)" />
 | 
			
		||||
  <path
 | 
			
		||||
     d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z"
 | 
			
		||||
     inkscape:randomized="0"
 | 
			
		||||
     inkscape:rounded="0"
 | 
			
		||||
     inkscape:flatsided="false"
 | 
			
		||||
     sodipodi:arg2="1.0471976"
 | 
			
		||||
     sodipodi:arg1="0"
 | 
			
		||||
     sodipodi:r2="2.5558052"
 | 
			
		||||
     sodipodi:r1="5.1116104"
 | 
			
		||||
     sodipodi:cy="60.073212"
 | 
			
		||||
     sodipodi:cx="11.55581"
 | 
			
		||||
     sodipodi:sides="3"
 | 
			
		||||
     id="path4504"
 | 
			
		||||
     style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     sodipodi:type="star"
 | 
			
		||||
     transform="matrix(0,1,-1,0,72.0074,71.7877)"
 | 
			
		||||
     inkscape:transform-center-y="1.2779029" />
 | 
			
		||||
  <path
 | 
			
		||||
     inkscape:transform-center-y="-1.2779026"
 | 
			
		||||
     transform="matrix(0,-1,-1,0,96,96)"
 | 
			
		||||
     sodipodi:type="star"
 | 
			
		||||
     style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
     id="path4506"
 | 
			
		||||
     sodipodi:sides="3"
 | 
			
		||||
     sodipodi:cx="11.55581"
 | 
			
		||||
     sodipodi:cy="60.073212"
 | 
			
		||||
     sodipodi:r1="5.1116104"
 | 
			
		||||
     sodipodi:r2="2.5558052"
 | 
			
		||||
     sodipodi:arg1="0"
 | 
			
		||||
     sodipodi:arg2="1.0471976"
 | 
			
		||||
     inkscape:flatsided="false"
 | 
			
		||||
     inkscape:rounded="0"
 | 
			
		||||
     inkscape:randomized="0"
 | 
			
		||||
     d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z" />
 | 
			
		||||
  <path
 | 
			
		||||
     sodipodi:nodetypes="cccc"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     id="path4615-5"
 | 
			
		||||
     d="m 171.82574,65.174193 16.34854,0 -8.17427,-13.348454 z"
 | 
			
		||||
     style="fill:#fbb917;fill-opacity:1;fill-rule:evenodd;stroke:#fbb917;stroke-width:1.65161395;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
     d="m 179,55 0,6 2,0 0,-6"
 | 
			
		||||
     id="path4300"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccc" />
 | 
			
		||||
  <path
 | 
			
		||||
     style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
 | 
			
		||||
     d="m 179,62 0,2 2,0 0,-2"
 | 
			
		||||
     id="path4300-6"
 | 
			
		||||
     inkscape:connector-curvature="0"
 | 
			
		||||
     sodipodi:nodetypes="cccc" />
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 35 KiB  | 
							
								
								
									
										2
									
								
								public/css/jquery.datetimepicker.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								public/css/jquery.datetimepicker.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/jquery.datetimepicker.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/jquery.datetimepicker.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/jsoneditor.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/jsoneditor.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/css/lightbox.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								public/css/lightbox.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
body:after{content:url(../images/close.png) url(../images/loading.gif) url(../images/prev.png) url(../images/next.png);display:none}body.lb-disable-scrolling{overflow:hidden}.lightboxOverlay{position:absolute;top:0;left:0;z-index:9999;background-color:#000;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=80);opacity:.8;display:none}.lightbox{position:absolute;left:0;width:100%;z-index:10000;text-align:center;line-height:0;font-weight:400}.lightbox .lb-image{display:block;height:auto;max-width:inherit;border-radius:3px}.lightbox a img{border:none}.lb-outerContainer{position:relative;background-color:#fff;*zoom:1;width:250px;height:250px;margin:0 auto;border-radius:4px}.lb-outerContainer:after{content:"";display:table;clear:both}.lb-container{padding:4px}.lb-loader{position:absolute;top:43%;left:0;height:25%;width:100%;text-align:center;line-height:0}.lb-cancel{display:block;width:32px;height:32px;margin:0 auto;background:url(../images/loading.gif) no-repeat}.lb-nav{position:absolute;top:0;left:0;height:100%;width:100%;z-index:10}.lb-container>.nav{left:0}.lb-nav a{outline:none;background-image:url('data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==')}.lb-next,.lb-prev{height:100%;cursor:pointer;display:block}.lb-nav a.lb-prev{width:34%;left:0;float:left;background:url(../images/prev.png) left 48% no-repeat;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-prev:hover{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}.lb-nav a.lb-next{width:64%;right:0;float:right;background:url(../images/next.png) right 48% no-repeat;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;-webkit-transition:opacity .6s;transition:opacity .6s}.lb-nav a.lb-next:hover{filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}.lb-dataContainer{margin:0 auto;padding-top:5px;*zoom:1;width:100%;border-bottom-left-radius:4px;border-bottom-right-radius:4px}.lb-dataContainer:after{content:"";display:table;clear:both}.lb-data{padding:0 4px;color:#ccc}.lb-data .lb-details{width:85%;float:left;text-align:left;line-height:1.1em}.lb-data .lb-caption{font-size:13px;font-weight:700;line-height:1em}.lb-data .lb-number{display:block;clear:left;padding-bottom:1em;font-size:12px;color:#999}.lb-data .lb-close{display:block;float:right;width:30px;height:30px;background:url(../images/close.png) 100% 0 no-repeat;text-align:right;outline:none;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=70);opacity:.7;-webkit-transition:opacity .2s;transition:opacity .2s}.lb-data .lb-close:hover{cursor:pointer;filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}
 | 
			
		||||
/*# sourceMappingURL=lightbox.min.css.map */
 | 
			
		||||
							
								
								
									
										1
									
								
								public/css/lightbox.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/lightbox.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										6
									
								
								public/css/quill.snow.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								public/css/quill.snow.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/quill.snow.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/quill.snow.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								public/css/style.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								public/css/style.min.css
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1
									
								
								public/css/style.min.css.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								public/css/style.min.css.map
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user