<?php

namespace Nauvalazhar\FacadePlease\Commands;

use Illuminate\Console\Command;
use Artisan;

class FacadePleaseDiag extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'facade:diag {name} {--methods} {--private} {--public}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Laravel 5 Facade Generator';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $this->path = "\\";
        } else {
            $this->path = "/";
        }
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $m_option = $this->option('methods');
        $pr_option = $this->option('private');
        $pb_option = $this->option('public');
        $name = $this->argument('name');
        $path = app_path(config('facadeplease.namespace') . $this->path . $name . 'ClassFacade.php');
        if(!file_exists($path)) {
            $this->error("\n    Whoopps! Facade couldn't be found, sorry.\n");
            $this->info("\n    Suggest:\n");
            $this->info("    'php artisan facade:list' to see the list of facades\n\n");
            exit();
        }
        $get_content = file_get_contents($path);
        $get_content = trim($get_content);
        $class = new \ReflectionClass("App\\" . config("facadeplease.namespace") . "\\" . $name . "ClassFacade");
        $methods = $class->getMethods(\ReflectionMethod::IS_PUBLIC);
        $private = $class->getMethods(\ReflectionMethod::IS_PRIVATE);
        $_m = "";
        if(!$m_option) {
            $this->info("\n" . $name . ' Facade Diagnosis:');
            $this->info("");
            $this->info('Facade Name     : ' . $name);
            $this->info('Class Name      : ' . $name . "ClassFacade");
            $this->info('Path            : ' . $path);
            $this->info('Public Methods  : ' . count($methods));
            $this->info('Private Methods : ' . count($private));
        }
        if((!$pb_option && !$pr_option) || ($pb_option && !$pr_option) || ($pb_option && $pr_option)) {
            $this->info("\nPublic Methods:\n");
            foreach($methods as $item) {
                $_m .= "=> " . $item->name . "\n";
            }
        }
        $this->info($_m);
        $_p = "";
        if((!$pb_option && !$pr_option) || (!$pb_option && $pr_option) || ($pb_option && $pr_option)) {
            $this->info("Private Methods:\n");
            foreach($private as $item1) {
                $_p .= "=> " . $item1->name . "\n";
            }
        }

        $this->info($_p);
    }
}


<?php

namespace Nauvalazhar\FacadePlease\Commands;

use Illuminate\Console\Command;
use Artisan;

