<?php

/**
 * @file
 * TeamSpeak 3 PHP Framework
 *
 * $Id: TeamSpeak3.php 9/26/2011 7:06:29 scp@orilla $
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package   TeamSpeak3
 * @version   1.1.8-beta
 * @author    Sven 'ScP' Paulsen
 * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved.
 */

namespace ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3;

/**
 * @class TeamSpeak3
 * @brief Factory class all for TeamSpeak 3 PHP Framework objects.
 */
class TeamSpeak3
{
  /**
   * TeamSpeak 3 protocol welcome message.
   */
  const READY = "TS3";

  /**
   * TeamSpeak 3 protocol greeting message prefix.
   */
  const GREET = "Welcome";

  /**
   * TeamSpeak 3 protocol error message prefix.
   */
  const ERROR = "error";

  /**
   * TeamSpeak 3 protocol event message prefix.
   */
  const EVENT = "notify";

  /**
   * TeamSpeak 3 protocol server connection handler ID prefix.
   */
  const SCHID = "selected";

  /**
   * TeamSpeak 3 PHP Framework version.
   */
  const LIB_VERSION = "1.1.8-beta";

  /*@
   * TeamSpeak 3 protocol separators.
   */
  const SEPARATOR_LINE               = "\n"; //!< protocol line separator
  const SEPARATOR_LIST               = "|";  //!< protocol list separator
  const SEPARATOR_CELL               = " ";  //!< protocol cell separator
  const SEPARATOR_PAIR               = "=";  //!< protocol pair separator

  /*@
   * TeamSpeak 3 log levels.
   */
  const LOGLEVEL_CRITICAL            = 0x00; //!< 0: these messages stop the program
  const LOGLEVEL_ERROR               = 0x01; //!< 1: everything that is really bad
  const LOGLEVEL_WARNING             = 0x02; //!< 2: everything that might be bad
  const LOGLEVEL_DEBUG               = 0x03; //!< 3: output that might help find a problem
  const LOGLEVEL_INFO                = 0x04; //!< 4: informational output
  const LOGLEVEL_DEVEL               = 0x05; //!< 5: development output

  /*@
   * TeamSpeak 3 token types.
   */
  const TOKEN_SERVERGROUP            = 0x00; //!< 0: server group token  (id1={groupID} id2=0)
  const TOKEN_CHANNELGROUP           = 0x01; //!< 1: channel group token (id1={groupID} id2={channelID})

  /*@
   * TeamSpeak 3 codec identifiers.
   */
  const CODEC_SPEEX_NARROWBAND       = 0x00; //!< 0: speex narrowband     (mono, 16bit, 8kHz)
  const CODEC_SPEEX_WIDEBAND         = 0x01; //!< 1: speex wideband       (mono, 16bit, 16kHz)
  const CODEC_SPEEX_ULTRAWIDEBAND    = 0x02; //!< 2: speex ultra-wideband (mono, 16bit, 32kHz)
  const CODEC_CELT_MONO              = 0x03; //!< 3: celt mono            (mono, 16bit, 48kHz)

  /*@
   * TeamSpeak 3 codec encryption modes.
   */
  const CODEC_CRYPT_INDIVIDUAL       = 0x00; //!< 0: configure per channel
  const CODEC_CRYPT_DISABLED         = 0x01; //!< 1: globally disabled
  const CODEC_CRYPT_ENABLED          = 0x02; //!< 2: globally enabled

  /*@
   * TeamSpeak 3 kick reason types.
   */
  const KICK_CHANNEL                 = 0x04; //!< 4: kick client from channel
  const KICK_SERVER                  = 0x05; //!< 5: kick client from server

  /*@
   * TeamSpeak 3 text message target modes.
   */
  const TEXTMSG_CLIENT               = 0x01; //!< 1: target is a client
  const TEXTMSG_CHANNEL              = 0x02; //!< 2: target is a channel
  const TEXTMSG_SERVER               = 0x03; //!< 3: target is a virtual server

  /*@
   * TeamSpeak 3 host message modes.
   */
  const HOSTMSG_NONE                 = 0x00; //!< 0: display no message
  const HOSTMSG_LOG                  = 0x01; //!< 1: display message in chatlog
  const HOSTMSG_MODAL                = 0x02; //!< 2: display message in modal dialog
  const HOSTMSG_MODALQUIT            = 0x03; //!< 3: display message in modal dialog and close connection

  /*@
   * TeamSpeak 3 host banner modes.
   */
  const HOSTBANNER_NO_ADJUST         = 0x00; //!< 0: do not adjust
  const HOSTBANNER_IGNORE_ASPECT     = 0x01; //!< 1: adjust bug ignore aspect ratio
  const HOSTBANNER_KEEP_ASPECT       = 0x02; //!< 2: adjust and keep aspect ratio

  /*@
   * TeamSpeak 3 client identification types.
   */
  const CLIENT_TYPE_REGULAR          = 0x00; //!< 0: regular client
  const CLIENT_TYPE_SERVERQUERY      = 0x01; //!< 1: query client

  /*@
   * TeamSpeak 3 permission group database types.
   */
  const GROUP_DBTYPE_TEMPLATE        = 0x00; //!< 0: template group     (used for new virtual servers)
  const GROUP_DBTYPE_REGULAR         = 0x01; //!< 1: regular group      (used for regular clients)
  const GROUP_DBTYPE_SERVERQUERY     = 0x02; //!< 2: global query group (used for ServerQuery clients)

  /*@
   * TeamSpeak 3 permission group name modes.
   */
  const GROUP_NAMEMODE_HIDDEN        = 0x00; //!< 0: display no name
  const GROUP_NAMEMODE_BEFORE        = 0x01; //!< 1: display name before client nickname
  const GROUP_NAMEMODE_BEHIND        = 0x02; //!< 2: display name after client nickname

  /*@
   * TeamSpeak 3 permission group identification types.
   */
  const GROUP_IDENTIFIY_STRONGEST    = 0x01; //!< 1: identify most powerful group
  const GROUP_IDENTIFIY_WEAKEST      = 0x02; //!< 2: identify weakest group

  /*@
   * TeamSpeak 3 permission types.
   */
  const PERM_TYPE_SERVERGROUP        = 0x00; //!< 0: server group permission
  const PERM_TYPE_CLIENT             = 0x01; //!< 1: client specific permission
  const PERM_TYPE_CHANNEL            = 0x02; //!< 2: channel specific permission
  const PERM_TYPE_CHANNELGROUP       = 0x03; //!< 3: channel group permission
  const PERM_TYPE_CHANNELCLIENT      = 0x04; //!< 4: channel-client specific permission

  /*@
   * TeamSpeak 3 permission categories.
   */
  const PERM_CAT_GLOBAL              = 0x10; //!< 00010000: global permissions
  const PERM_CAT_GLOBAL_INFORMATION  = 0x11; //!< 00010001: global permissions -> global information
  const PERM_CAT_GLOBAL_SERVER_MGMT  = 0x12; //!< 00010010: global permissions -> virtual server management
  const PERM_CAT_GLOBAL_ADM_ACTIONS  = 0x13; //!< 00010011: global permissions -> global administrative actions
  const PERM_CAT_GLOBAL_SETTINGS     = 0x14; //!< 00010100: global permissions -> global settings
  const PERM_CAT_SERVER              = 0x20; //!< 00100000: virtual server permissions
  const PERM_CAT_SERVER_INFORMATION  = 0x21; //!< 00100001: virtual server permissions -> virtual server information
  const PERM_CAT_SERVER_ADM_ACTIONS  = 0x22; //!< 00100010: virtual server permissions -> virtual server administrative actions
  const PERM_CAT_SERVER_SETTINGS     = 0x23; //!< 00100011: virtual server permissions -> virtual server settings
  const PERM_CAT_CHANNEL             = 0x30; //!< 00110000: channel permissions
  const PERM_CAT_CHANNEL_INFORMATION = 0x31; //!< 00110001: channel permissions -> channel information
  const PERM_CAT_CHANNEL_CREATE      = 0x32; //!< 00110010: channel permissions -> create channels
  const PERM_CAT_CHANNEL_MODIFY      = 0x33; //!< 00110011: channel permissions -> edit channels
  const PERM_CAT_CHANNEL_DELETE      = 0x34; //!< 00110100: channel permissions -> delete channels
  const PERM_CAT_CHANNEL_ACCESS      = 0x35; //!< 00110101: channel permissions -> access channels
  const PERM_CAT_GROUP               = 0x40; //!< 01000000: group permissions
  const PERM_CAT_GROUP_INFORMATION   = 0x41; //!< 01000001: group permissions -> group information
  const PERM_CAT_GROUP_CREATE        = 0x42; //!< 01000010: group permissions -> create groups
  const PERM_CAT_GROUP_MODIFY        = 0x43; //!< 01000011: group permissions -> edit groups
  const PERM_CAT_GROUP_DELETE        = 0x44; //!< 01000100: group permissions -> delete groups
  const PERM_CAT_CLIENT              = 0x50; //!< 01010000: client permissions
  const PERM_CAT_CLIENT_INFORMATION  = 0x51; //!< 01010001: client permissions -> client information
  const PERM_CAT_CLIENT_ADM_ACTIONS  = 0x52; //!< 01010010: client permissions -> client administrative actions
  const PERM_CAT_CLIENT_BASICS       = 0x53; //!< 01010011: client permissions -> client basic communication
  const PERM_CAT_CLIENT_MODIFY       = 0x54; //!< 01010100: client permissions -> edit clients
  const PERM_CAT_FILETRANSFER        = 0x60; //!< 01100000: file transfer permissions
  const PERM_CAT_NEEDED_MODIFY_POWER = 0xFF; //!< 11111111: needed permission modify power (grant) permissions

  /*@
   * TeamSpeak 3 file types.
   */
  const FILE_TYPE_DIRECTORY          = 0x00; //!< 0: file is directory
  const FILE_TYPE_REGULAR            = 0x01; //!< 1: file is regular

  /*@
   * TeamSpeak 3 server snapshot types.
   */
  const SNAPSHOT_STRING              = 0x00; //!< 0: default string
  const SNAPSHOT_BASE64              = 0x01; //!< 1: base64 string
  const SNAPSHOT_HEXDEC              = 0x02; //!< 2: hexadecimal string

  /*@
   * TeamSpeak 3 channel spacer types.
   */
  const SPACER_SOLIDLINE             = 0x00; //!< 0: solid line
  const SPACER_DASHLINE              = 0x01; //!< 1: dash line
  const SPACER_DOTLINE               = 0x02; //!< 2: dot line
  const SPACER_DASHDOTLINE           = 0x03; //!< 3: dash dot line
  const SPACER_DASHDOTDOTLINE        = 0x04; //!< 4: dash dot dot line
  const SPACER_CUSTOM                = 0x05; //!< 5: custom format

