<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\ManiaScript;

use ManiaLib\Gui\Manialink;

/**
 * @see http://code.google.com/p/manialib/source/browse/trunk/media/maniascript/manialib.xml
 */
abstract class UI
{

    static function getDialog($openControlId, $message, array $action = array())
    {
        $script = 'manialib_ui_dialog("%s", "%s", %s); ';
        $openControlId = Tools::escapeString($openControlId);
        $message = Tools::escapeString($message);
        $action = Tools::array2maniascript($action);
        return sprintf($script, $openControlId, $message, $action);
    }

    /**
     * Teh infamous dialog box
     *
     * @param string $openControlId Id of the element that will open the dialog when clicked
     * @param string $message Message to show in the dialog
     * @param array $action A ManiaScript Framework Action
     */
    static function dialog($openControlId, $message, array $action = array())
    {
        Manialink::appendScript(static::getDialog($openControlId, $message, $action));
    }

    static function getMessage($openControlId, $message)
    {
        $script = 'manialib_ui_message("%s", "%s"); ';
        $openControlId = Tools::escapeString($openControlId);
        $message = Tools::escapeString($message);
        return sprintf($script, $openControlId, $message);
    }

    /**
     * Teh infamous dialog box
     *
     * @param string $openControlId Id of the element that will open the dialog when clicked
     * @param string $message Message to show in the dialog
     * @param array $action A ManiaScript Framework Action
     */
    static function message($openControlId, $message)
    {

        Manialink::appendScript(static::getMessage($openControlId, $message));
    }

    static function getTooltip($controlId, $message)
    {
        $script = 'manialib_ui_tooltip("%s", "%s"); ';
        $controlId = Tools::escapeString($controlId);
        $message = Tools::escapeString($message);
        return sprintf($script, $controlId, $message);
    }

    /**
     * Nice little tooltip when mousing over
     *
     * @param string $controlId Id of the element that will be tooltiped
     * @param string $message
     */
    static function tooltip($controlId, $message)
    {
        Manialink::appendScript(static::getTooltip($controlId, $message));
    }

    static function getDatePicker($entryId, $openControlId)
    {
        $script = 'manialib_ui_datepicker_init("%s", "%s");';
        $entryId = Tools::escapeString($entryId);
        $openControlId = Tools::escapeString($openControlId);
        return sprintf($script, $entryId, $openControlId);
    }

    static function datePicker($entryId, $openControlId)
    {
        Manialink::appendScript(static::getDatePicker($entryId, $openControlId));
    }

    static function getMagnifier($imageId, $scale)
    {
        $script = 'manialib_ui_magnifier("%s", "%f"); ';
        $controlId = Tools::escapeString($imageId);
        return sprintf($script, $controlId, $scale);
    }