class FacadePlease extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'facade {argument?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Laravel 5 Facade Generator';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $arg = $this->argument('argument');
        if(!$arg || $arg == 'about') {
            $this->info("\nWelcome to Laravel 5 Facade Generator!\n
Here you can create your own facade easily, just one command and your facade is ready to use.\n
Usage:
php artisan facade usage

Credits:
=> @nauvalazhar
=> @rizalio\n
Thanks for using this package.
");
        }else if($arg == 'version') {
            $this->info('Version 0.2.0');
        }else if($arg == 'usage') {
            $this->info("
Create | Create a new facade
------
php artisan facade:please MyFacade

Delete | Delete facade
------
php artisan facade:delete MyFacade

List | List all facades
----
php artisan facade:list

Diagnosis | Get facade information
---------
php artisan facade:diag MyFacade [--methods] [--public] [--private]

More info
---------
GitHub: https://github.com/nauvalazhar/facade-please

");
        }else{
            $this->info('Command "' . $arg . '" is undefined!');
            $this->info("\nUsage:
php artisan facade usage\n");
        }
    }
}


<?php

namespace kato\behaviors;

use kato\modules\tag\models\Tag;
use yii\base\Behavior;
use yii\db\ActiveRecord;

class NormalizeTags extends Behavior
{

    /**
     * @var string attribute
     */
    public $attribute = "tags";

    public $updateTags = false;
    private $oldTags = null;
    public $tagType = null;

    /**
     * @inheritdoc
     */
    public function events()
    {
        $return = [];
        $return[ActiveRecord::EVENT_BEFORE_VALIDATE] = 'normalize';
        if ($this->updateTags === true) {
            $return[ActiveRecord::EVENT_AFTER_FIND] = 'duplicateTags';
            $return[ActiveRecord::EVENT_AFTER_UPDATE] = 'updateTags';
        }

        return $return;
    }

    /**
     * Normalizes the user-entered tags.
     */
    public function normalize()
    {
        if (!empty($this->owner->{$this->attribute})) {
            $this->owner->{$this->attribute} = $this->array2string(array_unique($this->string2array($this->owner->{$this->attribute})));
        }
    }

    public function updateTags()
    {
        $oldTags = $this->string2array($this->oldTags);
        $newTags = $this->string2array($this->owner->{$this->attribute});

        Tag::addTags(array_values(array_diff($newTags,$oldTags)), $this->tagType);
        Tag::removeTags(array_values(array_diff($oldTags,$newTags)), $this->tagType);
    }

    public function duplicateTags()
    {
        if (!empty($this->owner->{$this->attribute})) {
            $this->oldTags = $this->owner->{$this->attribute};
        }
    }

    private function string2array($tags)
    {
        return preg_split('/\s*,\s*/',trim($tags),-1,PREG_SPLIT_NO_EMPTY);
    }

    private function array2string($tags)
    {
        return implode(', ',$tags);
    }
}


<?php

namespace BugBuster\BeUserOnlineBundle\EventListener;

use Contao\FrontendUser;
use Contao\BackendUser;
use Contao\User;

class UserAuthenticateListener
{
    /**
     * @var ContaoFrameworkInterface
     */
    private $framework;

    /**
     * Authentication hash
     * @var string
     */
    protected $strHash;

    public function __construct()
    {

    }

    /**
     * onSetUserAuthenticate
     *
     * @return array                Add your custom modules to the list and return the array of back end modules.
     */
    public function onSetUserAuthenticate(User $user)
    {
        $intUserId = $user->getData()['id']; // for user id, ugly, but I don't know what's better.

        $strHash = '';
        $time = time();

        if ($user instanceof FrontendUser)
        {
            $strCookie = 'FE_USER_AUTH';
        }

        if ($user instanceof BackendUser)
        {
            $strCookie = 'BE_USER_AUTH';
        }

        // Generate the cookie hash
        $token = $_COOKIE["csrf_contao_csrf_token"];
        $strHash = sha1($token.$strCookie);

        // Update session
        \Database::getInstance()->prepare("UPDATE tl_beuseronline_session SET tstamp=$time WHERE pid=? AND hash=?")
                                ->execute($intUserId, $strHash);

        //use app_dev.php to dump
        //dump from Symfony\Component\VarDumper\VarDumper
        //dump($arrModules['content']['modules']);

    }
}


<?php

declare(strict_types=1);

namespace Mapado\RestClientSdk\Helper;

/**
 * Some array helpers.
 * Greatly inspired by Laravel's helper: https://github.com/rappasoft/laravel-helpers
 *
 * @author Julien Deniau <julien.deniau@mapado.com>
 */
class ArrayHelper
{
    /**
     * Get an item from an array using "dot" notation.
     *
     * @param  mixed   $default
     *
     * @return mixed
     */
    public static function arrayGet(
        array $array,
        ?string $key,
        $default = null
    ) {
        if (null === $key) {
            return $array;
        }

        if (isset($array[$key])) {
            return $array[$key];
        }

        foreach (explode('.', $key) as $segment) {
            if (!is_array($array) || !array_key_exists($segment, $array)) {
                return self::value($default);
            }
            $array = $array[$segment];
        }

        return $array;
    }

    /**
     * Check if an item exists in an array using "dot" notation.
     */
    public static function arrayHas(array $array, ?string $key): bool
    {
        if (empty($array) || null === $key) {
            return false;
        }

        if (array_key_exists($key, $array)) {
            return true;
        }

        foreach (explode('.', $key) as $segment) {
            if (!is_array($array) || !array_key_exists($segment, $array)) {
                return false;
            }

            $array = $array[$segment];
        }

        return true;
    }

    /**
     * Flatten a multi-dimensional associative array with dots.
     */
    public static function arrayDot(array $array, string $prepend = ''): array
    {
        $results = [];
        foreach ($array as $key => $value) {
            if (is_array($value) && !empty($value)) {
                $results = array_merge(
                    $results,
                    static::arrayDot($value, $prepend . $key . '.')
                );
            } else {
                $results[$prepend . $key] = $value;
            }
        }

        return $results;
    }

    public static function arrayDiffAssocRecursive(
        array $array1,
        array $array2
    ): array {
        return array_diff_assoc(
            static::arrayDot($array1),
            static::arrayDot($array2)
        );
    }

    public static function arraySame(array $array1, array $array2): bool
    {
        return empty(static::arrayDiffAssocRecursive($array1, $array2));
    }

    /**
     * Return the default value of the given value.
     *
     * @param  mixed  $value
     *
     * @return mixed
     */
    public static function value($value)
    {
        return $value instanceof \Closure ? $value() : $value;
    }
}


<?php

namespace kato\behaviors;

use yii\base\Behavior;
use yii\base\Event;
use yii\db\ActiveRecord;

/**
 * SoftDelete

 * Usage:
 *
 * ~~~
 * public function behaviors() {
 *     return [
 *         'softDelete' => ['class' => 'kato\behaviors\SoftDelete',
 *             'attribute' => 'deleted',
 *             'safeMode' => true,
 *         ],
 *     ];
 * }
 * ~~~
 * Call functions
 * soft-delete model
 * $model->remove();
 *
 * restore model
 * $model->restore();
 *
 * delete model from db
 * $model->forceDelete();
 *
 * soft-delete model if $safeMode = true
 * delete model from db if $safeMode = false
 * $model->delete();
 */
class SoftDelete extends Behavior {

    const IS_DELETED = 1;
    const NOT_DELETED = 0;

    /**
     * @var string SoftDelete attribute
     */
    public $attribute = "deleted";

    /**
     * @var bool If true, this behavior will process '$model->delete()' as a soft-delete. Thus, the
     *           only way to truely delete a record is to call '$model->forceDelete()'
     */
    public $safeMode = true;

    /**
     * @inheritdoc
     */
    public function events() {
        return [ActiveRecord::EVENT_BEFORE_DELETE => 'doDelete'];
    }

    /**
     * Set the attribute with the current timestamp to mark as deleted
     *
     * @param Event $event
     */
    public function doDelete($event) {

        // do nothing if safeMode is disabled. this will result in a normal deletion
        if (!$this->safeMode) {
            return;
        }

        // remove and mark as invalid to prevent real deletion
        $this->remove();
        $event->isValid = false;
    }

    /**
     * Remove (aka soft-delete) record
     */
    public function remove() {

        // evaluate timestamp and set attribute
        //$timestamp = $this->evaluateTimestamp();
        $attribute = $this->attribute;
        $this->owner->$attribute = self::IS_DELETED;

        // save record
        $this->owner->save(false, [$attribute]);
    }

    /**
     * Restore soft-deleted record
     */
    public function restore() {

        // mark attribute as null
        $attribute = $this->attribute;
        $this->owner->$attribute = self::NOT_DELETED;

        // save record
        $this->owner->save(false, [$attribute]);
    }

    /**
     * Delete record from database regardless of the $safeMode attribute
     */
    public function forceDelete() {

        // store model so that we can detach the behavior and delete as normal
        $model = $this->owner;
        $this->detach();
        $model->delete();
    }
}


<?php

namespace KevinEm\WePay\Laravel\Providers;

use Illuminate\Support\ServiceProvider;
use KevinEm\WePay\Laravel\WePayLaravel;

class WePayServiceProvider extends ServiceProvider
{

    /**
     * Perform post-registration booting of services.
     *
     * @return void
     */
    public function boot()
    {
        $config = $this->app['path.config'] . '/wepay.php';

        $this->publishes([
            __DIR__ . '/../config.php' => $config
        ]);
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        $this->mergeConfigFrom(__DIR__ . '/../config.php', 'wepay');

        $this->app->bind('wepay', function ($app) {
            return new WePayLaravel($app['config']['wepay']);
        });
    }
}


<?php

declare(strict_types=1);

namespace Mapado\RestClientSdk\Collection;

use ArrayIterator;

/**
 * Class Collection
 *
 * @author Florent Clerc <florent.clerc@mapado.com>
 */
class Collection implements \IteratorAggregate, \Serializable, \Countable, \ArrayAccess
{
    /**
     * The elements of the collection.
     *
     * @var array
     */
    private $elements;

    /**
     * extra properties that are not the main list but linked data
     * It can be "_embed" or "_links" for HAL response
     * or "hydra:totalItems" for JSON-LD
     * or anything you want to really ("foo" is OK for exemple)
     *
     * @var array
     */
    private $extraProperties;

    /**
     * @param array $elements the data elements as an array
     * @param array $extraProperties the extra properties
     */
    public function __construct(
        array $elements = [],
        array $extraProperties = []
    ) {
        $this->elements = $elements;
        $this->extraProperties = $extraProperties;
    }

    /**
     * Returns inner elements collection.
     */
    public function toArray(): array
    {
        return $this->elements;
    }

    /**
     * {@inheritdoc}
     */
    public function serialize()
    {
        return serialize($this->elements);
    }

    /**
     * {@inheritdoc}
     */
    public function unserialize($values)
    {
        $this->elements = unserialize($values);
    }

    /**
     * {@inheritdoc}
     */
    public function count()
    {
        return count($this->elements);
    }

    /**
     * Returns element count in collection.
     */
    public function getTotalItems(): int
    {
        return $this->count();
    }

    /**
     * {@inheritdoc}
     */
    public function offsetSet($offset, $value)
    {
        if (null === $offset) {
            $this->elements[] = $value;
        } else {
            $this->elements[$offset] = $value;
        }
    }

    /**
     * {@inheritdoc}
     */
    public function offsetExists($offset)
    {
        return isset($this->elements[$offset]);
    }

    /**
     * {@inheritdoc}
     */
    public function offsetUnset($offset)
    {
        unset($this->elements[$offset]);
    }

    /**
     * {@inheritdoc}
     */
    public function offsetGet($offset)
    {
        return isset($this->elements[$offset])
            ? $this->elements[$offset]
            : null;
    }

    /**
     * {@inheritdoc}
     */
    public function getIterator(): ArrayIterator
    {
        return new ArrayIterator($this->elements);
    }

    /**
     * getExtraProperties
     */
    public function getExtraProperties(): array
    {
        return $this->extraProperties;
    }

    /**
     * return the value of an extra property
     *
     * @return mixed
     */
    public function getExtraProperty(string $key)
    {
        if (isset($this->extraProperties[$key])) {
            return $this->extraProperties[$key];
        }
    }
}


<?php

namespace kato\helpers;

class KatoBase extends \yii\base\Object
{
    /**
     * delete directory recursivly
     */
    public static function deleteDirectory($dir, $keepDir=false) {
        if (!file_exists($dir)) return true;
        if (!is_dir($dir)) return unlink($dir);
        foreach (scandir($dir) as $item) {
            if ($item == '.' || $item == '..') continue;
            if (!deleteDirectory($dir.DIRECTORY_SEPARATOR.$item)) return false;
        }
        if($keepDir)
            return true;
        else
            return rmdir($dir);
    }

    /**
     * merges new Get into current url
     * use it as: url("/model/action", mergeGet($_GET, 'limit', '50'));
     */
    public static function mergeGet($get, $key, $value) {
        if (array_key_exists($key, $get)) {
            $get[$key]=$value;
        }
        $array = array_merge(array($key => $value), $get);

        return $array;
    }

    /**
     * gets the data from a URL
     * Usage: $returned_content = get_data('http://davidwalsh.name');
     * Alternatively, you can use the file_get_contents function remotely, but many hosts don't allow this.
     */
    public static function get_data($url) {
        $ch = curl_init();
        $timeout = 5;
        //For your script we can also add a User Agent:
        $userAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)";

        curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);

        curl_setopt($ch, CURLOPT_FAILONERROR, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_AUTOREFERER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }

    /**
     * Creates random string
     * default lenght is 8
     */
    public static function genRandomString($length=8) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

        $size = strlen( $chars );
        $str='';
        for( $i = 0; $i < $length; $i++ ) {
            $str .= $chars[ rand( 0, $size - 1 ) ];
        }

        return $str;
    }

    /**
     * returns array containing: lat, lng, postcode
     * Usage: pass in postcode
     * @param $postcode
     * @param bool $r
     * @return array|bool|mixed
     */
    public static function getPostcodeData($postcode, $r = false) {
        $trim_postcode = str_replace(' ', '', preg_replace("/[^a-zA-Z0-9\s]/", "", strtolower($postcode)));

        $q_center = "http://maps.googleapis.com/maps/api/geocode/json?address=" . $trim_postcode . "&sensor=false&region=gb";
        $json_center = file_get_contents($q_center);
        $details_center = json_decode($json_center, TRUE);

        if($details_center['status']=='OVER_QUERY_LIMIT') return false;

        if ($r) return $details_center;

        if (isset($details_center['results']) && isset($details_center['results'][0])) {

            $center_lat=null;
            $center_lng=null;
            if (isset($details_center['results'][0]['geometry']['location'])) {
                $center_lat = $details_center['results'][0]['geometry']['location']['lat'];
                $center_lng = $details_center['results'][0]['geometry']['location']['lng'];
            }

            $boundsNE=null;
            $boundsSW=null;
            if (isset($details_center['results'][0]['geometry']['bounds'])) {
                $boundsNE = $details_center['results'][0]['geometry']['bounds']['northeast'];
                $boundsSW = $details_center['results'][0]['geometry']['bounds']['southwest'];
            }

            $status = isset($details_center['results'][0]['status']) ? $details_center['results'][0]['status']: '';
            $types = isset($details_center['results'][0]['types']) ? $details_center['results'][0]['types'] : '' ;

            return array(
                'postcode' => $trim_postcode,
                'lat' => $center_lat,
                'lng' => $center_lng,
                'NE' => $boundsNE,
                'SW' => $boundsSW,
                'status' => $status,
                'types' => $types
            );

        } else {

            return false;

        }
    }

    /**
     * Helper function to limit the words in a string
     *
     * @param string $string the given string
     * @param int $word_limit the number of words to limit to
     * @return string the limited string
     */

    public static function limit_words($string, $word_limit)
    {
        $words = explode(' ',$string);
        return trim(implode(' ', array_splice($words, 0, $word_limit))) .'...';
    }

    /**
     * Helper function to recusively get all files in a directory
     *
     * @param string $directory start directory
     * @param string $ext optional limit to file extensions
     * @return array the matched files
     */
    public static function get_files($directory, $ext = '')
    {
        $array_items = array();
        if($handle = opendir($directory)){
            while(false !== ($file = readdir($handle))){
                if($file != "." && $file != ".."){
                    if(is_dir($directory. "/" . $file)){
                        $array_items = array_merge($array_items, self::get_files($directory. "/" . $file, $ext));
                    } else {
                        $file = $directory . "/" . $file;
                        if(!$ext || strstr($file, $ext)) $array_items[] = preg_replace("/\/\//si", "/", $file);
                    }
                }
            }
            closedir($handle);
        }
        return $array_items;
    }

    /**
     * Strip tags and limit description
     * @param $content
     * @param string $tag
     * @param int $wordLimit
     * @return string
     */
    public static function genShortDesc($content, $tag = 'p' , $wordLimit = 20)
    {
        if (preg_match('%(<' . $tag . '[^>]*>.*?</' . $tag . '>)%i', $content, $regs)) {
            $result = $regs[1];
        } else {
            $result = "";
        }

        return self::limit_words(strip_tags($result), $wordLimit);
    }

    /**
     * Returns a sanitized string, typically for URLs.
     *
     * Parameters:
     *     $string - The string to sanitize.
     *     $force_lowercase - Force the string to lowercase?
     *     $anal - If set to *true*, will remove all non-alphanumeric characters.
     */

    public static function sanitizeFile($string, $force_lowercase = true, $anal = false) {
        $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
            "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—",
            "â€”", "â€“", ",", "<", ".", ">", "/", "?");
        $clean = trim(str_replace($strip, "", strip_tags($string)));
        $clean = preg_replace('/\s+/', "-", $clean);
        $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ;
        return ($force_lowercase) ?
            (function_exists('mb_strtolower')) ?
                mb_strtolower($clean, 'UTF-8') :
                strtolower($clean) :
            $clean;
    }

    /**
     * PHP byteFormat function for formatting bytes
     * Function takes three parameter: (bytes mandatory, unit optional, decimals optional)
     *
     * @param $bytes
     * @param string $unit
     * @param int $decimals
     * @param null $numberOnly
     * @return string
     */
    public static function formatBytes($bytes, $unit = "", $decimals = 2, $numberOnly = null) {
        $units = array('B' => 0, 'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4,
            'PB' => 5, 'EB' => 6, 'ZB' => 7, 'YB' => 8);

        $value = 0;
        if ($bytes > 0) {
            // Generate automatic prefix by bytes
            // If wrong prefix given
            if (!array_key_exists($unit, $units)) {
                $pow = floor(log($bytes)/log(1024));
                $unit = array_search($pow, $units);
            }

            // Calculate byte value by prefix
            $value = ($bytes/pow(1024,floor($units[$unit])));
        }

        // If decimals is not numeric or decimals is less than 0
        // then set default value
        if (!is_numeric($decimals) || $decimals < 0) {
            $decimals = 2;
        }

        // Format output
        if (is_null($numberOnly)) {
            return sprintf('%.' . $decimals . 'f '.$unit, $value);
        } else {
            return sprintf('%.' . $decimals . 'f ', $value);
        }
    }
}