  /*@
   * TeamSpeak 3 channel spacer alignments.
   */
  const SPACER_ALIGN_LEFT            = 0x00; //!< 0: alignment left
  const SPACER_ALIGN_RIGHT           = 0x01; //!< 1: alignment right
  const SPACER_ALIGN_CENTER          = 0x02; //!< 2: alignment center
  const SPACER_ALIGN_REPEAT          = 0x03; //!< 3: repeat until the whole line is filled

  /**
   * Stores an array containing various chars which need to be escaped while communicating
   * with a TeamSpeak 3 Server.
   *
   * @var array
   */
  protected static $escape_patterns = array(
    "\\" => "\\\\", // backslash
    "/"  => "\\/",  // slash
    " "  => "\\s",  // whitespace
    "|"  => "\\p",  // pipe
    ";"  => "\\;",  // semicolon
    "\a" => "\\a",  // bell
    "\b" => "\\b",  // backspace
    "\f" => "\\f",  // formfeed
    "\n" => "\\n",  // newline
    "\r" => "\\r",  // carriage return
    "\t" => "\\t",  // horizontal tab
    "\v" => "\\v"   // vertical tab
  );

  /**
   * Factory for TeamSpeak3_Adapter_Abstract classes. $uri must be formatted as
   * "<adapter>://<user>:<pass>@<host>:<port>/<options>#<flags>". All parameters
   * except adapter, host and port are optional.
   *
   * === Supported Options ===
   *   - timeout
   *   - blocking
   *   - nickname
   *   - no_query_clients
   *   - use_offline_as_virtual
   *   - clients_before_channels
   *   - server_id|server_uid|server_port|server_name|server_tsdns
   *   - channel_id|channel_name
   *   - client_id|client_uid|client_name
   *
   * === Supported Flags (only one per $uri) ===
   *   - no_query_clients
   *   - use_offline_as_virtual
   *   - clients_before_channels
   *
   * === URI Examples ===
   *   - serverquery://127.0.0.1:10011/
   *   - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1
   *   - serverquery://127.0.0.1:10011/?server_port=9987&channel_id=1#no_query_clients
   *   - serverquery://127.0.0.1:10011/?server_port=9987&client_name=ScP
   *   - filetransfer://127.0.0.1:30011/
   *   - blacklist
   *   - update
   *
   * @param  string $uri
   * @return TeamSpeak3_Adapter_Abstract
   * @return TeamSpeak3_Node_Abstract
   */
  public static function factory($uri)
  {
    self::init();

    $uri = new Helper\Uri($uri);

    $adapter = self::getAdapterName($uri->getScheme());
    $options = array("host" => $uri->getHost(), "port" => $uri->getPort(), "timeout" => intval($uri->getQueryVar("timeout", 10)), "blocking" => intval($uri->getQueryVar("blocking", 1)));

//    self::loadClass($adapter);

    $object = new $adapter($options);

    if($object instanceof Adapter\ServerQuery)
    {
      $node = $object->getHost();

      if($uri->hasUser() && $uri->hasPass())
      {
        $node->login($uri->getUser(), $uri->getPass());
      }

      /* option to pre-define nickname */
      if($uri->hasQueryVar("nickname"))
      {
        $node->setPredefinedQueryName($uri->getQueryVar("nickname"));
      }

      /* flag to use offline servers in virtual mode */
      if($uri->getFragment() == "use_offline_as_virtual")
      {
        $node->setUseOfflineAsVirtual(TRUE);
      }
      elseif($uri->hasQueryVar("use_offline_as_virtual"))
      {
        $node->setUseOfflineAsVirtual($uri->getQueryVar("use_offline_as_virtual") ? TRUE : FALSE);
      }

      /* flag to fetch clients before sub-channels */
      if($uri->getFragment() == "clients_before_channels")
      {
        $node->setLoadClientlistFirst(TRUE);
      }
      elseif($uri->hasQueryVar("clients_before_channels"))
      {
        $node->setLoadClientlistFirst($uri->getQueryVar("clients_before_channels") ? TRUE : FALSE);
      }

      /* flag to hide ServerQuery clients */
      if($uri->getFragment() == "no_query_clients")
      {
        $node->setExcludeQueryClients(TRUE);
      }
      elseif($uri->hasQueryVar("no_query_clients"))
      {
        $node->setExcludeQueryClients($uri->getQueryVar("no_query_clients") ? TRUE : FALSE);
      }

      /* access server node object */
      if($uri->hasQueryVar("server_id"))
      {
        $node = $node->serverGetById($uri->getQueryVar("server_id"));
      }
      elseif($uri->hasQueryVar("server_uid"))
      {
        $node = $node->serverGetByUid($uri->getQueryVar("server_uid"));
      }
      elseif($uri->hasQueryVar("server_port"))
      {
        $node = $node->serverGetByPort($uri->getQueryVar("server_port"));
      }
      elseif($uri->hasQueryVar("server_name"))
      {
        $node = $node->serverGetByName($uri->getQueryVar("server_name"));
      }
      elseif($uri->hasQueryVar("server_tsdns"))
      {
        $node = $node->serverGetByTSDNS($uri->getQueryVar("server_tsdns"));
      }

      /* direct access to node objects */
      if($node instanceof Node\Server)
      {
        /* access channel node object */
        if($uri->hasQueryVar("channel_id"))
        {
          $node = $node->channelGetById($uri->getQueryVar("channel_id"));
        }
        elseif($uri->hasQueryVar("channel_name"))
        {
          $node = $node->channelGetByName($uri->getQueryVar("channel_name"));
        }

        /* access client node object */
        if($uri->hasQueryVar("client_id"))
        {
          $node = $node->clientGetById($uri->getQueryVar("client_id"));
        }
        if($uri->hasQueryVar("client_uid"))
        {
          $node = $node->clientGetByUid($uri->getQueryVar("client_uid"));
        }
        elseif($uri->hasQueryVar("client_name"))
        {
          $node = $node->clientGetByName($uri->getQueryVar("client_name"));
        }
      }

      return $node;
    }

    return $object;
  }

  /**
   * Loads a class from a PHP file. The filename must be formatted as "$class.php".
   *
   * include() is not prefixed with the @ operator because if the file is loaded and
   * contains a parse error, execution will halt silently and this is difficult to debug.
   *
   * @param  string $class
   * @throws LogicException
   * @return boolean
   */
//  protected static function loadClass($class)
//  {
//    if(class_exists($class, FALSE) || interface_exists($class, FALSE))
//    {
//      return;
//    }
//
//    if(preg_match("/[^a-z0-9\\/\\\\_.-]/i", $class))
//    {
//      throw new LogicException("illegal characters in classname '" . $class . "'");
//    }
//
//    $file = self::getFilePath($class) . ".php";
//
//    if(!file_exists($file) || !is_readable($file))
//    {
//      throw new LogicException("file '" . $file . "' does not exist or is not readable");
//    }
//
//    if(class_exists($class, FALSE) || interface_exists($class, FALSE))
//    {
//      throw new LogicException("class '" . $class . "' does not exist");
//    }
//
//    return include_once($file);
//  }

  /**
   * Generates a possible file path for $name.
   *
   * @param  string $name
   * @return string
   */
  protected static function getFilePath($name)
  {
//    $path = str_replace('\\', DIRECTORY_SEPARATOR, $name);
//    $path = str_replace('TeamSpeak3', dirname(__FILE__), $path);

    return APP_ROOT.DIRECTORY_SEPARATOR.'libraries'.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $name);
  }

  /**
   * Returns the name of an adapter class by $name.
   *
   * @param  string $name
   * @param  string $namespace
   * @throws Adapter\Exception
   * @return string
   */
  protected static function getAdapterName($name)
  {
    $path = self::getFilePath(__NAMESPACE__.'\\Adapter\\');
    $scan = scandir($path);

    foreach($scan as $node)
    {
      $file = Helper\String::factory($node)->toLower();

      if($file->startsWith($name) && $file->endsWith(".php"))
      {
        return __NAMESPACE__.'\\Adapter\\' . str_replace(".php", "", $node);
      }
    }

    throw new Adapter\Exception("adapter '" . $name . "' does not exist");
  }

  /**
   * spl_autoload() suitable implementation for supporting class autoloading.
   *
   * @param  string $class
   * @return boolean
   */
//  public static function autoload($class)
//  {
//    if(substr($class, 0, strlen(__CLASS__)) != __CLASS__) return;
//
//    try
//    {
//      self::loadClass($class);
//
//      return TRUE;
//    }
//    catch(Exception $e)
//    {
//      return FALSE;
//    }
//  }

  /**
   * Checks for required PHP features, enables autoloading and starts a default profiler.
   *
   * @throws LogicException
   * @return void
   */
  public static function init()
  {
//    if(version_compare(phpversion(), "5.2.1") == -1)
//    {
//      throw new LogicException("this particular software cannot be used with the installed version of PHP");
//    }

    if(!function_exists("stream_socket_client"))
    {
      throw new LogicException("network functions are not available in this PHP installation");
    }

//    if(!function_exists("spl_autoload_register"))
//    {
//      throw new LogicException("autoload functions are not available in this PHP installation");
//    }
//
//    if(!class_exists("TeamSpeak3_Helper_Profiler"))
//    {
//      spl_autoload_register(array(__CLASS__, "autoload"));
//    }

	Helper\Profiler::start();
  }

  /**
   * Returns an assoc array containing all escape patterns available on a TeamSpeak 3
   * Server.
   *
   * @return array
   */
  public static function getEscapePatterns()
  {
    return self::$escape_patterns;
  }

  /**
   * Debug helper function. This is a wrapper for var_dump() that adds the pre-format tags,
   * cleans up newlines and indents, and runs htmlentities() before output.
   *
   * @param  mixed  $var
   * @param  bool   $echo
   * @return string
   */
  public static function dump($var, $echo = TRUE)
  {
    ob_start();
    var_dump($var);

    $output = ob_get_clean();
    $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);

    if(PHP_SAPI == "cli")
    {
      $output = PHP_EOL . PHP_EOL . $output . PHP_EOL;
    }
    else
    {
      $output = "<pre>" . htmlspecialchars($output, ENT_QUOTES) . "</pre>";
    }

    if($echo) echo($output);

    return $output;
  }
}

