]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Add FirePHP plugin - uses FirePHP as an output method for logging
authorCraig Andrews <candrews@integralblue.com>
Sat, 5 Dec 2009 07:13:40 +0000 (02:13 -0500)
committerCraig Andrews <candrews@integralblue.com>
Sat, 5 Dec 2009 07:13:40 +0000 (02:13 -0500)
plugins/FirePHP/FirePHPPlugin.php [new file with mode: 0644]
plugins/FirePHP/README [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/CHANGELOG [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/CREDITS [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/README [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php4 [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/LICENSE [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php [new file with mode: 0644]
plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php4 [new file with mode: 0644]

diff --git a/plugins/FirePHP/FirePHPPlugin.php b/plugins/FirePHP/FirePHPPlugin.php
new file mode 100644 (file)
index 0000000..37b3977
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+/*
+StatusNet Plugin: 0.9
+Plugin Name: FirePHP
+Description: Sends StatusNet log output to FirePHP
+Version: 0.1
+Author: Craig Andrews <candrews@integralblue.com>
+Author URI: http://candrews.integralblue.com/
+*/
+
+/*
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @package MinifyPlugin
+ * @maintainer Craig Andrews <candrews@integralblue.com>
+ */
+
+if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+// We bundle the FirePHP library...
+set_include_path(get_include_path() . PATH_SEPARATOR . dirname(__FILE__) . '/extlib/FirePHP/lib');
+
+class FirePHPPlugin extends Plugin
+{
+    private $firephp;
+
+    function onInitializePlugin()
+    {
+        //Output buffering has to be enabled so FirePHP can send the HTTP headers it needs
+        ob_start();
+        require_once('FirePHPCore/FirePHP.class.php');
+        $this->firephp = FirePHP::getInstance(true);
+    }
+
+    function onStartLog(&$priority, &$msg, &$filename)
+    {
+        static $firephp_priorities = array(FirePHP::ERROR, FirePHP::ERROR, FirePHP::ERROR, FirePHP::ERROR,
+                                      FirePHP::WARN, FirePHP::LOG, FirePHP::LOG, FirePHP::INFO);
+        $priority = $firephp_priorities[$priority];
+        $this->firephp->fb($msg, $priority);
+    }
+}
+
diff --git a/plugins/FirePHP/README b/plugins/FirePHP/README
new file mode 100644 (file)
index 0000000..ee22794
--- /dev/null
@@ -0,0 +1,21 @@
+The FirePHP writes StatusNet's log output to FirePHP.
+
+Using FirePHP on production sites can expose sensitive information.
+    You must protect the security of your application by disabling FirePHP
+    logging on your live site.
+
+Installation
+============
+add "addPlugin('FirePHP',
+    array('setting'=>'value', 'setting2'=>'value2', ...);"
+to the bottom of your config.php
+
+Settings
+========
+None at the moment.
+
+Example
+=======
+
+addPlugin('FirePHP', array());
+
diff --git a/plugins/FirePHP/extlib/FirePHP/CHANGELOG b/plugins/FirePHP/extlib/FirePHP/CHANGELOG
new file mode 100644 (file)
index 0000000..6191980
--- /dev/null
@@ -0,0 +1,110 @@
+
+2008-06-14 - Release Version: 0.3.1
+
+  - (Issue 108) ignore class name case in object filter
+
+2009-05-11 - Release Version: 0.3
+2009-05-01 - Release Version: 0.3.rc.1
+
+  - (Issue 90) PHP4 compatible version of FirePHPCore
+  - (Issue 98) Thrown exceptions don't send an HTTP 500 if the FirePHP exception handler is enabled
+  - (Issue 85) Support associative arrays in encodeTable method in FirePHP.class.php
+  - (Issue 66) Add a new getOptions() public method in API
+  - (Issue 82) Define $this->options outside of __construct
+  - (Issue 72) Message error if group name is null
+  - (Issue 68) registerErrorHandler() and registerExceptionHandler() should returns previous handlers defined
+  - (Issue 69) Add the missing register handler in the triumvirate (error, exception, assert)
+  - (Issue 75) [Error & Exception Handling] Option to not exit script execution
+  - (Issue 83) Exception handler can't throw exceptions
+  - (Issue 80) Auto/Pre collapsing groups AND Custom group row colors
+
+2008-11-09 - Release Version: 0.2.1
+
+  - (Issue 70) Problem when logging resources
+
+2008-10-21 - Release Version: 0.2.0
+
+       - Updated version to 0.2.0
+       - Switched to using __sleep instead of __wakeup
+       - Added support to exclude object members when encoding
+  - Add support to enable/disable logging
+
+2008-10-17 - Release Version: 0.2.b.8
+  
+  - New implementation for is_utf8()
+  - (Issue 55) maxObjectDepth Option not working correctly when using TABLE and EXCEPTION Type
+  - Bugfix for max[Object|Array]Depth when encoding nested array/object graphs
+  - Bugfix for FB::setOptions()
+
+2008-10-16 - Release Version: 0.2.b.7
+
+  - (Issue 45) Truncate dump when string have non utf8 cars
+  - (Issue 52) logging will not work when firephp object gets stored in the session.
+
+2008-10-16 - Release Version: 0.2.b.6
+
+  - (Issue 37) Display file and line information for each log message
+  - (Issue 51) Limit output of object graphs
+  - Bugfix for encoding object members set to NULL|false|''
+
+2008-10-14 - Release Version: 0.2.b.5
+
+  - Updated JsonStream wildfire protocol to be more robust
+  - (Issue 33) PHP error notices running demos
+  - (Issue 48) Warning: ReflectionProperty::getValue() expects exactly 1 parameter, 0 given
+
+2008-10-08 - Release Version: 0.2.b.4
+
+       - Bugfix for logging objects with recursion
+
+2008-10-08 - Release Version: 0.2.b.3
+
+  - (Issue 43) Notice message in 0.2b2
+  - Added support for PHP's native json_encode() if available
+  - Revised object encoder to detect object recursion
+
+2008-10-07 - Release Version: 0.2.b.2
+
+  - (Issue 28) Need solution for logging private and protected object variables
+  - Added trace() and table() aliases in FirePHP class
+  - (Issue 41) Use PHP doc in FirePHP
+  - (Issue 39) Static logging method for object oriented API
+
+2008-10-01 - Release Version: 0.2.b.1
+
+  - Added support for error and exception handling
+  - Updated min PHP version for PEAR package to 5.2
+  - Added version constant for library
+  - Gave server library it's own wildfire plugin namespace
+  - Migrated communication protocol to Wildfire JsonStream
+  - Added support for console groups using "group" and "groupEnd"
+  - Added support for log, info, warn and error logging aliases
+  - (Issue 29) problem with TRACE when using with error_handler
+  - (Issue 33) PHP error notices running demos
+  - (Issue 12) undefined index php notice
+  - Removed closing ?> php tags
+  - (Issue 13) the code in the fb() function has a second return statement that will never be reached
+
+2008-07-30 - Release Version: 0.1.1.3
+
+       - Include __className property in JSON string if variable was an object
+       - Bugfix - Mis-spelt "Exception" in JSON encoding code
+
+2008-06-13 - Release Version: 0.1.1.1
+
+       - Bugfix - Standardize windows paths in stack traces
+       - Bugfix - Display correct stack trace info in windows environments
+       - Bugfix - Check $_SERVER['HTTP_USER_AGENT'] before returning
+
+2008-06-13 - Release Version: 0.1.1
+
+       - Added support for FirePHP::TRACE log style
+       - Changed license to New BSD License
+
+2008-06-06 - Release Version: 0.0.2
+
+  - Bugfix - Added usleep() to header writing loop to ensure unique index
+  - Bugfix - Ensure chunk_split does not generate trailing "\n" with empty data header
+  - Added support for FirePHP::TABLE log style
+  
\ No newline at end of file
diff --git a/plugins/FirePHP/extlib/FirePHP/CREDITS b/plugins/FirePHP/extlib/FirePHP/CREDITS
new file mode 100644 (file)
index 0000000..5f0d463
--- /dev/null
@@ -0,0 +1,12 @@
+                         _______________________________
+                         F  i  r  e  P  H  P  C  o  r  e
+                         
+  Current Development
+  -------------------
+    
+  Christoph Dorn <christoph@christophdorn.com>
+  Michael Day    <manveru.alma@gmail.com>
+
+  If you've done work on FirePHPCore and you are not listed here,
+  please feel free to add yourself.
+
diff --git a/plugins/FirePHP/extlib/FirePHP/README b/plugins/FirePHP/extlib/FirePHP/README
new file mode 100644 (file)
index 0000000..033719f
--- /dev/null
@@ -0,0 +1,32 @@
+
+Version: 0.3.1
+
+------------------------------------------------------
+       Requirements
+------------------------------------------------------
+
+Client Side:
+
+       - Firefox - http://www.getfirefox.com/
+       - Firebug - http://www.getfirebug.com/
+       - FirePHP - http://www.firephp.org/
+
+Server Side:
+       
+       - PHP 5 (complete functionality)
+       - PHP 4 (most functionality)
+
+
+------------------------------------------------------
+       Install Tutorial
+------------------------------------------------------
+       
+       http://www.firephp.org/HQ/Install.htm
+       
+       
+------------------------------------------------------
+       Support
+------------------------------------------------------
+       
+       http://forum.firephp.org/
+       
diff --git a/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php b/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php
new file mode 100644 (file)
index 0000000..d8ae13f
--- /dev/null
@@ -0,0 +1,1529 @@
+<?php
+/**
+ * *** BEGIN LICENSE BLOCK *****
+ *  
+ * This file is part of FirePHP (http://www.firephp.org/).
+ * 
+ * Software License Agreement (New BSD License)
+ * 
+ * Copyright (c) 2006-2009, Christoph Dorn
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ *     * Neither the name of Christoph Dorn nor the names of its
+ *       contributors may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * ***** END LICENSE BLOCK *****
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+/**
+ * Sends the given data to the FirePHP Firefox Extension.
+ * The data can be displayed in the Firebug Console or in the
+ * "Server" request tab.
+ * 
+ * For more information see: http://www.firephp.org/
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+class FirePHP {
+  
+  /**
+   * FirePHP version
+   *
+   * @var string
+   */
+  const VERSION = '0.3';
+  
+  /**
+   * Firebug LOG level
+   *
+   * Logs a message to firebug console.
+   * 
+   * @var string
+   */
+  const LOG = 'LOG';
+  
+  /**
+   * Firebug INFO level
+   *
+   * Logs a message to firebug console and displays an info icon before the message.
+   * 
+   * @var string
+   */
+  const INFO = 'INFO';
+  
+  /**
+   * Firebug WARN level
+   *
+   * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
+   * 
+   * @var string
+   */
+  const WARN = 'WARN';
+  
+  /**
+   * Firebug ERROR level
+   *
+   * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
+   * 
+   * @var string
+   */
+  const ERROR = 'ERROR';
+  
+  /**
+   * Dumps a variable to firebug's server panel
+   *
+   * @var string
+   */
+  const DUMP = 'DUMP';
+  
+  /**
+   * Displays a stack trace in firebug console
+   *
+   * @var string
+   */
+  const TRACE = 'TRACE';
+  
+  /**
+   * Displays an exception in firebug console
+   * 
+   * Increments the firebug error count.
+   *
+   * @var string
+   */
+  const EXCEPTION = 'EXCEPTION';
+  
+  /**
+   * Displays an table in firebug console
+   *
+   * @var string
+   */
+  const TABLE = 'TABLE';
+  
+  /**
+   * Starts a group in firebug console
+   * 
+   * @var string
+   */
+  const GROUP_START = 'GROUP_START';
+  
+  /**
+   * Ends a group in firebug console
+   * 
+   * @var string
+   */
+  const GROUP_END = 'GROUP_END';
+  
+  /**
+   * Singleton instance of FirePHP
+   *
+   * @var FirePHP
+   */
+  protected static $instance = null;
+  
+  /**
+   * Flag whether we are logging from within the exception handler
+   * 
+   * @var boolean
+   */
+  protected $inExceptionHandler = false;
+  
+  /**
+   * Flag whether to throw PHP errors that have been converted to ErrorExceptions
+   * 
+   * @var boolean
+   */
+  protected $throwErrorExceptions = true;
+  
+  /**
+   * Flag whether to convert PHP assertion errors to Exceptions
+   * 
+   * @var boolean
+   */
+  protected $convertAssertionErrorsToExceptions = true;
+  
+  /**
+   * Flag whether to throw PHP assertion errors that have been converted to Exceptions
+   * 
+   * @var boolean
+   */
+  protected $throwAssertionExceptions = false;
+  
+  /**
+   * Wildfire protocol message index
+   *
+   * @var int
+   */
+  protected $messageIndex = 1;
+    
+  /**
+   * Options for the library
+   * 
+   * @var array
+   */
+  protected $options = array('maxObjectDepth' => 10,
+                             'maxArrayDepth' => 20,
+                             'useNativeJsonEncode' => true,
+                             'includeLineNumbers' => true);
+
+  /**
+   * Filters used to exclude object members when encoding
+   * 
+   * @var array
+   */
+  protected $objectFilters = array();
+  
+  /**
+   * A stack of objects used to detect recursion during object encoding
+   * 
+   * @var object
+   */
+  protected $objectStack = array();
+  
+  /**
+   * Flag to enable/disable logging
+   * 
+   * @var boolean
+   */
+  protected $enabled = true;
+
+  /**
+   * The object constructor
+   */
+  function __construct() {
+  }
+
+  /**
+   * When the object gets serialized only include specific object members.
+   * 
+   * @return array
+   */  
+  public function __sleep() {
+    return array('options','objectFilters','enabled');
+  }
+    
+  /**
+   * Gets singleton instance of FirePHP
+   *
+   * @param boolean $AutoCreate
+   * @return FirePHP
+   */
+  public static function getInstance($AutoCreate=false) {
+    if($AutoCreate===true && !self::$instance) {
+      self::init();
+    }
+    return self::$instance;
+  }
+   
+  /**
+   * Creates FirePHP object and stores it for singleton access
+   *
+   * @return FirePHP
+   */
+  public static function init() {
+    return self::$instance = new self();
+  }
+  
+  /**
+   * Enable and disable logging to Firebug
+   * 
+   * @param boolean $Enabled TRUE to enable, FALSE to disable
+   * @return void
+   */
+  public function setEnabled($Enabled) {
+    $this->enabled = $Enabled;
+  }
+  
+  /**
+   * Check if logging is enabled
+   * 
+   * @return boolean TRUE if enabled
+   */
+  public function getEnabled() {
+    return $this->enabled;
+  }
+  
+  /**
+   * Specify a filter to be used when encoding an object
+   * 
+   * Filters are used to exclude object members.
+   * 
+   * @param string $Class The class name of the object
+   * @param array $Filter An array of members to exclude
+   * @return void
+   */
+  public function setObjectFilter($Class, $Filter) {
+    $this->objectFilters[strtolower($Class)] = $Filter;
+  }
+  
+  /**
+   * Set some options for the library
+   * 
+   * Options:
+   *  - maxObjectDepth: The maximum depth to traverse objects (default: 10)
+   *  - maxArrayDepth: The maximum depth to traverse arrays (default: 20)
+   *  - useNativeJsonEncode: If true will use json_encode() (default: true)
+   *  - includeLineNumbers: If true will include line numbers and filenames (default: true)
+   * 
+   * @param array $Options The options to be set
+   * @return void
+   */
+  public function setOptions($Options) {
+    $this->options = array_merge($this->options,$Options);
+  }
+  
+  /**
+   * Get options from the library
+   *
+   * @return array The currently set options
+   */
+  public function getOptions() {
+    return $this->options;
+  }
+  
+  /**
+   * Register FirePHP as your error handler
+   * 
+   * Will throw exceptions for each php error.
+   * 
+   * @return mixed Returns a string containing the previously defined error handler (if any)
+   */
+  public function registerErrorHandler($throwErrorExceptions=true)
+  {
+    //NOTE: The following errors will not be caught by this error handler:
+    //      E_ERROR, E_PARSE, E_CORE_ERROR,
+    //      E_CORE_WARNING, E_COMPILE_ERROR,
+    //      E_COMPILE_WARNING, E_STRICT
+    
+    $this->throwErrorExceptions = $throwErrorExceptions;
+    
+    return set_error_handler(array($this,'errorHandler'));     
+  }
+
+  /**
+   * FirePHP's error handler
+   * 
+   * Throws exception for each php error that will occur.
+   *
+   * @param int $errno
+   * @param string $errstr
+   * @param string $errfile
+   * @param int $errline
+   * @param array $errcontext
+   */
+  public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
+  {
+    // Don't throw exception if error reporting is switched off
+    if (error_reporting() == 0) {
+      return;
+    }
+    // Only throw exceptions for errors we are asking for
+    if (error_reporting() & $errno) {
+
+      $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
+      if($this->throwErrorExceptions) {
+        throw $exception;
+      } else {
+        $this->fb($exception);
+      }
+    }
+  }
+  
+  /**
+   * Register FirePHP as your exception handler
+   * 
+   * @return mixed Returns the name of the previously defined exception handler,
+   *               or NULL on error.
+   *               If no previous handler was defined, NULL is also returned.
+   */
+  public function registerExceptionHandler()
+  {
+    return set_exception_handler(array($this,'exceptionHandler'));     
+  }
+  
+  /**
+   * FirePHP's exception handler
+   * 
+   * Logs all exceptions to your firebug console and then stops the script.
+   *
+   * @param Exception $Exception
+   * @throws Exception
+   */
+  function exceptionHandler($Exception) {
+    
+    $this->inExceptionHandler = true;
+
+    header('HTTP/1.1 500 Internal Server Error');
+
+    $this->fb($Exception);
+    
+    $this->inExceptionHandler = false;
+  }
+  
+  /**
+   * Register FirePHP driver as your assert callback
+   * 
+   * @param boolean $convertAssertionErrorsToExceptions
+   * @param boolean $throwAssertionExceptions
+   * @return mixed Returns the original setting or FALSE on errors
+   */
+  public function registerAssertionHandler($convertAssertionErrorsToExceptions=true, $throwAssertionExceptions=false)
+  {
+    $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions;
+    $this->throwAssertionExceptions = $throwAssertionExceptions;
+    
+    if($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) {
+      throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!');
+    }
+    
+    return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
+  }
+  
+  /**
+   * FirePHP's assertion handler
+   *
+   * Logs all assertions to your firebug console and then stops the script.
+   *
+   * @param string $file File source of assertion
+   * @param int    $line Line source of assertion
+   * @param mixed  $code Assertion code
+   */
+  public function assertionHandler($file, $line, $code)
+  {
+
+    if($this->convertAssertionErrorsToExceptions) {
+      
+      $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line);
+
+      if($this->throwAssertionExceptions) {
+        throw $exception;
+      } else {
+        $this->fb($exception);
+      }
+    
+    } else {
+    
+      $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line));
+    
+    }
+  }  
+  
+  /**
+   * Set custom processor url for FirePHP
+   *
+   * @param string $URL
+   */    
+  public function setProcessorUrl($URL)
+  {
+    $this->setHeader('X-FirePHP-ProcessorURL', $URL);
+  }
+
+  /**
+   * Set custom renderer url for FirePHP
+   *
+   * @param string $URL
+   */
+  public function setRendererUrl($URL)
+  {
+    $this->setHeader('X-FirePHP-RendererURL', $URL);
+  }
+  
+  /**
+   * Start a group for following messages.
+   * 
+   * Options:
+   *   Collapsed: [true|false]
+   *   Color:     [#RRGGBB|ColorName]
+   *
+   * @param string $Name
+   * @param array $Options OPTIONAL Instructions on how to log the group
+   * @return true
+   * @throws Exception
+   */
+  public function group($Name, $Options=null) {
+    
+    if(!$Name) {
+      throw $this->newException('You must specify a label for the group!');
+    }
+    
+    if($Options) {
+      if(!is_array($Options)) {
+        throw $this->newException('Options must be defined as an array!');
+      }
+      if(array_key_exists('Collapsed', $Options)) {
+        $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false';
+      }
+    }
+    
+    return $this->fb(null, $Name, FirePHP::GROUP_START, $Options);
+  }
+  
+  /**
+   * Ends a group you have started before
+   *
+   * @return true
+   * @throws Exception
+   */
+  public function groupEnd() {
+    return $this->fb(null, null, FirePHP::GROUP_END);
+  }
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::LOG
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public function log($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP::LOG);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::INFO
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public function info($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP::INFO);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::WARN
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public function warn($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP::WARN);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::ERROR
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public function error($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP::ERROR);
+  } 
+
+  /**
+   * Dumps key and variable to firebug server panel
+   *
+   * @see FirePHP::DUMP
+   * @param string $Key
+   * @param mixed $Variable
+   * @return true
+   * @throws Exception
+   */
+  public function dump($Key, $Variable) {
+    return $this->fb($Variable, $Key, FirePHP::DUMP);
+  }
+  
+  /**
+   * Log a trace in the firebug console
+   *
+   * @see FirePHP::TRACE
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public function trace($Label) {
+    return $this->fb($Label, FirePHP::TRACE);
+  } 
+
+  /**
+   * Log a table in the firebug console
+   *
+   * @see FirePHP::TABLE
+   * @param string $Label
+   * @param string $Table
+   * @return true
+   * @throws Exception
+   */
+  public function table($Label, $Table) {
+    return $this->fb($Table, $Label, FirePHP::TABLE);
+  }
+  
+  /**
+   * Check if FirePHP is installed on client
+   *
+   * @return boolean
+   */
+  public function detectClientExtension() {
+    /* Check if FirePHP is installed on client */
+    if(!@preg_match_all('/\sFirePHP\/([\.|\d]*)\s?/si',$this->getUserAgent(),$m) ||
+       !version_compare($m[1][0],'0.0.6','>=')) {
+      return false;
+    }
+    return true;    
+  }
+  /**
+   * Log varible to Firebug
+   * 
+   * @see http://www.firephp.org/Wiki/Reference/Fb
+   * @param mixed $Object The variable to be logged
+   * @return true Return TRUE if message was added to headers, FALSE otherwise
+   * @throws Exception
+   */
+  public function fb($Object) {
+  
+    if(!$this->enabled) {
+      return false;
+    }
+  
+    if (headers_sent($filename, $linenum)) {
+      // If we are logging from within the exception handler we cannot throw another exception
+      if($this->inExceptionHandler) {
+        // Simply echo the error out to the page
+        echo '<div style="border: 2px solid red; font-family: Arial; font-size: 12px; background-color: lightgray; padding: 5px;"><span style="color: red; font-weight: bold;">FirePHP ERROR:</span> Headers already sent in <b>'.$filename.'</b> on line <b>'.$linenum.'</b>. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.</div>';
+      } else {
+        throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.');
+      }
+    }
+  
+    $Type = null;
+    $Label = null;
+    $Options = array();
+  
+    if(func_num_args()==1) {
+    } else
+    if(func_num_args()==2) {
+      switch(func_get_arg(1)) {
+        case self::LOG:
+        case self::INFO:
+        case self::WARN:
+        case self::ERROR:
+        case self::DUMP:
+        case self::TRACE:
+        case self::EXCEPTION:
+        case self::TABLE:
+        case self::GROUP_START:
+        case self::GROUP_END:
+          $Type = func_get_arg(1);
+          break;
+        default:
+          $Label = func_get_arg(1);
+          break;
+      }
+    } else
+    if(func_num_args()==3) {
+      $Type = func_get_arg(2);
+      $Label = func_get_arg(1);
+    } else
+    if(func_num_args()==4) {
+      $Type = func_get_arg(2);
+      $Label = func_get_arg(1);
+      $Options = func_get_arg(3);
+    } else {
+      throw $this->newException('Wrong number of arguments to fb() function!');
+    }
+  
+  
+    if(!$this->detectClientExtension()) {
+      return false;
+    }
+  
+    $meta = array();
+    $skipFinalObjectEncode = false;
+  
+    if($Object instanceof Exception) {
+
+      $meta['file'] = $this->_escapeTraceFile($Object->getFile());
+      $meta['line'] = $Object->getLine();
+      
+      $trace = $Object->getTrace();
+      if($Object instanceof ErrorException
+         && isset($trace[0]['function'])
+         && $trace[0]['function']=='errorHandler'
+         && isset($trace[0]['class'])
+         && $trace[0]['class']=='FirePHP') {
+           
+        $severity = false;
+        switch($Object->getSeverity()) {
+          case E_WARNING: $severity = 'E_WARNING'; break;
+          case E_NOTICE: $severity = 'E_NOTICE'; break;
+          case E_USER_ERROR: $severity = 'E_USER_ERROR'; break;
+          case E_USER_WARNING: $severity = 'E_USER_WARNING'; break;
+          case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break;
+          case E_STRICT: $severity = 'E_STRICT'; break;
+          case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break;
+          case E_DEPRECATED: $severity = 'E_DEPRECATED'; break;
+          case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break;
+        }
+           
+        $Object = array('Class'=>get_class($Object),
+                        'Message'=>$severity.': '.$Object->getMessage(),
+                        'File'=>$this->_escapeTraceFile($Object->getFile()),
+                        'Line'=>$Object->getLine(),
+                        'Type'=>'trigger',
+                        'Trace'=>$this->_escapeTrace(array_splice($trace,2)));
+        $skipFinalObjectEncode = true;
+      } else {
+        $Object = array('Class'=>get_class($Object),
+                        'Message'=>$Object->getMessage(),
+                        'File'=>$this->_escapeTraceFile($Object->getFile()),
+                        'Line'=>$Object->getLine(),
+                        'Type'=>'throw',
+                        'Trace'=>$this->_escapeTrace($trace));
+        $skipFinalObjectEncode = true;
+      }
+      $Type = self::EXCEPTION;
+      
+    } else
+    if($Type==self::TRACE) {
+      
+      $trace = debug_backtrace();
+      if(!$trace) return false;
+      for( $i=0 ; $i<sizeof($trace) ; $i++ ) {
+
+        if(isset($trace[$i]['class'])
+           && isset($trace[$i]['file'])
+           && ($trace[$i]['class']=='FirePHP'
+               || $trace[$i]['class']=='FB')
+           && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+               || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+          /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+        } else
+        if(isset($trace[$i]['class'])
+           && isset($trace[$i+1]['file'])
+           && $trace[$i]['class']=='FirePHP'
+           && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+          /* Skip fb() */
+        } else
+        if($trace[$i]['function']=='fb'
+           || $trace[$i]['function']=='trace'
+           || $trace[$i]['function']=='send') {
+          $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'',
+                          'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'',
+                          'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'',
+                          'Message'=>$trace[$i]['args'][0],
+                          'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'',
+                          'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'',
+                          'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'',
+                          'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1)));
+
+          $skipFinalObjectEncode = true;
+          $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+          $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+          break;
+        }
+      }
+
+    } else
+    if($Type==self::TABLE) {
+      
+      if(isset($Object[0]) && is_string($Object[0])) {
+        $Object[1] = $this->encodeTable($Object[1]);
+      } else {
+        $Object = $this->encodeTable($Object);
+      }
+
+      $skipFinalObjectEncode = true;
+      
+    } else
+    if($Type==self::GROUP_START) {
+      
+      if(!$Label) {
+        throw $this->newException('You must specify a label for the group!');
+      }
+      
+    } else {
+      if($Type===null) {
+        $Type = self::LOG;
+      }
+    }
+    
+    if($this->options['includeLineNumbers']) {
+      if(!isset($meta['file']) || !isset($meta['line'])) {
+
+        $trace = debug_backtrace();
+        for( $i=0 ; $trace && $i<sizeof($trace) ; $i++ ) {
+  
+          if(isset($trace[$i]['class'])
+             && isset($trace[$i]['file'])
+             && ($trace[$i]['class']=='FirePHP'
+                 || $trace[$i]['class']=='FB')
+             && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+                 || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+            /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+          } else
+          if(isset($trace[$i]['class'])
+             && isset($trace[$i+1]['file'])
+             && $trace[$i]['class']=='FirePHP'
+             && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+            /* Skip fb() */
+          } else
+          if(isset($trace[$i]['file'])
+             && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') {
+            /* Skip FB::fb() */
+          } else {
+            $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+            $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+            break;
+          }
+        }      
+      
+      }
+    } else {
+      unset($meta['file']);
+      unset($meta['line']);
+    }
+
+       $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
+       $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION);
+    $structure_index = 1;
+    if($Type==self::DUMP) {
+      $structure_index = 2;
+       $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
+    } else {
+       $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
+    }
+  
+    if($Type==self::DUMP) {
+       $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}';
+    } else {
+      $msg_meta = $Options;
+      $msg_meta['Type'] = $Type;
+      if($Label!==null) {
+        $msg_meta['Label'] = $Label;
+      }
+      if(isset($meta['file']) && !isset($msg_meta['File'])) {
+        $msg_meta['File'] = $meta['file'];
+      }
+      if(isset($meta['line']) && !isset($msg_meta['Line'])) {
+        $msg_meta['Line'] = $meta['line'];
+      }
+       $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']';
+    }
+    
+    $parts = explode("\n",chunk_split($msg, 5000, "\n"));
+
+    for( $i=0 ; $i<count($parts) ; $i++) {
+        
+        $part = $parts[$i];
+        if ($part) {
+            
+            if(count($parts)>2) {
+              // Message needs to be split into multiple parts
+              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+                               (($i==0)?strlen($msg):'')
+                               . '|' . $part . '|'
+                               . (($i<count($parts)-2)?'\\':''));
+            } else {
+              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+                               strlen($part) . '|' . $part . '|');
+            }
+            
+            $this->messageIndex++;
+            
+            if ($this->messageIndex > 99999) {
+                throw $this->newException('Maximum number (99,999) of messages reached!');             
+            }
+        }
+    }
+
+       $this->setHeader('X-Wf-1-Index',$this->messageIndex-1);
+
+    return true;
+  }
+  
+  /**
+   * Standardizes path for windows systems.
+   *
+   * @param string $Path
+   * @return string
+   */
+  protected function _standardizePath($Path) {
+    return preg_replace('/\\\\+/','/',$Path);    
+  }
+  
+  /**
+   * Escape trace path for windows systems
+   *
+   * @param array $Trace
+   * @return array
+   */
+  protected function _escapeTrace($Trace) {
+    if(!$Trace) return $Trace;
+    for( $i=0 ; $i<sizeof($Trace) ; $i++ ) {
+      if(isset($Trace[$i]['file'])) {
+        $Trace[$i]['file'] = $this->_escapeTraceFile($Trace[$i]['file']);
+      }
+      if(isset($Trace[$i]['args'])) {
+        $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']);
+      }
+    }
+    return $Trace;    
+  }
+  
+  /**
+   * Escape file information of trace for windows systems
+   *
+   * @param string $File
+   * @return string
+   */
+  protected function _escapeTraceFile($File) {
+    /* Check if we have a windows filepath */
+    if(strpos($File,'\\')) {
+      /* First strip down to single \ */
+      
+      $file = preg_replace('/\\\\+/','\\',$File);
+      
+      return $file;
+    }
+    return $File;
+  }
+
+  /**
+   * Send header
+   *
+   * @param string $Name
+   * @param string_type $Value
+   */
+  protected function setHeader($Name, $Value) {
+    return header($Name.': '.$Value);
+  }
+
+  /**
+   * Get user agent
+   *
+   * @return string|false
+   */
+  protected function getUserAgent() {
+    if(!isset($_SERVER['HTTP_USER_AGENT'])) return false;
+    return $_SERVER['HTTP_USER_AGENT'];
+  }
+
+  /**
+   * Returns a new exception
+   *
+   * @param string $Message
+   * @return Exception
+   */
+  protected function newException($Message) {
+    return new Exception($Message);
+  }
+  
+  /**
+   * Encode an object into a JSON string
+   * 
+   * Uses PHP's jeson_encode() if available
+   * 
+   * @param object $Object The object to be encoded
+   * @return string The JSON string
+   */
+  public function jsonEncode($Object, $skipObjectEncode=false)
+  {
+    if(!$skipObjectEncode) {
+      $Object = $this->encodeObject($Object);
+    }
+    
+    if(function_exists('json_encode')
+       && $this->options['useNativeJsonEncode']!=false) {
+
+      return json_encode($Object);
+    } else {
+      return $this->json_encode($Object);
+    }
+  }
+
+  /**
+   * Encodes a table by encoding each row and column with encodeObject()
+   * 
+   * @param array $Table The table to be encoded
+   * @return array
+   */  
+  protected function encodeTable($Table) {
+    
+    if(!$Table) return $Table;
+    
+    $new_table = array();
+    foreach($Table as $row) {
+  
+      if(is_array($row)) {
+        $new_row = array();
+        
+        foreach($row as $item) {
+          $new_row[] = $this->encodeObject($item);
+        }
+        
+        $new_table[] = $new_row;
+      }
+    }
+    
+    return $new_table;
+  }
+
+  /**
+   * Encodes an object including members with
+   * protected and private visibility
+   * 
+   * @param Object $Object The object to be encoded
+   * @param int $Depth The current traversal depth
+   * @return array All members of the object
+   */
+  protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1)
+  {
+    $return = array();
+
+    if (is_resource($Object)) {
+
+      return '** '.(string)$Object.' **';
+
+    } else    
+    if (is_object($Object)) {
+
+        if ($ObjectDepth > $this->options['maxObjectDepth']) {
+          return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **';
+        }
+        
+        foreach ($this->objectStack as $refVal) {
+            if ($refVal === $Object) {
+                return '** Recursion ('.get_class($Object).') **';
+            }
+        }
+        array_push($this->objectStack, $Object);
+                
+        $return['__className'] = $class = get_class($Object);
+        $class_lower = strtolower($class);
+
+        $reflectionClass = new ReflectionClass($class);  
+        $properties = array();
+        foreach( $reflectionClass->getProperties() as $property) {
+          $properties[$property->getName()] = $property;
+        }
+            
+        $members = (array)$Object;
+            
+        foreach( $properties as $raw_name => $property ) {
+          
+          $name = $raw_name;
+          if($property->isStatic()) {
+            $name = 'static:'.$name;
+          }
+          if($property->isPublic()) {
+            $name = 'public:'.$name;
+          } else
+          if($property->isPrivate()) {
+            $name = 'private:'.$name;
+            $raw_name = "\0".$class."\0".$raw_name;
+          } else
+          if($property->isProtected()) {
+            $name = 'protected:'.$name;
+            $raw_name = "\0".'*'."\0".$raw_name;
+          }
+          
+          if(!(isset($this->objectFilters[$class_lower])
+               && is_array($this->objectFilters[$class_lower])
+               && in_array($raw_name,$this->objectFilters[$class_lower]))) {
+
+            if(array_key_exists($raw_name,$members)
+               && !$property->isStatic()) {
+              
+              $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1);      
+            
+            } else {
+              if(method_exists($property,'setAccessible')) {
+                $property->setAccessible(true);
+                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
+              } else
+              if($property->isPublic()) {
+                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
+              } else {
+                $return[$name] = '** Need PHP 5.3 to get value **';
+              }
+            }
+          } else {
+            $return[$name] = '** Excluded by Filter **';
+          }
+        }
+        
+        // Include all members that are not defined in the class
+        // but exist in the object
+        foreach( $members as $raw_name => $value ) {
+          
+          $name = $raw_name;
+          
+          if ($name{0} == "\0") {
+            $parts = explode("\0", $name);
+            $name = $parts[2];
+          }
+          
+          if(!isset($properties[$name])) {
+            $name = 'undeclared:'.$name;
+              
+            if(!(isset($this->objectFilters[$class_lower])
+                 && is_array($this->objectFilters[$class_lower])
+                 && in_array($raw_name,$this->objectFilters[$class_lower]))) {
+              
+              $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1);
+            } else {
+              $return[$name] = '** Excluded by Filter **';
+            }
+          }
+        }
+        
+        array_pop($this->objectStack);
+        
+    } elseif (is_array($Object)) {
+
+        if ($ArrayDepth > $this->options['maxArrayDepth']) {
+          return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **';
+        }
+      
+        foreach ($Object as $key => $val) {
+          
+          // Encoding the $GLOBALS PHP array causes an infinite loop
+          // if the recursion is not reset here as it contains
+          // a reference to itself. This is the only way I have come up
+          // with to stop infinite recursion in this case.
+          if($key=='GLOBALS'
+             && is_array($val)
+             && array_key_exists('GLOBALS',$val)) {
+            $val['GLOBALS'] = '** Recursion (GLOBALS) **';
+          }
+          
+          $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1);
+        }
+    } else {
+      if(self::is_utf8($Object)) {
+        return $Object;
+      } else {
+        return utf8_encode($Object);
+      }
+    }
+    return $return;
+  }
+
+  /**
+   * Returns true if $string is valid UTF-8 and false otherwise.
+   *
+   * @param mixed $str String to be tested
+   * @return boolean
+   */
+  protected static function is_utf8($str) {
+    $c=0; $b=0;
+    $bits=0;
+    $len=strlen($str);
+    for($i=0; $i<$len; $i++){
+        $c=ord($str[$i]);
+        if($c > 128){
+            if(($c >= 254)) return false;
+            elseif($c >= 252) $bits=6;
+            elseif($c >= 248) $bits=5;
+            elseif($c >= 240) $bits=4;
+            elseif($c >= 224) $bits=3;
+            elseif($c >= 192) $bits=2;
+            else return false;
+            if(($i+$bits) > $len) return false;
+            while($bits > 1){
+                $i++;
+                $b=ord($str[$i]);
+                if($b < 128 || $b > 191) return false;
+                $bits--;
+            }
+        }
+    }
+    return true;
+  } 
+
+  /**
+   * Converts to and from JSON format.
+   *
+   * JSON (JavaScript Object Notation) is a lightweight data-interchange
+   * format. It is easy for humans to read and write. It is easy for machines
+   * to parse and generate. It is based on a subset of the JavaScript
+   * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+   * This feature can also be found in  Python. JSON is a text format that is
+   * completely language independent but uses conventions that are familiar
+   * to programmers of the C-family of languages, including C, C++, C#, Java,
+   * JavaScript, Perl, TCL, and many others. These properties make JSON an
+   * ideal data-interchange language.
+   *
+   * This package provides a simple encoder and decoder for JSON notation. It
+   * is intended for use with client-side Javascript applications that make
+   * use of HTTPRequest to perform server communication functions - data can
+   * be encoded into JSON notation for use in a client-side javascript, or
+   * decoded from incoming Javascript requests. JSON format is native to
+   * Javascript, and can be directly eval()'ed with no further parsing
+   * overhead
+   *
+   * All strings should be in ASCII or UTF-8 format!
+   *
+   * LICENSE: Redistribution and use in source and binary forms, with or
+   * without modification, are permitted provided that the following
+   * conditions are met: Redistributions of source code must retain the
+   * above copyright notice, this list of conditions and the following
+   * disclaimer. Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *
+   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+   * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+   * DAMAGE.
+   *
+   * @category
+   * @package     Services_JSON
+   * @author      Michal Migurski <mike-json@teczno.com>
+   * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+   * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+   * @author      Christoph Dorn <christoph@christophdorn.com>
+   * @copyright   2005 Michal Migurski
+   * @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
+   * @license     http://www.opensource.org/licenses/bsd-license.php
+   * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+   */
+   
+     
+  /**
+   * Keep a list of objects as we descend into the array so we can detect recursion.
+   */
+  private $json_objectStack = array();
+
+
+ /**
+  * convert a string from one UTF-8 char to one UTF-16 char
+  *
+  * Normally should be handled by mb_convert_encoding, but
+  * provides a slower PHP-only method for installations
+  * that lack the multibye string extension.
+  *
+  * @param    string  $utf8   UTF-8 character
+  * @return   string  UTF-16 character
+  * @access   private
+  */
+  private function json_utf82utf16($utf8)
+  {
+      // oh please oh please oh please oh please oh please
+      if(function_exists('mb_convert_encoding')) {
+          return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+      }
+
+      switch(strlen($utf8)) {
+          case 1:
+              // this case should never be reached, because we are in ASCII range
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return $utf8;
+
+          case 2:
+              // return a UTF-16 character from a 2-byte UTF-8 char
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return chr(0x07 & (ord($utf8{0}) >> 2))
+                   . chr((0xC0 & (ord($utf8{0}) << 6))
+                       | (0x3F & ord($utf8{1})));
+
+          case 3:
+              // return a UTF-16 character from a 3-byte UTF-8 char
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return chr((0xF0 & (ord($utf8{0}) << 4))
+                       | (0x0F & (ord($utf8{1}) >> 2)))
+                   . chr((0xC0 & (ord($utf8{1}) << 6))
+                       | (0x7F & ord($utf8{2})));
+      }
+
+      // ignoring UTF-32 for now, sorry
+      return '';
+  }
+
+ /**
+  * encodes an arbitrary variable into JSON format
+  *
+  * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+  *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+  *                           if var is a strng, note that encode() always expects it
+  *                           to be in ASCII or UTF-8 format!
+  *
+  * @return   mixed   JSON string representation of input var or an error if a problem occurs
+  * @access   public
+  */
+  private function json_encode($var)
+  {
+    
+    if(is_object($var)) {
+      if(in_array($var,$this->json_objectStack)) {
+        return '"** Recursion **"';
+      }
+    }
+          
+      switch (gettype($var)) {
+          case 'boolean':
+              return $var ? 'true' : 'false';
+
+          case 'NULL':
+              return 'null';
+
+          case 'integer':
+              return (int) $var;
+
+          case 'double':
+          case 'float':
+              return (float) $var;
+
+          case 'string':
+              // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+              $ascii = '';
+              $strlen_var = strlen($var);
+
+             /*
+              * Iterate over every character in the string,
+              * escaping with a slash or encoding to UTF-8 where necessary
+              */
+              for ($c = 0; $c < $strlen_var; ++$c) {
+
+                  $ord_var_c = ord($var{$c});
+
+                  switch (true) {
+                      case $ord_var_c == 0x08:
+                          $ascii .= '\b';
+                          break;
+                      case $ord_var_c == 0x09:
+                          $ascii .= '\t';
+                          break;
+                      case $ord_var_c == 0x0A:
+                          $ascii .= '\n';
+                          break;
+                      case $ord_var_c == 0x0C:
+                          $ascii .= '\f';
+                          break;
+                      case $ord_var_c == 0x0D:
+                          $ascii .= '\r';
+                          break;
+
+                      case $ord_var_c == 0x22:
+                      case $ord_var_c == 0x2F:
+                      case $ord_var_c == 0x5C:
+                          // double quote, slash, slosh
+                          $ascii .= '\\'.$var{$c};
+                          break;
+
+                      case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                          // characters U-00000000 - U-0000007F (same as ASCII)
+                          $ascii .= $var{$c};
+                          break;
+
+                      case (($ord_var_c & 0xE0) == 0xC0):
+                          // characters U-00000080 - U-000007FF, mask 110XXXXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                          $c += 1;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xF0) == 0xE0):
+                          // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}));
+                          $c += 2;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xF8) == 0xF0):
+                          // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}));
+                          $c += 3;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xFC) == 0xF8):
+                          // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}),
+                                       ord($var{$c + 4}));
+                          $c += 4;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xFE) == 0xFC):
+                          // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}),
+                                       ord($var{$c + 4}),
+                                       ord($var{$c + 5}));
+                          $c += 5;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+                  }
+              }
+
+              return '"'.$ascii.'"';
+
+          case 'array':
+             /*
+              * As per JSON spec if any array key is not an integer
+              * we must treat the the whole array as an object. We
+              * also try to catch a sparsely populated associative
+              * array with numeric keys here because some JS engines
+              * will create an array with empty indexes up to
+              * max_index which can cause memory issues and because
+              * the keys, which may be relevant, will be remapped
+              * otherwise.
+              *
+              * As per the ECMA and JSON specification an object may
+              * have any string as a property. Unfortunately due to
+              * a hole in the ECMA specification if the key is a
+              * ECMA reserved word or starts with a digit the
+              * parameter is only accessible using ECMAScript's
+              * bracket notation.
+              */
+
+              // treat as a JSON object
+              if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                  
+                  $this->json_objectStack[] = $var;
+
+                  $properties = array_map(array($this, 'json_name_value'),
+                                          array_keys($var),
+                                          array_values($var));
+
+                  array_pop($this->json_objectStack);
+
+                  foreach($properties as $property) {
+                      if($property instanceof Exception) {
+                          return $property;
+                      }
+                  }
+
+                  return '{' . join(',', $properties) . '}';
+              }
+
+              $this->json_objectStack[] = $var;
+
+              // treat it like a regular array
+              $elements = array_map(array($this, 'json_encode'), $var);
+
+              array_pop($this->json_objectStack);
+
+              foreach($elements as $element) {
+                  if($element instanceof Exception) {
+                      return $element;
+                  }
+              }
+
+              return '[' . join(',', $elements) . ']';
+
+          case 'object':
+              $vars = self::encodeObject($var);
+
+              $this->json_objectStack[] = $var;
+
+              $properties = array_map(array($this, 'json_name_value'),
+                                      array_keys($vars),
+                                      array_values($vars));
+
+              array_pop($this->json_objectStack);
+              
+              foreach($properties as $property) {
+                  if($property instanceof Exception) {
+                      return $property;
+                  }
+              }
+                     
+              return '{' . join(',', $properties) . '}';
+
+          default:
+              return null;
+      }
+  }
+
+ /**
+  * array-walking function for use in generating JSON-formatted name-value pairs
+  *
+  * @param    string  $name   name of key to use
+  * @param    mixed   $value  reference to an array element to be encoded
+  *
+  * @return   string  JSON-formatted name-value pair, like '"name":value'
+  * @access   private
+  */
+  private function json_name_value($name, $value)
+  {
+      // Encoding the $GLOBALS PHP array causes an infinite loop
+      // if the recursion is not reset here as it contains
+      // a reference to itself. This is the only way I have come up
+      // with to stop infinite recursion in this case.
+      if($name=='GLOBALS'
+         && is_array($value)
+         && array_key_exists('GLOBALS',$value)) {
+        $value['GLOBALS'] = '** Recursion **';
+      }
+    
+      $encoded_value = $this->json_encode($value);
+
+      if($encoded_value instanceof Exception) {
+          return $encoded_value;
+      }
+
+      return $this->json_encode(strval($name)) . ':' . $encoded_value;
+  }
+}
diff --git a/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php4 b/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/FirePHP.class.php4
new file mode 100644 (file)
index 0000000..7cc4bfb
--- /dev/null
@@ -0,0 +1,1292 @@
+<?php
+/**
+ * *** BEGIN LICENSE BLOCK *****
+ *  
+ * This file is part of FirePHP (http://www.firephp.org/).
+ * 
+ * Software License Agreement (New BSD License)
+ * 
+ * Copyright (c) 2006-2009, Christoph Dorn
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ *     * Neither the name of Christoph Dorn nor the names of its
+ *       contributors may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * ***** END LICENSE BLOCK *****
+ * 
+ * This verion of FirePHPCore is for use with PHP4. If you do not require PHP4 
+ * compatibility, it is suggested you use FirePHPCore.class.php instead.
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @author      Michael Day <manveru.alma@gmail.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+/**
+ * FirePHP version
+ * 
+ * @var string
+ */
+define('FirePHP_VERSION', '0.3');
+
+/**
+ * Firebug LOG level
+ * 
+ * Logs a message to firebug console
+ * 
+ * @var string
+ */
+define('FirePHP_LOG', 'LOG');
+
+/**
+ * Firebug INFO level
+ * 
+ * Logs a message to firebug console and displays an info icon before the message
+ *
+ * @var string
+ */
+define('FirePHP_INFO', 'INFO');
+
+/**
+ * Firebug WARN level
+ * 
+ * Logs a message to firebug console, displays a warning icon before the message and colors the line turquoise
+ *
+ * @var string
+ */
+define('FirePHP_WARN', 'WARN');
+
+/**
+ * Firebug ERROR level
+ * 
+ * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
+ *
+ * @var string
+ */
+define('FirePHP_ERROR', 'ERROR');
+
+/**
+ * Dumps a variable to firebug's server panel
+ *
+ * @var string
+ */
+define('FirePHP_DUMP', 'DUMP');
+
+/**
+ * Displays a stack trace in firebug console
+ * 
+ * @var string
+ */
+define('FirePHP_TRACE', 'TRACE');
+
+/**
+ * Displays a table in firebug console
+ *
+ * @var string
+ */
+define('FirePHP_TABLE', 'TABLE');
+/**
+ * Starts a group in firebug console
+ *
+ * @var string
+ */
+define('FirePHP_GROUP_START', 'GROUP_START');
+
+/**
+ * Ends a group in firebug console
+ * 
+ * @var string
+ */
+define('FirePHP_GROUP_END', 'GROUP_END');
+
+/**
+ * Sends the given data to the FirePHP Firefox Extension.
+ * The data can be displayed in the Firebug Console or in the
+ * "Server" request tab.
+ * 
+ * For more information see: http://www.firephp.org/
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @author      Michael Day <manveru.alma@gmail.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+class FirePHP {
+  /**
+   * Wildfire protocol message index
+   *
+   * @var int
+   */
+  var $messageIndex = 1;
+    
+  /**
+   * Options for the library
+   * 
+   * @var array
+   */
+  var $options = array('maxObjectDepth' => 10,
+                       'maxArrayDepth' => 20,
+                       'useNativeJsonEncode' => true,
+                       'includeLineNumbers' => true);
+
+  /**
+   * Filters used to exclude object members when encoding
+   * 
+   * @var array
+   */
+  var $objectFilters = array();
+  
+  /**
+   * A stack of objects used to detect recursion during object encoding
+   * 
+   * @var object
+   */
+  var $objectStack = array();
+  
+  /**
+   * Flag to enable/disable logging
+   * 
+   * @var boolean
+   */
+  var $enabled = true;
+
+  /**
+   * The object constructor
+   */
+  function FirePHP() {
+  }
+
+    
+  /**
+   * When the object gets serialized only include specific object members.
+   * 
+   * @return array
+   */  
+  function __sleep() {
+    return array('options','objectFilters','enabled');
+  }
+
+  /**
+   * Gets singleton instance of FirePHP
+   *
+   * @param boolean $AutoCreate
+   * @return FirePHP
+   */
+  function &getInstance($AutoCreate=false) {
+       global $FirePHP_Instance;
+       
+       if($AutoCreate===true && !$FirePHP_Instance) {
+               $FirePHP_Instance = new FirePHP();
+       }
+       
+       return $FirePHP_Instance;
+  }
+    
+  /**
+   * Enable and disable logging to Firebug
+   * 
+   * @param boolean $Enabled TRUE to enable, FALSE to disable
+   * @return void
+   */
+  function setEnabled($Enabled) {
+    $this->enabled = $Enabled;
+  }
+  
+  /**
+   * Check if logging is enabled
+   * 
+   * @return boolean TRUE if enabled
+   */
+  function getEnabled() {
+    return $this->enabled;
+  }
+  
+  /**
+   * Specify a filter to be used when encoding an object
+   * 
+   * Filters are used to exclude object members.
+   * 
+   * @param string $Class The class name of the object
+   * @param array $Filter An array of members to exclude
+   * @return void
+   */
+  function setObjectFilter($Class, $Filter) {
+    $this->objectFilters[strtolower($Class)] = $Filter;
+  }
+  
+  /**
+   * Set some options for the library
+   * 
+   * Options:
+   *  - maxObjectDepth: The maximum depth to traverse objects (default: 10)
+   *  - maxArrayDepth: The maximum depth to traverse arrays (default: 20)
+   *  - useNativeJsonEncode: If true will use json_encode() (default: true)
+   *  - includeLineNumbers: If true will include line numbers and filenames (default: true)
+   * 
+   * @param array $Options The options to be set
+   * @return void
+   */
+  function setOptions($Options) {
+    $this->options = array_merge($this->options,$Options);
+  }
+  
+  /**
+   * Get options from the library
+   *
+   * @return array The currently set options
+   */
+  function getOptions() {
+    return $this->options;
+  }
+  
+  /**
+   * Register FirePHP as your error handler
+   * 
+   * Will use FirePHP to log each php error.
+   *
+   * @return mixed Returns a string containing the previously defined error handler (if any)
+   */
+  function registerErrorHandler()
+  {
+    //NOTE: The following errors will not be caught by this error handler:
+    //      E_ERROR, E_PARSE, E_CORE_ERROR,
+    //      E_CORE_WARNING, E_COMPILE_ERROR,
+    //      E_COMPILE_WARNING, E_STRICT
+    
+    return set_error_handler(array($this,'errorHandler'));     
+  }
+
+  /**
+   * FirePHP's error handler
+   * 
+   * Logs each php error that will occur.
+   *
+   * @param int $errno
+   * @param string $errstr
+   * @param string $errfile
+   * @param int $errline
+   * @param array $errcontext
+   */
+  function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
+  {
+       global $FirePHP_Instance;
+    // Don't log error if error reporting is switched off
+    if (error_reporting() == 0) {
+      return;
+    }
+    // Only log error for errors we are asking for
+    if (error_reporting() & $errno) {
+      $FirePHP_Instance->group($errstr);
+      $FirePHP_Instance->error("{$errfile}, line $errline");
+      $FirePHP_Instance->groupEnd();
+    }
+  }
+  
+  /**
+   * Register FirePHP driver as your assert callback
+   * 
+   * @return mixed Returns the original setting
+   */
+  function registerAssertionHandler()
+  {
+    return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
+  }
+  
+  /**
+   * FirePHP's assertion handler
+   *
+   * Logs all assertions to your firebug console and then stops the script.
+   *
+   * @param string $file File source of assertion
+   * @param int    $line Line source of assertion
+   * @param mixed  $code Assertion code
+   */
+  function assertionHandler($file, $line, $code)
+  {
+    $this->fb($code, 'Assertion Failed', FirePHP_ERROR, array('File'=>$file,'Line'=>$line));
+  }  
+  
+  /**
+   * Set custom processor url for FirePHP
+   *
+   * @param string $URL
+   */    
+  function setProcessorUrl($URL)
+  {
+    $this->setHeader('X-FirePHP-ProcessorURL', $URL);
+  }
+
+  /**
+   * Set custom renderer url for FirePHP
+   *
+   * @param string $URL
+   */
+  function setRendererUrl($URL)
+  {
+    $this->setHeader('X-FirePHP-RendererURL', $URL);
+  }
+  
+  /**
+   * Start a group for following messages.
+   * 
+   * Options:
+   *   Collapsed: [true|false]
+   *   Color:     [#RRGGBB|ColorName]
+   *
+   * @param string $Name
+   * @param array $Options OPTIONAL Instructions on how to log the group
+   * @return true
+   * @throws Exception
+   */
+  function group($Name, $Options=null) {
+    
+    if(!$Name) {
+      trigger_error('You must specify a label for the group!');
+    }
+    
+    if($Options) {
+      if(!is_array($Options)) {
+        trigger_error('Options must be defined as an array!');
+      }
+      if(array_key_exists('Collapsed', $Options)) {
+        $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false';
+      }
+    }
+    
+    return $this->fb(null, $Name, FirePHP_GROUP_START, $Options);
+  }
+  
+  /**
+   * Ends a group you have started before
+   *
+   * @return true
+   * @throws Exception
+   */
+  function groupEnd() {
+    return $this->fb(null, null, FirePHP_GROUP_END);
+  }
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::LOG
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  function log($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP_LOG);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::INFO
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  function info($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP_INFO);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::WARN
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  function warn($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP_WARN);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::ERROR
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  function error($Object, $Label=null) {
+    return $this->fb($Object, $Label, FirePHP_ERROR);
+  } 
+
+  /**
+   * Dumps key and variable to firebug server panel
+   *
+   * @see FirePHP::DUMP
+   * @param string $Key
+   * @param mixed $Variable
+   * @return true
+   * @throws Exception
+   */
+  function dump($Key, $Variable) {
+    return $this->fb($Variable, $Key, FirePHP_DUMP);
+  }
+  
+  /**
+   * Log a trace in the firebug console
+   *
+   * @see FirePHP::TRACE
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  function trace($Label) {
+    return $this->fb($Label, FirePHP_TRACE);
+  } 
+
+  /**
+   * Log a table in the firebug console
+   *
+   * @see FirePHP::TABLE
+   * @param string $Label
+   * @param string $Table
+   * @return true
+   * @throws Exception
+   */
+  function table($Label, $Table) {
+    return $this->fb($Table, $Label, FirePHP_TABLE);
+  }
+  
+  /**
+   * Check if FirePHP is installed on client
+   *
+   * @return boolean
+   */
+  function detectClientExtension() {
+    /* Check if FirePHP is installed on client */
+    if(!@preg_match_all('/\sFirePHP\/([\.|\d]*)\s?/si',$this->getUserAgent(),$m) ||
+       !version_compare($m[1][0],'0.0.6','>=')) {
+      return false;
+    }
+    return true;    
+  }
+  /**
+   * Log varible to Firebug
+   * 
+   * @see http://www.firephp.org/Wiki/Reference/Fb
+   * @param mixed $Object The variable to be logged
+   * @return true Return TRUE if message was added to headers, FALSE otherwise
+   * @throws Exception
+   */
+  function fb($Object) {
+  
+    if(!$this->enabled) {
+      return false;
+    }
+  
+    if (headers_sent($filename, $linenum)) {
+        trigger_error('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.');
+    }
+  
+    $Type = null;
+    $Label = null;
+    $Options = array();
+  
+    if(func_num_args()==1) {
+    } else
+    if(func_num_args()==2) {
+      switch(func_get_arg(1)) {
+        case FirePHP_LOG:
+        case FirePHP_INFO:
+        case FirePHP_WARN:
+        case FirePHP_ERROR:
+        case FirePHP_DUMP:
+        case FirePHP_TRACE:
+        case FirePHP_TABLE:
+        case FirePHP_GROUP_START:
+        case FirePHP_GROUP_END:
+          $Type = func_get_arg(1);
+          break;
+        default:
+          $Label = func_get_arg(1);
+          break;
+      }
+    } else
+    if(func_num_args()==3) {
+      $Type = func_get_arg(2);
+      $Label = func_get_arg(1);
+    } else
+    if(func_num_args()==4) {
+      $Type = func_get_arg(2);
+      $Label = func_get_arg(1);
+      $Options = func_get_arg(3);
+    } else {
+      trigger_error('Wrong number of arguments to fb() function!');
+    }
+  
+  
+    if(!$this->detectClientExtension()) {
+      return false;
+    }
+  
+    $meta = array();
+    $skipFinalObjectEncode = false;
+  
+    if($Type==FirePHP_TRACE) {
+      
+      $trace = debug_backtrace();
+      if(!$trace) return false;
+      for( $i=0 ; $i<sizeof($trace) ; $i++ ) {
+
+        if(isset($trace[$i]['class'])
+           && isset($trace[$i]['file'])
+           && ($trace[$i]['class']=='FirePHP'
+               || $trace[$i]['class']=='FB')
+           && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+               || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+          /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+        } else
+        if(isset($trace[$i]['class'])
+           && isset($trace[$i+1]['file'])
+           && $trace[$i]['class']=='FirePHP'
+           && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+          /* Skip fb() */
+        } else
+        if($trace[$i]['function']=='fb'
+           || $trace[$i]['function']=='trace'
+           || $trace[$i]['function']=='send') {
+          $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'',
+                          'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'',
+                          'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'',
+                          'Message'=>$trace[$i]['args'][0],
+                          'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'',
+                          'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'',
+                          'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'',
+                          'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1)));
+
+          $skipFinalObjectEncode = true;
+          $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+          $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+          break;
+        }
+      }
+
+    } else
+    if($Type==FirePHP_TABLE) {
+      
+      if(isset($Object[0]) && is_string($Object[0])) {
+        $Object[1] = $this->encodeTable($Object[1]);
+      } else {
+        $Object = $this->encodeTable($Object);
+      }
+
+      $skipFinalObjectEncode = true;
+      
+    } else
+    if($Type==FirePHP_GROUP_START) {
+      
+      if(!$Label) {
+        trigger_error('You must specify a label for the group!');
+      }
+    } else {
+      if($Type===null) {
+        $Type = FirePHP_LOG;
+      }
+    }
+    
+    if($this->options['includeLineNumbers']) {
+      if(!isset($meta['file']) || !isset($meta['line'])) {
+
+        $trace = debug_backtrace();
+        for( $i=0 ; $trace && $i<sizeof($trace) ; $i++ ) {
+  
+          if(isset($trace[$i]['class'])
+             && isset($trace[$i]['file'])
+             && ($trace[$i]['class']=='FirePHP'
+                 || $trace[$i]['class']=='FB')
+             && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
+                 || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
+            /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
+          } else
+          if(isset($trace[$i]['class'])
+             && isset($trace[$i+1]['file'])
+             && $trace[$i]['class']=='FirePHP'
+             && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
+            /* Skip fb() */
+          } else
+          if(isset($trace[$i]['file'])
+             && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') {
+            /* Skip FB::fb() */
+          } else {
+            $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
+            $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
+            break;
+          }
+        }      
+      
+      }
+    } else {
+      unset($meta['file']);
+      unset($meta['line']);
+    }
+
+       $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
+       $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.FirePHP_VERSION);
+    $structure_index = 1;
+    if($Type==FirePHP_DUMP) {
+      $structure_index = 2;
+       $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
+    } else {
+       $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
+    }
+  
+    if($Type==FirePHP_DUMP) {
+       $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}';
+    } else {
+      $msg_meta = $Options;
+      $msg_meta['Type'] = $Type;
+      if($Label!==null) {
+        $msg_meta['Label'] = $Label;
+      }
+      if(isset($meta['file']) && !isset($msg_meta['File'])) {
+        $msg_meta['File'] = $meta['file'];
+      }
+      if(isset($meta['line']) && !isset($msg_meta['Line'])) {
+        $msg_meta['Line'] = $meta['line'];
+      }
+       $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']';
+    }
+    
+    $parts = explode("\n",chunk_split($msg, 5000, "\n"));
+
+    for( $i=0 ; $i<count($parts) ; $i++) {
+        
+        $part = $parts[$i];
+        if ($part) {
+            
+            if(count($parts)>2) {
+              // Message needs to be split into multiple parts
+              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+                               (($i==0)?strlen($msg):'')
+                               . '|' . $part . '|'
+                               . (($i<count($parts)-2)?'\\':''));
+            } else {
+              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
+                               strlen($part) . '|' . $part . '|');
+            }
+            
+            $this->messageIndex++;
+            
+            if ($this->messageIndex > 99999) {
+                trigger_error('Maximum number (99,999) of messages reached!');             
+            }
+        }
+    }
+
+       $this->setHeader('X-Wf-1-Index',$this->messageIndex-1);
+
+    return true;
+  }
+  
+  
+  /**
+   * Standardizes path for windows systems.
+   *
+   * @param string $Path
+   * @return string
+   */
+   function _standardizePath($Path) {
+    return preg_replace('/\\\\+/','/',$Path);    
+  }
+  
+  /**
+   * Escape trace path for windows systems
+   *
+   * @param array $Trace
+   * @return array
+   */
+   function _escapeTrace($Trace) {
+    if(!$Trace) return $Trace;
+    for( $i=0 ; $i<sizeof($Trace) ; $i++ ) {
+      if(isset($Trace[$i]['file'])) {
+        $Trace[$i]['file'] = $this->_escapeTraceFile($Trace[$i]['file']);
+      }
+      if(isset($Trace[$i]['args'])) {
+        $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']);
+      }
+    }
+    return $Trace;    
+  }
+  
+  /**
+   * Escape file information of trace for windows systems
+   *
+   * @param string $File
+   * @return string
+   */
+   function _escapeTraceFile($File) {
+    /* Check if we have a windows filepath */
+    if(strpos($File,'\\')) {
+      /* First strip down to single \ */
+      
+      $file = preg_replace('/\\\\+/','\\',$File);
+      
+      return $file;
+    }
+    return $File;
+  }
+
+  /**
+   * Send header
+   *
+   * @param string $Name
+   * @param string_type $Value
+   */
+   function setHeader($Name, $Value) {
+    return header($Name.': '.$Value);
+  }
+
+  /**
+   * Get user agent
+   *
+   * @return string|false
+   */
+   function getUserAgent() {
+    if(!isset($_SERVER['HTTP_USER_AGENT'])) return false;
+    return $_SERVER['HTTP_USER_AGENT'];
+  }
+
+  /**
+   * Encode an object into a JSON string
+   * 
+   * Uses PHP's jeson_encode() if available
+   * 
+   * @param object $Object The object to be encoded
+   * @return string The JSON string
+   */
+   function jsonEncode($Object, $skipObjectEncode=false)
+  {
+    if(!$skipObjectEncode) {
+      $Object = $this->encodeObject($Object);
+    }
+    
+    if(function_exists('json_encode')
+       && $this->options['useNativeJsonEncode']!=false) {
+
+      return json_encode($Object);
+    } else {
+      return $this->json_encode($Object);
+    }
+  }
+  
+  /**
+   * Encodes a table by encoding each row and column with encodeObject()
+   * 
+   * @param array $Table The table to be encoded
+   * @return array
+   */  
+   function encodeTable($Table) {
+    
+    if(!$Table) return $Table;
+    
+    $new_table = array();
+    foreach($Table as $row) {
+  
+      if(is_array($row)) {
+        $new_row = array();
+        
+        foreach($row as $item) {
+          $new_row[] = $this->encodeObject($item);
+        }
+        
+        $new_table[] = $new_row;
+      }
+    }
+    
+    return $new_table;
+  }
+  
+  /**
+   * Encodes an object
+   * 
+   * @param Object $Object The object to be encoded
+   * @param int $Depth The current traversal depth
+   * @return array All members of the object
+   */
+   function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1)
+  {
+    $return = array();
+
+    if (is_resource($Object)) {
+
+      return '** '.(string)$Object.' **';
+
+    } else    
+    if (is_object($Object)) {
+
+        if ($ObjectDepth > $this->options['maxObjectDepth']) {
+          return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **';
+        }
+        
+        foreach ($this->objectStack as $refVal) {
+            if ($refVal === $Object) {
+                return '** Recursion ('.get_class($Object).') **';
+            }
+        }
+        array_push($this->objectStack, $Object);
+                
+        $return['__className'] = $class = get_class($Object);
+        $class_lower = strtolower($class);
+
+        $members = (array)$Object;
+            
+        // Include all members that are not defined in the class
+        // but exist in the object
+        foreach( $members as $raw_name => $value ) {
+          
+          $name = $raw_name;
+          
+          if ($name{0} == "\0") {
+            $parts = explode("\0", $name);
+            $name = $parts[2];
+          }
+          
+          if(!isset($properties[$name])) {
+            $name = 'undeclared:'.$name;
+              
+            if(!(isset($this->objectFilters[$class_lower])
+                 && is_array($this->objectFilters[$class_lower])
+                 && in_array($raw_name,$this->objectFilters[$class_lower]))) {
+              
+              $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1);
+            } else {
+              $return[$name] = '** Excluded by Filter **';
+            }
+          }
+        }
+        
+        array_pop($this->objectStack);
+        
+    } elseif (is_array($Object)) {
+
+        if ($ArrayDepth > $this->options['maxArrayDepth']) {
+          return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **';
+        }
+      
+        foreach ($Object as $key => $val) {
+          
+          // Encoding the $GLOBALS PHP array causes an infinite loop
+          // if the recursion is not reset here as it contains
+          // a reference to itself. This is the only way I have come up
+          // with to stop infinite recursion in this case.
+          if($key=='GLOBALS'
+             && is_array($val)
+             && array_key_exists('GLOBALS',$val)) {
+            $val['GLOBALS'] = '** Recursion (GLOBALS) **';
+          }
+          
+          $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1);
+        }
+    } else {
+      if($this->is_utf8($Object)) {
+        return $Object;
+      } else {
+        return utf8_encode($Object);
+      }
+    }
+    return $return;
+       
+  }
+
+  /**
+   * Returns true if $string is valid UTF-8 and false otherwise.
+   *
+   * @param mixed $str String to be tested
+   * @return boolean
+   */
+   function is_utf8($str) {
+    $c=0; $b=0;
+    $bits=0;
+    $len=strlen($str);
+    for($i=0; $i<$len; $i++){
+        $c=ord($str[$i]);
+        if($c > 128){
+            if(($c >= 254)) return false;
+            elseif($c >= 252) $bits=6;
+            elseif($c >= 248) $bits=5;
+            elseif($c >= 240) $bits=4;
+            elseif($c >= 224) $bits=3;
+            elseif($c >= 192) $bits=2;
+            else return false;
+            if(($i+$bits) > $len) return false;
+            while($bits > 1){
+                $i++;
+                $b=ord($str[$i]);
+                if($b < 128 || $b > 191) return false;
+                $bits--;
+            }
+        }
+    }
+    return true;
+  } 
+
+  /**
+   * Converts to and from JSON format.
+   *
+   * JSON (JavaScript Object Notation) is a lightweight data-interchange
+   * format. It is easy for humans to read and write. It is easy for machines
+   * to parse and generate. It is based on a subset of the JavaScript
+   * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
+   * This feature can also be found in  Python. JSON is a text format that is
+   * completely language independent but uses conventions that are familiar
+   * to programmers of the C-family of languages, including C, C++, C#, Java,
+   * JavaScript, Perl, TCL, and many others. These properties make JSON an
+   * ideal data-interchange language.
+   *
+   * This package provides a simple encoder and decoder for JSON notation. It
+   * is intended for use with client-side Javascript applications that make
+   * use of HTTPRequest to perform server communication functions - data can
+   * be encoded into JSON notation for use in a client-side javascript, or
+   * decoded from incoming Javascript requests. JSON format is native to
+   * Javascript, and can be directly eval()'ed with no further parsing
+   * overhead
+   *
+   * All strings should be in ASCII or UTF-8 format!
+   *
+   * LICENSE: Redistribution and use in source and binary forms, with or
+   * without modification, are permitted provided that the following
+   * conditions are met: Redistributions of source code must retain the
+   * above copyright notice, this list of conditions and the following
+   * disclaimer. Redistributions in binary form must reproduce the above
+   * copyright notice, this list of conditions and the following disclaimer
+   * in the documentation and/or other materials provided with the
+   * distribution.
+   *
+   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+   * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+   * DAMAGE.
+   *
+   * @category
+   * @package     Services_JSON
+   * @author      Michal Migurski <mike-json@teczno.com>
+   * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
+   * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
+   * @author      Christoph Dorn <christoph@christophdorn.com>
+   * @copyright   2005 Michal Migurski
+   * @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
+   * @license     http://www.opensource.org/licenses/bsd-license.php
+   * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
+   */
+   
+     
+  /**
+   * Keep a list of objects as we descend into the array so we can detect recursion.
+   */
+  var $json_objectStack = array();
+
+
+ /**
+  * convert a string from one UTF-8 char to one UTF-16 char
+  *
+  * Normally should be handled by mb_convert_encoding, but
+  * provides a slower PHP-only method for installations
+  * that lack the multibye string extension.
+  *
+  * @param    string  $utf8   UTF-8 character
+  * @return   string  UTF-16 character
+  * @access   private
+  */
+  function json_utf82utf16($utf8)
+  {
+      // oh please oh please oh please oh please oh please
+      if(function_exists('mb_convert_encoding')) {
+          return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+      }
+
+      switch(strlen($utf8)) {
+          case 1:
+              // this case should never be reached, because we are in ASCII range
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return $utf8;
+
+          case 2:
+              // return a UTF-16 character from a 2-byte UTF-8 char
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return chr(0x07 & (ord($utf8{0}) >> 2))
+                   . chr((0xC0 & (ord($utf8{0}) << 6))
+                       | (0x3F & ord($utf8{1})));
+
+          case 3:
+              // return a UTF-16 character from a 3-byte UTF-8 char
+              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+              return chr((0xF0 & (ord($utf8{0}) << 4))
+                       | (0x0F & (ord($utf8{1}) >> 2)))
+                   . chr((0xC0 & (ord($utf8{1}) << 6))
+                       | (0x7F & ord($utf8{2})));
+      }
+
+      // ignoring UTF-32 for now, sorry
+      return '';
+  }
+
+ /**
+  * encodes an arbitrary variable into JSON format
+  *
+  * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
+  *                           see argument 1 to Services_JSON() above for array-parsing behavior.
+  *                           if var is a strng, note that encode() always expects it
+  *                           to be in ASCII or UTF-8 format!
+  *
+  * @return   mixed   JSON string representation of input var or an error if a problem occurs
+  * @access   public
+  */
+  function json_encode($var)
+  {
+    
+    if(is_object($var)) {
+      if(in_array($var,$this->json_objectStack)) {
+        return '"** Recursion **"';
+      }
+    }
+          
+      switch (gettype($var)) {
+          case 'boolean':
+              return $var ? 'true' : 'false';
+
+          case 'NULL':
+              return 'null';
+
+          case 'integer':
+              return (int) $var;
+
+          case 'double':
+          case 'float':
+              return (float) $var;
+
+          case 'string':
+              // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
+              $ascii = '';
+              $strlen_var = strlen($var);
+
+             /*
+              * Iterate over every character in the string,
+              * escaping with a slash or encoding to UTF-8 where necessary
+              */
+              for ($c = 0; $c < $strlen_var; ++$c) {
+
+                  $ord_var_c = ord($var{$c});
+
+                  switch (true) {
+                      case $ord_var_c == 0x08:
+                          $ascii .= '\b';
+                          break;
+                      case $ord_var_c == 0x09:
+                          $ascii .= '\t';
+                          break;
+                      case $ord_var_c == 0x0A:
+                          $ascii .= '\n';
+                          break;
+                      case $ord_var_c == 0x0C:
+                          $ascii .= '\f';
+                          break;
+                      case $ord_var_c == 0x0D:
+                          $ascii .= '\r';
+                          break;
+
+                      case $ord_var_c == 0x22:
+                      case $ord_var_c == 0x2F:
+                      case $ord_var_c == 0x5C:
+                          // double quote, slash, slosh
+                          $ascii .= '\\'.$var{$c};
+                          break;
+
+                      case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
+                          // characters U-00000000 - U-0000007F (same as ASCII)
+                          $ascii .= $var{$c};
+                          break;
+
+                      case (($ord_var_c & 0xE0) == 0xC0):
+                          // characters U-00000080 - U-000007FF, mask 110XXXXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
+                          $c += 1;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xF0) == 0xE0):
+                          // characters U-00000800 - U-0000FFFF, mask 1110XXXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}));
+                          $c += 2;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xF8) == 0xF0):
+                          // characters U-00010000 - U-001FFFFF, mask 11110XXX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}));
+                          $c += 3;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xFC) == 0xF8):
+                          // characters U-00200000 - U-03FFFFFF, mask 111110XX
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}),
+                                       ord($var{$c + 4}));
+                          $c += 4;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+
+                      case (($ord_var_c & 0xFE) == 0xFC):
+                          // characters U-04000000 - U-7FFFFFFF, mask 1111110X
+                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
+                          $char = pack('C*', $ord_var_c,
+                                       ord($var{$c + 1}),
+                                       ord($var{$c + 2}),
+                                       ord($var{$c + 3}),
+                                       ord($var{$c + 4}),
+                                       ord($var{$c + 5}));
+                          $c += 5;
+                          $utf16 = $this->json_utf82utf16($char);
+                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
+                          break;
+                  }
+              }
+
+              return '"'.$ascii.'"';
+
+          case 'array':
+             /*
+              * As per JSON spec if any array key is not an integer
+              * we must treat the the whole array as an object. We
+              * also try to catch a sparsely populated associative
+              * array with numeric keys here because some JS engines
+              * will create an array with empty indexes up to
+              * max_index which can cause memory issues and because
+              * the keys, which may be relevant, will be remapped
+              * otherwise.
+              *
+              * As per the ECMA and JSON specification an object may
+              * have any string as a property. Unfortunately due to
+              * a hole in the ECMA specification if the key is a
+              * ECMA reserved word or starts with a digit the
+              * parameter is only accessible using ECMAScript's
+              * bracket notation.
+              */
+
+              // treat as a JSON object
+              if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
+                  
+                  $this->json_objectStack[] = $var;
+
+                  $properties = array_map(array($this, 'json_name_value'),
+                                          array_keys($var),
+                                          array_values($var));
+
+                  array_pop($this->json_objectStack);
+
+                  return '{' . join(',', $properties) . '}';
+              }
+
+              $this->json_objectStack[] = $var;
+
+              // treat it like a regular array
+              $elements = array_map(array($this, 'json_encode'), $var);
+
+              array_pop($this->json_objectStack);
+
+              return '[' . join(',', $elements) . ']';
+
+          case 'object':
+              $vars = FirePHP::encodeObject($var);
+
+              $this->json_objectStack[] = $var;
+
+              $properties = array_map(array($this, 'json_name_value'),
+                                      array_keys($vars),
+                                      array_values($vars));
+
+              array_pop($this->json_objectStack);
+              
+              return '{' . join(',', $properties) . '}';
+
+          default:
+              return null;
+      }
+  }
+
+ /**
+  * array-walking function for use in generating JSON-formatted name-value pairs
+  *
+  * @param    string  $name   name of key to use
+  * @param    mixed   $value  reference to an array element to be encoded
+  *
+  * @return   string  JSON-formatted name-value pair, like '"name":value'
+  * @access   private
+  */
+  function json_name_value($name, $value)
+  {
+      // Encoding the $GLOBALS PHP array causes an infinite loop
+      // if the recursion is not reset here as it contains
+      // a reference to itself. This is the only way I have come up
+      // with to stop infinite recursion in this case.
+      if($name=='GLOBALS'
+         && is_array($value)
+         && array_key_exists('GLOBALS',$value)) {
+        $value['GLOBALS'] = '** Recursion **';
+      }
+    
+      $encoded_value = $this->json_encode($value);
+
+      return $this->json_encode(strval($name)) . ':' . $encoded_value;
+  }
+}
+
diff --git a/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/LICENSE b/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/LICENSE
new file mode 100644 (file)
index 0000000..3e390f9
--- /dev/null
@@ -0,0 +1,29 @@
+Software License Agreement (New BSD License)
+
+Copyright (c) 2006-2009, Christoph Dorn
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+
+    * Neither the name of Christoph Dorn nor the names of its
+      contributors may be used to endorse or promote products derived from this
+      software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php b/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php
new file mode 100644 (file)
index 0000000..9d1857c
--- /dev/null
@@ -0,0 +1,261 @@
+<?php
+
+/* ***** BEGIN LICENSE BLOCK *****
+ *  
+ * This file is part of FirePHP (http://www.firephp.org/).
+ * 
+ * Software License Agreement (New BSD License)
+ * 
+ * Copyright (c) 2006-2009, Christoph Dorn
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ *     * Neither the name of Christoph Dorn nor the names of its
+ *       contributors may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * ***** END LICENSE BLOCK *****
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+
+require_once dirname(__FILE__).'/FirePHP.class.php';
+
+/**
+ * Sends the given data to the FirePHP Firefox Extension.
+ * The data can be displayed in the Firebug Console or in the
+ * "Server" request tab.
+ * 
+ * @see http://www.firephp.org/Wiki/Reference/Fb
+ * @param mixed $Object
+ * @return true
+ * @throws Exception
+ */
+function fb()
+{
+  $instance = FirePHP::getInstance(true);
+  
+  $args = func_get_args();
+  return call_user_func_array(array($instance,'fb'),$args);
+}
+
+
+class FB
+{
+  /**
+   * Enable and disable logging to Firebug
+   * 
+   * @see FirePHP->setEnabled()
+   * @param boolean $Enabled TRUE to enable, FALSE to disable
+   * @return void
+   */
+  public static function setEnabled($Enabled) {
+    $instance = FirePHP::getInstance(true);
+    $instance->setEnabled($Enabled);
+  }
+  
+  /**
+   * Check if logging is enabled
+   * 
+   * @see FirePHP->getEnabled()
+   * @return boolean TRUE if enabled
+   */
+  public static function getEnabled() {
+    $instance = FirePHP::getInstance(true);
+    return $instance->getEnabled();
+  }  
+  
+  /**
+   * Specify a filter to be used when encoding an object
+   * 
+   * Filters are used to exclude object members.
+   * 
+   * @see FirePHP->setObjectFilter()
+   * @param string $Class The class name of the object
+   * @param array $Filter An array or members to exclude
+   * @return void
+   */
+  public static function setObjectFilter($Class, $Filter) {
+    $instance = FirePHP::getInstance(true);
+    $instance->setObjectFilter($Class, $Filter);
+  }
+  
+  /**
+   * Set some options for the library
+   * 
+   * @see FirePHP->setOptions()
+   * @param array $Options The options to be set
+   * @return void
+   */
+  public static function setOptions($Options) {
+    $instance = FirePHP::getInstance(true);
+    $instance->setOptions($Options);
+  }
+
+  /**
+   * Get options for the library
+   * 
+   * @see FirePHP->getOptions()
+   * @return array The options
+   */
+  public static function getOptions() {
+    $instance = FirePHP::getInstance(true);
+    return $instance->getOptions();
+  }
+
+  /**
+   * Log object to firebug
+   * 
+   * @see http://www.firephp.org/Wiki/Reference/Fb
+   * @param mixed $Object
+   * @return true
+   * @throws Exception
+   */
+  public static function send()
+  {
+    $instance = FirePHP::getInstance(true);
+    $args = func_get_args();
+    return call_user_func_array(array($instance,'fb'),$args);
+  }
+
+  /**
+   * Start a group for following messages
+   * 
+   * Options:
+   *   Collapsed: [true|false]
+   *   Color:     [#RRGGBB|ColorName]
+   *
+   * @param string $Name
+   * @param array $Options OPTIONAL Instructions on how to log the group
+   * @return true
+   */
+  public static function group($Name, $Options=null) {
+    $instance = FirePHP::getInstance(true);
+    return $instance->group($Name, $Options);
+  }
+
+  /**
+   * Ends a group you have started before
+   *
+   * @return true
+   * @throws Exception
+   */
+  public static function groupEnd() {
+    return self::send(null, null, FirePHP::GROUP_END);
+  }
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::LOG
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public static function log($Object, $Label=null) {
+    return self::send($Object, $Label, FirePHP::LOG);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::INFO
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public static function info($Object, $Label=null) {
+    return self::send($Object, $Label, FirePHP::INFO);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::WARN
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public static function warn($Object, $Label=null) {
+    return self::send($Object, $Label, FirePHP::WARN);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::ERROR
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public static function error($Object, $Label=null) {
+    return self::send($Object, $Label, FirePHP::ERROR);
+  } 
+
+  /**
+   * Dumps key and variable to firebug server panel
+   *
+   * @see FirePHP::DUMP
+   * @param string $Key
+   * @param mixed $Variable
+   * @return true
+   * @throws Exception
+   */
+  public static function dump($Key, $Variable) {
+    return self::send($Variable, $Key, FirePHP::DUMP);
+  } 
+
+  /**
+   * Log a trace in the firebug console
+   *
+   * @see FirePHP::TRACE
+   * @param string $Label
+   * @return true
+   * @throws Exception
+   */
+  public static function trace($Label) {
+    return self::send($Label, FirePHP::TRACE);
+  } 
+
+  /**
+   * Log a table in the firebug console
+   *
+   * @see FirePHP::TABLE
+   * @param string $Label
+   * @param string $Table
+   * @return true
+   * @throws Exception
+   */
+  public static function table($Label, $Table) {
+    return self::send($Table, $Label, FirePHP::TABLE);
+  } 
+
+}
+
diff --git a/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php4 b/plugins/FirePHP/extlib/FirePHP/lib/FirePHPCore/fb.php4
new file mode 100644 (file)
index 0000000..5b69e34
--- /dev/null
@@ -0,0 +1,251 @@
+<?php
+
+/* ***** BEGIN LICENSE BLOCK *****
+ *  
+ * This file is part of FirePHP (http://www.firephp.org/).
+ * 
+ * Software License Agreement (New BSD License)
+ * 
+ * Copyright (c) 2006-2009, Christoph Dorn
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ * 
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ * 
+ *     * Neither the name of Christoph Dorn nor the names of its
+ *       contributors may be used to endorse or promote products derived from this
+ *       software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * ***** END LICENSE BLOCK *****
+ * 
+ * @copyright   Copyright (C) 2007-2009 Christoph Dorn
+ * @author      Christoph Dorn <christoph@christophdorn.com>
+ * @author      Michael Day <manveru.alma@gmail.com>
+ * @license     http://www.opensource.org/licenses/bsd-license.php
+ * @package     FirePHP
+ */
+
+require_once dirname(__FILE__).'/FirePHP.class.php4';
+
+/**
+ * Sends the given data to the FirePHP Firefox Extension.
+ * The data can be displayed in the Firebug Console or in the
+ * "Server" request tab.
+ * 
+ * @see http://www.firephp.org/Wiki/Reference/Fb
+ * @param mixed $Object
+ * @return true
+ * @throws Exception
+ */
+function fb()
+{
+  $instance =& FirePHP::getInstance(true);
+
+  $args = func_get_args();
+  return call_user_func_array(array(&$instance,'fb'),$args);
+}
+
+
+class FB
+{
+  /**
+   * Enable and disable logging to Firebug
+   * 
+   * @see FirePHP->setEnabled()
+   * @param boolean $Enabled TRUE to enable, FALSE to disable
+   * @return void
+   */
+  function setEnabled($Enabled) {
+    $instance =& FirePHP::getInstance(true);
+    $instance->setEnabled($Enabled);
+  }
+  
+  /**
+   * Check if logging is enabled
+   * 
+   * @see FirePHP->getEnabled()
+   * @return boolean TRUE if enabled
+   */
+  function getEnabled() {
+    $instance =& FirePHP::getInstance(true);
+    return $instance->getEnabled();
+  }  
+  
+  /**
+   * Specify a filter to be used when encoding an object
+   * 
+   * Filters are used to exclude object members.
+   * 
+   * @see FirePHP->setObjectFilter()
+   * @param string $Class The class name of the object
+   * @param array $Filter An array or members to exclude
+   * @return void
+   */
+  function setObjectFilter($Class, $Filter) {
+    $instance =& FirePHP::getInstance(true);
+    $instance->setObjectFilter($Class, $Filter);
+  }
+  
+  /**
+   * Set some options for the library
+   * 
+   * @see FirePHP->setOptions()
+   * @param array $Options The options to be set
+   * @return void
+   */
+  function setOptions($Options) {
+    $instance =& FirePHP::getInstance(true);
+    $instance->setOptions($Options);
+  }
+
+  /**
+   * Get options for the library
+   * 
+   * @see FirePHP->getOptions()
+   * @return array The options
+   */
+  function getOptions() {
+    $instance =& FirePHP::getInstance(true);
+    return $instance->getOptions();
+  }
+
+  /**
+   * Log object to firebug
+   * 
+   * @see http://www.firephp.org/Wiki/Reference/Fb
+   * @param mixed $Object
+   * @return true
+   */
+  function send()
+  {
+    $instance =& FirePHP::getInstance(true);
+    $args = func_get_args();
+    return call_user_func_array(array(&$instance,'fb'),$args);
+  }
+
+  /**
+   * Start a group for following messages
+   * 
+   * Options:
+   *   Collapsed: [true|false]
+   *   Color:     [#RRGGBB|ColorName]
+   *
+   * @param string $Name
+   * @param array $Options OPTIONAL Instructions on how to log the group
+   * @return true
+   */
+  function group($Name, $Options=null) {
+    $instance =& FirePHP::getInstance(true);
+    return $instance->group($Name, $Options);
+  }
+
+  /**
+   * Ends a group you have started before
+   *
+   * @return true
+   */
+  function groupEnd() {
+    return FB::send(null, null, FirePHP_GROUP_END);
+  }
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::LOG
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   */
+  function log($Object, $Label=null) {
+    return FB::send($Object, $Label, FirePHP_LOG);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::INFO
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   */
+  function info($Object, $Label=null) {
+    return FB::send($Object, $Label, FirePHP_INFO);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::WARN
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   */
+  function warn($Object, $Label=null) {
+    return FB::send($Object, $Label, FirePHP_WARN);
+  } 
+
+  /**
+   * Log object with label to firebug console
+   *
+   * @see FirePHP::ERROR
+   * @param mixes $Object
+   * @param string $Label
+   * @return true
+   */
+  function error($Object, $Label=null) {
+    return FB::send($Object, $Label, FirePHP_ERROR);
+  } 
+
+  /**
+   * Dumps key and variable to firebug server panel
+   *
+   * @see FirePHP::DUMP
+   * @param string $Key
+   * @param mixed $Variable
+   * @return true
+   */
+  function dump($Key, $Variable) {
+    return FB::send($Variable, $Key, FirePHP_DUMP);
+  } 
+
+  /**
+   * Log a trace in the firebug console
+   *
+   * @see FirePHP::TRACE
+   * @param string $Label
+   * @return true
+   */
+  function trace($Label) {
+    return FB::send($Label, FirePHP_TRACE);
+  } 
+
+  /**
+   * Log a table in the firebug console
+   *
+   * @see FirePHP::TABLE
+   * @param string $Label
+   * @param string $Table
+   * @return true
+   */
+  function table($Label, $Table) {
+    return FB::send($Table, $Label, FirePHP_TABLE);
+  } 
+}