<?php

namespace VM\TimeOverlapCalculator;

use VM\TimeOverlapCalculator\Entity\TimeSlotInterface;
use VM\TimeOverlapCalculator\Generator\TimeSlotGeneratorInterface;

class TimeOverlapCalculator
{
    const TIME_UNIT_SECOND = 1;
    const TIME_UNIT_MINUTE = 60;
    const TIME_UNIT_HOUR = 60 * 60;
    const TIME_UNIT_DAY = 60 * 60 * 24;

    /**
     * Check if given time slots overlap
     *
     * @param TimeSlotInterface $baseTimeSlot
     * @param TimeSlotInterface $overlappingTimeSlot
     *
     * @return bool
     */
    public function isOverlap(TimeSlotInterface $baseTimeSlot, TimeSlotInterface $overlappingTimeSlot)
    {
        return $baseTimeSlot->getStart() < $overlappingTimeSlot->getEnd()
               && $overlappingTimeSlot->getStart() < $baseTimeSlot->getEnd();
    }

    /**
     * Calculate size of overlap and convert into given time unit (seconds, minutes, hours, days)
     *
     * @param TimeSlotInterface $baseTimeSlot
     * @param TimeSlotInterface $overlappingTimeSlot
     * @param int               $timeUnit            self::TIME_UNIT_SECOND by default
     *
     * @return float
     */
    public function calculateOverlap(
        TimeSlotInterface $baseTimeSlot,
        TimeSlotInterface $overlappingTimeSlot,
        $timeUnit = self::TIME_UNIT_SECOND
    ) {
        $overlapSize = 0;

        if ($this->isOverlap($baseTimeSlot, $overlappingTimeSlot)) {
            $overlapStart = ($baseTimeSlot->getStart() < $overlappingTimeSlot->getStart())
                ? $overlappingTimeSlot->getStart()
                : $baseTimeSlot->getStart();

            $overlapEnd = $baseTimeSlot->getEnd() > $overlappingTimeSlot->getEnd()
                ? $overlappingTimeSlot->getEnd()
                : $baseTimeSlot->getEnd();

            $overlapSize = $overlapEnd->getTimestamp() - $overlapStart->getTimestamp();
        }

        return $overlapSize / $timeUnit;
    }

    /**
     * Create an array of non overlapped time slots
     *
     * @param TimeSlotInterface          $baseTimeSlot
     * @param TimeSlotInterface[]        $overlappingTimeSlots
     * @param TimeSlotGeneratorInterface $timeSlotGenerator
     *
     * @return TimeSlotInterface[]
     */
    public function getNonOverlappedTimeSlots(
        TimeSlotInterface $baseTimeSlot,
        array $overlappingTimeSlots,
        TimeSlotGeneratorInterface $timeSlotGenerator
    ) {
        $baseTimeSlots = [
            $timeSlotGenerator->createTimeSlot($baseTimeSlot->getStart(), $baseTimeSlot->getEnd()),
        ];

        foreach ($overlappingTimeSlots as $overlappingTimeSlot) {
            $freeTimeSlots = [];
            foreach ($baseTimeSlots as $timeSlot) {
                $freeTimeSlots =  array_merge(
                    $freeTimeSlots,
                    $this->fetchNonOverlappedTimeSlots($timeSlot, $overlappingTimeSlot, $timeSlotGenerator)
                );
            }

            $baseTimeSlots = $freeTimeSlots;
        }

        return $baseTimeSlots;
    }

    /**
     * Merge all overlapped time slots into single time slot
     *
     * @param TimeSlotGeneratorInterface $timeSlotGenerator
     * @param TimeSlotInterface[]        $timeSlots
     *
     * @return TimeSlotInterface[]
     */
    public function mergeOverlappedTimeSlots(TimeSlotGeneratorInterface $timeSlotGenerator, array $timeSlots)
    {
        if (empty($timeSlots)) {
            return [];
        }

        $timeSlots = $this->sortTimeSlotsByStartTime($timeSlots);
        $mergedTimeSlots = [
            $timeSlotGenerator->createTimeSlot($timeSlots[0]->getStart(), $timeSlots[0]->getEnd()),
        ];
        $headIndex = 0;

        foreach ($timeSlots as $timeSlot) {
            $headTimeSlot = $mergedTimeSlots[$headIndex];

            if ($timeSlot->getStart() > $headTimeSlot->getEnd()) {
                $mergedTimeSlots[] = $timeSlotGenerator->createTimeSlot(
                    $timeSlot->getStart(),
                    $timeSlot->getEnd()
                );
                $headIndex ++;
            } elseif ($headTimeSlot->getEnd() < $timeSlot->getEnd()) {
                $mergedTimeSlots[$headIndex] = $timeSlotGenerator->createTimeSlot(
                    $headTimeSlot->getStart(),
                    $timeSlot->getEnd()
                );
            }
        }

        return $mergedTimeSlots;
    }

    /**
     * @param TimeSlotInterface          $baseTimeSlot
     * @param TimeSlotInterface          $overlappingTimeSlot
     * @param TimeSlotGeneratorInterface $timeSlotGenerator
     *
     * @return array
     */
    private function fetchNonOverlappedTimeSlots(
        TimeSlotInterface $baseTimeSlot,
        TimeSlotInterface $overlappingTimeSlot,
        TimeSlotGeneratorInterface $timeSlotGenerator
    ) {
        $freeTimeSlots = [];

        if ($this->isOverlap($baseTimeSlot, $overlappingTimeSlot)) {
            if ($overlappingTimeSlot->getStart() > $baseTimeSlot->getStart()
                && $overlappingTimeSlot->getStart() < $baseTimeSlot->getEnd()
            ) {
                $freeTimeSlots[] = $timeSlotGenerator->createTimeSlot(
                    clone $baseTimeSlot->getStart(),
                    clone $overlappingTimeSlot->getStart()
                );
            }

            if ($overlappingTimeSlot->getEnd() > $baseTimeSlot->getStart()
                && $overlappingTimeSlot->getEnd() < $baseTimeSlot->getEnd()
            ) {
                $freeTimeSlots[] = $timeSlotGenerator->createTimeSlot(
                    clone $overlappingTimeSlot->getEnd(),
                    clone $baseTimeSlot->getEnd()
                );
            }
        } else {
            $freeTimeSlots[] = $timeSlotGenerator->createTimeSlot(
                clone $baseTimeSlot->getStart(),
                clone $baseTimeSlot->getEnd()
            );
        }

        return $freeTimeSlots;
    }

    /**
     * @param TimeSlotInterface[] $timeSlots
     *
     * @return TimeSlotInterface[]
     */
    private function sortTimeSlotsByStartTime(array $timeSlots)
    {
        usort($timeSlots, function($a, $b) {
           if ($a->getStart() < $b->getStart()) {
               return -1;
           }

            if ($a->getStart() > $b->getStart()) {
                return 1;
            }

            return 0;
        });

        return $timeSlots;
    }
}


<?php

namespace Nauvalazhar\FacadePlease\Commands;

use Illuminate\Console\Command;
use Artisan;

class FacadePleaseList extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'facade:list';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Laravel 5 Facade Generator';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
            $this->path = "\\";
        } else {
            $this->path = "/";
        }
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $path = app_path(config('facadeplease.namespace'));
        $files = scandir($path);
        $files = array_diff(scandir($path), array('.', '..'));
        $_f = "";
        $this->info("\nFacade contained in the 'app/".config('facadeplease.namespace')."' folder:");
        foreach($files as $item) {
            if(strpos($item, "Class")) {
                $_f .= "=> " . str_replace("ClassFacade.php", "", $item) ."\n";
            }
        }
        $this->info($_f);
        $this->info("[NOTE] To see all facade methods, you can use the command 'php artisan facade:diag FacadeName'\n");
    }
}


<?php

// Prince - PHP interface
// Copyright 2005-2016 YesLogic Pty. Ltd.
// http://www.princexml.com

class Prince
{
    private $exePath;
    private $styleSheets;
    private $scripts;
    private $fileAttachments;
    private $licenseFile;
    private $licenseKey;
    private $inputType;
    private $javascript;
    private $baseURL;
    private $doXInclude;
    private $xmlExternalEntities;
    private $noLocalFiles;
    private $remaps;
    private $noNetwork;
    private $authUser;
    private $authPassword;
    private $authServer;
    private $authScheme;
    private $authMethod;
    private $noAuthPreemptive;
    private $httpProxy;
    private $httpTimeout;
    private $cookie;
    private $cookieJar;
    private $sslCaCert;
    private $sslCaPath;
    private $sslVersion;
    private $insecure;
    private $noParallelDownloads;
    private $logFile;
    private $verbose;
    private $debug;
    private $noWarnCss;
    private $fileRoot;
    private $embedFonts;
    private $subsetFonts;
    private $noArtificialFonts;
    private $forceIdentityEncoding;
    private $compress;
    private $pdfOutputIntent;
    private $convertColors;
    private $fallbackCmykProfile;
    private $pdfProfile;
    private $pdfTitle;
    private $pdfSubject;
    private $pdfAuthor;
    private $pdfKeywords;
    private $pdfCreator;
    private $media;
    private $pageSize;
    private $pageMargin;
    private $noAuthorStyle;
    private $noDefaultStyle;
    private $encrypt;
    private $encryptInfo;
    private $options;