/*!
 * \mainpage API Documentation
 *
 * \section welcome_sec Introduction
 *
 * \subsection welcome1 What is the TS3 PHP Framework?
 * Initially released in January 2010, the TS3 PHP Framework is a powerful, open source, object-oriented framework
 * implemented in PHP 5 and licensed under the GNU General Public License. It's based on simplicity and a rigorously
 * tested agile codebase. Extend the functionality of your servers with scripts or create powerful web applications
 * to manage all features of your TeamSpeak 3 Server instances.
 *
 * Tested. Thoroughly. Enterprise-ready and built with agile methods, the TS3 PHP Framework has been unit-tested from
 * the start to ensure that all code remains stable and easy for you to extend, re-test with your extensions, and
 * further maintain.
 *
 * \subsection welcome2 Why should I use the TS3 PHP Framework rather than other PHP libraries?
 * The TS3 PHP Framework is a is a modern use-at-will framework that provides individual components to communicate
 * with the TeamSpeak 3 Server.
 *
 * There are lots of arguments for the TS3 PHP Framework in comparison with other PHP based libraries. It is the most
 * dynamic and feature-rich piece of software in its class. In addition, it's the only PHP library that parses the data
 * spit out of the ServerQuery interface correctly.
 *
 * \section sysreqs_sec Requirements
 * The TS3 PHP Framework currently supports PHP 5.2.1 or later, but we strongly recommend the most current release of
 * PHP for critical security and performance enhancements. If you want to create a web application using the TS3 PHP
 * Framework, you need a PHP 5 interpreter with a web server configured to handle PHP scripts correctly.
 *
 * Note that the majority of TS3 PHP Framework development and deployment is done on Apache, so there is more community
 * experience and testing performed on Apache than on other web servers.
 *
 * \section feature_sec Features
 * Features of the TS3 PHP Framework include:
 *
 *   - Fully object-oriented PHP 5 and E_STRICT compliant components
 *   - Access to all TeamSpeak 3 Server features via ServerQuery
 *   - Integrated full featured and customizable TSViewer interfaces
 *   - Full support for file transfers to up- and /or download custom icons and other stuff
 *   - Powerful error handling capablities using exceptions and customizable error messages
 *   - Query mechanisms for several official services such as the blacklist and auto-update servers
 *   - Dynamic signal slots for event based scripting
 *   - ...
 *
 * \section example_sec Usage Examples
 *
 * \subsection example1 1. Kick all Clients from a Virtual Server
 * @code
 *   // connect to local server, authenticate and quickly spawn an object for the virtual server on port 9987
 *   $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987");
 *
 *   // query clientlist from virtual server
 *   $arr_ClientList = $ts3_VirtualServer->clientList();
 *
 *   // kick all clients online with a single command
 *   $ts3_VirtualServer->clientKick($arr_ClientList, TeamSpeak3::KICK_SERVER, "evil kick XD");
 * @endcode
 *
 * \subsection example2 2. Modify the Settings of each Virtual Server
 * @code
 *   // connect to local server, authenticate and quickly spawn an object for the server instance
 *   $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?use_offline_as_virtual=1");
 *
 *   // walk through list of virtual servers
 *   foreach($ts3_ServerInstance as $ts3_VirtualServer)
 *   {
 *     // modify the virtual servers hostbanner URL only
 *     $ts3_VirtualServer["virtualserver_hostbanner_gfx_url"] = "http://www.example.com/banners/banner01_468x60.jpg";
 *
 *     // modify multiple virtual server properties at once
 *     $ts3_VirtualServer->modify(
 *       "virtualserver_hostbutton_tooltip" => "My Company",
 *       "virtualserver_hostbutton_url"     => "http://www.example.com",
 *       "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg",
 *     );
 *   }
 * @endcode
 *
 * \subsection example3 3. Modify the Permissions of Admins on each Virtual Server
 * @code
 *   // connect to local server, authenticate and quickly spawn an object for the server instance
 *   $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?use_offline_as_virtual=1");
 *
 *   // walk through list of virtual servers
 *   foreach($ts3_ServerInstance as $ts3_VirtualServer)
 *   {
 *     // identify the most powerful group on the virtual server
 *     $ts3_ServerGroup = $ts3_VirtualServer->serverGroupIdentify();
 *
 *     // assign a new permission
 *     $ts3_ServerGroup->permAssign("b_virtualserver_modify_hostbanner", TRUE);
 *
 *     // revoke an existing permission
 *     $ts3_ServerGroup->permRemove("b_virtualserver_modify_maxclients");
 *   }
 * @endcode
 *
 * \subsection example4 4. Create a new Virtual Server
 * @code
 *   // connect to local server and authenticate
 *   $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/");
 *
 *   // create a virtual server and get its ID
 *   $new_sid = $ts3_ServerInstance->serverCreate(
 *     "virtualserver_name"               => "My TeamSpeak 3 Server",
 *     "virtualserver_maxclients"         => 64,
 *     "virtualserver_hostbutton_tooltip" => "My Company",
 *     "virtualserver_hostbutton_url"     => "http://www.example.com",
 *     "virtualserver_hostbutton_gfx_url" => "http://www.example.com/buttons/button01_24x24.jpg",
 *   );
 * @endcode
 *
 * \subsection example5 5. Create a hierarchical Channel Stucture
 * @code
 *   // connect to local server, authenticate and quickly spawn an object for the virtual server on port 9987
 *   $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987");
 *
 *   // create a top-level channel and get its ID
 *   $top_cid = $ts3_VirtualServer->channelCreate(
 *     "channel_name"           => "My Channel",
 *     "channel_topic"          => "This is a top-level channel",
 *     "channel_codec"          => TeamSpeak3::CODEC_SPEEX_WIDEBAND,
 *     "channel_flag_permanent" => TRUE,
 *   );
 *
 *   // create a sub-level channel and get its ID
 *   $sub_cid = $ts3_VirtualServer->channelCreate(
 *     "channel_name"           => "My Sub-Channel",
 *     "channel_topic"          => "This is a sub-level channel",
 *     "channel_codec"          => TeamSpeak3::CODEC_SPEEX_NARROWBAND,
 *     "channel_flag_permanent" => TRUE,
 *     "cpid"                   => $top_cid,
 *   );
 * @endcode
 *
 * \subsection example6 6. Send a Text Message to outdated Clients
 * @code
 *   // connect to local server, authenticate and quickly spawn an object for the virtual server on port 9987
 *   $ts3_VirtualServer = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/?server_port=9987");
 *
 *   // connect to default update server
 *   $ts3_UpdateServer = TeamSpeak3::factory("update");
 *
 *   // walk through list of clients on virtual server
 *   foreach($ts3_VirtualServer->clientList() as $ts3_Client)
 *   {
 *     // skip query clients
 *     if($ts3_Client["client_type"]) continue;
 *
 *     // send test message if client build is outdated
 *     if($ts3_Client->getRev() < $ts3_UpdateServer->getRev())
 *     {
 *       $ts3_Client->message("[COLOR=red]your client is [B]outdated[/B]... update now![/COLOR]");
 *     }
 *   }
 * @endcode
 *
 * \subsection example7 7. Check if the Server Instance is Outdated or Blacklisted
 * @code
 *   // connect to local server and authenticate
 *   $ts3_ServerInstance = TeamSpeak3::factory("serverquery://username:password@127.0.0.1:10011/");
 *
 *   // connect to default update server
 *   $ts3_UpdateServer = TeamSpeak3::factory("update");
 *
 *   // send global text message if the server is outdated
 *   if($ts3_ServerInstance->version("build") < $ts3_UpdateServer->getServerRev())
 *   {
 *     $ts3_ServerInstance->message("[COLOR=red]your server is [B]outdated[/B]... update now![/COLOR]");
 *   }
 *
 *   // connect to default blacklist server
 *   $ts3_BlacklistServer = TeamSpeak3::factory("blacklist");
 *
 *   // send global text message if the server is blacklisted
 *   if($ts3_BlacklistServer->isBlacklisted($ts3_ServerInstance))
 *   {
 *     $ts3_ServerInstance->message("[COLOR=red]your server is [B]blacklisted[/B]... disconnect now![/COLOR]");
 *   }
 * @endcode
 *
 * Speed up new development and reduce maintenance costs by using the TS3 PHP Framework!
 */


<?php

namespace Encore\Wx\Element\Traits;

use wxSize;

trait Sizable
{
    /**
     * Create a wxSize object from the width/height
     *
     * @return wxSize
     */
    protected function getSize()
    {
        if ($this->width and $this->height) {
            return new wxSize($this->width, $this->height);
        }

        return wxDefaultSize;
    }
}


<?php
/**
 * @see https://github.com/dotkernel/dot-navigation/ for the canonical source repository
 * @copyright Copyright (c) 2017 Apidemia (https://www.apidemia.com)
 * @license https://github.com/dotkernel/dot-navigation/blob/master/LICENSE.md MIT License
 */

declare(strict_types = 1);

namespace Dot\Navigation\View;

use Dot\Navigation\Exception\RuntimeException;
use Dot\Navigation\NavigationContainer;
use Dot\Navigation\Service\NavigationInterface;
use Zend\Escaper\Escaper;
use Zend\Expressive\Template\TemplateRendererInterface;

/**
 * Class AbstractNavigationHelper
 * @package Dot\Navigation\Helper
 */
abstract class AbstractNavigationRenderer implements RendererInterface
{
    /** @var NavigationInterface */
    protected $navigation;

    /** @var  string */
    protected $partial;

    /** @var TemplateRendererInterface */
    protected $template;

    /**
     * AbstractNavigationHelper constructor.
     * @param NavigationInterface $navigation
     * @param TemplateRendererInterface $template
     */
    public function __construct(NavigationInterface $navigation, TemplateRendererInterface $template)
    {
        $this->navigation = $navigation;
        $this->template = $template;
    }

    /**
     * @param array $attributes
     * @return string
     */
    public function htmlAttributes(array $attributes): string
    {
        $xhtml = '';
        $escaper = new Escaper();

        foreach ($attributes as $key => $val) {
            $key = $escaper->escapeHtml($key);

            if (('on' == substr($key, 0, 2)) || ('constraints' == $key)) {
                // Don't escape event attributes; _do_ substitute double quotes with singles
                if (!is_scalar($val)) {
                    // non-scalar data should be cast to JSON first
                    $val = json_encode($val);
                }
            } else {
                if (is_array($val)) {
                    $val = implode(' ', $val);
                }
            }

            $val = $escaper->escapeHtmlAttr($val);

            if ('id' == $key) {
                $val = $this->normalizeId($val);
            }
            if (strpos($val, '"') !== false) {
                $xhtml .= " $key='$val'";
            } else {
                $xhtml .= " $key=\"$val\"";
            }
        }
        return $xhtml;
    }

    /**
     * Normalize an ID
     *
     * @param  string $value
     * @return string
     */
    protected function normalizeId(string $value): string
    {
        if (strstr($value, '[')) {
            if ('[]' == substr($value, -2)) {
                $value = substr($value, 0, strlen($value) - 2);
            }
            $value = trim($value, ']');
            $value = str_replace('][', '-', $value);
            $value = str_replace('[', '-', $value);
        }
        return $value;
    }

    /**
     * @return string|null
     */
    public function getPartial(): ?string
    {
        return $this->partial;
    }

    /**
     * @param string $partial
     */
    public function setPartial(string $partial)
    {
        $this->partial = $partial;
    }

    /**
     * @param string|NavigationContainer $container
     * @return NavigationContainer
     */
    protected function getContainer($container): NavigationContainer
    {
        if (is_string($container)) {
            return $this->navigation->getContainer($container);
        } elseif (!$container instanceof NavigationContainer) {
            throw new RuntimeException('Container must be a string or an instance of ' . NavigationContainer::class);
        }

        return $container;
    }

