| @@ -0,0 +1,127 @@ | ||
| <?php | ||
| /** | ||
| * @package Molajo | ||
| * @subpackage Model | ||
| * @copyright Copyright (C) 2012 Amy Stephen. All rights reserved. | ||
| * @license GNU General Public License Version 2, or later http://www.gnu.org/licenses/gpl.html | ||
| */ | ||
| defined('MOLAJO') or die; | ||
|
|
||
| /** | ||
| * Load | ||
| * | ||
| * @package Molajo | ||
| * @subpackage Model | ||
| * @since 1.0 | ||
| */ | ||
| class MolajoLoadModel extends MolajoItemModel | ||
| { | ||
| /** | ||
| * load | ||
| * | ||
| * Method to load a specific item from a specific model. | ||
| * Creates and runs the database query, allows for additional data, | ||
| * and returns integrated data as the item requested | ||
| * | ||
| * @return object | ||
| * @since 1.0 | ||
| */ | ||
| public function load() | ||
| { | ||
| $this->_setLoadQuery(); | ||
|
|
||
| $this->_runLoadQuery(); | ||
| if (empty($this->query_results)) { | ||
| return false; | ||
| } | ||
|
|
||
| $this->_getLoadAdditionalData(); | ||
|
|
||
| return $this->query_results; | ||
| } | ||
|
|
||
| /** | ||
| * _setLoadQuery | ||
| * | ||
| * Retrieve all elements of the specific table for a specific item | ||
| * | ||
| * @return object | ||
| * @since 1.0 | ||
| */ | ||
| protected function _setLoadQuery() | ||
| { | ||
| $this->query = $this->db->getQuery(true); | ||
|
|
||
| $this->query->select(' * '); | ||
| $this->query->from($this->db->qn($this->table_name)); | ||
| $this->query->where($this->primary_key | ||
| . ' = ' | ||
| . $this->db->q($this->id)); | ||
|
|
||
| $this->db->setQuery($this->query->__toString()); | ||
| } | ||
|
|
||
| /** | ||
| * _runLoadQuery | ||
| * | ||
| * Execute query and returns an associative array of data elements | ||
| * | ||
| * @return array | ||
| * @since 1.0 | ||
| */ | ||
| protected function _runLoadQuery() | ||
| { | ||
| $this->query_results = $this->db->loadAssoc(); | ||
|
|
||
| if (empty($this->query_results)) { | ||
| return false; | ||
| } | ||
|
|
||
| if (key_exists('custom_fields', $this->query_results) | ||
| && is_array($this->query_results['custom_fields']) | ||
| ) { | ||
| $registry = new Registry(); | ||
| $registry->loadString($this->query_results['custom_fields']); | ||
| $this->query_results['custom_fields'] = (string)$registry; | ||
| } | ||
|
|
||
| if (key_exists('parameters', $this->query_results) | ||
| && is_array($this->query_results['parameters']) | ||
| ) { | ||
| $registry = new Registry(); | ||
| $registry->loadString($this->query_results['parameters']); | ||
| $this->query_results['parameters'] = (string)$registry; | ||
| } | ||
|
|
||
| if (key_exists('metadata', $this->query_results) | ||
| && is_array($this->query_results['metadata']) | ||
| ) { | ||
| $registry = new Registry(); | ||
| $registry->loadString($this->query_results['metadata']); | ||
| $this->query_results['metadata'] = (string)$registry; | ||
| } | ||
|
|
||
| if ($this->db->getErrorNum()) { | ||
| $e = new MolajoException($this->db->getErrorMsg()); | ||
| $this->setError($e); | ||
| return false; | ||
| } | ||
|
|
||
| return $this->query_results; | ||
| } | ||
|
|
||
| /** | ||
| * _getAdditionalData | ||
| * | ||
| * Method to append additional data elements needed to the standard | ||
| * array of elements provided by the data source | ||
| * | ||
| * @return array | ||
| * @since 1.0 | ||
| */ | ||
| protected function _getLoadAdditionalData() | ||
| { | ||
| return $this->query_results; | ||
| } | ||
| } | ||
|
|
| @@ -38,3 +38,9 @@ | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Debug | ||
| */ | ||
| $load->requireClassFile(PLATFORM_MOLAJO . '/debug/PhpConsole.php', 'PhpConsole'); | ||
| PhpConsole::start(true, true, PLATFORM_MOLAJO . '/debug'); | ||
|
|
||
| @@ -0,0 +1,316 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * | ||
| * @see http://code.google.com/p/php-console | ||
| * @author Barbushin Sergey http://linkedin.com/in/barbushin | ||
| * @version 1.1 | ||
| * | ||
| * @desc Sending messages to Google Chrome console | ||
| * | ||
| * You need to install Google Chrome extension: | ||
| * https://chrome.google.com/extensions/detail/nfhmhhlpfleoednkpnnnkolmclajemef | ||
| * | ||
| * All class properties and methods are static because it's required to let | ||
| * them work on script shutdown when FATAL error occurs. | ||
| * | ||
| */ | ||
| class PhpConsole { | ||
|
|
||
| public static $ignoreRepeatedEvents = false; | ||
| public static $callOldErrorHandler = true; | ||
| public static $callOldExceptionsHandler = true; | ||
|
|
||
| /** | ||
| * @var PhpConsole | ||
| */ | ||
| protected static $instance; | ||
|
|
||
| protected $handledMessagesHashes = array(); | ||
| protected $sourceBasePath; | ||
|
|
||
| protected function __construct($handleErrors, $handleExceptions, $sourceBasePath) { | ||
| if($handleErrors) { | ||
| $this->initErrorsHandler(); | ||
| } | ||
| if($handleExceptions) { | ||
| $this->initExceptionsHandler(); | ||
| } | ||
| if($sourceBasePath) { | ||
| $this->sourceBasePath = realpath($sourceBasePath); | ||
| } | ||
| $this->initClient(); | ||
| } | ||
|
|
||
| public static function start($handleErrors = true, $handleExceptions = true, $sourceBasePath = null) { | ||
| if(!self::$instance) { | ||
| self::$instance = new PhpConsole($handleErrors, $handleExceptions, $sourceBasePath); | ||
| } | ||
| } | ||
|
|
||
| protected function handle(PhpConsoleEvent $event) { | ||
| if(self::$ignoreRepeatedEvents) { | ||
| $eventHash = md5($event->message . $event->file . $event->line); | ||
| if(in_array($eventHash, $this->handledMessagesHashes)) { | ||
| return; | ||
| } | ||
| else { | ||
| $this->handledMessagesHashes[] = $eventHash; | ||
| } | ||
| } | ||
| $this->sendEventToClient($event); | ||
| } | ||
|
|
||
| public function __destruct() { | ||
| self::flushMessagesBuffer(); | ||
| } | ||
|
|
||
| /*************************************************************** | ||
| CLIENT | ||
| **************************************************************/ | ||
|
|
||
| const clientProtocolCookie = 'phpcslc'; | ||
| const serverProtocolCookie = 'phpcsls'; | ||
| const serverProtocol = 4; | ||
| const messagesCookiePrefix = 'phpcsl_'; | ||
| const cookiesLimit = 50; | ||
| const cookieSizeLimit = 4000; | ||
| const messageLengthLimit = 2500; | ||
|
|
||
| protected static $isEnabledOnClient; | ||
| protected static $isDisabled; | ||
| protected static $messagesBuffer = array(); | ||
| protected static $bufferLength = 0; | ||
| protected static $messagesSent = 0; | ||
| protected static $cookiesSent = 0; | ||
| protected static $index = 0; | ||
|
|
||
| protected function initClient() { | ||
| if(self::$isEnabledOnClient === null) { | ||
| self::setEnabledOnServer(); | ||
| self::$isEnabledOnClient = self::isEnabledOnClient(); | ||
| if(self::$isEnabledOnClient) { | ||
| ob_start(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected static function isEnabledOnClient() { | ||
| return isset($_COOKIE[self::clientProtocolCookie]) && $_COOKIE[self::clientProtocolCookie] == self::serverProtocol; | ||
| } | ||
|
|
||
| protected static function setEnabledOnServer() { | ||
| if(!isset($_COOKIE[self::serverProtocolCookie]) || $_COOKIE[self::serverProtocolCookie] != self::serverProtocol) { | ||
| self::setCookie(self::serverProtocolCookie, self::serverProtocol); | ||
| } | ||
| } | ||
|
|
||
| protected function sendEventToClient(PhpConsoleEvent $event) { | ||
| if(!self::$isEnabledOnClient || self::$isDisabled) { | ||
| return; | ||
| } | ||
| $message = array(); | ||
| $message['type'] = strpos($event->tags, 'error,') === 0 ? 'error' : 'debug'; | ||
| $message['subject'] = $event->type; | ||
| $message['text'] = substr($event->message, 0, self::messageLengthLimit); | ||
|
|
||
| if($event->file) { | ||
| $message['source'] = ($this->sourceBasePath ? preg_replace('!^' . preg_quote($this->sourceBasePath, '!') . '!', '', $event->file) : $event->file) . ($event->line ? ':' . $event->line : ''); | ||
| } | ||
| if($event->trace) { | ||
| $traceArray = $this->convertTraceToArray($event->trace, $event->file, $event->line); | ||
| if($traceArray) { | ||
| $message['trace'] = $traceArray; | ||
| } | ||
| } | ||
|
|
||
| self::pushMessageToBuffer($message); | ||
|
|
||
| if(strpos($event->tags, ',fatal')) { | ||
| self::flushMessagesBuffer(); | ||
| } | ||
| } | ||
|
|
||
| protected function convertTraceToArray($traceData, $eventFile = null, $eventLine = null) { | ||
| $trace = array(); | ||
| foreach($traceData as $call) { | ||
| if((isset($call['class']) && $call['class'] == __CLASS__) || (!$trace && isset($call['file']) && $call['file'] == $eventFile && $call['line'] == $eventLine)) { | ||
| $trace = array(); | ||
| continue; | ||
| } | ||
| $args = array(); | ||
| if(isset($call['args'])) { | ||
| foreach($call['args'] as $arg) { | ||
| if(is_object($arg)) { | ||
| $args[] = get_class($arg); | ||
| } | ||
| elseif(is_array($arg)) { | ||
| $args[] = 'Array'; | ||
| } | ||
| else { | ||
| $arg = var_export($arg, 1); | ||
| $args[] = strlen($arg) > 12 ? substr($arg, 0, 8) . '...\'' : $arg; | ||
| } | ||
| } | ||
| } | ||
| if(isset($call['file']) && $this->sourceBasePath) { | ||
| $call['file'] = preg_replace('!^' . preg_quote($this->sourceBasePath, '!') . '!', '', $call['file']); | ||
| } | ||
| $trace[] = (isset($call['file']) ? ($call['file'] . ':' . $call['line']) : '[internal call]') . ' - ' . (isset($call['class']) ? $call['class'] . $call['type'] : '') . $call['function'] . '(' . implode(', ', $args) . ')'; | ||
| } | ||
| $trace = array_reverse($trace); | ||
| foreach($trace as $i => &$call) { | ||
| $call = '#' . ($i + 1) . ' ' . $call; | ||
| } | ||
| return $trace; | ||
| } | ||
|
|
||
| protected static function pushMessageToBuffer($message) { | ||
| $encodedMessageLength = strlen(rawurlencode(json_encode($message))); | ||
| if(self::$bufferLength + $encodedMessageLength > self::cookieSizeLimit) { | ||
| self::flushMessagesBuffer(); | ||
| } | ||
| self::$messagesBuffer[] = $message; | ||
| self::$bufferLength += $encodedMessageLength; | ||
| } | ||
|
|
||
| protected static function getNextIndex() { | ||
| return substr(number_format(microtime(1), 3, '', ''), -6) + self::$index++; | ||
| } | ||
|
|
||
| public static function flushMessagesBuffer() { | ||
| if(self::$messagesBuffer) { | ||
| self::sendMessages(self::$messagesBuffer); | ||
| self::$bufferLength = 0; | ||
| self::$messagesSent += count(self::$messagesBuffer); | ||
| self::$messagesBuffer = array(); | ||
| self::$cookiesSent++; | ||
| if(self::$cookiesSent == self::cookiesLimit) { | ||
| self::$isDisabled = true; | ||
| $message = array('type' => 'error', 'subject' => 'PHP CONSOLE', 'text' => 'MESSAGES LIMIT EXCEEDED BECAUSE OF COOKIES STORAGE LIMIT. TOTAL MESSAGES SENT: ' . self::$messagesSent, 'source' => __FILE__, 'notify' => 3); | ||
| self::sendMessages(array($message)); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| protected static function setCookie($name, $value) { | ||
| if(headers_sent($file, $line)) { | ||
| throw new Exception('setcookie() failed because haders are sent (' . $file . ':' . $line . '). Try to use ob_start()'); | ||
| } | ||
| setcookie($name, $value, null, '/'); | ||
| } | ||
|
|
||
| protected static function sendMessages($messages) { | ||
| self::setCookie(self::messagesCookiePrefix . self::getNextIndex(), json_encode($messages)); | ||
| } | ||
|
|
||
| /*************************************************************** | ||
| ERRORS | ||
| **************************************************************/ | ||
|
|
||
| protected $codesTags = array(E_ERROR => 'fatal', E_WARNING => 'warning', E_PARSE => 'fatal', E_NOTICE => 'notice', E_CORE_ERROR => 'fatal', E_CORE_WARNING => 'warning', E_COMPILE_ERROR => 'fatal', E_COMPILE_WARNING => 'warning', E_USER_ERROR => 'fatal', E_USER_WARNING => 'warning', E_USER_NOTICE => 'notice', E_STRICT => 'warning'); | ||
| protected $codesNames = array(E_ERROR => 'E_ERROR', E_WARNING => 'E_WARNING', E_PARSE => 'E_PARSE', E_NOTICE => 'E_NOTICE', E_CORE_ERROR => 'E_CORE_ERROR', E_CORE_WARNING => 'E_CORE_WARNING', E_COMPILE_ERROR => 'E_COMPILE_ERROR', E_COMPILE_WARNING => 'E_COMPILE_WARNING', E_USER_ERROR => 'E_USER_ERROR', E_USER_WARNING => 'E_USER_WARNING', E_USER_NOTICE => 'E_USER_NOTICE', E_STRICT => 'E_STRICT'); | ||
| protected $notCompitableCodes = array('E_RECOVERABLE_ERROR' => 'warning', 'E_DEPRECATED' => 'warning'); | ||
| protected $oldErrorHandler; | ||
|
|
||
| protected function initErrorsHandler() { | ||
| ini_set('display_errors', false); | ||
| ini_set('html_errors', false); | ||
| ini_set('ignore_repeated_errors', self::$ignoreRepeatedEvents); | ||
| ini_set('ignore_repeated_source', self::$ignoreRepeatedEvents); | ||
|
|
||
| foreach($this->notCompitableCodes as $code => $tag) { | ||
| if(defined($code)) { | ||
| $this->codesTags[constant($code)] = $tag; | ||
| $this->codesNames[constant($code)] = $code; | ||
| } | ||
| } | ||
|
|
||
| $this->oldErrorHandler = set_error_handler(array($this, 'handleError')); | ||
| register_shutdown_function(array($this, 'checkFatalError')); | ||
| } | ||
|
|
||
| public function checkFatalError() { | ||
| $error = error_get_last(); | ||
| if($error) { | ||
| $this->handleError($error['type'], $error['message'], $error['file'], $error['line']); | ||
| } | ||
| } | ||
|
|
||
| public function handleError($code = null, $message = null, $file = null, $line = null) { | ||
| if(error_reporting() == 0) { // if error has been supressed with an @ | ||
| return; | ||
| } | ||
| if(!$code) { | ||
| $code = E_USER_ERROR; | ||
| } | ||
|
|
||
| $event = new PhpConsoleEvent(); | ||
| $event->tags = 'error,' . (isset($this->codesTags[$code]) ? $this->codesTags[$code] : 'warning'); | ||
| $event->message = $message; | ||
| $event->type = isset($this->codesNames[$code]) ? $this->codesNames[$code] : $code; | ||
| $event->file = $file; | ||
| $event->line = $line; | ||
| $event->trace = debug_backtrace(); | ||
|
|
||
| $this->handle($event); | ||
|
|
||
| if(self::$callOldErrorHandler && $this->oldErrorHandler) { | ||
| call_user_func_array($this->oldErrorHandler, array($code, $message, $file, $line)); | ||
| } | ||
| } | ||
|
|
||
| /*************************************************************** | ||
| EXCEPTIONS | ||
| **************************************************************/ | ||
|
|
||
| protected $oldExceptionsHandler; | ||
|
|
||
| protected function initExceptionsHandler() { | ||
| $this->oldExceptionsHandler = set_exception_handler(array($this, 'handleException')); | ||
| } | ||
|
|
||
| public function handleException(Exception $exception) { | ||
| $event = new PhpConsoleEvent(); | ||
| $event->message = $exception->getMessage(); | ||
| $event->tags = 'error,fatal,exception,' . get_class($exception); | ||
| $event->type = get_class($exception); | ||
| $event->file = $exception->getFile(); | ||
| $event->line = $exception->getLine(); | ||
| $event->trace = $exception->getTrace(); | ||
|
|
||
| $this->handle($event); | ||
|
|
||
| // TODO: check if need to throw | ||
| if(self::$callOldExceptionsHandler && $this->oldExceptionsHandler) { | ||
| call_user_func($this->oldExceptionsHandler, $exception); | ||
| } | ||
| } | ||
|
|
||
| /*************************************************************** | ||
| DEBUG | ||
| **************************************************************/ | ||
|
|
||
| public static function debug($message, $tags = 'debug') { | ||
| if(self::$instance) { | ||
| $event = new PhpConsoleEvent(); | ||
| $event->message = $message; | ||
| $event->tags = $tags; | ||
| $event->type = $tags; | ||
| self::$instance->handle($event); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| class PhpConsoleEvent { | ||
| public $message; | ||
| public $type; | ||
| public $tags; | ||
| public $trace; | ||
| public $file; | ||
| public $line; | ||
| } | ||
|
|
||
| function debug($message, $tags = 'debug') { | ||
| PhpConsole::debug($message, $tags); | ||
| } |
| @@ -0,0 +1,13 @@ | ||
| Release 1.1 | ||
|
|
||
| Fixed: error in PHP < 5.3 syntax error, unexpected T_STATIC in PhpConsole.php on line 249 | ||
| Fixed: PhpConsole::convertTraceToString for calls without arguments | ||
| Added: basePath stripping | ||
|
|
||
| Release 1.0 | ||
|
|
||
| * Debug: Handle all exceptions and errors (even fatal) | ||
| * Added: Handle all exceptions and errors (even fatal) | ||
| * Added: Ignore repeated events when PhpConsole::$ignoreRepeatedEvents | ||
| * Added: Call previouse errors handler when PhpConsole::$callOldErrorHandler | ||
| * Added: Call previous exceptions handler when PhpConsole::$callOldExceptionsHandler |
| @@ -0,0 +1,24 @@ | ||
| <?php | ||
|
|
||
| require_once('PhpConsole.php'); | ||
| PhpConsole::start(true, true, dirname(__FILE__)); | ||
|
|
||
| // test | ||
|
|
||
| debug('debug message'); | ||
| debug('SELECT * FROM users', 'db'); | ||
|
|
||
| class TestErrorBacktrace { | ||
| function __construct() { | ||
| $this->yeah(12, array()); | ||
| } | ||
| function yeah() { | ||
| self::oops('some string', new stdClass()); | ||
| } | ||
| static function oops() { | ||
| file_get_contents('oops.txt'); | ||
| throw new Exception('Exception with call backtrace'); | ||
| } | ||
| } | ||
|
|
||
| new TestErrorBacktrace(); |
| @@ -0,0 +1,165 @@ | ||
| GNU LESSER GENERAL PUBLIC LICENSE | ||
| Version 3, 29 June 2007 | ||
|
|
||
| Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> | ||
| Everyone is permitted to copy and distribute verbatim copies | ||
| of this license document, but changing it is not allowed. | ||
|
|
||
|
|
||
| This version of the GNU Lesser General Public License incorporates | ||
| the terms and conditions of version 3 of the GNU General Public | ||
| License, supplemented by the additional permissions listed below. | ||
|
|
||
| 0. Additional Definitions. | ||
|
|
||
| As used herein, "this License" refers to version 3 of the GNU Lesser | ||
| General Public License, and the "GNU GPL" refers to version 3 of the GNU | ||
| General Public License. | ||
|
|
||
| "The Library" refers to a covered work governed by this License, | ||
| other than an Application or a Combined Work as defined below. | ||
|
|
||
| An "Application" is any work that makes use of an interface provided | ||
| by the Library, but which is not otherwise based on the Library. | ||
| Defining a subclass of a class defined by the Library is deemed a mode | ||
| of using an interface provided by the Library. | ||
|
|
||
| A "Combined Work" is a work produced by combining or linking an | ||
| Application with the Library. The particular version of the Library | ||
| with which the Combined Work was made is also called the "Linked | ||
| Version". | ||
|
|
||
| The "Minimal Corresponding Source" for a Combined Work means the | ||
| Corresponding Source for the Combined Work, excluding any source code | ||
| for portions of the Combined Work that, considered in isolation, are | ||
| based on the Application, and not on the Linked Version. | ||
|
|
||
| The "Corresponding Application Code" for a Combined Work means the | ||
| object code and/or source code for the Application, including any data | ||
| and utility programs needed for reproducing the Combined Work from the | ||
| Application, but excluding the System Libraries of the Combined Work. | ||
|
|
||
| 1. Exception to Section 3 of the GNU GPL. | ||
|
|
||
| You may convey a covered work under sections 3 and 4 of this License | ||
| without being bound by section 3 of the GNU GPL. | ||
|
|
||
| 2. Conveying Modified Versions. | ||
|
|
||
| If you modify a copy of the Library, and, in your modifications, a | ||
| facility refers to a function or data to be supplied by an Application | ||
| that uses the facility (other than as an argument passed when the | ||
| facility is invoked), then you may convey a copy of the modified | ||
| version: | ||
|
|
||
| a) under this License, provided that you make a good faith effort to | ||
| ensure that, in the event an Application does not supply the | ||
| function or data, the facility still operates, and performs | ||
| whatever part of its purpose remains meaningful, or | ||
|
|
||
| b) under the GNU GPL, with none of the additional permissions of | ||
| this License applicable to that copy. | ||
|
|
||
| 3. Object Code Incorporating Material from Library Header Files. | ||
|
|
||
| The object code form of an Application may incorporate material from | ||
| a header file that is part of the Library. You may convey such object | ||
| code under terms of your choice, provided that, if the incorporated | ||
| material is not limited to numerical parameters, data structure | ||
| layouts and accessors, or small macros, inline functions and templates | ||
| (ten or fewer lines in length), you do both of the following: | ||
|
|
||
| a) Give prominent notice with each copy of the object code that the | ||
| Library is used in it and that the Library and its use are | ||
| covered by this License. | ||
|
|
||
| b) Accompany the object code with a copy of the GNU GPL and this license | ||
| document. | ||
|
|
||
| 4. Combined Works. | ||
|
|
||
| You may convey a Combined Work under terms of your choice that, | ||
| taken together, effectively do not restrict modification of the | ||
| portions of the Library contained in the Combined Work and reverse | ||
| engineering for debugging such modifications, if you also do each of | ||
| the following: | ||
|
|
||
| a) Give prominent notice with each copy of the Combined Work that | ||
| the Library is used in it and that the Library and its use are | ||
| covered by this License. | ||
|
|
||
| b) Accompany the Combined Work with a copy of the GNU GPL and this license | ||
| document. | ||
|
|
||
| c) For a Combined Work that displays copyright notices during | ||
| execution, include the copyright notice for the Library among | ||
| these notices, as well as a reference directing the user to the | ||
| copies of the GNU GPL and this license document. | ||
|
|
||
| d) Do one of the following: | ||
|
|
||
| 0) Convey the Minimal Corresponding Source under the terms of this | ||
| License, and the Corresponding Application Code in a form | ||
| suitable for, and under terms that permit, the user to | ||
| recombine or relink the Application with a modified version of | ||
| the Linked Version to produce a modified Combined Work, in the | ||
| manner specified by section 6 of the GNU GPL for conveying | ||
| Corresponding Source. | ||
|
|
||
| 1) Use a suitable shared library mechanism for linking with the | ||
| Library. A suitable mechanism is one that (a) uses at run time | ||
| a copy of the Library already present on the user's computer | ||
| system, and (b) will operate properly with a modified version | ||
| of the Library that is interface-compatible with the Linked | ||
| Version. | ||
|
|
||
| e) Provide Installation Information, but only if you would otherwise | ||
| be required to provide such information under section 6 of the | ||
| GNU GPL, and only to the extent that such information is | ||
| necessary to install and execute a modified version of the | ||
| Combined Work produced by recombining or relinking the | ||
| Application with a modified version of the Linked Version. (If | ||
| you use option 4d0, the Installation Information must accompany | ||
| the Minimal Corresponding Source and Corresponding Application | ||
| Code. If you use option 4d1, you must provide the Installation | ||
| Information in the manner specified by section 6 of the GNU GPL | ||
| for conveying Corresponding Source.) | ||
|
|
||
| 5. Combined Libraries. | ||
|
|
||
| You may place library facilities that are a work based on the | ||
| Library side by side in a single library together with other library | ||
| facilities that are not Applications and are not covered by this | ||
| License, and convey such a combined library under terms of your | ||
| choice, if you do both of the following: | ||
|
|
||
| a) Accompany the combined library with a copy of the same work based | ||
| on the Library, uncombined with any other library facilities, | ||
| conveyed under the terms of this License. | ||
|
|
||
| b) Give prominent notice with the combined library that part of it | ||
| is a work based on the Library, and explaining where to find the | ||
| accompanying uncombined form of the same work. | ||
|
|
||
| 6. Revised Versions of the GNU Lesser General Public License. | ||
|
|
||
| The Free Software Foundation may publish revised and/or new versions | ||
| of the GNU Lesser General Public License from time to time. Such new | ||
| versions will be similar in spirit to the present version, but may | ||
| differ in detail to address new problems or concerns. | ||
|
|
||
| Each version is given a distinguishing version number. If the | ||
| Library as you received it specifies that a certain numbered version | ||
| of the GNU Lesser General Public License "or any later version" | ||
| applies to it, you have the option of following the terms and | ||
| conditions either of that published version or of any later version | ||
| published by the Free Software Foundation. If the Library as you | ||
| received it does not specify a version number of the GNU Lesser | ||
| General Public License, you may choose any version of the GNU Lesser | ||
| General Public License ever published by the Free Software Foundation. | ||
|
|
||
| If the Library as you received it specifies that a proxy can decide | ||
| whether future versions of the GNU Lesser General Public License shall | ||
| apply, that proxy's public statement of acceptance of any version is | ||
| permanent authorization for you to choose that version for the | ||
| Library. |
| @@ -0,0 +1,16 @@ | ||
| Extra lightweight errors/exceptions/debugs handler for Google Chrome extension PHP Console | ||
|
|
||
| SVN/trunk: | ||
| http://lagger.googlecode.com/svn/trunk/PhpConsole | ||
|
|
||
| Project site: | ||
| http://code.google.com/p/php-console | ||
|
|
||
| Project updates by RSS: | ||
| http://code.google.com/feeds/p/php-console/updates/basic | ||
|
|
||
| Contact to developer (freelancer, looking for interesting web-projects): | ||
| http://linkedin.com/in/barbushin | ||
|
|
||
| PHP Console development donation: | ||
| http://web-grant.com/donation/php-console |