    public function __construct($exePath)
    {
        $this->exePath = $exePath;
        $this->styleSheets = '';
        $this->scripts = '';
        $this->fileAttachments = '';
        $this->licenseFile = '';
        $this->licenseKey = '';
        $this->inputType = 'auto';
        $this->javascript = false;
        $this->baseURL = '';
        $this->doXInclude = false;
        $this->xmlExternalEntities = false;
        $this->noLocalFiles = false;
        $this->remaps = '';
        $this->noNetwork = false;
        $this->authUser = '';
        $this->authPassword = '';
        $this->authServer = '';
        $this->authScheme = '';
        $this->authMethod = '';
        $this->noAuthPreemptive = false;
        $this->httpProxy = '';
        $this->httpTimeout = '';
        $this->cookie = '';
        $this->cookieJar = '';
        $this->sslCaCert = '';
        $this->sslCaPath = '';
        $this->sslVersion = '';
        $this->insecure = false;
        $this->noParallelDownloads = false;
        $this->logFile = '';
        $this->verbose = false;
        $this->debug = false;
        $this->noWarnCss = false;
        $this->fileRoot = '';
        $this->embedFonts = true;
        $this->subsetFonts = true;
        $this->noArtificialFonts = false;
        $this->forceIdentityEncoding = false;
        $this->compress = true;
        $this->pdfOutputIntent = '';
        $this->convertColors = false;
        $this->fallbackCmykProfile = '';
        $this->pdfProfile = '';
        $this->pdfTitle = '';
        $this->pdfSubject = '';
        $this->pdfAuthor = '';
        $this->pdfKeywords = '';
        $this->pdfCreator = '';
        $this->media = '';
        $this->pageSize = '';
        $this->pageMargin = '';
        $this->noAuthorStyle = false;
        $this->noDefaultStyle = false;
        $this->encrypt = false;
        $this->encryptInfo = '';
        $this->options = '';
    }

    // Add a CSS style sheet that will be applied to each document.
    // cssPath: The filename of the CSS style sheet.
    public function addStyleSheet($cssPath)
    {
        $this->styleSheets .= '-s "' . $cssPath . '" ';
    }

    // Clear all of the CSS style sheets.
    public function clearStyleSheets()
    {
        $this->styleSheets = '';
    }

    // Add a JavaScript script that will be run before conversion.
    // jsPath: The filename of the script.
    public function addScript($jsPath)
    {
        $this->scripts .= '--script "' . $jsPath . '" ';
    }

    // Clear all of the scripts.
    public function clearScripts()
    {
        $this->scripts = '';
    }

    //Add a file attachment that will be attached to the PDF file
    //filePath: The filename of the file attachment.
    public function addFileAttachment($filePath)
    {
        $this->fileAttachments .= '--attach=' . '"' . $filePath .  '" ';
    }

    //Clear all of the file attachments.
    public function clearFileAttachments()
    {
        $this->fileAttachments = '';
    }

    //Specify the license file.
    //file: The filename of the license file.
    public function setLicenseFile($file)
    {
        $this->licenseFile = $file;
    }

    //Specify the license key.
    //key: The license key
    public function setLicenseKey($key)
    {
        $this->licenseKey = $key;
    }

    //Specify the input type of the document.
    //inputType: Can take a value of : "xml", "html" or "auto".
    public function setInputType($inputType)
    {
        $this->inputType = $inputType;
    }

    // Specify whether JavaScript found in documents should be run.
    // js: True if document scripts should be run.
    public function setJavaScript($js)
    {
        $this->javascript = $js;
    }

    // Specify whether documents should be parsed as HTML or XML/XHTML.
    // html: True if all documents should be treated as HTML.
    public function setHTML($html)
    {
        if($html)
        {
            $this->inputType = "html";
        }
        else
        {
            $this->inputType = "xml";
        }
    }

    // Specify a file that Prince should use to log error/warning messages.
    // logFile: The filename that Prince should use to log error/warning
    //      messages, or '' to disable logging.
    public function setLog($logFile)
    {
        $this->logFile = $logFile;
    }

    //Specify whether to log informative messages.
    public function setVerbose($verbose)
    {
        $this->verbose = $verbose;
    }

    //Specify whether to log debug messages.
    public function setDebug($debug)
    {
        $this->debug = $debug;
    }

    //Specify whether to warn about CSS.
    public function setNoWarnCss($noWarnCss)
    {
        $this->noWarnCss = $noWarnCss;
    }

    // Specify the base URL of the input document.
    // baseURL: The base URL or path of the input document, or ''.
    public function setBaseURL($baseURL)
    {
        $this->baseURL = $baseURL;
    }

    // Specify whether XML Inclusions (XInclude) processing should be applied
    // to input documents. XInclude processing will be performed by default
    // unless explicitly disabled.
    // xinclude: False to disable XInclude processing.
    public function setXInclude($xinclude)
    {
        $this->doXInclude = $xinclude;
    }

    // Specifies whether XML external entities should be allowed to be used.
    public function setXmlExternalEntities($xmlExternalEntities)
    {
        $this->xmlExternalEntities = $xmlExternalEntities ;
    }

    //Specify whether to disable access to local files.
    public function setNoLocalFiles($noLocalFiles)
    {
        $this->noLocalFiles = $noLocalFiles;
    }

    // Add a mapping of URL prefix to a local directory.
    public function addRemap($url, $dir)
    {
        $this->remaps .= '--remap="' . $url . '"="' . $dir . '" ';
    }

    // Clear all of the remaps.
    public function clearRemaps()
    {
        $this->remaps = '';
    }

    // Specify thether to disable network access.
    public function setNoNetwork($noNetwork)
    {
        $this->noNetwork = $noNetwork;
    }

    //Specify HTTP authentication methods. (basic, digest, ntlm, negotiate)
    public function setAuthMethod($authMethod)
    {
        if(strcasecmp($authMethod, 'basic') == 0)
        {
            $this->authMethod = 'basic';
        }
        else if(strcasecmp($authMethod, 'digest') == 0)
        {
            $this->authMethod = 'digest';
        }
        else if(strcasecmp($authMethod, 'ntlm') == 0)
        {
            $this->authMethod = 'ntlm';
        }
        else if(strcasecmp($authMethod, 'negotiate') == 0)
        {
            $this->authMethod = 'negotiate';
        }
        else
        {
            $this->authMethod = '';
        }
    }

    //Specify username for HTTP authentication.
    public function setAuthUser($authUser)
    {
        $this->authUser = $this->cmdlineArgEscape($authUser);
    }

    //Specify password for HTTP authentication.
    public function setAuthPassword($authPassword)
    {
        $this->authPassword = $this->cmdlineArgEscape($authPassword);
    }

    //Only send USER:PASS to this server.
    public function setAuthServer($authServer)
    {
        $this->authServer = $authServer;
    }

    //Only send USER:PASS for this scheme. (HTTP, HTTPS)
    public function setAuthScheme($authScheme)
    {
        if(strcasecmp($authScheme, 'http') == 0)
        {
            $this->authScheme = 'http';
        }
        else if(strcasecmp($authScheme, 'https') == 0)
        {
            $this->authScheme = 'https';
        }
        else
        {
            $this->authScheme = '';
        }
    }

    //Do not authenticate with named servers until asked.
    public function setNoAuthPreemptive($noAuthPreemptive)
    {
        $this->noAuthPreemptive = $noAuthPreemptive;
    }

    //Specify the URL for the HTTP proxy server, if needed.
    //proxy: The URL for the HTTP proxy server.
    public function setHttpProxy($proxy)
    {
        $this->httpProxy = $proxy;
    }

    //Specify the HTTP timeout in seconds.
    public function setHttpTimeout($timeout)
    {
        $this->httpTimeout = $timeout;
    }

    //Specify a Set-Cookie header value.
    public function setCookie($cookie)
    {
        $this->cookie = $cookie;
    }

    //Specify a file containing HTTP cookies.
    public function setCookieJar($cookieJar)
    {
        $this->cookieJar = $cookieJar;
    }

    //Specify an SSL certificate file.
    public function setSslCaCert($sslCaCert)
    {
        $this->sslCaCert = $sslCaCert;
    }

    //Specify an SSL certificate directory.
    public function setSslCaPath($sslCaPath)
    {
        $this->sslCaPath = $sslCaPath;
    }

    //Specify an SSL/TLS version to use.
    public function setSslVersion($sslVersion)
    {
        $this->sslVersion = $sslVersion;
    }

    //Specify whether to disable SSL verification.
    //insecure: If set to true, SSL verification is disabled. (not recommended)
    public function setInsecure($insecure)
    {
        $this->insecure = $insecure;
    }

    //Specify whether to disable disable parallel downloads.
    //noParallelDownloads: If set to true, parallel downloads are disabled.
    public function setNoParallelDownloads($noParallelDownloads)
    {
        $this->noParallelDownloads = $noParallelDownloads;
    }

    //Specify the root directory for absolute filenames. This can be used
    //when converting a local file that uses absolute paths to refer to web
    //resources. For example, /images/logo.jpg can be
    //rewritten to /usr/share/images/logo.jpg by specifying "/usr/share" as the root.
    //fileRoot: The path to prepend to absolute filenames.
    public function setFileRoot($fileRoot)
    {
        $this->fileRoot = $fileRoot;
    }

    // Specify whether fonts should be embedded in the output PDF file. Fonts
    // will be embedded by default unless explicitly disabled.
    // embedFonts: False to disable PDF font embedding.
    public function setEmbedFonts($embedFonts)
    {
        $this->embedFonts = $embedFonts;
    }

    // Specify whether embedded fonts should be subset.
    // Fonts will be subset by default unless explicitly disabled.
    // subsetFonts: False to disable PDF font subsetting.
    public function setSubsetFonts($subsetFonts)
    {
        $this->subsetFonts = $subsetFonts;
    }