    /**
     * Cleans array of attributes based on valid input.
     *
     * @param array $input
     * @param array $valid
     * @return array
     */
    protected function cleanAttributes(array $input, array $valid): array
    {
        foreach ($input as $key => $value) {
            if (preg_match('/^data-(.+)/', $key) || in_array($key, $valid)) {
                continue;
            }
            unset($input[$key]);
        }
        return $input;
    }
}


<?php namespace Gears\Arrays\Conversions\From;
////////////////////////////////////////////////////////////////////////////////
// __________ __             ________                   __________
// \______   \  |__ ______  /  _____/  ____ _____ ______\______   \ _______  ___
//  |     ___/  |  \\____ \/   \  ____/ __ \\__  \\_  __ \    |  _//  _ \  \/  /
//  |    |   |   Y  \  |_> >    \_\  \  ___/ / __ \|  | \/    |   (  <_> >    <
//  |____|   |___|  /   __/ \______  /\___  >____  /__|  |______  /\____/__/\_ \
//                \/|__|           \/     \/     \/             \/            \/
// -----------------------------------------------------------------------------
//          Designed and Developed by Brad Jones <brad @="bjc.id.au" />
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////

use \Gears\Arrays\Conversions\Template;

class Lines extends Template
{
	/**
	 * Property: memory
	 * =========================================================================
	 * This is the amount of memory that we will take up to create a
	 * file pointer to a temporay place in main memory.
	 *
	 * Defaults to 5MB
	 */
	protected $memory = 5;

	/**
	 * Property: trim
	 * =========================================================================
	 * Remove leading and trailing whitespace
	 *
	 * Defaults to true
	 */
	protected $trim = true;

	/**
	 * Method: Convert
	 * =========================================================================
	 * This will do the actual converting
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $data - A string of lines to convert to an array
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * array
	 */
	public function Convert($data)
	{
		// Create an array
		$lines = array();

		// Create a file pointer to our Text Data
		$fp = fopen('php://temp/maxmemory:'.$this->memory*(1024*1024), 'r+');
		fputs($fp, $data);
		rewind($fp);

		// Loop through each line and add it to our array
		while (!feof($fp))
		{
			if ($this->trim) $lines[] = trim(fgets($fp));
			else $lines[] = fgets($fp);
		}
		fclose($fp);

		// Return the array
		return $lines;
	}
}


<?php namespace Gears\Arrays\Conversions\To;
////////////////////////////////////////////////////////////////////////////////
// __________ __             ________                   __________
// \______   \  |__ ______  /  _____/  ____ _____ ______\______   \ _______  ___
//  |     ___/  |  \\____ \/   \  ____/ __ \\__  \\_  __ \    |  _//  _ \  \/  /
//  |    |   |   Y  \  |_> >    \_\  \  ___/ / __ \|  | \/    |   (  <_> >    <
//  |____|   |___|  /   __/ \______  /\___  >____  /__|  |______  /\____/__/\_ \
//                \/|__|           \/     \/     \/             \/            \/
// -----------------------------------------------------------------------------
//          Designed and Developed by Brad Jones <brad @="bjc.id.au" />
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////

use \XmlWriter;
use \Gears\Arrays\Conversions\Template;

class Xml extends Template
{
	/**
	 * Property: indent
	 * =========================================================================
	 * Do we want to have the XML formated so it is readable.
	 */
	protected $indent = false;

	/**
	 * Method: Convert
	 * =========================================================================
	 * This will do the actual converting
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $data - An array to convert to XML
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * xml
	 */
	public function Convert($data)
	{
		// Create a new xml document
		$xml = new XmlWriter();
		$xml->openMemory();
		$xml->setIndent($this->indent);
		$xml->startDocument('1.0', 'UTF-8');

		// Recursively create the body of the document
		$this->RecursXML($xml, $data);

		// End the document
		$xml->endElement();

		// Return the XML Document as a String
		return $xml->outputMemory(true);
	}

	/**
	 * Method: RecursXML
	 * =========================================================================
	 * This is the resursive function that will convert the each node of the
	 * array to xml.
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $xml - The XMLWriter Instance
	 * $data - The array to convert
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * xml
	 */
	private function RecursXML(XMLWriter $xml, $data)
	{
		// Loop through the array
		foreach($data as $key => $value)
		{
			// Take care of any attributes
			if (!empty($key) && $key == '@attributes')
			{
				// Loop through the attributes
				foreach ($value as $attribute_name => $attribute_value)
				{
					$xml->writeAttribute($attribute_name, $attribute_value);
				}
				continue;
			}

			// Do we need to go further into the array
			if(is_array($value))
			{
				// Check for indexed type
				if (isset($value[0]))
				{
					foreach ($value as $value_data)
					{
						if (is_array($value_data))
						{
							$xml->startElement($key);
							$this->RecursXML($xml, $value_data);
							$xml->endElement();
						}
						else
						{
							$xml->writeElement($key, $value_data);
						}
					}
				}
				else
				{
					$xml->startElement($key);
					$this->RecursXML($xml, $value);
					$xml->endElement();
				}
				continue;
			}

			// We are not allowed to have a numric key
			if (is_numeric($key)) $key = 'index_'.$key;

			$xml->writeElement($key, $value);
		}
	}
}


<?php

namespace Encore\Wx\Element;

use wxStaticText;
use Encore\Giml\ElementTrait;
use Encore\Giml\ElementInterface;
use Encore\Wx\Element\Traits\Wx;
use Encore\Wx\Element\Traits\Sizable;
use Encore\Wx\Element\Traits\Positionable;

class Label implements ElementInterface
{
    use ElementTrait;
    use Sizable;
    use Positionable;
    use Wx;

    /**
     * Initialise the object
     *
     * @return void
     */
    public function init()
    {
        $this->element = new wxStaticText($this->parent->getParent()->getRaw(), wxID_ANY, $this->text ?: $this->value, $this->getPosition(), $this->getSize());

        $this->parent->getRaw()->Add($this->element);
    }

    /**
     * Set the label value
     *
     * @param string $value
     */
    public function setValue($value)
    {
        if ($this->element) {
            $this->element->SetLabel($value);
        }

        $this->value = $value;
    }
}


<?php

namespace DevGroup\ExtensionsManager;

use DevGroup\ExtensionsManager\helpers\ExtensionFileWriter;
use DevGroup\ExtensionsManager\models\Extension;
use Yii;
use yii\base\Module;

/**
 * Class ExtensionsManager is the main module in extensions-manager package.
 *
 * @package DevGroup\ExtensionsManager
 */
class ExtensionsManager extends Module
{
    /**
     * @var bool Automatically discover migration paths for using with dmstr/yii2-migrate-command package
     */
    public $autoDiscoverMigrations = true;

    /**
     * @var bool Discover dotplant extensions migrations. Normally this should be false.
     */
    public $discoverDotPlantMigrations = false;

    /**
     * Set of constant listed below describes DeferredGroup. Using them we can define what kind of activity was performed.
     * COMPOSER_INSTALL_DEFERRED_GROUP and COMPOSER_UNINSTALL_DEFERRED_GROUP are used in
     * DeferredQueueCompleteHandler as identifiers to rewrite self::$extensionsStorage file after
     * extension install or uninstall process.
     */
    const COMPOSER_INSTALL_DEFERRED_GROUP = 'ext_manager_composer_install';
    const COMPOSER_UNINSTALL_DEFERRED_GROUP = 'ext_manager_composer_uninstall';
    const EXTENSION_ACTIVATE_DEFERRED_GROUP = 'ext_manager_extension_activate';
    const EXTENSION_DEACTIVATE_DEFERRED_GROUP = 'ext_manager_extension_deactivate';
    const EXTENSION_DUMMY_DEFERRED_GROUP = 'ext_manager_dummy_report';

    /**
     * Next set of constants describes tasks what can be performed from front-end. All of this used as a data attributes
     * in buttons markup and then in the ExtensionsController to define what task we need to do.
     */
    const INSTALL_DEFERRED_TASK = 'install-def-task';
    const UNINSTALL_DEFERRED_TASK = 'uninstall-def-task';
    const ACTIVATE_DEFERRED_TASK = 'activate-def-task';
    const DEACTIVATE_DEFERRED_TASK = 'deactivate-def-task';
    const CHECK_UPDATES_DEFERRED_TASK = 'check-updates-def-task';

    /**
     * Migration directions used in the ExtensionsController
     */
    const MIGRATE_TYPE_DOWN = 'down';
    const MIGRATE_TYPE_UP = 'up';

    /**
     * ConfigurationUpdater component is used for writing application configs.
     * You can configure it as usual yii2 Component.
     *
     * @var \DevGroup\ExtensionsManager\helpers\ConfigurationUpdater
     */
    public $configurationUpdater = [
        'class' => 'DevGroup\ExtensionsManager\helpers\ConfigurationUpdater',
        'configs' => [
            'common-generated' => 'commonApplicationAttributes',
            'web-generated' => 'webApplicationAttributes',
            'console-generated' => 'consoleApplicationAttributes',
            'params-generated' => 'appParams',
            'aliases-generated' => 'aliases',
        ],
    ];

    /**
     * Location of extensions storage file. Aliases can be used.
     * File contains of a php return statement with array consisting elements with the following information:
     * - composer_name - name of composer package
     * - composer_type - type of composer package(if is set in composer.json of package)
     * - is_active - boolean, if this extension is active
     * - is_core - boolean, true if it is core extension and should be protected from uninstalling
     *
     * @var string
     */
    public $extensionsStorage = '@app/config/extensions.php';

    /** @var string Packegist URL */
    public $packagistUrl = 'https://packagist.org';

    /**
     * @var string token to access api.github.com.
     * Without this token you will able to perform 60 requests daily only
     */
    public $githubAccessToken;

    /**
     * @var string  due to https://developer.github.com/v3/#user-agent-required
     * you have to pass username or application name in headers while requesting github API
     */
    public $applicationName = 'DevGroup-ru/yii2-extensions-manager';

    /** @var string github API URL */
    public $githubApiUrl = 'https://api.github.com';

    /** @var int number of Extension shown on Extension Search and Extension Index pages */
    public $extensionsPerPage = 10;

    /** @var string path to composer file */
    public $composerPath = './composer.phar';

    /** @var int Show detailed output for composer commands */
    public $verbose = 0;

    /** @var string path to store ignored from git local composer.json file */
    private $_localExtensionsPath = '@app/extensions';

    /** @var array default contents of local ignored composer.json */
    private $_composerArray = [
        "name" => "devgroup/ext-meta-package",
        "description" => "File to store local extensions",
        "minimum-stability" => "dev",
        "require" => [],
        "config" => [
            "vendor-dir" => "../vendor",
            "process-timeout" => 1800,
            "preferred-install" => "dist",
            "store-auths" => true,
        ],
        "extra" => [
            "merge-plugin" => [
                "include" => [
                    "../composer.json",
                ],
                "merge-extra" => true,
                "merge-extra-deep" => true,
            ],
        ],
    ];

    /**
     * @var array Array of extensions descriptions
     */
    private $_extensions = [];