    static function magnifier($imageId, $scale)
    {
        Manialink::appendScript(static::getMagnifier($imageId, $scale));
    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Database;

class Connection
{

    /**
     * @var array[\ManiaLib\Database\ConnectionParams]
     */
    static protected $connections = array();

    /**
     * @var \ManiaLib\Database\Config
     */
    protected $config;

    /**
     * @var \ManiaLib\Database\ConnectionsParams
     */
    protected $params;

    /**
     * MySQL connection ressource
     */
    protected $connection;

    /**
     * Current charset
     * @var string
     */
    protected $charset;

    /**
     * Currently selected database
     * @vat string
     */
    protected $database;

    /**
     * @var int
     */
    protected $transactionRefCount;

    /**
     * @var bool
     */
    protected $transactionRollback;

    /**
     * The easiest way to retrieve a database connection. Works as a singleton,
     * and returns a connection with the default parameters
     * @return \ManiaLib\Database\Connection
     */
    static function getInstance()
    {
        if (\array_key_exists('default', static::$connections)) {
            return static::$connections['default'];
        }

        $config = Config::getInstance();

        $params = new ConnectionParams();
        $params->id = 'default';
        $params->host = $config->host;
        $params->user = $config->user;
        $params->password = $config->password;
        $params->database = $config->database;
        $params->charset = $config->charset;
        $params->persistent = $config->persistent;

        return static::factory($params);
    }

    /**
     * Advanced connection retrieval. You can have multiple instances of the
     * Connection object so you can work with several MySQL servers. If you don't
     * give any parameters, it will work as static::getInstance()
     * @return \ManiaLib\Database\Connection
     */
    static function factory(ConnectionParams $params)
    {
        if (!$params->id) {
            throw new Exception('ConnectionParams object has no ID');
        }
        if (!array_key_exists($params->id, static::$connections)) {
            static::$connections[$params->id] = new static($params);
        }
        return static::$connections[$params->id];
    }

    protected function __construct(ConnectionParams $params)
    {
        $this->config = Config::getInstance();
        $this->params = $params;

        if ($this->params->persistent) {
            $this->connection = mysqli_connect(
                'p:' . $this->params->host,
                $this->params->user,
                $this->params->password
            );
        } else {
            $this->connection = mysqli_connect(
                $this->params->host,
                $this->params->user,
                $this->params->password
            );
        }

        if (!$this->connection) {
            throw new Exception('Connection failed');
        }

        $this->setCharset($this->params->charset);
        $this->select($this->params->database);
    }

    function setCharset($charset)
    {
        if ($charset != $this->charset) {
            $this->charset = $charset;
            if (!mysqli_set_charset($this->connection, $charset)) {
                throw new Exception('Couldn\'t set charset: ' . $charset);
            }
        }
    }

    function select($database)
    {
        if ($database && $database != $this->database) {
            $this->database = $database;
            if (!mysqli_select_db($this->connection, $this->database)) {
                throw new Exception(mysqli_error($this->connection), mysqli_errno($this->connection));
            }
        }
    }

    function quote($string)
    {
        return '\'' . mysqli_real_escape_string($this->connection, $string) . '\'';
    }

    /**
     * @return RecordSet
     */
    function execute($query /* , sprintf style params... */)
    {
        $mtime = microtime(true);
        if (func_num_args() > 1) {
            $query = call_user_func_array('sprintf', func_get_args());
        }

        $query = $this->instrumentQuery($query);

        $result = mysqli_query($this->connection, $query);
        if (!$result) {
            throw new QueryException(mysqli_error($this->connection) . ': ' . $query, mysqli_errno($this->connection));
        }
        if ($this->config->queryLog) {
            $mtime2 = round((microtime(true) - $mtime) * 1000);
            $message = str_pad($mtime2 . ' ms', 10, ' ') . $query;
            \ManiaLib\Utils\Logger::info($message);
        }
        if ($this->config->slowQueryLog) {
            $mtime2 = round((microtime(true) - $mtime) * 1000);
            if ($mtime2 > $this->config->slowQueryThreshold) {
                $message = str_pad($mtime2 . ' ms', 10, ' ') . $query;
                \ManiaLib\Utils\Logger::info($message);
            }
        }
        return new RecordSet($result);
    }

    /**
     * @param string $query
     * @return string Augmented query
     */
    protected function instrumentQuery($query)
    {
        $bt = debug_backtrace();
        if (count($bt) < 3) {
            return $query;
        }
        array_shift($bt);
        array_shift($bt);
        $frame = array_shift($bt);
        $class = \ManiaLib\Utils\Arrays::get($frame, 'class');
        $type = \ManiaLib\Utils\Arrays::get($frame, 'type');
        $function = \ManiaLib\Utils\Arrays::get($frame, 'function');
        $line = \ManiaLib\Utils\Arrays::get($frame, 'line');

        $queryHeader = sprintf("/* Function: %s%s%s(), Line: %d*/ ", $class, $type, $function, $line);
        $query = $queryHeader . trim($query);
        return $query;
    }

    function delete($table, $identifier)
    {
        $criteria = array();
        foreach ($identifier as $key => $value) {
            $criteria[] = sprintf('%s = %s', $key, $value);
        }
        $criteria = implode(' AND ', $criteria);
        $query = sprintf('DELETE FROM %s WHERE %s', $table, $criteria);
        return $this->execute($query);
    }

    function affectedRows()
    {
        return mysqli_affected_rows($this->connection);
    }

    function insertID()
    {
        return mysqli_insert_id($this->connection);
    }

    function isConnected()
    {
        return (!$this->connection);
    }

    function getDatabase()
    {
        return $this->database;
    }

    /**
     * ACID Transactions
     * ONLY WORKS WITH INNODB TABLES !
     *
     * ----
     *
     * It handles EXPERIMENTAL (== never tested!!!) nested transactions
     * one "BEGIN" on the first call of beginTransaction
     * one "COMMIT" on the last call of commitTransaction (when the ref count is 1)
     * one "ROLLBACK" on the first call of rollbackTransaction
     */
    function beginTransaction()
    {
        if ($this->transactionRollback) {
            throw new Exception('Transaction must be rollback\'ed!');
        }
        if ($this->transactionRefCount === null) {
            $this->execute('BEGIN');
            $this->transactionRefCount = 1;
        } else {
            $this->transactionRefCount++;
        }
    }

    /**
     * @see static::beginTransaction()
     */
    function commitTransaction()
    {
        if ($this->transactionRollback) {
            throw new Exception('Transaction must be rollback\'ed!');
        }
        if ($this->transactionRefCount === null) {
            throw new Exception('Transaction was not previously started');
        } elseif ($this->transactionRefCount > 1) {
            $this->transactionRefCount--;
        } elseif ($this->transactionRefCount == 1) {
            $this->execute('COMMIT');
            $this->transactionRefCount = null;
        } else {
            throw new Exception(
                'Transaction reference counter error: ' .
                print_r($this->transactionRefCount, true));
        }
    }

    /**
     * @see static::beginTransaction()
     */
    function rollbackTransaction()
    {
        if (!$this->transactionRollback) {
            $this->transactionRollback = true;
            $this->execute('ROLLBACK');
        }

        if ($this->transactionRefCount > 1) {
            $this->transactionRefCount--;
        } elseif ($this->transactionRefCount == 1) {
            $this->transactionRefCount = null;
            $this->transactionRollback = null;
        } else {
            throw new Exception(
                'Transaction reference counter error: ' .
                print_r($this->transactionRefCount, true));
        }
    }

    function doTransaction($callback)
    {
        try {
            $this->beginTransaction();
            call_user_func($callback);
            $this->commitTransaction();
        } catch (\Exception $e) {
            $this->rollbackTransaction();
            throw $e;
        }
    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\ManiaScript;

/**
 * @see http://code.google.com/p/manialib/source/browse/trunk/media/maniascript/manialib.xml
 */
abstract class Tools
{

    /**
     * Returns a escaped and quoted string so you can use it a func param.
     * Eg. if you pass ubisoft"nadeo il will return "ubisoft\"nadeo"
     * @return string
     */
    static function quote($string)
    {
        return sprintf('"%s"', self::escapeString($string));
    }

    static function escapeString($string)
    {
        $string = addcslashes($string, '\"');
        $string = str_replace(array("\n", "\r"), array('\n', ''), $string);
        return $string;
    }

    /**
     * Converts a PHP array to a Text[] ManiaScript array (note the type!).
     * Usefull when used with "ManiaScript Framework Actions"
     */
    static function array2maniascript(array $array, $preserveKeys = false)
    {
        if (!$array) {
            // hack because "[]" is not supported and "Text[]" doesnt work yet
            return $preserveKeys ? '[""=>""]' : '[""]';
        }
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                if ($preserveKeys) {
                    $array[$k] = sprintf('"%s"=>%s', self::escapeString($k), self::array2maniascript($v, $preserveKeys));
                } else {
                    $array[$k] = self::array2maniascript($v, $preserveKeys);
                }
            } elseif ($preserveKeys) {
                $array[$k] = sprintf('"%s"=>"%s"', self::escapeString($k), self::escapeString($v));
            } else {
                $array[$k] = sprintf('"%s"', self::escapeString($v));
            }
        }
        return '[' . implode(', ', $array) . ']';
    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Gui\Maniacode;

abstract class Maniacode
{

    public static $domDocument;
    public static $parentNodes;

    /**
     * Loads the Maniacode GUI Toolkit. This should be called before doing anything with the toolkit
     *
     * @param bool True if you don't want to see a message at the end of the execution of the maniacode
     * @param bool Wheter you want to create the root "<maniacode>" element in the XML
     */
    final public static function load($noconfirmation = false,
                                      $createManialinkElement = true)
    {
        self::$domDocument = new \DOMDocument('1.0', 'utf8');
        self::$parentNodes = array();

        if ($createManialinkElement) {
            $maniacode = self::$domDocument->createElement('maniacode');
            if ($noconfirmation)
                $maniacode->setAttribute('noconfirmation', $noconfirmation);
            self::$domDocument->appendChild($maniacode);
            self::$parentNodes[] = $maniacode;
        }
    }

    /**
     * Renders the Maniacode if no return the script will be stopped
     * @param bool Whether you want to return the XML instead of printing it
     * @return mixed The XML string if param true, in other case it returns void
     */
    final public static function render($return = false)
    {
        if ($return) {
            return self::$domDocument->saveXML();
        } else {
            header('Content-Type: text/xml; charset=utf-8');
            echo self::$domDocument->saveXML();
            exit();
        }
    }

    /**
     * Append some XML code to the document
     * @param string $XML The given XML
     */
    static function appendXML($XML)
    {
        $doc = new \DOMDocument('1.0', 'utf8');
        $doc->loadXML($XML);
        $node = self::$domDocument->importNode($doc->firstChild, true);
        end(self::$parentNodes)->appendChild($node);
    }

}


<?php
/*
Copyright 2014 Johan Desmyter <johan@etic.yt>

This file is part of nykopol/gpsd-client.

nykopol/gpsd-client is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

nykopol/gpsd-client is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with nykopol/gpsd-client. If not, see http://www.gnu.org/licenses/
*/

namespace Nykopol\GpsdClient;

/**
 * Client class for GPSD service
 * see : http://catb.org/gpsd/client-howto.html
 */
class Client
{
    /**
     * Host of the service (default: localhost)
     * @var string
     */
    protected $host;

    /**
     * Tcp port (port: 2947)
     * @var int
     */
    protected $port;

    /**
     * Stream
     * @var resource
     */
    protected $stream;

    /**
     * Constructor
     * @param string $host
     * @param int $port
     */
    public function __construct($host = 'localhost', $port = 2947){
        $this->host = $host;
        $this->port = $port;
    }

    public function __destruct() {
        $this->disconnect();
    }

    /**
     * Connect to the service
     * @return string service informations json_decoded
     * @throws Exception
     */
    public function connect(){
        $this->stream = stream_socket_client('tcp://'.$this->host.':'.$this->port, $errno, $errstr, 10);
        if(!$this->stream){
            throw new Exception("Error $errno : $errstr");
        }

        return fgets($this->stream);
    }

    /**
     * Set service watch settings
     *
     * @param bool $enable tell the service to watch or not the devices (default: true)
     * @param string $format the desired format of the returned datas (default: json)
     */
    public function watch($enable = true, $format = 'json'){
        if($enable){
            fwrite($this->stream, '?WATCH={"enable":true,"'.$format.'":true}');
        }else{
            fwrite($this->stream, '?WATCH={"enable":false}');
        }
    }

    /**
     * Get the next message of the given class (TPV, AIS, SKY, ...)
     * @param string $class Classe name of the desired message
     * @param bool $buffer get the next message from buffer or the next one in time
     * @param bool $blocking use stream bocking mode or not (block until next or return null if nothing new)
     * @return
     */
    public function getNext($class, $buffer = false, $blocking = true){

        if(!$buffer && !$blocking){
            throw new \InvalidArgumentException("If the buffer is not used, blocking mode must be enabled.");
        }

        // flush buffer
        if(!$buffer){
            stream_set_blocking($this->stream, 0);
            while(fgets($this->stream)){ }
            stream_set_blocking($this->stream, 1);
        }

        stream_set_blocking($this->stream, $blocking ? 1 : 0);

        // get next message
        while(1){
            $message = fgets($this->stream);
            if(false !== strpos($message, $class)){
                return $message;
            }
        }

    }

    /**
     * Disconnect from the service
     */
    public function disconnect(){
        if($this->stream){
            fclose($this->stream);
        }
    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Gui;

abstract class Element extends Component implements Drawable
{

    const USE_ABSOLUTE_URL = true;

    protected $style;
    protected $subStyle;
    protected $manialink;
    protected $goto;
    protected $manialinkId;
    protected $url;
    protected $urlId;

    /**
     * @deprecated
     */
    protected $maniazone;
    protected $bgcolor;
    protected $bgcolorfocus;
    protected $opacity;

    /**
     * @deprecated
     */
    protected $addPlayerId;
    protected $scriptevents;
    protected $action;
    protected $actionKey;
    protected $image;
    protected $imageid;
    protected $imageFocus;
    protected $imageFocusid;
    // FIXME Change that to static & use late static binding
    protected $xmlTagName = 'xmltag'; // Redeclare this for each child
    protected $xml;

    /**
     * Used by cards, all the elements in that array will be renderd before
     * the post filter.
     * @var array[\ManiaLib\Gui\Element]
     */
    protected $cardElements = array();
    protected $cardElementsHalign = 'left';
    protected $cardElementsValign = 'top';
    protected $cardElementsPosX = 0;
    protected $cardElementsPosY = 0;
    protected $cardElementsPosZ = 0.1;

    /**
     * @var \ManiaLib\Gui\Layouts\AbstractLayout
     */
    protected $cardElementsLayout = null;

    /**
     * Manialink element default constructor. It's common to specify the size of
     * the element in the constructor.
     *
     * @param float Width of the element
     * @param float Height of the element
     */
    function __construct($sizeX = 20, $sizeY = 20)
    {
        $this->sizeX = $sizeX;
        $this->sizeY = $sizeY;
    }

    /**
     * Sets the style of the element. See http://fish.stabb.de/styles/ of the
     * manialink 'example' for more information on Manialink styles.
     * @param string
     */
    function setStyle($style)
    {
        $this->style = $style;
    }

    /**
     * Sets the sub-style of the element. See http://fish.stabb.de/styles/ of
     * the manialink 'example' for more information on Manialink styles.
     * @param string
     */
    function setSubStyle($substyle)
    {
        $this->subStyle = $substyle;
    }

    /**
     * Sets the Manialink of the element. It works as a hyperlink.
     * @param string Can be either a short Manialink or an URL pointing to a
     * Manialink
     */
    function setManialink($manialink)
    {
        $this->manialink = $manialink;
    }

    /**
     * Sets the Manialink id of the element. It works as a hyperlink.
     * @param string Can be either a short Manialink or an URL pointing to a
     * Manialink
     */
    function setManialinkId($manialinkId)
    {
        $this->manialinkId = $manialinkId;
    }

    /**
     * @ignore
     */
    function setGoto($manialink)
    {
        $this->manialink = $manialink;
    }

    /**
     * Sets the hyperlink of the element
     * @param string An URL
     */
    function setUrl($url)
    {
        $this->url = $url;
    }

    /**
     * Sets the hyperlink id of the element
     * @param string An URL
     */
    function setUrlId($urlId)
    {
        $this->urlId = $urlId;
    }

    /**
     * Sets the Maniazones link of the element
     * @param string
     * @deprecated
     */
    function setManiazone($maniazone)
    {
        $this->maniazone = $maniazone;
    }

    function setScriptEvents($scriptEvents = 1)
    {
        $this->scriptevents = $scriptEvents;
    }

    /**
     * @deprecated
     */
    function addPlayerId()
    {
        $this->addPlayerId = 1;
    }

    /**
     * Sets the action of the element. For example, if you use the action "0" in
     * the explorer, it closes the explorer when you click on the element.
     * @param int
     */
    function setAction($action)
    {
        $this->action = $action;
    }

    /**
     * Sets the action key associated to the element. Only works on dedicated
     * servers.
     * @param int
     */
    function setActionKey($actionKey)
    {
        $this->actionKey = $actionKey;
    }

    /**
     * Sets the background color of the element using a 3-digit RGB hexadecimal
     * value. For example, "fff" is white and "000" is black
     * @param string 3-digit RGB hexadecimal value
     */
    function setBgcolor($bgcolor)
    {
        $this->bgcolor = $bgcolor;
        $this->setStyle(null);
        $this->setSubStyle(null);
    }

    function setBgcolorFocus($bgcolor)
    {
        $this->bgcolorfocus = $bgcolor;
        $this->setStyle(null);
        $this->setSubStyle(null);
    }

    /**
     * Set the opacity of a quad or a label
     * @param float $opacity
     */
    function setOpacity($opacity)
    {
        $this->opacity = $opacity;
    }

    /**
     * Applies an image to the element
     * @param string The image filename (or URL)
     * @param bool Whether to prefix the filename with the default images dir URL
     */
    function setImage($image, $absoluteUrl = false)
    {
        $this->setStyle(null);
        $this->setSubStyle(null);
        if (!$absoluteUrl) {
            $this->image = Manialink::$imagesURL . $image;
        } else {
            $this->image = $image;
        }
    }

    /**
     * Set the image id of the element, used for internationalization
     */
    function setImageid($imageid)
    {
        $this->setStyle(null);
        $this->setSubStyle(null);
        $this->imageid = $imageid;
    }

    /**
     * Applies an image to the highlighter state of the element
     * @param string The image filename (or URL)
     * @param bool Whether to prefix the filename with the default images dir URL
     */
    function setImageFocus($imageFocus, $absoluteUrl = false)
    {
        $this->setStyle(null);
        $this->setSubStyle(null);
        if (!$absoluteUrl) {
            $this->imageFocus = Manialink::$imagesURL . $imageFocus;
        } else {
            $this->imageFocus = $imageFocus;
        }
    }

    /**
     * Set the image focus id of the element, used for internationalization
     */
    function setImageFocusid($imageFocusid)
    {
        $this->setStyle(null);
        $this->setSubStyle(null);
        $this->imageFocusid = $imageFocusid;
    }

    /**
     * Returns the style of the element
     * @return string
     */
    function getStyle()
    {
        return $this->style;
    }

    /**
     * Returns the substyle of the element
     * @return string
     */
    function getSubStyle()
    {
        return $this->subStyle;
    }

    /**
     * Returns the Manialink hyperlink of the element
     * @return string
     */
    function getManialink()
    {
        return $this->manialink;
    }

    /**
     * @ignore
     */
    function getGoto()
    {
        return $this->goto;
    }

    /**
     * Returns the Manialink hyperlink id of the element
     * @return string
     */
    function getManialinkId()
    {
        return $this->manialinkId;
    }

    /**
     * Returns the Maniazones hyperlink of the element
     * @return string
     * @deprecated
     */
    function getManiazone()
    {
        return $this->maniazone;
    }

    function getScriptEvents()
    {
        return $this->scriptevents;
    }

    /**
     * Returns the hyperlink of the element
     * @return string
     */
    function getUrl()
    {
        return $this->url;
    }

    /**
     * Returns the hyperlink id of the element
     * @return string
     */
    function getUrlId()
    {
        return $this->urlId;
    }

    /**
     * Returns the action associated to the element
     * @return int
     */
    function getAction()
    {
        return $this->action;
    }

    /**
     * Returns the action key associated to the element
     * @return int
     */
    function getActionKey()
    {
        return $this->actionKey;
    }

    /**
     * Returns whether the elements adds player information parameter to the URL
     * when it's clicked
     * @return boolean
     */
    function getAddPlayerId()
    {
        return $this->addPlayerId;
    }

    /**
     * Returns the background color of the element
     * @return string 3-digit RGB hexadecimal value
     */
    function getBgcolor()
    {
        return $this->bgcolor;
    }

    function getBgcolorFocus()
    {
        return $this->bgcolorfocus;
    }

    function getOpacity()
    {
        return $this->opacity;
    }

    /**
     * Returns the image placed in the element
     * @return string The image URL
     */
    function getImage()
    {
        return $this->image;
    }

    function getImageid()
    {
        return $this->imageid;
    }

    /**
     * Returns the image placed in the element in its highlighted state
     * @return string The image URL
     */
    function getImageFocus()
    {
        return $this->imageFocus;
    }

    function getImageFocusid()
    {
        return $this->imageFocusid;
    }

    /**
     * Imports links and actions from another Manialink element
     * @param \ManiaLib\Gui\Element The source object
     */
    function addLink(\ManiaLib\Gui\Element $object)
    {
        $this->manialink = $object->getManialink();
        $this->url = $object->getUrl();
        $this->maniazone = $object->getManiazone();
        $this->goto = $object->getGoto();
        $this->action = $object->getAction();
        $this->actionKey = $object->getActionKey();
        if ($object->getAddPlayerId()) {
            $this->addPlayerId = 1;
        }
    }

    /**
     * Returns whether the object has a link or an action (either Manialink,
     * Maniazones link, hyperlink or action)
     * @return string
     */
    function hasLink()
    {
        return $this->manialink || $this->url || $this->action || $this->maniazone || $this->scriptevents;
    }

    function setCardElementPosition($posX = 0, $posY = 0, $posZ = 0)
    {
        $this->cardElementsPosX = $posX;
        $this->cardElementsPosY = $posY;
        $this->cardElementsPosZ = $posZ;
    }

    /**
     * @deprecated
     */
    protected function addCardElement(\ManiaLib\Gui\Element $element)
    {
        $this->cardElements[] = $element;
    }

    /**
     * Override this method in subclasses to perform some action before
     * rendering the element
     * @ignore
     */
    protected function preFilter()
    {

    }

    /**
     * Override this method in subclasses to perform some action after rendering
     * the element
     * @ignore
     */
    protected function postFilter()
    {

    }

    final protected function buildXML()
    {
        if (!$this->xmlTagName) {
            return;
        }

        $this->xml = Manialink::createElement($this->xmlTagName);
        $this->getParentNode()->appendChild($this->xml);

        // Add id
        if ($this->id !== null) $this->xml->setAttribute('id', $this->id);

        // Add pos
        if ($this->posX || $this->posY || $this->posZ) {
            $this->xml->setAttribute('posn', $this->posX . ' ' . $this->posY . ' ' . $this->posZ);
        }

        // Add size
        if ($this->sizeX || $this->sizeY) {
            $this->xml->setAttribute('sizen', $this->sizeX . ' ' . $this->sizeY);
        }
        if ($this->scale !== null) $this->xml->setAttribute('scale', $this->scale);

        // Add alignement
        if ($this->halign !== null) $this->xml->setAttribute('halign', $this->halign);
        if ($this->valign !== null) $this->xml->setAttribute('valign', $this->valign);

        // Add styles
        if ($this->style !== null) $this->xml->setAttribute('style', $this->style);
        if ($this->subStyle !== null) $this->xml->setAttribute('substyle', $this->subStyle);
        if ($this->bgcolor !== null) $this->xml->setAttribute('bgcolor', $this->bgcolor);
        if ($this->bgcolorfocus !== null) $this->xml->setAttribute('bgcolorfocus', $this->bgcolorfocus);
        if ($this->opacity !== null) $this->xml->setAttribute('opacity', $this->opacity);

        // Add links
        if (Manialink::$linksEnabled) {
            if ($this->addPlayerId !== null) $this->xml->setAttribute('addplayerid', $this->addPlayerId);
            if ($this->manialink !== null) $this->xml->setAttribute('manialink', $this->manialink);
            if ($this->goto !== null) $this->xml->setAttribute('goto', $this->goto);
            if ($this->manialinkId !== null) $this->xml->setAttribute('manialinkId', $this->manialinkId);
            if ($this->url !== null) $this->xml->setAttribute('url', $this->url);
            if ($this->urlId !== null) $this->xml->setAttribute('urlid', $this->urlId);
            if ($this->maniazone !== null) $this->xml->setAttribute('maniazone', $this->maniazone);

            // Add action
            if ($this->action !== null) $this->xml->setAttribute('action', $this->action);
        }
        if ($this->actionKey !== null) $this->xml->setAttribute('actionkey', $this->actionKey);

        // Add images
        if ($this->image !== null) $this->xml->setAttribute('image', $this->image);
        if ($this->imageid !== null) $this->xml->setAttribute('imageid', $this->imageid);
        if ($this->imageFocus !== null) $this->xml->setAttribute('imagefocus', $this->imageFocus);
        if ($this->imageFocusid !== null) $this->xml->setAttribute('imagefocusid', $this->imageFocusid);

        // Add Script Attributes
        if ($this->id) $this->xml->setAttribute('id', $this->id);
        if ($this->scriptevents !== null) $this->xml->setAttribute('scriptevents', $this->scriptevents);
        if ($this->hidden !== null) $this->xml->setAttribute('hidden', $this->hidden);

        // Add all other attributes
        foreach ($this->attributes as $name => $value) {
            $this->xml->setAttribute($name, $value);
        }
    }

    final protected function handleCardElements()
    {
        if (!$this->cardElements) {
            return;
        }

        // Align relative to the parent elements
        $arr = Tools::getAlignedPos($this, $this->cardElementsHalign, $this->cardElementsValign);
        $x = $arr["x"];
        $y = $arr["y"];

        Manialink::beginFrame(
            $x + $this->cardElementsPosX, $y + $this->cardElementsPosY, $this->posZ + $this->cardElementsPosZ, $this->scale);
        Manialink::beginFrame(0, 0, 0, null, $this->cardElementsLayout);

        foreach ($this->cardElements as $element) {
            $element->save();
        }

        Manialink::endFrame();
        Manialink::endFrame();
    }

    /**
     * Saves the object in the Manialink object stack for further rendering.
     * Thanks to the use of \ManiaLib\Gui\Element::preFilter() and \ManiaLib\Gui\Element::
     * postFilter(), you shouldn't have to override this method
     */
    final function save()
    {
        if ($this->visible === false) {
            return;
        }

        $this->preFilter();

        $layout = $this->getParentLayout();
        if ($layout instanceof Layouts\AbstractLayout) {
            $layout->preFilter($this);
            $layout->updateComponent($this);
        }

        $frame = $this->getParentFrame();
        if ($frame instanceof Elements\Frame) {
            if ($frame->getSizeX()) {
                $x = Tools::getAlignedPosX(0, $frame->getSizeX(), $frame->getHalign('left'), $this->getRelativeHalign('left'));
                $this->incPosX($x);
            }
            if ($frame->getSizeY()) {
                $y = Tools::getAlignedPosY(0, $frame->getSizeY(), $frame->getValign('top'), $this->getRelativeValign('top'));
                $this->incPosY($y);
            }
        }

        $this->buildXML();

        if ($layout instanceof Layouts\AbstractLayout) {
            $layout->postFilter($this);
        }

        $this->handleCardElements();

        $this->postFilter();
    }

}


<?php namespace Arcanedev\LaravelSeo;

/**
 * Class     Seo
 *
 * @package  Arcanedev\LaravelSeo
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 */
class Seo
{
    /* -----------------------------------------------------------------
     |  Constants
     | -----------------------------------------------------------------
     */

    const KEY = 'laravel-seo';

    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Get the seo config.
     *
     * @param  string|null  $key
     * @param  mixed|null   $default
     *
     * @return mixed
     */
    public static function getConfig($key = null, $default = null)
    {
        $key = self::KEY.(is_null($key) ? '' : '.'.$key);

        return config()->get($key, $default);
    }

    /**
     * Set the seo config.
     *
     * @param  string      $key
     * @param  mixed|null  $value
     */
    public static function setConfig($key, $value = null)
    {
        config()->set(self::KEY.'.'.$key, $value);
    }

    /**
     * Get the seo translation.
     *
     * @param  string  $key
     * @param  array   $replace
     * @param  string  $locale
     *
     * @return string
     */
    public static function getTrans($key = null, $replace = [], $locale = null)
    {
        return trans(self::KEY.'::'.$key, $replace, $locale);
    }
}


<?php

namespace Nexmo\Entity;

use ArrayAccess;
use ArrayIterator;
use Countable;
use IteratorAggregate;

/**
 * An Immutable key value pair collection
 *
 * @author Carson Full <carsonfull@gmail.com>
 */
class Collection implements ArrayAccess, Countable, IteratorAggregate
{
    /**
     * @var array
     */
    protected $data;

    /**
     * @param array|Collection $data
     */
    public function __construct($data)
    {
        if ($data instanceof Collection) {
            $data = $data->all();
        }
        $this->data = $data;
    }

    /**
     * Get an item from collection with the given key.
     *
     * @param string $key
     *
     * @return mixed|null
     */
    public function get($key)
    {
        return isset($this->data[$key]) ? $this->data[$key] : null;
    }

    /**
     * Get a list item from collection with given key.
     * If item does not exist an empty array is returned.
     *
     * @param string        $key
     * @param callable|null $callback Optional callable to map items in list
     *
     * @return array
     */
    public function getArray($key, callable $callback = null)
    {
        $list = $this->get($key);
        if (!is_array($list)) {
            return [];
        }
        if (is_callable($callback)) {
            return array_map($callback, $list);
        }
        return $list;
    }

    /**
     * Return whether collection has an item with the given key.
     *
     * @param string $key
     *
     * @return bool
     */
    public function has($key)
    {
        return array_key_exists($key, $this->data);
    }

    /**
     * Return all the items in collection.
     *
     * @return array
     */
    public function all()
    {
        return $this->data;
    }

    /**
     * @inheritdoc
     */
    public function offsetExists($offset)
    {
        return $this->has($offset);
    }

    /**
     * @inheritdoc
     */
    public function offsetGet($offset)
    {
        return $this->get($offset);
    }

    /**
     * @inheritdoc
     */
    public function offsetSet($offset, $value)
    {
    }

    /**
     * @inheritdoc
     */
    public function offsetUnset($offset)
    {
    }

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

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


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Utils;

/*
 * Info: pattern (?<!\$)((?:\$\$)*) match an even number of $
 */
abstract class Formatting
{
    /**
     * Removes each single character code in $codes string
     * Adding l, h or p will also strip links
     * Adding an hexadecimal char will also strip colors
     */
    static function stripCodes($string, $codes)
    {
        if (preg_match('/[hlp]/iu', $codes))
            $string = self::stripLinks($string);
        if (preg_match('/[0-9a-f]/iu', $codes))
            $string = self::stripColors($string);
        return preg_replace('/(?<!\$)((?:\$\$)*)\$[' . $codes . ']/iu', '$1', $string);
    }

    /**
     * Removes wide, bold and shadowed
     */
    static function stripWideFonts($string)
    {
        return self::stripCodes($string, 'wos');
    }

    /**
     * Removes links
     */
    static function stripLinks($string)
    {
        return preg_replace('/(?<!\$)((?:\$\$)*)\$[hlp](?:\[.*?\]|\[.*?$)?(.*?)(?:\$[hlp]|(\$z)|$)/iu', '$1$2$3', $string);
    }

    /**
     * Removes colors
     */
    static function stripColors($string)
    {
        return preg_replace('/(?<!\$)((?:\$\$)*)\$(?:g|[0-9a-f][^\$]{0,2})/iu', '$1', $string);
    }

    /**
     * Removes all styles
     */
    static function stripStyles($string)
    {
        $string = preg_replace('/(?<!\$)((?:\$\$)*)\$[^$0-9a-hlp]/iu', '$1', $string);
        $string = self::stripLinks($string);
        $string = self::stripColors($string);
        return $string;
    }

    static function contrastColors($string, $background)
    {
        $background = Color::StringToRgb24($background);
        return preg_replace_callback('/(?<!\$)((?:\$\$)*)(\$[0-9a-f][^\$]{0,2})/iu',
            function ($matches) use ($background) {
                $color = Color::StringToRgb24($matches[2]);
                $color = Color::Contrast($color, $background);
                $color = Color::Rgb24ToRgb12($color);
                $color = Color::Rgb12ToString($color);
                return $matches[1] . '$' . $color;
            }, $string);
    }
}


<?php namespace Arcanedev\LaravelSeo\Models;

use Arcanedev\LaravelSeo\Entities\RedirectStatuses;
use Arcanedev\LaravelSeo\Seo;
use Symfony\Component\HttpFoundation\Response;

/**
 * Class     Redirect
 *
 * @package  Arcanedev\LaravelSeo\Models
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 *
 * @property  int             id
 * @property  string          old_url
 * @property  string          new_url
 * @property  int             status
 * @property  string          status_name
 * @property  \Carbon\Carbon  created_at
 * @property  \Carbon\Carbon  updated_at
 */
class Redirect extends AbstractModel
{
    /* -----------------------------------------------------------------
     |  Properties
     | -----------------------------------------------------------------
     */

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['old_url', 'new_url', 'status'];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'status' => 'integer',
    ];

    /* -----------------------------------------------------------------
     |  Constructor
     | -----------------------------------------------------------------
     */

    /**
     * Meta constructor.
     *
     * @param  array  $attributes
     */
    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);

        $this->setTable(Seo::getConfig('redirects.table', 'redirects'));
    }

    /**
     * The "booting" method of the model.
     */
    public static function boot()
    {
        parent::boot();

        // Extract these methods to Event/Listener Classes
        static::saved(function() {
            static::clearCache();
        });

        static::deleted(function() {
            static::clearCache();
        });
    }

    /* -----------------------------------------------------------------
     |  Getters & Setters
     | -----------------------------------------------------------------
     */

    /**
     * Get the `status_name` attribute.
     *
     * @return string
     */
    public function getStatusNameAttribute()
    {
        return RedirectStatuses::get($this->status);
    }

    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Create a redirect url.
     *
     * @param  string  $oldUrl
     * @param  string  $newUrl
     * @param  int     $status
     *
     * @return \Arcanedev\LaravelSeo\Models\Redirect
     */
    public static function createOne($oldUrl, $newUrl, $status = Response::HTTP_MOVED_PERMANENTLY)
    {
        $redirect = new self([
            'old_url' => $oldUrl,
            'new_url' => $newUrl,
            'status'  => $status,
        ]);

        $redirect->save();

        return $redirect;
    }

    /* -----------------------------------------------------------------
     |  Other Methods
     | -----------------------------------------------------------------
     */

    /**
     * Clear the cached data.
     */
    protected static function clearCache()
    {
        cache()->forget(
            Seo::getConfig('redirector.drivers.eloquent.options.cache.key', 'seo-redirects')
        );
    }
}


<?php namespace Arcanedev\LaravelSeo\Providers;

use Arcanedev\LaravelSeo\Http\Middleware\RedirectsMissingPages;
use Arcanedev\LaravelSeo\Seo;
use Arcanedev\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Contracts\Http\Kernel as HttpKernel;

/**
 * Class     RouteServiceProvider
 *
 * @package  Arcanedev\LaravelSeo\Providers
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 */
class RouteServiceProvider extends ServiceProvider
{
    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Bootstrap any application services.
     */
    public function boot()
    {
        if (Seo::getConfig('redirector.enabled', false))
            $this->app->make(HttpKernel::class)->pushMiddleware(RedirectsMissingPages::class);

        parent::boot();
    }
}


<?php

namespace Nexmo\Service;

use Nexmo\Entity;
use Nexmo\Entity\MatchingStrategy;
use Nexmo\Exception;

/**
 * Account management APIs
 *
 * @property-read Account\Balance $balance
 * @property-read Account\Numbers $numbers
 * @property-read Account\Pricing $pricing
 *
 * @author Carson Full <carsonfull@gmail.com>
 */
class Account extends ResourceCollection
{
    /**
     * Returns the balance in euros
     *
     * @return float
     * @throws Exception
     */
    public function balance()
    {
        return $this->balance->invoke();
    }

    /**
     * Get all inbound numbers associated with your Nexmo account
     *
     * @param int $index                Page index
     * @param int $size                 Page size (max 100)
     * @param int $pattern              A matching pattern
     * @param int $searchPattern        Strategy for matching pattern.
     *                                  0 = starts with
     *                                  1 = anywhere
     *                                  2 = ends with
     *
     * @return Entity\NumberCollection|Entity\Number[]
     * @throws Exception
     */
    public function numbers($index = 1, $size = 10, $pattern = null, $searchPattern = MatchingStrategy::STARTS_WITH)
    {
        return $this->numbers->invoke($index, $size, $pattern, $searchPattern);
    }
}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Cache;

const APC = 'apc';
const MEMCACHE = 'memcache';
const MEMCACHED = 'memcached';
const MYSQL = 'mysql';
const NONE = 'nocache';

/**
 * La classe qu'on a du mal à la trouver
 */
abstract class Cache
{

    /**
     * Factory for getting instances on cache objects.
     * You specify the driver to use as a parameter, and
     * it automatically falls back to the "NoCache" driver
     * if not found
     * @return \ManiaLib\Cache\CacheInterface
     */
    static function factory($driver = null)
    {
        try {
            switch ($driver) {
                case APC:
                    return static::getDriver('APC');
                case MEMCACHED:
                    try {
                        return static::getDriver('Memcached');
                    } catch (Exception $e) {
                        return static::getDriver('Memcache');
                    }
                case MEMCACHE:
                    return static::getDriver('Memcache');
                case MYSQL:
                    return static::getDriver('MySQL');
                default:
                    throw new Exception();
            }
        } catch (Exception $e) {
            $config = Config::getInstance();
            $driver = $config->fallbackDriver ?: 'NoCache';
            return static::getDriver($driver);
        }
    }

    /**
     * Returns a unique prefix to avoid cache collisions
     * between several applications
     * @return string
     */
    static function getPrefix()
    {
        return crc32(__FILE__) . '_';
    }

    protected static function getDriver($driver)
    {
        $className = __NAMESPACE__ . '\\Drivers\\' . $driver;
        if (!class_exists($className)) {
            throw new Exception(sprintf('Cache driver %s does not exist', $className));
        }
        return call_user_func(array($className, 'getInstance'));
    }

}


<?php

namespace Nexmo\Service\Account\Pricing;

use Nexmo\Entity;
use Nexmo\Exception;
use Nexmo\Service\Service;

/**
 * Retrieve Nexmo's outbound SMS/Voice pricing for a given phone number.
 *
 * @author Carson Full <carsonfull@gmail.com>
 */
class Phone extends Service
{
    /**
     * @var string
     */
    protected $product;

    /**
     * @inheritdoc
     */
    public function getEndpoint()
    {
        return 'account/get-phone-pricing/outbound/' . $this->product;
    }

    /**
     * @param string $product
     * @param string $phone
     *
     * @return Entity\PricingPhone
     * @throws Exception
     */
    public function invoke($product = null, $phone = null)
    {
        if (!$product) {
            throw new Exception('$product parameter cannot be blank');
        }
        if (!in_array($product, ['sms', 'voice'], true)) {
            throw new Exception('$product parameter must be "sms" or "voice"');
        }
        if (!$phone) {
            throw new Exception('$phone parameter cannot be blank');
        }
        $this->product = $product;
        return new Entity\PricingPhone($this->exec([
            'phone' => $phone,
        ]));
    }

    /**
     * @inheritdoc
     */
    protected function validateResponse(array $json)
    {
        if (!isset($json['country-code'])) {
            throw new Exception('country-code property expected');
        }
        if (!isset($json['phone'])) {
            throw new Exception('phone property expected');
        }
        if (!isset($json['price'])) {
            throw new Exception('price property expected');
        }
    }
}


<?php
namespace Nexmo\Service\Number;

use Nexmo\Entity\MatchingStrategy;
use Nexmo\Entity\NumberCollection;
use Nexmo\Exception;
use Nexmo\Service\Service;

class Search extends Service
{
    /**
     * @inheritdoc
     */
    public function getRateLimit()
    {
        // Max number of requests per second. Nexmo developer API claims 3/sec max, but actually more than 2/sec causes error 429 Too Many Requests.
        return 2;
    }

    /**
     * @inheritdoc
     */
    public function getEndpoint()
    {
        return 'number/search';
    }

    /**
     * @param int        $index
     * @param int        $size
     * @param string|int $pattern
     * @param int        $searchPattern
     *
     * @return NumberCollection
     * @throws Exception
     */
    public function invoke($country = null, $index = 1, $size = 10, $pattern = null, $searchPattern = MatchingStrategy::STARTS_WITH, $features = 'SMS')
    {
        if (!$country) {
            throw new Exception("\$country parameter cannot be blank");
        }

        $size = min($size, 100);

        return new NumberCollection($this->exec([
            // Nexmo API requires $country value to be uppercase.
            'country' => strtoupper($country),
            'index' => $index,
            'size' => $size,
            'pattern' => $pattern,
            'search_pattern' => $searchPattern,
            'features' => $features,
        ]));
    }

    /**
     * @inheritdoc
     */
    protected function validateResponse(array $json)
    {
        // If the 'numbers' element exists (which it won't if no numbers are available for a search), validate it is an array.
        if (isset($json['numbers']) && !is_array($json['numbers'])) {
            throw new Exception('numbers property not an array');
        }
    }
}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Gui;

abstract class Manialink
{

    const DEFAULT_BACKGROUND = 1;
    const HIDE_BACKGROUND = 0;
    const STARS_BACKGROUND = 'stars';
    const STATIONS_BACKGROUND = 'stations';
    const TITLE_BACKGROUND = 'title';

    /**
     * @var \DOMDocument
     */
    public static $domDocument;

    /**
     * @var \DOMNode[]
     */
    public static $parentNodes;

    /**
     * @var Layouts\AbstractLayout[]
     */
    public static $parentLayouts;

    /**
     * @var Elements\Frame[]
     */
    public static $parentFrames;
    public static $linksEnabled = true;
    public static $langsURL;
    public static $imagesURL;
    public static $mediaURL;

    /**
     * Loads the Manialink GUI toolkit. This should be called before doing
     * anything with the toolkit.
     * @param bool Whether you want to create the root "<manialink>" element in the XML
     */
    final public static function load($root = true, $timeout = 0, $version = 1, $background = self::DEFAULT_BACKGROUND, $navigable3d = false)
    {
        if (class_exists('\ManiaLib\Application\Config')) {
            $config = \ManiaLib\Application\Config::getInstance();
            self::$langsURL = $config->getLangsURL();
            self::$imagesURL = $config->getImagesURL();
            self::$mediaURL = $config->getMediaURL();
        }

        // Load the XML object
        self::$domDocument = new \DOMDocument('1.0', 'utf-8');
        self::$parentNodes = array();
        self::$parentLayouts = array();
        self::$parentFrames = array();

        if ($root) {
            $nodeManialink = self::$domDocument->createElement('manialink');
            $nodeManialink->setAttribute('version', $version);
            $nodeManialink->setAttribute('background', $background);
            $nodeManialink->setAttribute('navigable3d', (int)$navigable3d);
            self::$domDocument->appendChild($nodeManialink);
            self::$parentNodes[] = $nodeManialink;

            $nodeTimeout = self::$domDocument->createElement('timeout');
            $nodeManialink->appendChild($nodeTimeout);
            $nodeTimeout->nodeValue = $timeout;
        } else {
            $frame = self::$domDocument->createElement('frame');
            self::$domDocument->appendChild($frame);
            self::$parentNodes[] = $frame;
        }
    }

    /**
     * Renders the Manialink
     * @param boolean Wehther you want to return the XML instead of printing it
     */
    final public static function render($return = false)
    {
        if ($return) {
            return self::$domDocument->saveXML();
        } else {
            header('Content-Type: text/xml; charset=utf-8');
            echo self::$domDocument->saveXML();
        }
    }

    /**
     * Creates a new Manialink frame, with an optionnal associated layout
     *
     * @param float X position
     * @param float Y position
     * @param float Z position
     * @param float Scale (default is null or 1)
     * @param \ManiaLib\Gui\Layouts\AbstractLayout The optionnal layout associated with the frame. If
     * you pass a layout object, all the items inside the frame will be
     * positionned using constraints defined by the layout
     */
    final public static function beginFrame($x = 0, $y = 0, $z = 0, $scale = null,
                                            \ManiaLib\Gui\Layouts\AbstractLayout $layout = null)
    {
        $frame = new Elements\Frame();
        $frame->setPosition($x, $y, $z);
        $frame->setScale($scale);
        if ($layout instanceof Layouts\AbstractLayout) {
            $frame->setLayout($layout);
        }
        $frame->buildXML();

        self::$parentFrames[] = $frame;
        self::$parentNodes[] = $frame->getDOMElement();
        self::$parentLayouts[] = $frame->getLayout();
    }

    /**
     * Closes the current Manialink frame
     */
    final public static function endFrame()
    {
        if (!end(self::$parentNodes)->hasChildNodes()) {
            end(self::$parentNodes)->nodeValue = ' ';
        }
        array_pop(self::$parentNodes);
        array_pop(self::$parentLayouts);
        $frame = array_pop(self::$parentFrames);
        $frame->save();
    }

    final static function setFrameId($id)
    {
        end(self::$parentFrames)->setId($id);
    }

    final static function setFrameScriptEvents($scriptEvents = 1)
    {
        $frame = end(self::$parentNodes);
        $frame->setAttribute('scriptevents', $scriptEvents);
    }

    /**
     * Redirects the user to the specified Manialink
     */
    final public static function redirect($link, $render = true)
    {
        self::$domDocument = new \DOMDocument('1.0', 'utf-8');
        self::$parentNodes = array();
        self::$parentLayouts = array();

        $redirect = self::$domDocument->createElement('redirect');
        $redirect->appendChild(self::$domDocument->createTextNode($link));
        self::$domDocument->appendChild($redirect);
        self::$parentNodes[] = $redirect;

        if ($render) {
            if (ob_get_contents()) {
                ob_clean();
            }
            header('Content-Type: text/xml; charset=utf-8');
            echo self::$domDocument->saveXML();
        } else {
            return self::$domDocument->saveXML();
        }
    }

    static function createElement($tagName)
    {
        return self::$domDocument->createElement($tagName);
    }

    static function comment($comment)
    {
        end(self::$parentNodes)->appendChild(self::$domDocument->createComment($comment));
    }

    /**
     * Append some XML code to the document
     * @param string Some XML code
     */
    static function appendXML($XML)
    {
        $doc = new \DOMDocument('1.0', 'utf-8');
        $doc->loadXML($XML);
        $node = self::$domDocument->importNode($doc->firstChild, true);
        end(self::$parentNodes)->appendChild($node);
    }

    static function appendScript($maniaScript)
    {
        $script = self::$domDocument->createElement('script');
        $script->appendChild(self::$domDocument->createTextNode($maniaScript));
        end(self::$parentNodes)->appendChild($script);
    }

    /**
     * Disable all Manialinks, URLs and actions of GUIElement objects as long as it is disabled
     */
    static function disableLinks()
    {
        self::$linksEnabled = false;
    }

    /**
     * Enable links
     */
    static function enableLinks()
    {
        self::$linksEnabled = true;
    }

}


<?php namespace Arcanedev\LaravelSeo;

use Arcanedev\LaravelSeo\Contracts\RedirectorFactory;
use Illuminate\Support\Manager;

/**
 * Class     RedirectorManager
 *
 * @package  Arcanedev\LaravelSeo
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 */
class RedirectorManager extends Manager implements RedirectorFactory
{
    /* -----------------------------------------------------------------
     |  Getters & Setters
     | -----------------------------------------------------------------
     */

    /**
     * Get the default driver name.
     *
     * @return string
     */
    public function getDefaultDriver()
    {
        return Seo::getConfig('redirector.default', 'config');
    }

    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Get a driver instance.
     *
     * @param  string  $driver
     *
     * @return \Arcanedev\LaravelSeo\Contracts\Redirector
     */
    public function driver($driver = null)
    {
        return parent::driver($driver);
    }

    /**
     * Build the config redirector driver.
     *
     * @return \Arcanedev\LaravelSeo\Redirectors\ConfigurationRedirector
     */
    public function createConfigDriver()
    {
        return $this->buildDriver('config');
    }

    /**
     * Build the eloquent redirector driver.
     *
     * @return \Arcanedev\LaravelSeo\Redirectors\EloquentRedirector
     */
    public function createEloquentDriver()
    {
        return $this->buildDriver('eloquent', [
            'model' => Seo::getConfig('redirects.model'),
        ]);
    }

    /* -----------------------------------------------------------------
     |  Other Methods
     | -----------------------------------------------------------------
     */

    /**
     * Build the redirector.
     *
     * @param  string  $driver
     * @param  array   $extra
     *
     * @return mixed
     */
    private function buildDriver($driver, array $extra = [])
    {
        $router  = $this->app->make(\Illuminate\Contracts\Routing\Registrar::class);
        $class   = Seo::getConfig("redirector.drivers.$driver.class");
        $options = Seo::getConfig("redirector.drivers.$driver.options", []);

        return new $class($router, array_merge($extra, $options));
    }
}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Gui\Layouts;

/**
 * Abstract class used for building layouts
 */
abstract class AbstractLayout extends \ManiaLib\Gui\Component
{

    public $xIndex = 0;
    public $yIndex = 0;
    public $zIndex = 0;
    protected $marginWidth;
    protected $marginHeight;
    protected $borderWidth;
    protected $borderHeight;

    /**
     * Default constructor is used to set the size of the layout, just like
     * \ManiaLib\Gui\Element
     * @param float Layout's width
     * @param float Layout's height
     */
    function __construct($sizeX = 20, $sizeY = 20)
    {
        $this->sizeX = $sizeX;
        $this->sizeY = $sizeY;
    }

    /**
     * Sets the horizontal margin between two elements of the layout
     * @param float
     */
    function setMarginWidth($marginWidth)
    {
        $this->marginWidth = $marginWidth;
    }

    /**
     * Sets the vertical margin between two elements of the layout
     * @param float
     */
    function setMarginHeight($marginHeight)
    {
        $this->marginHeight = $marginHeight;
    }

    /**
     * Sets the margin between two elements of the layout
     * @param Horizontal margin
     * @param Vertical margin
     */
    function setMargin($marginWidth = 0, $marginHeight = 0)
    {
        $this->marginWidth = $marginWidth;
        $this->marginHeight = $marginHeight;
    }

    /**
     * Returns the horizontal margin between two elements of the layout
     * @return float
     */
    function getMarginWidth()
    {
        return $this->marginWidth;
    }

    /**
     * Returns the vertical margin between two elements of the layout
     * @return float
     */
    function getMarginHeight()
    {
        return $this->marginHeight;
    }

    /**
     * Sets the width between the layout outer border and its content
     * @param float
     */
    function setBorderWidth($borderWidth)
    {
        $this->borderWidth = $borderWidth;
        $this->xIndex = $borderWidth;
    }

    /**
     * Sets the height between the layout outer border and its content
     * @param float
     */
    function setBorderHeight($borderHeight)
    {
        $this->borderHeight = $borderHeight;
        $this->yIndex = -$borderHeight;
    }

    /**
     * Sets the gap between the layout outer border and its content
     * @param Border width
     * @param Border height
     */
    function setBorder($borderWidth = 0, $borderHeight = 0)
    {
        $this->borderWidth = $borderWidth;
        $this->xIndex = $borderWidth;
        $this->borderHeight = $borderHeight;
        $this->yIndex = -$borderHeight;
    }

    /**
     * Returns the width between the layout outer border and its content
     * @return float
     */
    function getBorderWidth()
    {
        return $this->borderWidth;
    }

    /**
     * Returns the height between the layout outer border and its content
     * @return float
     */
    function getBorderHeight()
    {
        return $this->borderHeight;
    }

    final function updateComponent(\ManiaLib\Gui\Component $item)
    {
        $item->incPosX($this->xIndex);
        $item->incPosY($this->yIndex);
        $item->incPosZ($this->zIndex);
    }

    /**
     * Override this method to perform an action before rendering an item.
     * Typical use: look for overflow
     */
    function preFilter(\ManiaLib\Gui\Component $item)
    {

    }

    /**
     * Override this method to perform an action after rendering an an item.
     * Typical use: update x,y,z indexes for the next item
     */
    function postFilter(\ManiaLib\Gui\Component $item)
    {

    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Application\Tracking;

use ManiaLib\Utils\Arrays;

/**
 * Google Analytics tracking in Manialinks
 */
class GoogleAnalytics
{

    const GA_TRACKING_URL = 'http://www.google-analytics.com/__utm.gif';

    /**
     * @var \ManiaLib\Gui\Elements\Quad
     */
    public $trackingQuad;

    /**
     * Urchin version
     */
    public $utmwv = '4.8.6';

    /**
     * Hostname
     */
    public $utmhn;

    /**
     * Charsert
     */
    public $utmcs = 'UTF-8';

    /**
     * Screen resolution
     */
    public $utmsr = '-';

    /**
     * Color-depth
     */
    public $utmsc = '-';

    /**
     * Language
     */
    public $utmul;

    /**
     * Java enabled
     */
    public $utmje = 0;

    /**
     * Flash version
     */
    public $utmfl = 0;

    /**
     * Random
     */
    public $utmhid;

    /**
     * Referer
     */
    public $utmr = 0;

    /**
     * Route
     */
    public $utmp;

    /**
     * Google Analytics account
     */
    public $utmac;

    /**
     * Random
     */
    public $utmn;

    /**
     * @see http://stackoverflow.com/questions/6236895/what-is-utmu-parameter-in-google-analytics-utm-gif-request
     */
    public $utmu = null;

    /**
     * Carriage return (?)
     */
    public $utmcr = 1;

    /**
     * Document title
     */
    public $utmdt;

    /**
     * Cookie
     */
    public $utmcc;

    /**
     * Cookie var
     */
    public $__utma;

    /**
     * Cookie var
     */
    public $__utmb;

    /**
     * Cookie var
     */
    public $__utmc;

    /**
     * Cookie var
     */
    public $__utmz;

    /**
     * Event tracking
     */
    public $utme;
    protected $domainHash;
    protected $visitorId;
    protected $cookieNameSuffix;

    function __construct($account, $cookieNameSuffix = null, $domainName = null)
    {
        $this->utmac = $account;
        $this->cookieNameSuffix = $cookieNameSuffix;
        $this->utmhid = rand(1000000000, 9999999999);
        $this->utmn = rand(1000000000, 9999999999);
        $this->utmul = Arrays::get($_SERVER, 'HTTP_ACCEPT_LANGUAGE');
        $this->utmr = Arrays::get($_SERVER, 'HTTP_REFERER');
        $this->utmhn = $domainName ?: Arrays::get($_SERVER, 'HTTP_HOST');
        $this->utmp = Arrays::get($_SERVER, 'REQUEST_URI');
    }

    /**
     * Loads cookie information
     * @see http://services.google.com/analytics/breeze/en/ga_cookies/index.html
     */
    function loadCookie()
    {
        $domainHash = $this->getDomainHash();
        $cookieRandom = rand(1000000000, 2147483647); //number under 2147483647

        $cookieUtma = '__utma' . $this->cookieNameSuffix;
        $cookieUtmb = '__utmb' . $this->cookieNameSuffix;
        $cookieUtmc = '__utmc' . $this->cookieNameSuffix;
        $cookieUtmz = '__utmz' . $this->cookieNameSuffix;

        $utma = Arrays::get($_COOKIE, $cookieUtma, '');
        $utma = $utma ? explode('.', $utma) : array();

        $utmb = Arrays::get($_COOKIE, $cookieUtmb, '');
        $utmb = $utmb ? explode('.', $utmb) : array();

        $utmc = Arrays::get($_COOKIE, $cookieUtmc, '');
        $utmc = $utmc ? explode('.', $utmc) : array();

        $utmz = array();

        $utma[0] = $domainHash; // Domain hash
        $utma[1] = Arrays::get($utma, 1, $cookieRandom); // Random unique ID
        $utma[2] = Arrays::get($utma, 2, time()); // Time of initial visit
        $utma[3] = Arrays::get($utma, 3, time()); // Begining of previous session
        $utma[4] = Arrays::get($utma, 4, time()); // Begining of current session
        $utma[5] = Arrays::get($utma, 5, 0); // Session counter

        if (!$utmb || !$utmc) {
            // New session has started
            $utma[5]++;
            $utma[3] = $utma[4];
            $utma[4] = time();
        }

        $utmb[0] = $domainHash;

        $utmc[0] = $domainHash;

        $utmz[0] = $domainHash; // Domain hash
        $utmz[1] = time(); // Timestamp
        $utmz[2] = $utma[5]; // Session number
        $utmz[3] = 1; // Campaign number
        $utmz[4] = // Campaign information
            'utmcsr=(direct)|' .//utm_source
            'utmccn=(direct)|' .//utm_campaign
            'utmcmd=(none)'; //utm_medium'

        $__utma = implode('.', $utma);
        $__utmb = implode('.', $utmb);
        $__utmc = implode('.', $utmc);
        $__utmz = implode('.', $utmz);

        setcookie($cookieUtma, $__utma, strtotime('+2 years'));
        setcookie($cookieUtmb, $__utmb, strtotime('+30 minutes'));
        setcookie($cookieUtmc, $__utmb, 0);
        setcookie($cookieUtmz, $__utmz, strtotime('+6 months'));

        $this->__utma = $__utma . ';';
        $this->__utmb = $__utmb . ';';
        $this->__utmc = $__utmc . ';';
        $this->__utmz = $__utmz . ';';
    }

    /**
     * Computes the tracking URL and returns it. Its is a 1*1 gif image that
     * should be called by the client.
     * @return string
     */
    function getTrackingURL()
    {
        $params = array(
            'utmwv' => $this->utmwv,
            'utmhn' => $this->utmhn,
            'utmcs' => $this->utmcs,
            'utmsr' => $this->utmsr,
            'utmsc' => $this->utmsc,
            'utmul' => $this->utmul,
            'utmje' => $this->utmje,
            'utmfl' => $this->utmfl,
            'utmhid' => $this->utmhid,
            'utmr' => $this->utmr,
            'utmp' => $this->utmp,
            'utmac' => $this->utmac,
            'utmn' => $this->utmn,
            'utmu' => $this->utmu,
            'utmcr' => $this->utmcr,
            'utmdt' => $this->utmdt,
            'utmcc' =>
                '__utma=' . $this->__utma . '+' .
//					'__utmb='.$this->__utmb.'+'.
//					'__utmc='.$this->__utmc.'+'.
                '__utmz=' . $this->__utmz
        );

        return self::GA_TRACKING_URL . '?' . http_build_query($params);
    }

    // FIXME ManiaLib If anyone knows how to encode data in Google Analytics's utme param' we'd be glad to hear :)
    /**
     * Experimentation about using Event Tracking in manialinks.
     * Because I don't know the exact algorithm to encode data in utme, you should
     * only use alphanumeric chars in the parameters for now.
     * To quote official doc: "Value is encoded. Used for events and custom variables."
     *
     * @see https://developers.google.com/analytics/resources/articles/gaTrackingTroubleshooting#gifParameters
     * @beta
     */
    function getEventTrackingURL($category, $action, $label, $value = null)
    {
        $this->utme = sprintf('5(%s*%s*%s)', $category, $action, $label);
        if ($value !== null) {
            $this->utme .= sprintf('(%d)', $value);
        }

        $params = array(
            'utmwv' => $this->utmwv,
            //'utms' => null ?
            'utmn' => $this->utmn,
            'utmhn' => $this->utmhn,
            'utmt' => 'event',
            'utme' => $this->utme,
            'utmcs' => $this->utmcs,
            'utmsr' => $this->utmsr,
            //'utmvp' => $this->utmvp, view port resolution
            'utmsc' => $this->utmsc,
            'utmul' => $this->utmul,
            'utmje' => $this->utmje,
            'utmfl' => $this->utmfl,
            'utmdt' => $this->utmdt,
            'utmhid' => $this->utmhid,
            'utmr' => $this->utmr,
            'utmp' => $this->utmp,
            'utmac' => $this->utmac,
            'utmcc' =>
                '__utma=' . $this->__utma . '+' .
//					'__utmb='.$this->__utmb.'+'.
//					'__utmc='.$this->__utmc.'+'.
                '__utmz=' . $this->__utmz,
        );

        return self::GA_TRACKING_URL . '?' . http_build_query($params);
    }

    protected function getDomainHash()
    {
        if (!$this->domainHash) {
            $domain = $this->utmhn;
            if (!$domain) {
                return 1;
            }
            $h = 0;
            $g = 0;
            $length = strlen($domain) - 1;
            for ($i = $length; $i >= 0; $i--) {
                $c = (int)(ord($domain[$i]));
                $h = (($h << 6) & 0xfffffff) + $c + ($c << 14);
                $g = ($h & 0xfe00000);
                if ($g != 0) $h = ($h ^ ($g >> 21));
            }
            $this->domainHash = $h;
        }
        return $this->domainHash;
    }

}


<?php
/**
 * ManiaLib - Lightweight PHP framework for Manialinks
 *
 * @see         http://code.google.com/p/manialib/
 * @copyright   Copyright (c) 2009-2011 NADEO (http://www.nadeo.com)
 * @license     http://www.gnu.org/licenses/lgpl.html LGPL License 3
 * @version     $Revision$:
 * @author      $Author$:
 * @date        $Date$:
 */

namespace ManiaLib\Utils;

class StyleParser
{
    /**
     * Constants to represent a style using a bit mask, color is on the 12 right bits
     */
    const COLORED = 0x1000;
    const ITALIC = 0x2000;
    const BOLD = 0x4000;
    const SHADOWED = 0x8000;
    const CAPITALIZED = 0x10000;
    const WIDE = 0x20000;
    const NARROW = 0x40000;

    static private $gameProtocol = 'maniaplanet';
    static private $contrast = Color::CONTRAST_AUTO;
    static private $background = null;
    static private $fonts = array();

    static function getGameProtocol()
    {
        return self::$gameProtocol;
    }

    static function setGameProtocol($protocol)
    {
        self::$gameProtocol = $protocol;
    }

    static function getContrast()
    {
        return self::$contrast;
    }

    /**
     * Colors which are too similar to the background will stay as they are
     */
    static function contrastDisable()
    {
        self::$contrast = null;
    }

    /**
     * Colors which are too similar to the background will be automaically contrasted
     */
    static function contrastAuto()
    {
        self::$contrast = Color::CONTRAST_AUTO;
    }

    /**
     * Colors which are too similar to the background will be always made darker
     */
    static function contrastForceDarker()
    {
        self::$contrast = Color::CONTRAST_DARKER;
    }

    /**
     * Colors which are too similar to the background will be always made darker
     */
    static function contrastForceLighter()
    {
        self::$contrast = Color::CONTRAST_LIGHTER;
    }

    static function getBackground()
    {
        return self::$background;
    }

    /**
     * Set the background color for contrasting colors
     */
    static function setBackground($background)
    {
        self::$background = Color::StringToRgb24($background);
    }

    /**
     * Declare a font to use with onImage function
     */
    static function declareFont($name, $normal, $bold = null, $italic = null, $boldItalic = null)
    {
        self::$fonts[$name] = array(
            0 => $normal,
            StyleParser::BOLD => $bold ?: $normal,
            StyleParser::ITALIC => $italic ?: $normal,
            StyleParser::BOLD | StyleParser::ITALIC => $boldItalic ?: ($bold ?: ($italic ?: $normal))
        );
    }

    static function getFont($name, $style)
    {
        if (isset(self::$fonts[$name]))
            return self::$fonts[$name][$style];
        return null;
    }

    /**
     * Get the html code of a string with style codes
     */
    static function toHtml($string)
    {
        return implode('', self::parseString($string));
    }

    /**
     * Draw a string with on an image, method will be choose depending on the size wanted
     * @param string $string The style-coded string to draw
     * @param imageResource $image The image to draw on
     * @param string $fontName The TTF font to use, which has been declared previously
     * @param int $x X position
     * @param int $y Y position
     * @param int $size Font size
     * @param string $defaultColor Default text color in 3 or 6 hexadecimal characters
     */
    static function onImage($string, $image, $fontName, $x = 0, $y = 0, $size = 10, $defaultColor = '000')
    {
        if ($size <= 5)
            self::onImageQuality($string, $image, $fontName, $x, $y, $size, $defaultColor, 3);
        else if ($size <= 10)
            self::onImageQuality($string, $image, $fontName, $x, $y, $size, $defaultColor, 2);
        else if ($size <= 20)
            self::onImageQuality($string, $image, $fontName, $x, $y, $size, $defaultColor, 1);
        else
            self::onImageFast($string, $image, $fontName, $x, $y, $size, $defaultColor);
    }

    /**
     * Draw a string with on an image using fast method. There can be glitches when using small sizes
     * @param string $string The style-coded string to draw
     * @param imageResource $image The image to draw on
     * @param string $fontName The TTF font to use, which has been declared previously
     * @param int $x X position
     * @param int $y Y position
     * @param int $size Font size
     * @param string $defaultColor Default text color in 3 or 6 hexadecimal characters
     */
    static function onImageFast($string, $image, $fontName, $x = 0, $y = 0, $size = 10, $defaultColor = '000')
    {
        $defaultColor = Color::StringToRgb24($defaultColor);

        $xOffset = 0;
        foreach (self::parseString($string) as $token)
            $xOffset += $token->onImage($image, $fontName, $x + $xOffset, $y, $size, $defaultColor, 1);
    }

    /**
     * Draw a string with on an image using quality method. Slow with big text size
     * @param string $string The style-coded string to draw
     * @param imageResource $image The image to draw on
     * @param string $fontName The TTF font to use, which has been declared previously
     * @param int $x X position
     * @param int $y Y position
     * @param int $size Font size
     * @param string $defaultColor Default text color in 3 or 6 hexadecimal characters
     * @param int $precision Higher value means higher precision (but also longer execution time), usual values are 1 to 3
     */
    static function onImageQuality($string, $image, $fontName, $x = 0, $y = 0, $size = 10, $defaultColor = '000', $precision = 2)
    {
        $defaultColor = Color::StringToRgb24($defaultColor);
        $factor = 1 << ($precision > 31 ? 31 : $precision);

        $tokens = self::parseString($string);
        $rawText = '';
        foreach ($tokens as $token)
            $rawText .= $token->text;
        $maxBBox = imagettfbbox($size, 0, self::$fonts[$fontName]->getFile(), $rawText);

        $brush = imagecreatetruecolor($maxBBox[2] * 2, -$maxBBox[5] + 5);
        imagefill($brush, 0, 0, 0x7fffffff);
        $hugeBrush = imagecreatetruecolor(imagesx($brush) * $factor, imagesy($brush) * $factor);
        imagefill($hugeBrush, 0, 0, 0x7fffffff);

        $xOffset = 0;
        foreach ($tokens as $token)
            $xOffset += $token->onImage($hugeBrush, $fontName, $xOffset, imagesy($hugeBrush) * .75, $factor * $size, $defaultColor, $factor);

        $brushX = $x + imagesx($brush) / 2;
        $brushY = $y - imagesy($brush) * .25;
        imagecopyresampled($brush, $hugeBrush, 0, 0, 0, 0, imagesx($brush), imagesy($brush), imagesx($hugeBrush), imagesy($hugeBrush));
        imagesetbrush($image, $brush);
        imageline($image, $brushX, $brushY, $brushX, $brushY, IMG_COLOR_BRUSHED);
    }

    static private function parseString($string)
    {
        $tokens = array();
        $textToken = new TextToken();
        $linkToken = null;

        $stylesStack = array();
        $style = 0;

        $isCode = false;
        $isQuickLink = false;
        $isPrettyLink = false;
        $linkLevel = 0;
        $color = '';

        $lambdaEndLink = function () use (&$tokens, &$textToken, &$linkToken, &$isQuickLink, &$isPrettyLink, &$style) {
            if ($textToken->text !== '') {
                $tokens[] = $textToken;
                $textToken = new TextToken($style);
            }
            if (end($tokens) === $linkToken)
                array_pop($tokens);
            else
                $tokens[] = new KnilToken();

            $linkToken = null;
            $isQuickLink = false;
            $isPrettyLink = false;
        };
        $lambdaEndText = function ($force = false) use (&$tokens, &$textToken, &$style) {
            if ($force || $style != $textToken->style) {
                if ($textToken->text !== '') {
                    $tokens[] = $textToken;
                    $textToken = new TextToken($style);
                } else
                    $textToken->style = $style;
            }
        };

        foreach (preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY) as $char) {
            if ($isCode) {
                $isManialink = false;

                switch ($char) {
                    case 'i':
                        $style ^= self::ITALIC;
                        break;
                    case 'o':
                        $style ^= self::BOLD;
                        break;
                    case 's':
                        $style ^= self::SHADOWED;
                        break;
                    case 'w':
                        $style |= self::WIDE;
                        $style &= ~self::NARROW;
                        break;
                    case 'n':
                        $style |= self::NARROW;
                        $style &= ~self::WIDE;
                        break;
                    case 'm':
                        $style &= ~(self::NARROW | self::WIDE);
                        break;
                    case 't':
                        $style ^= self::CAPITALIZED;
                        break;
                    case 'g':
                        $style &= empty($stylesStack) ? ~0x1fff : (end($stylesStack) | ~0x1fff);
                        break;
                    case 'z':
                        $style = empty($stylesStack) ? 0 : end($stylesStack);
                        if ($linkToken)
                            $lambdaEndLink();
                        break;
                    case 'h':
                    case 'p':
                        $isManialink = true;
                    case 'l':
                        if ($linkToken)
                            $lambdaEndLink();
                        else {
                            $lambdaEndText(true);
                            $tokens[] = $linkToken = new LinkToken($isManialink);
                            $isQuickLink = true;
                            $isPrettyLink = true;
                            $linkLevel = count($stylesStack);
                        }
                        break;
                    case '$':
                        $textToken->text .= '$';
                        break;
                    case '<':
                        array_push($stylesStack, $style);
                        break;
                    case '>':
                        if (!empty($stylesStack)) {
                            $style = array_pop($stylesStack);
                            if ($linkToken && $linkLevel > count($stylesStack))
                                $lambdaEndLink();
                        }
                        break;
                    default:
                        if (stripos('0123456789abcdef', $char) !== false)
                            $color = $char;
                }

                $lambdaEndText();
                $isCode = false;
            } else if ($char === '$') {
                $isCode = true;
                $color = '';
                if ($isQuickLink && $isPrettyLink)
                    $isPrettyLink = false;
            } else if ($color !== '') {
                $color .= preg_replace('/[^0-9a-f]/iu', '0', $char);
                if (strlen($color) == 3) {
                    $style &= ~0xfff;
                    $style |= self::COLORED | Color::StringToRgb12($color);

                    $lambdaEndText();
                    $color = '';
                }
            } else if ($isQuickLink && $isPrettyLink) {
                if ($char === '[')
                    $isQuickLink = false;
                else {
                    $isPrettyLink = false;
                    $textToken->text .= $char;
                    $linkToken->link .= $char;
                }
            } else if ($isPrettyLink) {
                if ($char === ']')
                    $isPrettyLink = false;
                else
                    $linkToken->link .= $char;
            } else {
                $textToken->text .= $char;
                if ($isQuickLink)
                    $linkToken->link .= $char;
            }
        }

        if ($textToken->text !== '')
            $tokens[] = $textToken;

        if ($linkToken) {
            if (end($tokens) === $linkToken)
                array_pop($tokens);
            else
                $tokens[] = new KnilToken();
        }

        return $tokens;
    }
}

class TextToken
{
    public $style;
    public $text;

    function __construct($style = 0, $text = '')
    {
        $this->style = $style;
        $this->text = $text;
    }

    function __toString()
    {
        if ($this->style) {
            $styles = '';
            if ($this->style & StyleParser::COLORED) {
                if (StyleParser::getBackground() !== null && StyleParser::getContrast() !== null) {
                    $color = Color::Rgb12ToRgb24($this->style & 0xfff);
                    $color = Color::Contrast($color, StyleParser::getBackground(), StyleParser::getContrast());
                    $color = Color::Rgb24ToString($color);
                } else
                    $color = Color::Rgb12ToString($this->style & 0xfff);
                $styles .= 'color:#' . $color . ';';
            }
            if ($this->style & StyleParser::ITALIC)
                $styles .= 'font-style:italic;';
            if ($this->style & StyleParser::BOLD)
                $styles .= 'font-weight:bold;';
            if ($this->style & StyleParser::SHADOWED)
                $styles .= 'text-shadow:1px 1px 1px rgba(0,0,0,.5);';
            if ($this->style & StyleParser::CAPITALIZED)
                $this->text = strtoupper($this->text);
            if ($this->style & StyleParser::WIDE)
                $styles .= 'letter-spacing:.1em;font-size:105%;';
            else if ($this->style & StyleParser::NARROW)
                $styles .= 'letter-spacing:-.1em;font-size:95%;';
            return '' . htmlentities($this->text, ENT_QUOTES, 'UTF-8') . '';
        } else
            return htmlentities($this->text, ENT_QUOTES, 'UTF-8');
    }

    function onImage($image, $fontName, $x, $y, $size, $color, $shadowOffset)
    {
        $fontFile = StyleParser::getFont($fontName, $this->style & (StyleParser::BOLD | StyleParser::ITALIC));

        if ($this->style & StyleParser::COLORED) {
            $color = Color::Rgb12ToRgb24($this->style & 0xfff);
            if (StyleParser::getBackground() !== null && StyleParser::getContrast() !== null)
                $color = Color::Contrast($color, StyleParser::getBackground(), StyleParser::getContrast());
        }

        $width = 0;
        $extraSpace = $size / 5;
        if ($this->style & StyleParser::WIDE || $this->style & StyleParser::NARROW) {
            $ratio = ($this->style & StyleParser::WIDE) ? 1.5 : 1 / 1.5;
            $extraSpace *= $ratio;
            foreach ((array)$this->text as $char) {
                $bBox = imagettfbbox($size, 0, $fontFile, $char);
                //echo print_r($bBox, true).'
';

                $temp = imagecreatetruecolor(($bBox[2] - $bBox[0]) * 2, ($bBox[3] - $bBox[5]) * 2);
                imagefill($temp, 0, 0, 0x7fffffff);
                $brush = imagecreatetruecolor(imagesx($temp) * $ratio, imagesy($temp));
                imagefill($brush, 0, 0, 0x7fffffff);
                $brushX = $x + $width + imagesx($brush) / 2;
                $brushY = $y;

                if ($this->style & StyleParser::SHADOWED)
                    imagettftext($temp, $size, 0, -$bBox[0] + $shadowOffset, $bBox[3] - $bBox[5] + $shadowOffset, 0x3f000000, $fontFile, $char);
                imagettftext($temp, $size, 0, -$bBox[0], $bBox[3] - $bBox[5], $color, $fontFile, $char);
                imagecopyresampled($brush, $temp, 0, 0, 0, 0, imagesx($brush), imagesy($brush), imagesx($temp), imagesy($temp));
                imagesetbrush($image, $brush);
                imageline($image, $brushX, $brushY, $brushX, $brushY, IMG_COLOR_BRUSHED);

                imagedestroy($temp);
                imagedestroy($brush);

                $width += ($bBox[2] - $bBox[0] + $extraSpace) * $ratio;
            }
        } else {
            foreach ((array)$this->text as $char) {
                $bBox = imagettfbbox($size, 0, $fontFile, $char);

                if ($this->style & StyleParser::SHADOWED)
                    imagettftext($image, $size, 0, $x + $width - $bBox[0] + $shadowOffset, $y + $shadowOffset, 0x3f000000, $fontFile, $char);
                imagettftext($image, $size, 0, $x + $width - $bBox[0], $y, $color, $fontFile, $char);

                $width += $bBox[2] - $bBox[0] + $extraSpace;
            }
        }
        return $width;
    }
}

class LinkToken
{
    public $link;
    public $isManialink;

    function __construct($isManialink)
    {
        $this->link = '';
        $this->isManialink = $isManialink;
    }

    function __toString()
    {
        $link = $this->link;
        if ($this->isManialink) {
            $protocol = StyleParser::getGameProtocol() . '://';
            if (substr($link, 0, strlen($protocol)) != $protocol)
                $link = StyleParser::getGameProtocol() . ':///:' . $link;
        } else if (!preg_match('/^[a-z][a-z0-9+.-]*:\/\//ui', $link)) {
            $link = 'http://' . $link;
        }
        $link = htmlentities($link, ENT_QUOTES, 'UTF-8');
        $target = $this->isManialink ? '' : 'target="_blank"';
        return sprintf('', $link, $target);
    }

    function onImage($image, Font $font, $x, $y, $size, $color, $shadowOffset)
    {
        return null;
    }
}

class KnilToken
{

    function __toString()
    {
        return '';
    }

    function onImage($image, Font $font, $x, $y, $size, $color, $shadowOffset)
    {
        return null;
    }
}


<?php namespace Arcanedev\LaravelSeo\Redirectors;

use Arcanedev\LaravelSeo\Contracts\Redirector;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Contracts\Routing\Registrar as Router;

/**
 * Class     AbstractRedirector
 *
 * @package  Arcanedev\LaravelSeo\Redirectors
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 */
abstract class AbstractRedirector implements Redirector
{
    /* -----------------------------------------------------------------
     |  Properties
     | -----------------------------------------------------------------
     */

    /** @var \Illuminate\Contracts\Routing\Registrar */
    protected $router;

    /** @var  \Illuminate\Http\Request */
    protected $request;

    /** @var  array */
    protected $options = [];

    /* -----------------------------------------------------------------
     |  Constructor
     | -----------------------------------------------------------------
     */

    /**
     * AbstractRedirector constructor.
     *
     * @param  \Illuminate\Contracts\Routing\Registrar  $router
     * @param  array                                    $options
     */
    public function __construct(Router $router, array $options)
    {
        $this->router  = $router;
        $this->options = $options;
    }

    /* -----------------------------------------------------------------
     |  Getters & Setters
     | -----------------------------------------------------------------
     */
    /**
     * Get an option.
     *
     * @param  string      $key
     * @param  mixed|null  $default
     *
     * @return mixed
     */
    public function getOption($key, $default = null)
    {
        return Arr::get($this->options, $key, $default);
    }

    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Get the redirect url.
     *
     * @param  \Illuminate\Http\Request  $request
     *
     * @return \Illuminate\Http\Response|null
     */
    public function getRedirectFor(Request $request)
    {
        $this->request = $request;

        collect($this->getRedirectedUrls())->each(function ($redirects, $missingUrl) {
            $this->router->get($missingUrl, function () use ($redirects) {
                return redirect()->to(
                    $this->determineRedirectUrl($redirects),
                    $this->determineRedirectStatusCode($redirects)
                );
            });
        });

        try {
            return $this->router->dispatch($request);
        }
        catch (\Exception $e) {
            return null;
        }
    }

    /**
     * @param  array|string  $redirects
     *
     * @return string
     */
    protected function determineRedirectUrl($redirects)
    {
        return $this->resolveRouterParameters(
            is_array($redirects) ? reset($redirects) : $redirects
        );
    }

    /**
     * @param  mixed  $redirects
     *
     * @return int
     */
    protected function determineRedirectStatusCode($redirects)
    {
        return is_array($redirects) ? end($redirects) : Response::HTTP_MOVED_PERMANENTLY;
    }

    /**
     * @param  string  $redirectUrl
     *
     * @return string
     */
    protected function resolveRouterParameters($redirectUrl)
    {
        foreach ($this->router->getCurrentRoute()->parameters() as $key => $value) {
            $redirectUrl = str_replace("{{$key}}", $value, $redirectUrl);
        }

        return $redirectUrl;
    }
}


<?php namespace Arcanedev\LaravelSeo\Redirectors;

use Arcanedev\LaravelSeo\Contracts\Redirector;
use Arcanedev\LaravelSeo\Models\Redirect;

/**
 * Class     EloquentRedirector
 *
 * @package  Arcanedev\LaravelSeo\Redirectors
 * @author   ARCANEDEV <arcanedev.maroc@gmail.com>
 */
class EloquentRedirector extends AbstractRedirector implements Redirector
{
    /* -----------------------------------------------------------------
     |  Main Methods
     | -----------------------------------------------------------------
     */

    /**
     * Get the redirected URLs.
     *
     * @return array
     */
    public function getRedirectedUrls()
    {
        return $this->getCachedRedirects()
            ->keyBy('old_url')
            ->transform(function (Redirect $item) {
                return [$item->new_url, $item->status];
            })
            ->toArray();
    }

    /**
     * Get the cached redirection urls.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    protected function getCachedRedirects()
    {
        return cache()->remember($this->getOption('cache.key'), $this->getOption('cache.duration'), function () {
            return $this->getRedirectModel()->get();
        });
    }

    /**
     * Get the redirect model.
     *
     * @return \Arcanedev\LaravelSeo\Models\Redirect
     */
    private function getRedirectModel()
    {
        return app(
            $this->getOption('model', \Arcanedev\LaravelSeo\Models\Redirect::class)
        );
    }
}