    // Specify whether artificial bold/italic fonts should be generated if
    // necessary. Artificial fonts are enabled by default.
    // artificialFonts: False to disable artificial bold/italic fonts.
    public function setNoArtificialFonts($noArtificialFonts)
    {
        $this->noArtificialFonts = $noArtificialFonts;
    }

    //Specify whether to use force identity encoding.
    public function setForceIdentityEncoding($forceIdentityEncoding)
    {
        $this->forceIdentityEncoding = $forceIdentityEncoding;
    }

    // Specify whether compression should be applied to the output PDF file.
    // Compression will be applied by default unless explicitly disabled.
    // compress: False to disable PDF compression.
    public function setCompress($compress)
    {
        $this->compress = $compress;
    }

    //Specify the ICC profile to use.
    //Also optionally specify whether to convert colors to output intent color space.
    //$pdfOutputIntent is the ICC profile to be used.
    public function setPDFOutputIntent($pdfOutputIntent, $convertColors = false)
    {
        $this->pdfOutputIntent = $pdfOutputIntent;
        $this->convertColors = $convertColors;
    }

    //Specify fallback ICC profile for uncalibrated CMYK.
    public function setFallbackCmykProfile($fallbackCmykProfile)
    {
        $this->fallbackCmykProfile = $fallbackCmykProfile;
    }

    //Specify the PDF profile to use.
    public function setPDFProfile($pdfProfile)
    {
        $this->pdfProfile = $pdfProfile;
    }

    // Specify the document title for PDF metadata.
    public function setPDFTitle($pdfTitle)
    {
        $this->pdfTitle = $pdfTitle;
    }

    // Specify the document subject for PDF metadata.
    public function setPDFSubject($pdfSubject)
    {
        $this->pdfSubject = $pdfSubject;
    }

    // Specify the document author for PDF metadata.
    public function setPDFAuthor($pdfAuthor)
    {
        $this->pdfAuthor = $pdfAuthor;
    }

    //Specify the document keywords for PDF metadata.
    public function setPDFKeywords($pdfKeywords)
    {
        $this->pdfKeywords = $pdfKeywords;
    }

    //Specify the document creator for PDF metadata.
    public function setPDFCreator($pdfCreator)
    {
        $this->pdfCreator = $pdfCreator;
    }

    //Specify the media type (eg. print, screen).
    public function setMedia($media)
    {
        $this->media = $media;
    }

    //Specify the page size (eg. A4).
    public function setPageSize($pageSize)
    {
        $this->pageSize = $pageSize;
    }

    //Specify the page margin (eg. 20mm).
    public function setPageMargin($pageMargin)
    {
        $this->pageMargin = $pageMargin;
    }

    //Specify whether to ignore author style sheets.
    public function setNoAuthorStyle($noAuthorStyle)
    {
        $this->noAuthorStyle = $noAuthorStyle;
    }

    //Specify whether to ignore default style sheets.
    public function setNoDefaultStyle($noDefaultStyle)
    {
        $this->noDefaultStyle = $noDefaultStyle;
    }

    // Specify whether encryption should be applied to the output PDF file.
    // Encryption will not be applied by default unless explicitly enabled.
    // encrypt: True to enable PDF encryption.
    public function setEncrypt($encrypt)
    {
        $this->encrypt = $encrypt;
    }

    // Set the parameters used for PDF encryption. Calling this method will
    // also enable PDF encryption, equivalent to calling setEncrypt(true).
    // keyBits: The size of the encryption key in bits (must be 40 or 128).
    // userPassword: The user password for the PDF file.
    // ownerPassword: The owner password for the PDF file.
    // disallowPrint: True to disallow printing of the PDF file.
    // disallowModify: True to disallow modification of the PDF file.
    // disallowCopy: True to disallow copying from the PDF file.
    // disallowAnnotate: True to disallow annotation of the PDF file.
    public function setEncryptInfo($keyBits,
                                   $userPassword,
                                   $ownerPassword,
                                   $disallowPrint = false,
                                   $disallowModify = false,
                                   $disallowCopy = false,
                                   $disallowAnnotate = false)
    {
        if ($keyBits != 40 && $keyBits != 128)
        {
            throw new Exception("Invalid value for keyBits: $keyBits" .
                " (must be 40 or 128)");
        }

        $this->encrypt = true;

        $this->encryptInfo =
            ' --key-bits ' . $keyBits .
            ' --user-password="' . $this->cmdlineArgEscape($userPassword) .
            '" --owner-password="' . $this->cmdlineArgEscape($ownerPassword) . '" ';

        if ($disallowPrint)
        {
            $this->encryptInfo .= '--disallow-print ';
        }

        if ($disallowModify)
        {
            $this->encryptInfo .= '--disallow-modify ';
        }

        if ($disallowCopy)
        {
            $this->encryptInfo .= '--disallow-copy ';
        }

        if ($disallowAnnotate)
        {
            $this->encryptInfo .= '--disallow-annotate ';
        }
    }

    //Set other options.
    public function setOptions($options)
    {
        $this->options = $options;
    }

    // Convert an XML or HTML file to a PDF file.
    // The name of the output PDF file will be the same as the name of the
    // input file but with an extension of ".pdf".
    // xmlPath: The filename of the input XML or HTML document.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_file($xmlPath, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=normal ';
        $pathAndArgs .= '"' . $xmlPath . '"';