    /**
     * @inheritdoc
     */
    public function init()
    {
        ExtensionFileWriter::checkLocalStorage(
            Yii::getAlias($this->_localExtensionsPath),
            $this->_composerArray
        );
        parent::init();
        $this->configurationUpdater['class'] = 'DevGroup\ExtensionsManager\helpers\ConfigurationUpdater';
        $this->configurationUpdater = Yii::createObject($this->configurationUpdater);
    }

    /**
     * Returns Extension[] or one Extension array by package name found in self::$extensionsStorage.
     *
     * @param string $packageName
     * @param bool $ignoreCache
     * @return Extension|models\Extension[]
     */
    public function getExtensions($packageName = '', $ignoreCache = false)
    {
        if (count($this->_extensions) === 0 || true === $ignoreCache) {
            $fileName = Yii::getAlias($this->extensionsStorage);
            $canLoad = false;
            if (true === file_exists($fileName) && true === is_readable($fileName)) {
                $canLoad = true;
            } else {
                $canLoad = ExtensionFileWriter::generateConfig();
            }
            if (true === $canLoad) {
                $this->_extensions = include $fileName;
            } else {
                Yii::$app->session->setFlash('error', Yii::t('extensions-manager', 'Unable to create extensions file'));
            }
        }
        if (false === empty($packageName)) {
            return isset($this->_extensions[$packageName]) ? $this->_extensions[$packageName] : [];
        }
        return $this->_extensions;
    }

    /**
     * @param string $packageName
     * @return bool
     */
    public function extensionIsActive($packageName)
    {
        $ext = $this->getExtensions($packageName, true);
        if (true === isset($ext['is_active'])) {
            return 1 == $ext['is_active'];
        }
        return false;
    }

    /**
     * @param string $packageName
     * @return bool
     */
    public function extensionIsCore($packageName)
    {
        $ext = $this->getExtensions($packageName);
        if (true === isset($ext['is_core'])) {
            return 1 == $ext['is_core'];
        }
        return false;
    }

    /**
     * @return array
     */
    public static function navLinks()
    {
        return $navItems = [
            'index' => [
                'label' => Yii::t('extensions-manager', 'Extensions'),
                'url' => ['/extensions-manager/extensions/index'],
            ],
            'search' => [
                'label' => Yii::t('extensions-manager', 'Search'),
                'url' => ['/extensions-manager/extensions/search'],
            ],
            'config' => [
                'label' => Yii::t('extensions-manager', 'Configuration'),
                'url' => ['config', 'sectionIndex' => 0],
                'visible' => Yii::$app->user->can('extensions-manager-configure-extension')
            ],
        ];
    }

    /**
     * @return bool|string
     */
    public function getLocalExtensionsPath()
    {
        return Yii::getAlias($this->_localExtensionsPath);
    }

    /**
     * @return ExtensionsManager|null
     */
    public static function module()
    {
        if (null === $module = Yii::$app->getModule('extensions-manager')) {
            $module = new self('extensions-manager');
        }
        return $module;
    }
}


<?php namespace Gears\Arrays;
////////////////////////////////////////////////////////////////////////////////
// __________ __             ________                   __________
// \______   \  |__ ______  /  _____/  ____ _____ ______\______   \ _______  ___
//  |     ___/  |  \\____ \/   \  ____/ __ \\__  \\_  __ \    |  _//  _ \  \/  /
//  |    |   |   Y  \  |_> >    \_\  \  ___/ / __ \|  | \/    |   (  <_> >    <
//  |____|   |___|  /   __/ \______  /\___  >____  /__|  |______  /\____/__/\_ \
//                \/|__|           \/     \/     \/             \/            \/
// -----------------------------------------------------------------------------
//          Designed and Developed by Brad Jones <brad @="bjc.id.au" />
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////

use \Illuminate\Support\Collection;
use \Gears\Arrays\Iterator;
use \Gears\Arrays\Exceptions\InvalidMethod;

class Fluent extends Collection
{
	/**
	 * Method: convert
	 * =========================================================================
	 * This is a convenience front end to our conversion classes.
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * This method uses some smart dynamic parameters matching.
	 * Best shown with an example:
	 *
	 * ```php
	 * Arr::a([1,2,3])->convert('csv') // 1,2,3
	 * Arr::a()->convert('1,2,3', 'csv') // array(1,2,3)
	 * Arr::a([1,2,3])->convert('csv', ['delimiter' => "-"]) // 1-2-3
	 * Arr::a()->convert('1-2-3', 'csv', ['delimiter' => "-"]) // array(1,2,3)
	 * ```
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * mixed
	 */
	public function convert($arg1, $arg2 = null, $arg3 = array())
	{
		// Create the converter class names
		if (is_null($arg2) || is_array($arg2))
		{
			$converter = '\Gears\Arrays\Conversions\To\\'.ucfirst($arg1);
			$data = $this->items;
			$options = $arg2;
		}
		else
		{
			$converter = '\Gears\Arrays\Conversions\From\\'.ucfirst($arg2);
			$data = $arg1;
			$options = $arg3;
		}

		// Initiate a new converter
		$converter =  new $converter($options);

		// Run the conversion
		$results = $converter->Convert($data);

		// Return a new version of ourself if the result is an array
		if (is_array($results))
		{
			return new static($results);
		}
		else
		{
			return $results;
		}
	}

	/**
	 * Method: get
	 * =========================================================================
	 * Get an item from the collection by key.
	 *
	 * For example:
	 *
	 * ```php
	 * $data = Arr::a(['a' => ['b' => ['c' => 'd']]]);
	 * echo $data->get('a.b.c'); // outputs: d
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $key - Can be a single key, "dot" separated keys or an array of keys.
	 * $default - What value would you like to have returned on failure?
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * mixed
	 */
	public function get($key, $default = null)
	{
		// Get the keys array
		if (is_string($key))
		{
			// We found the key in the root of the array
			if ($this->offsetExists($key))
			{
				return $this->offsetGet($key);
			}

			$keys = explode('.', $key);
		}
		elseif (isArrayLike($key))
		{
			$keys = $key;
		}
		else
		{
			// Bail Out - we need a key
			// NOTE: value()_is a laravel helper
			return value($default);
		}

		// Start searching in the root of the array
		$array = $this->items;

		// Loop through the keys
		foreach ($keys as $x)
		{
			// Check to see if the key exists
			if (!isArrayLike($array) || !array_key_exists($x, $array))
			{
				// Bail out and return the default.
				// NOTE: value() is a laravel helper.
				return value($default);
			}

			// Keep recursing into the array
			$array = $array[$x];
		}

		if (is_array($array))
		{
			$value = new static($array);
			$this->set($key, $value);
		}
		else
		{
			$value = $array;
		}

		// Return the value
		return $value;
	}

	/**
	 * Method: set
	 * =========================================================================
	 * Set an item on the collection by key.
	 *
	 * For example:
	 *
	 * ```php
	 * $data = Arr::a();
	 * $data->set('a.b.c', 'd');
	 * echo $data->a->b->c; // outputs: d
	 * ```
	 *
	 * NOTE: If no key is given to the method, the entire array will be
	 * replaced. This is in keeping with the procedual version of this method.
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $key - Can be a single key, "dot" separated keys or an array of keys.
	 * $value - The value to set on the collection.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * static
	 */
	public function set($key, $value)
	{
		// Get the keys array
		if (is_string($key))
		{
			$keys = explode('.', $key);
		}
		elseif (isArrayLike($key))
		{
			$keys = $key;
		}
		else
		{
			// Assume key not provided, replace entire array with new value.
			$this->items = (array) $value;
			return $this;
		}

		// Start in the root of the array
		$array =& $this->items;

		// Loop through the keys
		while (count($keys) > 1)
		{
			// Get the next key
			$key = array_shift($keys);

			// If the key doesn't exist at this depth, we will just create an
			// empty array to hold the next value, allowing us to create the
			// arrays to hold final values at the correct depth. Then we'll
			// keep digging into the array.
			if (!isset($array[$key]) || !isArrayLike($array[$key]))
			{
				$array[$key] = new static();
			}

			// Recurse into the array
			$array =& $array[$key];
		}

		// Set the new value
		$array[array_shift($keys)] = $value;

		// Return ourselves to allow method chaining
		return $this;
	}

	/**
	 * Method: add
	 * =========================================================================
	 * Add an item to the collection by key, if it doesn't exist.
	 *
	 * For example:
	 *
	 * ```php
	 * $data = Arr::a(['a' => ['b' => ['c' => 'd']]]);
	 * $data->add('a', '123'); // fails
	 * $data->add('z', '123'); // works
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $key - Can be a single key, "dot" separated keys or an array of keys.
	 * $value - The value to set on the collection.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * static
	 */
	public function add($key, $value = null)
	{
		if (is_null($value))
		{
			$this->offsetSet(null, $key);
		}
		else
		{
			if (is_null($this->get($key)))
			{
				$this->set($key, $value);
			}
		}

		return $this;
	}

	/**
	 * Method: offsetGet
	 * =========================================================================
	 * Returns the value at specified offset.
	 * See: http://php.net/manual/en/class.arrayaccess.php
	 *
	 * *We have overloaded the ```\Illuminate\Support\Collection```
	 * version so that we can provide a recursive interface.*
	 *
	 * For example:
	 *
	 * ```php
	 * $data = Arr:a([[1,2,3]]);
	 * print_r($data[0]);
	 * ```
	 *
	 * Results in:
	 *
	 * ```
	 * Gears\Arrays\Fluent Object
	 * (
	 * 		[items:protected] => Array
	 * 		(
	 * 			[0] => 1,
	 * 			[1] => 2,
	 * 			[2] => 3
	 * 		)
	 * )
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $key - The key of the underlying array to retrive.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * mixed
	 */
	public function offsetGet($key)
	{
		$value = parent::offsetGet($key);

		if (is_array($value)) $this->offsetSet($key, new static($value));

		return parent::offsetGet($key);
	}

	/**
	 * Method: getIterator
	 * =========================================================================
	 * This returns an array iterator so foreach works on our array like object.
	 * See: http://php.net/manual/en/class.iteratoraggregate.php
	 *
	 * *We have overloaded the ```\Illuminate\Support\Collection```
	 * version so that we can provide a recursive interface.*
	 *
	 * For example:
	 *
	 * ```php
	 * foreach (Arr::a([[1,2,3]]) as $item)
	 * {
	 *  	print_r($item);
	 * }
	 * ```
	 *
	 * Results in:
	 *
	 * ```
	 * Gears\Arrays\Fluent Object
	 * (
	 * 		[items:protected] => Array
	 * 		(
	 * 			[0] => 1,
	 * 			[1] => 2,
	 * 			[2] => 3
	 * 		)
	 * )
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * n/a
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * \Gears\Arrays\Iterator
	 */
	public function getIterator()
	{
		return new Iterator($this->items);
	}