        return $this->convert_internal_file_to_file($pathAndArgs, $msgs, $dats);

    }

    // Convert an XML or HTML file to a PDF file.
    // xmlPath: The filename of the input XML or HTML document.
    // pdfPath: The filename of the output PDF file.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_file_to_file($xmlPath, $pdfPath, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=normal ';
        $pathAndArgs .= '"' . $xmlPath . '" -o "' . $pdfPath . '"';

        return $this->convert_internal_file_to_file($pathAndArgs, $msgs, $dats);
    }

    //Convert multiple XML or HTML files to a PDF file.
    // xmlPaths: An array of the input XML or HTML documents.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_multiple_files($xmlPaths, $pdfPath, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=normal ';

        foreach($xmlPaths as $xmlPath)
        {
            $pathAndArgs .= '"' . $xmlPath . '" ';
        }
        $pathAndArgs .= '-o "' . $pdfPath . '"';

        return $this->convert_internal_file_to_file($pathAndArgs, $msgs, $dats);
    }

    // Convert multiple XML or HTML files to a PDF file, which will be passed
    // through to the output buffer of the current PHP page.
    // xmlPaths: An array of the input XML or HTML documents.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_multiple_files_to_passthru($xmlPaths, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=buffered ';

        foreach($xmlPaths as $xmlPath)
        {
            $pathAndArgs .= '"' . $xmlPath . '" ';
        }
        $pathAndArgs .= '-o -';

        return $this->convert_internal_file_to_passthru($pathAndArgs, $msgs, $dats);
    }

    // Convert an XML or HTML file to a PDF file, which will be passed
    // through to the output buffer of the current PHP page.
    // xmlPath: The filename of the input XML or HTML document.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_file_to_passthru($xmlPath, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=buffered "' . $xmlPath . '" -o -';

        return $this->convert_internal_file_to_passthru($pathAndArgs, $msgs, $dats);
    }

    // Convert an XML or HTML string to a PDF file, which will be passed
    // through to the output buffer of the current PHP page.
    // xmlString: A string containing an XML or HTML document.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_string_to_passthru($xmlString, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=buffered -';

        return $this->convert_internal_string_to_passthru($pathAndArgs, $xmlString, $msgs, $dats);
    }

    // Convert an XML or HTML string to a PDF file.
    // xmlString: A string containing an XML or HTML document.
    // pdfPath: The filename of the output PDF file.
    // msgs: An optional array in which to return error and warning messages.
    // dats: An optional array in which to return data messages.
    // Returns true if a PDF file was generated successfully.
    public function convert_string_to_file($xmlString, $pdfPath, &$msgs = array(), &$dats = array())
    {
        $pathAndArgs = $this->getCommandLine();
        $pathAndArgs .= '--structured-log=normal ';
        $pathAndArgs .= ' - -o "' . $pdfPath . '"';

        return $this->convert_internal_string_to_file($pathAndArgs, $xmlString, $msgs, $dats);
    }

    private function getCommandLine()
    {
        $cmdline = '"' . $this->exePath . '" ' . $this->styleSheets . $this->scripts . $this->fileAttachments . $this->remaps;

        if (strcasecmp($this->inputType, 'auto') == 0)
        {
        }
        else
        {
            $cmdline .=  '-i "' . $this->inputType . '" ';
        }

        if ($this->javascript)
        {
            $cmdline .= '--javascript ';
        }

        if ($this->baseURL != '')
        {
            $cmdline .= '--baseurl="' . $this->baseURL . '" ';
        }

        if ($this->doXInclude == false)
        {
            $cmdline .= '--no-xinclude ';
        }
        else
        {
            $cmdline .= '--xinclude ';
        }

        if ($this->xmlExternalEntities == true)
        {
            $cmdline .= '--xml-external-entities ';
        }

        if ($this->noLocalFiles == true)
        {
            $cmdline .= '--no-local-files ';
        }

        if ($this->noNetwork == true)
        {
            $cmdline .= '--no-network ';
        }

        if ($this->httpProxy != '')
        {
            $cmdline .= '--http-proxy="' . $this->httpProxy . '" ';
        }

        if ($this->httpTimeout !='')
        {
            $cmdline .= '--http-timeout="' . $this->httpTimeout . '" ';
        }

        if ($this->cookie != '')
        {
            $cmdline .= '--cookie="' . $this->cookie . '" ';
        }

        if ($this->cookieJar != '')
        {
            $cmdline .= '--cookiejar="' . $this->cookieJar . '" ';
        }

        if ($this->sslCaCert != '')
        {
            $cmdline .= '--ssl-cacert="' . $this->sslCaCert . '" ';
        }

        if ($this->sslCaPath != '')
        {
            $cmdline .= '--ssl-capath="' . $this->sslCaPath . '" ';
        }

        if ($this->sslVersion != '')
        {
            $cmdline .= '--ssl-version="' . $this->sslVersion . '" ';
        }

        if ($this->insecure)
        {
            $cmdline .= '--insecure ';
        }

        if ($this->noParallelDownloads)
        {
            $cmdline .= '--no-parallel-downloads ';
        }

        if ($this->logFile != '')
        {
            $cmdline .= '--log="' . $this->logFile . '" ';
        }

        if($this->verbose)
        {
            $cmdline .= '--verbose ';
        }

        if($this->debug)
        {
            $cmdline .= '--debug ';
        }

        if($this->noWarnCss)
        {
            $cmdline .= '--no-warn-css ';
        }

        if ($this->fileRoot != '')
        {
            $cmdline .= '--fileroot="' . $this->fileRoot . '" ';
        }

        if ($this->licenseFile != '')
        {
            $cmdline .= '--license-file="' . $this->licenseFile . '" ';
        }

        if ($this->licenseKey != '')
        {
            $cmdline .= '--license-key="' . $this->licenseKey . '" ';
        }

        if ($this->embedFonts == false)
        {
            $cmdline .= '--no-embed-fonts ';
        }

        if ($this->subsetFonts == false)
        {
            $cmdline .= '--no-subset-fonts ';
        }

        if ($this->noArtificialFonts == true)
        {
            $cmdline .= '--no-artificial-fonts ';
        }

        if ($this->authMethod != '')
        {
            $cmdline .=  '--auth-method="' . $this->cmdlineArgEscape($this->authMethod) . '" ';
        }

        if ($this->authUser != '')
        {
            $cmdline .= '--auth-user="' . $this->cmdlineArgEscape($this->authUser) . '" ';
        }

        if ($this->authPassword != '')
        {
            $cmdline .= '--auth-password="' . $this->cmdlineArgEscape($this->authPassword) . '" ';
        }

        if ($this->authServer != '')
        {
            $cmdline .= '--auth-server="' . $this->cmdlineArgEscape($this->authServer) . '" ';
        }

        if ($this->authScheme != '')
        {
            $cmdline .= '--auth-scheme="' . $this->cmdlineArgEscape($this->authScheme) . '" ';
        }

        if ($this->noAuthPreemptive)
        {
            $cmdline .= '--no-auth-preemptive ';
        }

        if ($this->media != '')
        {
            $cmdline .= '--media="' . $this->cmdlineArgEscape($this->media) . '" ';
        }

        if ($this->pageSize != '')
        {
            $cmdline .= '--page-size="' . $this->cmdlineArgEscape($this->pageSize) . '" ';
        }

        if ($this->pageMargin != '')
        {
            $cmdline .= '--page-margin="' . $this->cmdlineArgEscape($this->pageMargin) . '" ';
        }

        if ($this->noAuthorStyle == true)
        {
            $cmdline .= '--no-author-style ';
        }

        if ($this->noDefaultStyle == true)
        {
            $cmdline .= '--no-default-style ';
        }

        if ($this->forceIdentityEncoding == true)
        {
            $cmdline .= '--force-identity-encoding ';
        }

        if ($this->compress == false)
        {
            $cmdline .= '--no-compress ';
        }

        if ($this->pdfOutputIntent != '')
        {
            $cmdline .= '--pdf-output-intent="' . $this->cmdlineArgEscape($this->pdfOutputIntent) . '" ';

            if ($this->convertColors == true)
            {
                $cmdline .= '--convert-colors ';
            }
        }

        if ($this->fallbackCmykProfile != '')
        {
            $cmdline .= '--fallback-cmyk-profile="'. $this->cmdlineArgEscape($this->fallbackCmykProfile) . '" ';
        }

        if ($this->pdfProfile != '')
        {
            $cmdline .= '--pdf-profile="' . $this->cmdlineArgEscape($this->pdfProfile) . '" ';
        }

        if ($this->pdfTitle != '')
        {
            $cmdline .= '--pdf-title="' . $this->cmdlineArgEscape($this->pdfTitle) . '" ';
        }

        if ($this->pdfSubject != '')
        {
            $cmdline .= '--pdf-subject="' . $this->cmdlineArgEscape($this->pdfSubject) . '" ';
        }

        if ($this->pdfAuthor != '')
        {
            $cmdline .= '--pdf-author="' . $this->cmdlineArgEscape($this->pdfAuthor) . '" ';
        }

        if ($this->pdfKeywords != '')
        {
            $cmdline .= '--pdf-keywords="' . $this->cmdlineArgEscape($this->pdfKeywords) . '" ';
        }

        if ($this->pdfCreator != '')
        {
            $cmdline .= '--pdf-creator="' . $this->cmdlineArgEscape($this->pdfCreator) . '" ';
        }

        if ($this->encrypt)
        {
            $cmdline .= '--encrypt ' . $this->encryptInfo;
        }

        if ($this->options != '')
        {
            $cmdline .= $this->cmdlineArgEscape($this->options) . ' ';
        }

        return $cmdline;
    }

    private function convert_internal_file_to_file($pathAndArgs, &$msgs, &$dats)
    {
        $descriptorspec = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );

        $process = proc_open($pathAndArgs, $descriptorspec, $pipes, NULL, NULL, array('bypass_shell' => TRUE));

        if (is_resource($process))
        {
            $result = $this->readMessages($pipes[2], $msgs, $dats);

            fclose($pipes[0]);
            fclose($pipes[1]);
            fclose($pipes[2]);

            proc_close($process);

            return ($result == 'success');
        }
        else
        {
            throw new Exception("Failed to execute $pathAndArgs");
        }
    }

    private function convert_internal_string_to_file($pathAndArgs, $xmlString, &$msgs, &$dats)
    {
        $descriptorspec = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );

        $process = proc_open($pathAndArgs, $descriptorspec, $pipes, NULL, NULL, array('bypass_shell' => TRUE));

        if (is_resource($process))
        {
            fwrite($pipes[0], $xmlString);
            fclose($pipes[0]);
            fclose($pipes[1]);

            $result = $this->readMessages($pipes[2], $msgs, $dats);

            fclose($pipes[2]);

            proc_close($process);

            return ($result == 'success');
        }
        else
        {
            throw new Exception("Failed to execute $pathAndArgs");
        }
    }

    private function convert_internal_file_to_passthru($pathAndArgs, &$msgs, &$dats)
    {
        $descriptorspec = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );

        $process = proc_open($pathAndArgs, $descriptorspec, $pipes, NULL, NULL, array('bypass_shell' => TRUE));

        if (is_resource($process))
        {
            fclose($pipes[0]);
            fpassthru($pipes[1]);
            fclose($pipes[1]);

            $result = $this->readMessages($pipes[2], $msgs, $dats);

            fclose($pipes[2]);

            proc_close($process);

            return ($result == 'success');
        }
        else
        {
            throw new Exception("Failed to execute $pathAndArgs");
        }
    }

    private function convert_internal_string_to_passthru($pathAndArgs, $xmlString, &$msgs, &$dats)
    {
        $descriptorspec = array(
            0 => array("pipe", "r"),
            1 => array("pipe", "w"),
            2 => array("pipe", "w")
        );

        $process = proc_open($pathAndArgs, $descriptorspec, $pipes, NULL, NULL, array('bypass_shell' => TRUE));

        if (is_resource($process))
        {
            fwrite($pipes[0], $xmlString);
            fclose($pipes[0]);
            fpassthru($pipes[1]);
            fclose($pipes[1]);

            $result = $this->readMessages($pipes[2], $msgs, $dats);

            fclose($pipes[2]);

            proc_close($process);

            return ($result == 'success');
        }
        else
        {
            throw new Exception("Failed to execute $pathAndArgs");
        }
    }

    private function readMessages($pipe, &$msgs, &$dats)
    {
        while (!feof($pipe))
        {
            $line = fgets($pipe);

            if ($line != false)
            {
                $msgtag = substr($line, 0, 4);
                $msgbody = rtrim(substr($line, 4));

                if ($msgtag == 'fin|')
                {
                    return $msgbody;
                }
                else if ($msgtag == 'msg|')
                {
                    $msg = explode('|', $msgbody, 4);

                    // $msg[0] = 'err' | 'wrn' | 'inf'
                    // $msg[1] = filename / line number
                    // $msg[2] = message text, trailing newline stripped

                    $msgs[] = $msg;
                }
                else if ($msgtag == 'dat|')
                {
                    $dat = explode('|', $msgbody, 2);

                    $dats[] = $dat;
                }
                else
                {
                    // ignore other messages
                }
            }
        }

        return '';
    }

    private function cmdlineArgEscape($argStr)
    {
        return $this->cmdlineArgEscape2($this->cmdlineArgEscape1($argStr));
    }

    //In the input string $argStr, a double quote with zero or more preceding backslash(es)
    //will be replaced with: n*backslash + doublequote => (2*n+1)*backslash + doublequote
    private function cmdlineArgEscape1($argStr)
    {
        //chr(34) is character double quote ( " ), chr(92) is character backslash ( \ ).
        $len = strlen($argStr);

        $outputStr = '';
        $numSlashes = 0;
        $subStrStart = 0;

        for($i = 0; $i < $len; $i++)
        {
            if($argStr[$i] == chr(34))
            {
                $numSlashes = 0;
                $j = $i - 1;
                while($j >= 0)
                {
                    if($argStr[$j] == chr(92))
                    {
                        $numSlashes += 1;
                        $j -= 1;
                    }
                    else
                    {
                        break;
                    }
                }

                $outputStr .= substr($argStr, $subStrStart, ($i - $numSlashes - $subStrStart));

                for($k = 0; $k < $numSlashes; $k++)
                {
                    $outputStr .= chr(92) . chr(92);
                }
                $outputStr  .= chr(92) . chr(34);

                $subStrStart = $i + 1;
            }
        }
        $outputStr .= substr($argStr, $subStrStart, ($i - $subStrStart));

        return $outputStr;
    }

    //Double the number of trailing backslash(es):      n*trailing backslash => (2*n)*trailing backslash.
    private function cmdlineArgEscape2($argStr)
    {
        //chr(92) is character backslash ( \ ).
        $len = strlen($argStr);

        $numTrailingSlashes = 0;
        for($i = ($len - 1); $i  >= 0; $i--)
        {
            if($argStr[$i] == chr(92))
            {
                $numTrailingSlashes += 1;
            }
            else
            {
                break;
            }
        }

        while($numTrailingSlashes > 0)
        {
            $argStr .= chr(92);
            $numTrailingSlashes -= 1;
        }

        return $argStr;
    }
}
?>