	/**
	 * Method: __set
	 * =========================================================================
	 * This is a PHP Magic Method.
	 * See: http://php.net/manual/en/language.oop5.magic.php
	 *
	 * This enables the object access syntax:
	 *
	 * ```php
	 * $data = Arr::a();
	 * $data->foo = 'bar';
	 * print_r($data);
	 * ```
	 *
	 * The results of the above look like:
	 *
	 * ```
	 * Gears\Arrays\Fluent Object
	 * (
	 * 		[items:protected] => Array
	 * 		(
	 * 			'foo' => 'bar'
	 * 		)
	 * )
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $name - The name or key of the item to set on the underlying array.
	 * $value - The value toi set on the underlying array.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * void
	 */
	public function __set($name, $value)
	{
		$this->offsetSet($name, $value);
	}

	/**
	 * Method: __get
	 * =========================================================================
	 * This is a PHP Magic Method.
	 * See: http://php.net/manual/en/language.oop5.magic.php
	 *
	 * This enables the object access syntax:
	 *
	 * ```php
	 * $data = Arr::a(['foo' => 'bar']);
	 * echo $data->foo; // Outputs: bar
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $name - The name or key of the item to get from the underlying array.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * mixed
	 */
	public function __get($name)
	{
		return $this->offsetGet($name);
	}

	/**
	 * Method: __isset
	 * =========================================================================
	 * This is a PHP Magic Method.
	 * See: http://php.net/manual/en/language.oop5.magic.php
	 *
	 * This enables you to use isset() or empty() like so:
	 *
	 * ```php
	 * $data = Arr::a(['foo' => 'bar']);
	 * isset($data->foo); // true
	 * isset($data->bar); // false
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $name - The name or key of the item to test on the underlying array.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * bool
	 */
	public function __isset($name)
	{
		return $this->offsetExists($name);
	}

	/**
	 * Method: __unset
	 * =========================================================================
	 * This is a PHP Magic Method.
	 * See: http://php.net/manual/en/language.oop5.magic.php
	 *
	 * This enables you to use unset() like so:
	 *
	 * ```php
	 * $data = Arr::a(['foo' => 'bar']);
	 * isset($data->foo); // true
	 * unset($data->foo);
	 * isset($data->foo); // false
	 * ```
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $name - The name or key of the item to test on the underlying array.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * void
	 */
	public function __unset($name)
	{
		$this->offsetUnset($name);
	}

	/**
	 * Method: __call
	 * =========================================================================
	 * The existing methods in the ```Illuminate\Support\Collection``` class
	 * are awesome. But there are some extra methods we would like to have
	 * access to.
	 *
	 * This will first look for a function under our \Gears\Arrays
	 * namespace. If one is found we call that function for you, as if it
	 * were a method of this class.
	 *
	 * If we can't find a function there we then check for any macros that have
	 * been defined on the \Gears\Arrays class. Again running that for you
	 * automatically.
	 *
	 * On failure of all that we finally throw an InvalidMethod Exception.
	 *
	 * Parameters:
	 * -------------------------------------------------------------------------
	 * $name - The name of the \Gears\Arrays\"FUNCTION" to call.
	 * $arguments - The arguments to pass to the function.
	 *
	 * Returns:
	 * -------------------------------------------------------------------------
	 * mixed
	 */
	public function __call($name, $arguments)
	{
		// Create the function name
		$func_name = '\Gears\Arrays\\'.$name;

		// Does the function exist
		if (!function_exists($func_name))
		{
			// Try a macro
			if (\Gears\Arrays::hasMacro($name))
			{
				// Just a reminder that macros can't have values
				// passed by reference due to __callStatic.
				$func_name = '\Gears\Arrays::'.$name;
			}
			else
			{
				// Bail out, we don't have a function to run
				throw new InvalidMethod($name);
			}
		}

		// Prepend the current items to the arguments
		// Some functions require a reference to the array so we define it here.
		$new_args = [&$this->items];

		foreach ($arguments as $arg)
		{
			// We also check for any arguments that might need
			// to be transformed into an actual array. As most of
			// the procedural functions expect real arrays and not
			// ArrayLike objects.
			if (isArrayLike($arg, true))
			{
				$new_args[] = $arg->toArray();
			}
			else
			{
				$new_args[] = $arg;
			}
		}

		// Save the new arguments
		$arguments = $new_args;

		// Call the function
		$result = call_user_func_array($func_name, $arguments);

		if (empty($result))
		{
			// Nothing to return so just return the current instance.
			// This probably means a function that acted on the array
			// by reference ran.
			return $this;
		}
		else
		{
			if (is_array($result))
			{
				// Return a new instance of ourselves with the new results.
				return new static($result);
			}
			else
			{
				// Otherwise we just return the result from the function.
				// This is now the end of our Gears\Array\Fluent object.
				return $result;
			}
		}
	}
}


<?php

namespace Shoko\TwitchApiBundle\Factory;

use Shoko\TwitchApiBundle\Model\Entity\Game;
use Shoko\TwitchApiBundle\Model\Entity\GameList;

/**
 * Class GameFactory.
 */
class GameFactory implements FactoryInterface
{
    /**
     * @param array      $data
     * @param false|Game $game
     *
     * @return Game
     */
    public function createEntity(array $data, $game = false)
    {
        if (false === $game) {
            $game = Game::create();
        }

        if (isset($data['name'])) {
            $game = $game->setName($data['name']);
        }

        if (isset($data['_links'])) {
            $game = $game->setLinks($data['_links']);
        }

        if (isset($data['logo'])) {
            $game = $game->setLogo($data['logo']);
        }

        if (isset($data['box'])) {
            $game = $game->setBox($data['box']);
        }

        if (isset($data['_id'])) {
            $game = $game->setId($data['_id']);
        }

        if (isset($data['giantbomb_id'])) {
            $game = $game->setGiantBombId($data['giantbomb_id']);
        }

        if (isset($data['popularity'])) {
            $game = $game->setPopularity($data['popularity']);
        }

        return $game;
    }

    /**
     * @param array          $data
     * @param false|GameList $gameList
     *
     * @return GameList
     */
    public function createList(array $data, $gameList = false)
    {
        if (false === $gameList) {
            $gameList = GameList::create();
        }

        if (isset($data['games'])) {
            $gameList = $gameList->setGames($this->createGames($data['games']));
        }

        if (isset($data['_links'])) {
            $gameList = $gameList->setLinks($data['_links']);
        }

        return $gameList;
    }

    /**
     * @param array $games
     *
     * @return array
     */
    public function createGames(array $games)
    {
        $tmp = [];
        foreach ($games as $entry) {
            $tmp[] = $this->createEntity($entry);
        }

        return $tmp;
    }

    /**
     * @param array $data
     *
     * @return Top
     */
    public function createTop(array $data)
    {
        return (new TopFactory())->createEntity($data);
    }
}


<?php

namespace Shoko\TwitchApiBundle\Factory;

use Shoko\TwitchApiBundle\Model\Entity\User;

/**
 * Class UserFactory.
 */
class UserFactory implements FactoryInterface
{
    /**
     * @param array $data
     * @param false|User $user
     *
     * @return User
     */
    public function createEntity(array $data, $user = false)
    {
        if (false === $user) {
            $user = User::create();
        }

        if (isset($data['type'])) {
            $user = $user->setType($data['type']);
        }

        if (isset($data['name'])) {
            $user = $user->setName($data['name']);
        }

        if (isset($data['created_at'])) {
            $user = $user->setCreatedAt(new \DateTime($data['created_at']));
        }

        if (isset($data['updated_at'])) {
            $user = $user->setUpdatedAt(new \DateTime($data['updated_at']));
        }

        if (isset($data['_links'])) {
            $user = $user->setLinks($data['_links']);
        }

        if (isset($data['logo'])) {
            $user = $user->setLogo($data['logo']);
        }

        if (isset($data['_id'])) {
            $user = $user->setId($data['_id']);
        }

        if (isset($data['display_name'])) {
            $user = $user->setDisplayName($data['display_name']);
        }

        if (isset($data['bio'])) {
            $user = $user->setBio($data['bio']);
        }

        return $user;
    }
}


<?php

namespace Shoko\TwitchApiBundle\Factory;

use Shoko\TwitchApiBundle\Model\Entity\Top;

/**
 * Class TopFactory.
 */
class TopFactory implements FactoryInterface
{
    /**
     * @param array      $data
     * @param false|Rank $rank
     *
     * @return Rank
     */
    public function createEntity(array $data, $rank = false)
    {
        if (false === $rank) {
            $rank = Top::create();
        }

        if (isset($data['top'])) {
            $rank = $rank->setRanks($this->createRanks($data['top']));
        }

        if (isset($data['_links'])) {
            $rank = $rank->setLinks($data['_links']);
        }

        if (isset($data['_total'])) {
            $rank = $rank->setTotal($data['_total']);
        }

        return $rank;
    }

    /**
     * @param array $ranks
     *
     * @return array
     */
    public function createRanks(array $ranks)
    {
        $tmp = [];
        foreach ($ranks as $entry) {
            $tmp[] = (new RankFactory())->createEntity($entry);
        }

        return $tmp;
    }
}


<?php

namespace Encore\Wx\Element;

use wxFrame;
use Encore\Giml\ElementTrait;
use Encore\Giml\ElementInterface;
use Encore\Wx\Element\Traits\Wx;
use Encore\Wx\Element\Traits\Events;
use Encore\Wx\Element\Traits\Options;
use Encore\Wx\Element\Traits\Sizable;
use Encore\Wx\Element\Traits\Positionable;

class Frame implements ElementInterface
{
    use ElementTrait;
    use Wx;
    use Positionable;
    use Sizable;
    use Events;
    use Options;

    protected $events = [
        'onClose' => wxEVT_CLOSE_WINDOW,
        'onMinimize' => wxEVT_ICONIZE,
        'onMenuOpen' => wxEVT_MENU_OPEN,
        'onMenuClose' => wxEVT_MENU_CLOSE,
        'onMenuHighlight' => wxEVT_MENU_HIGHLIGHT,
    ];

    protected $options = [
        'closeBox' => wxCLOSE_BOX
    ];

    /**
     * Initialise the object
     *
     * @return void
     */
    public function init()
    {
        $this->element = new wxFrame(null, wxID_ANY, $this->title, $this->getPosition(), $this->getSize(), wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL|$this->buildOptions());

        $this->bindEvents();
    }
}


<?php

namespace Encore\Wx;

use Encore\Wx\Element\Frame;
use Encore\Wx\Element\Dialog;
use Encore\Giml\ElementInterface;
use Encore\Giml\CollectionInterface;
use Encore\Controller\ControllerAwareTrait;
use Encore\Controller\ControllerAwareInterface;
use Encore\Container\ContainerAwareInterface;
use Encore\Container\ContainerAwareTrait;
use Encore\Giml\Exception\DuplicateIdException;

class Collection implements CollectionInterface, ControllerAwareInterface, ContainerAwareInterface
{
    use ControllerAwareTrait;
    use ContainerAwareTrait;

    protected $objects = [];
    protected $ids = [];