<?php

declare(strict_types=1);

namespace Mapado\RestClientSdk;

use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\TransferException;
use Mapado\RestClientSdk\Exception\RestClientException;
use Mapado\RestClientSdk\Exception\RestException;
use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpFoundation\Request;

/**
 * Class RestClient
 *
 * @author Julien Deniau <julien.deniau@mapado.com>
 */
class RestClient
{
    /**
     * @var ClientInterface
     */
    private $httpClient;

    /**
     * @var ?string
     */
    private $baseUrl;

    /**
     * @var bool
     */
    private $logHistory;

    /**
     * @var array
     */
    private $requestHistory;

    /**
     * @var ?Request
     */
    private $currentRequest;

    public function __construct(
        ClientInterface $httpClient,
        ?string $baseUrl = null
    ) {
        $this->httpClient = $httpClient;
        $this->baseUrl = (null !== $baseUrl && '/' === mb_substr($baseUrl, -1))
            ? mb_substr($baseUrl, 0, -1)
            : $baseUrl;
        $this->logHistory = false;
        $this->requestHistory = [];
    }

    public function isHistoryLogged(): bool
    {
        return $this->logHistory;
    }

    public function setCurrentRequest(Request $currentRequest): self
    {
        $this->currentRequest = $currentRequest;

        return $this;
    }

    public function setLogHistory(bool $logHistory): self
    {
        $this->logHistory = $logHistory;

        return $this;
    }

    public function getRequestHistory(): array
    {
        return $this->requestHistory;
    }

    /**
     * get a path
     *
     * @return array|ResponseInterface|null
     *
     * @throws RestException
     */
    public function get(string $path, array $parameters = [])
    {
        $requestUrl = $this->baseUrl . $path;
        try {
            return $this->executeRequest('GET', $requestUrl, $parameters);
        } catch (ClientException $e) {
            $response = $e->getResponse();
            if (null !== $response && 404 === $response->getStatusCode()) {
                return null;
            }
            throw new RestClientException(
                'Error while getting resource',
                $path,
                [],
                7,
                $e
            );
        } catch (TransferException $e) {
            throw new RestException(
                'Error while getting resource',
                $path,
                [],
                1,
                $e
            );
        }
    }

    /**
     * @throws RestException
     */
    public function delete(string $path): void
    {
        try {
            $this->executeRequest('DELETE', $this->baseUrl . $path);
        } catch (ClientException $e) {
            return;
        } catch (TransferException $e) {
            throw new RestException(
                'Error while deleting resource',
                $path,
                [],
                2,
                $e
            );
        }
    }

    /**
     * @return array|ResponseInterface
     *
     * @throws RestClientException
     * @throws RestException
     */
    public function post(string $path, array $data, array $parameters = [])
    {
        $parameters['json'] = $data;
        try {
            return $this->executeRequest(
                'POST',
                $this->baseUrl . $path,
                $parameters
            );
        } catch (ClientException $e) {
            throw new RestClientException(
                'Cannot create resource',
                $path,
                [],
                3,
                $e
            );
        } catch (TransferException $e) {
            throw new RestException(
                'Error while posting resource',
                $path,
                [],
                4,
                $e
            );
        }
    }

    /**
     * @return array|ResponseInterface
     *
     * @throws RestClientException
     * @throws RestException
     */
    public function put(string $path, array $data, array $parameters = [])
    {
        $parameters['json'] = $data;

        try {
            return $this->executeRequest(
                'PUT',
                $this->baseUrl . $path,
                $parameters
            );
        } catch (ClientException $e) {
            throw new RestClientException(
                'Cannot update resource',
                $path,
                [],
                5,
                $e
            );
        } catch (TransferException $e) {
            throw new RestException(
                'Error while puting resource',
                $path,
                [],
                6,
                $e
            );
        }
    }

    /**
     * Merge default parameters.
     */
    protected function mergeDefaultParameters(array $parameters): array
    {
        $request = $this->getCurrentRequest();

        $defaultParameters = ['version' => '1.0'];
        $defaultParameters['headers'] = ['Referer' => $request->getUri()];

        return array_replace_recursive($defaultParameters, $parameters);
    }

    protected function getCurrentRequest(): Request
    {
        if (!$this->currentRequest) {
            $this->currentRequest = Request::createFromGlobals();
        }

        return $this->currentRequest;
    }

    /**
     * Executes request.
     *
     * @return ResponseInterface|array
     *
     * @throws TransferException
     */
    private function executeRequest(
        string $method,
        string $url,
        array $parameters = []
    ) {
        $parameters = $this->mergeDefaultParameters($parameters);

        $startTime = null;
        if ($this->isHistoryLogged()) {
            $startTime = microtime(true);
        }

        try {
            $response = $this->httpClient->request($method, $url, $parameters);
            $this->logRequest(
                $startTime,
                $method,
                $url,
                $parameters,
                $response
            );
        } catch (RequestException $e) {
            $this->logRequest(
                $startTime,
                $method,
                $url,
                $parameters,
                $e->getResponse()
            );
            throw $e;
        } catch (TransferException $e) {
            $this->logRequest($startTime, $method, $url, $parameters);
            throw $e;
        }

        $headers = $response->getHeaders();
        $jsonContentTypeList = ['application/ld+json', 'application/json'];

        $requestIsJson = false;

        if (isset($headers['Content-Type'])) {
            foreach ($jsonContentTypeList as $contentType) {
                if (
                    false !==
                    mb_stripos($headers['Content-Type'][0], $contentType)
                ) {
                    $requestIsJson = true;
                    break;
                }
            }
        }

        if ($requestIsJson) {
            return json_decode((string) $response->getBody(), true);
        } else {
            return $response;
        }
    }

    private function logRequest(
        ?float $startTime,
        string $method,
        string $url,
        array $parameters,
        ?ResponseInterface $response = null
    ): void {
        if ($this->isHistoryLogged()) {
            $queryTime = microtime(true) - $startTime;

            $this->requestHistory[] = [
                'method' => $method,
                'url' => $url,
                'parameters' => $parameters,
                'response' => $response,
                'responseBody' => $response
                    ? json_decode((string) $response->getBody(), true)
                    : null,
                'queryTime' => $queryTime,
                'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS),
            ];
        }
    }
}


<?php

/**
 * Contao Bootstrap
 *
 * @package    contao-bootstrap
 * @subpackage Tab
 * @author     David Molineus <david.molineus@netzmacht.de>
 * @copyright  2013-2018 netzmacht David Molineus. All rights reserved.
 * @license    LGPL-3.0 https://github.com/contao-bootstrap/tab
 * @filesource
 */

declare(strict_types=1);

namespace ContaoBootstrap\Tab\Component\ContentElement;

use Assert\AssertionFailedException;
use Contao\ContentModel;
use Contao\Database\Result;
use Contao\Model;
use Contao\Model\Collection;
use ContaoBootstrap\Core\Helper\ColorRotate;
use ContaoBootstrap\Grid\GridIterator;
use ContaoBootstrap\Grid\GridProvider;
use ContaoBootstrap\Tab\View\Tab\NavigationIterator;
use ContaoBootstrap\Tab\View\Tab\TabRegistry;
use Netzmacht\Contao\Toolkit\Component\ContentElement\AbstractContentElement;
use Netzmacht\Contao\Toolkit\Routing\RequestScopeMatcher;
use Netzmacht\Contao\Toolkit\View\Template\TemplateReference as ToolkitTemplateReference;
use Symfony\Component\Templating\EngineInterface as TemplateEngine;
use Symfony\Component\Translation\TranslatorInterface as Translator;

/**
 * Class AbstractTabElement
 */
abstract class AbstractTabElement extends AbstractContentElement
{
    /**
     * Color rotate.
     *
     * @var ColorRotate
     */
    private $colorRotate;

    /**
     * Request scope matcher.
     *
     * @var RequestScopeMatcher
     */
    private $scopeMatcher;

    /**
     * Tab registry.
     *
     * @var TabRegistry
     */
    private $tabRegistry;

    /**
     * Grid provider.
     *
     * @var GridProvider|null
     */
    private $gridProvider;

    /**
     * The translator.
     *
     * @var Translator
     */
    private $translator;

    /**
     * AbstractContentElement constructor.
     *
     * @param Model|Collection|Result $model          Object model or result.
     * @param TemplateEngine          $templateEngine Template engine.
     * @param Translator              $translator     The translator.
     * @param ColorRotate             $colorRotate    ColorRotate helper.
     * @param RequestScopeMatcher     $scopeMatcher   Request scope matcher.
     * @param TabRegistry             $tabRegistry    Tab registry.
     * @param GridProvider|null       $gridProvider   Grid provider.
     * @param string                  $column         Column or section name.
     */
    public function __construct(
        $model,
        TemplateEngine $templateEngine,
        Translator $translator,
        ColorRotate $colorRotate,
        RequestScopeMatcher $scopeMatcher,
        TabRegistry $tabRegistry,
        ?GridProvider $gridProvider,
        string $column = 'main'
    ) {
        parent::__construct($model, $templateEngine, $column);

        $this->translator   = $translator;
        $this->colorRotate  = $colorRotate;
        $this->scopeMatcher = $scopeMatcher;
        $this->tabRegistry  = $tabRegistry;
        $this->gridProvider = $gridProvider;
    }

    /**
     * {@inheritdoc}
     */
    public function generate(): string
    {
        if ($this->isBackendRequest()) {
            $iterator = $this->getIterator();

            if ($iterator && $this->getParent() !== $this->getModel()) {
                $iterator->next();
            }

            return $this->renderBackendView($this->getParent(), $iterator);
        }

        return parent::generate();
    }

    /**
     * Get the grid provider.
     *
     * @return TabRegistry
     */
    protected function getTabRegistry(): TabRegistry
    {
        return $this->tabRegistry;
    }

    /**
     * Render the backend view.
     *
     * @param ContentModel|null  $start    Start element.
     * @param NavigationIterator $iterator Iterator.
     *
     * @return string
     */
    protected function renderBackendView($start, NavigationIterator $iterator = null): string
    {
        $parent = $this->getParent();

        return $this->render(
            new ToolkitTemplateReference(
                'be_bs_tab',
                'html5',
                ToolkitTemplateReference::SCOPE_BACKEND
            ),
            [
                'name'  => $parent ? $parent->bs_tab_name : null,
                'color' => $start ? $this->rotateColor('ce:' . $start->id) : null,
                'error' => $start ? null : $this->translator->trans('ERR.bsTabParentMissing', [], 'contao_default'),
                'title' => $iterator ? $iterator->currentTitle() : null,
            ]
        );
    }

    /**
     * Check if we are in backend mode.
     *
     * @return bool
     */
    protected function isBackendRequest(): bool
    {
        return $this->scopeMatcher->isBackendRequest();
    }

    /**
     * Get the tab navigation iterator.
     *
     * @return NavigationIterator
     */
    protected function getIterator(): ?NavigationIterator
    {
        $parent = $this->getParent();

        if (!$parent) {
            return null;
        }

        try {
            return $this->getTabRegistry()->getIterator((string) $parent->id);
        } catch (AssertionFailedException $e) {
            return null;
        }
    }

    /**
     * Get the parent model.
     *
     * @return ContentModel|null
     */
    protected function getParent(): ?ContentModel
    {
        return ContentModel::findByPk($this->get('bs_tab_parent'));
    }

    /**
     * Get the grid iterator.
     *
     * @return GridIterator|null
     */
    protected function getGridIterator(): ?GridIterator
    {
        $parent = $this->getParent();

        if (!$parent || !$this->gridProvider || !$parent->bs_grid) {
            return null;
        }

        try {
            $gridIterator = $this->gridProvider->getIterator('ce:' . $parent->id, (int) $parent->bs_grid);

            return $gridIterator;
        } catch (\RuntimeException $e) {
            return null;
        }
    }

    /**
     * Rotate the color for an identifier.
     *
     * @param string $identifier The color identifier.
     *
     * @return string
     */
    protected function rotateColor(string $identifier): string
    {
        return $this->colorRotate->getColor($identifier);
    }
}


<?php
namespace bupy7\bbcode;

use yii\helpers\HtmlPurifier;
use yii\base\Behavior;
use yii\db\ActiveRecord;
use yii\base\InvalidConfigException;
use JBBCode\CodeDefinitionBuilder;
use JBBCode\CodeDefinitionSet;
use JBBCode\CodeDefinition;

/**
 * Home page of extension: https://github.com/bupy7/yii2-bbcode/
 * Home page of jBBCode: http://jbbcode.com/
 * Home page of HtmlPurifier: http://htmlpurifier.org/
 *
 * Behavior for parsing BB-codes at base jBBCode and HtmlPurifier.
 *
 * @author Belosludcev Vasilij http://mihaly4.ru
 * @version 1.1
 */
class BBCodeBehavior extends Behavior
{

    /**
     * @var string Attribute name where content BBCodes.
     * If this property is NULL will be an exception is thrown.
     */
    public $attribute;

    /**
     * @var string Attribute name where will be save result the pasing BB-codes.
     * If this property is NULL will be an exception is thrown.
     */
    public $saveAttribute;

    /**
     * @var boolean Whether calling HtmlPurifier before process of parsing BB-codes.
     */
    public $enableHtmlPurifierBefore = false;

    /**
     * @var boolean Whether calling HtmlPurifier after process of parsing BB-codes.
     */
    public $enableHtmlPurifierAfter = false;

    /**
     * @var array|\Closure|null $config The config to use for HtmlPurifier.
     * If not specified or `null` the default config will be used.
     * You can use an array or an anonymous function to provide configuration options:
     *
     * - An array will be passed to the `HTMLPurifier_Config::create()` method.
     * - An anonymous function will be called after the config was created.
     *   The signature should be: `function($config)` where `$config` will be an
     *   instance of `HTMLPurifier_Config`.
     *
     *   Here is a usage example of such a function:
     *
     *   ~~~
     *   // Allow the HTML5 data attribute `data-type` on `img` elements.
     *   function($config) {
     *     $config->getHTMLDefinition(true)
     *            ->addAttribute('img', 'data-type', 'Text');
     *   })
     *   ~~~
     *   This is configuration apply before process of parsing BB-codes.
     */
    public $configHtmlPurifierBefore = [];

    /**
     * @var array|\Closure|null $config The config to use for HtmlPurifier.
     * If not specified or `null` the default config will be used.
     * You can use an array or an anonymous function to provide configuration options:
     *
     * - An array will be passed to the `HTMLPurifier_Config::create()` method.
     * - An anonymous function will be called after the config was created.
     *   The signature should be: `function($config)` where `$config` will be an
     *   instance of `HTMLPurifier_Config`.
     *
     *   Here is a usage example of such a function:
     *
     *   ~~~
     *   // Allow the HTML5 data attribute `data-type` on `img` elements.
     *   function($config) {
     *     $config->getHTMLDefinition(true)
     *            ->addAttribute('img', 'data-type', 'Text');
     *   })
     *   ~~~
     *   This is configuration apply after process of parsing BB-codes.
     */
    public $configHtmlPurifierAfter = [];

    /**
     * @var string Class name of provides a default set of common bbcode definitions.
     * By default '\bupy7\bbcode\definitions\DefaultCodeDefinitionSet'.
     */
    public $defaultCodeDefinitionSet = '\bupy7\bbcode\definitions\DefaultCodeDefinitionSet';

    /**
     * @var array Adding new custom bbcodes to your parser is easy.
     * For simple text-replacement bbcodes, just create a replacement string
     * that contains {param} where the bbcode's content should go.
     * Optionally, you may use the {option} variable for an option.
     * Example:
     * [
     *      // as elements of array
     *      ['quote', '
{param}
'],
     *
     *      // as class name where class is instance of extended class \JBBCode\CodeDefinitionBuilder
     *      '/namespace/to/CodeDefinitionBuilder/ExtendedClassName',
     *
     *      // as extended instance of extended class \JBBCode\CodeDefinitionBuilder
     *      $className,
     *
     *      // as callable function where $builder is instance of class \JBBCode\CodeDefinitionBuilder
     *      function($builder) {
     *          $builder->setTagName('code');
     *          $builder->setReplacementText('
{param}
');
     *          return $builder->build();
     *      },
     * ]
     */
    public $codeDefinitionBuilder = [];

    /**
     * @var array BB-code definitions extended of class \JBBCode\CodeDefinitionSet
     * Example:
     * [
     *      // as class name where class is instance of extended class \JBBCode\CodeDefinitionSet
     *      '/namespace/to/CodeDefinitionSet/ExtendedClassName',
     *
     *      // as extended instance of extended class \JBBCode\CodeDefinitionSet
     *      $className,
     * ]
     */
    public $codeDefinitionSet = [];

    /**
     * @var array BB-code definitions extended of class \JBBCode\CodeDefinition
     * Example:
     * [
     *      // as class name where class is instance of extended class \JBBCode\CodeDefinition
     *      '/namespace/to/CodeDefinition/ExtendedClassName',
     *
     *      // as extended instance of extended class \JBBCode\CodeDefinition
     *      $className,
     * ]
     */
    public $codeDefinition = [];

    /**
     * @var boolean Whether to return content as html or bb-codes. If property
     * is `true` then return as HTML, else as BB-codes.
     */
    public $asHtml = true;

    /**
     * @inheritdoc
     */
    public function init()
    {
        if (!$this->attribute || !$this->saveAttribute) {
            throw new InvalidConfigException('Invalid configuration of property `attribute` or `saveAttributes`.');
        }
        parent::init();
    }

    /**
     * Call behavior before save model of \yii\db\ActiveRecord.
     *
     * @return array
     */
    public function events()
    {
        return [
            ActiveRecord::EVENT_BEFORE_UPDATE => 'beforeSave',
            ActiveRecord::EVENT_BEFORE_INSERT => 'beforeSave',
        ];
    }

    /**
     * Parsing BB-codes before save of model.
     *
     * @param \yii\base\Event $event
     */
    public function beforeSave($event)
    {
        $content = $this->owner->{$this->attribute};

        if ($this->enableHtmlPurifierBefore) {
            $content = HtmlPurifier::process($content, $this->configHtmlPurifierBefore);
        }

        $content = $this->process($content);

        if ($this->enableHtmlPurifierAfter) {
            $content = HtmlPurifier::process($content, $this->configHtmlPurifierAfter);
        }

        $this->owner->{$this->saveAttribute} = $content;
    }

    /**
     * Parsing of BB-codes.
     *
     * @param string $content Content for parsing.
     * @return string
     */
    protected function process($content)
    {
        $parser = new Parser();

        $parser->addCodeDefinitionSet(new $this->defaultCodeDefinitionSet());

        // add definitions builder
        foreach ($this->codeDefinitionBuilder as $item) {
            if (is_string($item)) {
                $builder = new $item;
                if ($builder instanceof CodeDefinitionBuilder) {
                    $parser->addCodeDefinition($builder->build());
                }
            } elseif ($item instanceof CodeDefinitionBuilder) {
                $parser->addCodeDefinition($item->build());
            } elseif (is_callable($item)) {
                $parser->addCodeDefinition(call_user_func_array($item, [new CodeDefinitionBuilder('', '')]));
            } elseif (isset($item[0]) && isset($item[1])) {
                $builder = new CodeDefinitionBuilder($item[0], $item[1]);
                $parser->addCodeDefinition($builder->build());
            }
        }
        //added definitions set
        foreach ($this->codeDefinitionSet as $item) {
            if (is_string($item)) {
                $set = new $item;
                if ($set instanceof CodeDefinitionSet) {
                    $parser->addCodeDefinitionSet($set);
                }
            } elseif ($item instanceof CodeDefinitionSet) {
                $parser->addCodeDefinitionSet($item);
            }
        }
        //added definitions
        foreach ($this->codeDefinition as $item) {
            if (is_string($item)) {
                $set = new $item;
                if ($set instanceof CodeDefinition) {
                    $parser->addCodeDefinition($set);
                }
            } elseif ($item instanceof CodeDefinition) {
                $parser->addCodeDefinition($item);
            }
        }

        $parser->parse($content);

        if ($this->asHtml) {
            return $parser->getAsHtml();
        }
        return $parser->getAsBBCode();
    }

}