    /**
     * Add an element to the collection
     *
     * @param ElementInterface $element
     */
    public function add(ElementInterface $element)
    {
        $id = $element->id;

        if ($id === null) $id = $this->generateId();

        $element->id = $id;

        $this->checkId($id);

        $this->objects[] = $element;

        if (count($this->objects) === 1) {
            array_unshift($this->objects, 'pseudo');
            unset($this->objects[0]);
        }

        $this->ids[array_search($element, $this->objects, true)] = $id;
    }

    /**
     * Get the top-level window element
     *
     * @return ElementInterface
     */
    public function getTopLevelWindow()
    {
        foreach ($this->objects as $object) {
            if ($object instanceof Frame
            or $object instanceof Dialog) {
                return $object;
            }
        }
    }

    /**
     * Remove the element from the collection
     *
     * @return void
     */
    public function remove($element)
    {
        $trueId = $this->getTrueId($element);

        $this->objects[$trueId]->destroy();

        unset($this->objects[$trueId]);
        unset($this->ids[$trueId]);
    }

    /**
     * Get an element by its ID
     *
     * @param  string|int $id
     * @return ElementInterface
     */
    public function getElementById($id)
    {
        $id = $this->getTrueId($id);

        if ($id === false) {
            // Throw something
            return;
        }

        return $this->objects[$id];
    }

    /**
     * Get the true ID for a custom element ID
     *
     * @param  mixed $id
     * @return int
     */
    public function getTrueId($id)
    {
        return array_search($id, $this->ids, true);
    }

    /**
     * Generate an ID if one wasn't specified
     *
     * @return string
     */
    public function generateId()
    {
        return uniqid('auto', true);
    }

    /**
     * Check an ID does not already exist
     *
     * @param  mixed $id
     * @throws DuplicateIdException
     * @return void
     */
    protected function checkId($id)
    {
        if (in_array($id, $this->ids)) {
            throw new DuplicateIdException("The ID '{$id}' is already in use");
        }
    }
}


<?php

namespace Rougin\Describe;

use Rougin\Describe\Driver\DriverInterface;

/**
 * Table
 *
 * Stores the table information from the given results.
 *
 * @package Describe
 * @author  Rougin Gutib <rougingutib@gmail.com>
 */
class Table
{
    /**
     * @var \Rougin\Describe\Driver\DriverInterface
     */
    protected $driver;

    /**
     * @var string
     */
    protected $name;

    /**
     * Initializes the table instance.
     *
     * @param string                                  $name
     * @param \Rougin\Describe\Driver\DriverInterface $driver
     */
    public function __construct($name, DriverInterface $driver)
    {
        $this->driver = $driver;

        $this->name = (string) $name;
    }

    /**
     * Returns an array of Column instances.
     *
     * @return \Rougin\Describe\Column[]
     */
    public function columns()
    {
        return $this->driver->columns($this->name);
    }

    /**
     * Returns the name of the table.
     *
     * @return string
     */
    public function name()
    {
        return $this->name;
    }

    /**
     * Returns the primary key of a table.
     *
     * @return \Rougin\Describe\Column|null
     */
    public function primary()
    {
        foreach ($this->columns() as $column) {
            $primary = $column->isPrimaryKey();

            $primary && $result = $column;
        }

        return isset($result) ? $result : null;
    }
}


<?php
/**
 * This file is a part of the page-fetcher package.
 *
 * Read more at https://github.com/themichaelhall/page-fetcher
 */
declare(strict_types=1);

namespace MichaelHall\PageFetcher;

use MichaelHall\PageFetcher\Interfaces\PageFetcherInterface;
use MichaelHall\PageFetcher\Interfaces\PageFetcherRequestInterface;
use MichaelHall\PageFetcher\Interfaces\PageFetcherResponseInterface;

/**
 * Fake page fetcher class.
 *
 * @since 1.0.0
 */
class FakePageFetcher implements PageFetcherInterface
{
    /**
     * Constructs a fake page fetcher.
     *
     * @since 1.0.0
     */
    public function __construct()
    {
        $this->responseHandler = null;
    }

    /**
     * Fetches the content from a request.
     *
     * @since 1.0.0
     *
     * @param PageFetcherRequestInterface $request The page fetcher request.
     *
     * @return PageFetcherResponseInterface The page fetcher response.
     */
    public function fetch(PageFetcherRequestInterface $request): PageFetcherResponseInterface
    {
        if ($this->responseHandler === null) {
            return new PageFetcherResponse();
        }

        return call_user_func($this->responseHandler, $request);
    }

    /**
     * Sets the response handler to use for returning a response.
     *
     * The handler must be a callable in form: function(PageFetcherRequestInterface $request): PageFetcherResponseInterface
     *
     * @since 1.0.0
     *
     * @param callable $responseHandler The response handler.
     */
    public function setResponseHandler(callable $responseHandler): void
    {
        $this->responseHandler = $responseHandler;
    }

    /**
     * @var callable|null My response handler.
     */
    private $responseHandler;
}


<?php

/**
 * @file
 * TeamSpeak 3 PHP Framework
 *
 * $Id: Update.php 9/26/2011 7:06:29 scp@orilla $
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * @package   TeamSpeak3
 * @version   1.1.8-beta
 * @author    Sven 'ScP' Paulsen
 * @copyright Copyright (c) 2010 by Planet TeamSpeak. All rights reserved.
 */

namespace ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Adapter;

/**
 * @class TeamSpeak3_Adapter_Update
 * @brief Provides methods to query the latest TeamSpeak 3 build numbers from the master server.
 */
class Update extends AbstractAdapter
{
  /**
   * The IPv4 address or FQDN of the TeamSpeak Systems update server.
   *
   * @var string
   */
  protected $default_host = "update.teamspeak.com";

  /**
   * The UDP port number of the TeamSpeak Systems update server.
   *
   * @var integer
   */
  protected $default_port = 17384;

  /**
   * Stores an array containing the latest build numbers.
   *
   * @var array
   */
  protected $build_numbers = null;

  /**
   * Connects the TeamSpeak3_Transport_Abstract object and performs initial actions on the remote
   * server.
   *
   * @throws Update\Exception
   * @return void
   */
  public function syn()
  {
    if(!isset($this->options["host"]) || empty($this->options["host"])) $this->options["host"] = $this->default_host;
    if(!isset($this->options["port"]) || empty($this->options["port"])) $this->options["port"] = $this->default_port;

    $this->initTransport($this->options, '\ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Transport\UDP');
    $this->transport->setAdapter($this);

    \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Helper\Profiler::init(spl_object_hash($this));

    $this->getTransport()->send(\ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Helper\String::fromHex(32));

    if(!preg_match_all("/,?(\d+),?/", $this->getTransport()->read(32), $matches) || !isset($matches[1]))
    {
      throw new Update\Exception("invalid reply from the server");
    }

    $this->build_numbers = $matches[1];

    \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Helper\Signal::getInstance()->emit("updateConnected", $this);
  }

  /**
   * The TeamSpeak3_Adapter_Update destructor.
   *
   * @return void
   */
  public function __destruct()
  {
    if($this->getTransport() instanceof \ManiaLivePlugins\Standard\TeamSpeak\TeamSpeak3\Transport\AbstractTransport && $this->getTransport()->isConnected())
    {
      $this->getTransport()->disconnect();
    }
  }

  /**
   * Returns the build number for a specified development status. $channel must be
   * set to one of the following values:
   *
   * - stable
   * - beta
   * - alpha
   * - server
   *
   * @param  string  $channel
   * @throws Update\Exception
   * @return integer
   */
  public function getRev($channel = "stable")
  {
    switch($channel)
    {
      case "stable":
        return isset($this->build_numbers[0]) ? $this->build_numbers[0] : null;

      case "beta":
        return isset($this->build_numbers[1]) ? $this->build_numbers[1] : null;

      case "alpha":
        return isset($this->build_numbers[2]) ? $this->build_numbers[2] : null;

      case "server":
        return isset($this->build_numbers[3]) ? $this->build_numbers[3] : null;

      default:
        throw new Update\Exception("invalid update channel identifier (" . $channel . ")");
    }
  }

  /**
   * Alias for getRev() using the 'server' update channel.
   *
   * @param  string  $channel
   * @return integer
   */
  public function getServerRev()
  {
    return $this->getRev("server");
  }
}


<?php namespace Jonsa\PimpleResolver;

use Jonsa\PimpleResolver\Contract\ClassResolver as ClassResolverContract;
use Pimple\Container;
use Pimple\ServiceProviderInterface;

/**
 * Class ServiceProvider
 *
 * @package Jonsa\PimpleResolver
 * @author Jonas Sandström
 */
class ServiceProvider implements ServiceProviderInterface
{

    /**
     * This is the key used to bind the resolver implementation.
     *
     * @var string
     */
    const CLASS_RESOLVER = 'jonsa.pimple_resolver.class_resolver';

    /**
     * Set the event dispatcher. Either a dispatcher instance or a string where
     * a dispatcher can be found in the container.
     *
     * @var string
     */
    const EVENT_DISPATCHER = 'jonsa.pimple_resolver.event_dispatcher';

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

    /**
     * @var string
     */
    private $makeMethod;

    /**
     * @var string
     */
    private $bindMethod;

    /**
     * @param bool $bindContainerInstance
     * @param string $makeMethod
     * @param string $bindMethod
     */
    public function __construct($bindContainerInstance = true, $makeMethod = 'make', $bindMethod = 'bind')
    {
        $this->bindContainerInstance = (bool)$bindContainerInstance;
        $this->makeMethod = $makeMethod;
        $this->bindMethod = $bindMethod;
    }

    /**
     * Registers services on the given container.
     *
     * This method should only be used to configure services and parameters.
     * It should not get services.
     *
     * @param Container $container A container instance
     */
    public function register(Container $container)
    {
        $that = $this;

        $container[self::CLASS_RESOLVER] = function () use ($that, $container) {
            $resolver = new ClassResolver($that->getEventDispatcher($container));
            $that->bindContainer($resolver, $container);

            return $resolver;
        };

        $container[$this->makeMethod] = $container->protect(
            function ($abstract, $parameters = array()) use ($container) {
                return $container[ServiceProvider::CLASS_RESOLVER]
                    ->resolve($abstract, $parameters);
            }
        );

        $container[$this->bindMethod] = $container->protect(
            function ($abstract, $concrete, $protect = false) use ($container) {
                return $container[ServiceProvider::CLASS_RESOLVER]
                    ->bind($abstract, $concrete, $protect);
            }
        );
    }

    /**
     * @param ClassResolverContract $resolver
     * @param Container $container
     */
    private function bindContainer(ClassResolverContract $resolver, Container $container)
    {
        if ($this->bindContainerInstance) {
            $base = 'Pimple\\Container';
            $class = get_class($container);

            $resolver->bind($base, function () use ($container) {
                return $container;
            }, true);

            if ($class !== $base) {
                $resolver->bind($class, function () use ($container) {
                    return $container;
                }, true);
            }
        }
    }

    /**
     * @param Container $container
     * @return \Symfony\Component\EventDispatcher\EventDispatcherInterface|null
     */
    private function getEventDispatcher(Container $container)
    {
        if ($container->offsetExists(self::EVENT_DISPATCHER)) {
            $dispatcher = $container[self::EVENT_DISPATCHER];

            if (is_string($dispatcher)) {
                return $container[$dispatcher];
            }

            return $dispatcher;
        }

        return null;
    }

}


<?php

namespace DevGroup\ExtensionsManager\models;

use DevGroup\ExtensionsManager\helpers\ApplicationConfigWriter;
use Yii;
use yii\base\DynamicModel;
use yii\helpers\ArrayHelper;
use yii\helpers\StringHelper;

/**
 * Abstract class for configurable models of configurable modules.
 * @package app\models
 */
abstract class BaseConfigurationModel extends DynamicModel
{
    /**
     * Get a module name for this configuration model
     * @return string
     */
    abstract public function getModuleClassName();

    /**
     * Returns array of module configuration that should be stored in application config.
     * Array should be ready to merge in app config.
     * Used both for web only.
     *
     * @return array
     */
    abstract public function webApplicationAttributes();

    /**
     * Returns array of module configuration that should be stored in application config.
     * Array should be ready to merge in app config.
     * Used both for console only.
     *
     * @return array
     */
    abstract public function consoleApplicationAttributes();

    /**
     * Returns array of module configuration that should be stored in application config.
     * Array should be ready to merge in app config.
     * Used both for web and console.
     *
     * @return array
     */
    abstract public function commonApplicationAttributes();

    /**
     * Returns array of key=>values for configuration.
     *
     * @return mixed
     */
    abstract public function appParams();

    /**
     * Returns array of aliases that should be set in common config
     * @return array
     */
    abstract public function aliases();

    /**
     * BaseConfigurationModel constructor.
     * There are a building of rules, a building of attributeLabels and attributes definition here.
     * @param array $config
     */
    public function __construct(array $config = [])
    {
        $attributes = [];
        foreach ($this->rules() as $rules) {
            $attributes = ArrayHelper::merge($attributes, (array) $rules[0]);
        }
        $attributes = array_unique($attributes);
        parent::__construct($attributes, $config);
        $module = call_user_func([$this->getModuleClassName(), 'module']);
        foreach ($attributes as $name) {
            $this->$name = $module->$name;
        }
    }

    /**
     * The name of event that is triggered when this configuration is being saved.
     * The event will be triggered before model validation proceeds and after model is loaded with user-input.
     *
     * @return string Configuration save event name
     */
    public function configurationSaveEvent()
    {
        return StringHelper::basename(get_class($this)) . 'ConfigurationSaveEvent';
    }

    /**
     * @return string Returns filename of file for saving model state without '.php' extension
     */
    protected function stateFilename()
    {
        return preg_replace('#^.*\\\\(.*)$#', "$1", $this->className());
    }

    /**
     * Loads state from file
     * @param string $statePath Path where model state files are stored.
     * @return bool result
     */
    public function loadState($statePath)
    {
        $filename = Yii::getAlias($statePath . $this->stateFilename() . '.php');
        if (is_readable($filename) === true) {
            $this->loadAttributesFromState(
                include($filename)
            );
            return true;
        } else {
            return false;
        }
    }

    public function deleteFromState($statePath)
    {
        $filename = Yii::getAlias($statePath . $this->stateFilename() . '.php');
        if (true === is_readable($filename)) {
            return unlink($filename);
        }
        return false;
    }
    /**
     * Saves state to file
     * @param string $statePath Path where model state files are stored.
     * @return bool
     */
    public function saveState($statePath)
    {
        $filename = Yii::getAlias($statePath . $this->stateFilename() . '.php');
        $writer = new ApplicationConfigWriter([
            'filename' => $filename,
        ]);
        $writer->configuration = $this->getAttributesForStateSaving();
        $result =  $writer->commit();
        return $result;
    }

    /**
     * @return array attributes that used for saving configurable model state
     */
    public function getAttributesForStateSaving()
    {
        return $this->getAttributes();
    }

    /**
     * Fills model attributes with previous saved state
     * @param $values array of state form file
     * @return bool result
     */
    public function loadAttributesFromState($values)
    {
        parent::setAttributes($values, false);
        return true;
    }
}


<?php

namespace Shoko\TwitchApiBundle\Factory;

use Shoko\TwitchApiBundle\Model\Entity\MyChannel;

/**
 * Class MyChannelFactory.
 */
class MyChannelFactory implements FactoryInterface
{
    /**
     * @param array $data
     * @param false|MyChannel $myChannel
     *
     * @return MyChannel
     */
    public function createEntity(array $data, $myChannel = false)
    {
        if (false === $myChannel) {
            $myChannel = MyChannel::create();
        }

        $myChannel = (new ChannelFactory())->createEntity($data, $myChannel);

        if (isset($data['email'])) {
            $myChannel = $myChannel->setEmail($data['email']);
        }

        if (isset($data['stream_key'])) {
            $myChannel = $myChannel->setStreamKey($data['stream_key']);
        }

        return $myChannel;
    }
}


<?php

namespace Shoko\TwitchApiBundle\Factory;

use Shoko\TwitchApiBundle\Model\Entity\Me;

/**
 * Class MeFactory.
 */
class MeFactory implements FactoryInterface
{
    /**
     * @param array $data
     * @param false|Me $me
     *
     * @return Me
     */
    public function createEntity(array $data, $me = false)
    {
        if (false === $me) {
            $me = Me::create();
        }

        $me = (new UserFactory())->createEntity($data, $me);

        if (isset($data['email'])) {
            $me = $me->setEmail($data['email']);
        }

        if (isset($data['partnered'])) {
            $me = $me->setPartnered($data['partnered']);
        }

        if (isset($data['notifications'])) {
            $me = $me->setNotifications($data['notifications']);
        }

        return $me;
    }
}


<?php

namespace Rougin\Describe;

use Doctrine\Common\Inflector\Inflector;

/**
 * Column Class
 *
 * Stores a column information from the results given.
 *
 * @package Describe
 * @author  Rougin Gutib <rougingutib@gmail.com>
 */
class Column
{
    /**
     * @var boolean
     */
    protected $increment = false;

    /**
     * @var string
     */
    protected $type = '';

    /**
     * @var string
     */
    protected $default = '';

    /**
     * @var string
     */
    protected $field = '';

    /**
     * @var boolean
     */
    protected $foreign = false;

    /**
     * @var integer
     */
    protected $length = 0;

    /**
     * @var boolean
     */
    protected $null = false;

    /**
     * @var boolean
     */
    protected $primary = false;

    /**
     * @var array
     */
    protected $reference = array('field' => '', 'table' => '');

    /**
     * @var boolean
     */
    protected $unique = false;

    /**
     * @var boolean
     */
    protected $unsigned = false;

    /**
     * Gets the data type.
     *
     * @return string
     */
    public function getDataType()
    {
        return $this->type;
    }

    /**
     * Gets the default value.
     *
     * @return string
     */
    public function getDefaultValue()
    {
        return $this->default;
    }

    /**
     * Gets the column description.
     *
     * @return string
     */
    public function getField()
    {
        return $this->field;
    }

    /**
     * Gets the foreign field.
     *
     * @return string
     */
    public function getReferencedField()
    {
        return $this->reference['field'];
    }

    /**
     * Gets the foreign table.
     *
     * @return string
     */
    public function getReferencedTable()
    {
        return $this->reference['table'];
    }

    /**
     * Gets the field's length.
     *
     * @return integer
     */
    public function getLength()
    {
        return $this->length;
    }

    /**
     * Check if the field is an auto incrementing field.
     *
     * @return boolean
     */
    public function isAutoIncrement()
    {
        return $this->increment;
    }

    /**
     * Check if the field is a foreign key.
     *
     * @return boolean
     */
    public function isForeignKey()
    {
        return $this->foreign;
    }

    /**
     * Check if the field accept NULL values.
     *
     * @return boolean
     */
    public function isNull()
    {
        return $this->null;
    }

    /**
     * Check if the field is a primary key.
     *
     * @return boolean
     */
    public function isPrimaryKey()
    {
        return $this->primary;
    }

    /**
     * Check if field is unique.
     *
     * @return boolean
     */
    public function isUnique()
    {
        return $this->unique;
    }

    /**
     * Check if field is unsigned.
     *
     * @return boolean
     */
    public function isUnsigned()
    {
        return $this->unsigned;
    }

    /**
     * Sets the auto increment.
     *
     * @param boolean $increment
     */
    public function setAutoIncrement($increment)
    {
        $this->increment = $increment;

        return $this;
    }

    /**
     * Sets the data type.
     *
     * @param  string $type
     * @return self
     */
    public function setDataType($type)
    {
        $types = array('integer', 'string', 'string');

        $shorthand = array('int', 'varchar', 'text');

        $index = array_search($type, $shorthand);

        $this->type = $index === false ? $type : $types[$index];

        return $this;
    }

    /**
     * Sets the default value.
     *
     * @param string $default
     */
    public function setDefaultValue($default)
    {
        $this->default = $default;

        return $this;
    }

    /**
     * Sets the column's description.
     *
     * @param string $field
     */
    public function setField($field)
    {
        $this->field = $field;

        return $this;
    }

    /**
     * Sets the field as a foreign key.
     *
     * @param boolean $foreign
     */
    public function setForeign($foreign)
    {
        $this->foreign = $foreign;

        return $this;
    }

    /**
     * Sets the foreign field.
     *
     * @param string $field
     */
    public function setReferencedField($field)
    {
        $this->reference['field'] = $field;

        return $this;
    }

    /**
     * Sets the foreign table.
     *
     * @param string $table
     */
    public function setReferencedTable($table)
    {
        $this->reference['table'] = $table;

        return $this;
    }

    /**
     * Sets the field's length.
     *
     * @param integer $length
     */
    public function setLength($length)
    {
        $this->length = $length;

        return $this;
    }

    /**
     * Sets if field accepts NULL values.
     *
     * @param boolean $null
     */
    public function setNull($null = true)
    {
        $this->null = $null;

        return $this;
    }

    /**
     * Sets if field is a primary key.
     *
     * @param boolean $primary
     */
    public function setPrimary($primary = true)
    {
        $this->primary = $primary;

        return $this;
    }

    /**
     * Sets if field is a unique key.
     *
     * @param boolean $unique
     */
    public function setUnique($unique = true)
    {
        $this->unique = $unique;

        return $this;
    }

    /**
     * Sets if field is an unsigned key.
     *
     * @param boolean $unsigned
     */
    public function setUnsigned($unsigned = true)
    {
        $this->unsigned = $unsigned;

        return $this;
    }

    /**
     * Calls methods from this class in underscore case.
     * NOTE: To be removed in v2.0.0. All new methods are now in one word.
     *
     * @param  string $method
     * @param  mixed  $parameters
     * @return mixed
     */
    public function __call($method, $parameters)
    {
        $method = Inflector::camelize($method);

        if (method_exists($this, $method) === true) {
            $instance = array($this, $method);

            $result = call_user_func_array($instance, $parameters);
        }

        return isset($result) ? $result : $this;
    }
}