From bccac55cf99fd4cd0d21bc1ad5e0ef16a762d74f Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Sat, 15 Jun 2024 11:53:00 +0200 Subject: tests: Add some tests for the Zotlabs\Magic module. Only tests the delegate functionality at the moment. This patch also includes some minor fixes to the Magic module, triggered by the tests with empty destination URL's. --- Zotlabs/Module/Magic.php | 8 ++- tests/unit/Module/MagicTest.php | 109 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 tests/unit/Module/MagicTest.php diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php index 8259f7d39..deda4255d 100644 --- a/Zotlabs/Module/Magic.php +++ b/Zotlabs/Module/Magic.php @@ -40,7 +40,11 @@ class Magic extends Controller { goaway($dest); } - $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (isset($parsed['port']) ? ':' . $parsed['port'] : ''); + $basepath = unparse_url(array_filter( + $parsed, + fn (string $key) => in_array($key, ['scheme', 'host', 'port']), + ARRAY_FILTER_USE_KEY + )); $owapath = SConfig::get($basepath,'system','openwebauth', $basepath . '/owa'); // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. @@ -106,7 +110,7 @@ class Magic extends Controller { $headers['Content-Type'] = 'application/x-zot+json' ; $headers['X-Open-Web-Auth'] = random_string(); $headers['Host'] = $parsed['host']; - $headers['(request-target)'] = 'get ' . '/owa'; + $headers['(request-target)'] = 'get /owa'; $headers = HTTPSig::create_sig($headers,$channel['channel_prvkey'], channel_url($channel),true,'sha512'); $redirects = 0; diff --git a/tests/unit/Module/MagicTest.php b/tests/unit/Module/MagicTest.php new file mode 100644 index 000000000..4d50412ee --- /dev/null +++ b/tests/unit/Module/MagicTest.php @@ -0,0 +1,109 @@ +expectRedirectTo(''); + + $this->get('magic'); + } + + #[BackupStaticProperties(App::class)] + public function test_local_request_without_delegate(): void { + $baseurl = 'https://hubzilla.test'; + $dest_url = $baseurl . '/channel/testuser'; + + App::set_baseurl($baseurl); + + App::$observer = [ + 'xchan_hash' => 'the hash', + ]; + + // We pass a local URL, and have a valid observer, but as the + // delegate param is not passed, nothing will be done except + // redirecting to the passed dest url. + // + // This should probably return a 400 Invalid Request instead. + $this->expectRedirectTo($dest_url); + + $this->get('magic', [ 'bdest' => bin2hex($dest_url) ]); + } + + #[BackupStaticProperties(App::class)] + public function test_delegate_request_switches_channel_when_allowed(): void { + $baseurl = 'https://hubzilla.test'; + $dest_url = $baseurl . '/channel/testuser'; + + // Set the stage: + // Populate the global static App class with necessary values for the + // code under test + App::set_baseurl($baseurl); + App::$timezone = 'UTC'; + + // Simulate a foreign (to this hub) observer, + App::$observer = [ + 'xchan_hash' => 'foreign hash', + ]; + + // Create the channel the foreign observer wants to access + $result = create_identity([ + 'account_id' => $this->fixtures['account'][0]['account_id'], + 'nickname' => 'testuser', + 'name' => 'Trish Testuser', + ]); + + // Shortcut the permission checks, by saying this observer is allowed + // the delegate privilege over the target channel + insert_hook('perm_is_allowed', function (array &$perm) { + $perm['result'] = true; + }); + + // Add some dummy session data, so we can check that it's being + // pushed to the delegate session. + $original_session = [ + 'data' => 'Just some test session data', + ]; + + $_SESSION = $original_session; + + // Handle redirects manually, since we want to be able to check some + // assertions after the redirect is thrown. + $this->stub_goaway(); + + try { + // Send a request to get delegate privileges for the `testuser` channel + // on the local hub. + $this->get('magic', [ + 'bdest' => bin2hex($dest_url), + 'delegate' => 'testuser@hubzilla.test'] + ); + } catch (RedirectException $e) { + $this->assertEquals($dest_url, $e->getMessage()); + $this->assertEquals($result['channel']['channel_id'], App::$channel['channel_id']); + $this->assertEquals($original_session, $_SESSION['delegate_push']); + $this->assertEquals($result['channel']['channel_id'], $_SESSION['delegate_channel']); + $this->assertEquals('foreign hash', $_SESSION['delegate']); + $this->assertEquals($this->fixtures['account'][0]['account_id'], $_SESSION['account_id']); + } + } +} -- cgit v1.2.3 From c13645f1364e182c35903607d47dff76170b19fb Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Mon, 7 Oct 2024 11:34:02 +0200 Subject: Remove HTML5 parser lib deprecated in Hubzilla 5.0 --- library/HTML5/Data.php | 120 - library/HTML5/InputStream.php | 284 -- library/HTML5/Parser.php | 36 - library/HTML5/Tokenizer.php | 2307 ---------------- library/HTML5/TreeBuilder.php | 3721 -------------------------- library/HTML5/named-character-references.ser | 1 - 6 files changed, 6469 deletions(-) delete mode 100644 library/HTML5/Data.php delete mode 100644 library/HTML5/InputStream.php delete mode 100644 library/HTML5/Parser.php delete mode 100644 library/HTML5/Tokenizer.php delete mode 100644 library/HTML5/TreeBuilder.php delete mode 100644 library/HTML5/named-character-references.ser diff --git a/library/HTML5/Data.php b/library/HTML5/Data.php deleted file mode 100644 index fa97e3ee8..000000000 --- a/library/HTML5/Data.php +++ /dev/null @@ -1,120 +0,0 @@ - 0x000A, // LINE FEED (LF) - 0x80 => 0x20AC, // EURO SIGN ('€') - 0x81 => 0xFFFD, // REPLACEMENT CHARACTER - 0x82 => 0x201A, // SINGLE LOW-9 QUOTATION MARK ('‚') - 0x83 => 0x0192, // LATIN SMALL LETTER F WITH HOOK ('ƒ') - 0x84 => 0x201E, // DOUBLE LOW-9 QUOTATION MARK ('„') - 0x85 => 0x2026, // HORIZONTAL ELLIPSIS ('…') - 0x86 => 0x2020, // DAGGER ('†') - 0x87 => 0x2021, // DOUBLE DAGGER ('‡') - 0x88 => 0x02C6, // MODIFIER LETTER CIRCUMFLEX ACCENT ('ˆ') - 0x89 => 0x2030, // PER MILLE SIGN ('‰') - 0x8A => 0x0160, // LATIN CAPITAL LETTER S WITH CARON ('Š') - 0x8B => 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK ('‹') - 0x8C => 0x0152, // LATIN CAPITAL LIGATURE OE ('Œ') - 0x8D => 0xFFFD, // REPLACEMENT CHARACTER - 0x8E => 0x017D, // LATIN CAPITAL LETTER Z WITH CARON ('Ž') - 0x8F => 0xFFFD, // REPLACEMENT CHARACTER - 0x90 => 0xFFFD, // REPLACEMENT CHARACTER - 0x91 => 0x2018, // LEFT SINGLE QUOTATION MARK ('‘') - 0x92 => 0x2019, // RIGHT SINGLE QUOTATION MARK ('’') - 0x93 => 0x201C, // LEFT DOUBLE QUOTATION MARK ('“') - 0x94 => 0x201D, // RIGHT DOUBLE QUOTATION MARK ('”') - 0x95 => 0x2022, // BULLET ('•') - 0x96 => 0x2013, // EN DASH ('–') - 0x97 => 0x2014, // EM DASH ('—') - 0x98 => 0x02DC, // SMALL TILDE ('˜') - 0x99 => 0x2122, // TRADE MARK SIGN ('™') - 0x9A => 0x0161, // LATIN SMALL LETTER S WITH CARON ('š') - 0x9B => 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK ('›') - 0x9C => 0x0153, // LATIN SMALL LIGATURE OE ('œ') - 0x9D => 0xFFFD, // REPLACEMENT CHARACTER - 0x9E => 0x017E, // LATIN SMALL LETTER Z WITH CARON ('ž') - 0x9F => 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS ('Ÿ') - ); - - protected static $namedCharacterReferences; - - protected static $namedCharacterReferenceMaxLength; - - /** - * Returns the "real" Unicode codepoint of a malformed character - * reference. - */ - public static function getRealCodepoint($ref) { - if (!isset(self::$realCodepointTable[$ref])) return false; - else return self::$realCodepointTable[$ref]; - } - - public static function getNamedCharacterReferences() { - if (!self::$namedCharacterReferences) { - self::$namedCharacterReferences = unserialize( - file_get_contents(dirname(__FILE__) . '/named-character-references.ser')); - } - return self::$namedCharacterReferences; - } - - public static function getNamedCharacterReferenceMaxLength() { - if (!self::$namedCharacterReferenceMaxLength) { - $namedCharacterReferences = self::getNamedCharacterReferences(); - $lengths = array_map('strlen', array_keys($namedCharacterReferences)); - self::$namedCharacterReferenceMaxLength = max($lengths); - } - return self::$namedCharacterReferenceMaxLength; - } - - - /** - * Converts a Unicode codepoint to sequence of UTF-8 bytes. - * @note Shamelessly stolen from HTML Purifier, which is also - * shamelessly stolen from Feyd (which is in public domain). - */ - public static function utf8chr($code) { - if($code > 0x10FFFF or $code < 0x0 or - ($code >= 0xD800 and $code <= 0xDFFF) ) { - // bits are set outside the "valid" range as defined - // by UNICODE 4.1.0 - return "\xEF\xBF\xBD"; - } - - $x = $y = $z = $w = 0; - if ($code < 0x80) { - // regular ASCII character - $x = $code; - } else { - // set up bits for UTF-8 - $x = ($code & 0x3F) | 0x80; - if ($code < 0x800) { - $y = (($code & 0x7FF) >> 6) | 0xC0; - } else { - $y = (($code & 0xFC0) >> 6) | 0x80; - if($code < 0x10000) { - $z = (($code >> 12) & 0x0F) | 0xE0; - } else { - $z = (($code >> 12) & 0x3F) | 0x80; - $w = (($code >> 18) & 0x07) | 0xF0; - } - } - } - // set up the actual character - $ret = ''; - if($w) $ret .= chr($w); - if($z) $ret .= chr($z); - if($y) $ret .= chr($y); - $ret .= chr($x); - - return $ret; - } - -} diff --git a/library/HTML5/InputStream.php b/library/HTML5/InputStream.php deleted file mode 100644 index f98b42723..000000000 --- a/library/HTML5/InputStream.php +++ /dev/null @@ -1,284 +0,0 @@ - - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Some conventions: -// /* */ indicates verbatim text from the HTML 5 specification -// // indicates regular comments - -class HTML5_InputStream { - /** - * The string data we're parsing. - */ - private $data; - - /** - * The current integer byte position we are in $data - */ - private $char; - - /** - * Length of $data; when $char === $data, we are at the end-of-file. - */ - private $EOF; - - /** - * Parse errors. - */ - public $errors = array(); - - /** - * @param $data Data to parse - */ - public function __construct($data) { - - /* Given an encoding, the bytes in the input stream must be - converted to Unicode characters for the tokeniser, as - described by the rules for that encoding, except that the - leading U+FEFF BYTE ORDER MARK character, if any, must not - be stripped by the encoding layer (it is stripped by the rule below). - - Bytes or sequences of bytes in the original byte stream that - could not be converted to Unicode characters must be converted - to U+FFFD REPLACEMENT CHARACTER code points. */ - - // XXX currently assuming input data is UTF-8; once we - // build encoding detection this will no longer be the case - // - // We previously had an mbstring implementation here, but that - // implementation is heavily non-conforming, so it's been - // omitted. - if (extension_loaded('iconv')) { - // non-conforming - $data = @iconv('UTF-8', 'UTF-8//IGNORE', $data); - } else { - // we can make a conforming native implementation - throw new Exception('Not implemented, please install mbstring or iconv'); - } - - /* One leading U+FEFF BYTE ORDER MARK character must be - ignored if any are present. */ - if (substr($data, 0, 3) === "\xEF\xBB\xBF") { - $data = substr($data, 3); - } - - /* All U+0000 NULL characters in the input must be replaced - by U+FFFD REPLACEMENT CHARACTERs. Any occurrences of such - characters is a parse error. */ - for ($i = 0, $count = substr_count($data, "\0"); $i < $count; $i++) { - $this->errors[] = array( - 'type' => HTML5_Tokenizer::PARSEERROR, - 'data' => 'null-character' - ); - } - /* U+000D CARRIAGE RETURN (CR) characters and U+000A LINE FEED - (LF) characters are treated specially. Any CR characters - that are followed by LF characters must be removed, and any - CR characters not followed by LF characters must be converted - to LF characters. Thus, newlines in HTML DOMs are represented - by LF characters, and there are never any CR characters in the - input to the tokenization stage. */ - $data = str_replace( - array( - "\0", - "\r\n", - "\r" - ), - array( - "\xEF\xBF\xBD", - "\n", - "\n" - ), - $data - ); - - /* Any occurrences of any characters in the ranges U+0001 to - U+0008, U+000B, U+000E to U+001F, U+007F to U+009F, - U+D800 to U+DFFF , U+FDD0 to U+FDEF, and - characters U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFFE, U+2FFFF, - U+3FFFE, U+3FFFF, U+4FFFE, U+4FFFF, U+5FFFE, U+5FFFF, U+6FFFE, - U+6FFFF, U+7FFFE, U+7FFFF, U+8FFFE, U+8FFFF, U+9FFFE, U+9FFFF, - U+AFFFE, U+AFFFF, U+BFFFE, U+BFFFF, U+CFFFE, U+CFFFF, U+DFFFE, - U+DFFFF, U+EFFFE, U+EFFFF, U+FFFFE, U+FFFFF, U+10FFFE, and - U+10FFFF are parse errors. (These are all control characters - or permanently undefined Unicode characters.) */ - // Check PCRE is loaded. - if (extension_loaded('pcre')) { - $count = preg_match_all( - '/(?: - [\x01-\x08\x0B\x0E-\x1F\x7F] # U+0001 to U+0008, U+000B, U+000E to U+001F and U+007F - | - \xC2[\x80-\x9F] # U+0080 to U+009F - | - \xED(?:\xA0[\x80-\xFF]|[\xA1-\xBE][\x00-\xFF]|\xBF[\x00-\xBF]) # U+D800 to U+DFFFF - | - \xEF\xB7[\x90-\xAF] # U+FDD0 to U+FDEF - | - \xEF\xBF[\xBE\xBF] # U+FFFE and U+FFFF - | - [\xF0-\xF4][\x8F-\xBF]\xBF[\xBE\xBF] # U+nFFFE and U+nFFFF (1 <= n <= 10_{16}) - )/x', - $data, - $matches - ); - for ($i = 0; $i < $count; $i++) { - $this->errors[] = array( - 'type' => HTML5_Tokenizer::PARSEERROR, - 'data' => 'invalid-codepoint' - ); - } - } else { - // XXX: Need non-PCRE impl, probably using substr_count - } - - $this->data = $data; - $this->char = 0; - $this->EOF = strlen($data); - } - - /** - * Returns the current line that the tokenizer is at. - */ - public function getCurrentLine() { - // Check the string isn't empty - if($this->EOF) { - // Add one to $this->char because we want the number for the next - // byte to be processed. - return substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; - } else { - // If the string is empty, we are on the first line (sorta). - return 1; - } - } - - /** - * Returns the current column of the current line that the tokenizer is at. - */ - public function getColumnOffset() { - // strrpos is weird, and the offset needs to be negative for what we - // want (i.e., the last \n before $this->char). This needs to not have - // one (to make it point to the next character, the one we want the - // position of) added to it because strrpos's behaviour includes the - // final offset byte. - $lastLine = strrpos($this->data, "\n", $this->char - 1 - strlen($this->data)); - - // However, for here we want the length up until the next byte to be - // processed, so add one to the current byte ($this->char). - if($lastLine !== false) { - $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); - } else { - $findLengthOf = substr($this->data, 0, $this->char); - } - - // Get the length for the string we need. - if(extension_loaded('iconv')) { - return iconv_strlen($findLengthOf, 'utf-8'); - } elseif(extension_loaded('mbstring')) { - return mb_strlen($findLengthOf, 'utf-8'); - } elseif(extension_loaded('xml')) { - return strlen(utf8_decode($findLengthOf)); - } else { - $count = count_chars($findLengthOf); - // 0x80 = 0x7F - 0 + 1 (one added to get inclusive range) - // 0x33 = 0xF4 - 0x2C + 1 (one added to get inclusive range) - return array_sum(array_slice($count, 0, 0x80)) + - array_sum(array_slice($count, 0xC2, 0x33)); - } - } - - /** - * Retrieve the currently consume character. - * @note This performs bounds checking - */ - public function char() { - return ($this->char++ < $this->EOF) - ? $this->data[$this->char - 1] - : false; - } - - /** - * Get all characters until EOF. - * @note This performs bounds checking - */ - public function remainingChars() { - if($this->char < $this->EOF) { - $data = substr($this->data, $this->char); - $this->char = $this->EOF; - return $data; - } else { - return false; - } - } - - /** - * Matches as far as possible until we reach a certain set of bytes - * and returns the matched substring. - * @param $bytes Bytes to match. - */ - public function charsUntil($bytes, $max = null) { - if ($this->char < $this->EOF) { - if ($max === 0 || $max) { - $len = strcspn($this->data, $bytes, $this->char, $max); - } else { - $len = strcspn($this->data, $bytes, $this->char); - } - $string = (string) substr($this->data, $this->char, $len); - $this->char += $len; - return $string; - } else { - return false; - } - } - - /** - * Matches as far as possible with a certain set of bytes - * and returns the matched substring. - * @param $bytes Bytes to match. - */ - public function charsWhile($bytes, $max = null) { - if ($this->char < $this->EOF) { - if ($max === 0 || $max) { - $len = strspn($this->data, $bytes, $this->char, $max); - } else { - $len = strspn($this->data, $bytes, $this->char); - } - $string = (string) substr($this->data, $this->char, $len); - $this->char += $len; - return $string; - } else { - return false; - } - } - - /** - * Unconsume one character. - */ - public function unget() { - if ($this->char <= $this->EOF) { - $this->char--; - } - } -} diff --git a/library/HTML5/Parser.php b/library/HTML5/Parser.php deleted file mode 100644 index 5f9ca560e..000000000 --- a/library/HTML5/Parser.php +++ /dev/null @@ -1,36 +0,0 @@ -parse(); - return $tokenizer->save(); - } - /** - * Parses an HTML fragment. - * @param $text HTML text to parse - * @param $context String name of context element to pretend parsing is in. - * @param $builder Custom builder implementation - * @return Parsed HTML as DOMDocument - */ - static public function parseFragment($text, $context = null, $builder = null) { - $tokenizer = new HTML5_Tokenizer($text, $builder); - $tokenizer->parseFragment($context); - return $tokenizer->save(); - } -} diff --git a/library/HTML5/Tokenizer.php b/library/HTML5/Tokenizer.php deleted file mode 100644 index 06c73065f..000000000 --- a/library/HTML5/Tokenizer.php +++ /dev/null @@ -1,2307 +0,0 @@ - -Copyright 2008 Edward Z. Yang -Copyright 2009 Geoffrey Sneddon - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Some conventions: -// /* */ indicates verbatim text from the HTML 5 specification -// // indicates regular comments - -// all flags are in hyphenated form - -class HTML5_Tokenizer { - /** - * Points to an InputStream object. - */ - protected $stream; - - /** - * Tree builder that the tokenizer emits token to. - */ - private $tree; - - /** - * Current content model we are parsing as. - */ - protected $content_model; - - /** - * Current token that is being built, but not yet emitted. Also - * is the last token emitted, if applicable. - */ - protected $token; - - // These are constants describing the content model - const PCDATA = 0; - const RCDATA = 1; - const CDATA = 2; - const PLAINTEXT = 3; - - // These are constants describing tokens - // XXX should probably be moved somewhere else, probably the - // HTML5 class. - const DOCTYPE = 0; - const STARTTAG = 1; - const ENDTAG = 2; - const COMMENT = 3; - const CHARACTER = 4; - const SPACECHARACTER = 5; - const EOF = 6; - const PARSEERROR = 7; - - // These are constants representing bunches of characters. - const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; - const UPPER_ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; - const LOWER_ALPHA = 'abcdefghijklmnopqrstuvwxyz'; - const DIGIT = '0123456789'; - const HEX = '0123456789ABCDEFabcdef'; - const WHITESPACE = "\t\n\x0c "; - - /** - * @param $data Data to parse - */ - public function __construct($data, $builder = null) { - $this->stream = new HTML5_InputStream($data); - if (!$builder) $this->tree = new HTML5_TreeBuilder; - $this->content_model = self::PCDATA; - } - - public function parseFragment($context = null) { - $this->tree->setupContext($context); - if ($this->tree->content_model) { - $this->content_model = $this->tree->content_model; - $this->tree->content_model = null; - } - $this->parse(); - } - - // XXX maybe convert this into an iterator? regardless, this function - // and the save function should go into a Parser facade of some sort - /** - * Performs the actual parsing of the document. - */ - public function parse() { - // Current state - $state = 'data'; - // This is used to avoid having to have look-behind in the data state. - $lastFourChars = ''; - /** - * Escape flag as specified by the HTML5 specification: "used to - * control the behavior of the tokeniser. It is either true or - * false, and initially must be set to the false state." - */ - $escape = false; - //echo "\n\n"; - while($state !== null) { - - /*echo $state . ' '; - switch ($this->content_model) { - case self::PCDATA: echo 'PCDATA'; break; - case self::RCDATA: echo 'RCDATA'; break; - case self::CDATA: echo 'CDATA'; break; - case self::PLAINTEXT: echo 'PLAINTEXT'; break; - } - if ($escape) echo " escape"; - echo "\n";*/ - - switch($state) { - case 'data': - - /* Consume the next input character */ - $char = $this->stream->char(); - $lastFourChars .= $char; - if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4); - - // see below for meaning - $hyp_cond = - !$escape && - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ); - $amp_cond = - !$escape && - ( - $this->content_model === self::PCDATA || - $this->content_model === self::RCDATA - ); - $lt_cond = - $this->content_model === self::PCDATA || - ( - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ) && - !$escape - ); - $gt_cond = - $escape && - ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ); - - if($char === '&' && $amp_cond) { - /* U+0026 AMPERSAND (&) - When the content model flag is set to one of the PCDATA or RCDATA - states and the escape flag is false: switch to the - character reference data state. Otherwise: treat it as per - the "anything else" entry below. */ - $state = 'characterReferenceData'; - - } elseif( - $char === '-' && - $hyp_cond && - $lastFourChars === '' - ) { - /* If the content model flag is set to either the RCDATA state or - the CDATA state, and the escape flag is true, and the last three - characters in the input stream including this one are U+002D - HYPHEN-MINUS, U+002D HYPHEN-MINUS, U+003E GREATER-THAN SIGN ("-->"), - set the escape flag to false. */ - $escape = false; - - /* In any case, emit the input character as a character token. - Stay in the data state. */ - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => '>' - )); - // We do the "any case" part as part of "anything else". - - } elseif($char === false) { - /* EOF - Emit an end-of-file token. */ - $state = null; - $this->tree->emitToken(array( - 'type' => self::EOF - )); - - } elseif($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - // Directly after emitting a token you switch back to the "data - // state". At that point spaceCharacters are important so they are - // emitted separately. - $chars = $this->stream->charsWhile(self::WHITESPACE); - $this->emitToken(array( - 'type' => self::SPACECHARACTER, - 'data' => $char . $chars - )); - $lastFourChars .= $chars; - if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4); - - } else { - /* Anything else - THIS IS AN OPTIMIZATION: Get as many character that - otherwise would also be treated as a character token and emit it - as a single character token. Stay in the data state. */ - - $mask = ''; - if ($hyp_cond) $mask .= '-'; - if ($amp_cond) $mask .= '&'; - if ($lt_cond) $mask .= '<'; - if ($gt_cond) $mask .= '>'; - - if ($mask === '') { - $chars = $this->stream->remainingChars(); - } else { - $chars = $this->stream->charsUntil($mask); - } - - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => $char . $chars - )); - - $lastFourChars .= $chars; - if (strlen($lastFourChars) > 4) $lastFourChars = substr($lastFourChars, -4); - - $state = 'data'; - } - break; - - case 'characterReferenceData': - /* (This cannot happen if the content model flag - is set to the CDATA state.) */ - - /* Attempt to consume a character reference, with no - additional allowed character. */ - $entity = $this->consumeCharacterReference(); - - /* If nothing is returned, emit a U+0026 AMPERSAND - character token. Otherwise, emit the character token that - was returned. */ - // This is all done when consuming the character reference. - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => $entity - )); - - /* Finally, switch to the data state. */ - $state = 'data'; - break; - - case 'tagOpen': - $char = $this->stream->char(); - - switch($this->content_model) { - case self::RCDATA: - case self::CDATA: - /* Consume the next input character. If it is a - U+002F SOLIDUS (/) character, switch to the close - tag open state. Otherwise, emit a U+003C LESS-THAN - SIGN character token and reconsume the current input - character in the data state. */ - // We consumed above. - - if($char === '/') { - $state = 'closeTagOpen'; - - } else { - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => '<' - )); - - $this->stream->unget(); - - $state = 'data'; - } - break; - - case self::PCDATA: - /* If the content model flag is set to the PCDATA state - Consume the next input character: */ - // We consumed above. - - if($char === '!') { - /* U+0021 EXCLAMATION MARK (!) - Switch to the markup declaration open state. */ - $state = 'markupDeclarationOpen'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the close tag open state. */ - $state = 'closeTagOpen'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new start tag token, set its tag name to the lowercase - version of the input character (add 0x0020 to the character's code - point), then switch to the tag name state. (Don't emit the token - yet; further details will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $state = 'tagName'; - - } elseif('a' <= $char && $char <= 'z') { - /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z - Create a new start tag token, set its tag name to the input - character, then switch to the tag name state. (Don't emit - the token yet; further details will be filled in before it - is emitted.) */ - $this->token = array( - 'name' => $char, - 'type' => self::STARTTAG, - 'attr' => array() - ); - - $state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit a U+003C LESS-THAN SIGN character token and a - U+003E GREATER-THAN SIGN character token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name-but-got-right-bracket' - )); - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => '<>' - )); - - $state = 'data'; - - } elseif($char === '?') { - /* U+003F QUESTION MARK (?) - Parse error. Switch to the bogus comment state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name-but-got-question-mark' - )); - $this->token = array( - 'data' => '?', - 'type' => self::COMMENT - ); - $state = 'bogusComment'; - - } else { - /* Anything else - Parse error. Emit a U+003C LESS-THAN SIGN character token and - reconsume the current input character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-tag-name' - )); - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => '<' - )); - - $state = 'data'; - $this->stream->unget(); - } - break; - } - break; - - case 'closeTagOpen': - if ( - $this->content_model === self::RCDATA || - $this->content_model === self::CDATA - ) { - /* If the content model flag is set to the RCDATA or CDATA - states... */ - $name = strtolower($this->stream->charsWhile(self::ALPHA)); - $following = $this->stream->char(); - $this->stream->unget(); - if ( - !$this->token || - $this->token['name'] !== $name || - $this->token['name'] === $name && !in_array($following, array("\x09", "\x0A", "\x0C", "\x20", "\x3E", "\x2F", false)) - ) { - /* if no start tag token has ever been emitted by this instance - of the tokenizer (fragment case), or, if the next few - characters do not match the tag name of the last start tag - token emitted (compared in an ASCII case-insensitive manner), - or if they do but they are not immediately followed by one of - the following characters: - - * U+0009 CHARACTER TABULATION - * U+000A LINE FEED (LF) - * U+000C FORM FEED (FF) - * U+0020 SPACE - * U+003E GREATER-THAN SIGN (>) - * U+002F SOLIDUS (/) - * EOF - - ...then emit a U+003C LESS-THAN SIGN character token, a - U+002F SOLIDUS character token, and switch to the data - state to process the next input character. */ - // XXX: Probably ought to replace in_array with $following === x ||... - - // We also need to emit $name now we've consumed that, as we - // know it'll just be emitted as a character token. - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => 'token = array( - 'name' => $name, - 'type' => self::ENDTAG - ); - - // Change to tag name state. - $state = 'tagName'; - } - } elseif ($this->content_model === self::PCDATA) { - /* Otherwise, if the content model flag is set to the PCDATA - state [...]: */ - $char = $this->stream->char(); - - if ('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN LETTER A through to U+005A LATIN LETTER Z - Create a new end tag token, set its tag name to the lowercase version - of the input character (add 0x0020 to the character's code point), then - switch to the tag name state. (Don't emit the token yet; further details - will be filled in before it is emitted.) */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::ENDTAG - ); - - $state = 'tagName'; - - } elseif ('a' <= $char && $char <= 'z') { - /* U+0061 LATIN SMALL LETTER A through to U+007A LATIN SMALL LETTER Z - Create a new end tag token, set its tag name to the - input character, then switch to the tag name state. - (Don't emit the token yet; further details will be - filled in before it is emitted.) */ - $this->token = array( - 'name' => $char, - 'type' => self::ENDTAG - ); - - $state = 'tagName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-right-bracket' - )); - $state = 'data'; - - } elseif($char === false) { - /* EOF - Parse error. Emit a U+003C LESS-THAN SIGN character token and a U+002F - SOLIDUS character token. Reconsume the EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-eof' - )); - $this->emitToken(array( - 'type' => self::CHARACTER, - 'data' => 'stream->unget(); - $state = 'data'; - - } else { - /* Parse error. Switch to the bogus comment state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-closing-tag-but-got-char' - )); - $this->token = array( - 'data' => $char, - 'type' => self::COMMENT - ); - $state = 'bogusComment'; - } - } - break; - - case 'tagName': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'beforeAttributeName'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'selfClosingStartTag'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the current input - character (add 0x0020 to the character's code point) to - the current tag token's tag name. Stay in the tag name state. */ - $chars = $this->stream->charsWhile(self::UPPER_ALPHA); - - $this->token['name'] .= strtolower($char . $chars); - $state = 'tagName'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-tag-name' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current tag token's tag name. - Stay in the tag name state. */ - $chars = $this->stream->charsUntil("\t\n\x0C />" . self::UPPER_ALPHA); - - $this->token['name'] .= $char . $chars; - $state = 'tagName'; - } - break; - - case 'beforeAttributeName': - /* Consume the next input character: */ - $char = $this->stream->char(); - - // this conditional is optimized, check bottom - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute name state. */ - $state = 'beforeAttributeName'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'selfClosingStartTag'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Start a new attribute in the current tag token. Set that - attribute's name to the lowercase version of the current - input character (add 0x0020 to the character's code - point), and its value to the empty string. Switch to the - attribute name state.*/ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => '' - ); - - $state = 'attributeName'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-name-but-got-eof' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003D EQUALS SIGN (=) - Parse error. Treat it as per the "anything else" entry - below. */ - if($char === '"' || $char === "'" || $char === '=') { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-in-attribute-name' - )); - } - - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => $char, - 'value' => '' - ); - - $state = 'attributeName'; - } - break; - - case 'attributeName': - // Consume the next input character: - $char = $this->stream->char(); - - // this conditional is optimized, check bottom - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the after attribute name state. */ - $state = 'afterAttributeName'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'selfClosingStartTag'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the current input - character (add 0x0020 to the character's code point) to - the current attribute's name. Stay in the attribute name - state. */ - $chars = $this->stream->charsWhile(self::UPPER_ALPHA); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= strtolower($char . $chars); - - $state = 'attributeName'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-name' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - Parse error. Treat it as per the "anything else" - entry below. */ - if($char === '"' || $char === "'") { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-in-attribute-name' - )); - } - - /* Anything else - Append the current input character to the current attribute's name. - Stay in the attribute name state. */ - $chars = $this->stream->charsUntil("\t\n\x0C /=>\"'" . self::UPPER_ALPHA); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['name'] .= $char . $chars; - - $state = 'attributeName'; - } - - /* When the user agent leaves the attribute name state - (and before emitting the tag token, if appropriate), the - complete attribute's name must be compared to the other - attributes on the same token; if there is already an - attribute on the token with the exact same name, then this - is a parse error and the new attribute must be dropped, along - with the value that gets associated with it (if any). */ - // this might be implemented in the emitToken method - break; - - case 'afterAttributeName': - // Consume the next input character: - $char = $this->stream->char(); - - // this is an optimized conditional, check the bottom - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after attribute name state. */ - $state = 'afterAttributeName'; - - } elseif($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'selfClosingStartTag'; - - } elseif($char === '=') { - /* U+003D EQUALS SIGN (=) - Switch to the before attribute value state. */ - $state = 'beforeAttributeValue'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Start a new attribute in the current tag token. Set that - attribute's name to the lowercase version of the current - input character (add 0x0020 to the character's code - point), and its value to the empty string. Switch to the - attribute name state. */ - $this->token['attr'][] = array( - 'name' => strtolower($char), - 'value' => '' - ); - - $state = 'attributeName'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-end-of-tag-but-got-eof' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - Parse error. Treat it as per the "anything else" - entry below. */ - if($char === '"' || $char === "'") { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'invalid-character-after-attribute-name' - )); - } - - /* Anything else - Start a new attribute in the current tag token. Set that attribute's - name to the current input character, and its value to the empty string. - Switch to the attribute name state. */ - $this->token['attr'][] = array( - 'name' => $char, - 'value' => '' - ); - - $state = 'attributeName'; - } - break; - - case 'beforeAttributeValue': - // Consume the next input character: - $char = $this->stream->char(); - - // this is an optimized conditional - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before attribute value state. */ - $state = 'beforeAttributeValue'; - - } elseif($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the attribute value (double-quoted) state. */ - $state = 'attributeValueDoubleQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the attribute value (unquoted) state and reconsume - this input character. */ - $this->stream->unget(); - $state = 'attributeValueUnquoted'; - - } elseif($char === '\'') { - /* U+0027 APOSTROPHE (') - Switch to the attribute value (single-quoted) state. */ - $state = 'attributeValueSingleQuoted'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the current tag token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-value-but-got-right-bracket' - )); - $this->emitToken($this->token); - $state = 'data'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume - the character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-attribute-value-but-got-eof' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+003D EQUALS SIGN (=) - Parse error. Treat it as per the "anything else" entry below. */ - if($char === '=') { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'equals-in-unquoted-attribute-value' - )); - } - - /* Anything else - Append the current input character to the current attribute's value. - Switch to the attribute value (unquoted) state. */ - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - $state = 'attributeValueUnquoted'; - } - break; - - case 'attributeValueDoubleQuoted': - // Consume the next input character: - $char = $this->stream->char(); - - if($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after attribute value (quoted) state. */ - $state = 'afterAttributeValueQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the character reference in attribute value - state, with the additional allowed character - being U+0022 QUOTATION MARK ("). */ - $this->characterReferenceInAttributeValue('"'); - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-double-quote' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (double-quoted) state. */ - $chars = $this->stream->charsUntil('"&'); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attributeValueDoubleQuoted'; - } - break; - - case 'attributeValueSingleQuoted': - // Consume the next input character: - $char = $this->stream->char(); - - if($char === "'") { - /* U+0022 QUOTATION MARK (') - Switch to the after attribute value state. */ - $state = 'afterAttributeValueQuoted'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->characterReferenceInAttributeValue("'"); - - } elseif($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the character - in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-single-quote' - )); - $this->emitToken($this->token); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (single-quoted) state. */ - $chars = $this->stream->charsUntil("'&"); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attributeValueSingleQuoted'; - } - break; - - case 'attributeValueUnquoted': - // Consume the next input character: - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'beforeAttributeName'; - - } elseif($char === '&') { - /* U+0026 AMPERSAND (&) - Switch to the entity in attribute value state. */ - $this->characterReferenceInAttributeValue(); - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume - the character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-attribute-value-no-quotes' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* U+0022 QUOTATION MARK (") - U+0027 APOSTROPHE (') - U+003D EQUALS SIGN (=) - Parse error. Treat it as per the "anything else" - entry below. */ - if($char === '"' || $char === "'" || $char === '=') { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-in-unquoted-attribute-value' - )); - } - - /* Anything else - Append the current input character to the current attribute's value. - Stay in the attribute value (unquoted) state. */ - $chars = $this->stream->charsUntil("\t\n\x0c &>\"'="); - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char . $chars; - - $state = 'attributeValueUnquoted'; - } - break; - - case 'afterAttributeValueQuoted': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before attribute name state. */ - $state = 'beforeAttributeName'; - - } elseif ($char === '/') { - /* U+002F SOLIDUS (/) - Switch to the self-closing start tag state. */ - $state = 'selfClosingStartTag'; - - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current tag token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-EOF-after-attribute-value' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Reconsume the character in the before attribute - name state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-after-attribute-value' - )); - $this->stream->unget(); - $state = 'beforeAttributeName'; - } - break; - - case 'selfClosingStartTag': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Set the self-closing flag of the current tag token. - Emit the current tag token. Switch to the data state. */ - // not sure if this is the name we want - $this->token['self-closing'] = true; - /* When an end tag token is emitted with its self-closing flag set, - that is a parse error. */ - if ($this->token['type'] === self::ENDTAG) { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'self-closing-end-tag' - )); - } - $this->emitToken($this->token); - $state = 'data'; - - } elseif ($char === false) { - /* EOF - Parse error. Emit the current tag token. Reconsume the - EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-eof-after-self-closing' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Reconsume the character in the before attribute name state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-character-after-self-closing' - )); - $this->stream->unget(); - $state = 'beforeAttributeName'; - } - break; - - case 'bogusComment': - /* (This can only happen if the content model flag is set to the PCDATA state.) */ - /* Consume every character up to the first U+003E GREATER-THAN SIGN - character (>) or the end of the file (EOF), whichever comes first. Emit - a comment token whose data is the concatenation of all the characters - starting from and including the character that caused the state machine - to switch into the bogus comment state, up to and including the last - consumed character before the U+003E character, if any, or up to the - end of the file otherwise. (If the comment was started by the end of - the file (EOF), the token is empty.) */ - $this->token['data'] .= (string) $this->stream->charsUntil('>'); - $this->stream->char(); - - $this->emitToken($this->token); - - /* Switch to the data state. */ - $state = 'data'; - break; - - case 'markupDeclarationOpen': - // Consume for below - $hyphens = $this->stream->charsWhile('-', 2); - if ($hyphens === '-') { - $this->stream->unget(); - } - if ($hyphens !== '--') { - $alpha = $this->stream->charsWhile(self::ALPHA, 7); - } - - /* If the next two characters are both U+002D HYPHEN-MINUS (-) - characters, consume those two characters, create a comment token whose - data is the empty string, and switch to the comment state. */ - if($hyphens === '--') { - $state = 'commentStart'; - $this->token = array( - 'data' => '', - 'type' => self::COMMENT - ); - - /* Otherwise if the next seven characters are a case-insensitive match - for the word "DOCTYPE", then consume those characters and switch to the - DOCTYPE state. */ - } elseif(strtoupper($alpha) === 'DOCTYPE') { - $state = 'doctype'; - - // XXX not implemented - /* Otherwise, if the insertion mode is "in foreign content" - and the current node is not an element in the HTML namespace - and the next seven characters are an ASCII case-sensitive - match for the string "[CDATA[" (the five uppercase letters - "CDATA" with a U+005B LEFT SQUARE BRACKET character before - and after), then consume those characters and switch to the - CDATA section state (which is unrelated to the content model - flag's CDATA state). */ - - /* Otherwise, is is a parse error. Switch to the bogus comment state. - The next character that is consumed, if any, is the first character - that will be in the comment. */ - } else { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-dashes-or-doctype' - )); - $this->token = array( - 'data' => (string) $alpha, - 'type' => self::COMMENT - ); - $state = 'bogusComment'; - } - break; - - case 'commentStart': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment start dash state. */ - $state = 'commentStartDash'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the comment token. Switch to the - data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'incorrect-comment' - )); - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the input character to the comment token's - data. Switch to the comment state. */ - $this->token['data'] .= $char; - $state = 'comment'; - } - break; - - case 'commentStartDash': - /* Consume the next input character: */ - $char = $this->stream->char(); - if ($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end state */ - $state = 'commentEnd'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Emit the comment token. Switch to the - data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'incorrect-comment' - )); - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - $this->token['data'] .= '-' . $char; - $state = 'comment'; - } - break; - - case 'comment': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end dash state */ - $state = 'commentEndDash'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the input character to the comment token's data. Stay in - the comment state. */ - $chars = $this->stream->charsUntil('-'); - - $this->token['data'] .= $char . $chars; - } - break; - - case 'commentEndDash': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Switch to the comment end state */ - $state = 'commentEnd'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the EOF character - in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment-end-dash' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append a U+002D HYPHEN-MINUS (-) character and the input - character to the comment token's data. Switch to the comment state. */ - $this->token['data'] .= '-'.$char; - $state = 'comment'; - } - break; - - case 'commentEnd': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the comment token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif($char === '-') { - /* U+002D HYPHEN-MINUS (-) - Parse error. Append a U+002D HYPHEN-MINUS (-) character - to the comment token's data. Stay in the comment end - state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-dash-after-double-dash-in-comment' - )); - $this->token['data'] .= '-'; - - } elseif($char === false) { - /* EOF - Parse error. Emit the comment token. Reconsume the - EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-comment-double-dash' - )); - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Parse error. Append two U+002D HYPHEN-MINUS (-) - characters and the input character to the comment token's - data. Switch to the comment state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-comment' - )); - $this->token['data'] .= '--'.$char; - $state = 'comment'; - } - break; - - case 'doctype': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the before DOCTYPE name state. */ - $state = 'beforeDoctypeName'; - - } else { - /* Anything else - Parse error. Reconsume the current character in the - before DOCTYPE name state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'need-space-after-doctype' - )); - $this->stream->unget(); - $state = 'beforeDoctypeName'; - } - break; - - case 'beforeDoctypeName': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE name state. */ - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Create a new DOCTYPE token. Set its - force-quirks flag to on. Emit the token. Switch to the - data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-doctype-name-but-got-right-bracket' - )); - $this->emitToken(array( - 'name' => '', - 'type' => self::DOCTYPE, - 'force-quirks' => true, - 'error' => true - )); - - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Create a new DOCTYPE token. Set the token's name to the - lowercase version of the input character (add 0x0020 to - the character's code point). Switch to the DOCTYPE name - state. */ - $this->token = array( - 'name' => strtolower($char), - 'type' => self::DOCTYPE, - 'error' => true - ); - - $state = 'doctypeName'; - - } elseif($char === false) { - /* EOF - Parse error. Create a new DOCTYPE token. Set its - force-quirks flag to on. Emit the token. Reconsume the - EOF character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-doctype-name-but-got-eof' - )); - $this->emitToken(array( - 'name' => '', - 'type' => self::DOCTYPE, - 'force-quirks' => true, - 'error' => true - )); - - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Create a new DOCTYPE token. Set the token's name to the - current input character. Switch to the DOCTYPE name state. */ - $this->token = array( - 'name' => $char, - 'type' => self::DOCTYPE, - 'error' => true - ); - - $state = 'doctypeName'; - } - break; - - case 'doctypeName': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Switch to the after DOCTYPE name state. */ - $state = 'afterDoctypeName'; - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif('A' <= $char && $char <= 'Z') { - /* U+0041 LATIN CAPITAL LETTER A through to U+005A LATIN CAPITAL LETTER Z - Append the lowercase version of the input character - (add 0x0020 to the character's code point) to the current - DOCTYPE token's name. Stay in the DOCTYPE name state. */ - $this->token['name'] .= strtolower($char); - - } elseif($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype-name' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's name. Stay in the DOCTYPE name state. */ - $this->token['name'] .= $char; - } - - // XXX this is probably some sort of quirks mode designation, - // check tree-builder to be sure. In general 'error' needs - // to be specc'ified, this probably means removing it at the end - $this->token['error'] = ($this->token['name'] === 'HTML') - ? false - : true; - break; - - case 'afterDoctypeName': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE name state. */ - - } elseif($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else */ - - $nextSix = strtoupper($char . $this->stream->charsWhile(self::ALPHA, 5)); - if ($nextSix === 'PUBLIC') { - /* If the next six characters are an ASCII - case-insensitive match for the word "PUBLIC", then - consume those characters and switch to the before - DOCTYPE public identifier state. */ - $state = 'beforeDoctypePublicIdentifier'; - - } elseif ($nextSix === 'SYSTEM') { - /* Otherwise, if the next six characters are an ASCII - case-insensitive match for the word "SYSTEM", then - consume those characters and switch to the before - DOCTYPE system identifier state. */ - $state = 'beforeDoctypeSystemIdentifier'; - - } else { - /* Otherwise, this is the parse error. Set the DOCTYPE - token's force-quirks flag to on. Switch to the bogus - DOCTYPE state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-space-or-right-bracket-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->token['error'] = true; - $state = 'bogusDoctype'; - } - } - break; - - case 'beforeDoctypePublicIdentifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE public identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's public identifier to the empty - string (not missing), then switch to the DOCTYPE public - identifier (double-quoted) state. */ - $this->token['public'] = ''; - $state = 'doctypePublicIdentifierDoubleQuoted'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's public identifier to the empty - string (not missing), then switch to the DOCTYPE public - identifier (single-quoted) state. */ - $this->token['public'] = ''; - $state = 'doctypePublicIdentifierSingleQuoted'; - } elseif ($char === '>') { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - )); - $this->token['force-quirks'] = true; - $state = 'bogusDoctype'; - } - break; - - case 'doctypePublicIdentifierDoubleQuoted': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after DOCTYPE public identifier state. */ - $state = 'afterDoctypePublicIdentifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's public identifier. Stay in the DOCTYPE - public identifier (double-quoted) state. */ - $this->token['public'] .= $char; - } - break; - - case 'doctypePublicIdentifierSingleQuoted': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "'") { - /* U+0027 APOSTROPHE (') - Switch to the after DOCTYPE public identifier state. */ - $state = 'afterDoctypePublicIdentifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's public identifier. Stay in the DOCTYPE - public identifier (double-quoted) state. */ - $this->token['public'] .= $char; - } - break; - - case 'afterDoctypePublicIdentifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE public identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's system identifier to the - empty string (not missing), then switch to the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] = ''; - $state = 'doctypeSystemIdentifierDoubleQuoted'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's system identifier to the - empty string (not missing), then switch to the DOCTYPE - system identifier (single-quoted) state. */ - $this->token['system'] = ''; - $state = 'doctypeSystemIdentifierSingleQuoted'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - )); - $this->token['force-quirks'] = true; - $state = 'bogusDoctype'; - } - break; - - case 'beforeDoctypeSystemIdentifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the before DOCTYPE system identifier state. */ - } elseif ($char === '"') { - /* U+0022 QUOTATION MARK (") - Set the DOCTYPE token's system identifier to the empty - string (not missing), then switch to the DOCTYPE system - identifier (double-quoted) state. */ - $this->token['system'] = ''; - $state = 'doctypeSystemIdentifierDoubleQuoted'; - } elseif ($char === "'") { - /* U+0027 APOSTROPHE (') - Set the DOCTYPE token's system identifier to the empty - string (not missing), then switch to the DOCTYPE system - identifier (single-quoted) state. */ - $this->token['system'] = ''; - $state = 'doctypeSystemIdentifierSingleQuoted'; - } elseif ($char === '>') { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Parse error. Set the DOCTYPE token's force-quirks flag - to on. Switch to the bogus DOCTYPE state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - )); - $this->token['force-quirks'] = true; - $state = 'bogusDoctype'; - } - break; - - case 'doctypeSystemIdentifierDoubleQuoted': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '"') { - /* U+0022 QUOTATION MARK (") - Switch to the after DOCTYPE system identifier state. */ - $state = 'afterDoctypeSystemIdentifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's system identifier. Stay in the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] .= $char; - } - break; - - case 'doctypeSystemIdentifierSingleQuoted': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === "'") { - /* U+0027 APOSTROPHE (') - Switch to the after DOCTYPE system identifier state. */ - $state = 'afterDoctypeSystemIdentifier'; - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Switch to the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-end-of-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* EOF - Parse error. Set the DOCTYPE token's force-quirks flag - to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Append the current input character to the current - DOCTYPE token's system identifier. Stay in the DOCTYPE - system identifier (double-quoted) state. */ - $this->token['system'] .= $char; - } - break; - - case 'afterDoctypeSystemIdentifier': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if($char === "\t" || $char === "\n" || $char === "\x0c" || $char === ' ') { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - Stay in the after DOCTYPE system identifier state. */ - } elseif ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the current DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - } elseif ($char === false) { - /* Parse error. Set the DOCTYPE token's force-quirks - flag to on. Emit that DOCTYPE token. Reconsume the EOF - character in the data state. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'eof-in-doctype' - )); - $this->token['force-quirks'] = true; - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - } else { - /* Anything else - Parse error. Switch to the bogus DOCTYPE state. - (This does not set the DOCTYPE token's force-quirks - flag to on.) */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'unexpected-char-in-doctype' - )); - $state = 'bogusDoctype'; - } - break; - - case 'bogusDoctype': - /* Consume the next input character: */ - $char = $this->stream->char(); - - if ($char === '>') { - /* U+003E GREATER-THAN SIGN (>) - Emit the DOCTYPE token. Switch to the data state. */ - $this->emitToken($this->token); - $state = 'data'; - - } elseif($char === false) { - /* EOF - Emit the DOCTYPE token. Reconsume the EOF character in - the data state. */ - $this->emitToken($this->token); - $this->stream->unget(); - $state = 'data'; - - } else { - /* Anything else - Stay in the bogus DOCTYPE state. */ - } - break; - - // case 'cdataSection': - - } - } - } - - /** - * Returns a serialized representation of the tree. - */ - public function save() { - return $this->tree->save(); - } - - /** - * Returns the input stream. - */ - public function stream() { - return $this->stream; - } - - private function consumeCharacterReference($allowed = false, $inattr = false) { - // This goes quite far against spec, and is far closer to the Python - // impl., mainly because we don't do the large unconsuming the spec - // requires. - - // All consumed characters. - $chars = $this->stream->char(); - - /* This section defines how to consume a character - reference. This definition is used when parsing character - references in text and in attributes. - - The behavior depends on the identity of the next character - (the one immediately after the U+0026 AMPERSAND character): */ - - if ( - $chars[0] === "\x09" || - $chars[0] === "\x0A" || - $chars[0] === "\x0C" || - $chars[0] === "\x20" || - $chars[0] === '<' || - $chars[0] === '&' || - $chars === false || - $chars[0] === $allowed - ) { - /* U+0009 CHARACTER TABULATION - U+000A LINE FEED (LF) - U+000C FORM FEED (FF) - U+0020 SPACE - U+003C LESS-THAN SIGN - U+0026 AMPERSAND - EOF - The additional allowed character, if there is one - Not a character reference. No characters are consumed, - and nothing is returned. (This is not an error, either.) */ - // We already consumed, so unconsume. - $this->stream->unget(); - return '&'; - } elseif ($chars[0] === '#') { - /* Consume the U+0023 NUMBER SIGN. */ - // Um, yeah, we already did that. - /* The behavior further depends on the character after - the U+0023 NUMBER SIGN: */ - $chars .= $this->stream->char(); - if (isset($chars[1]) && ($chars[1] === 'x' || $chars[1] === 'X')) { - /* U+0078 LATIN SMALL LETTER X - U+0058 LATIN CAPITAL LETTER X */ - /* Consume the X. */ - // Um, yeah, we already did that. - /* Follow the steps below, but using the range of - characters U+0030 DIGIT ZERO through to U+0039 DIGIT - NINE, U+0061 LATIN SMALL LETTER A through to U+0066 - LATIN SMALL LETTER F, and U+0041 LATIN CAPITAL LETTER - A, through to U+0046 LATIN CAPITAL LETTER F (in other - words, 0123456789, ABCDEF, abcdef). */ - $char_class = self::HEX; - /* When it comes to interpreting the - number, interpret it as a hexadecimal number. */ - $hex = true; - } else { - /* Anything else */ - // Unconsume because we shouldn't have consumed this. - $chars = $chars[0]; - $this->stream->unget(); - /* Follow the steps below, but using the range of - characters U+0030 DIGIT ZERO through to U+0039 DIGIT - NINE (i.e. just 0123456789). */ - $char_class = self::DIGIT; - /* When it comes to interpreting the number, - interpret it as a decimal number. */ - $hex = false; - } - - /* Consume as many characters as match the range of characters given above. */ - $consumed = $this->stream->charsWhile($char_class); - if ($consumed === '' || $consumed === false) { - /* If no characters match the range, then don't consume - any characters (and unconsume the U+0023 NUMBER SIGN - character and, if appropriate, the X character). This - is a parse error; nothing is returned. */ - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-numeric-entity' - )); - return '&' . $chars; - } else { - /* Otherwise, if the next character is a U+003B SEMICOLON, - consume that too. If it isn't, there is a parse error. */ - if ($this->stream->char() !== ';') { - $this->stream->unget(); - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'numeric-entity-without-semicolon' - )); - } - - /* If one or more characters match the range, then take - them all and interpret the string of characters as a number - (either hexadecimal or decimal as appropriate). */ - $codepoint = $hex ? hexdec($consumed) : (int) $consumed; - - /* If that number is one of the numbers in the first column - of the following table, then this is a parse error. Find the - row with that number in the first column, and return a - character token for the Unicode character given in the - second column of that row. */ - $new_codepoint = HTML5_Data::getRealCodepoint($codepoint); - if ($new_codepoint) { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'illegal-windows-1252-entity' - )); - $codepoint = $new_codepoint; - } else { - /* Otherwise, if the number is in the range 0x0000 to 0x0008, - U+000B, U+000E to 0x001F, 0x007F to 0x009F, 0xD800 to 0xDFFF , - 0xFDD0 to 0xFDEF, or is one of 0xFFFE, 0xFFFF, 0x1FFFE, 0x1FFFF, - 0x2FFFE, 0x2FFFF, 0x3FFFE, 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, - 0x5FFFF, 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE, 0x8FFFF, - 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF, 0xBFFFE, 0xBFFFF, 0xCFFFE, - 0xCFFFF, 0xDFFFE, 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF, - 0x10FFFE, or 0x10FFFF, or is higher than 0x10FFFF, then this - is a parse error; return a character token for the U+FFFD - REPLACEMENT CHARACTER character instead. */ - // && has higher precedence than || - if ( - $codepoint >= 0x0000 && $codepoint <= 0x0008 || - $codepoint === 0x000B || - $codepoint >= 0x000E && $codepoint <= 0x001F || - $codepoint >= 0x007F && $codepoint <= 0x009F || - $codepoint >= 0xD800 && $codepoint <= 0xDFFF || - $codepoint >= 0xFDD0 && $codepoint <= 0xFDEF || - ($codepoint & 0xFFFE) === 0xFFFE || - $codepoint > 0x10FFFF - ) { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'illegal-codepoint-for-numeric-entity' - )); - $codepoint = 0xFFFD; - } - } - - /* Otherwise, return a character token for the Unicode - character whose code point is that number. */ - return HTML5_Data::utf8chr($codepoint); - } - - } else { - /* Anything else */ - - /* Consume the maximum number of characters possible, - with the consumed characters matching one of the - identifiers in the first column of the named character - references table (in a case-sensitive manner). */ - - // we will implement this by matching the longest - // alphanumeric + semicolon string, and then working - // our way backwards - $chars .= $this->stream->charsWhile(self::DIGIT . self::ALPHA . ';', HTML5_Data::getNamedCharacterReferenceMaxLength() - 1); - $len = strlen($chars); - - $refs = HTML5_Data::getNamedCharacterReferences(); - $codepoint = false; - for($c = $len; $c > 0; $c--) { - $id = substr($chars, 0, $c); - if(isset($refs[$id])) { - $codepoint = $refs[$id]; - break; - } - } - - /* If no match can be made, then this is a parse error. - No characters are consumed, and nothing is returned. */ - if (!$codepoint) { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'expected-named-entity' - )); - return '&' . $chars; - } - - /* If the last character matched is not a U+003B SEMICOLON - (;), there is a parse error. */ - $semicolon = true; - if (substr($id, -1) !== ';') { - $this->emitToken(array( - 'type' => self::PARSEERROR, - 'data' => 'named-entity-without-semicolon' - )); - $semicolon = false; - } - - - /* If the character reference is being consumed as part of - an attribute, and the last character matched is not a - U+003B SEMICOLON (;), and the next character is in the - range U+0030 DIGIT ZERO to U+0039 DIGIT NINE, U+0041 - LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z, - or U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z, - then, for historical reasons, all the characters that were - matched after the U+0026 AMPERSAND (&) must be unconsumed, - and nothing is returned. */ - if ( - $inattr && !$semicolon && - strspn(substr($chars, $c, 1), self::ALPHA . self::DIGIT) - ) { - return '&' . $chars; - } - - /* Otherwise, return a character token for the character - corresponding to the character reference name (as given - by the second column of the named character references table). */ - return HTML5_Data::utf8chr($codepoint) . substr($chars, $c); - } - } - - private function characterReferenceInAttributeValue($allowed = false) { - /* Attempt to consume a character reference. */ - $entity = $this->consumeCharacterReference($allowed, true); - - /* If nothing is returned, append a U+0026 AMPERSAND - character to the current attribute's value. - - Otherwise, append the returned character token to the - current attribute's value. */ - $char = (!$entity) - ? '&' - : $entity; - - $last = count($this->token['attr']) - 1; - $this->token['attr'][$last]['value'] .= $char; - - /* Finally, switch back to the attribute value state that you - were in when were switched into this state. */ - } - - /** - * Emits a token, passing it on to the tree builder. - */ - protected function emitToken($token, $checkStream = true) { - if ($checkStream) { - // Emit errors from input stream. - while ($this->stream->errors) { - $this->emitToken(array_shift($this->stream->errors), false); - } - } - - // the current structure of attributes is not a terribly good one - $this->tree->emitToken($token); - - if(is_int($this->tree->content_model)) { - $this->content_model = $this->tree->content_model; - $this->tree->content_model = null; - - } elseif($token['type'] === self::ENDTAG) { - $this->content_model = self::PCDATA; - } - } -} - diff --git a/library/HTML5/TreeBuilder.php b/library/HTML5/TreeBuilder.php deleted file mode 100644 index 578e73682..000000000 --- a/library/HTML5/TreeBuilder.php +++ /dev/null @@ -1,3721 +0,0 @@ - -Copyright 2009 Edward Z. Yang - -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*/ - -// Tags for FIX ME!!!: (in order of priority) -// XXX - should be fixed NAO! -// XERROR - with regards to parse errors -// XSCRIPT - with regards to scripting mode -// XENCODING - with regards to encoding (for reparsing tests) - -class HTML5_TreeBuilder { - public $stack = array(); - public $content_model; - - private $mode; - private $original_mode; - private $secondary_mode; - private $dom; - // Whether or not normal insertion of nodes should actually foster - // parent (used in one case in spec) - private $foster_parent = false; - private $a_formatting = array(); - - private $head_pointer = null; - private $form_pointer = null; - - private $flag_frameset_ok = true; - private $flag_force_quirks = false; - private $ignored = false; - private $quirks_mode = null; - // this gets to 2 when we want to ignore the next lf character, and - // is decrement at the beginning of each processed token (this way, - // code can check for (bool)$ignore_lf_token, but it phases out - // appropriately) - private $ignore_lf_token = 0; - private $fragment = false; - private $root; - - private $scoping = array('applet','button','caption','html','marquee','object','table','td','th', 'svg:foreignObject'); - private $formatting = array('a','b','big','code','em','font','i','nobr','s','small','strike','strong','tt','u'); - private $special = array('address','area','article','aside','base','basefont','bgsound', - 'blockquote','body','br','center','col','colgroup','command','dd','details','dialog','dir','div','dl', - 'dt','embed','fieldset','figure','footer','form','frame','frameset','h1','h2','h3','h4','h5', - 'h6','head','header','hgroup','hr','iframe','img','input','isindex','li','link', - 'listing','menu','meta','nav','noembed','noframes','noscript','ol', - 'p','param','plaintext','pre','script','select','spacer','style', - 'tbody','textarea','tfoot','thead','title','tr','ul','wbr'); - - // Tree construction modes - const INITIAL = 0; - const BEFORE_HTML = 1; - const BEFORE_HEAD = 2; - const IN_HEAD = 3; - const IN_HEAD_NOSCRIPT = 4; - const AFTER_HEAD = 5; - const IN_BODY = 6; - const IN_CDATA_RCDATA = 7; - const IN_TABLE = 8; - const IN_CAPTION = 9; - const IN_COLUMN_GROUP = 10; - const IN_TABLE_BODY = 11; - const IN_ROW = 12; - const IN_CELL = 13; - const IN_SELECT = 14; - const IN_SELECT_IN_TABLE= 15; - const IN_FOREIGN_CONTENT= 16; - const AFTER_BODY = 17; - const IN_FRAMESET = 18; - const AFTER_FRAMESET = 19; - const AFTER_AFTER_BODY = 20; - const AFTER_AFTER_FRAMESET = 21; - - /** - * Converts a magic number to a readable name. Use for debugging. - */ - private function strConst($number) { - static $lookup; - if (!$lookup) { - $r = new ReflectionClass('HTML5_TreeBuilder'); - $lookup = array_flip($r->getConstants()); - } - return $lookup[$number]; - } - - // The different types of elements. - const SPECIAL = 100; - const SCOPING = 101; - const FORMATTING = 102; - const PHRASING = 103; - - // Quirks modes in $quirks_mode - const NO_QUIRKS = 200; - const QUIRKS_MODE = 201; - const LIMITED_QUIRKS_MODE = 202; - - // Marker to be placed in $a_formatting - const MARKER = 300; - - // Namespaces for foreign content - const NS_HTML = null; // to prevent DOM from requiring NS on everything - const NS_MATHML = 'http://www.w3.org/1998/Math/MathML'; - const NS_SVG = 'http://www.w3.org/2000/svg'; - const NS_XLINK = 'http://www.w3.org/1999/xlink'; - const NS_XML = 'http://www.w3.org/XML/1998/namespace'; - const NS_XMLNS = 'http://www.w3.org/2000/xmlns/'; - - public function __construct() { - $this->mode = self::INITIAL; - $this->dom = new DOMDocument; - - $this->dom->encoding = 'UTF-8'; - $this->dom->preserveWhiteSpace = true; - $this->dom->substituteEntities = true; - $this->dom->strictErrorChecking = false; - } - - // Process tag tokens - public function emitToken($token, $mode = null) { - // XXX: ignore parse errors... why are we emitting them, again? - if ($token['type'] === HTML5_Tokenizer::PARSEERROR) return; - if ($mode === null) $mode = $this->mode; - - /* - $backtrace = debug_backtrace(); - if ($backtrace[1]['class'] !== 'HTML5_TreeBuilder') echo "--\n"; - echo $this->strConst($mode); - if ($this->original_mode) echo " (originally ".$this->strConst($this->original_mode).")"; - echo "\n "; - token_dump($token); - $this->printStack(); - $this->printActiveFormattingElements(); - if ($this->foster_parent) echo " -> this is a foster parent mode\n"; - */ - - if ($this->ignore_lf_token) $this->ignore_lf_token--; - $this->ignored = false; - // indenting is a little wonky, this can be changed later on - switch ($mode) { - - case self::INITIAL: - - /* A character token that is one of U+0009 CHARACTER TABULATION, - * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020 SPACE */ - if ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - if ( - $token['name'] !== 'html' || !empty($token['public']) || - !empty($token['system']) || $token !== 'about:legacy-compat' - ) { - /* If the DOCTYPE token's name is not a case-sensitive match - * for the string "html", or if the token's public identifier - * is not missing, or if the token's system identifier is - * neither missing nor a case-sensitive match for the string - * "about:legacy-compat", then there is a parse error (this - * is the DOCTYPE parse error). */ - // DOCTYPE parse error - } - /* Append a DocumentType node to the Document node, with the name - * attribute set to the name given in the DOCTYPE token, or the - * empty string if the name was missing; the publicId attribute - * set to the public identifier given in the DOCTYPE token, or - * the empty string if the public identifier was missing; the - * systemId attribute set to the system identifier given in the - * DOCTYPE token, or the empty string if the system identifier - * was missing; and the other attributes specific to - * DocumentType objects set to null and empty lists as - * appropriate. Associate the DocumentType node with the - * Document object so that it is returned as the value of the - * doctype attribute of the Document object. */ - if (!isset($token['public'])) $token['public'] = null; - if (!isset($token['system'])) $token['system'] = null; - // Yes this is hacky. I'm kind of annoyed that I can't appendChild - // a doctype to DOMDocument. Maybe I haven't chanted the right - // syllables. - $impl = new DOMImplementation(); - // This call can fail for particularly pathological cases (namely, - // the qualifiedName parameter ($token['name']) could be missing. - if ($token['name']) { - $doctype = $impl->createDocumentType($token['name'], $token['public'], $token['system']); - $this->dom->appendChild($doctype); - } else { - // It looks like libxml's not actually *able* to express this case. - // So... don't. - $this->dom->emptyDoctype = true; - } - $public = is_null($token['public']) ? false : strtolower($token['public']); - $system = is_null($token['system']) ? false : strtolower($token['system']); - $publicStartsWithForQuirks = array( - "+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//", - ); - $publicSetToForQuirks = array( - "-//w3o//dtd w3 html strict 3.0//", - "-/w3c/dtd html 4.0 transitional/en", - "html", - ); - $publicStartsWithAndSystemForQuirks = array( - "-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//", - ); - $publicStartsWithForLimitedQuirks = array( - "-//w3c//dtd xhtml 1.0 frameset//", - "-//w3c//dtd xhtml 1.0 transitional//", - ); - $publicStartsWithAndSystemForLimitedQuirks = array( - "-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//", - ); - // first, do easy checks - if ( - !empty($token['force-quirks']) || - strtolower($token['name']) !== 'html' - ) { - $this->quirks_mode = self::QUIRKS_MODE; - } else { - do { - if ($system) { - foreach ($publicStartsWithAndSystemForQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) break; - foreach ($publicStartsWithAndSystemForLimitedQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::LIMITED_QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) break; - } - foreach ($publicSetToForQuirks as $x) { - if ($public === $x) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (!is_null($this->quirks_mode)) break; - foreach ($publicStartsWithForLimitedQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::LIMITED_QUIRKS_MODE; - } - } - if (!is_null($this->quirks_mode)) break; - if ($system === "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - foreach ($publicStartsWithForQuirks as $x) { - if (strncmp($public, $x, strlen($x)) === 0) { - $this->quirks_mode = self::QUIRKS_MODE; - break; - } - } - if (is_null($this->quirks_mode)) { - $this->quirks_mode = self::NO_QUIRKS; - } - } while (false); - } - $this->mode = self::BEFORE_HTML; - } else { - // parse error - /* Switch the insertion mode to "before html", then reprocess the - * current token. */ - $this->mode = self::BEFORE_HTML; - $this->quirks_mode = self::QUIRKS_MODE; - $this->emitToken($token); - } - break; - - case self::BEFORE_HTML: - - /* A DOCTYPE token */ - if($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // Parse error. Ignore the token. - $this->ignored = true; - - /* A comment token */ - } elseif($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the Document object with the data - attribute set to the data given in the comment token. */ - $comment = $this->dom->createComment($token['data']); - $this->dom->appendChild($comment); - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - } elseif($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - - /* A start tag whose tag name is "html" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] == 'html') { - /* Create an element for the token in the HTML namespace. Append it - * to the Document object. Put this element in the stack of open - * elements. */ - $html = $this->insertElement($token, false); - $this->dom->appendChild($html); - $this->stack[] = $html; - - $this->mode = self::BEFORE_HEAD; - - } else { - /* Create an html element. Append it to the Document object. Put - * this element in the stack of open elements. */ - $html = $this->dom->createElementNS(self::NS_HTML, 'html'); - $this->dom->appendChild($html); - $this->stack[] = $html; - - /* Switch the insertion mode to "before head", then reprocess the - * current token. */ - $this->mode = self::BEFORE_HEAD; - $this->emitToken($token); - } - break; - - case self::BEFORE_HEAD: - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Ignore the token. */ - $this->ignored = true; - - /* A comment token */ - } elseif($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A DOCTYPE token */ - } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) { - /* Parse error. Ignore the token */ - $this->ignored = true; - // parse error - - /* A start tag token with the tag name "html" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - /* Process the token using the rules for the "in body" - * insertion mode. */ - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag token with the tag name "head" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') { - /* Insert an HTML element for the token. */ - $element = $this->insertElement($token); - - /* Set the head element pointer to this new element node. */ - $this->head_pointer = $element; - - /* Change the insertion mode to "in head". */ - $this->mode = self::IN_HEAD; - - /* An end tag whose tag name is one of: "head", "body", "html", "br" */ - } elseif( - $token['type'] === HTML5_Tokenizer::ENDTAG && ( - $token['name'] === 'head' || $token['name'] === 'body' || - $token['name'] === 'html' || $token['name'] === 'br' - )) { - /* Act as if a start tag token with the tag name "head" and no - * attributes had been seen, then reprocess the current token. */ - $this->emitToken(array( - 'name' => 'head', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - $this->emitToken($token); - - /* Any other end tag */ - } elseif($token['type'] === HTML5_Tokenizer::ENDTAG) { - /* Parse error. Ignore the token. */ - $this->ignored = true; - - } else { - /* Act as if a start tag token with the tag name "head" and no - * attributes had been seen, then reprocess the current token. - * Note: This will result in an empty head element being - * generated, with the current token being reprocessed in the - * "after head" insertion mode. */ - $this->emitToken(array( - 'name' => 'head', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - $this->emitToken($token); - } - break; - - case self::IN_HEAD: - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE. */ - if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Insert the character into the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - /* A DOCTYPE token */ - } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) { - /* Parse error. Ignore the token. */ - $this->ignored = true; - // parse error - - /* A start tag whose tag name is "html" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && - $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag whose tag name is one of: "base", "command", "link" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && - ($token['name'] === 'base' || $token['name'] === 'command' || - $token['name'] === 'link')) { - /* Insert an HTML element for the token. Immediately pop the - * current node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - /* A start tag whose tag name is "meta" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'meta') { - /* Insert an HTML element for the token. Immediately pop the - * current node off the stack of open elements. */ - $this->insertElement($token); - array_pop($this->stack); - - // XERROR: Acknowledge the token's self-closing flag, if it is set. - - // XENCODING: If the element has a charset attribute, and its value is a - // supported encoding, and the confidence is currently tentative, - // then change the encoding to the encoding given by the value of - // the charset attribute. - // - // Otherwise, if the element has a content attribute, and applying - // the algorithm for extracting an encoding from a Content-Type to - // its value returns a supported encoding encoding, and the - // confidence is currently tentative, then change the encoding to - // the encoding encoding. - - /* A start tag with the tag name "title" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'title') { - $this->insertRCDATAElement($token); - - /* A start tag whose tag name is "noscript", if the scripting flag is enabled, or - * A start tag whose tag name is one of: "noframes", "style" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && - ($token['name'] === 'noscript' || $token['name'] === 'noframes' || $token['name'] === 'style')) { - // XSCRIPT: Scripting flag not respected - $this->insertCDATAElement($token); - - // XSCRIPT: Scripting flag disable not implemented - - /* A start tag with the tag name "script" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') { - /* 1. Create an element for the token in the HTML namespace. */ - $node = $this->insertElement($token, false); - - /* 2. Mark the element as being "parser-inserted" */ - // Uhhh... XSCRIPT - - /* 3. If the parser was originally created for the HTML - * fragment parsing algorithm, then mark the script element as - * "already executed". (fragment case) */ - // ditto... XSCRIPT - - /* 4. Append the new element to the current node and push it onto - * the stack of open elements. */ - end($this->stack)->appendChild($node); - $this->stack[] = $node; - // I guess we could squash these together - - /* 6. Let the original insertion mode be the current insertion mode. */ - $this->original_mode = $this->mode; - /* 7. Switch the insertion mode to "in CDATA/RCDATA" */ - $this->mode = self::IN_CDATA_RCDATA; - /* 5. Switch the tokeniser's content model flag to the CDATA state. */ - $this->content_model = HTML5_Tokenizer::CDATA; - - /* An end tag with the tag name "head" */ - } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'head') { - /* Pop the current node (which will be the head element) off the stack of open elements. */ - array_pop($this->stack); - - /* Change the insertion mode to "after head". */ - $this->mode = self::AFTER_HEAD; - - // Slight logic inversion here to minimize duplication - /* A start tag with the tag name "head". */ - /* An end tag whose tag name is not one of: "body", "html", "br" */ - } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] !== 'html' && - $token['name'] !== 'body' && $token['name'] !== 'br')) { - // Parse error. Ignore the token. - $this->ignored = true; - - /* Anything else */ - } else { - /* Act as if an end tag token with the tag name "head" had been - * seen, and reprocess the current token. */ - $this->emitToken(array( - 'name' => 'head', - 'type' => HTML5_Tokenizer::ENDTAG - )); - - /* Then, reprocess the current token. */ - $this->emitToken($token); - } - break; - - case self::IN_HEAD_NOSCRIPT: - if ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // parse error - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'noscript') { - /* Pop the current node (which will be a noscript element) from the - * stack of open elements; the new current node will be a head - * element. */ - array_pop($this->stack); - $this->mode = self::IN_HEAD; - } elseif ( - ($token['type'] === HTML5_Tokenizer::SPACECHARACTER) || - ($token['type'] === HTML5_Tokenizer::COMMENT) || - ($token['type'] === HTML5_Tokenizer::STARTTAG && ( - $token['name'] === 'link' || $token['name'] === 'meta' || - $token['name'] === 'noframes' || $token['name'] === 'style'))) { - $this->processWithRulesFor($token, self::IN_HEAD); - // inverted logic - } elseif ( - ($token['type'] === HTML5_Tokenizer::STARTTAG && ( - $token['name'] === 'head' || $token['name'] === 'noscript')) || - ($token['type'] === HTML5_Tokenizer::ENDTAG && - $token['name'] !== 'br')) { - // parse error - } else { - // parse error - $this->emitToken(array( - 'type' => HTML5_Tokenizer::ENDTAG, - 'name' => 'noscript', - )); - $this->emitToken($token); - } - break; - - case self::AFTER_HEAD: - /* Handle the token as follows: */ - - /* A character token that is one of one of U+0009 CHARACTER TABULATION, - U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF), - or U+0020 SPACE */ - if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) { - /* Append the character to the current node. */ - $this->insertText($token['data']); - - /* A comment token */ - } elseif($token['type'] === HTML5_Tokenizer::COMMENT) { - /* Append a Comment node to the current node with the data attribute - set to the data given in the comment token. */ - $this->insertComment($token['data']); - - } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) { - // parse error - - } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') { - $this->processWithRulesFor($token, self::IN_BODY); - - /* A start tag token with the tag name "body" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'body') { - $this->insertElement($token); - - /* Set the frameset-ok flag to "not ok". */ - $this->flag_frameset_ok = false; - - /* Change the insertion mode to "in body". */ - $this->mode = self::IN_BODY; - - /* A start tag token with the tag name "frameset" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'frameset') { - /* Insert a frameset element for the token. */ - $this->insertElement($token); - - /* Change the insertion mode to "in frameset". */ - $this->mode = self::IN_FRAMESET; - - /* A start tag token whose tag name is one of: "base", "link", "meta", - "script", "style", "title" */ - } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'], - array('base', 'link', 'meta', 'noframes', 'script', 'style', 'title'))) { - // parse error - /* Push the node pointed to by the head element pointer onto the - * stack of open elements. */ - $this->stack[] = $this->head_pointer; - $this->processWithRulesFor($token, self::IN_HEAD); - array_splice($this->stack, array_search($this->head_pointer, $this->stack, true), 1); - - // inversion of specification - } elseif( - ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'head') || - ($token['type'] === HTML5_Tokenizer::ENDTAG && - $token['name'] !== 'body' && $token['name'] !== 'html' && - $token['name'] !== 'br')) { - // parse error - - /* Anything else */ - } else { - $this->emitToken(array( - 'name' => 'body', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - $this->flag_frameset_ok = true; - $this->emitToken($token); - } - break; - - case self::IN_BODY: - /* Handle the token as follows: */ - - switch($token['type']) { - /* A character token */ - case HTML5_Tokenizer::CHARACTER: - case HTML5_Tokenizer::SPACECHARACTER: - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Append the token's character to the current node. */ - $this->insertText($token['data']); - - /* If the token is not one of U+0009 CHARACTER TABULATION, - * U+000A LINE FEED (LF), U+000C FORM FEED (FF), or U+0020 - * SPACE, then set the frameset-ok flag to "not ok". */ - // i.e., if any of the characters is not whitespace - if (strlen($token['data']) !== strspn($token['data'], HTML5_Tokenizer::WHITESPACE)) { - $this->flag_frameset_ok = false; - } - break; - - /* A comment token */ - case HTML5_Tokenizer::COMMENT: - /* Append a Comment node to the current node with the data - attribute set to the data given in the comment token. */ - $this->insertComment($token['data']); - break; - - case HTML5_Tokenizer::DOCTYPE: - // parse error - break; - - case HTML5_Tokenizer::STARTTAG: - switch($token['name']) { - case 'html': - // parse error - /* For each attribute on the token, check to see if the - * attribute is already present on the top element of the - * stack of open elements. If it is not, add the attribute - * and its corresponding value to that element. */ - foreach($token['attr'] as $attr) { - if(!$this->stack[0]->hasAttribute($attr['name'])) { - $this->stack[0]->setAttribute($attr['name'], $attr['value']); - } - } - break; - - case 'base': case 'command': case 'link': case 'meta': case 'noframes': - case 'script': case 'style': case 'title': - /* Process the token as if the insertion mode had been "in - head". */ - $this->processWithRulesFor($token, self::IN_HEAD); - break; - - /* A start tag token with the tag name "body" */ - case 'body': - /* Parse error. If the second element on the stack of open - elements is not a body element, or, if the stack of open - elements has only one node on it, then ignore the token. - (fragment case) */ - if(count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') { - $this->ignored = true; - // Ignore - - /* Otherwise, for each attribute on the token, check to see - if the attribute is already present on the body element (the - second element) on the stack of open elements. If it is not, - add the attribute and its corresponding value to that - element. */ - } else { - foreach($token['attr'] as $attr) { - if(!$this->stack[1]->hasAttribute($attr['name'])) { - $this->stack[1]->setAttribute($attr['name'], $attr['value']); - } - } - } - break; - - case 'frameset': - // parse error - /* If the second element on the stack of open elements is - * not a body element, or, if the stack of open elements - * has only one node on it, then ignore the token. - * (fragment case) */ - if(count($this->stack) === 1 || $this->stack[1]->tagName !== 'body') { - $this->ignored = true; - // Ignore - } elseif (!$this->flag_frameset_ok) { - $this->ignored = true; - // Ignore - } else { - /* 1. Remove the second element on the stack of open - * elements from its parent node, if it has one. */ - if($this->stack[1]->parentNode) { - $this->stack[1]->parentNode->removeChild($this->stack[1]); - } - - /* 2. Pop all the nodes from the bottom of the stack of - * open elements, from the current node up to the root - * html element. */ - array_splice($this->stack, 1); - - $this->insertElement($token); - $this->mode = self::IN_FRAMESET; - } - break; - - // in spec, there is a diversion here - - case 'address': case 'article': case 'aside': case 'blockquote': - case 'center': case 'datagrid': case 'details': case 'dialog': case 'dir': - case 'div': case 'dl': case 'fieldset': case 'figure': case 'footer': - case 'header': case 'hgroup': case 'menu': case 'nav': - case 'ol': case 'p': case 'section': case 'ul': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - /* A start tag whose tag name is one of: "h1", "h2", "h3", "h4", - "h5", "h6" */ - case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* If the current node is an element whose tag name is one - * of "h1", "h2", "h3", "h4", "h5", or "h6", then this is a - * parse error; pop the current node off the stack of open - * elements. */ - $peek = array_pop($this->stack); - if (in_array($peek->tagName, array("h1", "h2", "h3", "h4", "h5", "h6"))) { - // parse error - } else { - $this->stack[] = $peek; - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - break; - - case 'pre': case 'listing': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - $this->insertElement($token); - /* If the next token is a U+000A LINE FEED (LF) character - * token, then ignore that token and move on to the next - * one. (Newlines at the start of pre blocks are ignored as - * an authoring convenience.) */ - $this->ignore_lf_token = 2; - $this->flag_frameset_ok = false; - break; - - /* A start tag whose tag name is "form" */ - case 'form': - /* If the form element pointer is not null, ignore the - token with a parse error. */ - if($this->form_pointer !== null) { - $this->ignored = true; - // Ignore. - - /* Otherwise: */ - } else { - /* If the stack of open elements has a p element in - scope, then act as if an end tag with the tag name p - had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Insert an HTML element for the token, and set the - form element pointer to point to the element created. */ - $element = $this->insertElement($token); - $this->form_pointer = $element; - } - break; - - // condensed specification - case 'li': case 'dd': case 'dt': - /* 1. Set the frameset-ok flag to "not ok". */ - $this->flag_frameset_ok = false; - - $stack_length = count($this->stack) - 1; - for($n = $stack_length; 0 <= $n; $n--) { - /* 2. Initialise node to be the current node (the - bottommost node of the stack). */ - $stop = false; - $node = $this->stack[$n]; - $cat = $this->getElementCategory($node); - - // for case 'li': - /* 3. If node is an li element, then act as if an end - * tag with the tag name "li" had been seen, then jump - * to the last step. */ - // for case 'dd': case 'dt': - /* If node is a dd or dt element, then act as if an end - * tag with the same tag name as node had been seen, then - * jump to the last step. */ - if(($token['name'] === 'li' && $node->tagName === 'li') || - ($token['name'] !== 'li' && ($node->tagName === 'dd' || $node->tagName === 'dt'))) { // limited conditional - $this->emitToken(array( - 'type' => HTML5_Tokenizer::ENDTAG, - 'name' => $node->tagName, - )); - break; - } - - /* 4. If node is not in the formatting category, and is - not in the phrasing category, and is not an address, - div or p element, then stop this algorithm. */ - if($cat !== self::FORMATTING && $cat !== self::PHRASING && - $node->tagName !== 'address' && $node->tagName !== 'div' && - $node->tagName !== 'p') { - break; - } - - /* 5. Otherwise, set node to the previous entry in the - * stack of open elements and return to step 2. */ - } - - /* 6. This is the last step. */ - - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Finally, insert an HTML element with the same tag - name as the token's. */ - $this->insertElement($token); - break; - - /* A start tag token whose tag name is "plaintext" */ - case 'plaintext': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been - seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - $this->content_model = HTML5_Tokenizer::PLAINTEXT; - break; - - // more diversions - - /* A start tag whose tag name is "a" */ - case 'a': - /* If the list of active formatting elements contains - an element whose tag name is "a" between the end of the - list and the last marker on the list (or the start of - the list if there is no marker on the list), then this - is a parse error; act as if an end tag with the tag name - "a" had been seen, then remove that element from the list - of active formatting elements and the stack of open - elements if the end tag didn't already remove it (it - might not have if the element is not in table scope). */ - $leng = count($this->a_formatting); - - for($n = $leng - 1; $n >= 0; $n--) { - if($this->a_formatting[$n] === self::MARKER) { - break; - - } elseif($this->a_formatting[$n]->tagName === 'a') { - $a = $this->a_formatting[$n]; - $this->emitToken(array( - 'name' => 'a', - 'type' => HTML5_Tokenizer::ENDTAG - )); - if (in_array($a, $this->a_formatting)) { - $a_i = array_search($a, $this->a_formatting, true); - if($a_i !== false) array_splice($this->a_formatting, $a_i, 1); - } - if (in_array($a, $this->stack)) { - $a_i = array_search($a, $this->stack, true); - if ($a_i !== false) array_splice($this->stack, $a_i, 1); - } - break; - } - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - case 'b': case 'big': case 'code': case 'em': case 'font': case 'i': - case 's': case 'small': case 'strike': - case 'strong': case 'tt': case 'u': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - case 'nobr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* If the stack of open elements has a nobr element in - * scope, then this is a parse error; act as if an end tag - * with the tag name "nobr" had been seen, then once again - * reconstruct the active formatting elements, if any. */ - if ($this->elementInScope('nobr')) { - $this->emitToken(array( - 'name' => 'nobr', - 'type' => HTML5_Tokenizer::ENDTAG, - )); - $this->reconstructActiveFormattingElements(); - } - - /* Insert an HTML element for the token. */ - $el = $this->insertElement($token); - - /* Add that element to the list of active formatting - elements. */ - $this->a_formatting[] = $el; - break; - - // another diversion - - /* A start tag token whose tag name is "button" */ - case 'button': - /* If the stack of open elements has a button element in scope, - then this is a parse error; act as if an end tag with the tag - name "button" had been seen, then reprocess the token. (We don't - do that. Unnecessary.) (I hope you're right! -- ezyang) */ - if($this->elementInScope('button')) { - $this->emitToken(array( - 'name' => 'button', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - $this->flag_frameset_ok = false; - break; - - case 'applet': case 'marquee': case 'object': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Insert a marker at the end of the list of active - formatting elements. */ - $this->a_formatting[] = self::MARKER; - - $this->flag_frameset_ok = false; - break; - - // spec diversion - - /* A start tag whose tag name is "table" */ - case 'table': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->quirks_mode !== self::QUIRKS_MODE && - $this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - $this->flag_frameset_ok = false; - - /* Change the insertion mode to "in table". */ - $this->mode = self::IN_TABLE; - break; - - /* A start tag whose tag name is one of: "area", "basefont", - "bgsound", "br", "embed", "img", "param", "spacer", "wbr" */ - case 'area': case 'basefont': case 'bgsound': case 'br': - case 'embed': case 'img': case 'input': case 'keygen': case 'spacer': - case 'wbr': - /* Reconstruct the active formatting elements, if any. */ - $this->reconstructActiveFormattingElements(); - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - $this->flag_frameset_ok = false; - break; - - case 'param': case 'source': - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - break; - - /* A start tag whose tag name is "hr" */ - case 'hr': - /* If the stack of open elements has a p element in scope, - then act as if an end tag with the tag name p had been seen. */ - if($this->elementInScope('p')) { - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } - - /* Insert an HTML element for the token. */ - $this->insertElement($token); - - /* Immediately pop the current node off the stack of open elements. */ - array_pop($this->stack); - - // YYY: Acknowledge the token's self-closing flag, if it is set. - - $this->flag_frameset_ok = false; - break; - - /* A start tag whose tag name is "image" */ - case 'image': - /* Parse error. Change the token's tag name to "img" and - reprocess it. (Don't ask.) */ - $token['name'] = 'img'; - $this->emitToken($token); - break; - - /* A start tag whose tag name is "isindex" */ - case 'isindex': - /* Parse error. */ - - /* If the form element pointer is not null, - then ignore the token. */ - if($this->form_pointer === null) { - /* Act as if a start tag token with the tag name "form" had - been seen. */ - /* If the token has an attribute called "action", set - * the action attribute on the resulting form - * element to the value of the "action" attribute of - * the token. */ - $attr = array(); - $action = $this->getAttr($token, 'action'); - if ($action !== false) { - $attr[] = array('name' => 'action', 'value' => $action); - } - $this->emitToken(array( - 'name' => 'form', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => $attr - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->emitToken(array( - 'name' => 'hr', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "p" had - been seen. */ - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - - /* Act as if a start tag token with the tag name "label" - had been seen. */ - $this->emitToken(array( - 'name' => 'label', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => array() - )); - - /* Act as if a stream of character tokens had been seen. */ - $prompt = $this->getAttr($token, 'prompt'); - if ($prompt === false) { - $prompt = 'This is a searchable index. '. - 'Insert your search keywords here: '; - } - $this->emitToken(array( - 'data' => $prompt, - 'type' => HTML5_Tokenizer::CHARACTER, - )); - - /* Act as if a start tag token with the tag name "input" - had been seen, with all the attributes from the "isindex" - token, except with the "name" attribute set to the value - "isindex" (ignoring any explicit "name" attribute). */ - $attr = array(); - foreach ($token['attr'] as $keypair) { - if ($keypair['name'] === 'name' || $keypair['name'] === 'action' || - $keypair['name'] === 'prompt') continue; - $attr[] = $keypair; - } - $attr[] = array('name' => 'name', 'value' => 'isindex'); - - $this->emitToken(array( - 'name' => 'input', - 'type' => HTML5_Tokenizer::STARTTAG, - 'attr' => $attr - )); - - /* Act as if an end tag token with the tag name "label" - had been seen. */ - $this->emitToken(array( - 'name' => 'label', - 'type' => HTML5_Tokenizer::ENDTAG - )); - - /* Act as if an end tag token with the tag name "p" had - been seen. */ - $this->emitToken(array( - 'name' => 'p', - 'type' => HTML5_Tokenizer::ENDTAG - )); - - /* Act as if a start tag token with the tag name "hr" had - been seen. */ - $this->emitToken(array( - 'name' => 'hr', - 'type' => HTML5_Tokenizer::STARTTAG - )); - - /* Act as if an end tag token with the tag name "form" had - been seen. */ - $this->emitToken(array( - 'name' => 'form', - 'type' => HTML5_Tokenizer::ENDTAG - )); - } else { - $this->ignored = true; - } - break; - - /* A start tag whose tag name is "textarea" */ - case 'textarea': - $this->insertElement($token); - - /* If the next token is a U+000A LINE FEED (LF) - * character token, then ignore that token and move on to - * the next one. (Newlines at the start of textarea - * elements are ignored as an authoring convenience.) - * need flag, see also
 */
-                    $this->ignore_lf_token = 2;
-
-                    $this->original_mode = $this->mode;
-                    $this->flag_frameset_ok = false;
-                    $this->mode = self::IN_CDATA_RCDATA;
-
-                    /* Switch the tokeniser's content model flag to the
-                    RCDATA state. */
-                    $this->content_model = HTML5_Tokenizer::RCDATA;
-                break;
-
-                /* A start tag token whose tag name is "xmp" */
-                case 'xmp':
-                    /* Reconstruct the active formatting elements, if any. */
-                    $this->reconstructActiveFormattingElements();
-
-                    $this->flag_frameset_ok = false;
-
-                    $this->insertCDATAElement($token);
-                break;
-
-                case 'iframe':
-                    $this->flag_frameset_ok = false;
-                    $this->insertCDATAElement($token);
-                break;
-
-                case 'noembed': case 'noscript':
-                    // XSCRIPT: should check scripting flag
-                    $this->insertCDATAElement($token);
-                break;
-
-                /* A start tag whose tag name is "select" */
-                case 'select':
-                    /* Reconstruct the active formatting elements, if any. */
-                    $this->reconstructActiveFormattingElements();
-
-                    /* Insert an HTML element for the token. */
-                    $this->insertElement($token);
-
-                    $this->flag_frameset_ok = false;
-
-                    /* If the insertion mode is one of in table", "in caption",
-                     * "in column group", "in table body", "in row", or "in
-                     * cell", then switch the insertion mode to "in select in
-                     * table". Otherwise, switch the insertion mode  to "in
-                     * select". */
-                    if (
-                        $this->mode === self::IN_TABLE || $this->mode === self::IN_CAPTION ||
-                        $this->mode === self::IN_COLUMN_GROUP || $this->mode ==+self::IN_TABLE_BODY ||
-                        $this->mode === self::IN_ROW || $this->mode === self::IN_CELL
-                    ) {
-                        $this->mode = self::IN_SELECT_IN_TABLE;
-                    } else {
-                        $this->mode = self::IN_SELECT;
-                    }
-                break;
-
-                case 'option': case 'optgroup':
-                    if ($this->elementInScope('option')) {
-                        $this->emitToken(array(
-                            'name' => 'option',
-                            'type' => HTML5_Tokenizer::ENDTAG,
-                        ));
-                    }
-                    $this->reconstructActiveFormattingElements();
-                    $this->insertElement($token);
-                break;
-
-                case 'rp': case 'rt':
-                    /* If the stack of open elements has a ruby element in scope, then generate
-                     * implied end tags. If the current node is not then a ruby element, this is
-                     * a parse error; pop all the nodes from the current node up to the node
-                     * immediately before the bottommost ruby element on the stack of open elements.
-                     */
-                    if ($this->elementInScope('ruby')) {
-                        $this->generateImpliedEndTags();
-                    }
-                    $peek = false;
-                    do {
-                        if ($peek) {
-                            // parse error
-                        }
-                        $peek = array_pop($this->stack);
-                    } while ($peek->tagName !== 'ruby');
-                    $this->stack[] = $peek; // we popped one too many
-                    $this->insertElement($token);
-                break;
-
-                // spec diversion
-
-                case 'math':
-                    $this->reconstructActiveFormattingElements();
-                    $token = $this->adjustMathMLAttributes($token);
-                    $token = $this->adjustForeignAttributes($token);
-                    $this->insertForeignElement($token, self::NS_MATHML);
-                    if (isset($token['self-closing'])) {
-                        // XERROR: acknowledge the token's self-closing flag
-                        array_pop($this->stack);
-                    }
-                    if ($this->mode !== self::IN_FOREIGN_CONTENT) {
-                        $this->secondary_mode = $this->mode;
-                        $this->mode = self::IN_FOREIGN_CONTENT;
-                    }
-                break;
-
-                case 'svg':
-                    $this->reconstructActiveFormattingElements();
-                    $token = $this->adjustSVGAttributes($token);
-                    $token = $this->adjustForeignAttributes($token);
-                    $this->insertForeignElement($token, self::NS_SVG);
-                    if (isset($token['self-closing'])) {
-                        // XERROR: acknowledge the token's self-closing flag
-                        array_pop($this->stack);
-                    }
-                    if ($this->mode !== self::IN_FOREIGN_CONTENT) {
-                        $this->secondary_mode = $this->mode;
-                        $this->mode = self::IN_FOREIGN_CONTENT;
-                    }
-                break;
-
-                case 'caption': case 'col': case 'colgroup': case 'frame': case 'head':
-                case 'tbody': case 'td': case 'tfoot': case 'th': case 'thead': case 'tr':
-                    // parse error
-                break;
-
-                /* A start tag token not covered by the previous entries */
-                default:
-                    /* Reconstruct the active formatting elements, if any. */
-                    $this->reconstructActiveFormattingElements();
-
-                    $this->insertElement($token);
-                    /* This element will be a phrasing  element. */
-                break;
-            }
-            break;
-
-            case HTML5_Tokenizer::ENDTAG:
-            switch($token['name']) {
-                /* An end tag with the tag name "body" */
-                case 'body':
-                    /* If the second element in the stack of open elements is
-                    not a body element, this is a parse error. Ignore the token.
-                    (innerHTML case) */
-                    if(count($this->stack) < 2 || $this->stack[1]->tagName !== 'body') {
-                        $this->ignored = true;
-
-                    /* Otherwise, if there is a node in the stack of open
-                     * elements that is not either a dd element, a dt
-                     * element, an li element, an optgroup element, an
-                     * option element, a p element, an rp element, an rt
-                     * element, a tbody element, a td element, a tfoot
-                     * element, a th element, a thead element, a tr element,
-                     * the body element, or the html element, then this is a
-                     * parse error. */
-                    } else {
-                        // XERROR: implement this check for parse error
-                    }
-
-                    /* Change the insertion mode to "after body". */
-                    $this->mode = self::AFTER_BODY;
-                break;
-
-                /* An end tag with the tag name "html" */
-                case 'html':
-                    /* Act as if an end tag with tag name "body" had been seen,
-                    then, if that token wasn't ignored, reprocess the current
-                    token. */
-                    $this->emitToken(array(
-                        'name' => 'body',
-                        'type' => HTML5_Tokenizer::ENDTAG
-                    ));
-
-                    if (!$this->ignored) $this->emitToken($token);
-                break;
-
-                case 'address': case 'article': case 'aside': case 'blockquote':
-                case 'center': case 'datagrid': case 'details': case 'dir':
-                case 'div': case 'dl': case 'fieldset': case 'figure': case 'footer':
-                case 'header': case 'hgroup': case 'listing': case 'menu':
-                case 'nav': case 'ol': case 'pre': case 'section': case 'ul':
-                    /* If the stack of open elements has an element in scope
-                    with the same tag name as that of the token, then generate
-                    implied end tags. */
-                    if($this->elementInScope($token['name'])) {
-                        $this->generateImpliedEndTags();
-
-                        /* Now, if the current node is not an element with
-                        the same tag name as that of the token, then this
-                        is a parse error. */
-                        // XERROR: implement parse error logic
-
-                        /* If the stack of open elements has an element in
-                        scope with the same tag name as that of the token,
-                        then pop elements from this stack until an element
-                        with that tag name has been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== $token['name']);
-                    } else {
-                        // parse error
-                    }
-                break;
-
-                /* An end tag whose tag name is "form" */
-                case 'form':
-                    /* Let node be the element that the form element pointer is set to. */
-                    $node = $this->form_pointer;
-                    /* Set the form element pointer  to null. */
-                    $this->form_pointer = null;
-                    /* If node is null or the stack of open elements does not 
-                        * have node in scope, then this is a parse error; ignore the token. */
-                    if ($node === null || !in_array($node, $this->stack)) {
-                        // parse error
-                        $this->ignored = true;
-                    } else {
-                        /* 1. Generate implied end tags. */
-                        $this->generateImpliedEndTags();
-                        /* 2. If the current node is not node, then this is a parse error.  */
-                        if (end($this->stack) !== $node) {
-                            // parse error
-                        }
-                        /* 3. Remove node from the stack of open elements. */
-                        array_splice($this->stack, array_search($node, $this->stack, true), 1);
-                    }
-
-                break;
-
-                /* An end tag whose tag name is "p" */
-                case 'p':
-                    /* If the stack of open elements has a p element in scope,
-                    then generate implied end tags, except for p elements. */
-                    if($this->elementInScope('p')) {
-                        /* Generate implied end tags, except for elements with
-                         * the same tag name as the token. */
-                        $this->generateImpliedEndTags(array('p'));
-
-                        /* If the current node is not a p element, then this is
-                        a parse error. */
-                        // XERROR: implement
-
-                        /* Pop elements from the stack of open elements  until
-                         * an element with the same tag name as the token has
-                         * been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== 'p');
-
-                    } else {
-                        // parse error
-                        $this->emitToken(array(
-                            'name' => 'p',
-                            'type' => HTML5_Tokenizer::STARTTAG,
-                        ));
-                        $this->emitToken($token);
-                    }
-                break;
-
-                /* An end tag whose tag name is "dd", "dt", or "li" */
-                case 'dd': case 'dt': case 'li':
-                    if($this->elementInScope($token['name'])) {
-                        $this->generateImpliedEndTags(array($token['name']));
-
-                        /* If the current node is not an element with the same
-                        tag name as the token, then this is a parse error. */
-                        // XERROR: implement parse error
-
-                        /* Pop elements from the stack of open elements  until
-                         * an element with the same tag name as the token has
-                         * been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== $token['name']);
-
-                    } else {
-                        // parse error
-                    }
-                break;
-
-                /* An end tag whose tag name is one of: "h1", "h2", "h3", "h4",
-                "h5", "h6" */
-                case 'h1': case 'h2': case 'h3': case 'h4': case 'h5': case 'h6':
-                    $elements = array('h1', 'h2', 'h3', 'h4', 'h5', 'h6');
-
-                    /* If the stack of open elements has in scope an element whose
-                    tag name is one of "h1", "h2", "h3", "h4", "h5", or "h6", then
-                    generate implied end tags. */
-                    if($this->elementInScope($elements)) {
-                        $this->generateImpliedEndTags();
-
-                        /* Now, if the current node is not an element with the same
-                        tag name as that of the token, then this is a parse error. */
-                        // XERROR: implement parse error
-
-                        /* If the stack of open elements has in scope an element
-                        whose tag name is one of "h1", "h2", "h3", "h4", "h5", or
-                        "h6", then pop elements from the stack until an element
-                        with one of those tag names has been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while (!in_array($node->tagName, $elements));
-                    } else {
-                        // parse error
-                    }
-                break;
-
-                /* An end tag whose tag name is one of: "a", "b", "big", "em",
-                "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u" */
-                case 'a': case 'b': case 'big': case 'code': case 'em': case 'font':
-                case 'i': case 'nobr': case 's': case 'small': case 'strike':
-                case 'strong': case 'tt': case 'u':
-                    // XERROR: generally speaking this needs parse error logic
-                    /* 1. Let the formatting element be the last element in
-                    the list of active formatting elements that:
-                        * is between the end of the list and the last scope
-                        marker in the list, if any, or the start of the list
-                        otherwise, and
-                        * has the same tag name as the token.
-                    */
-                    while(true) {
-                        for($a = count($this->a_formatting) - 1; $a >= 0; $a--) {
-                            if($this->a_formatting[$a] === self::MARKER) {
-                                break;
-
-                            } elseif($this->a_formatting[$a]->tagName === $token['name']) {
-                                $formatting_element = $this->a_formatting[$a];
-                                $in_stack = in_array($formatting_element, $this->stack, true);
-                                $fe_af_pos = $a;
-                                break;
-                            }
-                        }
-
-                        /* If there is no such node, or, if that node is
-                        also in the stack of open elements but the element
-                        is not in scope, then this is a parse error. Abort
-                        these steps. The token is ignored. */
-                        if(!isset($formatting_element) || ($in_stack &&
-                        !$this->elementInScope($token['name']))) {
-                            $this->ignored = true;
-                            break;
-
-                        /* Otherwise, if there is such a node, but that node
-                        is not in the stack of open elements, then this is a
-                        parse error; remove the element from the list, and
-                        abort these steps. */
-                        } elseif(isset($formatting_element) && !$in_stack) {
-                            unset($this->a_formatting[$fe_af_pos]);
-                            $this->a_formatting = array_merge($this->a_formatting);
-                            break;
-                        }
-
-                        /* Otherwise, there is a formatting element and that
-                         * element is in the stack and is in scope. If the
-                         * element is not the current node, this is a parse
-                         * error. In any case, proceed with the algorithm as
-                         * written in the following steps. */
-                        // XERROR: implement me
-
-                        /* 2. Let the furthest block be the topmost node in the
-                        stack of open elements that is lower in the stack
-                        than the formatting element, and is not an element in
-                        the phrasing or formatting categories. There might
-                        not be one. */
-                        $fe_s_pos = array_search($formatting_element, $this->stack, true);
-                        $length = count($this->stack);
-
-                        for($s = $fe_s_pos + 1; $s < $length; $s++) {
-                            $category = $this->getElementCategory($this->stack[$s]);
-
-                            if($category !== self::PHRASING && $category !== self::FORMATTING) {
-                                $furthest_block = $this->stack[$s];
-                                break;
-                            }
-                        }
-
-                        /* 3. If there is no furthest block, then the UA must
-                        skip the subsequent steps and instead just pop all
-                        the nodes from the bottom of the stack of open
-                        elements, from the current node up to the formatting
-                        element, and remove the formatting element from the
-                        list of active formatting elements. */
-                        if(!isset($furthest_block)) {
-                            for($n = $length - 1; $n >= $fe_s_pos; $n--) {
-                                array_pop($this->stack);
-                            }
-
-                            unset($this->a_formatting[$fe_af_pos]);
-                            $this->a_formatting = array_merge($this->a_formatting);
-                            break;
-                        }
-
-                        /* 4. Let the common ancestor be the element
-                        immediately above the formatting element in the stack
-                        of open elements. */
-                        $common_ancestor = $this->stack[$fe_s_pos - 1];
-
-                        /* 5. Let a bookmark note the position of the
-                        formatting element in the list of active formatting
-                        elements relative to the elements on either side
-                        of it in the list. */
-                        $bookmark = $fe_af_pos;
-
-                        /* 6. Let node and last node  be the furthest block.
-                        Follow these steps: */
-                        $node = $furthest_block;
-                        $last_node = $furthest_block;
-
-                        while(true) {
-                            for($n = array_search($node, $this->stack, true) - 1; $n >= 0; $n--) {
-                                /* 6.1 Let node be the element immediately
-                                prior to node in the stack of open elements. */
-                                $node = $this->stack[$n];
-
-                                /* 6.2 If node is not in the list of active
-                                formatting elements, then remove node from
-                                the stack of open elements and then go back
-                                to step 1. */
-                                if(!in_array($node, $this->a_formatting, true)) {
-                                    array_splice($this->stack, $n, 1);
-
-                                } else {
-                                    break;
-                                }
-                            }
-
-                            /* 6.3 Otherwise, if node is the formatting
-                            element, then go to the next step in the overall
-                            algorithm. */
-                            if($node === $formatting_element) {
-                                break;
-
-                            /* 6.4 Otherwise, if last node is the furthest
-                            block, then move the aforementioned bookmark to
-                            be immediately after the node in the list of
-                            active formatting elements. */
-                            } elseif($last_node === $furthest_block) {
-                                $bookmark = array_search($node, $this->a_formatting, true) + 1;
-                            }
-
-                            /* 6.5 Create an element for the token for which
-                             * the element node was created, replace the entry
-                             * for node in the list of active formatting
-                             * elements with an entry for the new element,
-                             * replace the entry for node in the stack of open
-                             * elements with an entry for the new element, and
-                             * let node be the new element. */
-                            // we don't know what the token is anymore
-                            $clone = $node->cloneNode();
-                            $a_pos = array_search($node, $this->a_formatting, true);
-                            $s_pos = array_search($node, $this->stack, true);
-                            $this->a_formatting[$a_pos] = $clone;
-                            $this->stack[$s_pos] = $clone;
-                            $node = $clone;
-
-                            /* 6.6 Insert last node into node, first removing
-                            it from its previous parent node if any. */
-                            if($last_node->parentNode !== null) {
-                                $last_node->parentNode->removeChild($last_node);
-                            }
-
-                            $node->appendChild($last_node);
-
-                            /* 6.7 Let last node be node. */
-                            $last_node = $node;
-
-                            /* 6.8 Return to step 1 of this inner set of steps. */
-                        }
-
-                        /* 7. If the common ancestor node is a table, tbody,
-                         * tfoot, thead, or tr element, then, foster parent
-                         * whatever last node ended up being in the previous
-                         * step, first removing it from its previous parent
-                         * node if any. */
-                        if ($last_node->parentNode) { // common step
-                            $last_node->parentNode->removeChild($last_node);
-                        }
-                        if (in_array($common_ancestor->tagName, array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
-                            $this->fosterParent($last_node);
-                        /* Otherwise, append whatever last node  ended up being
-                         * in the previous step to the common ancestor node,
-                         * first removing it from its previous parent node if
-                         * any. */
-                        } else {
-                            $common_ancestor->appendChild($last_node);
-                        }
-
-                        /* 8. Create an element for the token for which the
-                         * formatting element was created. */
-                        $clone = $formatting_element->cloneNode();
-
-                        /* 9. Take all of the child nodes of the furthest
-                        block and append them to the element created in the
-                        last step. */
-                        while($furthest_block->hasChildNodes()) {
-                            $child = $furthest_block->firstChild;
-                            $furthest_block->removeChild($child);
-                            $clone->appendChild($child);
-                        }
-
-                        /* 10. Append that clone to the furthest block. */
-                        $furthest_block->appendChild($clone);
-
-                        /* 11. Remove the formatting element from the list
-                        of active formatting elements, and insert the new element
-                        into the list of active formatting elements at the
-                        position of the aforementioned bookmark. */
-                        $fe_af_pos = array_search($formatting_element, $this->a_formatting, true);
-                        array_splice($this->a_formatting, $fe_af_pos, 1);
-
-                        $af_part1 = array_slice($this->a_formatting, 0, $bookmark - 1);
-                        $af_part2 = array_slice($this->a_formatting, $bookmark);
-                        $this->a_formatting = array_merge($af_part1, array($clone), $af_part2);
-
-                        /* 12. Remove the formatting element from the stack
-                        of open elements, and insert the new element into the stack
-                        of open elements immediately below the position of the
-                        furthest block in that stack. */
-                        $fe_s_pos = array_search($formatting_element, $this->stack, true);
-                        array_splice($this->stack, $fe_s_pos, 1);
-
-                        $fb_s_pos = array_search($furthest_block, $this->stack, true);
-                        $s_part1 = array_slice($this->stack, 0, $fb_s_pos + 1);
-                        $s_part2 = array_slice($this->stack, $fb_s_pos + 1);
-                        $this->stack = array_merge($s_part1, array($clone), $s_part2);
-
-                        /* 13. Jump back to step 1 in this series of steps. */
-                        unset($formatting_element, $fe_af_pos, $fe_s_pos, $furthest_block);
-                    }
-                break;
-
-                case 'applet': case 'button': case 'marquee': case 'object':
-                    /* If the stack of open elements has an element in scope whose
-                    tag name matches the tag name of the token, then generate implied
-                    tags. */
-                    if($this->elementInScope($token['name'])) {
-                        $this->generateImpliedEndTags();
-
-                        /* Now, if the current node is not an element with the same
-                        tag name as the token, then this is a parse error. */
-                        // XERROR: implement logic
-
-                        /* Pop elements from the stack of open elements  until
-                         * an element with the same tag name as the token has
-                         * been popped from the stack. */
-                        do {
-                            $node = array_pop($this->stack);
-                        } while ($node->tagName !== $token['name']);
-
-                        /* Clear the list of active formatting elements up to the
-                         * last marker. */
-                        $keys = array_keys($this->a_formatting, self::MARKER, true);
-                        $marker = end($keys);
-
-                        for($n = count($this->a_formatting) - 1; $n > $marker; $n--) {
-                            array_pop($this->a_formatting);
-                        }
-                    } else {
-                        // parse error
-                    }
-                break;
-
-                case 'br':
-                    // Parse error
-                    $this->emitToken(array(
-                        'name' => 'br',
-                        'type' => HTML5_Tokenizer::STARTTAG,
-                    ));
-                break;
-
-                /* An end tag token not covered by the previous entries */
-                default:
-                    for($n = count($this->stack) - 1; $n >= 0; $n--) {
-                        /* Initialise node to be the current node (the bottommost
-                        node of the stack). */
-                        $node = $this->stack[$n];
-
-                        /* If node has the same tag name as the end tag token,
-                        then: */
-                        if($token['name'] === $node->tagName) {
-                            /* Generate implied end tags. */
-                            $this->generateImpliedEndTags();
-
-                            /* If the tag name of the end tag token does not
-                            match the tag name of the current node, this is a
-                            parse error. */
-                            // XERROR: implement this
-
-                            /* Pop all the nodes from the current node up to
-                            node, including node, then stop these steps. */
-                            // XSKETCHY
-                            do {
-                                $pop = array_pop($this->stack);
-                            } while ($pop !== $node);
-                            break;
-
-                        } else {
-                            $category = $this->getElementCategory($node);
-
-                            if($category !== self::FORMATTING && $category !== self::PHRASING) {
-                                /* Otherwise, if node is in neither the formatting
-                                category nor the phrasing category, then this is a
-                                parse error. Stop this algorithm. The end tag token
-                                is ignored. */
-                                $this->ignored = true;
-                                break;
-                                // parse error
-                            }
-                        }
-                        /* Set node to the previous entry in the stack of open elements. Loop. */
-                    }
-                break;
-            }
-            break;
-        }
-        break;
-
-    case self::IN_CDATA_RCDATA:
-        if (
-            $token['type'] === HTML5_Tokenizer::CHARACTER ||
-            $token['type'] === HTML5_Tokenizer::SPACECHARACTER
-        ) {
-            $this->insertText($token['data']);
-        } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-            // parse error
-            /* If the current node is a script  element, mark the script
-             * element as "already executed". */
-            // probably not necessary
-            array_pop($this->stack);
-            $this->mode = $this->original_mode;
-            $this->emitToken($token);
-        } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'script') {
-            array_pop($this->stack);
-            $this->mode = $this->original_mode;
-            // we're ignoring all of the execution stuff
-        } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG) {
-            array_pop($this->stack);
-            $this->mode = $this->original_mode;
-        }
-    break;
-
-    case self::IN_TABLE:
-        $clear = array('html', 'table');
-
-        /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-        U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-        or U+0020 SPACE */
-        if($token['type'] === HTML5_Tokenizer::SPACECHARACTER &&
-        /* If the current table is tainted, then act as described in
-         * the "anything else" entry below. */
-        // Note: hsivonen has a test that fails due to this line
-        // because he wants to convince Hixie not to do taint
-        !$this->currentTableIsTainted()) {
-            /* Append the character to the current node. */
-            $this->insertText($token['data']);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the current node with the data
-            attribute set to the data given in the comment token. */
-            $this->insertComment($token['data']);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        /* A start tag whose tag name is "caption" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'caption') {
-            /* Clear the stack back to a table context. */
-            $this->clearStackToTableContext($clear);
-
-            /* Insert a marker at the end of the list of active
-            formatting elements. */
-            $this->a_formatting[] = self::MARKER;
-
-            /* Insert an HTML element for the token, then switch the
-            insertion mode to "in caption". */
-            $this->insertElement($token);
-            $this->mode = self::IN_CAPTION;
-
-        /* A start tag whose tag name is "colgroup" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'colgroup') {
-            /* Clear the stack back to a table context. */
-            $this->clearStackToTableContext($clear);
-
-            /* Insert an HTML element for the token, then switch the
-            insertion mode to "in column group". */
-            $this->insertElement($token);
-            $this->mode = self::IN_COLUMN_GROUP;
-
-        /* A start tag whose tag name is "col" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'col') {
-            $this->emitToken(array(
-                'name' => 'colgroup',
-                'type' => HTML5_Tokenizer::STARTTAG,
-                'attr' => array()
-            ));
-
-            $this->emitToken($token);
-
-        /* A start tag whose tag name is one of: "tbody", "tfoot", "thead" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-        array('tbody', 'tfoot', 'thead'))) {
-            /* Clear the stack back to a table context. */
-            $this->clearStackToTableContext($clear);
-
-            /* Insert an HTML element for the token, then switch the insertion
-            mode to "in table body". */
-            $this->insertElement($token);
-            $this->mode = self::IN_TABLE_BODY;
-
-        /* A start tag whose tag name is one of: "td", "th", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        in_array($token['name'], array('td', 'th', 'tr'))) {
-            /* Act as if a start tag token with the tag name "tbody" had been
-            seen, then reprocess the current token. */
-            $this->emitToken(array(
-                'name' => 'tbody',
-                'type' => HTML5_Tokenizer::STARTTAG,
-                'attr' => array()
-            ));
-
-            $this->emitToken($token);
-
-        /* A start tag whose tag name is "table" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'table') {
-            /* Parse error. Act as if an end tag token with the tag name "table"
-            had been seen, then, if that token wasn't ignored, reprocess the
-            current token. */
-            $this->emitToken(array(
-                'name' => 'table',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-
-            if (!$this->ignored) $this->emitToken($token);
-
-        /* An end tag whose tag name is "table" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'table') {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. (fragment case) */
-            if(!$this->elementInScope($token['name'], true)) {
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                do {
-                    $node = array_pop($this->stack);
-                } while ($node->tagName !== 'table');
-
-                /* Reset the insertion mode appropriately. */
-                $this->resetInsertionMode();
-            }
-
-        /* An end tag whose tag name is one of: "body", "caption", "col",
-        "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('body', 'caption', 'col', 'colgroup', 'html', 'tbody', 'td',
-        'tfoot', 'th', 'thead', 'tr'))) {
-            // Parse error. Ignore the token.
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        ($token['name'] === 'style' || $token['name'] === 'script')) {
-            $this->processWithRulesFor($token, self::IN_HEAD);
-
-        } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'input' &&
-        // assignment is intentional
-        /* If the token does not have an attribute with the name "type", or
-         * if it does, but that attribute's value is not an ASCII
-         * case-insensitive match for the string "hidden", then: act as
-         * described in the "anything else" entry below. */
-        ($type = $this->getAttr($token, 'type')) && strtolower($type) === 'hidden') {
-            // I.e., if its an input with the type attribute == 'hidden'
-            /* Otherwise */
-            // parse error
-            $this->insertElement($token);
-            array_pop($this->stack);
-        } elseif ($token['type'] === HTML5_Tokenizer::EOF) {
-            /* If the current node is not the root html element, then this is a parse error. */
-            if (end($this->stack)->tagName !== 'html') {
-                // Note: It can only be the current node in the fragment case.
-                // parse error
-            }
-            /* Stop parsing. */
-        /* Anything else */
-        } else {
-            /* Parse error. Process the token as if the insertion mode was "in
-            body", with the following exception: */
-
-            $old = $this->foster_parent;
-            $this->foster_parent = true;
-            $this->processWithRulesFor($token, self::IN_BODY);
-            $this->foster_parent = $old;
-        }
-    break;
-
-    case self::IN_CAPTION:
-        /* An end tag whose tag name is "caption" */
-        if($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'caption') {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. (fragment case) */
-            if(!$this->elementInScope($token['name'], true)) {
-                $this->ignored = true;
-                // Ignore
-
-            /* Otherwise: */
-            } else {
-                /* Generate implied end tags. */
-                $this->generateImpliedEndTags();
-
-                /* Now, if the current node is not a caption element, then this
-                is a parse error. */
-                // XERROR: implement
-
-                /* Pop elements from this stack until a caption element has
-                been popped from the stack. */
-                do {
-                    $node = array_pop($this->stack);
-                } while ($node->tagName !== 'caption');
-
-                /* Clear the list of active formatting elements up to the last
-                marker. */
-                $this->clearTheActiveFormattingElementsUpToTheLastMarker();
-
-                /* Switch the insertion mode to "in table". */
-                $this->mode = self::IN_TABLE;
-            }
-
-        /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-        "tbody", "td", "tfoot", "th", "thead", "tr", or an end tag whose tag
-        name is "table" */
-        } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-        array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
-        'thead', 'tr'))) || ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'table')) {
-            /* Parse error. Act as if an end tag with the tag name "caption"
-            had been seen, then, if that token wasn't ignored, reprocess the
-            current token. */
-            $this->emitToken(array(
-                'name' => 'caption',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-
-            if (!$this->ignored) $this->emitToken($token);
-
-        /* An end tag whose tag name is one of: "body", "col", "colgroup",
-        "html", "tbody", "td", "tfoot", "th", "thead", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('body', 'col', 'colgroup', 'html', 'tbody', 'tfoot', 'th',
-        'thead', 'tr'))) {
-            // Parse error. Ignore the token.
-            $this->ignored = true;
-
-        /* Anything else */
-        } else {
-            /* Process the token as if the insertion mode was "in body". */
-            $this->processWithRulesFor($token, self::IN_BODY);
-        }
-    break;
-
-    case self::IN_COLUMN_GROUP:
-        /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-        U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-        or U+0020 SPACE */
-        if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-            /* Append the character to the current node. */
-            $this->insertText($token['data']);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the current node with the data
-            attribute set to the data given in the comment token. */
-            $this->insertToken($token['data']);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* A start tag whose tag name is "col" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'col') {
-            /* Insert a col element for the token. Immediately pop the current
-            node off the stack of open elements. */
-            $this->insertElement($token);
-            array_pop($this->stack);
-            // XERROR: Acknowledge the token's self-closing flag, if it is set.
-
-        /* An end tag whose tag name is "colgroup" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'colgroup') {
-            /* If the current node is the root html element, then this is a
-            parse error, ignore the token. (fragment case) */
-            if(end($this->stack)->tagName === 'html') {
-                $this->ignored = true;
-
-            /* Otherwise, pop the current node (which will be a colgroup
-            element) from the stack of open elements. Switch the insertion
-            mode to "in table". */
-            } else {
-                array_pop($this->stack);
-                $this->mode = self::IN_TABLE;
-            }
-
-        /* An end tag whose tag name is "col" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'col') {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-
-        /* An end-of-file token */
-        /* If the current node is the root html  element */
-        } elseif($token['type'] === HTML5_Tokenizer::EOF && end($this->stack)->tagName === 'html') {
-            /* Stop parsing */
-
-        /* Anything else */
-        } else {
-            /* Act as if an end tag with the tag name "colgroup" had been seen,
-            and then, if that token wasn't ignored, reprocess the current token. */
-            $this->emitToken(array(
-                'name' => 'colgroup',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-
-            if (!$this->ignored) $this->emitToken($token);
-        }
-    break;
-
-    case self::IN_TABLE_BODY:
-        $clear = array('tbody', 'tfoot', 'thead', 'html');
-
-        /* A start tag whose tag name is "tr" */
-        if($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'tr') {
-            /* Clear the stack back to a table body context. */
-            $this->clearStackToTableContext($clear);
-
-            /* Insert a tr element for the token, then switch the insertion
-            mode to "in row". */
-            $this->insertElement($token);
-            $this->mode = self::IN_ROW;
-
-        /* A start tag whose tag name is one of: "th", "td" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        ($token['name'] === 'th' ||    $token['name'] === 'td')) {
-            /* Parse error. Act as if a start tag with the tag name "tr" had
-            been seen, then reprocess the current token. */
-            $this->emitToken(array(
-                'name' => 'tr',
-                'type' => HTML5_Tokenizer::STARTTAG,
-                'attr' => array()
-            ));
-
-            $this->emitToken($token);
-
-        /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. */
-            if(!$this->elementInScope($token['name'], true)) {
-                // Parse error
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                /* Clear the stack back to a table body context. */
-                $this->clearStackToTableContext($clear);
-
-                /* Pop the current node from the stack of open elements. Switch
-                the insertion mode to "in table". */
-                array_pop($this->stack);
-                $this->mode = self::IN_TABLE;
-            }
-
-        /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-        "tbody", "tfoot", "thead", or an end tag whose tag name is "table" */
-        } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-        array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead'))) ||
-        ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
-            /* If the stack of open elements does not have a tbody, thead, or
-            tfoot element in table scope, this is a parse error. Ignore the
-            token. (fragment case) */
-            if(!$this->elementInScope(array('tbody', 'thead', 'tfoot'), true)) {
-                // parse error
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                /* Clear the stack back to a table body context. */
-                $this->clearStackToTableContext($clear);
-
-                /* Act as if an end tag with the same tag name as the current
-                node ("tbody", "tfoot", or "thead") had been seen, then
-                reprocess the current token. */
-                $this->emitToken(array(
-                    'name' => end($this->stack)->tagName,
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-
-                $this->emitToken($token);
-            }
-
-        /* An end tag whose tag name is one of: "body", "caption", "col",
-        "colgroup", "html", "td", "th", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th', 'tr'))) {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-
-        /* Anything else */
-        } else {
-            /* Process the token as if the insertion mode was "in table". */
-            $this->processWithRulesFor($token, self::IN_TABLE);
-        }
-    break;
-
-    case self::IN_ROW:
-        $clear = array('tr', 'html');
-
-        /* A start tag whose tag name is one of: "th", "td" */
-        if($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        ($token['name'] === 'th' || $token['name'] === 'td')) {
-            /* Clear the stack back to a table row context. */
-            $this->clearStackToTableContext($clear);
-
-            /* Insert an HTML element for the token, then switch the insertion
-            mode to "in cell". */
-            $this->insertElement($token);
-            $this->mode = self::IN_CELL;
-
-            /* Insert a marker at the end of the list of active formatting
-            elements. */
-            $this->a_formatting[] = self::MARKER;
-
-        /* An end tag whose tag name is "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'tr') {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. (fragment case) */
-            if(!$this->elementInScope($token['name'], true)) {
-                // Ignore.
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                /* Clear the stack back to a table row context. */
-                $this->clearStackToTableContext($clear);
-
-                /* Pop the current node (which will be a tr element) from the
-                stack of open elements. Switch the insertion mode to "in table
-                body". */
-                array_pop($this->stack);
-                $this->mode = self::IN_TABLE_BODY;
-            }
-
-        /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-        "tbody", "tfoot", "thead", "tr" or an end tag whose tag name is "table" */
-        } elseif(($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-        array('caption', 'col', 'colgroup', 'tbody', 'tfoot', 'thead', 'tr'))) ||
-        ($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'table')) {
-            /* Act as if an end tag with the tag name "tr" had been seen, then,
-            if that token wasn't ignored, reprocess the current token. */
-            $this->emitToken(array(
-                'name' => 'tr',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-            if (!$this->ignored) $this->emitToken($token);
-
-        /* An end tag whose tag name is one of: "tbody", "tfoot", "thead" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        in_array($token['name'], array('tbody', 'tfoot', 'thead'))) {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. */
-            if(!$this->elementInScope($token['name'], true)) {
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                /* Otherwise, act as if an end tag with the tag name "tr" had
-                been seen, then reprocess the current token. */
-                $this->emitToken(array(
-                    'name' => 'tr',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-
-                $this->emitToken($token);
-            }
-
-        /* An end tag whose tag name is one of: "body", "caption", "col",
-        "colgroup", "html", "td", "th" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('body', 'caption', 'col', 'colgroup', 'html', 'td', 'th'))) {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-
-        /* Anything else */
-        } else {
-            /* Process the token as if the insertion mode was "in table". */
-            $this->processWithRulesFor($token, self::IN_TABLE);
-        }
-    break;
-
-    case self::IN_CELL:
-        /* An end tag whose tag name is one of: "td", "th" */
-        if($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        ($token['name'] === 'td' || $token['name'] === 'th')) {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as that of the token, then this is a
-            parse error and the token must be ignored. */
-            if(!$this->elementInScope($token['name'], true)) {
-                $this->ignored = true;
-
-            /* Otherwise: */
-            } else {
-                /* Generate implied end tags, except for elements with the same
-                tag name as the token. */
-                $this->generateImpliedEndTags(array($token['name']));
-
-                /* Now, if the current node is not an element with the same tag
-                name as the token, then this is a parse error. */
-                // XERROR: Implement parse error code
-
-                /* Pop elements from this stack until an element with the same
-                tag name as the token has been popped from the stack. */
-                do {
-                    $node = array_pop($this->stack);
-                } while ($node->tagName !== $token['name']);
-
-                /* Clear the list of active formatting elements up to the last
-                marker. */
-                $this->clearTheActiveFormattingElementsUpToTheLastMarker();
-
-                /* Switch the insertion mode to "in row". (The current node
-                will be a tr element at this point.) */
-                $this->mode = self::IN_ROW;
-            }
-
-        /* A start tag whose tag name is one of: "caption", "col", "colgroup",
-        "tbody", "td", "tfoot", "th", "thead", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && in_array($token['name'],
-        array('caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
-        'thead', 'tr'))) {
-            /* If the stack of open elements does not have a td or th element
-            in table scope, then this is a parse error; ignore the token.
-            (fragment case) */
-            if(!$this->elementInScope(array('td', 'th'), true)) {
-                // parse error
-                $this->ignored = true;
-
-            /* Otherwise, close the cell (see below) and reprocess the current
-            token. */
-            } else {
-                $this->closeCell();
-                $this->emitToken($token);
-            }
-
-        /* An end tag whose tag name is one of: "body", "caption", "col",
-        "colgroup", "html" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('body', 'caption', 'col', 'colgroup', 'html'))) {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-
-        /* An end tag whose tag name is one of: "table", "tbody", "tfoot",
-        "thead", "tr" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && in_array($token['name'],
-        array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
-            /* If the stack of open elements does not have a td or th element
-            in table scope, then this is a parse error; ignore the token.
-            (innerHTML case) */
-            if(!$this->elementInScope(array('td', 'th'), true)) {
-                // Parse error
-                $this->ignored = true;
-
-            /* Otherwise, close the cell (see below) and reprocess the current
-            token. */
-            } else {
-                $this->closeCell();
-                $this->emitToken($token);
-            }
-
-        /* Anything else */
-        } else {
-            /* Process the token as if the insertion mode was "in body". */
-            $this->processWithRulesFor($token, self::IN_BODY);
-        }
-    break;
-
-    case self::IN_SELECT:
-        /* Handle the token as follows: */
-
-        /* A character token */
-        if(
-            $token['type'] === HTML5_Tokenizer::CHARACTER ||
-            $token['type'] === HTML5_Tokenizer::SPACECHARACTER
-        ) {
-            /* Append the token's character to the current node. */
-            $this->insertText($token['data']);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the current node with the data
-            attribute set to the data given in the comment token. */
-            $this->insertComment($token['data']);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-            $this->processWithRulesFor($token, self::INBODY);
-
-        /* A start tag token whose tag name is "option" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'option') {
-            /* If the current node is an option element, act as if an end tag
-            with the tag name "option" had been seen. */
-            if(end($this->stack)->tagName === 'option') {
-                $this->emitToken(array(
-                    'name' => 'option',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-            }
-
-            /* Insert an HTML element for the token. */
-            $this->insertElement($token);
-
-        /* A start tag token whose tag name is "optgroup" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'optgroup') {
-            /* If the current node is an option element, act as if an end tag
-            with the tag name "option" had been seen. */
-            if(end($this->stack)->tagName === 'option') {
-                $this->emitToken(array(
-                    'name' => 'option',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-            }
-
-            /* If the current node is an optgroup element, act as if an end tag
-            with the tag name "optgroup" had been seen. */
-            if(end($this->stack)->tagName === 'optgroup') {
-                $this->emitToken(array(
-                    'name' => 'optgroup',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-            }
-
-            /* Insert an HTML element for the token. */
-            $this->insertElement($token);
-
-        /* An end tag token whose tag name is "optgroup" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'optgroup') {
-            /* First, if the current node is an option element, and the node
-            immediately before it in the stack of open elements is an optgroup
-            element, then act as if an end tag with the tag name "option" had
-            been seen. */
-            $elements_in_stack = count($this->stack);
-
-            if($this->stack[$elements_in_stack - 1]->tagName === 'option' &&
-            $this->stack[$elements_in_stack - 2]->tagName === 'optgroup') {
-                $this->emitToken(array(
-                    'name' => 'option',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-            }
-
-            /* If the current node is an optgroup element, then pop that node
-            from the stack of open elements. Otherwise, this is a parse error,
-            ignore the token. */
-            if(end($this->stack)->tagName === 'optgroup') {
-                array_pop($this->stack);
-            } else {
-                // parse error
-                $this->ignored = true;
-            }
-
-        /* An end tag token whose tag name is "option" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'option') {
-            /* If the current node is an option element, then pop that node
-            from the stack of open elements. Otherwise, this is a parse error,
-            ignore the token. */
-            if(end($this->stack)->tagName === 'option') {
-                array_pop($this->stack);
-            } else {
-                // parse error
-                $this->ignored = true;
-            }
-
-        /* An end tag whose tag name is "select" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'select') {
-            /* If the stack of open elements does not have an element in table
-            scope with the same tag name as the token, this is a parse error.
-            Ignore the token. (fragment case) */
-            if(!$this->elementInScope($token['name'], true)) {
-                $this->ignored = true;
-                // parse error
-
-            /* Otherwise: */
-            } else {
-                /* Pop elements from the stack of open elements until a select
-                element has been popped from the stack. */
-                do {
-                    $node = array_pop($this->stack);
-                } while ($node->tagName !== 'select');
-
-                /* Reset the insertion mode appropriately. */
-                $this->resetInsertionMode();
-            }
-
-        /* A start tag whose tag name is "select" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'select') {
-            /* Parse error. Act as if the token had been an end tag with the
-            tag name "select" instead. */
-            $this->emitToken(array(
-                'name' => 'select',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        ($token['name'] === 'input' || $token['name'] === 'textarea')) {
-            // parse error
-            $this->emitToken(array(
-                'name' => 'select',
-                'type' => HTML5_Tokenizer::ENDTAG
-            ));
-            $this->emitToken($token);
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'script') {
-            $this->processWithRulesFor($token, self::IN_HEAD);
-
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            // XERROR: If the current node is not the root html element, then this is a parse error.
-            /* Stop parsing */
-
-        /* Anything else */
-        } else {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-        }
-    break;
-
-    case self::IN_SELECT_IN_TABLE:
-
-        if($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        in_array($token['name'], array('caption', 'table', 'tbody',
-        'tfoot', 'thead', 'tr', 'td', 'th'))) {
-            // parse error
-            $this->emitToken(array(
-                'name' => 'select',
-                'type' => HTML5_Tokenizer::ENDTAG,
-            ));
-            $this->emitToken($token);
-
-        /* An end tag whose tag name is one of: "caption", "table", "tbody",
-        "tfoot", "thead", "tr", "td", "th" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        in_array($token['name'], array('caption', 'table', 'tbody', 'tfoot', 'thead', 'tr', 'td', 'th')))  {
-            /* Parse error. */
-            // parse error
-
-            /* If the stack of open elements has an element in table scope with
-            the same tag name as that of the token, then act as if an end tag
-            with the tag name "select" had been seen, and reprocess the token.
-            Otherwise, ignore the token. */
-            if($this->elementInScope($token['name'], true)) {
-                $this->emitToken(array(
-                    'name' => 'select',
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-
-                $this->emitToken($token);
-            } else {
-                $this->ignored = true;
-            }
-        } else {
-            $this->processWithRulesFor($token, self::IN_SELECT);
-        }
-    break;
-
-    case self::IN_FOREIGN_CONTENT:
-        if ($token['type'] === HTML5_Tokenizer::CHARACTER ||
-        $token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-            $this->insertText($token['data']);
-        } elseif ($token['type'] === HTML5_Tokenizer::COMMENT) {
-            $this->insertComment($token['data']);
-        } elseif ($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // XERROR: parse error
-        } elseif ($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'script' && end($this->stack)->tagName === 'script' &&
-        end($this->stack)->namespaceURI === self::NS_SVG) {
-            array_pop($this->stack);
-            // a bunch of script running mumbo jumbo
-        } elseif (
-            ($token['type'] === HTML5_Tokenizer::STARTTAG &&
-                ((
-                    $token['name'] !== 'mglyph' &&
-                    $token['name'] !== 'malignmark' &&
-                    end($this->stack)->namespaceURI === self::NS_MATHML &&
-                    in_array(end($this->stack)->tagName, array('mi', 'mo', 'mn', 'ms', 'mtext'))
-                ) ||
-                (
-                    $token['name'] === 'svg' &&
-                    end($this->stack)->namespaceURI === self::NS_MATHML &&
-                    end($this->stack)->tagName === 'annotation-xml'
-                ) ||
-                (
-                    end($this->stack)->namespaceURI === self::NS_SVG &&
-                    in_array(end($this->stack)->tagName, array('foreignObject', 'desc', 'title'))
-                ) ||
-                (
-                    // XSKETCHY
-                    end($this->stack)->namespaceURI === self::NS_HTML
-                ))
-            ) || $token['type'] === HTML5_Tokenizer::ENDTAG
-        ) {
-            $this->processWithRulesFor($token, $this->secondary_mode);
-            /* If, after doing so, the insertion mode is still "in foreign 
-             * content", but there is no element in scope that has a namespace 
-             * other than the HTML namespace, switch the insertion mode to the 
-             * secondary insertion mode. */
-            if ($this->mode === self::IN_FOREIGN_CONTENT) {
-                $found = false;
-                // this basically duplicates elementInScope()
-                for ($i = count($this->stack) - 1; $i >= 0; $i--) {
-                    $node = $this->stack[$i];
-                    if ($node->namespaceURI !== self::NS_HTML) {
-                        $found = true;
-                        break;
-                    } elseif (in_array($node->tagName, array('table', 'html',
-                    'applet', 'caption', 'td', 'th', 'button', 'marquee',
-                    'object')) || ($node->tagName === 'foreignObject' &&
-                    $node->namespaceURI === self::NS_SVG)) {
-                        break;
-                    }
-                }
-                if (!$found) {
-                    $this->mode = $this->secondary_mode;
-                }
-            }
-        } elseif ($token['type'] === HTML5_Tokenizer::EOF || (
-        $token['type'] === HTML5_Tokenizer::STARTTAG &&
-        (in_array($token['name'], array('b', "big", "blockquote", "body", "br", 
-        "center", "code", "dd", "div", "dl", "dt", "em", "embed", "h1", "h2", 
-        "h3", "h4", "h5", "h6", "head", "hr", "i", "img", "li", "listing", 
-        "menu", "meta", "nobr", "ol", "p", "pre", "ruby", "s",  "small", 
-        "span", "strong", "strike",  "sub", "sup", "table", "tt", "u", "ul", 
-        "var")) || ($token['name'] === 'font' && ($this->getAttr($token, 'color') ||
-        $this->getAttr($token, 'face') || $this->getAttr($token, 'size')))))) {
-            // XERROR: parse error
-            do {
-                $node = array_pop($this->stack);
-            } while ($node->namespaceURI !== self::NS_HTML);
-            $this->stack[] = $node;
-            $this->mode = $this->secondary_mode;
-            $this->emitToken($token);
-        } elseif ($token['type'] === HTML5_Tokenizer::STARTTAG) {
-            static $svg_lookup = array(
-                'altglyph' => 'altGlyph',
-                'altglyphdef' => 'altGlyphDef',
-                'altglyphitem' => 'altGlyphItem',
-                'animatecolor' => 'animateColor',
-                'animatemotion' => 'animateMotion',
-                'animatetransform' => 'animateTransform',
-                'clippath' => 'clipPath',
-                'feblend' => 'feBlend',
-                'fecolormatrix' => 'feColorMatrix',
-                'fecomponenttransfer' => 'feComponentTransfer',
-                'fecomposite' => 'feComposite',
-                'feconvolvematrix' => 'feConvolveMatrix',
-                'fediffuselighting' => 'feDiffuseLighting',
-                'fedisplacementmap' => 'feDisplacementMap',
-                'fedistantlight' => 'feDistantLight',
-                'feflood' => 'feFlood',
-                'fefunca' => 'feFuncA',
-                'fefuncb' => 'feFuncB',
-                'fefuncg' => 'feFuncG',
-                'fefuncr' => 'feFuncR',
-                'fegaussianblur' => 'feGaussianBlur',
-                'feimage' => 'feImage',
-                'femerge' => 'feMerge',
-                'femergenode' => 'feMergeNode',
-                'femorphology' => 'feMorphology',
-                'feoffset' => 'feOffset',
-                'fepointlight' => 'fePointLight',
-                'fespecularlighting' => 'feSpecularLighting',
-                'fespotlight' => 'feSpotLight',
-                'fetile' => 'feTile',
-                'feturbulence' => 'feTurbulence',
-                'foreignobject' => 'foreignObject',
-                'glyphref' => 'glyphRef',
-                'lineargradient' => 'linearGradient',
-                'radialgradient' => 'radialGradient',
-                'textpath' => 'textPath',
-            );
-            $current = end($this->stack);
-            if ($current->namespaceURI === self::NS_MATHML) {
-                $token = $this->adjustMathMLAttributes($token);
-            }
-            if ($current->namespaceURI === self::NS_SVG &&
-            isset($svg_lookup[$token['name']])) {
-                $token['name'] = $svg_lookup[$token['name']];
-            }
-            if ($current->namespaceURI === self::NS_SVG) {
-                $token = $this->adjustSVGAttributes($token);
-            }
-            $token = $this->adjustForeignAttributes($token);
-            $this->insertForeignElement($token, $current->namespaceURI);
-            if (isset($token['self-closing'])) {
-                array_pop($this->stack);
-                // XERROR: acknowledge self-closing flag
-            }
-        }
-    break;
-
-    case self::AFTER_BODY:
-        /* Handle the token as follows: */
-
-        /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-        U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-        or U+0020 SPACE */
-        if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-            /* Process the token as it would be processed if the insertion mode
-            was "in body". */
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the first element in the stack of open
-            elements (the html element), with the data attribute set to the
-            data given in the comment token. */
-            $comment = $this->dom->createComment($token['data']);
-            $this->stack[0]->appendChild($comment);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* An end tag with the tag name "html" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG && $token['name'] === 'html') {
-            /*     If the parser was originally created as part of the HTML
-             *     fragment parsing algorithm, this is a parse error; ignore
-             *     the token. (fragment case) */
-            $this->ignored = true;
-            // XERROR: implement this
-
-            $this->mode = self::AFTER_AFTER_BODY;
-
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            /* Stop parsing */
-
-        /* Anything else */
-        } else {
-            /* Parse error. Set the insertion mode to "in body" and reprocess
-            the token. */
-            $this->mode = self::IN_BODY;
-            $this->emitToken($token);
-        }
-    break;
-
-    case self::IN_FRAMESET:
-        /* Handle the token as follows: */
-
-        /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-        U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-        U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
-        if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-            /* Append the character to the current node. */
-            $this->insertText($token['data']);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the current node with the data
-            attribute set to the data given in the comment token. */
-            $this->insertComment($token['data']);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        /* A start tag with the tag name "frameset" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'frameset') {
-            $this->insertElement($token);
-
-        /* An end tag with the tag name "frameset" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'frameset') {
-            /* If the current node is the root html element, then this is a
-            parse error; ignore the token. (fragment case) */
-            if(end($this->stack)->tagName === 'html') {
-                $this->ignored = true;
-                // Parse error
-
-            } else {
-                /* Otherwise, pop the current node from the stack of open
-                elements. */
-                array_pop($this->stack);
-
-                /* If the parser was not originally created as part of the HTML 
-                 * fragment parsing algorithm  (fragment case), and the current 
-                 * node is no longer a frameset element, then switch the 
-                 * insertion mode to "after frameset". */
-                $this->mode = self::AFTER_FRAMESET;
-            }
-
-        /* A start tag with the tag name "frame" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'frame') {
-            /* Insert an HTML element for the token. */
-            $this->insertElement($token);
-
-            /* Immediately pop the current node off the stack of open elements. */
-            array_pop($this->stack);
-
-            // XERROR: Acknowledge the token's self-closing flag, if it is set.
-
-        /* A start tag with the tag name "noframes" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'noframes') {
-            /* Process the token using the rules for the "in head" insertion mode. */
-            $this->processwithRulesFor($token, self::IN_HEAD);
-
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            // XERROR: If the current node is not the root html element, then this is a parse error.
-            /* Stop parsing */
-        /* Anything else */
-        } else {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-        }
-    break;
-
-    case self::AFTER_FRAMESET:
-        /* Handle the token as follows: */
-
-        /* A character token that is one of one of U+0009 CHARACTER TABULATION,
-        U+000A LINE FEED (LF), U+000B LINE TABULATION, U+000C FORM FEED (FF),
-        U+000D CARRIAGE RETURN (CR), or U+0020 SPACE */
-        if($token['type'] === HTML5_Tokenizer::SPACECHARACTER) {
-            /* Append the character to the current node. */
-            $this->insertText($token['data']);
-
-        /* A comment token */
-        } elseif($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the current node with the data
-            attribute set to the data given in the comment token. */
-            $this->insertComment($token['data']);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE) {
-            // parse error
-
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html') {
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* An end tag with the tag name "html" */
-        } elseif($token['type'] === HTML5_Tokenizer::ENDTAG &&
-        $token['name'] === 'html') {
-            $this->mode = self::AFTER_AFTER_FRAMESET;
-
-        /* A start tag with the tag name "noframes" */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG &&
-        $token['name'] === 'noframes') {
-            $this->processWithRulesFor($token, self::IN_HEAD);
-
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            /* Stop parsing */
-
-        /* Anything else */
-        } else {
-            /* Parse error. Ignore the token. */
-            $this->ignored = true;
-        }
-    break;
-
-    case self::AFTER_AFTER_BODY:
-        /* A comment token */
-        if($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the Document object with the data
-            attribute set to the data given in the comment token. */
-            $comment = $this->dom->createComment($token['data']);
-            $this->dom->appendChild($comment);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE ||
-        $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
-        ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* An end-of-file token */
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            /* OMG DONE!! */
-        } else {
-            // parse error
-            $this->mode = self::IN_BODY;
-            $this->emitToken($token);
-        }
-    break;
-
-    case self::AFTER_AFTER_FRAMESET:
-        /* A comment token */
-        if($token['type'] === HTML5_Tokenizer::COMMENT) {
-            /* Append a Comment node to the Document object with the data
-            attribute set to the data given in the comment token. */
-            $comment = $this->dom->createComment($token['data']);
-            $this->dom->appendChild($comment);
-
-        } elseif($token['type'] === HTML5_Tokenizer::DOCTYPE ||
-        $token['type'] === HTML5_Tokenizer::SPACECHARACTER ||
-        ($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'html')) {
-            $this->processWithRulesFor($token, self::IN_BODY);
-
-        /* An end-of-file token */
-        } elseif($token['type'] === HTML5_Tokenizer::EOF) {
-            /* OMG DONE!! */
-        } elseif($token['type'] === HTML5_Tokenizer::STARTTAG && $token['name'] === 'nofrmaes') {
-            $this->processWithRulesFor($token, self::IN_HEAD);
-        } else {
-            // parse error
-        }
-    break;
-    }
-        // end funky indenting
-        }
-
-    private function insertElement($token, $append = true) {
-        $el = $this->dom->createElementNS(self::NS_HTML, $token['name']);
-
-        if (!empty($token['attr'])) {
-            foreach($token['attr'] as $attr) {
-
-				// mike@macgirvin.com 2011-11-17, check attribute name for
-				// validity (ignoring extenders and combiners) as illegal chars in names
-				// causes everything to abort
-
- 				$valid = preg_match('/^[a-zA-Z\_\:]([\-a-zA-Z0-9\_\:\.]+$)/',$attr['name'],$matches);
-                if($attr['name'] && (!$el->hasAttribute($attr['name'])) && ($valid)) {
-                    $el->setAttribute($attr['name'], $attr['value']);
-                }
-            }
-        }
-        if ($append) {
-            $this->appendToRealParent($el);
-            $this->stack[] = $el;
-        }
-
-        return $el;
-    }
-
-    private function insertText($data) {
-        if ($data === '') return;
-        if ($this->ignore_lf_token) {
-            if ($data[0] === "\n") {
-                $data = substr($data, 1);
-                if ($data === false) return;
-            }
-        }
-        $text = $this->dom->createTextNode($data);
-        $this->appendToRealParent($text);
-    }
-
-    private function insertComment($data) {
-        $comment = $this->dom->createComment($data);
-        $this->appendToRealParent($comment);
-    }
-
-    private function appendToRealParent($node) {
-        // this is only for the foster_parent case
-        /* If the current node is a table, tbody, tfoot, thead, or tr
-        element, then, whenever a node would be inserted into the current
-        node, it must instead be inserted into the foster parent element. */
-        if(!$this->foster_parent || !in_array(end($this->stack)->tagName,
-        array('table', 'tbody', 'tfoot', 'thead', 'tr'))) {
-            end($this->stack)->appendChild($node);
-        } else {
-            $this->fosterParent($node);
-        }
-    }
-
-    private function elementInScope($el, $table = false) {
-        if(is_array($el)) {
-            foreach($el as $element) {
-                if($this->elementInScope($element, $table)) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-
-        $leng = count($this->stack);
-
-        for($n = 0; $n < $leng; $n++) {
-            /* 1. Initialise node to be the current node (the bottommost node of
-            the stack). */
-            $node = $this->stack[$leng - 1 - $n];
-
-            if($node->tagName === $el) {
-                /* 2. If node is the target node, terminate in a match state. */
-                return true;
-
-            // these are the common states for "in scope" and "in table scope"
-            } elseif($node->tagName === 'table' || $node->tagName === 'html') {
-                return false;
-
-            // these are only valid for "in scope"
-            } elseif(!$table &&
-            (in_array($node->tagName, array('applet', 'caption', 'td',
-                'th', 'button', 'marquee', 'object')) ||
-                $node->tagName === 'foreignObject' && $node->namespaceURI === self::NS_SVG)) {
-                return false;
-            }
-
-            /* Otherwise, set node to the previous entry in the stack of open
-            elements and return to step 2. (This will never fail, since the loop
-            will always terminate in the previous step if the top of the stack
-            is reached.) */
-        }
-    }
-
-    private function reconstructActiveFormattingElements() {
-        /* 1. If there are no entries in the list of active formatting elements,
-        then there is nothing to reconstruct; stop this algorithm. */
-        $formatting_elements = count($this->a_formatting);
-
-        if($formatting_elements === 0) {
-            return false;
-        }
-
-        /* 3. Let entry be the last (most recently added) element in the list
-        of active formatting elements. */
-        $entry = end($this->a_formatting);
-
-        /* 2. If the last (most recently added) entry in the list of active
-        formatting elements is a marker, or if it is an element that is in the
-        stack of open elements, then there is nothing to reconstruct; stop this
-        algorithm. */
-        if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
-            return false;
-        }
-
-        for($a = $formatting_elements - 1; $a >= 0; true) {
-            /* 4. If there are no entries before entry in the list of active
-            formatting elements, then jump to step 8. */
-            if($a === 0) {
-                $step_seven = false;
-                break;
-            }
-
-            /* 5. Let entry be the entry one earlier than entry in the list of
-            active formatting elements. */
-            $a--;
-            $entry = $this->a_formatting[$a];
-
-            /* 6. If entry is neither a marker nor an element that is also in
-            thetack of open elements, go to step 4. */
-            if($entry === self::MARKER || in_array($entry, $this->stack, true)) {
-                break;
-            }
-        }
-
-        while(true) {
-            /* 7. Let entry be the element one later than entry in the list of
-            active formatting elements. */
-            if(isset($step_seven) && $step_seven === true) {
-                $a++;
-                $entry = $this->a_formatting[$a];
-            }
-
-            /* 8. Perform a shallow clone of the element entry to obtain clone. */
-            $clone = $entry->cloneNode();
-
-            /* 9. Append clone to the current node and push it onto the stack
-            of open elements  so that it is the new current node. */
-            $this->appendToRealParent($clone);
-            $this->stack[] = $clone;
-
-            /* 10. Replace the entry for entry in the list with an entry for
-            clone. */
-            $this->a_formatting[$a] = $clone;
-
-            /* 11. If the entry for clone in the list of active formatting
-            elements is not the last entry in the list, return to step 7. */
-            if(end($this->a_formatting) !== $clone) {
-                $step_seven = true;
-            } else {
-                break;
-            }
-        }
-    }
-
-    private function clearTheActiveFormattingElementsUpToTheLastMarker() {
-        /* When the steps below require the UA to clear the list of active
-        formatting elements up to the last marker, the UA must perform the
-        following steps: */
-
-        while(true) {
-            /* 1. Let entry be the last (most recently added) entry in the list
-            of active formatting elements. */
-            $entry = end($this->a_formatting);
-
-            /* 2. Remove entry from the list of active formatting elements. */
-            array_pop($this->a_formatting);
-
-            /* 3. If entry was a marker, then stop the algorithm at this point.
-            The list has been cleared up to the last marker. */
-            if($entry === self::MARKER) {
-                break;
-            }
-        }
-    }
-
-    private function generateImpliedEndTags($exclude = array()) {
-        /* When the steps below require the UA to generate implied end tags,
-        then, if the current node is a dd element, a dt element, an li element,
-        a p element, a td element, a th  element, or a tr element, the UA must
-        act as if an end tag with the respective tag name had been seen and
-        then generate implied end tags again. */
-        $node = end($this->stack);
-        $elements = array_diff(array('dd', 'dt', 'li', 'p', 'td', 'th', 'tr'), $exclude);
-
-        while(in_array(end($this->stack)->tagName, $elements)) {
-            array_pop($this->stack);
-        }
-    }
-
-    private function getElementCategory($node) {
-        if (!is_object($node)) debug_print_backtrace();
-        $name = $node->tagName;
-        if(in_array($name, $this->special))
-            return self::SPECIAL;
-
-        elseif(in_array($name, $this->scoping))
-            return self::SCOPING;
-
-        elseif(in_array($name, $this->formatting))
-            return self::FORMATTING;
-
-        else
-            return self::PHRASING;
-    }
-
-    private function clearStackToTableContext($elements) {
-        /* When the steps above require the UA to clear the stack back to a
-        table context, it means that the UA must, while the current node is not
-        a table element or an html element, pop elements from the stack of open
-        elements. */
-        while(true) {
-            $name = end($this->stack)->tagName;
-
-            if(in_array($name, $elements)) {
-                break;
-            } else {
-                array_pop($this->stack);
-            }
-        }
-    }
-
-    private function resetInsertionMode($context = null) {
-        /* 1. Let last be false. */
-        $last = false;
-        $leng = count($this->stack);
-
-        for($n = $leng - 1; $n >= 0; $n--) {
-            /* 2. Let node be the last node in the stack of open elements. */
-            $node = $this->stack[$n];
-
-            /* 3. If node is the first node in the stack of open elements, then 
-             * set last to true and set node to the context  element. (fragment 
-             * case) */
-            if($this->stack[0]->isSameNode($node)) {
-                $last = true;
-                $node = $context;
-            }
-
-            /* 4. If node is a select element, then switch the insertion mode to
-            "in select" and abort these steps. (fragment case) */
-            if($node->tagName === 'select') {
-                $this->mode = self::IN_SELECT;
-                break;
-
-            /* 5. If node is a td or th element, then switch the insertion mode
-            to "in cell" and abort these steps. */
-            } elseif($node->tagName === 'td' || $node->nodeName === 'th') {
-                $this->mode = self::IN_CELL;
-                break;
-
-            /* 6. If node is a tr element, then switch the insertion mode to
-            "in    row" and abort these steps. */
-            } elseif($node->tagName === 'tr') {
-                $this->mode = self::IN_ROW;
-                break;
-
-            /* 7. If node is a tbody, thead, or tfoot element, then switch the
-            insertion mode to "in table body" and abort these steps. */
-            } elseif(in_array($node->tagName, array('tbody', 'thead', 'tfoot'))) {
-                $this->mode = self::IN_TABLE_BODY;
-                break;
-
-            /* 8. If node is a caption element, then switch the insertion mode
-            to "in caption" and abort these steps. */
-            } elseif($node->tagName === 'caption') {
-                $this->mode = self::IN_CAPTION;
-                break;
-
-            /* 9. If node is a colgroup element, then switch the insertion mode
-            to "in column group" and abort these steps. (innerHTML case) */
-            } elseif($node->tagName === 'colgroup') {
-                $this->mode = self::IN_COLUMN_GROUP;
-                break;
-
-            /* 10. If node is a table element, then switch the insertion mode
-            to "in table" and abort these steps. */
-            } elseif($node->tagName === 'table') {
-                $this->mode = self::IN_TABLE;
-                break;
-
-            /* 11. If node is an element from the MathML namespace or the SVG 
-             * namespace, then switch the insertion mode to "in foreign 
-             * content", let the secondary insertion mode be "in body", and 
-             * abort these steps. */
-            } elseif($node->namespaceURI === self::NS_SVG ||
-            $node->namespaceURI === self::NS_MATHML) {
-                $this->mode = self::IN_FOREIGN_CONTENT;
-                $this->secondary_mode = self::IN_BODY;
-                break;
-
-            /* 12. If node is a head element, then switch the insertion mode
-            to "in body" ("in body"! not "in head"!) and abort these steps.
-            (fragment case) */
-            } elseif($node->tagName === 'head') {
-                $this->mode = self::IN_BODY;
-                break;
-
-            /* 13. If node is a body element, then switch the insertion mode to
-            "in body" and abort these steps. */
-            } elseif($node->tagName === 'body') {
-                $this->mode = self::IN_BODY;
-                break;
-
-            /* 14. If node is a frameset element, then switch the insertion
-            mode to "in frameset" and abort these steps. (fragment case) */
-            } elseif($node->tagName === 'frameset') {
-                $this->mode = self::IN_FRAMESET;
-                break;
-
-            /* 15. If node is an html element, then: if the head element
-            pointer is null, switch the insertion mode to "before head",
-            otherwise, switch the insertion mode to "after head". In either
-            case, abort these steps. (fragment case) */
-            } elseif($node->tagName === 'html') {
-                $this->mode = ($this->head_pointer === null)
-                    ? self::BEFORE_HEAD
-                    : self::AFTER_HEAD;
-
-                break;
-
-            /* 16. If last is true, then set the insertion mode to "in body"
-            and    abort these steps. (fragment case) */
-            } elseif($last) {
-                $this->mode = self::IN_BODY;
-                break;
-            }
-        }
-    }
-
-    private function closeCell() {
-        /* If the stack of open elements has a td or th element in table scope,
-        then act as if an end tag token with that tag name had been seen. */
-        foreach(array('td', 'th') as $cell) {
-            if($this->elementInScope($cell, true)) {
-                $this->emitToken(array(
-                    'name' => $cell,
-                    'type' => HTML5_Tokenizer::ENDTAG
-                ));
-
-                break;
-            }
-        }
-    }
-
-    private function processWithRulesFor($token, $mode) {
-        /* "using the rules for the m insertion mode", where m is one of these
-         * modes, the user agent must use the rules described under the m
-         * insertion mode's section, but must leave the insertion mode
-         * unchanged unless the rules in m themselves switch the insertion mode
-         * to a new value. */
-        return $this->emitToken($token, $mode);
-    }
-
-    private function insertCDATAElement($token) {
-        $this->insertElement($token);
-        $this->original_mode = $this->mode;
-        $this->mode = self::IN_CDATA_RCDATA;
-        $this->content_model = HTML5_Tokenizer::CDATA;
-    }
-
-    private function insertRCDATAElement($token) {
-        $this->insertElement($token);
-        $this->original_mode = $this->mode;
-        $this->mode = self::IN_CDATA_RCDATA;
-        $this->content_model = HTML5_Tokenizer::RCDATA;
-    }
-
-    private function getAttr($token, $key) {
-        if (!isset($token['attr'])) return false;
-        $ret = false;
-        foreach ($token['attr'] as $keypair) {
-            if ($keypair['name'] === $key) $ret = $keypair['value'];
-        }
-        return $ret;
-    }
-
-    private function getCurrentTable() {
-        /* The current table is the last table  element in the stack of open 
-         * elements, if there is one. If there is no table element in the stack 
-         * of open elements (fragment case), then the current table is the 
-         * first element in the stack of open elements (the html element). */
-        for ($i = count($this->stack) - 1; $i >= 0; $i--) {
-            if ($this->stack[$i]->tagName === 'table') {
-                return $this->stack[$i];
-            }
-        }
-        return $this->stack[0];
-    }
-
-    private function getFosterParent() {
-        /* The foster parent element is the parent element of the last
-        table element in the stack of open elements, if there is a
-        table element and it has such a parent element. If there is no
-        table element in the stack of open elements (innerHTML case),
-        then the foster parent element is the first element in the
-        stack of open elements (the html  element). Otherwise, if there
-        is a table element in the stack of open elements, but the last
-        table element in the stack of open elements has no parent, or
-        its parent node is not an element, then the foster parent
-        element is the element before the last table element in the
-        stack of open elements. */
-        for($n = count($this->stack) - 1; $n >= 0; $n--) {
-            if($this->stack[$n]->tagName === 'table') {
-                $table = $this->stack[$n];
-                break;
-            }
-        }
-
-        if(isset($table) && $table->parentNode !== null) {
-            return $table->parentNode;
-
-        } elseif(!isset($table)) {
-            return $this->stack[0];
-
-        } elseif(isset($table) && ($table->parentNode === null ||
-        $table->parentNode->nodeType !== XML_ELEMENT_NODE)) {
-            return $this->stack[$n - 1];
-        }
-    }
-
-    public function fosterParent($node) {
-        $foster_parent = $this->getFosterParent();
-        $table = $this->getCurrentTable(); // almost equivalent to last table element, except it can be html
-        /* When a node node is to be foster parented, the node node  must be 
-         * inserted into the foster parent element, and the current table must 
-         * be marked as tainted. (Once the current table has been tainted, 
-         * whitespace characters are inserted into the foster parent element 
-         * instead of the current node.) */
-        $table->tainted = true;
-        /* If the foster parent element is the parent element of the last table 
-         * element in the stack of open elements, then node must be inserted 
-         * immediately before the last table element in the stack of open 
-         * elements in the foster parent element; otherwise, node must be 
-         * appended to the foster parent element. */
-        if ($table->tagName === 'table' && $table->parentNode->isSameNode($foster_parent)) {
-            $foster_parent->insertBefore($node, $table);
-        } else {
-            $foster_parent->appendChild($node);
-        }
-    }
-
-    /**
-     * For debugging, prints the stack
-     */
-    private function printStack() {
-        $names = array();
-        foreach ($this->stack as $i => $element) {
-            $names[] = $element->tagName;
-        }
-        echo "  -> stack [" . implode(', ', $names) . "]\n";
-    }
-
-    /**
-     * For debugging, prints active formatting elements
-     */
-    private function printActiveFormattingElements() {
-        if (!$this->a_formatting) return;
-        $names = array();
-        foreach ($this->a_formatting as $node) {
-            if ($node === self::MARKER) $names[] = 'MARKER';
-            else $names[] = $node->tagName;
-        }
-        echo "  -> active formatting [" . implode(', ', $names) . "]\n";
-    }
-
-    public function currentTableIsTainted() {
-        return !empty($this->getCurrentTable()->tainted);
-    }
-
-    /**
-     * Sets up the tree constructor for building a fragment.
-     */
-    public function setupContext($context = null) {
-        $this->fragment = true;
-        if ($context) {
-            $context = $this->dom->createElementNS(self::NS_HTML, $context);
-            /* 4.1. Set the HTML parser's tokenization  stage's content model
-             * flag according to the context element, as follows: */
-            switch ($context->tagName) {
-            case 'title': case 'textarea':
-                $this->content_model = HTML5_Tokenizer::RCDATA;
-                break;
-            case 'style': case 'script': case 'xmp': case 'iframe':
-            case 'noembed': case 'noframes':
-                $this->content_model = HTML5_Tokenizer::CDATA;
-                break;
-            case 'noscript':
-                // XSCRIPT: assuming scripting is enabled
-                $this->content_model = HTML5_Tokenizer::CDATA;
-                break;
-            case 'plaintext':
-                $this->content_model = HTML5_Tokenizer::PLAINTEXT;
-                break;
-            }
-            /* 4.2. Let root be a new html element with no attributes. */
-            $root = $this->dom->createElementNS(self::NS_HTML, 'html');
-            $this->root = $root;
-            /* 4.3 Append the element root to the Document node created above. */
-            $this->dom->appendChild($root);
-            /* 4.4 Set up the parser's stack of open elements so that it 
-             * contains just the single element root. */
-            $this->stack = array($root);
-            /* 4.5 Reset the parser's insertion mode appropriately. */
-            $this->resetInsertionMode($context);
-            /* 4.6 Set the parser's form element pointer  to the nearest node 
-             * to the context element that is a form element (going straight up 
-             * the ancestor chain, and including the element itself, if it is a 
-             * form element), or, if there is no such form element, to null. */
-            $node = $context;
-            do {
-                if ($node->tagName === 'form') {
-                    $this->form_pointer = $node;
-                    break;
-                }
-            } while ($node = $node->parentNode);
-        }
-    }
-
-    public function adjustMathMLAttributes($token) {
-        foreach ($token['attr'] as &$kp) {
-            if ($kp['name'] === 'definitionurl') {
-                $kp['name'] = 'definitionURL';
-            }
-        }
-        return $token;
-    }
-
-    public function adjustSVGAttributes($token) {
-        static $lookup = array(
-            'attributename' => 'attributeName',
-            'attributetype' => 'attributeType',
-            'basefrequency' => 'baseFrequency',
-            'baseprofile' => 'baseProfile',
-            'calcmode' => 'calcMode',
-            'clippathunits' => 'clipPathUnits',
-            'contentscripttype' => 'contentScriptType',
-            'contentstyletype' => 'contentStyleType',
-            'diffuseconstant' => 'diffuseConstant',
-            'edgemode' => 'edgeMode',
-            'externalresourcesrequired' => 'externalResourcesRequired',
-            'filterres' => 'filterRes',
-            'filterunits' => 'filterUnits',
-            'glyphref' => 'glyphRef',
-            'gradienttransform' => 'gradientTransform',
-            'gradientunits' => 'gradientUnits',
-            'kernelmatrix' => 'kernelMatrix',
-            'kernelunitlength' => 'kernelUnitLength',
-            'keypoints' => 'keyPoints',
-            'keysplines' => 'keySplines',
-            'keytimes' => 'keyTimes',
-            'lengthadjust' => 'lengthAdjust',
-            'limitingconeangle' => 'limitingConeAngle',
-            'markerheight' => 'markerHeight',
-            'markerunits' => 'markerUnits',
-            'markerwidth' => 'markerWidth',
-            'maskcontentunits' => 'maskContentUnits',
-            'maskunits' => 'maskUnits',
-            'numoctaves' => 'numOctaves',
-            'pathlength' => 'pathLength',
-            'patterncontentunits' => 'patternContentUnits',
-            'patterntransform' => 'patternTransform',
-            'patternunits' => 'patternUnits',
-            'pointsatx' => 'pointsAtX',
-            'pointsaty' => 'pointsAtY',
-            'pointsatz' => 'pointsAtZ',
-            'preservealpha' => 'preserveAlpha',
-            'preserveaspectratio' => 'preserveAspectRatio',
-            'primitiveunits' => 'primitiveUnits',
-            'refx' => 'refX',
-            'refy' => 'refY',
-            'repeatcount' => 'repeatCount',
-            'repeatdur' => 'repeatDur',
-            'requiredextensions' => 'requiredExtensions',
-            'requiredfeatures' => 'requiredFeatures',
-            'specularconstant' => 'specularConstant',
-            'specularexponent' => 'specularExponent',
-            'spreadmethod' => 'spreadMethod',
-            'startoffset' => 'startOffset',
-            'stddeviation' => 'stdDeviation',
-            'stitchtiles' => 'stitchTiles',
-            'surfacescale' => 'surfaceScale',
-            'systemlanguage' => 'systemLanguage',
-            'tablevalues' => 'tableValues',
-            'targetx' => 'targetX',
-            'targety' => 'targetY',
-            'textlength' => 'textLength',
-            'viewbox' => 'viewBox',
-            'viewtarget' => 'viewTarget',
-            'xchannelselector' => 'xChannelSelector',
-            'ychannelselector' => 'yChannelSelector',
-            'zoomandpan' => 'zoomAndPan',
-        );
-        foreach ($token['attr'] as &$kp) {
-            if (isset($lookup[$kp['name']])) {
-                $kp['name'] = $lookup[$kp['name']];
-            }
-        }
-        return $token;
-    }
-
-    public function adjustForeignAttributes($token) {
-        static $lookup = array(
-            'xlink:actuate' => array('xlink', 'actuate', self::NS_XLINK),
-            'xlink:arcrole' => array('xlink', 'arcrole', self::NS_XLINK),
-            'xlink:href' => array('xlink', 'href', self::NS_XLINK),
-            'xlink:role' => array('xlink', 'role', self::NS_XLINK),
-            'xlink:show' => array('xlink', 'show', self::NS_XLINK),
-            'xlink:title' => array('xlink', 'title', self::NS_XLINK),
-            'xlink:type' => array('xlink', 'type', self::NS_XLINK),
-            'xml:base' => array('xml', 'base', self::NS_XML),
-            'xml:lang' => array('xml', 'lang', self::NS_XML),
-            'xml:space' => array('xml', 'space', self::NS_XML),
-            'xmlns' => array(null, 'xmlns', self::NS_XMLNS),
-            'xmlns:xlink' => array('xmlns', 'xlink', self::NS_XMLNS),
-        );
-        foreach ($token['attr'] as &$kp) {
-            if (isset($lookup[$kp['name']])) {
-                $kp['name'] = $lookup[$kp['name']];
-            }
-        }
-        return $token;
-    }
-
-    public function insertForeignElement($token, $namespaceURI) {
-        $el = $this->dom->createElementNS($namespaceURI, $token['name']);
-        if (!empty($token['attr'])) {
-            foreach ($token['attr'] as $kp) {
-                $attr = $kp['name'];
-                if (is_array($attr)) {
-                    $ns = $attr[2];
-                    $attr = $attr[1];
-                } else {
-                    $ns = self::NS_HTML;
-                }
-                if (!$el->hasAttributeNS($ns, $attr)) {
-                    // XSKETCHY: work around godawful libxml bug
-                    if ($ns === self::NS_XLINK) {
-                        $el->setAttribute('xlink:'.$attr, $kp['value']);
-                    } elseif ($ns === self::NS_HTML) {
-                        // Another godawful libxml bug
-                        $el->setAttribute($attr, $kp['value']);
-                    } else {
-                        $el->setAttributeNS($ns, $attr, $kp['value']);
-                    }
-                }
-            }
-        }
-        $this->appendToRealParent($el);
-        $this->stack[] = $el;
-        // XERROR: see below
-        /* If the newly created element has an xmlns attribute in the XMLNS 
-         * namespace  whose value is not exactly the same as the element's 
-         * namespace, that is a parse error. Similarly, if the newly created 
-         * element has an xmlns:xlink attribute in the XMLNS namespace whose 
-         * value is not the XLink Namespace, that is a parse error. */
-    }
-
-    public function save() {
-        $this->dom->normalize();
-        if (!$this->fragment) {
-            return $this->dom;
-        } else {
-            if ($this->root) {
-                return $this->root->childNodes;
-            } else {
-                return $this->dom->childNodes;
-            }
-        }
-    }
-}
-
diff --git a/library/HTML5/named-character-references.ser b/library/HTML5/named-character-references.ser
deleted file mode 100644
index 3004c4b91..000000000
--- a/library/HTML5/named-character-references.ser
+++ /dev/null
@@ -1 +0,0 @@
-a:2137:{s:6:"AElig;";i:198;s:5:"AElig";i:198;s:4:"AMP;";i:38;s:3:"AMP";i:38;s:7:"Aacute;";i:193;s:6:"Aacute";i:193;s:7:"Abreve;";i:258;s:6:"Acirc;";i:194;s:5:"Acirc";i:194;s:4:"Acy;";i:1040;s:4:"Afr;";i:120068;s:7:"Agrave;";i:192;s:6:"Agrave";i:192;s:6:"Alpha;";i:913;s:6:"Amacr;";i:256;s:4:"And;";i:10835;s:6:"Aogon;";i:260;s:5:"Aopf;";i:120120;s:14:"ApplyFunction;";i:8289;s:6:"Aring;";i:197;s:5:"Aring";i:197;s:5:"Ascr;";i:119964;s:7:"Assign;";i:8788;s:7:"Atilde;";i:195;s:6:"Atilde";i:195;s:5:"Auml;";i:196;s:4:"Auml";i:196;s:10:"Backslash;";i:8726;s:5:"Barv;";i:10983;s:7:"Barwed;";i:8966;s:4:"Bcy;";i:1041;s:8:"Because;";i:8757;s:11:"Bernoullis;";i:8492;s:5:"Beta;";i:914;s:4:"Bfr;";i:120069;s:5:"Bopf;";i:120121;s:6:"Breve;";i:728;s:5:"Bscr;";i:8492;s:7:"Bumpeq;";i:8782;s:5:"CHcy;";i:1063;s:5:"COPY;";i:169;s:4:"COPY";i:169;s:7:"Cacute;";i:262;s:4:"Cap;";i:8914;s:21:"CapitalDifferentialD;";i:8517;s:8:"Cayleys;";i:8493;s:7:"Ccaron;";i:268;s:7:"Ccedil;";i:199;s:6:"Ccedil";i:199;s:6:"Ccirc;";i:264;s:8:"Cconint;";i:8752;s:5:"Cdot;";i:266;s:8:"Cedilla;";i:184;s:10:"CenterDot;";i:183;s:4:"Cfr;";i:8493;s:4:"Chi;";i:935;s:10:"CircleDot;";i:8857;s:12:"CircleMinus;";i:8854;s:11:"CirclePlus;";i:8853;s:12:"CircleTimes;";i:8855;s:25:"ClockwiseContourIntegral;";i:8754;s:22:"CloseCurlyDoubleQuote;";i:8221;s:16:"CloseCurlyQuote;";i:8217;s:6:"Colon;";i:8759;s:7:"Colone;";i:10868;s:10:"Congruent;";i:8801;s:7:"Conint;";i:8751;s:16:"ContourIntegral;";i:8750;s:5:"Copf;";i:8450;s:10:"Coproduct;";i:8720;s:32:"CounterClockwiseContourIntegral;";i:8755;s:6:"Cross;";i:10799;s:5:"Cscr;";i:119966;s:4:"Cup;";i:8915;s:7:"CupCap;";i:8781;s:3:"DD;";i:8517;s:9:"DDotrahd;";i:10513;s:5:"DJcy;";i:1026;s:5:"DScy;";i:1029;s:5:"DZcy;";i:1039;s:7:"Dagger;";i:8225;s:5:"Darr;";i:8609;s:6:"Dashv;";i:10980;s:7:"Dcaron;";i:270;s:4:"Dcy;";i:1044;s:4:"Del;";i:8711;s:6:"Delta;";i:916;s:4:"Dfr;";i:120071;s:17:"DiacriticalAcute;";i:180;s:15:"DiacriticalDot;";i:729;s:23:"DiacriticalDoubleAcute;";i:733;s:17:"DiacriticalGrave;";i:96;s:17:"DiacriticalTilde;";i:732;s:8:"Diamond;";i:8900;s:14:"DifferentialD;";i:8518;s:5:"Dopf;";i:120123;s:4:"Dot;";i:168;s:7:"DotDot;";i:8412;s:9:"DotEqual;";i:8784;s:22:"DoubleContourIntegral;";i:8751;s:10:"DoubleDot;";i:168;s:16:"DoubleDownArrow;";i:8659;s:16:"DoubleLeftArrow;";i:8656;s:21:"DoubleLeftRightArrow;";i:8660;s:14:"DoubleLeftTee;";i:10980;s:20:"DoubleLongLeftArrow;";i:10232;s:25:"DoubleLongLeftRightArrow;";i:10234;s:21:"DoubleLongRightArrow;";i:10233;s:17:"DoubleRightArrow;";i:8658;s:15:"DoubleRightTee;";i:8872;s:14:"DoubleUpArrow;";i:8657;s:18:"DoubleUpDownArrow;";i:8661;s:18:"DoubleVerticalBar;";i:8741;s:10:"DownArrow;";i:8595;s:13:"DownArrowBar;";i:10515;s:17:"DownArrowUpArrow;";i:8693;s:10:"DownBreve;";i:785;s:20:"DownLeftRightVector;";i:10576;s:18:"DownLeftTeeVector;";i:10590;s:15:"DownLeftVector;";i:8637;s:18:"DownLeftVectorBar;";i:10582;s:19:"DownRightTeeVector;";i:10591;s:16:"DownRightVector;";i:8641;s:19:"DownRightVectorBar;";i:10583;s:8:"DownTee;";i:8868;s:13:"DownTeeArrow;";i:8615;s:10:"Downarrow;";i:8659;s:5:"Dscr;";i:119967;s:7:"Dstrok;";i:272;s:4:"ENG;";i:330;s:4:"ETH;";i:208;s:3:"ETH";i:208;s:7:"Eacute;";i:201;s:6:"Eacute";i:201;s:7:"Ecaron;";i:282;s:6:"Ecirc;";i:202;s:5:"Ecirc";i:202;s:4:"Ecy;";i:1069;s:5:"Edot;";i:278;s:4:"Efr;";i:120072;s:7:"Egrave;";i:200;s:6:"Egrave";i:200;s:8:"Element;";i:8712;s:6:"Emacr;";i:274;s:17:"EmptySmallSquare;";i:9723;s:21:"EmptyVerySmallSquare;";i:9643;s:6:"Eogon;";i:280;s:5:"Eopf;";i:120124;s:8:"Epsilon;";i:917;s:6:"Equal;";i:10869;s:11:"EqualTilde;";i:8770;s:12:"Equilibrium;";i:8652;s:5:"Escr;";i:8496;s:5:"Esim;";i:10867;s:4:"Eta;";i:919;s:5:"Euml;";i:203;s:4:"Euml";i:203;s:7:"Exists;";i:8707;s:13:"ExponentialE;";i:8519;s:4:"Fcy;";i:1060;s:4:"Ffr;";i:120073;s:18:"FilledSmallSquare;";i:9724;s:22:"FilledVerySmallSquare;";i:9642;s:5:"Fopf;";i:120125;s:7:"ForAll;";i:8704;s:11:"Fouriertrf;";i:8497;s:5:"Fscr;";i:8497;s:5:"GJcy;";i:1027;s:3:"GT;";i:62;s:2:"GT";i:62;s:6:"Gamma;";i:915;s:7:"Gammad;";i:988;s:7:"Gbreve;";i:286;s:7:"Gcedil;";i:290;s:6:"Gcirc;";i:284;s:4:"Gcy;";i:1043;s:5:"Gdot;";i:288;s:4:"Gfr;";i:120074;s:3:"Gg;";i:8921;s:5:"Gopf;";i:120126;s:13:"GreaterEqual;";i:8805;s:17:"GreaterEqualLess;";i:8923;s:17:"GreaterFullEqual;";i:8807;s:15:"GreaterGreater;";i:10914;s:12:"GreaterLess;";i:8823;s:18:"GreaterSlantEqual;";i:10878;s:13:"GreaterTilde;";i:8819;s:5:"Gscr;";i:119970;s:3:"Gt;";i:8811;s:7:"HARDcy;";i:1066;s:6:"Hacek;";i:711;s:4:"Hat;";i:94;s:6:"Hcirc;";i:292;s:4:"Hfr;";i:8460;s:13:"HilbertSpace;";i:8459;s:5:"Hopf;";i:8461;s:15:"HorizontalLine;";i:9472;s:5:"Hscr;";i:8459;s:7:"Hstrok;";i:294;s:13:"HumpDownHump;";i:8782;s:10:"HumpEqual;";i:8783;s:5:"IEcy;";i:1045;s:6:"IJlig;";i:306;s:5:"IOcy;";i:1025;s:7:"Iacute;";i:205;s:6:"Iacute";i:205;s:6:"Icirc;";i:206;s:5:"Icirc";i:206;s:4:"Icy;";i:1048;s:5:"Idot;";i:304;s:4:"Ifr;";i:8465;s:7:"Igrave;";i:204;s:6:"Igrave";i:204;s:3:"Im;";i:8465;s:6:"Imacr;";i:298;s:11:"ImaginaryI;";i:8520;s:8:"Implies;";i:8658;s:4:"Int;";i:8748;s:9:"Integral;";i:8747;s:13:"Intersection;";i:8898;s:15:"InvisibleComma;";i:8291;s:15:"InvisibleTimes;";i:8290;s:6:"Iogon;";i:302;s:5:"Iopf;";i:120128;s:5:"Iota;";i:921;s:5:"Iscr;";i:8464;s:7:"Itilde;";i:296;s:6:"Iukcy;";i:1030;s:5:"Iuml;";i:207;s:4:"Iuml";i:207;s:6:"Jcirc;";i:308;s:4:"Jcy;";i:1049;s:4:"Jfr;";i:120077;s:5:"Jopf;";i:120129;s:5:"Jscr;";i:119973;s:7:"Jsercy;";i:1032;s:6:"Jukcy;";i:1028;s:5:"KHcy;";i:1061;s:5:"KJcy;";i:1036;s:6:"Kappa;";i:922;s:7:"Kcedil;";i:310;s:4:"Kcy;";i:1050;s:4:"Kfr;";i:120078;s:5:"Kopf;";i:120130;s:5:"Kscr;";i:119974;s:5:"LJcy;";i:1033;s:3:"LT;";i:60;s:2:"LT";i:60;s:7:"Lacute;";i:313;s:7:"Lambda;";i:923;s:5:"Lang;";i:10218;s:11:"Laplacetrf;";i:8466;s:5:"Larr;";i:8606;s:7:"Lcaron;";i:317;s:7:"Lcedil;";i:315;s:4:"Lcy;";i:1051;s:17:"LeftAngleBracket;";i:10216;s:10:"LeftArrow;";i:8592;s:13:"LeftArrowBar;";i:8676;s:20:"LeftArrowRightArrow;";i:8646;s:12:"LeftCeiling;";i:8968;s:18:"LeftDoubleBracket;";i:10214;s:18:"LeftDownTeeVector;";i:10593;s:15:"LeftDownVector;";i:8643;s:18:"LeftDownVectorBar;";i:10585;s:10:"LeftFloor;";i:8970;s:15:"LeftRightArrow;";i:8596;s:16:"LeftRightVector;";i:10574;s:8:"LeftTee;";i:8867;s:13:"LeftTeeArrow;";i:8612;s:14:"LeftTeeVector;";i:10586;s:13:"LeftTriangle;";i:8882;s:16:"LeftTriangleBar;";i:10703;s:18:"LeftTriangleEqual;";i:8884;s:17:"LeftUpDownVector;";i:10577;s:16:"LeftUpTeeVector;";i:10592;s:13:"LeftUpVector;";i:8639;s:16:"LeftUpVectorBar;";i:10584;s:11:"LeftVector;";i:8636;s:14:"LeftVectorBar;";i:10578;s:10:"Leftarrow;";i:8656;s:15:"Leftrightarrow;";i:8660;s:17:"LessEqualGreater;";i:8922;s:14:"LessFullEqual;";i:8806;s:12:"LessGreater;";i:8822;s:9:"LessLess;";i:10913;s:15:"LessSlantEqual;";i:10877;s:10:"LessTilde;";i:8818;s:4:"Lfr;";i:120079;s:3:"Ll;";i:8920;s:11:"Lleftarrow;";i:8666;s:7:"Lmidot;";i:319;s:14:"LongLeftArrow;";i:10229;s:19:"LongLeftRightArrow;";i:10231;s:15:"LongRightArrow;";i:10230;s:14:"Longleftarrow;";i:10232;s:19:"Longleftrightarrow;";i:10234;s:15:"Longrightarrow;";i:10233;s:5:"Lopf;";i:120131;s:15:"LowerLeftArrow;";i:8601;s:16:"LowerRightArrow;";i:8600;s:5:"Lscr;";i:8466;s:4:"Lsh;";i:8624;s:7:"Lstrok;";i:321;s:3:"Lt;";i:8810;s:4:"Map;";i:10501;s:4:"Mcy;";i:1052;s:12:"MediumSpace;";i:8287;s:10:"Mellintrf;";i:8499;s:4:"Mfr;";i:120080;s:10:"MinusPlus;";i:8723;s:5:"Mopf;";i:120132;s:5:"Mscr;";i:8499;s:3:"Mu;";i:924;s:5:"NJcy;";i:1034;s:7:"Nacute;";i:323;s:7:"Ncaron;";i:327;s:7:"Ncedil;";i:325;s:4:"Ncy;";i:1053;s:20:"NegativeMediumSpace;";i:8203;s:19:"NegativeThickSpace;";i:8203;s:18:"NegativeThinSpace;";i:8203;s:22:"NegativeVeryThinSpace;";i:8203;s:21:"NestedGreaterGreater;";i:8811;s:15:"NestedLessLess;";i:8810;s:8:"NewLine;";i:10;s:4:"Nfr;";i:120081;s:8:"NoBreak;";i:8288;s:17:"NonBreakingSpace;";i:160;s:5:"Nopf;";i:8469;s:4:"Not;";i:10988;s:13:"NotCongruent;";i:8802;s:10:"NotCupCap;";i:8813;s:21:"NotDoubleVerticalBar;";i:8742;s:11:"NotElement;";i:8713;s:9:"NotEqual;";i:8800;s:10:"NotExists;";i:8708;s:11:"NotGreater;";i:8815;s:16:"NotGreaterEqual;";i:8817;s:15:"NotGreaterLess;";i:8825;s:16:"NotGreaterTilde;";i:8821;s:16:"NotLeftTriangle;";i:8938;s:21:"NotLeftTriangleEqual;";i:8940;s:8:"NotLess;";i:8814;s:13:"NotLessEqual;";i:8816;s:15:"NotLessGreater;";i:8824;s:13:"NotLessTilde;";i:8820;s:12:"NotPrecedes;";i:8832;s:22:"NotPrecedesSlantEqual;";i:8928;s:18:"NotReverseElement;";i:8716;s:17:"NotRightTriangle;";i:8939;s:22:"NotRightTriangleEqual;";i:8941;s:21:"NotSquareSubsetEqual;";i:8930;s:23:"NotSquareSupersetEqual;";i:8931;s:15:"NotSubsetEqual;";i:8840;s:12:"NotSucceeds;";i:8833;s:22:"NotSucceedsSlantEqual;";i:8929;s:17:"NotSupersetEqual;";i:8841;s:9:"NotTilde;";i:8769;s:14:"NotTildeEqual;";i:8772;s:18:"NotTildeFullEqual;";i:8775;s:14:"NotTildeTilde;";i:8777;s:15:"NotVerticalBar;";i:8740;s:5:"Nscr;";i:119977;s:7:"Ntilde;";i:209;s:6:"Ntilde";i:209;s:3:"Nu;";i:925;s:6:"OElig;";i:338;s:7:"Oacute;";i:211;s:6:"Oacute";i:211;s:6:"Ocirc;";i:212;s:5:"Ocirc";i:212;s:4:"Ocy;";i:1054;s:7:"Odblac;";i:336;s:4:"Ofr;";i:120082;s:7:"Ograve;";i:210;s:6:"Ograve";i:210;s:6:"Omacr;";i:332;s:6:"Omega;";i:937;s:8:"Omicron;";i:927;s:5:"Oopf;";i:120134;s:21:"OpenCurlyDoubleQuote;";i:8220;s:15:"OpenCurlyQuote;";i:8216;s:3:"Or;";i:10836;s:5:"Oscr;";i:119978;s:7:"Oslash;";i:216;s:6:"Oslash";i:216;s:7:"Otilde;";i:213;s:6:"Otilde";i:213;s:7:"Otimes;";i:10807;s:5:"Ouml;";i:214;s:4:"Ouml";i:214;s:8:"OverBar;";i:175;s:10:"OverBrace;";i:9182;s:12:"OverBracket;";i:9140;s:16:"OverParenthesis;";i:9180;s:9:"PartialD;";i:8706;s:4:"Pcy;";i:1055;s:4:"Pfr;";i:120083;s:4:"Phi;";i:934;s:3:"Pi;";i:928;s:10:"PlusMinus;";i:177;s:14:"Poincareplane;";i:8460;s:5:"Popf;";i:8473;s:3:"Pr;";i:10939;s:9:"Precedes;";i:8826;s:14:"PrecedesEqual;";i:10927;s:19:"PrecedesSlantEqual;";i:8828;s:14:"PrecedesTilde;";i:8830;s:6:"Prime;";i:8243;s:8:"Product;";i:8719;s:11:"Proportion;";i:8759;s:13:"Proportional;";i:8733;s:5:"Pscr;";i:119979;s:4:"Psi;";i:936;s:5:"QUOT;";i:34;s:4:"QUOT";i:34;s:4:"Qfr;";i:120084;s:5:"Qopf;";i:8474;s:5:"Qscr;";i:119980;s:6:"RBarr;";i:10512;s:4:"REG;";i:174;s:3:"REG";i:174;s:7:"Racute;";i:340;s:5:"Rang;";i:10219;s:5:"Rarr;";i:8608;s:7:"Rarrtl;";i:10518;s:7:"Rcaron;";i:344;s:7:"Rcedil;";i:342;s:4:"Rcy;";i:1056;s:3:"Re;";i:8476;s:15:"ReverseElement;";i:8715;s:19:"ReverseEquilibrium;";i:8651;s:21:"ReverseUpEquilibrium;";i:10607;s:4:"Rfr;";i:8476;s:4:"Rho;";i:929;s:18:"RightAngleBracket;";i:10217;s:11:"RightArrow;";i:8594;s:14:"RightArrowBar;";i:8677;s:20:"RightArrowLeftArrow;";i:8644;s:13:"RightCeiling;";i:8969;s:19:"RightDoubleBracket;";i:10215;s:19:"RightDownTeeVector;";i:10589;s:16:"RightDownVector;";i:8642;s:19:"RightDownVectorBar;";i:10581;s:11:"RightFloor;";i:8971;s:9:"RightTee;";i:8866;s:14:"RightTeeArrow;";i:8614;s:15:"RightTeeVector;";i:10587;s:14:"RightTriangle;";i:8883;s:17:"RightTriangleBar;";i:10704;s:19:"RightTriangleEqual;";i:8885;s:18:"RightUpDownVector;";i:10575;s:17:"RightUpTeeVector;";i:10588;s:14:"RightUpVector;";i:8638;s:17:"RightUpVectorBar;";i:10580;s:12:"RightVector;";i:8640;s:15:"RightVectorBar;";i:10579;s:11:"Rightarrow;";i:8658;s:5:"Ropf;";i:8477;s:13:"RoundImplies;";i:10608;s:12:"Rrightarrow;";i:8667;s:5:"Rscr;";i:8475;s:4:"Rsh;";i:8625;s:12:"RuleDelayed;";i:10740;s:7:"SHCHcy;";i:1065;s:5:"SHcy;";i:1064;s:7:"SOFTcy;";i:1068;s:7:"Sacute;";i:346;s:3:"Sc;";i:10940;s:7:"Scaron;";i:352;s:7:"Scedil;";i:350;s:6:"Scirc;";i:348;s:4:"Scy;";i:1057;s:4:"Sfr;";i:120086;s:15:"ShortDownArrow;";i:8595;s:15:"ShortLeftArrow;";i:8592;s:16:"ShortRightArrow;";i:8594;s:13:"ShortUpArrow;";i:8593;s:6:"Sigma;";i:931;s:12:"SmallCircle;";i:8728;s:5:"Sopf;";i:120138;s:5:"Sqrt;";i:8730;s:7:"Square;";i:9633;s:19:"SquareIntersection;";i:8851;s:13:"SquareSubset;";i:8847;s:18:"SquareSubsetEqual;";i:8849;s:15:"SquareSuperset;";i:8848;s:20:"SquareSupersetEqual;";i:8850;s:12:"SquareUnion;";i:8852;s:5:"Sscr;";i:119982;s:5:"Star;";i:8902;s:4:"Sub;";i:8912;s:7:"Subset;";i:8912;s:12:"SubsetEqual;";i:8838;s:9:"Succeeds;";i:8827;s:14:"SucceedsEqual;";i:10928;s:19:"SucceedsSlantEqual;";i:8829;s:14:"SucceedsTilde;";i:8831;s:9:"SuchThat;";i:8715;s:4:"Sum;";i:8721;s:4:"Sup;";i:8913;s:9:"Superset;";i:8835;s:14:"SupersetEqual;";i:8839;s:7:"Supset;";i:8913;s:6:"THORN;";i:222;s:5:"THORN";i:222;s:6:"TRADE;";i:8482;s:6:"TSHcy;";i:1035;s:5:"TScy;";i:1062;s:4:"Tab;";i:9;s:4:"Tau;";i:932;s:7:"Tcaron;";i:356;s:7:"Tcedil;";i:354;s:4:"Tcy;";i:1058;s:4:"Tfr;";i:120087;s:10:"Therefore;";i:8756;s:6:"Theta;";i:920;s:10:"ThinSpace;";i:8201;s:6:"Tilde;";i:8764;s:11:"TildeEqual;";i:8771;s:15:"TildeFullEqual;";i:8773;s:11:"TildeTilde;";i:8776;s:5:"Topf;";i:120139;s:10:"TripleDot;";i:8411;s:5:"Tscr;";i:119983;s:7:"Tstrok;";i:358;s:7:"Uacute;";i:218;s:6:"Uacute";i:218;s:5:"Uarr;";i:8607;s:9:"Uarrocir;";i:10569;s:6:"Ubrcy;";i:1038;s:7:"Ubreve;";i:364;s:6:"Ucirc;";i:219;s:5:"Ucirc";i:219;s:4:"Ucy;";i:1059;s:7:"Udblac;";i:368;s:4:"Ufr;";i:120088;s:7:"Ugrave;";i:217;s:6:"Ugrave";i:217;s:6:"Umacr;";i:362;s:9:"UnderBar;";i:818;s:11:"UnderBrace;";i:9183;s:13:"UnderBracket;";i:9141;s:17:"UnderParenthesis;";i:9181;s:6:"Union;";i:8899;s:10:"UnionPlus;";i:8846;s:6:"Uogon;";i:370;s:5:"Uopf;";i:120140;s:8:"UpArrow;";i:8593;s:11:"UpArrowBar;";i:10514;s:17:"UpArrowDownArrow;";i:8645;s:12:"UpDownArrow;";i:8597;s:14:"UpEquilibrium;";i:10606;s:6:"UpTee;";i:8869;s:11:"UpTeeArrow;";i:8613;s:8:"Uparrow;";i:8657;s:12:"Updownarrow;";i:8661;s:15:"UpperLeftArrow;";i:8598;s:16:"UpperRightArrow;";i:8599;s:5:"Upsi;";i:978;s:8:"Upsilon;";i:933;s:6:"Uring;";i:366;s:5:"Uscr;";i:119984;s:7:"Utilde;";i:360;s:5:"Uuml;";i:220;s:4:"Uuml";i:220;s:6:"VDash;";i:8875;s:5:"Vbar;";i:10987;s:4:"Vcy;";i:1042;s:6:"Vdash;";i:8873;s:7:"Vdashl;";i:10982;s:4:"Vee;";i:8897;s:7:"Verbar;";i:8214;s:5:"Vert;";i:8214;s:12:"VerticalBar;";i:8739;s:13:"VerticalLine;";i:124;s:18:"VerticalSeparator;";i:10072;s:14:"VerticalTilde;";i:8768;s:14:"VeryThinSpace;";i:8202;s:4:"Vfr;";i:120089;s:5:"Vopf;";i:120141;s:5:"Vscr;";i:119985;s:7:"Vvdash;";i:8874;s:6:"Wcirc;";i:372;s:6:"Wedge;";i:8896;s:4:"Wfr;";i:120090;s:5:"Wopf;";i:120142;s:5:"Wscr;";i:119986;s:4:"Xfr;";i:120091;s:3:"Xi;";i:926;s:5:"Xopf;";i:120143;s:5:"Xscr;";i:119987;s:5:"YAcy;";i:1071;s:5:"YIcy;";i:1031;s:5:"YUcy;";i:1070;s:7:"Yacute;";i:221;s:6:"Yacute";i:221;s:6:"Ycirc;";i:374;s:4:"Ycy;";i:1067;s:4:"Yfr;";i:120092;s:5:"Yopf;";i:120144;s:5:"Yscr;";i:119988;s:5:"Yuml;";i:376;s:5:"ZHcy;";i:1046;s:7:"Zacute;";i:377;s:7:"Zcaron;";i:381;s:4:"Zcy;";i:1047;s:5:"Zdot;";i:379;s:15:"ZeroWidthSpace;";i:8203;s:5:"Zeta;";i:918;s:4:"Zfr;";i:8488;s:5:"Zopf;";i:8484;s:5:"Zscr;";i:119989;s:7:"aacute;";i:225;s:6:"aacute";i:225;s:7:"abreve;";i:259;s:3:"ac;";i:8766;s:4:"acd;";i:8767;s:6:"acirc;";i:226;s:5:"acirc";i:226;s:6:"acute;";i:180;s:5:"acute";i:180;s:4:"acy;";i:1072;s:6:"aelig;";i:230;s:5:"aelig";i:230;s:3:"af;";i:8289;s:4:"afr;";i:120094;s:7:"agrave;";i:224;s:6:"agrave";i:224;s:8:"alefsym;";i:8501;s:6:"aleph;";i:8501;s:6:"alpha;";i:945;s:6:"amacr;";i:257;s:6:"amalg;";i:10815;s:4:"amp;";i:38;s:3:"amp";i:38;s:4:"and;";i:8743;s:7:"andand;";i:10837;s:5:"andd;";i:10844;s:9:"andslope;";i:10840;s:5:"andv;";i:10842;s:4:"ang;";i:8736;s:5:"ange;";i:10660;s:6:"angle;";i:8736;s:7:"angmsd;";i:8737;s:9:"angmsdaa;";i:10664;s:9:"angmsdab;";i:10665;s:9:"angmsdac;";i:10666;s:9:"angmsdad;";i:10667;s:9:"angmsdae;";i:10668;s:9:"angmsdaf;";i:10669;s:9:"angmsdag;";i:10670;s:9:"angmsdah;";i:10671;s:6:"angrt;";i:8735;s:8:"angrtvb;";i:8894;s:9:"angrtvbd;";i:10653;s:7:"angsph;";i:8738;s:6:"angst;";i:8491;s:8:"angzarr;";i:9084;s:6:"aogon;";i:261;s:5:"aopf;";i:120146;s:3:"ap;";i:8776;s:4:"apE;";i:10864;s:7:"apacir;";i:10863;s:4:"ape;";i:8778;s:5:"apid;";i:8779;s:5:"apos;";i:39;s:7:"approx;";i:8776;s:9:"approxeq;";i:8778;s:6:"aring;";i:229;s:5:"aring";i:229;s:5:"ascr;";i:119990;s:4:"ast;";i:42;s:6:"asymp;";i:8776;s:8:"asympeq;";i:8781;s:7:"atilde;";i:227;s:6:"atilde";i:227;s:5:"auml;";i:228;s:4:"auml";i:228;s:9:"awconint;";i:8755;s:6:"awint;";i:10769;s:5:"bNot;";i:10989;s:9:"backcong;";i:8780;s:12:"backepsilon;";i:1014;s:10:"backprime;";i:8245;s:8:"backsim;";i:8765;s:10:"backsimeq;";i:8909;s:7:"barvee;";i:8893;s:7:"barwed;";i:8965;s:9:"barwedge;";i:8965;s:5:"bbrk;";i:9141;s:9:"bbrktbrk;";i:9142;s:6:"bcong;";i:8780;s:4:"bcy;";i:1073;s:6:"bdquo;";i:8222;s:7:"becaus;";i:8757;s:8:"because;";i:8757;s:8:"bemptyv;";i:10672;s:6:"bepsi;";i:1014;s:7:"bernou;";i:8492;s:5:"beta;";i:946;s:5:"beth;";i:8502;s:8:"between;";i:8812;s:4:"bfr;";i:120095;s:7:"bigcap;";i:8898;s:8:"bigcirc;";i:9711;s:7:"bigcup;";i:8899;s:8:"bigodot;";i:10752;s:9:"bigoplus;";i:10753;s:10:"bigotimes;";i:10754;s:9:"bigsqcup;";i:10758;s:8:"bigstar;";i:9733;s:16:"bigtriangledown;";i:9661;s:14:"bigtriangleup;";i:9651;s:9:"biguplus;";i:10756;s:7:"bigvee;";i:8897;s:9:"bigwedge;";i:8896;s:7:"bkarow;";i:10509;s:13:"blacklozenge;";i:10731;s:12:"blacksquare;";i:9642;s:14:"blacktriangle;";i:9652;s:18:"blacktriangledown;";i:9662;s:18:"blacktriangleleft;";i:9666;s:19:"blacktriangleright;";i:9656;s:6:"blank;";i:9251;s:6:"blk12;";i:9618;s:6:"blk14;";i:9617;s:6:"blk34;";i:9619;s:6:"block;";i:9608;s:5:"bnot;";i:8976;s:5:"bopf;";i:120147;s:4:"bot;";i:8869;s:7:"bottom;";i:8869;s:7:"bowtie;";i:8904;s:6:"boxDL;";i:9559;s:6:"boxDR;";i:9556;s:6:"boxDl;";i:9558;s:6:"boxDr;";i:9555;s:5:"boxH;";i:9552;s:6:"boxHD;";i:9574;s:6:"boxHU;";i:9577;s:6:"boxHd;";i:9572;s:6:"boxHu;";i:9575;s:6:"boxUL;";i:9565;s:6:"boxUR;";i:9562;s:6:"boxUl;";i:9564;s:6:"boxUr;";i:9561;s:5:"boxV;";i:9553;s:6:"boxVH;";i:9580;s:6:"boxVL;";i:9571;s:6:"boxVR;";i:9568;s:6:"boxVh;";i:9579;s:6:"boxVl;";i:9570;s:6:"boxVr;";i:9567;s:7:"boxbox;";i:10697;s:6:"boxdL;";i:9557;s:6:"boxdR;";i:9554;s:6:"boxdl;";i:9488;s:6:"boxdr;";i:9484;s:5:"boxh;";i:9472;s:6:"boxhD;";i:9573;s:6:"boxhU;";i:9576;s:6:"boxhd;";i:9516;s:6:"boxhu;";i:9524;s:9:"boxminus;";i:8863;s:8:"boxplus;";i:8862;s:9:"boxtimes;";i:8864;s:6:"boxuL;";i:9563;s:6:"boxuR;";i:9560;s:6:"boxul;";i:9496;s:6:"boxur;";i:9492;s:5:"boxv;";i:9474;s:6:"boxvH;";i:9578;s:6:"boxvL;";i:9569;s:6:"boxvR;";i:9566;s:6:"boxvh;";i:9532;s:6:"boxvl;";i:9508;s:6:"boxvr;";i:9500;s:7:"bprime;";i:8245;s:6:"breve;";i:728;s:7:"brvbar;";i:166;s:6:"brvbar";i:166;s:5:"bscr;";i:119991;s:6:"bsemi;";i:8271;s:5:"bsim;";i:8765;s:6:"bsime;";i:8909;s:5:"bsol;";i:92;s:6:"bsolb;";i:10693;s:5:"bull;";i:8226;s:7:"bullet;";i:8226;s:5:"bump;";i:8782;s:6:"bumpE;";i:10926;s:6:"bumpe;";i:8783;s:7:"bumpeq;";i:8783;s:7:"cacute;";i:263;s:4:"cap;";i:8745;s:7:"capand;";i:10820;s:9:"capbrcup;";i:10825;s:7:"capcap;";i:10827;s:7:"capcup;";i:10823;s:7:"capdot;";i:10816;s:6:"caret;";i:8257;s:6:"caron;";i:711;s:6:"ccaps;";i:10829;s:7:"ccaron;";i:269;s:7:"ccedil;";i:231;s:6:"ccedil";i:231;s:6:"ccirc;";i:265;s:6:"ccups;";i:10828;s:8:"ccupssm;";i:10832;s:5:"cdot;";i:267;s:6:"cedil;";i:184;s:5:"cedil";i:184;s:8:"cemptyv;";i:10674;s:5:"cent;";i:162;s:4:"cent";i:162;s:10:"centerdot;";i:183;s:4:"cfr;";i:120096;s:5:"chcy;";i:1095;s:6:"check;";i:10003;s:10:"checkmark;";i:10003;s:4:"chi;";i:967;s:4:"cir;";i:9675;s:5:"cirE;";i:10691;s:5:"circ;";i:710;s:7:"circeq;";i:8791;s:16:"circlearrowleft;";i:8634;s:17:"circlearrowright;";i:8635;s:9:"circledR;";i:174;s:9:"circledS;";i:9416;s:11:"circledast;";i:8859;s:12:"circledcirc;";i:8858;s:12:"circleddash;";i:8861;s:5:"cire;";i:8791;s:9:"cirfnint;";i:10768;s:7:"cirmid;";i:10991;s:8:"cirscir;";i:10690;s:6:"clubs;";i:9827;s:9:"clubsuit;";i:9827;s:6:"colon;";i:58;s:7:"colone;";i:8788;s:8:"coloneq;";i:8788;s:6:"comma;";i:44;s:7:"commat;";i:64;s:5:"comp;";i:8705;s:7:"compfn;";i:8728;s:11:"complement;";i:8705;s:10:"complexes;";i:8450;s:5:"cong;";i:8773;s:8:"congdot;";i:10861;s:7:"conint;";i:8750;s:5:"copf;";i:120148;s:7:"coprod;";i:8720;s:5:"copy;";i:169;s:4:"copy";i:169;s:7:"copysr;";i:8471;s:6:"crarr;";i:8629;s:6:"cross;";i:10007;s:5:"cscr;";i:119992;s:5:"csub;";i:10959;s:6:"csube;";i:10961;s:5:"csup;";i:10960;s:6:"csupe;";i:10962;s:6:"ctdot;";i:8943;s:8:"cudarrl;";i:10552;s:8:"cudarrr;";i:10549;s:6:"cuepr;";i:8926;s:6:"cuesc;";i:8927;s:7:"cularr;";i:8630;s:8:"cularrp;";i:10557;s:4:"cup;";i:8746;s:9:"cupbrcap;";i:10824;s:7:"cupcap;";i:10822;s:7:"cupcup;";i:10826;s:7:"cupdot;";i:8845;s:6:"cupor;";i:10821;s:7:"curarr;";i:8631;s:8:"curarrm;";i:10556;s:12:"curlyeqprec;";i:8926;s:12:"curlyeqsucc;";i:8927;s:9:"curlyvee;";i:8910;s:11:"curlywedge;";i:8911;s:7:"curren;";i:164;s:6:"curren";i:164;s:15:"curvearrowleft;";i:8630;s:16:"curvearrowright;";i:8631;s:6:"cuvee;";i:8910;s:6:"cuwed;";i:8911;s:9:"cwconint;";i:8754;s:6:"cwint;";i:8753;s:7:"cylcty;";i:9005;s:5:"dArr;";i:8659;s:5:"dHar;";i:10597;s:7:"dagger;";i:8224;s:7:"daleth;";i:8504;s:5:"darr;";i:8595;s:5:"dash;";i:8208;s:6:"dashv;";i:8867;s:8:"dbkarow;";i:10511;s:6:"dblac;";i:733;s:7:"dcaron;";i:271;s:4:"dcy;";i:1076;s:3:"dd;";i:8518;s:8:"ddagger;";i:8225;s:6:"ddarr;";i:8650;s:8:"ddotseq;";i:10871;s:4:"deg;";i:176;s:3:"deg";i:176;s:6:"delta;";i:948;s:8:"demptyv;";i:10673;s:7:"dfisht;";i:10623;s:4:"dfr;";i:120097;s:6:"dharl;";i:8643;s:6:"dharr;";i:8642;s:5:"diam;";i:8900;s:8:"diamond;";i:8900;s:12:"diamondsuit;";i:9830;s:6:"diams;";i:9830;s:4:"die;";i:168;s:8:"digamma;";i:989;s:6:"disin;";i:8946;s:4:"div;";i:247;s:7:"divide;";i:247;s:6:"divide";i:247;s:14:"divideontimes;";i:8903;s:7:"divonx;";i:8903;s:5:"djcy;";i:1106;s:7:"dlcorn;";i:8990;s:7:"dlcrop;";i:8973;s:7:"dollar;";i:36;s:5:"dopf;";i:120149;s:4:"dot;";i:729;s:6:"doteq;";i:8784;s:9:"doteqdot;";i:8785;s:9:"dotminus;";i:8760;s:8:"dotplus;";i:8724;s:10:"dotsquare;";i:8865;s:15:"doublebarwedge;";i:8966;s:10:"downarrow;";i:8595;s:15:"downdownarrows;";i:8650;s:16:"downharpoonleft;";i:8643;s:17:"downharpoonright;";i:8642;s:9:"drbkarow;";i:10512;s:7:"drcorn;";i:8991;s:7:"drcrop;";i:8972;s:5:"dscr;";i:119993;s:5:"dscy;";i:1109;s:5:"dsol;";i:10742;s:7:"dstrok;";i:273;s:6:"dtdot;";i:8945;s:5:"dtri;";i:9663;s:6:"dtrif;";i:9662;s:6:"duarr;";i:8693;s:6:"duhar;";i:10607;s:8:"dwangle;";i:10662;s:5:"dzcy;";i:1119;s:9:"dzigrarr;";i:10239;s:6:"eDDot;";i:10871;s:5:"eDot;";i:8785;s:7:"eacute;";i:233;s:6:"eacute";i:233;s:7:"easter;";i:10862;s:7:"ecaron;";i:283;s:5:"ecir;";i:8790;s:6:"ecirc;";i:234;s:5:"ecirc";i:234;s:7:"ecolon;";i:8789;s:4:"ecy;";i:1101;s:5:"edot;";i:279;s:3:"ee;";i:8519;s:6:"efDot;";i:8786;s:4:"efr;";i:120098;s:3:"eg;";i:10906;s:7:"egrave;";i:232;s:6:"egrave";i:232;s:4:"egs;";i:10902;s:7:"egsdot;";i:10904;s:3:"el;";i:10905;s:9:"elinters;";i:9191;s:4:"ell;";i:8467;s:4:"els;";i:10901;s:7:"elsdot;";i:10903;s:6:"emacr;";i:275;s:6:"empty;";i:8709;s:9:"emptyset;";i:8709;s:7:"emptyv;";i:8709;s:7:"emsp13;";i:8196;s:7:"emsp14;";i:8197;s:5:"emsp;";i:8195;s:4:"eng;";i:331;s:5:"ensp;";i:8194;s:6:"eogon;";i:281;s:5:"eopf;";i:120150;s:5:"epar;";i:8917;s:7:"eparsl;";i:10723;s:6:"eplus;";i:10865;s:5:"epsi;";i:1013;s:8:"epsilon;";i:949;s:6:"epsiv;";i:949;s:7:"eqcirc;";i:8790;s:8:"eqcolon;";i:8789;s:6:"eqsim;";i:8770;s:11:"eqslantgtr;";i:10902;s:12:"eqslantless;";i:10901;s:7:"equals;";i:61;s:7:"equest;";i:8799;s:6:"equiv;";i:8801;s:8:"equivDD;";i:10872;s:9:"eqvparsl;";i:10725;s:6:"erDot;";i:8787;s:6:"erarr;";i:10609;s:5:"escr;";i:8495;s:6:"esdot;";i:8784;s:5:"esim;";i:8770;s:4:"eta;";i:951;s:4:"eth;";i:240;s:3:"eth";i:240;s:5:"euml;";i:235;s:4:"euml";i:235;s:5:"euro;";i:8364;s:5:"excl;";i:33;s:6:"exist;";i:8707;s:12:"expectation;";i:8496;s:13:"exponentiale;";i:8519;s:14:"fallingdotseq;";i:8786;s:4:"fcy;";i:1092;s:7:"female;";i:9792;s:7:"ffilig;";i:64259;s:6:"fflig;";i:64256;s:7:"ffllig;";i:64260;s:4:"ffr;";i:120099;s:6:"filig;";i:64257;s:5:"flat;";i:9837;s:6:"fllig;";i:64258;s:6:"fltns;";i:9649;s:5:"fnof;";i:402;s:5:"fopf;";i:120151;s:7:"forall;";i:8704;s:5:"fork;";i:8916;s:6:"forkv;";i:10969;s:9:"fpartint;";i:10765;s:7:"frac12;";i:189;s:6:"frac12";i:189;s:7:"frac13;";i:8531;s:7:"frac14;";i:188;s:6:"frac14";i:188;s:7:"frac15;";i:8533;s:7:"frac16;";i:8537;s:7:"frac18;";i:8539;s:7:"frac23;";i:8532;s:7:"frac25;";i:8534;s:7:"frac34;";i:190;s:6:"frac34";i:190;s:7:"frac35;";i:8535;s:7:"frac38;";i:8540;s:7:"frac45;";i:8536;s:7:"frac56;";i:8538;s:7:"frac58;";i:8541;s:7:"frac78;";i:8542;s:6:"frasl;";i:8260;s:6:"frown;";i:8994;s:5:"fscr;";i:119995;s:3:"gE;";i:8807;s:4:"gEl;";i:10892;s:7:"gacute;";i:501;s:6:"gamma;";i:947;s:7:"gammad;";i:989;s:4:"gap;";i:10886;s:7:"gbreve;";i:287;s:6:"gcirc;";i:285;s:4:"gcy;";i:1075;s:5:"gdot;";i:289;s:3:"ge;";i:8805;s:4:"gel;";i:8923;s:4:"geq;";i:8805;s:5:"geqq;";i:8807;s:9:"geqslant;";i:10878;s:4:"ges;";i:10878;s:6:"gescc;";i:10921;s:7:"gesdot;";i:10880;s:8:"gesdoto;";i:10882;s:9:"gesdotol;";i:10884;s:7:"gesles;";i:10900;s:4:"gfr;";i:120100;s:3:"gg;";i:8811;s:4:"ggg;";i:8921;s:6:"gimel;";i:8503;s:5:"gjcy;";i:1107;s:3:"gl;";i:8823;s:4:"glE;";i:10898;s:4:"gla;";i:10917;s:4:"glj;";i:10916;s:4:"gnE;";i:8809;s:5:"gnap;";i:10890;s:9:"gnapprox;";i:10890;s:4:"gne;";i:10888;s:5:"gneq;";i:10888;s:6:"gneqq;";i:8809;s:6:"gnsim;";i:8935;s:5:"gopf;";i:120152;s:6:"grave;";i:96;s:5:"gscr;";i:8458;s:5:"gsim;";i:8819;s:6:"gsime;";i:10894;s:6:"gsiml;";i:10896;s:3:"gt;";i:62;s:2:"gt";i:62;s:5:"gtcc;";i:10919;s:6:"gtcir;";i:10874;s:6:"gtdot;";i:8919;s:7:"gtlPar;";i:10645;s:8:"gtquest;";i:10876;s:10:"gtrapprox;";i:10886;s:7:"gtrarr;";i:10616;s:7:"gtrdot;";i:8919;s:10:"gtreqless;";i:8923;s:11:"gtreqqless;";i:10892;s:8:"gtrless;";i:8823;s:7:"gtrsim;";i:8819;s:5:"hArr;";i:8660;s:7:"hairsp;";i:8202;s:5:"half;";i:189;s:7:"hamilt;";i:8459;s:7:"hardcy;";i:1098;s:5:"harr;";i:8596;s:8:"harrcir;";i:10568;s:6:"harrw;";i:8621;s:5:"hbar;";i:8463;s:6:"hcirc;";i:293;s:7:"hearts;";i:9829;s:10:"heartsuit;";i:9829;s:7:"hellip;";i:8230;s:7:"hercon;";i:8889;s:4:"hfr;";i:120101;s:9:"hksearow;";i:10533;s:9:"hkswarow;";i:10534;s:6:"hoarr;";i:8703;s:7:"homtht;";i:8763;s:14:"hookleftarrow;";i:8617;s:15:"hookrightarrow;";i:8618;s:5:"hopf;";i:120153;s:7:"horbar;";i:8213;s:5:"hscr;";i:119997;s:7:"hslash;";i:8463;s:7:"hstrok;";i:295;s:7:"hybull;";i:8259;s:7:"hyphen;";i:8208;s:7:"iacute;";i:237;s:6:"iacute";i:237;s:3:"ic;";i:8291;s:6:"icirc;";i:238;s:5:"icirc";i:238;s:4:"icy;";i:1080;s:5:"iecy;";i:1077;s:6:"iexcl;";i:161;s:5:"iexcl";i:161;s:4:"iff;";i:8660;s:4:"ifr;";i:120102;s:7:"igrave;";i:236;s:6:"igrave";i:236;s:3:"ii;";i:8520;s:7:"iiiint;";i:10764;s:6:"iiint;";i:8749;s:7:"iinfin;";i:10716;s:6:"iiota;";i:8489;s:6:"ijlig;";i:307;s:6:"imacr;";i:299;s:6:"image;";i:8465;s:9:"imagline;";i:8464;s:9:"imagpart;";i:8465;s:6:"imath;";i:305;s:5:"imof;";i:8887;s:6:"imped;";i:437;s:3:"in;";i:8712;s:7:"incare;";i:8453;s:6:"infin;";i:8734;s:9:"infintie;";i:10717;s:7:"inodot;";i:305;s:4:"int;";i:8747;s:7:"intcal;";i:8890;s:9:"integers;";i:8484;s:9:"intercal;";i:8890;s:9:"intlarhk;";i:10775;s:8:"intprod;";i:10812;s:5:"iocy;";i:1105;s:6:"iogon;";i:303;s:5:"iopf;";i:120154;s:5:"iota;";i:953;s:6:"iprod;";i:10812;s:7:"iquest;";i:191;s:6:"iquest";i:191;s:5:"iscr;";i:119998;s:5:"isin;";i:8712;s:6:"isinE;";i:8953;s:8:"isindot;";i:8949;s:6:"isins;";i:8948;s:7:"isinsv;";i:8947;s:6:"isinv;";i:8712;s:3:"it;";i:8290;s:7:"itilde;";i:297;s:6:"iukcy;";i:1110;s:5:"iuml;";i:239;s:4:"iuml";i:239;s:6:"jcirc;";i:309;s:4:"jcy;";i:1081;s:4:"jfr;";i:120103;s:6:"jmath;";i:567;s:5:"jopf;";i:120155;s:5:"jscr;";i:119999;s:7:"jsercy;";i:1112;s:6:"jukcy;";i:1108;s:6:"kappa;";i:954;s:7:"kappav;";i:1008;s:7:"kcedil;";i:311;s:4:"kcy;";i:1082;s:4:"kfr;";i:120104;s:7:"kgreen;";i:312;s:5:"khcy;";i:1093;s:5:"kjcy;";i:1116;s:5:"kopf;";i:120156;s:5:"kscr;";i:120000;s:6:"lAarr;";i:8666;s:5:"lArr;";i:8656;s:7:"lAtail;";i:10523;s:6:"lBarr;";i:10510;s:3:"lE;";i:8806;s:4:"lEg;";i:10891;s:5:"lHar;";i:10594;s:7:"lacute;";i:314;s:9:"laemptyv;";i:10676;s:7:"lagran;";i:8466;s:7:"lambda;";i:955;s:5:"lang;";i:10216;s:6:"langd;";i:10641;s:7:"langle;";i:10216;s:4:"lap;";i:10885;s:6:"laquo;";i:171;s:5:"laquo";i:171;s:5:"larr;";i:8592;s:6:"larrb;";i:8676;s:8:"larrbfs;";i:10527;s:7:"larrfs;";i:10525;s:7:"larrhk;";i:8617;s:7:"larrlp;";i:8619;s:7:"larrpl;";i:10553;s:8:"larrsim;";i:10611;s:7:"larrtl;";i:8610;s:4:"lat;";i:10923;s:7:"latail;";i:10521;s:5:"late;";i:10925;s:6:"lbarr;";i:10508;s:6:"lbbrk;";i:10098;s:7:"lbrace;";i:123;s:7:"lbrack;";i:91;s:6:"lbrke;";i:10635;s:8:"lbrksld;";i:10639;s:8:"lbrkslu;";i:10637;s:7:"lcaron;";i:318;s:7:"lcedil;";i:316;s:6:"lceil;";i:8968;s:5:"lcub;";i:123;s:4:"lcy;";i:1083;s:5:"ldca;";i:10550;s:6:"ldquo;";i:8220;s:7:"ldquor;";i:8222;s:8:"ldrdhar;";i:10599;s:9:"ldrushar;";i:10571;s:5:"ldsh;";i:8626;s:3:"le;";i:8804;s:10:"leftarrow;";i:8592;s:14:"leftarrowtail;";i:8610;s:16:"leftharpoondown;";i:8637;s:14:"leftharpoonup;";i:8636;s:15:"leftleftarrows;";i:8647;s:15:"leftrightarrow;";i:8596;s:16:"leftrightarrows;";i:8646;s:18:"leftrightharpoons;";i:8651;s:20:"leftrightsquigarrow;";i:8621;s:15:"leftthreetimes;";i:8907;s:4:"leg;";i:8922;s:4:"leq;";i:8804;s:5:"leqq;";i:8806;s:9:"leqslant;";i:10877;s:4:"les;";i:10877;s:6:"lescc;";i:10920;s:7:"lesdot;";i:10879;s:8:"lesdoto;";i:10881;s:9:"lesdotor;";i:10883;s:7:"lesges;";i:10899;s:11:"lessapprox;";i:10885;s:8:"lessdot;";i:8918;s:10:"lesseqgtr;";i:8922;s:11:"lesseqqgtr;";i:10891;s:8:"lessgtr;";i:8822;s:8:"lesssim;";i:8818;s:7:"lfisht;";i:10620;s:7:"lfloor;";i:8970;s:4:"lfr;";i:120105;s:3:"lg;";i:8822;s:4:"lgE;";i:10897;s:6:"lhard;";i:8637;s:6:"lharu;";i:8636;s:7:"lharul;";i:10602;s:6:"lhblk;";i:9604;s:5:"ljcy;";i:1113;s:3:"ll;";i:8810;s:6:"llarr;";i:8647;s:9:"llcorner;";i:8990;s:7:"llhard;";i:10603;s:6:"lltri;";i:9722;s:7:"lmidot;";i:320;s:7:"lmoust;";i:9136;s:11:"lmoustache;";i:9136;s:4:"lnE;";i:8808;s:5:"lnap;";i:10889;s:9:"lnapprox;";i:10889;s:4:"lne;";i:10887;s:5:"lneq;";i:10887;s:6:"lneqq;";i:8808;s:6:"lnsim;";i:8934;s:6:"loang;";i:10220;s:6:"loarr;";i:8701;s:6:"lobrk;";i:10214;s:14:"longleftarrow;";i:10229;s:19:"longleftrightarrow;";i:10231;s:11:"longmapsto;";i:10236;s:15:"longrightarrow;";i:10230;s:14:"looparrowleft;";i:8619;s:15:"looparrowright;";i:8620;s:6:"lopar;";i:10629;s:5:"lopf;";i:120157;s:7:"loplus;";i:10797;s:8:"lotimes;";i:10804;s:7:"lowast;";i:8727;s:7:"lowbar;";i:95;s:4:"loz;";i:9674;s:8:"lozenge;";i:9674;s:5:"lozf;";i:10731;s:5:"lpar;";i:40;s:7:"lparlt;";i:10643;s:6:"lrarr;";i:8646;s:9:"lrcorner;";i:8991;s:6:"lrhar;";i:8651;s:7:"lrhard;";i:10605;s:4:"lrm;";i:8206;s:6:"lrtri;";i:8895;s:7:"lsaquo;";i:8249;s:5:"lscr;";i:120001;s:4:"lsh;";i:8624;s:5:"lsim;";i:8818;s:6:"lsime;";i:10893;s:6:"lsimg;";i:10895;s:5:"lsqb;";i:91;s:6:"lsquo;";i:8216;s:7:"lsquor;";i:8218;s:7:"lstrok;";i:322;s:3:"lt;";i:60;s:2:"lt";i:60;s:5:"ltcc;";i:10918;s:6:"ltcir;";i:10873;s:6:"ltdot;";i:8918;s:7:"lthree;";i:8907;s:7:"ltimes;";i:8905;s:7:"ltlarr;";i:10614;s:8:"ltquest;";i:10875;s:7:"ltrPar;";i:10646;s:5:"ltri;";i:9667;s:6:"ltrie;";i:8884;s:6:"ltrif;";i:9666;s:9:"lurdshar;";i:10570;s:8:"luruhar;";i:10598;s:6:"mDDot;";i:8762;s:5:"macr;";i:175;s:4:"macr";i:175;s:5:"male;";i:9794;s:5:"malt;";i:10016;s:8:"maltese;";i:10016;s:4:"map;";i:8614;s:7:"mapsto;";i:8614;s:11:"mapstodown;";i:8615;s:11:"mapstoleft;";i:8612;s:9:"mapstoup;";i:8613;s:7:"marker;";i:9646;s:7:"mcomma;";i:10793;s:4:"mcy;";i:1084;s:6:"mdash;";i:8212;s:14:"measuredangle;";i:8737;s:4:"mfr;";i:120106;s:4:"mho;";i:8487;s:6:"micro;";i:181;s:5:"micro";i:181;s:4:"mid;";i:8739;s:7:"midast;";i:42;s:7:"midcir;";i:10992;s:7:"middot;";i:183;s:6:"middot";i:183;s:6:"minus;";i:8722;s:7:"minusb;";i:8863;s:7:"minusd;";i:8760;s:8:"minusdu;";i:10794;s:5:"mlcp;";i:10971;s:5:"mldr;";i:8230;s:7:"mnplus;";i:8723;s:7:"models;";i:8871;s:5:"mopf;";i:120158;s:3:"mp;";i:8723;s:5:"mscr;";i:120002;s:7:"mstpos;";i:8766;s:3:"mu;";i:956;s:9:"multimap;";i:8888;s:6:"mumap;";i:8888;s:11:"nLeftarrow;";i:8653;s:16:"nLeftrightarrow;";i:8654;s:12:"nRightarrow;";i:8655;s:7:"nVDash;";i:8879;s:7:"nVdash;";i:8878;s:6:"nabla;";i:8711;s:7:"nacute;";i:324;s:4:"nap;";i:8777;s:6:"napos;";i:329;s:8:"napprox;";i:8777;s:6:"natur;";i:9838;s:8:"natural;";i:9838;s:9:"naturals;";i:8469;s:5:"nbsp;";i:160;s:4:"nbsp";i:160;s:5:"ncap;";i:10819;s:7:"ncaron;";i:328;s:7:"ncedil;";i:326;s:6:"ncong;";i:8775;s:5:"ncup;";i:10818;s:4:"ncy;";i:1085;s:6:"ndash;";i:8211;s:3:"ne;";i:8800;s:6:"neArr;";i:8663;s:7:"nearhk;";i:10532;s:6:"nearr;";i:8599;s:8:"nearrow;";i:8599;s:7:"nequiv;";i:8802;s:7:"nesear;";i:10536;s:7:"nexist;";i:8708;s:8:"nexists;";i:8708;s:4:"nfr;";i:120107;s:4:"nge;";i:8817;s:5:"ngeq;";i:8817;s:6:"ngsim;";i:8821;s:4:"ngt;";i:8815;s:5:"ngtr;";i:8815;s:6:"nhArr;";i:8654;s:6:"nharr;";i:8622;s:6:"nhpar;";i:10994;s:3:"ni;";i:8715;s:4:"nis;";i:8956;s:5:"nisd;";i:8954;s:4:"niv;";i:8715;s:5:"njcy;";i:1114;s:6:"nlArr;";i:8653;s:6:"nlarr;";i:8602;s:5:"nldr;";i:8229;s:4:"nle;";i:8816;s:11:"nleftarrow;";i:8602;s:16:"nleftrightarrow;";i:8622;s:5:"nleq;";i:8816;s:6:"nless;";i:8814;s:6:"nlsim;";i:8820;s:4:"nlt;";i:8814;s:6:"nltri;";i:8938;s:7:"nltrie;";i:8940;s:5:"nmid;";i:8740;s:5:"nopf;";i:120159;s:4:"not;";i:172;s:3:"not";i:172;s:6:"notin;";i:8713;s:8:"notinva;";i:8713;s:8:"notinvb;";i:8951;s:8:"notinvc;";i:8950;s:6:"notni;";i:8716;s:8:"notniva;";i:8716;s:8:"notnivb;";i:8958;s:8:"notnivc;";i:8957;s:5:"npar;";i:8742;s:10:"nparallel;";i:8742;s:8:"npolint;";i:10772;s:4:"npr;";i:8832;s:7:"nprcue;";i:8928;s:6:"nprec;";i:8832;s:6:"nrArr;";i:8655;s:6:"nrarr;";i:8603;s:12:"nrightarrow;";i:8603;s:6:"nrtri;";i:8939;s:7:"nrtrie;";i:8941;s:4:"nsc;";i:8833;s:7:"nsccue;";i:8929;s:5:"nscr;";i:120003;s:10:"nshortmid;";i:8740;s:15:"nshortparallel;";i:8742;s:5:"nsim;";i:8769;s:6:"nsime;";i:8772;s:7:"nsimeq;";i:8772;s:6:"nsmid;";i:8740;s:6:"nspar;";i:8742;s:8:"nsqsube;";i:8930;s:8:"nsqsupe;";i:8931;s:5:"nsub;";i:8836;s:6:"nsube;";i:8840;s:10:"nsubseteq;";i:8840;s:6:"nsucc;";i:8833;s:5:"nsup;";i:8837;s:6:"nsupe;";i:8841;s:10:"nsupseteq;";i:8841;s:5:"ntgl;";i:8825;s:7:"ntilde;";i:241;s:6:"ntilde";i:241;s:5:"ntlg;";i:8824;s:14:"ntriangleleft;";i:8938;s:16:"ntrianglelefteq;";i:8940;s:15:"ntriangleright;";i:8939;s:17:"ntrianglerighteq;";i:8941;s:3:"nu;";i:957;s:4:"num;";i:35;s:7:"numero;";i:8470;s:6:"numsp;";i:8199;s:7:"nvDash;";i:8877;s:7:"nvHarr;";i:10500;s:7:"nvdash;";i:8876;s:8:"nvinfin;";i:10718;s:7:"nvlArr;";i:10498;s:7:"nvrArr;";i:10499;s:6:"nwArr;";i:8662;s:7:"nwarhk;";i:10531;s:6:"nwarr;";i:8598;s:8:"nwarrow;";i:8598;s:7:"nwnear;";i:10535;s:3:"oS;";i:9416;s:7:"oacute;";i:243;s:6:"oacute";i:243;s:5:"oast;";i:8859;s:5:"ocir;";i:8858;s:6:"ocirc;";i:244;s:5:"ocirc";i:244;s:4:"ocy;";i:1086;s:6:"odash;";i:8861;s:7:"odblac;";i:337;s:5:"odiv;";i:10808;s:5:"odot;";i:8857;s:7:"odsold;";i:10684;s:6:"oelig;";i:339;s:6:"ofcir;";i:10687;s:4:"ofr;";i:120108;s:5:"ogon;";i:731;s:7:"ograve;";i:242;s:6:"ograve";i:242;s:4:"ogt;";i:10689;s:6:"ohbar;";i:10677;s:4:"ohm;";i:8486;s:5:"oint;";i:8750;s:6:"olarr;";i:8634;s:6:"olcir;";i:10686;s:8:"olcross;";i:10683;s:6:"oline;";i:8254;s:4:"olt;";i:10688;s:6:"omacr;";i:333;s:6:"omega;";i:969;s:8:"omicron;";i:959;s:5:"omid;";i:10678;s:7:"ominus;";i:8854;s:5:"oopf;";i:120160;s:5:"opar;";i:10679;s:6:"operp;";i:10681;s:6:"oplus;";i:8853;s:3:"or;";i:8744;s:6:"orarr;";i:8635;s:4:"ord;";i:10845;s:6:"order;";i:8500;s:8:"orderof;";i:8500;s:5:"ordf;";i:170;s:4:"ordf";i:170;s:5:"ordm;";i:186;s:4:"ordm";i:186;s:7:"origof;";i:8886;s:5:"oror;";i:10838;s:8:"orslope;";i:10839;s:4:"orv;";i:10843;s:5:"oscr;";i:8500;s:7:"oslash;";i:248;s:6:"oslash";i:248;s:5:"osol;";i:8856;s:7:"otilde;";i:245;s:6:"otilde";i:245;s:7:"otimes;";i:8855;s:9:"otimesas;";i:10806;s:5:"ouml;";i:246;s:4:"ouml";i:246;s:6:"ovbar;";i:9021;s:4:"par;";i:8741;s:5:"para;";i:182;s:4:"para";i:182;s:9:"parallel;";i:8741;s:7:"parsim;";i:10995;s:6:"parsl;";i:11005;s:5:"part;";i:8706;s:4:"pcy;";i:1087;s:7:"percnt;";i:37;s:7:"period;";i:46;s:7:"permil;";i:8240;s:5:"perp;";i:8869;s:8:"pertenk;";i:8241;s:4:"pfr;";i:120109;s:4:"phi;";i:966;s:5:"phiv;";i:966;s:7:"phmmat;";i:8499;s:6:"phone;";i:9742;s:3:"pi;";i:960;s:10:"pitchfork;";i:8916;s:4:"piv;";i:982;s:7:"planck;";i:8463;s:8:"planckh;";i:8462;s:7:"plankv;";i:8463;s:5:"plus;";i:43;s:9:"plusacir;";i:10787;s:6:"plusb;";i:8862;s:8:"pluscir;";i:10786;s:7:"plusdo;";i:8724;s:7:"plusdu;";i:10789;s:6:"pluse;";i:10866;s:7:"plusmn;";i:177;s:6:"plusmn";i:177;s:8:"plussim;";i:10790;s:8:"plustwo;";i:10791;s:3:"pm;";i:177;s:9:"pointint;";i:10773;s:5:"popf;";i:120161;s:6:"pound;";i:163;s:5:"pound";i:163;s:3:"pr;";i:8826;s:4:"prE;";i:10931;s:5:"prap;";i:10935;s:6:"prcue;";i:8828;s:4:"pre;";i:10927;s:5:"prec;";i:8826;s:11:"precapprox;";i:10935;s:12:"preccurlyeq;";i:8828;s:7:"preceq;";i:10927;s:12:"precnapprox;";i:10937;s:9:"precneqq;";i:10933;s:9:"precnsim;";i:8936;s:8:"precsim;";i:8830;s:6:"prime;";i:8242;s:7:"primes;";i:8473;s:5:"prnE;";i:10933;s:6:"prnap;";i:10937;s:7:"prnsim;";i:8936;s:5:"prod;";i:8719;s:9:"profalar;";i:9006;s:9:"profline;";i:8978;s:9:"profsurf;";i:8979;s:5:"prop;";i:8733;s:7:"propto;";i:8733;s:6:"prsim;";i:8830;s:7:"prurel;";i:8880;s:5:"pscr;";i:120005;s:4:"psi;";i:968;s:7:"puncsp;";i:8200;s:4:"qfr;";i:120110;s:5:"qint;";i:10764;s:5:"qopf;";i:120162;s:7:"qprime;";i:8279;s:5:"qscr;";i:120006;s:12:"quaternions;";i:8461;s:8:"quatint;";i:10774;s:6:"quest;";i:63;s:8:"questeq;";i:8799;s:5:"quot;";i:34;s:4:"quot";i:34;s:6:"rAarr;";i:8667;s:5:"rArr;";i:8658;s:7:"rAtail;";i:10524;s:6:"rBarr;";i:10511;s:5:"rHar;";i:10596;s:5:"race;";i:10714;s:7:"racute;";i:341;s:6:"radic;";i:8730;s:9:"raemptyv;";i:10675;s:5:"rang;";i:10217;s:6:"rangd;";i:10642;s:6:"range;";i:10661;s:7:"rangle;";i:10217;s:6:"raquo;";i:187;s:5:"raquo";i:187;s:5:"rarr;";i:8594;s:7:"rarrap;";i:10613;s:6:"rarrb;";i:8677;s:8:"rarrbfs;";i:10528;s:6:"rarrc;";i:10547;s:7:"rarrfs;";i:10526;s:7:"rarrhk;";i:8618;s:7:"rarrlp;";i:8620;s:7:"rarrpl;";i:10565;s:8:"rarrsim;";i:10612;s:7:"rarrtl;";i:8611;s:6:"rarrw;";i:8605;s:7:"ratail;";i:10522;s:6:"ratio;";i:8758;s:10:"rationals;";i:8474;s:6:"rbarr;";i:10509;s:6:"rbbrk;";i:10099;s:7:"rbrace;";i:125;s:7:"rbrack;";i:93;s:6:"rbrke;";i:10636;s:8:"rbrksld;";i:10638;s:8:"rbrkslu;";i:10640;s:7:"rcaron;";i:345;s:7:"rcedil;";i:343;s:6:"rceil;";i:8969;s:5:"rcub;";i:125;s:4:"rcy;";i:1088;s:5:"rdca;";i:10551;s:8:"rdldhar;";i:10601;s:6:"rdquo;";i:8221;s:7:"rdquor;";i:8221;s:5:"rdsh;";i:8627;s:5:"real;";i:8476;s:8:"realine;";i:8475;s:9:"realpart;";i:8476;s:6:"reals;";i:8477;s:5:"rect;";i:9645;s:4:"reg;";i:174;s:3:"reg";i:174;s:7:"rfisht;";i:10621;s:7:"rfloor;";i:8971;s:4:"rfr;";i:120111;s:6:"rhard;";i:8641;s:6:"rharu;";i:8640;s:7:"rharul;";i:10604;s:4:"rho;";i:961;s:5:"rhov;";i:1009;s:11:"rightarrow;";i:8594;s:15:"rightarrowtail;";i:8611;s:17:"rightharpoondown;";i:8641;s:15:"rightharpoonup;";i:8640;s:16:"rightleftarrows;";i:8644;s:18:"rightleftharpoons;";i:8652;s:17:"rightrightarrows;";i:8649;s:16:"rightsquigarrow;";i:8605;s:16:"rightthreetimes;";i:8908;s:5:"ring;";i:730;s:13:"risingdotseq;";i:8787;s:6:"rlarr;";i:8644;s:6:"rlhar;";i:8652;s:4:"rlm;";i:8207;s:7:"rmoust;";i:9137;s:11:"rmoustache;";i:9137;s:6:"rnmid;";i:10990;s:6:"roang;";i:10221;s:6:"roarr;";i:8702;s:6:"robrk;";i:10215;s:6:"ropar;";i:10630;s:5:"ropf;";i:120163;s:7:"roplus;";i:10798;s:8:"rotimes;";i:10805;s:5:"rpar;";i:41;s:7:"rpargt;";i:10644;s:9:"rppolint;";i:10770;s:6:"rrarr;";i:8649;s:7:"rsaquo;";i:8250;s:5:"rscr;";i:120007;s:4:"rsh;";i:8625;s:5:"rsqb;";i:93;s:6:"rsquo;";i:8217;s:7:"rsquor;";i:8217;s:7:"rthree;";i:8908;s:7:"rtimes;";i:8906;s:5:"rtri;";i:9657;s:6:"rtrie;";i:8885;s:6:"rtrif;";i:9656;s:9:"rtriltri;";i:10702;s:8:"ruluhar;";i:10600;s:3:"rx;";i:8478;s:7:"sacute;";i:347;s:6:"sbquo;";i:8218;s:3:"sc;";i:8827;s:4:"scE;";i:10932;s:5:"scap;";i:10936;s:7:"scaron;";i:353;s:6:"sccue;";i:8829;s:4:"sce;";i:10928;s:7:"scedil;";i:351;s:6:"scirc;";i:349;s:5:"scnE;";i:10934;s:6:"scnap;";i:10938;s:7:"scnsim;";i:8937;s:9:"scpolint;";i:10771;s:6:"scsim;";i:8831;s:4:"scy;";i:1089;s:5:"sdot;";i:8901;s:6:"sdotb;";i:8865;s:6:"sdote;";i:10854;s:6:"seArr;";i:8664;s:7:"searhk;";i:10533;s:6:"searr;";i:8600;s:8:"searrow;";i:8600;s:5:"sect;";i:167;s:4:"sect";i:167;s:5:"semi;";i:59;s:7:"seswar;";i:10537;s:9:"setminus;";i:8726;s:6:"setmn;";i:8726;s:5:"sext;";i:10038;s:4:"sfr;";i:120112;s:7:"sfrown;";i:8994;s:6:"sharp;";i:9839;s:7:"shchcy;";i:1097;s:5:"shcy;";i:1096;s:9:"shortmid;";i:8739;s:14:"shortparallel;";i:8741;s:4:"shy;";i:173;s:3:"shy";i:173;s:6:"sigma;";i:963;s:7:"sigmaf;";i:962;s:7:"sigmav;";i:962;s:4:"sim;";i:8764;s:7:"simdot;";i:10858;s:5:"sime;";i:8771;s:6:"simeq;";i:8771;s:5:"simg;";i:10910;s:6:"simgE;";i:10912;s:5:"siml;";i:10909;s:6:"simlE;";i:10911;s:6:"simne;";i:8774;s:8:"simplus;";i:10788;s:8:"simrarr;";i:10610;s:6:"slarr;";i:8592;s:14:"smallsetminus;";i:8726;s:7:"smashp;";i:10803;s:9:"smeparsl;";i:10724;s:5:"smid;";i:8739;s:6:"smile;";i:8995;s:4:"smt;";i:10922;s:5:"smte;";i:10924;s:7:"softcy;";i:1100;s:4:"sol;";i:47;s:5:"solb;";i:10692;s:7:"solbar;";i:9023;s:5:"sopf;";i:120164;s:7:"spades;";i:9824;s:10:"spadesuit;";i:9824;s:5:"spar;";i:8741;s:6:"sqcap;";i:8851;s:6:"sqcup;";i:8852;s:6:"sqsub;";i:8847;s:7:"sqsube;";i:8849;s:9:"sqsubset;";i:8847;s:11:"sqsubseteq;";i:8849;s:6:"sqsup;";i:8848;s:7:"sqsupe;";i:8850;s:9:"sqsupset;";i:8848;s:11:"sqsupseteq;";i:8850;s:4:"squ;";i:9633;s:7:"square;";i:9633;s:7:"squarf;";i:9642;s:5:"squf;";i:9642;s:6:"srarr;";i:8594;s:5:"sscr;";i:120008;s:7:"ssetmn;";i:8726;s:7:"ssmile;";i:8995;s:7:"sstarf;";i:8902;s:5:"star;";i:9734;s:6:"starf;";i:9733;s:16:"straightepsilon;";i:1013;s:12:"straightphi;";i:981;s:6:"strns;";i:175;s:4:"sub;";i:8834;s:5:"subE;";i:10949;s:7:"subdot;";i:10941;s:5:"sube;";i:8838;s:8:"subedot;";i:10947;s:8:"submult;";i:10945;s:6:"subnE;";i:10955;s:6:"subne;";i:8842;s:8:"subplus;";i:10943;s:8:"subrarr;";i:10617;s:7:"subset;";i:8834;s:9:"subseteq;";i:8838;s:10:"subseteqq;";i:10949;s:10:"subsetneq;";i:8842;s:11:"subsetneqq;";i:10955;s:7:"subsim;";i:10951;s:7:"subsub;";i:10965;s:7:"subsup;";i:10963;s:5:"succ;";i:8827;s:11:"succapprox;";i:10936;s:12:"succcurlyeq;";i:8829;s:7:"succeq;";i:10928;s:12:"succnapprox;";i:10938;s:9:"succneqq;";i:10934;s:9:"succnsim;";i:8937;s:8:"succsim;";i:8831;s:4:"sum;";i:8721;s:5:"sung;";i:9834;s:5:"sup1;";i:185;s:4:"sup1";i:185;s:5:"sup2;";i:178;s:4:"sup2";i:178;s:5:"sup3;";i:179;s:4:"sup3";i:179;s:4:"sup;";i:8835;s:5:"supE;";i:10950;s:7:"supdot;";i:10942;s:8:"supdsub;";i:10968;s:5:"supe;";i:8839;s:8:"supedot;";i:10948;s:8:"suphsub;";i:10967;s:8:"suplarr;";i:10619;s:8:"supmult;";i:10946;s:6:"supnE;";i:10956;s:6:"supne;";i:8843;s:8:"supplus;";i:10944;s:7:"supset;";i:8835;s:9:"supseteq;";i:8839;s:10:"supseteqq;";i:10950;s:10:"supsetneq;";i:8843;s:11:"supsetneqq;";i:10956;s:7:"supsim;";i:10952;s:7:"supsub;";i:10964;s:7:"supsup;";i:10966;s:6:"swArr;";i:8665;s:7:"swarhk;";i:10534;s:6:"swarr;";i:8601;s:8:"swarrow;";i:8601;s:7:"swnwar;";i:10538;s:6:"szlig;";i:223;s:5:"szlig";i:223;s:7:"target;";i:8982;s:4:"tau;";i:964;s:5:"tbrk;";i:9140;s:7:"tcaron;";i:357;s:7:"tcedil;";i:355;s:4:"tcy;";i:1090;s:5:"tdot;";i:8411;s:7:"telrec;";i:8981;s:4:"tfr;";i:120113;s:7:"there4;";i:8756;s:10:"therefore;";i:8756;s:6:"theta;";i:952;s:9:"thetasym;";i:977;s:7:"thetav;";i:977;s:12:"thickapprox;";i:8776;s:9:"thicksim;";i:8764;s:7:"thinsp;";i:8201;s:6:"thkap;";i:8776;s:7:"thksim;";i:8764;s:6:"thorn;";i:254;s:5:"thorn";i:254;s:6:"tilde;";i:732;s:6:"times;";i:215;s:5:"times";i:215;s:7:"timesb;";i:8864;s:9:"timesbar;";i:10801;s:7:"timesd;";i:10800;s:5:"tint;";i:8749;s:5:"toea;";i:10536;s:4:"top;";i:8868;s:7:"topbot;";i:9014;s:7:"topcir;";i:10993;s:5:"topf;";i:120165;s:8:"topfork;";i:10970;s:5:"tosa;";i:10537;s:7:"tprime;";i:8244;s:6:"trade;";i:8482;s:9:"triangle;";i:9653;s:13:"triangledown;";i:9663;s:13:"triangleleft;";i:9667;s:15:"trianglelefteq;";i:8884;s:10:"triangleq;";i:8796;s:14:"triangleright;";i:9657;s:16:"trianglerighteq;";i:8885;s:7:"tridot;";i:9708;s:5:"trie;";i:8796;s:9:"triminus;";i:10810;s:8:"triplus;";i:10809;s:6:"trisb;";i:10701;s:8:"tritime;";i:10811;s:9:"trpezium;";i:9186;s:5:"tscr;";i:120009;s:5:"tscy;";i:1094;s:6:"tshcy;";i:1115;s:7:"tstrok;";i:359;s:6:"twixt;";i:8812;s:17:"twoheadleftarrow;";i:8606;s:18:"twoheadrightarrow;";i:8608;s:5:"uArr;";i:8657;s:5:"uHar;";i:10595;s:7:"uacute;";i:250;s:6:"uacute";i:250;s:5:"uarr;";i:8593;s:6:"ubrcy;";i:1118;s:7:"ubreve;";i:365;s:6:"ucirc;";i:251;s:5:"ucirc";i:251;s:4:"ucy;";i:1091;s:6:"udarr;";i:8645;s:7:"udblac;";i:369;s:6:"udhar;";i:10606;s:7:"ufisht;";i:10622;s:4:"ufr;";i:120114;s:7:"ugrave;";i:249;s:6:"ugrave";i:249;s:6:"uharl;";i:8639;s:6:"uharr;";i:8638;s:6:"uhblk;";i:9600;s:7:"ulcorn;";i:8988;s:9:"ulcorner;";i:8988;s:7:"ulcrop;";i:8975;s:6:"ultri;";i:9720;s:6:"umacr;";i:363;s:4:"uml;";i:168;s:3:"uml";i:168;s:6:"uogon;";i:371;s:5:"uopf;";i:120166;s:8:"uparrow;";i:8593;s:12:"updownarrow;";i:8597;s:14:"upharpoonleft;";i:8639;s:15:"upharpoonright;";i:8638;s:6:"uplus;";i:8846;s:5:"upsi;";i:965;s:6:"upsih;";i:978;s:8:"upsilon;";i:965;s:11:"upuparrows;";i:8648;s:7:"urcorn;";i:8989;s:9:"urcorner;";i:8989;s:7:"urcrop;";i:8974;s:6:"uring;";i:367;s:6:"urtri;";i:9721;s:5:"uscr;";i:120010;s:6:"utdot;";i:8944;s:7:"utilde;";i:361;s:5:"utri;";i:9653;s:6:"utrif;";i:9652;s:6:"uuarr;";i:8648;s:5:"uuml;";i:252;s:4:"uuml";i:252;s:8:"uwangle;";i:10663;s:5:"vArr;";i:8661;s:5:"vBar;";i:10984;s:6:"vBarv;";i:10985;s:6:"vDash;";i:8872;s:7:"vangrt;";i:10652;s:11:"varepsilon;";i:949;s:9:"varkappa;";i:1008;s:11:"varnothing;";i:8709;s:7:"varphi;";i:966;s:6:"varpi;";i:982;s:10:"varpropto;";i:8733;s:5:"varr;";i:8597;s:7:"varrho;";i:1009;s:9:"varsigma;";i:962;s:9:"vartheta;";i:977;s:16:"vartriangleleft;";i:8882;s:17:"vartriangleright;";i:8883;s:4:"vcy;";i:1074;s:6:"vdash;";i:8866;s:4:"vee;";i:8744;s:7:"veebar;";i:8891;s:6:"veeeq;";i:8794;s:7:"vellip;";i:8942;s:7:"verbar;";i:124;s:5:"vert;";i:124;s:4:"vfr;";i:120115;s:6:"vltri;";i:8882;s:5:"vopf;";i:120167;s:6:"vprop;";i:8733;s:6:"vrtri;";i:8883;s:5:"vscr;";i:120011;s:8:"vzigzag;";i:10650;s:6:"wcirc;";i:373;s:7:"wedbar;";i:10847;s:6:"wedge;";i:8743;s:7:"wedgeq;";i:8793;s:7:"weierp;";i:8472;s:4:"wfr;";i:120116;s:5:"wopf;";i:120168;s:3:"wp;";i:8472;s:3:"wr;";i:8768;s:7:"wreath;";i:8768;s:5:"wscr;";i:120012;s:5:"xcap;";i:8898;s:6:"xcirc;";i:9711;s:5:"xcup;";i:8899;s:6:"xdtri;";i:9661;s:4:"xfr;";i:120117;s:6:"xhArr;";i:10234;s:6:"xharr;";i:10231;s:3:"xi;";i:958;s:6:"xlArr;";i:10232;s:6:"xlarr;";i:10229;s:5:"xmap;";i:10236;s:5:"xnis;";i:8955;s:6:"xodot;";i:10752;s:5:"xopf;";i:120169;s:7:"xoplus;";i:10753;s:7:"xotime;";i:10754;s:6:"xrArr;";i:10233;s:6:"xrarr;";i:10230;s:5:"xscr;";i:120013;s:7:"xsqcup;";i:10758;s:7:"xuplus;";i:10756;s:6:"xutri;";i:9651;s:5:"xvee;";i:8897;s:7:"xwedge;";i:8896;s:7:"yacute;";i:253;s:6:"yacute";i:253;s:5:"yacy;";i:1103;s:6:"ycirc;";i:375;s:4:"ycy;";i:1099;s:4:"yen;";i:165;s:3:"yen";i:165;s:4:"yfr;";i:120118;s:5:"yicy;";i:1111;s:5:"yopf;";i:120170;s:5:"yscr;";i:120014;s:5:"yucy;";i:1102;s:5:"yuml;";i:255;s:4:"yuml";i:255;s:7:"zacute;";i:378;s:7:"zcaron;";i:382;s:4:"zcy;";i:1079;s:5:"zdot;";i:380;s:7:"zeetrf;";i:8488;s:5:"zeta;";i:950;s:4:"zfr;";i:120119;s:5:"zhcy;";i:1078;s:8:"zigrarr;";i:8669;s:5:"zopf;";i:120171;s:5:"zscr;";i:120015;s:4:"zwj;";i:8205;s:5:"zwnj;";i:8204;}
\ No newline at end of file
-- 
cgit v1.2.3


From 6588e272db9e797447430f9f3853d365c56606eb Mon Sep 17 00:00:00 2001
From: Harald Eilertsen 
Date: Wed, 9 Oct 2024 20:51:00 +0200
Subject: Remove addon repo management from admin/addons.

This functionality was broken anyways, and needs to be rethought. Addon
reporitories can still be managed from the terminal using the tools in
util/.
---
 Zotlabs/Module/Admin/Addons.php    | 281 -------------------------------------
 Zotlabs/Storage/GitRepo.php        | 159 ---------------------
 view/tpl/admin_plugins.tpl         | 167 +---------------------
 view/tpl/admin_plugins_addrepo.tpl |   9 --
 4 files changed, 3 insertions(+), 613 deletions(-)
 delete mode 100644 Zotlabs/Storage/GitRepo.php
 delete mode 100644 view/tpl/admin_plugins_addrepo.tpl

diff --git a/Zotlabs/Module/Admin/Addons.php b/Zotlabs/Module/Admin/Addons.php
index b7cfb651c..681eed750 100644
--- a/Zotlabs/Module/Admin/Addons.php
+++ b/Zotlabs/Module/Admin/Addons.php
@@ -4,7 +4,6 @@ namespace Zotlabs\Module\Admin;
 
 use App;
 use \Zotlabs\Lib\Config;
-use \Zotlabs\Storage\GitRepo;
 use \Michelf\MarkdownExtra;
 
 class Addons {
@@ -24,227 +23,6 @@ class Addons {
 
 			goaway(z_root() . '/admin/addons/' . argv(2) );
 		}
-		elseif(argc() > 2) {
-			switch(argv(2)) {
-				case 'updaterepo':
-					if (array_key_exists('repoName', $_REQUEST)) {
-						$repoName = $_REQUEST['repoName'];
-					}
-					else {
-						json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
-					}
-					$extendDir = 'store/[data]/git/sys/extend';
-					$addonDir = $extendDir . '/addon';
-					if (!file_exists($extendDir)) {
-						if (!mkdir($extendDir, 0770, true)) {
-							logger('Error creating extend folder: ' . $extendDir);
-							json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
-						}
-						else {
-							if (!symlink(realpath('extend/addon'), $addonDir)) {
-								logger('Error creating symlink to addon folder: ' . $addonDir);
-								json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
-							}
-						}
-					}
-					$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
-					if (!is_dir($repoDir)) {
-						logger('Repo directory does not exist: ' . $repoDir);
-						json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
-					}
-					if (!is_writable($repoDir)) {
-						logger('Repo directory not writable to web server: ' . $repoDir);
-						json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
-					}
-					$git = new GitRepo('sys', null, false, $repoName, $repoDir);
-					try {
-						if ($git->pull()) {
-							$files = array_diff(scandir($repoDir), array('.', '..'));
-							foreach ($files as $file) {
-								if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
-									$source = '../extend/addon/' . $repoName . '/' . $file;
-									$target = realpath('addon/') . '/' . $file;
-									unlink($target);
-									if (!symlink($source, $target)) {
-										logger('Error linking addons to /addon');
-										json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
-									}
-								}
-							}
-							json_return_and_die(array('message' => 'Repo updated.', 'success' => true));
-						} else {
-							json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
-						}
-					} catch (\PHPGit\Exception\GitException $e) {
-						json_return_and_die(array('message' => 'Error updating addon repo.', 'success' => false));
-					}
-					break;
-				case 'removerepo':
-					if (array_key_exists('repoName', $_REQUEST)) {
-						$repoName = $_REQUEST['repoName'];
-					} else {
-						json_return_and_die(array('message' => 'No repo name provided.', 'success' => false));
-					}
-					$extendDir = 'store/[data]/git/sys/extend';
-					$addonDir = $extendDir . '/addon';
-					if (!file_exists($extendDir)) {
-						if (!mkdir($extendDir, 0770, true)) {
-							logger('Error creating extend folder: ' . $extendDir);
-							json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
-						} else {
-							if (!symlink(realpath('extend/addon'), $addonDir)) {
-								logger('Error creating symlink to addon folder: ' . $addonDir);
-								json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
-							}
-						}
-					}
-					$repoDir = 'store/[data]/git/sys/extend/addon/' . $repoName;
-					if (!is_dir($repoDir)) {
-						logger('Repo directory does not exist: ' . $repoDir);
-						json_return_and_die(array('message' => 'Invalid addon repo.', 'success' => false));
-					}
-					if (!is_writable($repoDir)) {
-						logger('Repo directory not writable to web server: ' . $repoDir);
-						json_return_and_die(array('message' => 'Repo directory not writable to web server.', 'success' => false));
-					}
-					/// @TODO remove directory and unlink /addon/files
-					if (rrmdir($repoDir)) {
-						json_return_and_die(array('message' => 'Repo deleted.', 'success' => true));
-					} else {
-						json_return_and_die(array('message' => 'Error deleting addon repo.', 'success' => false));
-					}
-					break;
-				case 'installrepo':
-					if (array_key_exists('repoURL', $_REQUEST)) {
-						require_once('library/PHPGit.autoload.php');			// Load PHPGit dependencies
-						$repoURL = $_REQUEST['repoURL'];
-						$extendDir = 'store/[data]/git/sys/extend';
-						$addonDir = $extendDir . '/addon';
-						if (!file_exists($extendDir)) {
-							if (!mkdir($extendDir, 0770, true)) {
-								logger('Error creating extend folder: ' . $extendDir);
-								json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
-							} else {
-								if (!symlink(realpath('extend/addon'), $addonDir)) {
-									logger('Error creating symlink to addon folder: ' . $addonDir);
-									json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
-								}
-							}
-						}
-						if (!is_writable($extendDir)) {
-							logger('Directory not writable to web server: ' . $extendDir);
-							json_return_and_die(array('message' => 'Directory not writable to web server.', 'success' => false));
-						}
-						$repoName = null;
-						if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
-							$repoName = $_REQUEST['repoName'];
-						} else {
-							$repoName = GitRepo::getRepoNameFromURL($repoURL);
-						}
-						if (!$repoName) {
-							logger('Invalid git repo');
-							json_return_and_die(array('message' => 'Invalid git repo', 'success' => false));
-						}
-						$repoDir = $addonDir . '/' . $repoName;
-						$tempRepoBaseDir = 'store/[data]/git/sys/temp/';
-						$tempAddonDir = $tempRepoBaseDir . $repoName;
-
-						if (!is_writable($addonDir) || !is_writable($tempAddonDir)) {
-							logger('Temp repo directory or /extend/addon not writable to web server: ' . $tempAddonDir);
-							json_return_and_die(array('message' => 'Temp repo directory not writable to web server.', 'success' => false));
-						}
-						rename($tempAddonDir, $repoDir);
-
-						if (!is_writable(realpath('addon/'))) {
-							logger('/addon directory not writable to web server: ' . $tempAddonDir);
-							json_return_and_die(array('message' => '/addon directory not writable to web server.', 'success' => false));
-						}
-						$files = array_diff(scandir($repoDir), array('.', '..'));
-						foreach ($files as $file) {
-							if (is_dir($repoDir . '/' . $file) && $file !== '.git') {
-								$source = '../extend/addon/' . $repoName . '/' . $file;
-								$target = realpath('addon/') . '/' . $file;
-								unlink($target);
-								if (!symlink($source, $target)) {
-									logger('Error linking addons to /addon');
-									json_return_and_die(array('message' => 'Error linking addons to /addon', 'success' => false));
-								}
-							}
-						}
-						$git = new GitRepo('sys', $repoURL, false, $repoName, $repoDir);
-						$repo = $git->probeRepo();
-						json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
-					}
-					break;
-				case 'addrepo':
-					if (array_key_exists('repoURL', $_REQUEST)) {
-						require_once('library/PHPGit.autoload.php');	 // Load PHPGit dependencies
-						$repoURL = $_REQUEST['repoURL'];
-						$extendDir = 'store/[data]/git/sys/extend';
-						$addonDir = $extendDir . '/addon';
-						$tempAddonDir = realpath('store/[data]') . '/git/sys/temp';
-						if (!file_exists($extendDir)) {
-							if (!mkdir($extendDir, 0770, true)) {
-								logger('Error creating extend folder: ' . $extendDir);
-								json_return_and_die(array('message' => 'Error creating extend folder: ' . $extendDir, 'success' => false));
-							} else {
-								if (!symlink(realpath('extend/addon'), $addonDir)) {
-									logger('Error creating symlink to addon folder: ' . $addonDir);
-									json_return_and_die(array('message' => 'Error creating symlink to addon folder: ' . $addonDir, 'success' => false));
-								}
-							}
-						}
-						if (!is_dir($tempAddonDir)) {
-							if (!mkdir($tempAddonDir, 0770, true)) {
-								logger('Error creating temp plugin repo folder: ' . $tempAddonDir);
-								json_return_and_die(array('message' => 'Error creating temp plugin repo folder: ' . $tempAddonDir, 'success' => false));
-							}
-						}
-						$repoName = null;
-						if (array_key_exists('repoName', $_REQUEST) && $_REQUEST['repoName'] !== '') {
-							$repoName = $_REQUEST['repoName'];
-						} else {
-							$repoName = GitRepo::getRepoNameFromURL($repoURL);
-						}
-						if (!$repoName) {
-							logger('Invalid git repo');
-							json_return_and_die(array('message' => 'Invalid git repo: ' . $repoName, 'success' => false));
-						}
-						$repoDir = $tempAddonDir . '/' . $repoName;
-						if (!is_writable($tempAddonDir)) {
-							logger('Temporary directory for new addon repo is not writable to web server: ' . $tempAddonDir);
-							json_return_and_die(array('message' => 'Temporary directory for new addon repo is not writable to web server.', 'success' => false));
-						}
-						// clone the repo if new automatically
-						$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
-
-						$remotes = $git->git->remote();
-						$fetchURL = $remotes['origin']['fetch'];
-						if ($fetchURL !== $git->url) {
-							if (rrmdir($repoDir)) {
-								$git = new GitRepo('sys', $repoURL, true, $repoName, $repoDir);
-							} else {
-								json_return_and_die(array('message' => 'Error deleting existing addon repo.', 'success' => false));
-							}
-						}
-						$repo = $git->probeRepo();
-						$repo['readme'] = $repo['manifest'] = null;
-						foreach ($git->git->tree('master') as $object) {
-							if ($object['type'] == 'blob' && (strtolower($object['file']) === 'readme.md' || strtolower($object['file']) === 'readme')) {
-								$repo['readme'] = MarkdownExtra::defaultTransform($git->git->cat->blob($object['hash']));
-							} else if ($object['type'] == 'blob' && strtolower($object['file']) === 'manifest.json') {
-								$repo['manifest'] = $git->git->cat->blob($object['hash']);
-							}
-						}
-						json_return_and_die(array('repo' => $repo, 'message' => '', 'success' => true));
-					} else {
-						json_return_and_die(array('message' => 'No repo URL provided', 'success' => false));
-					}
-					break;
-				default:
-					break;
-			}
-		}
 	}
 
 	/**
@@ -408,37 +186,6 @@ class Addons {
 
 		usort($plugins,'self::plugin_sort');
 
-		$allowManageRepos = false;
-		if(is_writable('extend/addon') && is_writable('store/[data]')) {
-			$allowManageRepos = true;
-		}
-
-		$admin_plugins_add_repo_form= replace_macros(
-			get_markup_template('admin_plugins_addrepo.tpl'), array(
-				'$post' => 'admin/addons/addrepo',
-				'$desc' => t('Enter the public git repository URL of the addon repo.'),
-				'$repoURL' => array('repoURL', t('Addon repo git URL'), '', ''),
-				'$repoName' => array('repoName', t('Custom repo name'), '', '', t('(optional)')),
-				'$submit' => t('Download Addon Repo')
-			)
-		);
-		$newRepoModalID = random_string(3);
-		$newRepoModal = replace_macros(
-			get_markup_template('generic_modal.tpl'), array(
-				'$id' => $newRepoModalID,
-				'$title' => t('Install new repo'),
-				'$ok' => t('Install'),
-				'$cancel' => t('Cancel')
-			)
-		);
-
-		$reponames = $this->listAddonRepos();
-		$addonrepos = [];
-		foreach($reponames as $repo) {
-			$addonrepos[] = array('name' => $repo, 'description' => '');
-			/// @TODO Parse repo info to provide more information about repos
-		}
-
 		$t = get_markup_template('admin_plugins.tpl');
 		return replace_macros($t, array(
 			'$title' => t('Administration'),
@@ -449,37 +196,9 @@ class Addons {
 			'$plugins' => $plugins,
 			'$disabled' => t('Disabled - version incompatibility'),
 			'$form_security_token' => get_form_security_token('admin_addons'),
-			'$allowManageRepos' => $allowManageRepos,
-			'$managerepos' => t('Manage Repos'),
-			'$installedtitle' => t('Installed Addon Repositories'),
-			'$addnewrepotitle' =>	t('Install a New Addon Repository'),
-			'$expandform' => false,
-			'$form' => $admin_plugins_add_repo_form,
-			'$newRepoModal' => $newRepoModal,
-			'$newRepoModalID' => $newRepoModalID,
-			'$addonrepos' => $addonrepos,
-			'$repoUpdateButton' => t('Update'),
-			'$repoBranchButton' => t('Switch branch'),
-			'$repoRemoveButton' => t('Remove')
 		));
 	}
 
-	function listAddonRepos() {
-		$addonrepos = [];
-		$addonDir = 'extend/addon/';
-		if(is_dir($addonDir)) {
-			if ($handle = opendir($addonDir)) {
-				while (false !== ($entry = readdir($handle))) {
-					if ($entry != "." && $entry != "..") {
-						$addonrepos[] = $entry;
-					}
-				}
-				closedir($handle);
-			}
-		}
-		return $addonrepos;
-	}
-
 	static public function plugin_sort($a,$b) {
 		return(strcmp(strtolower($a[2]['name']),strtolower($b[2]['name'])));
 	}
diff --git a/Zotlabs/Storage/GitRepo.php b/Zotlabs/Storage/GitRepo.php
deleted file mode 100644
index 306abc0ba..000000000
--- a/Zotlabs/Storage/GitRepo.php
+++ /dev/null
@@ -1,159 +0,0 @@
-
- */
-class GitRepo {
-
-	public $url = null;
-	public $name = null;
-	private $path = null;
-	private $channel = null;
-	public $git = null;
-	private $repoBasePath = null;
-
-	function __construct($channel = 'sys', $url = null, $clone = false, $name = null, $path = null) {
-
-		if ($channel === 'sys' && !is_site_admin()) {
-			logger('Only admin can use channel sys');
-			return null;
-		}
-
-		$this->repoBasePath = __DIR__ . '/../../store/git';
-		$this->channel = $channel;
-		$this->git = new PHPGit();
-
-		// Allow custom path for repo in the case of , for example
-		if ($path) {
-			$this->path = $path;
-		} else {
-			$this->path = $this->repoBasePath . "/" . $this->channel . "/" . $this->name;
-		}
-
-		if ($this->isValidGitRepoURL($url)) {
-			$this->url = $url;
-		}
-
-		if ($name) {
-			$this->name = $name;
-		} else {
-			$this->name = $this->getRepoNameFromURL($url);
-		}
-		if (!$this->name) {
-			logger('Error creating GitRepo. No repo name found.');
-			return null;
-		}
-
-		if (is_dir($this->path)) {
-			// ignore the $url input if it exists
-			// TODO: Check if the path is either empty or is a valid git repo and error if not
-			$this->git->setRepository($this->path);
-			// TODO: get repo metadata 
-			return;
-		}
-
-		if ($this->url) {
-			// create the folder and clone the repo at url to that folder if $clone is true
-			if ($clone) {
-				if (mkdir($this->path, 0770, true)) {
-					$this->git->setRepository($this->path);
-					if (!$this->cloneRepo()) {
-						// TODO: throw error
-						logger('git clone failed: ' . json_encode($this->git));
-					}
-				} else {
-					logger('git repo path could not be created: ' . json_encode($this->git));
-				}
-			}
-		}
-	}
-	
-	public function initRepo() {
-		if(!$this->path) return false;
-		try {
-			return $this->git->init($this->path);
-		} catch (\PHPGit\Exception\GitException $ex) {
-			return false;
-		}
-	}
-
-	public function pull() {
-		try {
-			$success = $this->git->pull();
-		} catch (\PHPGit\Exception\GitException $ex) {
-			return false;
-		}
-		return $success;
-	}
-
-	public function getRepoPath() {
-		return $this->path;
-	}
-
-	public function setRepoPath($directory) {
-		if (is_dir($directory)) {
-			$this->path->$directory;
-			$this->git->setRepository($directory);
-			return true;
-		}
-		return false;
-	}
-
-	public function setIdentity($user_name, $user_email) {
-		// setup user for commit messages
-		$this->git->config->set("user.name", $user_name, ['global' => false, 'system' => false]);
-		$this->git->config->set("user.email", $user_email, ['global' => false, 'system' => false]);
-	}
-
-	public function cloneRepo() {
-		if (validate_url($this->url) && $this->isValidGitRepoURL($this->url) && is_dir($this->path)) {
-			return $this->git->clone($this->url, $this->path);
-		}
-	}
-
-	public function probeRepo() {
-		$git = $this->git;
-		$repo = array();
-		$repo['remote'] = $git->remote();
-		$repo['branches'] = $git->branch(['all' => true]);
-		$repo['logs'] = $git->log(array('limit' => 50));
-		return $repo;
-	}
-	
-	// Commit changes to the repo. Default is to stage all changes and commit everything.
-	public function commit($msg, $options = array()) {
-		try {
-			return $this->git->commit($msg, $options);
-		} catch (\PHPGit\Exception\GitException $ex) {
-			return false;
-		}		
-	}
-
-	public static function isValidGitRepoURL($url) {
-		if (validate_url($url) && strrpos(parse_url($url, PHP_URL_PATH), '.')) {
-			return true;
-		} else {
-			return false;
-		}
-	}
-
-	public static function getRepoNameFromURL($url) {
-		$urlpath = parse_url($url, PHP_URL_PATH);
-		$lastslash = strrpos($urlpath, '/') + 1;
-		$gitext = strrpos($urlpath, '.');
-		if ($gitext) {
-			return substr($urlpath, $lastslash, $gitext - $lastslash);
-		} else {
-			return null;
-		}
-	}
-
-}
diff --git a/view/tpl/admin_plugins.tpl b/view/tpl/admin_plugins.tpl
index f231da2ad..659f87430 100644
--- a/view/tpl/admin_plugins.tpl
+++ b/view/tpl/admin_plugins.tpl
@@ -1,45 +1,8 @@
 
- {{if $allowManageRepos}} -
- -
- {{/if}}

{{$title}} - {{$page}}

-
@@ -47,9 +10,9 @@
{{foreach $plugins as $p}} -
+
- {{if ! $p.2.disabled}} + {{if ! $p.2.disabled}} {{else}} @@ -61,130 +24,6 @@
{{/foreach}} - +
-{{$newRepoModal}} - diff --git a/view/tpl/admin_plugins_addrepo.tpl b/view/tpl/admin_plugins_addrepo.tpl deleted file mode 100644 index e0e271d5a..000000000 --- a/view/tpl/admin_plugins_addrepo.tpl +++ /dev/null @@ -1,9 +0,0 @@ -
- -

{{$desc}}

- {{include file="field_input.tpl" field=$repoURL}} - {{include file="field_input.tpl" field=$repoName}} -
- -
-
-- cgit v1.2.3 From 2ed8908127f44a2a8d1326791e40668a425b7787 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Wed, 9 Oct 2024 21:02:08 +0200 Subject: Remove now unused PHPGit from library. --- library/composer/ClassLoader.php | 413 ------ library/composer/autoload_classmap.php | 9 - library/composer/autoload_namespaces.php | 11 - library/composer/autoload_psr4.php | 11 - library/composer/autoload_real.php | 50 - library/composer/installed.json | 157 --- library/kzykhys/git/.travis.yml | 20 - library/kzykhys/git/README.md | 1347 -------------------- library/kzykhys/git/phpunit.xml.dist | 28 - library/kzykhys/git/src/PHPGit/Command.php | 123 -- .../kzykhys/git/src/PHPGit/Command/AddCommand.php | 75 -- .../git/src/PHPGit/Command/ArchiveCommand.php | 96 -- .../git/src/PHPGit/Command/BranchCommand.php | 229 ---- .../kzykhys/git/src/PHPGit/Command/CatCommand.php | 91 -- .../git/src/PHPGit/Command/CheckoutCommand.php | 145 --- .../git/src/PHPGit/Command/CloneCommand.php | 71 -- .../git/src/PHPGit/Command/CommitCommand.php | 87 -- .../git/src/PHPGit/Command/ConfigCommand.php | 132 -- .../git/src/PHPGit/Command/DescribeCommand.php | 90 -- .../git/src/PHPGit/Command/FetchCommand.php | 112 -- .../kzykhys/git/src/PHPGit/Command/InitCommand.php | 65 - .../kzykhys/git/src/PHPGit/Command/LogCommand.php | 105 -- .../git/src/PHPGit/Command/MergeCommand.php | 110 -- .../kzykhys/git/src/PHPGit/Command/MvCommand.php | 70 - .../kzykhys/git/src/PHPGit/Command/PullCommand.php | 59 - .../kzykhys/git/src/PHPGit/Command/PushCommand.php | 65 - .../git/src/PHPGit/Command/RebaseCommand.php | 129 -- .../PHPGit/Command/Remote/SetBranchesCommand.php | 98 -- .../src/PHPGit/Command/Remote/SetHeadCommand.php | 120 -- .../src/PHPGit/Command/Remote/SetUrlCommand.php | 175 --- .../git/src/PHPGit/Command/RemoteCommand.php | 278 ---- .../git/src/PHPGit/Command/ResetCommand.php | 199 --- .../kzykhys/git/src/PHPGit/Command/RmCommand.php | 97 -- .../git/src/PHPGit/Command/ShortlogCommand.php | 134 -- .../kzykhys/git/src/PHPGit/Command/ShowCommand.php | 70 - .../git/src/PHPGit/Command/StashCommand.php | 309 ----- .../git/src/PHPGit/Command/StatusCommand.php | 147 --- .../kzykhys/git/src/PHPGit/Command/TagCommand.php | 156 --- .../kzykhys/git/src/PHPGit/Command/TreeCommand.php | 70 - .../git/src/PHPGit/Exception/GitException.php | 39 - library/kzykhys/git/src/PHPGit/Git.php | 308 ----- library/kzykhys/git/test/PHPGit/BaseTestCase.php | 33 - .../git/test/PHPGit/Command/AddCommandTest.php | 42 - .../git/test/PHPGit/Command/ArchiveCommandTest.php | 32 - .../git/test/PHPGit/Command/BranchCommandTest.php | 106 -- .../git/test/PHPGit/Command/CatCommandTest.php | 65 - .../test/PHPGit/Command/CheckoutCommandTest.php | 65 - .../git/test/PHPGit/Command/CloneCommandTest.php | 28 - .../git/test/PHPGit/Command/CommitCommandTest.php | 26 - .../git/test/PHPGit/Command/ConfigCommandTest.php | 55 - .../test/PHPGit/Command/DescribeCommandTest.php | 36 - .../git/test/PHPGit/Command/FetchCommandTest.php | 36 - .../git/test/PHPGit/Command/MergeCommandTest.php | 101 -- .../git/test/PHPGit/Command/MvCommandTest.php | 26 - .../git/test/PHPGit/Command/PullCommandTest.php | 22 - .../git/test/PHPGit/Command/PushCommandTest.php | 34 - .../git/test/PHPGit/Command/RebaseCommandTest.php | 154 --- .../Command/Remote/SetBranchesCommandTest.php | 28 - .../PHPGit/Command/Remote/SetHeadCommandTest.php | 56 - .../PHPGit/Command/Remote/SetUrlCommandTest.php | 46 - .../git/test/PHPGit/Command/RemoteCommandTest.php | 100 -- .../git/test/PHPGit/Command/ResetCommandTest.php | 128 -- .../git/test/PHPGit/Command/RmCommandTest.php | 51 - .../test/PHPGit/Command/ShortlogCommandTest.php | 71 -- .../git/test/PHPGit/Command/ShowCommandTest.php | 26 - .../git/test/PHPGit/Command/StashCommandTest.php | 204 --- .../git/test/PHPGit/Command/StatusCommandTest.php | 76 -- .../git/test/PHPGit/Command/TagCommandTest.php | 58 - .../git/test/PHPGit/Exception/GitExceptionTest.php | 23 - library/kzykhys/git/test/PHPGit/GitTest.php | 33 - 70 files changed, 7861 deletions(-) delete mode 100644 library/composer/ClassLoader.php delete mode 100644 library/composer/autoload_classmap.php delete mode 100644 library/composer/autoload_namespaces.php delete mode 100644 library/composer/autoload_psr4.php delete mode 100644 library/composer/autoload_real.php delete mode 100644 library/composer/installed.json delete mode 100644 library/kzykhys/git/.travis.yml delete mode 100644 library/kzykhys/git/README.md delete mode 100644 library/kzykhys/git/phpunit.xml.dist delete mode 100644 library/kzykhys/git/src/PHPGit/Command.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/AddCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/BranchCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/CatCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/CloneCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/CommitCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/FetchCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/InitCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/LogCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/MergeCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/MvCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/PullCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/PushCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/ResetCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/RmCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/ShowCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/StashCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/StatusCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/TagCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Command/TreeCommand.php delete mode 100644 library/kzykhys/git/src/PHPGit/Exception/GitException.php delete mode 100644 library/kzykhys/git/src/PHPGit/Git.php delete mode 100644 library/kzykhys/git/test/PHPGit/BaseTestCase.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php delete mode 100644 library/kzykhys/git/test/PHPGit/GitTest.php diff --git a/library/composer/ClassLoader.php b/library/composer/ClassLoader.php deleted file mode 100644 index 4e05d3b15..000000000 --- a/library/composer/ClassLoader.php +++ /dev/null @@ -1,413 +0,0 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0 class loader - * - * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - */ -class ClassLoader -{ - // PSR-4 - private $prefixLengthsPsr4 = array(); - private $prefixDirsPsr4 = array(); - private $fallbackDirsPsr4 = array(); - - // PSR-0 - private $prefixesPsr0 = array(); - private $fallbackDirsPsr0 = array(); - - private $useIncludePath = false; - private $classMap = array(); - - private $classMapAuthoritative = false; - - public function getPrefixes() - { - if (!empty($this->prefixesPsr0)) { - return call_user_func_array('array_merge', $this->prefixesPsr0); - } - - return array(); - } - - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-0 base directories - * @param bool $prepend Whether to prepend the directories - * - * @throws \InvalidArgumentException - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - * - * @throws \InvalidArgumentException - */ - public function setPsr4($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Turns off searching the prefix and fallback directories for classes - * that have not been registered with the class map. - * - * @param bool $classMapAuthoritative - */ - public function setClassMapAuthoritative($classMapAuthoritative) - { - $this->classMapAuthoritative = $classMapAuthoritative; - } - - /** - * Should class lookup fail if not found in the current class map? - * - * @return bool - */ - public function isClassMapAuthoritative() - { - return $this->classMapAuthoritative; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - } - - /** - * Unregisters this instance as an autoloader. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - includeFile($file); - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 - if ('\\' == $class[0]) { - $class = substr($class, 1); - } - - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - if ($this->classMapAuthoritative) { - return false; - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if ($file === null && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if ($file === null) { - // Remember that this class does not exist. - return $this->classMap[$class] = false; - } - - return $file; - } - - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach ($this->prefixDirsPsr4[$prefix] as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (is_file($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - } -} - -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; -} diff --git a/library/composer/autoload_classmap.php b/library/composer/autoload_classmap.php deleted file mode 100644 index 7a91153b0..000000000 --- a/library/composer/autoload_classmap.php +++ /dev/null @@ -1,9 +0,0 @@ - array($baseDir . '/src'), - '' => array($vendorDir . '/kzykhys/git/src'), -); diff --git a/library/composer/autoload_psr4.php b/library/composer/autoload_psr4.php deleted file mode 100644 index 1ccbde8ed..000000000 --- a/library/composer/autoload_psr4.php +++ /dev/null @@ -1,11 +0,0 @@ - array($vendorDir . '/symfony/process'), - 'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'), -); diff --git a/library/composer/autoload_real.php b/library/composer/autoload_real.php deleted file mode 100644 index 59b376b09..000000000 --- a/library/composer/autoload_real.php +++ /dev/null @@ -1,50 +0,0 @@ - $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - - $loader->register(true); - - return $loader; - } -} - -function composerRequire929ad7f4e2f44798d12d2ab06db7b39b($file) -{ - require $file; -} diff --git a/library/composer/installed.json b/library/composer/installed.json deleted file mode 100644 index 23dbdb9c7..000000000 --- a/library/composer/installed.json +++ /dev/null @@ -1,157 +0,0 @@ -[ - { - "name": "symfony/process", - "version": "v2.8.0", - "version_normalized": "2.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/1b988a88e3551102f3c2d9e1d47a18c3a78d6312", - "reference": "1b988a88e3551102f3c2d9e1d47a18c3a78d6312", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "time": "2015-11-30 12:35:10", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Process Component", - "homepage": "https://symfony.com" - }, - { - "name": "symfony/options-resolver", - "version": "v2.8.0", - "version_normalized": "2.8.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "e7f62cf7d9e48238299cfa5d0556aee8cff1e075" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/e7f62cf7d9e48238299cfa5d0556aee8cff1e075", - "reference": "e7f62cf7d9e48238299cfa5d0556aee8cff1e075", - "shasum": "" - }, - "require": { - "php": ">=5.3.9" - }, - "time": "2015-11-18 13:45:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.8-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony OptionsResolver Component", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ] - }, - { - "name": "kzykhys/git", - "version": "dev-master", - "version_normalized": "9999999-dev", - "source": { - "type": "git", - "url": "https://github.com/kzykhys/PHPGit.git", - "reference": "8b3ee3147d58e0aee62610f0aebcd30eb076ad5d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kzykhys/PHPGit/zipball/8b3ee3147d58e0aee62610f0aebcd30eb076ad5d", - "reference": "8b3ee3147d58e0aee62610f0aebcd30eb076ad5d", - "shasum": "" - }, - "require": { - "php": ">=5.3.2", - "symfony/options-resolver": ">=2.3", - "symfony/process": ">=2.3" - }, - "require-dev": { - "symfony/filesystem": ">=2.3" - }, - "time": "2014-02-27 13:14:59", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "installation-source": "source", - "autoload": { - "psr-0": { - "": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kazuyuki Hayashi", - "email": "hayashi@valnur.net" - } - ], - "description": "A Git wrapper for PHP5.3+" - } -] diff --git a/library/kzykhys/git/.travis.yml b/library/kzykhys/git/.travis.yml deleted file mode 100644 index ff4164104..000000000 --- a/library/kzykhys/git/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: php - -php: - - 5.5 - - 5.4 - - 5.3 - -before_script: - - composer require --no-update satooshi/php-coveralls:dev-master@dev sensiolabs/security-checker:dev-master - - composer update --dev --no-interaction - - git config --global user.name "John Doe" - - git config --global user.email "example@example.com" - -script: - - mkdir -p build/logs - - phpunit -c phpunit.xml.dist --coverage-clover build/logs/clover.xml - - php vendor/bin/security-checker security:check composer.lock - -after_script: - - php vendor/bin/coveralls \ No newline at end of file diff --git a/library/kzykhys/git/README.md b/library/kzykhys/git/README.md deleted file mode 100644 index b2f6635af..000000000 --- a/library/kzykhys/git/README.md +++ /dev/null @@ -1,1347 +0,0 @@ -PHPGit - A Git wrapper for PHP5.3+ -================================== - -[![Latest Unstable Version](https://poser.pugx.org/kzykhys/git/v/unstable.png)](https://packagist.org/packages/kzykhys/git) -[![Build Status](https://travis-ci.org/kzykhys/PHPGit.png?branch=master)](https://travis-ci.org/kzykhys/PHPGit) -[![Coverage Status](https://coveralls.io/repos/kzykhys/PHPGit/badge.png)](https://coveralls.io/r/kzykhys/PHPGit) -[![SensioLabsInsight](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f/mini.png)](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f) - -Requirements ------------- - -* PHP5.3 -* Git - -Installation ------------- - -Update your composer.json and run `composer update` - -``` json -{ - "require": { - "kzykhys/git": "dev-master" - } -} -``` - -Basic Usage ------------ - -``` php -clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -$git->remote->add('production', 'git://example.com/your/repo.git'); -$git->add('README.md'); -$git->commit('Adds README.md'); -$git->checkout('release'); -$git->merge('master'); -$git->push(); -$git->push('production', 'release'); -$git->tag->create('v1.0.1', 'release'); - -foreach ($git->tree('release') as $object) { - if ($object['type'] == 'blob') { - echo $git->show($object['file']); - } -} -``` - -API ---- - -### Git commands - -* [git add](#git-add) - * $git->[add](#git-addstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) -* [git archive](#git-archive) - * $git->[archive](#git-archivestring-file-string-tree--null-stringarraytraversable-path--null-array-options--)(_string_ $file, _string_ $tree = null, _string|array|\Traversable_ $path = null, _array_ $options = []) -* [git branch](#git-branch) - * $git->[branch](#git-brancharray-options--)(_array_ $options = []) - * $git->branch->[create](#git-branch-createstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) - * $git->branch->[move](#git-branch-movestring-branch-string-newbranch-array-options--)(_string_ $branch, _string_ $newBranch, _array_ $options = []) - * $git->branch->[delete](#git-branch-deletestring-branch-array-options--)(_string_ $branch, _array_ $options = []) -* [git cat-file](#git-cat-file) - * $git->cat->[blob](#git-cat-blobstring-object)(_string_ $object) - * $git->cat->[type](#git-cat-typestring-object)(_string_ $object) - * $git->cat->[size](#git-cat-sizestring-object)(_string_ $object) -* [git checkout](#git-checkout) - * $git->[checkout](#git-checkoutstring-branch-array-options--)(_string_ $branch, _array_ $options = []) - * $git->checkout->[create](#git-checkout-createstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) - * $git->checkout->[orphan](#git-checkout-orphanstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) -* [git clone](#git-clone) - * $git->[clone](#git-clonestring-repository-string-path--null-array-options--)(_string_ $repository, _string_ $path = null, _array_ $options = []) -* [git commit](#git-commit) - * $git->[commit](#git-commitstring-message-array-options--)(_string_ $message, _array_ $options = []) -* [git config](#git-config) - * $git->[config](#git-configarray-options--)(_array_ $options = []) - * $git->config->[set](#git-config-setstring-name-string-value-array-options--)(_string_ $name, _string_ $value, _array_ $options = []) - * $git->config->[add](#git-config-addstring-name-string-value-array-options--)(_string_ $name, _string_ $value, _array_ $options = []) -* [git describe](#git-describe) - * $git->[describe](#git-describestring-committish--null-array-options--)(_string_ $committish = null, _array_ $options = []) - * $git->describe->[tags](#git-describe-tagsstring-committish--null-array-options--)(_string_ $committish = null, _array_ $options = []) -* [git fetch](#git-fetch) - * $git->[fetch](#git-fetchstring-repository-string-refspec--null-array-options--)(_string_ $repository, _string_ $refspec = null, _array_ $options = []) - * $git->fetch->[all](#git-fetch-allarray-options--)(_array_ $options = []) -* [git init](#git-init) - * $git->[init](#git-initstring-path-array-options--)(_string_ $path, _array_ $options = []) -* [git log](#git-log) - * $git->[log](#git-logstring-revrange---string-path--null-array-options--)(_string_ $revRange = '', _string_ $path = null, _array_ $options = []) -* [git merge](#git-merge) - * $git->[merge](#git-mergestringarraytraversable-commit-string-message--null-array-options--)(_string|array|\Traversable_ $commit, _string_ $message = null, _array_ $options = []) - * $git->merge->[abort](#git-merge-abort)() -* [git mv](#git-mv) - * $git->[mv](#git-mvstringarrayiterator-source-string-destination-array-options--)(_string|array|\Iterator_ $source, _string_ $destination, _array_ $options = []) -* [git pull](#git-pull) - * $git->[pull](#git-pullstring-repository--null-string-refspec--null-array-options--)(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) -* [git push](#git-push) - * $git->[push](#git-pushstring-repository--null-string-refspec--null-array-options--)(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) -* [git rebase](#git-rebase) - * $git->[rebase](#git-rebasestring-upstream--null-string-branch--null-array-options--)(_string_ $upstream = null, _string_ $branch = null, _array_ $options = []) - * $git->rebase->[continues](#git-rebase-continues)() - * $git->rebase->[abort](#git-rebase-abort)() - * $git->rebase->[skip](#git-rebase-skip)() -* [git remote](#git-remote) - * $git->[remote](#git-remote)() - * $git->remote->[add](#git-remote-addstring-name-string-url-array-options--)(_string_ $name, _string_ $url, _array_ $options = []) - * $git->remote->[rename](#git-remote-renamestring-name-string-newname)(_string_ $name, _string_ $newName) - * $git->remote->[rm](#git-remote-rmstring-name)(_string_ $name) - * $git->remote->[show](#git-remote-showstring-name)(_string_ $name) - * $git->remote->[prune](#git-remote-prunestring-name--null)(_string_ $name = null) - * $git->remote->[head](#git-remote-headstring-name-string-branch--null)(_string_ $name, _string_ $branch = null) - * $git->remote->head->[set](#git-remote-head-setstring-name-string-branch)(_string_ $name, _string_ $branch) - * $git->remote->head->[delete](#git-remote-head-deletestring-name)(_string_ $name) - * $git->remote->head->[remote](#git-remote-head-remotestring-name)(_string_ $name) - * $git->remote->[branches](#git-remote-branchesstring-name-array-branches)(_string_ $name, _array_ $branches) - * $git->remote->branches->[set](#git-remote-branches-setstring-name-array-branches)(_string_ $name, _array_ $branches) - * $git->remote->branches->[add](#git-remote-branches-addstring-name-array-branches)(_string_ $name, _array_ $branches) - * $git->remote->[url](#git-remote-urlstring-name-string-newurl-string-oldurl--null-array-options--)(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) - * $git->remote->url->[set](#git-remote-url-setstring-name-string-newurl-string-oldurl--null-array-options--)(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) - * $git->remote->url->[add](#git-remote-url-addstring-name-string-newurl-array-options--)(_string_ $name, _string_ $newUrl, _array_ $options = []) - * $git->remote->url->[delete](#git-remote-url-deletestring-name-string-url-array-options--)(_string_ $name, _string_ $url, _array_ $options = []) -* [git reset](#git-reset) - * $git->[reset](#git-resetstringarraytraversable-paths-string-commit--null)(_string|array|\Traversable_ $paths, _string_ $commit = null) - * $git->reset->[soft](#git-reset-softstring-commit--null)(_string_ $commit = null) - * $git->reset->[mixed](#git-reset-mixedstring-commit--null)(_string_ $commit = null) - * $git->reset->[hard](#git-reset-hardstring-commit--null)(_string_ $commit = null) - * $git->reset->[merge](#git-reset-mergestring-commit--null)(_string_ $commit = null) - * $git->reset->[keep](#git-reset-keepstring-commit--null)(_string_ $commit = null) - * $git->reset->[mode](#git-reset-modestring-mode-string-commit--null)(_string_ $mode, _string_ $commit = null) -* [git rm](#git-rm) - * $git->[rm](#git-rmstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) - * $git->rm->[cached](#git-rm-cachedstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) -* [git shortlog](#git-shortlog) - * $git->[shortlog](#git-shortlogstringarraytraversable-commits--head)(_string|array|\Traversable_ $commits = HEAD) - * $git->shortlog->[summary](#git-shortlog-summarystring-commits--head)(_string_ $commits = HEAD) -* [git show](#git-show) - * $git->[show](#git-showstring-object-array-options--)(_string_ $object, _array_ $options = []) -* [git stash](#git-stash) - * $git->[stash](#git-stash)() - * $git->stash->[save](#git-stash-savestring-message--null-array-options--)(_string_ $message = null, _array_ $options = []) - * $git->stash->[lists](#git-stash-listsarray-options--)(_array_ $options = []) - * $git->stash->[show](#git-stash-showstring-stash--null)(_string_ $stash = null) - * $git->stash->[drop](#git-stash-dropstring-stash--null)(_string_ $stash = null) - * $git->stash->[pop](#git-stash-popstring-stash--null-array-options--)(_string_ $stash = null, _array_ $options = []) - * $git->stash->[apply](#git-stash-applystring-stash--null-array-options--)(_string_ $stash = null, _array_ $options = []) - * $git->stash->[branch](#git-stash-branchstring-name-string-stash--null)(_string_ $name, _string_ $stash = null) - * $git->stash->[clear](#git-stash-clear)() - * $git->stash->[create](#git-stash-create)() -* [git status](#git-status) - * $git->[status](#git-statusarray-options--)(_array_ $options = []) -* [git tag](#git-tag) - * $git->[tag](#git-tag)() - * $git->tag->[create](#git-tag-createstring-tag-string-commit--null-array-options--)(_string_ $tag, _string_ $commit = null, _array_ $options = []) - * $git->tag->[delete](#git-tag-deletestringarraytraversable-tag)(_string|array|\Traversable_ $tag) - * $git->tag->[verify](#git-tag-verifystringarraytraversable-tag)(_string|array|\Traversable_ $tag) -* [git ls-tree](#git-ls-tree) - * $git->[tree](#git-treestring-branch--master-string-path--)(_string_ $branch = master, _string_ $path = '') - -* * * * * - -### git add - -#### $git->add(_string|array|\Traversable_ $file, _array_ $options = []) - -Add file contents to the index - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->add('file.txt'); -$git->add('file.txt', ['force' => false, 'ignore-errors' => false); -``` - -##### Options - -- **force** (_boolean_) Allow adding otherwise ignored files -- **ignore-errors** (_boolean_) Do not abort the operation - -* * * * * - -### git archive - -#### $git->archive(_string_ $file, _string_ $tree = null, _string|array|\Traversable_ $path = null, _array_ $options = []) - -Create an archive of files from a named tree - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->archive('repo.zip', 'master', null, ['format' => 'zip']); -``` - -##### Options - -- **format** (_boolean_) Format of the resulting archive: tar or zip -- **prefix** (_boolean_) Prepend prefix/ to each filename in the archive - -* * * * * - -### git branch - -#### $git->branch(_array_ $options = []) - -Returns an array of both remote-tracking branches and local branches - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$branches = $git->branch(); -``` - -##### Output Example - -``` -[ - 'master' => ['current' => true, 'name' => 'master', 'hash' => 'bf231bb', 'title' => 'Initial Commit'], - 'origin/master' => ['current' => false, 'name' => 'origin/master', 'alias' => 'remotes/origin/master'] -] -``` - -##### Options - -- **all** (_boolean_) List both remote-tracking branches and local branches -- **remotes** (_boolean_) List the remote-tracking branches - -#### $git->branch->create(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) - -Creates a new branch head named **$branch** which points to the current HEAD, or **$startPoint** if given - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->branch->create('bugfix'); // from current HEAD -$git->branch->create('patch-1', 'a092bf7s'); // from commit -$git->branch->create('1.0.x-fix', 'v1.0.2'); // from tag -``` - -##### Options - -- **force** (_boolean_) Reset **$branch** to **$startPoint** if **$branch** exists already - -#### $git->branch->move(_string_ $branch, _string_ $newBranch, _array_ $options = []) - -Move/rename a branch and the corresponding reflog - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->branch->move('bugfix', '2.0'); -``` - -##### Options - -- **force** (_boolean_) Move/rename a branch even if the new branch name already exists - -#### $git->branch->delete(_string_ $branch, _array_ $options = []) - -Delete a branch - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->branch->delete('2.0'); -``` - -The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with --track or --set-upstream. - -##### Options - -- **force** (_boolean_) Delete a branch irrespective of its merged status - -* * * * * - -### git cat-file - -#### $git->cat->blob(_string_ $object) - -Returns the contents of blob object - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$contents = $git->cat->blob('e69de29bb2d1d6434b8b29ae775ad8'); -``` - -#### $git->cat->type(_string_ $object) - -Returns the object type identified by **$object** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$type = $git->cat->type('e69de29bb2d1d6434b8b29ae775ad8'); -``` - -#### $git->cat->size(_string_ $object) - -Returns the object size identified by **$object** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$type = $git->cat->size('e69de29bb2d1d6434b8b29ae775ad8'); -``` - -* * * * * - -### git checkout - -#### $git->checkout(_string_ $branch, _array_ $options = []) - -Switches branches by updating the index, working tree, and HEAD to reflect the specified branch or commit - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->checkout('develop'); -``` - -##### Options - -- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD -- **merge** (_boolean_) Merges local modification - -#### $git->checkout->create(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) - -Create a new branch and checkout - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->checkout->create('patch-1'); -$git->checkout->create('patch-2', 'develop'); -``` - -##### Options - -- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - -#### $git->checkout->orphan(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) - -Create a new orphan branch, named , started from and switch to it - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->checkout->orphan('gh-pages'); -``` - -##### Options - -- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - -* * * * * - -### git clone - -#### $git->clone(_string_ $repository, _string_ $path = null, _array_ $options = []) - -Clone a repository into a new directory - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); -``` - -##### Options - -- **shared** (_boolean_) Starts out without any object of its own -- **bare** (_boolean_) Make a bare GIT repository - -* * * * * - -### git commit - -#### $git->commit(_string_ $message, _array_ $options = []) - -Record changes to the repository - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -$git->add('README.md'); -$git->commit('Fixes README.md'); -``` - -##### Options - -- **all** (_boolean_) Stage files that have been modified and deleted -- **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit -- **squash** (_string_) Construct a commit message for use with rebase --autosquash -- **author** (_string_) Override the commit author -- **date** (_string_) Override the author date used in the commit -- **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default -- **amend** (_boolean_) Used to amend the tip of the current branch - -* * * * * - -### git config - -#### $git->config(_array_ $options = []) - -Returns all variables set in config file - - -##### Options - -- **global** (_boolean_) Read or write configuration options for the current user -- **system** (_boolean_) Read or write configuration options for all users on the current machine - -#### $git->config->set(_string_ $name, _string_ $value, _array_ $options = []) - -Set an option - -##### Options - -- **global** (_boolean_) Read or write configuration options for the current user -- **system** (_boolean_) Read or write configuration options for all users on the current machine - -#### $git->config->add(_string_ $name, _string_ $value, _array_ $options = []) - -Adds a new line to the option without altering any existing values - -##### Options - -- **global** (_boolean_) Read or write configuration options for the current user -- **system** (_boolean_) Read or write configuration options for all users on the current machine - -* * * * * - -### git describe - -#### $git->describe(_string_ $committish = null, _array_ $options = []) - -Returns the most recent tag that is reachable from a commit - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->tag->create('v1.0.0'); -$git->commit('Fixes #14'); -echo $git->describe('HEAD', ['tags' => true]); -``` - -##### Output Example - -``` -v1.0.0-1-g7049efc -``` - -##### Options - -- **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag -- **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag -- **always** (_boolean_) Show uniquely abbreviated commit object as fallback - -#### $git->describe->tags(_string_ $committish = null, _array_ $options = []) - -Equivalent to $git->describe($committish, ['tags' => true]); - -* * * * * - -### git fetch - -#### $git->fetch(_string_ $repository, _string_ $refspec = null, _array_ $options = []) - -Fetches named heads or tags from one or more other repositories, along with the objects necessary to complete them - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'git://your/repo.git'); -$git->fetch('origin'); -``` - -##### Options - -- **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD -- **keep** (_boolean_) Keep downloaded pack -- **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote - -#### $git->fetch->all(_array_ $options = []) - -Fetch all remotes - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'git://your/repo.git'); -$git->remote->add('release', 'git://your/another_repo.git'); -$git->fetch->all(); -``` - -##### Options - -- **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD -- **keep** (_boolean_) Keep downloaded pack -- **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote - -* * * * * - -### git init - -#### $git->init(_string_ $path, _array_ $options = []) - -Create an empty git repository or reinitialize an existing one - -``` php -$git = new PHPGit\Git(); -$git->init('/path/to/repo1'); -$git->init('/path/to/repo2', array('shared' => true, 'bare' => true)); -``` - -##### Options - -- **shared** (_boolean_) Specify that the git repository is to be shared amongst several users -- **bare** (_boolean_) Create a bare repository - -* * * * * - -### git log - -#### $git->log(_string_ $revRange = '', _string_ $path = null, _array_ $options = []) - -Returns the commit logs - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$logs = $git->log(array('limit' => 10)); -``` - -##### Output Example - -``` php -[ - 0 => [ - 'hash' => '1a821f3f8483747fd045eb1f5a31c3cc3063b02b', - 'name' => 'John Doe', - 'email' => 'john@example.com', - 'date' => 'Fri Jan 17 16:32:49 2014 +0900', - 'title' => 'Initial Commit' - ], - 1 => [ - //... - ] -] -``` - -##### Options - -- **limit** (_integer_) Limits the number of commits to show -- **skip** (_integer_) Skip number commits before starting to show the commit output - -* * * * * - -### git merge - -#### $git->merge(_string|array|\Traversable_ $commit, _string_ $message = null, _array_ $options = []) - -Incorporates changes from the named commits into the current branch - -```php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->merge('1.0'); -$git->merge('1.1', 'Merge message', ['strategy' => 'ours']); -``` - -##### Options - -- **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer -- **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible -- **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch -- **strategy** (_string_) Use the given merge strategy -- **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy - -#### $git->merge->abort() - -Abort the merge process and try to reconstruct the pre-merge state - -```php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -try { - $git->merge('dev'); -} catch (PHPGit\Exception\GitException $e) { - $git->merge->abort(); -} -``` - -* * * * * - -### git mv - -#### $git->mv(_string|array|\Iterator_ $source, _string_ $destination, _array_ $options = []) - -Move or rename a file, a directory, or a symlink - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->mv('UPGRADE-1.0.md', 'UPGRADE-1.1.md'); -``` - -##### Options - -- **force** (_boolean_) Force renaming or moving of a file even if the target exists - -* * * * * - -### git pull - -#### $git->pull(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) - -Fetch from and merge with another repository or a local branch - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->pull('origin', 'master'); -``` - -* * * * * - -### git push - -#### $git->push(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) - -Update remote refs along with associated objects - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->push('origin', 'master'); -``` - -* * * * * - -### git rebase - -#### $git->rebase(_string_ $upstream = null, _string_ $branch = null, _array_ $options = []) - -Forward-port local commits to the updated upstream head - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->fetch('origin'); -$git->rebase('origin/master'); -``` - -##### Options - -- **onto** (_string_) Starting point at which to create the new commits -- **no-verify** (_boolean_) Bypasses the pre-rebase hook -- **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto - -#### $git->rebase->continues() - -Restart the rebasing process after having resolved a merge conflict - -#### $git->rebase->abort() - -Abort the rebase operation and reset HEAD to the original branch - -#### $git->rebase->skip() - -Restart the rebasing process by skipping the current patch - -* * * * * - -### git remote - -#### $git->remote() - -Returns an array of existing remotes - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -$remotes = $git->remote(); -``` - -##### Output Example - -``` php -[ - 'origin' => [ - 'fetch' => 'https://github.com/kzykhys/Text.git', - 'push' => 'https://github.com/kzykhys/Text.git' - ] -] -``` - -#### $git->remote->add(_string_ $name, _string_ $url, _array_ $options = []) - -Adds a remote named **$name** for the repository at **$url** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->fetch('origin'); -``` - -##### Options - -- **tags** (_boolean_) With this option, `git fetch ` imports every tag from the remote repository -- **no-tags** (_boolean_) With this option, `git fetch ` does not import tags from the remote repository - -#### $git->remote->rename(_string_ $name, _string_ $newName) - -Rename the remote named **$name** to **$newName** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->rename('origin', 'upstream'); -``` - -#### $git->remote->rm(_string_ $name) - -Remove the remote named **$name** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->rm('origin'); -``` - -#### $git->remote->show(_string_ $name) - -Gives some information about the remote **$name** - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -echo $git->remote->show('origin'); -``` - -##### Output Example - -``` -\* remote origin - Fetch URL: https://github.com/kzykhys/Text.git - Push URL: https://github.com/kzykhys/Text.git - HEAD branch: master - Remote branch: - master tracked - Local branch configured for 'git pull': - master merges with remote master - Local ref configured for 'git push': - master pushes to master (up to date) -``` - -#### $git->remote->prune(_string_ $name = null) - -Deletes all stale remote-tracking branches under **$name** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->prune('origin'); -``` - -#### $git->remote->head(_string_ $name, _string_ $branch = null) - -Alias of set() - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->head('origin'); -``` - -#### $git->remote->head->set(_string_ $name, _string_ $branch) - -Sets the default branch for the named remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->head->set('origin'); -``` - -#### $git->remote->head->delete(_string_ $name) - -Deletes the default branch for the named remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->head->delete('origin'); -``` - -#### $git->remote->head->remote(_string_ $name) - -Determine the default branch by querying remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->head->remote('origin'); -``` - -#### $git->remote->branches(_string_ $name, _array_ $branches) - -Alias of set() - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->branches('origin', array('master', 'develop')); -``` - -#### $git->remote->branches->set(_string_ $name, _array_ $branches) - -Changes the list of branches tracked by the named remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->branches->set('origin', array('master', 'develop')); -``` - -#### $git->remote->branches->add(_string_ $name, _array_ $branches) - -Adds to the list of branches tracked by the named remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->branches->add('origin', array('master', 'develop')); -``` - -#### $git->remote->url(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) - -Alias of set() - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->url('origin', 'https://github.com/text/Text.git'); -``` - -##### Options - -- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - -#### $git->remote->url->set(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) - -Sets the URL remote to $newUrl - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->url->set('origin', 'https://github.com/text/Text.git'); -``` - -##### Options - -- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - -#### $git->remote->url->add(_string_ $name, _string_ $newUrl, _array_ $options = []) - -Adds new URL to remote - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->url->add('origin', 'https://github.com/text/Text.git'); -``` - -##### Options - -- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - -#### $git->remote->url->delete(_string_ $name, _string_ $url, _array_ $options = []) - -Deletes all URLs matching regex $url - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); -$git->remote->url->delete('origin', 'https://github.com'); -``` - -##### Options - -- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - -* * * * * - -### git reset - -#### $git->reset(_string|array|\Traversable_ $paths, _string_ $commit = null) - -Resets the index entries for all **$paths** to their state at **$commit** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset(); -``` - -#### $git->reset->soft(_string_ $commit = null) - -Resets the current branch head to **$commit** - -Does not touch the index file nor the working tree at all (but resets the head to **$commit**, -just like all modes do). -This leaves all your changed files "Changes to be committed", as git status would put it. - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->soft(); -``` - -#### $git->reset->mixed(_string_ $commit = null) - -Resets the current branch head to **$commit** - -Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) -and reports what has not been updated. This is the default action. - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->mixed(); -``` - -#### $git->reset->hard(_string_ $commit = null) - -Resets the current branch head to **$commit** - -Resets the index and working tree. Any changes to tracked files in the working tree since **$commit** are discarded - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->hard(); -``` - -#### $git->reset->merge(_string_ $commit = null) - -Resets the current branch head to **$commit** - -Resets the index and updates the files in the working tree that are different between **$commit** and HEAD, -but keeps those which are different between the index and working tree -(i.e. which have changes which have not been added). If a file that is different between **$commit** and -the index has unstaged changes, reset is aborted - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->merge(); -``` - -#### $git->reset->keep(_string_ $commit = null) - -Resets the current branch head to **$commit** - -Resets index entries and updates files in the working tree that are different between **$commit** and HEAD. -If a file that is different between **$commit** and HEAD has local changes, reset is aborted. - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->keep(); -``` - -#### $git->reset->mode(_string_ $mode, _string_ $commit = null) - -Resets the current branch head to **$commit** - -Possibly updates the index (resetting it to the tree of **$commit**) and the working tree depending on **$mode** - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->reset->mode('hard'); -``` - -* * * * * - -### git rm - -#### $git->rm(_string|array|\Traversable_ $file, _array_ $options = []) - -Remove files from the working tree and from the index - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->rm('CHANGELOG-1.0-1.1.txt', ['force' => true]); -``` - -##### Options - -- **force** (_boolean_) Override the up-to-date check -- **cached** (_boolean_) Unstage and remove paths only from the index -- **recursive** (_boolean_) Allow recursive removal when a leading directory name is given - -#### $git->rm->cached(_string|array|\Traversable_ $file, _array_ $options = []) - -Equivalent to $git->rm($file, ['cached' => true]); - -##### Options - -- **force** (_boolean_) Override the up-to-date check -- **recursive** (_boolean_) Allow recursive removal when a leading directory name is given - -* * * * * - -### git shortlog - -#### $git->shortlog(_string|array|\Traversable_ $commits = HEAD) - -Summarize 'git log' output - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$shortlog = $git->shortlog(); -``` - -##### Output Example - -``` php -[ - 'John Doe ' => [ - 0 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-10 12:56:15 +0300'), 'subject' => 'Update README'], - 1 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-15 12:56:15 +0300'), 'subject' => 'Update README'], - ], - //... -] -``` - -#### $git->shortlog->summary(_string_ $commits = HEAD) - -Suppress commit description and provide a commit count summary only - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$shortlog = $git->shortlog->summary(); -``` - -##### Output Example - -``` php -[ - 'John Doe ' => 153, - //... -] -``` - -* * * * * - -### git show - -#### $git->show(_string_ $object, _array_ $options = []) - -Shows one or more objects (blobs, trees, tags and commits) - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -echo $git->show('3ddee587e209661c8265d5bfd0df999836f6dfa2'); -``` - -##### Options - -- **format** (_string_) Pretty-print the contents of the commit logs in a given format, where can be one of oneline, short, medium, full, fuller, email, raw and format: -- **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix - -* * * * * - -### git stash - -#### $git->stash() - -Save your local modifications to a new stash, and run git reset --hard to revert them - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash(); -``` - -#### $git->stash->save(_string_ $message = null, _array_ $options = []) - -Save your local modifications to a new stash, and run git reset --hard to revert them. - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->save('My stash'); -``` - -#### $git->stash->lists(_array_ $options = []) - -Returns the stashes that you currently have - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$stashes = $git->stash->lists(); -``` - -##### Output Example - -``` php -[ - 0 => ['branch' => 'master', 'message' => '0e2f473 Fixes README.md'], - 1 => ['branch' => 'master', 'message' => 'ce1ddde Initial commit'], -] -``` - -#### $git->stash->show(_string_ $stash = null) - -Show the changes recorded in the stash as a diff between the stashed state and its original parent - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -echo $git->stash->show('stash@{0}'); -``` - -##### Output Example - -``` - REAMDE.md | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) -``` - -#### $git->stash->drop(_string_ $stash = null) - -Remove a single stashed state from the stash list - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->drop('stash@{0}'); -``` - -#### $git->stash->pop(_string_ $stash = null, _array_ $options = []) - -Remove a single stashed state from the stash list and apply it on top of the current working tree state - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->pop('stash@{0}'); -``` - -#### $git->stash->apply(_string_ $stash = null, _array_ $options = []) - -Like pop, but do not remove the state from the stash list - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->apply('stash@{0}'); -``` - -#### $git->stash->branch(_string_ $name, _string_ $stash = null) - -Creates and checks out a new branch named starting from the commit at which the was originally created, applies the changes recorded in to the new working tree and index - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->branch('hotfix', 'stash@{0}'); -``` - -#### $git->stash->clear() - -Remove all the stashed states - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->stash->clear(); -``` - -#### $git->stash->create() - -Create a stash (which is a regular commit object) and return its object name, without storing it anywhere in the ref namespace - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$commit = $git->stash->create(); -``` - -##### Output Example - -``` -877316ea6f95c43b7ccc2c2a362eeedfa78b597d -``` - -* * * * * - -### git status - -#### $git->status(_array_ $options = []) - -Returns the working tree status - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$status = $git->status(); -``` - -##### Constants - -- StatusCommand::UNMODIFIED [=' '] unmodified -- StatusCommand::MODIFIED [='M'] modified -- StatusCommand::ADDED [='A'] added -- StatusCommand::DELETED [='D'] deleted -- StatusCommand::RENAMED [='R'] renamed -- StatusCommand::COPIED [='C'] copied -- StatusCommand::UPDATED_BUT_UNMERGED [='U'] updated but unmerged -- StatusCommand::UNTRACKED [='?'] untracked -- StatusCommand::IGNORED [='!'] ignored - -##### Output Example - -``` php -[ - 'branch' => 'master', - 'changes' => [ - ['file' => 'item1.txt', 'index' => 'A', 'work_tree' => 'M'], - ['file' => 'item2.txt', 'index' => 'A', 'work_tree' => ' '], - ['file' => 'item3.txt', 'index' => '?', 'work_tree' => '?'], - ] -] -``` - -##### Options - -- **ignored** (_boolean_) Show ignored files as well - -* * * * * - -### git tag - -#### $git->tag() - -Returns an array of tags - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -$tags = $git->tag(); -``` - -##### Output Example - -``` -['v1.0.0', 'v1.0.1', 'v1.0.2'] -``` - -#### $git->tag->create(_string_ $tag, _string_ $commit = null, _array_ $options = []) - -Creates a tag object - -``` php -$git = new PHPGit\Git(); -$git->setRepository('/path/to/repo'); -$git->tag->create('v1.0.0'); -``` - -##### Options - -- **annotate** (_boolean_) Make an unsigned, annotated tag object -- **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key -- **force** (_boolean_) Replace an existing tag with the given name (instead of failing) - -#### $git->tag->delete(_string|array|\Traversable_ $tag) - -Delete existing tags with the given names - -#### $git->tag->verify(_string|array|\Traversable_ $tag) - -Verify the gpg signature of the given tag names - -* * * * * - -### git ls-tree - -#### $git->tree(_string_ $branch = master, _string_ $path = '') - -Returns the contents of a tree object - -``` php -$git = new PHPGit\Git(); -$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); -$git->setRepository('/path/to/repo'); -$tree = $git->tree('master'); -``` - -##### Output Example - -``` php -[ - ['mode' => '100644', 'type' => 'blob', 'hash' => '1f100ce9855b66111d34b9807e47a73a9e7359f3', 'file' => '.gitignore', 'sort' => '2:.gitignore'], - ['mode' => '100644', 'type' => 'blob', 'hash' => 'e0bfe494537037451b09c32636c8c2c9795c05c0', 'file' => '.travis.yml', 'sort' => '2:.travis.yml'], - ['mode' => '040000', 'type' => 'tree', 'hash' => '8d5438e79f77cd72de80c49a413f4edde1f3e291', 'file' => 'bin', 'sort' => '1:.bin'], -] -``` - -License -------- - -The MIT License - -Author ------- - -Kazuyuki Hayashi (@kzykhys) diff --git a/library/kzykhys/git/phpunit.xml.dist b/library/kzykhys/git/phpunit.xml.dist deleted file mode 100644 index ad8dd7b00..000000000 --- a/library/kzykhys/git/phpunit.xml.dist +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - test - - - - - - src - - - - \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command.php b/library/kzykhys/git/src/PHPGit/Command.php deleted file mode 100644 index 9238a5454..000000000 --- a/library/kzykhys/git/src/PHPGit/Command.php +++ /dev/null @@ -1,123 +0,0 @@ - - */ -abstract class Command -{ - - /** - * @var Git - */ - protected $git; - - /** - * @param Git $git - */ - public function __construct(Git $git) - { - $this->git = $git; - } - - /** - * Returns the combination of the default and the passed options - * - * @param array $options An array of options - * - * @return array - */ - public function resolve(array $options = array()) - { - $resolver = new OptionsResolver(); - $this->setDefaultOptions($resolver); - - return $resolver->resolve($options); - } - - /** - * Sets the default options - * - * @param OptionsResolverInterface $resolver The resolver for the options - * - * @codeCoverageIgnore - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - } - - /** - * Split string by new line or null(\0) - * - * @param string $input The string to split - * @param bool $useNull True to split by new line, otherwise null - * - * @return array - */ - protected function split($input, $useNull = false) - { - if ($useNull) { - $pattern = '/\0/'; - } else { - $pattern = '/\r?\n/'; - } - - return preg_split($pattern, rtrim($input), -1, PREG_SPLIT_NO_EMPTY); - } - - /** - * Adds boolean options to command arguments - * - * @param ProcessBuilder $builder A ProcessBuilder object - * @param array $options An array of options - * @param array $optionNames The names of options to add - */ - protected function addFlags(ProcessBuilder $builder, array $options = array(), array $optionNames = null) - { - if ($optionNames) { - foreach ($optionNames as $name) { - if (isset($options[$name]) && is_bool($options[$name]) && $options[$name]) { - $builder->add('--' . $name); - } - } - } else { - foreach ($options as $name => $option) { - if ($option) { - $builder->add('--' . $name); - } - } - } - } - - /** - * Adds options with values to command arguments - * - * @param ProcessBuilder $builder A ProcessBuilder object - * @param array $options An array of options - * @param array $optionNames The names of options to add - */ - protected function addValues(ProcessBuilder $builder, array $options = array(), array $optionNames = null) - { - if ($optionNames) { - foreach ($optionNames as $name) { - if (isset($options[$name]) && $options[$name]) { - $builder->add('--' . $name . '=' . $options[$name]); - } - } - } else { - foreach ($options as $name => $option) { - if ($option) { - $builder->add('--' . $name . '=' . $option); - } - } - } - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/AddCommand.php b/library/kzykhys/git/src/PHPGit/Command/AddCommand.php deleted file mode 100644 index c035b2412..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/AddCommand.php +++ /dev/null @@ -1,75 +0,0 @@ - - */ -class AddCommand extends Command -{ - - /** - * Add file contents to the index - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->add('file.txt'); - * $git->add('file.txt', ['force' => false, 'ignore-errors' => false); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Allow adding otherwise ignored files - * - **ignore-errors** (_boolean_) Do not abort the operation - * - * @param string|array|\Traversable $file Files to add content from - * @param array $options [optional] An array of options {@see AddCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($file, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('add'); - - $this->addFlags($builder, $options); - - if (!is_array($file) && !($file instanceof \Traversable)) { - $file = array($file); - } - - foreach ($file as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **force** (_boolean_) Allow adding otherwise ignored files - * - **ignore-errors** (_boolean_) Do not abort the operation - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - //'dry-run' => false, - 'force' => false, - 'ignore-errors' => false, - //'ignore-missing' => false, - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php b/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php deleted file mode 100644 index a6c9bd0d9..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php +++ /dev/null @@ -1,96 +0,0 @@ - - */ -class ArchiveCommand extends Command -{ - - /** - * Create an archive of files from a named tree - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->archive('repo.zip', 'master', null, ['format' => 'zip']); - * ``` - * - * ##### Options - * - * - **format** (_boolean_) Format of the resulting archive: tar or zip - * - **prefix** (_boolean_) Prepend prefix/ to each filename in the archive - * - * @param string $file The filename - * @param string $tree [optional] The tree or commit to produce an archive for - * @param string|array|\Traversable $path [optional] If one or more paths are specified, only these are included - * @param array $options [optional] An array of options {@see ArchiveCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($file, $tree = null, $path = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('archive'); - - if ($options['format']) { - $builder->add('--format=' . $options['format']); - } - - if ($options['prefix']) { - $builder->add('--prefix=' . $options['prefix']); - } - - $builder->add('-o')->add($file); - - if ($tree) { - $builder->add($tree); - } - - if (!is_array($path) && !($path instanceof \Traversable)) { - $path = array($path); - } - - foreach ($path as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **format** (_boolean_) Format of the resulting archive: tar or zip - * - **prefix** (_boolean_) Prepend prefix/ to each filename in the archive - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'format' => null, - 'prefix' => null - )); - - $resolver->setAllowedTypes(array( - 'format' => array('null', 'string'), - 'prefix' => array('null', 'string') - )); - - $resolver->setAllowedValues(array( - 'format' => array('tar', 'zip') - )); - } - - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php b/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php deleted file mode 100644 index 4b42f5048..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php +++ /dev/null @@ -1,229 +0,0 @@ - - */ -class BranchCommand extends Command -{ - - /** - * Returns an array of both remote-tracking branches and local branches - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $branches = $git->branch(); - * ``` - * - * ##### Output Example - * - * ``` - * [ - * 'master' => ['current' => true, 'name' => 'master', 'hash' => 'bf231bb', 'title' => 'Initial Commit'], - * 'origin/master' => ['current' => false, 'name' => 'origin/master', 'alias' => 'remotes/origin/master'] - * ] - * ``` - * - * ##### Options - * - * - **all** (_boolean_) List both remote-tracking branches and local branches - * - **remotes** (_boolean_) List the remote-tracking branches - * - * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} - * - * @throws GitException - * @return array - */ - public function __invoke(array $options = array()) - { - $options = $this->resolve($options); - $branches = array(); - $builder = $this->getProcessBuilder() - ->add('-v')->add('--abbrev=7'); - - if ($options['remotes']) { - $builder->add('--remotes'); - } - - if ($options['all']) { - $builder->add('--all'); - } - - $process = $builder->getProcess(); - $this->git->run($process); - - $lines = preg_split('/\r?\n/', rtrim($process->getOutput()), -1, PREG_SPLIT_NO_EMPTY); - - foreach ($lines as $line) { - $branch = array(); - preg_match('/(?\*| ) (?[^\s]+) +((?:->) (?[^\s]+)|(?[0-9a-z]{7}) (?.*))/', $line, $matches); - - $branch['current'] = ($matches['current'] == '*'); - $branch['name'] = $matches['name']; - - if (isset($matches['hash'])) { - $branch['hash'] = $matches['hash']; - $branch['title'] = $matches['title']; - } else { - $branch['alias'] = $matches['alias']; - } - - $branches[$matches['name']] = $branch; - } - - return $branches; - } - - /** - * Creates a new branch head named **$branch** which points to the current HEAD, or **$startPoint** if given - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->branch->create('bugfix'); // from current HEAD - * $git->branch->create('patch-1', 'a092bf7s'); // from commit - * $git->branch->create('1.0.x-fix', 'v1.0.2'); // from tag - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Reset **$branch** to **$startPoint** if **$branch** exists already - * - * @param string $branch The name of the branch to create - * @param string $startPoint [optional] The new branch head will point to this commit. - * It may be given as a branch name, a commit-id, or a tag. - * If this option is omitted, the current HEAD will be used instead. - * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function create($branch, $startPoint = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->getProcessBuilder(); - - if ($options['force']) { - $builder->add('-f'); - } - - $builder->add($branch); - - if ($startPoint) { - $builder->add($startPoint); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Move/rename a branch and the corresponding reflog - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->branch->move('bugfix', '2.0'); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Move/rename a branch even if the new branch name already exists - * - * @param string $branch The name of an existing branch to rename - * @param string $newBranch The new name for an existing branch - * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function move($branch, $newBranch, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->getProcessBuilder(); - - if ($options['force']) { - $builder->add('-M'); - } else { - $builder->add('-m'); - } - - $builder->add($branch)->add($newBranch); - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Delete a branch - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->branch->delete('2.0'); - * ``` - * - * The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with --track or --set-upstream. - * - * ##### Options - * - * - **force** (_boolean_) Delete a branch irrespective of its merged status - * - * @param string $branch The name of the branch to delete - * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function delete($branch, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->getProcessBuilder(); - - if ($options['force']) { - $builder->add('-D'); - } else { - $builder->add('-d'); - } - - $builder->add($branch); - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **force** (_boolean_) Reset <branchname> to <startpoint> if <branchname> exists already - * - **all** (_boolean_) List both remote-tracking branches and local branches - * - **remotes** (_boolean_) List or delete (if used with delete()) the remote-tracking branches - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'force' => false, - 'all' => false, - 'remotes' => false, - )); - } - - /** - * @return \Symfony\Component\Process\ProcessBuilder - */ - protected function getProcessBuilder() - { - return $this->git->getProcessBuilder() - ->add('branch'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CatCommand.php b/library/kzykhys/git/src/PHPGit/Command/CatCommand.php deleted file mode 100644 index 0c4fc1f41..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/CatCommand.php +++ /dev/null @@ -1,91 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; - -/** - * Provide content or type and size information for repository objects - `git cat-file` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class CatCommand extends Command -{ - - /** - * Returns the contents of blob object - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $contents = $git->cat->blob('e69de29bb2d1d6434b8b29ae775ad8'); - * ``` - * - * @param string $object The name of the blob object to show - * - * @throws GitException - * @return string - */ - public function blob($object) - { - $process = $this->git->getProcessBuilder() - ->add('cat-file') - ->add('blob') - ->add($object) - ->getProcess(); - - return $this->git->run($process); - } - - /** - * Returns the object type identified by **$object** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $type = $git->cat->type('e69de29bb2d1d6434b8b29ae775ad8'); - * ``` - * - * @param string $object The name of the object to show - * - * @throws GitException - * @return string - */ - public function type($object) - { - $process = $this->git->getProcessBuilder() - ->add('cat-file') - ->add('-t') - ->add($object) - ->getProcess(); - - return trim($this->git->run($process)); - } - - /** - * Returns the object size identified by **$object** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $type = $git->cat->size('e69de29bb2d1d6434b8b29ae775ad8'); - * ``` - * - * @param string $object The name of the object to show - * - * @throws GitException - * @return string - */ - public function size($object) - { - $process = $this->git->getProcessBuilder() - ->add('cat-file') - ->add('-s') - ->add($object) - ->getProcess(); - - return trim($this->git->run($process)); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php b/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php deleted file mode 100644 index caddf07bd..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php +++ /dev/null @@ -1,145 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Checkout a branch or paths to the working tree - `git checkout` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class CheckoutCommand extends Command -{ - - /** - * Switches branches by updating the index, working tree, and HEAD to reflect the specified branch or commit - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->checkout('develop'); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - * - **merge** (_boolean_) Merges local modification - * - * @param string $branch Branch to checkout - * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($branch, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('checkout'); - - $this->addFlags($builder, $options, array('force', 'merge')); - - $builder->add($branch); - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Create a new branch and checkout - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->checkout->create('patch-1'); - * $git->checkout->create('patch-2', 'develop'); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - * - * @param string $branch Branch to checkout - * @param string $startPoint The name of a commit at which to start the new branch - * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function create($branch, $startPoint = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('checkout') - ->add('-b'); - - $this->addFlags($builder, $options, array('force', 'merge')); - - $builder->add($branch); - - if ($startPoint) { - $builder->add($startPoint); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Create a new orphan branch, named <new_branch>, started from <start_point> and switch to it - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->checkout->orphan('gh-pages'); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - * - * @param string $branch Branch to checkout - * @param string $startPoint [optional] The name of a commit at which to start the new branch - * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function orphan($branch, $startPoint = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('checkout'); - - $this->addFlags($builder, $options, array('force', 'merge')); - - $builder->add('--orphan')->add($branch); - - if ($startPoint) { - $builder->add($startPoint); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD - * - **merge** (_boolean_) Merges local modification - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'force' => false, - 'merge' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php b/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php deleted file mode 100644 index cc6b4ab37..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Clone a repository into a new directory - `git clone` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class CloneCommand extends Command -{ - - /** - * Clone a repository into a new directory - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); - * ``` - * - * ##### Options - * - * - **shared** (_boolean_) Starts out without any object of its own - * - **bare** (_boolean_) Make a bare GIT repository - * - * @param string $repository The repository to clone from - * @param string $path [optional] The name of a new directory to clone into - * @param array $options [optional] An array of options {@see CloneCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($repository, $path = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('clone') - ->add('--quiet'); - - $this->addFlags($builder, $options); - - $builder->add($repository); - - if ($path) { - $builder->add($path); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **shared** (_boolean_) Starts out without any object of its own - * - **bare** (_boolean_) Make a bare GIT repository - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'shared' => false, - 'bare' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php b/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php deleted file mode 100644 index a4f2bdd95..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php +++ /dev/null @@ -1,87 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Record changes to the repository - `git commit` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class CommitCommand extends Command -{ - - /** - * Record changes to the repository - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * $git->add('README.md'); - * $git->commit('Fixes README.md'); - * ``` - * - * ##### Options - * - * - **all** (_boolean_) Stage files that have been modified and deleted - * - **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit - * - **squash** (_string_) Construct a commit message for use with rebase --autosquash - * - **author** (_string_) Override the commit author - * - **date** (_string_) Override the author date used in the commit - * - **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default - * - **amend** (_boolean_) Used to amend the tip of the current branch - * - * @param string $message Use the given <$msg> as the commit message - * @param array $options [optional] An array of options {@see CloneCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($message, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('commit') - ->add('-m')->add($message); - - $this->addFlags($builder, $options, array('all', 'amend')); - $this->addValues($builder, $options, array('reuse-message', 'squash', 'author', 'date', 'cleanup')); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **all** (_boolean_) Stage files that have been modified and deleted - * - **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit - * - **squash** (_string_) Construct a commit message for use with rebase --autosquash - * - **author** (_string_) Override the commit author - * - **date** (_string_) Override the author date used in the commit - * - **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default - * - **amend** (_boolean_) Used to amend the tip of the current branch - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'all' => false, - 'reuse-message' => null, - 'squash' => null, - 'author' => null, - 'date' => null, - 'cleanup' => null, - 'amend' => false - )); - - $resolver->setAllowedValues(array( - 'cleanup' => array(null, 'default', 'verbatim', 'whitespace', 'strip') - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php b/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php deleted file mode 100644 index cb8bb625f..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php +++ /dev/null @@ -1,132 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Get and set repository or global options - `git config` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class ConfigCommand extends Command -{ - - /** - * Returns all variables set in config file - * - * - * ##### Options - * - * - **global** (_boolean_) Read or write configuration options for the current user - * - **system** (_boolean_) Read or write configuration options for all users on the current machine - * - * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} - * - * @throws GitException - * @return array - */ - public function __invoke(array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('config') - ->add('--list') - ->add('--null'); - - $this->addFlags($builder, $options, array('global', 'system')); - - $config = array(); - $output = $this->git->run($builder->getProcess()); - $lines = $this->split($output, true); - - foreach ($lines as $line) { - list($name, $value) = explode("\n", $line, 2); - - if (isset($config[$name])) { - $config[$name] .= "\n" . $value; - } else { - $config[$name] = $value; - } - } - - return $config; - } - - /** - * Set an option - * - * ##### Options - * - * - **global** (_boolean_) Read or write configuration options for the current user - * - **system** (_boolean_) Read or write configuration options for all users on the current machine - * - * @param string $name The name of the option - * @param string $value The value to set - * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function set($name, $value, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('config'); - - $this->addFlags($builder, $options, array('global', 'system')); - - $builder->add($name)->add($value); - $process = $builder->getProcess(); - $this->git->run($process); - - return true; - } - - /** - * Adds a new line to the option without altering any existing values - * - * ##### Options - * - * - **global** (_boolean_) Read or write configuration options for the current user - * - **system** (_boolean_) Read or write configuration options for all users on the current machine - * - * @param string $name The name of the option - * @param string $value The value to add - * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function add($name, $value, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('config'); - - $this->addFlags($builder, $options, array('global', 'system')); - - $builder->add('--add')->add($name)->add($value); - $process = $builder->getProcess(); - $this->git->run($process); - - return true; - } - - /** - * {@inheritdoc} - * - * - **global** (_boolean_) Read or write configuration options for the current user - * - **system** (_boolean_) Read or write configuration options for all users on the current machine - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'global' => false, - 'system' => false, - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php b/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php deleted file mode 100644 index affdd009b..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php +++ /dev/null @@ -1,90 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Show the most recent tag that is reachable from a commit - `git describe` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class DescribeCommand extends Command -{ - - /** - * Returns the most recent tag that is reachable from a commit - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->tag->create('v1.0.0'); - * $git->commit('Fixes #14'); - * echo $git->describe('HEAD', ['tags' => true]); - * ``` - * - * ##### Output Example - * - * ``` - * v1.0.0-1-g7049efc - * ``` - * - * ##### Options - * - * - **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag - * - **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag - * - **always** (_boolean_) Show uniquely abbreviated commit object as fallback - * - * @param string $committish [optional] Committish object names to describe. - * @param array $options [optional] An array of options {@see DescribeCommand::setDefaultOptions} - * - * @return string - */ - public function __invoke($committish = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('describe'); - - $this->addFlags($builder, $options, array()); - - if ($committish) { - $builder->add($committish); - } - - return trim($this->git->run($builder->getProcess())); - } - - /** - * Equivalent to $git->describe($committish, ['tags' => true]); - * - * @param string $committish [optional] Committish object names to describe. - * @param array $options [optional] An array of options {@see DescribeCommand::setDefaultOptions} - * - * @return string - */ - public function tags($committish = null, array $options = array()) - { - $options['tags'] = true; - - return $this->__invoke($committish, $options); - } - - /** - * {@inheritdoc} - * - * - **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag - * - **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag - * - **always** (_boolean_) Show uniquely abbreviated commit object as fallback - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'all' => false, - 'tags' => false, - 'always' => false, - )); - } - -} diff --git a/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php b/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php deleted file mode 100644 index 1302038e8..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php +++ /dev/null @@ -1,112 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Download objects and refs from another repository - `git fetch` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class FetchCommand extends Command -{ - - /** - * Fetches named heads or tags from one or more other repositories, along with the objects necessary to complete them - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'git://your/repo.git'); - * $git->fetch('origin'); - * ``` - * - * ##### Options - * - * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD - * - **keep** (_boolean_) Keep downloaded pack - * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote - * - * @param string $repository The "remote" repository that is the source of a fetch or pull operation - * @param string $refspec The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>, - * followed by a colon :, followed by the destination ref <dst> - * @param array $options [optional] An array of options {@see FetchCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($repository, $refspec = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('fetch'); - - $this->addFlags($builder, $options); - $builder->add($repository); - - if ($refspec) { - $builder->add($refspec); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Fetch all remotes - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'git://your/repo.git'); - * $git->remote->add('release', 'git://your/another_repo.git'); - * $git->fetch->all(); - * ``` - * - * ##### Options - * - * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD - * - **keep** (_boolean_) Keep downloaded pack - * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote - * - * @param array $options [optional] An array of options {@see FetchCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function all(array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('fetch') - ->add('--all'); - - $this->addFlags($builder, $options); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD - * - **keep** (_boolean_) Keep downloaded pack - * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'append' => false, - //'force' => false, - 'keep' => false, - 'prune' => false, - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/InitCommand.php b/library/kzykhys/git/src/PHPGit/Command/InitCommand.php deleted file mode 100644 index 1ff56fa5b..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/InitCommand.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Create an empty git repository or reinitialize an existing one - `git init` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class InitCommand extends Command -{ - - /** - * Create an empty git repository or reinitialize an existing one - * - * ``` php - * $git = new PHPGit\Git(); - * $git->init('/path/to/repo1'); - * $git->init('/path/to/repo2', array('shared' => true, 'bare' => true)); - * ``` - * - * ##### Options - * - * - **shared** (_boolean_) Specify that the git repository is to be shared amongst several users - * - **bare** (_boolean_) Create a bare repository - * - * @param string $path The directory to create an empty repository - * @param array $options [optional] An array of options {@see InitCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($path, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('init'); - - $this->addFlags($builder, $options, array('shared', 'bare')); - - $process = $builder->add($path)->getProcess(); - $this->git->run($process); - - return true; - } - - /** - * {@inheritdoc} - * - * - **shared** (_boolean_) Specify that the git repository is to be shared amongst several users - * - **bare** (_boolean_) Create a bare repository - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'shared' => false, - 'bare' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/LogCommand.php b/library/kzykhys/git/src/PHPGit/Command/LogCommand.php deleted file mode 100644 index c116550f7..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/LogCommand.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Show commit logs - `git log` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class LogCommand extends Command -{ - - /** - * Returns the commit logs - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $logs = $git->log(array('limit' => 10)); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * 0 => [ - * 'hash' => '1a821f3f8483747fd045eb1f5a31c3cc3063b02b', - * 'name' => 'John Doe', - * 'email' => 'john@example.com', - * 'date' => 'Fri Jan 17 16:32:49 2014 +0900', - * 'title' => 'Initial Commit' - * ], - * 1 => [ - * //... - * ] - * ] - * ``` - * - * ##### Options - * - * - **limit** (_integer_) Limits the number of commits to show - * - **skip** (_integer_) Skip number commits before starting to show the commit output - * - * @param string $revRange [optional] Show only commits in the specified revision range - * @param string $path [optional] Show only commits that are enough to explain how the files that match the specified paths came to be - * @param array $options [optional] An array of options {@see LogCommand::setDefaultOptions} - * - * @throws GitException - * @return array - */ - public function __invoke($revRange = '', $path = null, array $options = array()) - { - $commits = array(); - $options = $this->resolve($options); - - $builder = $this->git->getProcessBuilder() - ->add('log') - ->add('-n')->add($options['limit']) - ->add('--skip=' . $options['skip']) - ->add('--format=%H||%aN||%aE||%aD||%s'); - - if ($revRange) { - $builder->add($revRange); - } - - if ($path) { - $builder->add('--')->add($path); - } - - $output = $this->git->run($builder->getProcess()); - $lines = $this->split($output); - - foreach ($lines as $line) { - list($hash, $name, $email, $date, $title) = preg_split('/\|\|/', $line, -1, PREG_SPLIT_NO_EMPTY); - $commits[] = array( - 'hash' => $hash, - 'name' => $name, - 'email' => $email, - 'date' => $date, - 'title' => $title - ); - } - - return $commits; - } - - /** - * {@inheritdoc} - * - * - **limit** (_integer_) Limits the number of commits to show - * - **skip** (_integer_) Skip number commits before starting to show the commit output - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'limit' => 10, - 'skip' => 0 - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php b/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php deleted file mode 100644 index e1987151f..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php +++ /dev/null @@ -1,110 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Join two or more development histories together - `git merge` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class MergeCommand extends Command -{ - - /** - * Incorporates changes from the named commits into the current branch - * - * ```php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->merge('1.0'); - * $git->merge('1.1', 'Merge message', ['strategy' => 'ours']); - * ``` - * - * ##### Options - * - * - **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer - * - **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible - * - **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch - * - **strategy** (_string_) Use the given merge strategy - * - **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy - * - * @param string|array|\Traversable $commit Commits to merge into our branch - * @param string $message [optional] Commit message to be used for the merge commit - * @param array $options [optional] An array of options {@see MergeCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function __invoke($commit, $message = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('merge'); - - $this->addFlags($builder, $options, array('no-ff', 'rerere-autoupdate', 'squash')); - - if (!is_array($commit) && !($commit instanceof \Traversable)) { - $commit = array($commit); - } - foreach ($commit as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Abort the merge process and try to reconstruct the pre-merge state - * - * ```php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * try { - * $git->merge('dev'); - * } catch (PHPGit\Exception\GitException $e) { - * $git->merge->abort(); - * } - * ``` - * - * @throws GitException - * @return bool - */ - public function abort() - { - $builder = $this->git->getProcessBuilder() - ->add('merge') - ->add('--abort'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer - * - **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible - * - **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch - * - **strategy** (_string_) Use the given merge strategy - * - **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'no-ff' => false, - 'rerere-autoupdate' => false, - 'squash' => false, - - 'strategy' => null, - 'strategy-option' => null - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/MvCommand.php b/library/kzykhys/git/src/PHPGit/Command/MvCommand.php deleted file mode 100644 index fe7ce6af6..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/MvCommand.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Move or rename a file, a directory, or a symlink - `git mv` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class MvCommand extends Command -{ - - /** - * Move or rename a file, a directory, or a symlink - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->mv('UPGRADE-1.0.md', 'UPGRADE-1.1.md'); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Force renaming or moving of a file even if the target exists - * - * @param string|array|\Iterator $source The files to move - * @param string $destination The destination - * @param array $options [optional] An array of options {@see MvCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($source, $destination, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('mv'); - - $this->addFlags($builder, $options, array('force')); - - if (!is_array($source) && !($source instanceof \Traversable)) { - $source = array($source); - } - - foreach ($source as $value) { - $builder->add($value); - } - - $builder->add($destination); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **force** (_boolean_) Force renaming or moving of a file even if the target exists - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'force' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/PullCommand.php b/library/kzykhys/git/src/PHPGit/Command/PullCommand.php deleted file mode 100644 index a7cea0025..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/PullCommand.php +++ /dev/null @@ -1,59 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Fetch from and merge with another repository or a local branch - `git pull` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class PullCommand extends Command -{ - - /** - * Fetch from and merge with another repository or a local branch - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->pull('origin', 'master'); - * ``` - * - * @param string $repository The "remote" repository that is the source of a fetch or pull operation - * @param string $refspec The format of a <refspec> parameter is an optional plus +, - * followed by the source ref <src>, followed by a colon :, followed by the destination ref <dst> - * @param array $options [optional] An array of options {@see PullCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($repository = null, $refspec = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('pull'); - - if ($repository) { - $builder->add($repository); - - if ($refspec) { - $builder->add($refspec); - } - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/PushCommand.php b/library/kzykhys/git/src/PHPGit/Command/PushCommand.php deleted file mode 100644 index d0665d735..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/PushCommand.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Update remote refs along with associated objects - `git push` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class PushCommand extends Command -{ - - /** - * Update remote refs along with associated objects - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->push('origin', 'master'); - * ``` - * - * @param string $repository The "remote" repository that is destination of a push operation - * @param string $refspec Specify what destination ref to update with what source object - * @param array $options [optional] An array of options {@see PushCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($repository = null, $refspec = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('push'); - - $this->addFlags($builder, $options); - - if ($repository) { - $builder->add($repository); - - if ($refspec) { - $builder->add($refspec); - } - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'all' => false, - 'mirror' => false, - 'tags' => false, - 'force' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php b/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php deleted file mode 100644 index 7516b360c..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php +++ /dev/null @@ -1,129 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Forward-port local commits to the updated upstream head - `git rebase` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class RebaseCommand extends Command -{ - - /** - * Forward-port local commits to the updated upstream head - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->fetch('origin'); - * $git->rebase('origin/master'); - * ``` - * - * ##### Options - * - * - **onto** (_string_) Starting point at which to create the new commits - * - **no-verify** (_boolean_) Bypasses the pre-rebase hook - * - **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto - * - * @param string $upstream [optional] Upstream branch to compare against - * @param string $branch [optional] Working branch; defaults to HEAD - * @param array $options [optional] An array of options {@see RebaseCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($upstream = null, $branch = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('rebase'); - - if ($options['onto']) { - $builder->add('--onto')->add($options['onto']); - } - - if ($upstream) { - $builder->add($upstream); - } - - if ($branch) { - $builder->add($branch); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Restart the rebasing process after having resolved a merge conflict - * - * @return bool - */ - public function continues() - { - $builder = $this->git->getProcessBuilder() - ->add('rebase') - ->add('--continue'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Abort the rebase operation and reset HEAD to the original branch - * - * @return bool - */ - public function abort() - { - $builder = $this->git->getProcessBuilder() - ->add('rebase') - ->add('--abort'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Restart the rebasing process by skipping the current patch - * - * @return bool - */ - public function skip() - { - $builder = $this->git->getProcessBuilder() - ->add('rebase') - ->add('--skip'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **onto** (_string_) Starting point at which to create the new commits - * - **no-verify** (_boolean_) Bypasses the pre-rebase hook - * - **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'onto' => null, - 'no-verify' => false, - 'force-rebase' => false - )); - - $resolver->setAllowedTypes(array( - 'onto' => array('null', 'string') - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php deleted file mode 100644 index 4e17a4d48..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php - -namespace PHPGit\Command\Remote; - -use PHPGit\Command; - -/** - * Changes the list of branches tracked by the named remote - * - * @author Kazuyuki Hayashi - */ -class SetBranchesCommand extends Command -{ - - /** - * Alias of set() - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->branches('origin', array('master', 'develop')); - * ``` - * - * @param string $name The remote name - * @param array $branches The names of the tracked branch - * - * @return bool - */ - public function __invoke($name, array $branches) - { - return $this->set($name, $branches); - } - - /** - * Changes the list of branches tracked by the named remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->branches->set('origin', array('master', 'develop')); - * ``` - * - * @param string $name The remote name - * @param array $branches The names of the tracked branch - * - * @return bool - */ - public function set($name, array $branches) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-branches') - ->add($name); - - foreach ($branches as $branch) { - $builder->add($branch); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Adds to the list of branches tracked by the named remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->branches->add('origin', array('master', 'develop')); - * ``` - * - * @param string $name The remote name - * @param array $branches The names of the tracked branch - * - * @return bool - */ - public function add($name, array $branches) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-branches') - ->add($name) - ->add('--add'); - - foreach ($branches as $branch) { - $builder->add($branch); - } - - $this->git->run($builder->getProcess()); - - return true; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php deleted file mode 100644 index 9241ef5b7..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php +++ /dev/null @@ -1,120 +0,0 @@ -<?php - -namespace PHPGit\Command\Remote; - -use PHPGit\Command; - -/** - * Sets or deletes the default branch (i.e. the target of the symbolic-ref refs/remotes/<name>/HEAD) for the named remote - * - * @author Kazuyuki Hayashi - */ -class SetHeadCommand extends Command -{ - - /** - * Alias of set() - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->head('origin'); - * ``` - * - * @param string $name The remote name - * @param string $branch [optional] The symbolic-ref to set - * - * @return bool - */ - public function __invoke($name, $branch = null) - { - return $this->set($name, $branch); - } - - /** - * Sets the default branch for the named remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->head->set('origin'); - * ``` - * - * @param string $name The remote name - * @param string $branch [optional] The symbolic-ref to set - * - * @return bool - */ - public function set($name, $branch) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-head') - ->add($name); - - if ($branch) { - $builder->add($branch); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Deletes the default branch for the named remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->head->delete('origin'); - * ``` - * - * @param string $name The remote name - * - * @return bool - */ - public function delete($name) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-head') - ->add($name) - ->add('-d'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Determine the default branch by querying remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->head->remote('origin'); - * ``` - * - * @param string $name The remote name - * - * @return bool - */ - public function remote($name) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-head') - ->add($name) - ->add('-a'); - - $this->git->run($builder->getProcess()); - - return true; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php deleted file mode 100644 index 7b7d84ff5..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php +++ /dev/null @@ -1,175 +0,0 @@ -<?php - -namespace PHPGit\Command\Remote; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Changes URL remote points to - * - * @author Kazuyuki Hayashi - */ -class SetUrlCommand extends Command -{ - - /** - * Alias of set() - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->url('origin', 'https://github.com/text/Text.git'); - * ``` - * - * ##### Options - * - * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - * - * @param string $name The name of remote - * @param string $newUrl The new URL - * @param string $oldUrl [optional] The old URL - * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($name, $newUrl, $oldUrl = null, array $options = array()) - { - return $this->set($name, $newUrl, $oldUrl, $options); - } - - /** - * Sets the URL remote to $newUrl - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->url->set('origin', 'https://github.com/text/Text.git'); - * ``` - * - * ##### Options - * - * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - * - * @param string $name The name of remote - * @param string $newUrl The new URL - * @param string $oldUrl [optional] The old URL - * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} - * - * @return bool - */ - public function set($name, $newUrl, $oldUrl = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-url'); - - $this->addFlags($builder, $options); - - $builder - ->add($name) - ->add($newUrl); - - if ($oldUrl) { - $builder->add($oldUrl); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Adds new URL to remote - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->url->add('origin', 'https://github.com/text/Text.git'); - * ``` - * - * ##### Options - * - * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - * - * @param string $name The name of remote - * @param string $newUrl The new URL - * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} - * - * @return bool - */ - public function add($name, $newUrl, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-url') - ->add('--add'); - - $this->addFlags($builder, $options); - - $builder - ->add($name) - ->add($newUrl); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Deletes all URLs matching regex $url - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->url->delete('origin', 'https://github.com'); - * ``` - * - * ##### Options - * - * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - * - * @param string $name The remote name - * @param string $url The URL to delete - * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} - * - * @return bool - */ - public function delete($name, $url, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('set-url') - ->add('--delete'); - - $this->addFlags($builder, $options); - - $builder - ->add($name) - ->add($url); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'push' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php b/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php deleted file mode 100644 index 08220a551..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php +++ /dev/null @@ -1,278 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Git; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Manage set of tracked repositories - `git remote` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - * - * @method head($name, $branch) Sets the default branch for the named remote - * @method branches($name, $branches) Changes the list of branches tracked by the named remote - * @method url($name, $newUrl, $oldUrl = null, $options = array()) Sets the URL remote to $newUrl - */ -class RemoteCommand extends Command -{ - - /** @var Remote\SetHeadCommand */ - public $head; - - /** @var Remote\SetBranchesCommand */ - public $branches; - - /** @var Remote\SetUrlCommand */ - public $url; - - /** - * @param Git $git - */ - public function __construct(Git $git) - { - parent::__construct($git); - - $this->head = new Remote\SetHeadCommand($git); - $this->branches = new Remote\SetBranchesCommand($git); - $this->url = new Remote\SetUrlCommand($git); - } - - /** - * Calls sub-commands - * - * @param string $name The name of a property - * @param array $arguments An array of arguments - * - * @throws \BadMethodCallException - * @return mixed - */ - public function __call($name, $arguments) - { - if (isset($this->{$name}) && is_callable($this->{$name})) { - return call_user_func_array($this->{$name}, $arguments); - } - - throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', __CLASS__, $name)); - } - - /** - * Returns an array of existing remotes - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * $remotes = $git->remote(); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * 'origin' => [ - * 'fetch' => 'https://github.com/kzykhys/Text.git', - * 'push' => 'https://github.com/kzykhys/Text.git' - * ] - * ] - * ``` - * - * @return array - */ - public function __invoke() - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('-v'); - - $remotes = array(); - $output = $this->git->run($builder->getProcess()); - $lines = $this->split($output); - - foreach ($lines as $line) { - if (preg_match('/^(.*)\t(.*)\s\((.*)\)$/', $line, $matches)) { - if (!isset($remotes[$matches[1]])) { - $remotes[$matches[1]] = array(); - } - - $remotes[$matches[1]][$matches[3]] = $matches[2]; - } - } - - return $remotes; - } - - /** - * Adds a remote named **$name** for the repository at **$url** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->fetch('origin'); - * ``` - * - * ##### Options - * - * - **tags** (_boolean_) With this option, `git fetch <name>` imports every tag from the remote repository - * - **no-tags** (_boolean_) With this option, `git fetch <name>` does not import tags from the remote repository - * - * @param string $name The name of the remote - * @param string $url The url of the remote - * @param array $options [optional] An array of options {@see RemoteCommand::setDefaultOptions} - * - * @return bool - */ - public function add($name, $url, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('add'); - - $this->addFlags($builder, $options, array('tags', 'no-tags')); - - $builder->add($name)->add($url); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Rename the remote named **$name** to **$newName** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->rename('origin', 'upstream'); - * ``` - * - * @param string $name The remote name to rename - * @param string $newName The new remote name - * - * @return bool - */ - public function rename($name, $newName) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('rename') - ->add($name) - ->add($newName); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Remove the remote named **$name** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - * $git->remote->rm('origin'); - * ``` - * - * @param string $name The remote name to remove - * - * @return bool - */ - public function rm($name) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('rm') - ->add($name); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Gives some information about the remote **$name** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * echo $git->remote->show('origin'); - * ``` - * - * ##### Output Example - * - * ``` - * \* remote origin - * Fetch URL: https://github.com/kzykhys/Text.git - * Push URL: https://github.com/kzykhys/Text.git - * HEAD branch: master - * Remote branch: - * master tracked - * Local branch configured for 'git pull': - * master merges with remote master - * Local ref configured for 'git push': - * master pushes to master (up to date) - * ``` - * - * @param string $name The remote name to show - * - * @return string - */ - public function show($name) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('show') - ->add($name); - - return $this->git->run($builder->getProcess()); - } - - /** - * Deletes all stale remote-tracking branches under **$name** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->remote->prune('origin'); - * ``` - * - * @param string $name The remote name - * - * @return bool - */ - public function prune($name = null) - { - $builder = $this->git->getProcessBuilder() - ->add('remote') - ->add('prune'); - - if ($name) { - $builder->add($name); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **tags** (_boolean_) With this option, `git fetch <name>` imports every tag from the remote repository - * - **no-tags** (_boolean_) With this option, `git fetch <name>` does not import tags from the remote repository - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'tags' => false, - 'no-tags' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php b/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php deleted file mode 100644 index f70f53e2e..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php +++ /dev/null @@ -1,199 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; - -/** - * Reset current HEAD to the specified state - `git reset` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class ResetCommand extends Command -{ - - /** - * Resets the index entries for all **$paths** to their state at **$commit** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset(); - * ``` - * - * @param string|array|\Traversable $paths The paths to reset - * @param string $commit The commit - * - * @return bool - */ - public function __invoke($paths, $commit = null) - { - $builder = $this->git->getProcessBuilder() - ->add('reset'); - - if ($commit) { - $builder->add($commit)->add('--'); - } - - if (!is_array($paths) && !($paths instanceof \Traversable)) { - $paths = array($paths); - } - - foreach ($paths as $path) { - $builder->add($path); - } - - try { - $this->git->run($builder->getProcess()); - } catch (GitException $e) { - // Confirm exit code - } - - return true; - } - - /** - * Resets the current branch head to **$commit** - * - * Does not touch the index file nor the working tree at all (but resets the head to **$commit**, - * just like all modes do). - * This leaves all your changed files "Changes to be committed", as git status would put it. - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->soft(); - * ``` - * - * @param string $commit The commit - * - * @return bool - */ - public function soft($commit = null) - { - return $this->mode('soft', $commit); - } - - /** - * Resets the current branch head to **$commit** - * - * Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) - * and reports what has not been updated. This is the default action. - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->mixed(); - * ``` - * - * @param string $commit The commit - * - * @return bool - */ - public function mixed($commit = null) - { - return $this->mode('mixed', $commit); - } - - /** - * Resets the current branch head to **$commit** - * - * Resets the index and working tree. Any changes to tracked files in the working tree since **$commit** are discarded - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->hard(); - * ``` - * - * @param string $commit The commit - * - * @return bool - */ - public function hard($commit = null) - { - return $this->mode('hard', $commit); - } - - /** - * Resets the current branch head to **$commit** - * - * Resets the index and updates the files in the working tree that are different between **$commit** and HEAD, - * but keeps those which are different between the index and working tree - * (i.e. which have changes which have not been added). If a file that is different between **$commit** and - * the index has unstaged changes, reset is aborted - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->merge(); - * ``` - * - * @param string $commit The commit - * - * @return bool - */ - public function merge($commit = null) - { - return $this->mode('merge', $commit); - } - - /** - * Resets the current branch head to **$commit** - * - * Resets index entries and updates files in the working tree that are different between **$commit** and HEAD. - * If a file that is different between **$commit** and HEAD has local changes, reset is aborted. - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->keep(); - * ``` - * - * @param string $commit The commit - * - * @return bool - */ - public function keep($commit = null) - { - return $this->mode('keep', $commit); - } - - /** - * Resets the current branch head to **$commit** - * - * Possibly updates the index (resetting it to the tree of **$commit**) and the working tree depending on **$mode** - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->reset->mode('hard'); - * ``` - * - * @param string $mode --<mode> - * @param string $commit The commit - * - * @throws \InvalidArgumentException - * @return bool - */ - public function mode($mode, $commit = null) - { - if (!in_array($mode, array('soft', 'mixed', 'hard', 'merge', 'keep'))) { - throw new \InvalidArgumentException('$mode must be one of the following: soft, mixed, hard, merge, keep'); - } - - $builder = $this->git->getProcessBuilder() - ->add('reset') - ->add('--' . $mode); - - if ($commit) { - $builder->add($commit); - } - - $this->git->run($builder->getProcess()); - - return true; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RmCommand.php b/library/kzykhys/git/src/PHPGit/Command/RmCommand.php deleted file mode 100644 index d6da31230..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/RmCommand.php +++ /dev/null @@ -1,97 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Remove files from the working tree and from the index - `git rm` - * - * @author Kazuyuki Hayashi - */ -class RmCommand extends Command -{ - - /** - * Remove files from the working tree and from the index - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->rm('CHANGELOG-1.0-1.1.txt', ['force' => true]); - * ``` - * - * ##### Options - * - * - **force** (_boolean_) Override the up-to-date check - * - **cached** (_boolean_) Unstage and remove paths only from the index - * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given - * - * @param string|array|\Traversable $file Files to remove. Fileglobs (e.g. *.c) can be given to remove all matching files. - * @param array $options [optional] An array of options {@see RmCommand::setDefaultOptions} - * - * @return bool - */ - public function __invoke($file, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('rm'); - - $this->addFlags($builder, $options, array('force', 'cached')); - - if ($options['recursive']) { - $builder->add('-r'); - } - - if (!is_array($file) && !($file instanceof \Traversable)) { - $file = array($file); - } - - foreach ($file as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Equivalent to $git->rm($file, ['cached' => true]); - * - * ##### Options - * - * - **force** (_boolean_) Override the up-to-date check - * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given - * - * @param string|array|\Traversable $file Files to remove. Fileglobs (e.g. *.c) can be given to remove all matching files. - * @param array $options [optional] An array of options {@see RmCommand::setDefaultOptions} - * - * @return bool - */ - public function cached($file, array $options = array()) - { - $options['cached'] = true; - - return $this->__invoke($file, $options); - } - - /** - * {@inheritdoc} - * - * - **force** (_boolean_) Override the up-to-date check - * - **cached** (_boolean_) Unstage and remove paths only from the index - * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'force' => false, - 'cached' => false, - 'recursive' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php b/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php deleted file mode 100644 index 23c66e464..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php +++ /dev/null @@ -1,134 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; - -/** - * Summarize 'git log' output - `git shortlog` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class ShortlogCommand extends Command -{ - - /** - * Summarize 'git log' output - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $shortlog = $git->shortlog(); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * 'John Doe <john@example.com>' => [ - * 0 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-10 12:56:15 +0300'), 'subject' => 'Update README'], - * 1 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-15 12:56:15 +0300'), 'subject' => 'Update README'], - * ], - * //... - * ] - * ``` - * @param string|array|\Traversable $commits [optional] Defaults to HEAD - * - * @return array - */ - public function __invoke($commits = 'HEAD') - { - $builder = $this->git->getProcessBuilder() - ->add('shortlog') - ->add('--numbered') - ->add('--format=') - ->add('-w256,2,2') - ->add('-e'); - - if (!is_array($commits) && !($commits instanceof \Traversable)) { - $commits = array($commits); - } - - foreach ($commits as $commit) { - $builder->add($commit); - } - - $process = $builder->getProcess(); - $process->setCommandLine(str_replace('--format=', '--format=%h|%ci|%s', $process->getCommandLine())); - - $output = $this->git->run($process); - $lines = $this->split($output); - $result = array(); - $author = null; - - foreach ($lines as $line) { - if (substr($line, 0, 1) != ' ') { - if (preg_match('/([^<>]*? <[^<>]+>)/', $line, $matches)) { - $author = $matches[1]; - $result[$author] = array(); - } - continue; - } - - list ($commit, $date, $subject) = explode('|', trim($line), 3); - $result[$author][] = array( - 'commit' => $commit, - 'date' => new \DateTime($date), - 'subject' => $subject - ); - } - - return $result; - } - - /** - * Suppress commit description and provide a commit count summary only - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $shortlog = $git->shortlog->summary(); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * 'John Doe <john@example.com>' => 153, - * //... - * ] - * ``` - * - * @param string $commits [optional] Defaults to HEAD - * - * @return array - */ - public function summary($commits = 'HEAD') - { - $builder = $this->git->getProcessBuilder() - ->add('shortlog') - ->add('--numbered') - ->add('--summary') - ->add('-e'); - - if (!is_array($commits) && !($commits instanceof \Traversable)) { - $commits = array($commits); - } - - foreach ($commits as $commit) { - $builder->add($commit); - } - - $output = $this->git->run($builder->getProcess()); - $lines = $this->split($output); - $result = array(); - - foreach ($lines as $line) { - list ($commits, $author) = explode("\t", trim($line), 2); - $result[$author] = (int) $commits; - } - - return $result; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php b/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php deleted file mode 100644 index 866388357..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Show various types of objects - `git show` - * - * @author Kazuyuki Hayashi - */ -class ShowCommand extends Command -{ - - /** - * Shows one or more objects (blobs, trees, tags and commits) - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * echo $git->show('3ddee587e209661c8265d5bfd0df999836f6dfa2'); - * ``` - * - * ##### Options - * - * - **format** (_string_) Pretty-print the contents of the commit logs in a given format, where <format> can be one of oneline, short, medium, full, fuller, email, raw and format:<string> - * - **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix - * - * @param string $object The names of objects to show - * @param array $options [optional] An array of options {@see ShowCommand::setDefaultOptions} - * - * @return string - */ - public function __invoke($object, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('show'); - - $this->addFlags($builder, $options, array('abbrev-commit')); - - if ($options['format']) { - $builder->add('--format=' . $options['format']); - } - - $builder->add($object); - - return $this->git->run($builder->getProcess()); - } - - /** - * {@inheritdoc} - * - * - **format** (_string_) Pretty-print the contents of the commit logs in a given format, where <format> can be one of oneline, short, medium, full, fuller, email, raw and format:<string> - * - **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'format' => null, - 'abbrev-commit' => false - )); - - $resolver->setAllowedTypes(array( - 'format' => array('null', 'string'), - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/StashCommand.php b/library/kzykhys/git/src/PHPGit/Command/StashCommand.php deleted file mode 100644 index 52dceaa6b..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/StashCommand.php +++ /dev/null @@ -1,309 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; - -/** - * Stash the changes in a dirty working directory away - `git stash` - * - * @author Kazuyuki Hayashi - */ -class StashCommand extends Command -{ - - /** - * Save your local modifications to a new stash, and run git reset --hard to revert them - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash(); - * ``` - * - * @return bool - */ - public function __invoke() - { - $builder = $this->git->getProcessBuilder() - ->add('stash'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Save your local modifications to a new stash, and run git reset --hard to revert them. - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->save('My stash'); - * ``` - * - * @param string $message [optional] The description along with the stashed state - * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} - * - * @return bool - */ - public function save($message = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('save'); - - $builder->add($message); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Returns the stashes that you currently have - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $stashes = $git->stash->lists(); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * 0 => ['branch' => 'master', 'message' => '0e2f473 Fixes README.md'], - * 1 => ['branch' => 'master', 'message' => 'ce1ddde Initial commit'], - * ] - * ``` - * - * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} - * - * @return array - */ - public function lists(array $options = array()) - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('list'); - - $output = $this->git->run($builder->getProcess()); - $lines = $this->split($output); - $list = array(); - - foreach ($lines as $line) { - if (preg_match('/stash@{(\d+)}:.* [Oo]n (.*): (.*)/', $line, $matches)) { - $list[$matches[1]] = array( - 'branch' => $matches[2], - 'message' => $matches[3] - ); - } - } - - return $list; - } - - /** - * Show the changes recorded in the stash as a diff between the stashed state and its original parent - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * echo $git->stash->show('stash@{0}'); - * ``` - * - * ##### Output Example - * - * ``` - * REAMDE.md | 2 +- - * 1 files changed, 1 insertions(+), 1 deletions(-) - * ``` - * - * @param string $stash The stash to show - * - * @return string - */ - public function show($stash = null) - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('show'); - - if ($stash) { - $builder->add($stash); - } - - return $this->git->run($builder->getProcess()); - } - - /** - * Remove a single stashed state from the stash list - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->drop('stash@{0}'); - * ``` - * - * @param string $stash The stash to drop - * - * @return mixed - */ - public function drop($stash = null) - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('drop'); - - if ($stash) { - $builder->add($stash); - } - - return $this->git->run($builder->getProcess()); - } - - /** - * Remove a single stashed state from the stash list and apply it on top of the current working tree state - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->pop('stash@{0}'); - * ``` - * - * @param string $stash The stash to pop - * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} - * - * @return bool - */ - public function pop($stash = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('pop'); - - $this->addFlags($builder, $options, array('index')); - - if ($stash) { - $builder->add($stash); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Like pop, but do not remove the state from the stash list - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->apply('stash@{0}'); - * ``` - * - * @param string $stash The stash to apply - * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} - * - * @return bool - */ - public function apply($stash = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('apply'); - - $this->addFlags($builder, $options, array('index')); - - if ($stash) { - $builder->add($stash); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Creates and checks out a new branch named <branchname> starting from the commit at which the <stash> was originally created, applies the changes recorded in <stash> to the new working tree and index - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->branch('hotfix', 'stash@{0}'); - * ``` - * - * @param string $name The name of the branch - * @param string $stash The stash - * - * @return bool - */ - public function branch($name, $stash = null) - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('branch') - ->add($name); - - if ($stash) { - $builder->add($stash); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Remove all the stashed states - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->stash->clear(); - * ``` - * - * @return bool - */ - public function clear() - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('clear'); - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Create a stash (which is a regular commit object) and return its object name, without storing it anywhere in the ref namespace - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $commit = $git->stash->create(); - * ``` - * - * ##### Output Example - * - * ``` - * 877316ea6f95c43b7ccc2c2a362eeedfa78b597d - * ``` - * - * @return string - */ - public function create() - { - $builder = $this->git->getProcessBuilder() - ->add('stash') - ->add('create'); - - return $this->git->run($builder->getProcess()); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php b/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php deleted file mode 100644 index c2bc983fe..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Show the working tree status - `git status` - * - * = unmodified - * M = modified - * A = added - * D = deleted - * R = renamed - * C = copied - * U = updated but unmerged - * - * X Y Meaning - * ------------------------------------------------- - * [MD] not updated - * M [ MD] updated in index - * A [ MD] added to index - * D [ M] deleted from index - * R [ MD] renamed in index - * C [ MD] copied in index - * [MARC] index and work tree matches - * [ MARC] M work tree changed since index - * [ MARC] D deleted in work tree - * ------------------------------------------------- - * D D unmerged, both deleted - * A U unmerged, added by us - * U D unmerged, deleted by them - * U A unmerged, added by them - * D U unmerged, deleted by us - * A A unmerged, both added - * U U unmerged, both modified - * ------------------------------------------------- - * ? ? untracked - * ! ! ignored - * ------------------------------------------------- - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class StatusCommand extends Command -{ - - const UNMODIFIED = ' '; - const MODIFIED = 'M'; - const ADDED = 'A'; - const DELETED = 'D'; - const RENAMED = 'R'; - const COPIED = 'C'; - const UPDATED_BUT_UNMERGED = 'U'; - const UNTRACKED = '?'; - const IGNORED = '!'; - - /** - * Returns the working tree status - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $status = $git->status(); - * ``` - * - * ##### Constants - * - * - StatusCommand::UNMODIFIED [=' '] unmodified - * - StatusCommand::MODIFIED [='M'] modified - * - StatusCommand::ADDED [='A'] added - * - StatusCommand::DELETED [='D'] deleted - * - StatusCommand::RENAMED [='R'] renamed - * - StatusCommand::COPIED [='C'] copied - * - StatusCommand::UPDATED_BUT_UNMERGED [='U'] updated but unmerged - * - StatusCommand::UNTRACKED [='?'] untracked - * - StatusCommand::IGNORED [='!'] ignored - * - * ##### Output Example - * - * ``` php - * [ - * 'branch' => 'master', - * 'changes' => [ - * ['file' => 'item1.txt', 'index' => 'A', 'work_tree' => 'M'], - * ['file' => 'item2.txt', 'index' => 'A', 'work_tree' => ' '], - * ['file' => 'item3.txt', 'index' => '?', 'work_tree' => '?'], - * ] - * ] - * ``` - * - * ##### Options - * - * - **ignored** (_boolean_) Show ignored files as well - * - * @param array $options [optional] An array of options {@see StatusCommand::setDefaultOptions} - * - * @return mixed - */ - public function __invoke(array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('status') - ->add('--porcelain')->add('-s')->add('-b')->add('--null'); - - $this->addFlags($builder, $options); - - $process = $builder->getProcess(); - $result = array('branch' => null, 'changes' => array()); - $output = $this->git->run($process); - - list($branch, $changes) = preg_split('/(\0|\n)/', $output, 2); - $lines = $this->split($changes, true); - - if (substr($branch, -11) == '(no branch)') { - $result['branch'] = null; - } elseif (preg_match('/([^ ]*)\.\.\..*?\[.*?\]$/', $branch, $matches)) { - $result['branch'] = $matches[1]; - } elseif (preg_match('/ ([^ ]*)$/', $branch, $matches)) { - $result['branch'] = $matches[1]; - } - - foreach ($lines as $line) { - $result['changes'][] = array( - 'file' => substr($line, 3), - 'index' => substr($line, 0, 1), - 'work_tree' => substr($line, 1, 1) - ); - } - - return $result; - } - - /** - * {@inheritdoc} - * - * - **ignored** (_boolean_) Show ignored files as well - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'ignored' => false - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/TagCommand.php b/library/kzykhys/git/src/PHPGit/Command/TagCommand.php deleted file mode 100644 index 197d3e887..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/TagCommand.php +++ /dev/null @@ -1,156 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; - -/** - * Create, list, delete or verify a tag object signed with GPG - `git tag` - * - * @author Kazuyuki Hayashi - */ -class TagCommand extends Command -{ - - /** - * Returns an array of tags - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * $tags = $git->tag(); - * ``` - * - * ##### Output Example - * - * ``` - * ['v1.0.0', 'v1.0.1', 'v1.0.2'] - * ``` - * - * @throws GitException - * @return array - */ - public function __invoke() - { - $builder = $this->git->getProcessBuilder() - ->add('tag'); - - $output = $this->git->run($builder->getProcess()); - - return $this->split($output); - } - - /** - * Creates a tag object - * - * ``` php - * $git = new PHPGit\Git(); - * $git->setRepository('/path/to/repo'); - * $git->tag->create('v1.0.0'); - * ``` - * - * ##### Options - * - * - **annotate** (_boolean_) Make an unsigned, annotated tag object - * - **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key - * - **force** (_boolean_) Replace an existing tag with the given name (instead of failing) - * - * @param string $tag The name of the tag to create - * @param string $commit The SHA1 object name of the commit object - * @param array $options [optional] An array of options {@see TagCommand::setDefaultOptions} - * - * @throws GitException - * @return bool - */ - public function create($tag, $commit = null, array $options = array()) - { - $options = $this->resolve($options); - $builder = $this->git->getProcessBuilder() - ->add('tag') - ->add($tag); - - $this->addFlags($builder, $options, array('annotate', 'sign', 'force')); - - if ($commit) { - $builder->add($commit); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Delete existing tags with the given names - * - * @param string|array|\Traversable $tag The name of the tag to create - * - * @throws GitException - * @return bool - */ - public function delete($tag) - { - $builder = $this->git->getProcessBuilder() - ->add('tag') - ->add('-d'); - - if (!is_array($tag) && !($tag instanceof \Traversable)) { - $tag = array($tag); - } - - foreach ($tag as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * Verify the gpg signature of the given tag names - * - * @param string|array|\Traversable $tag The name of the tag to create - * - * @throws GitException - * @return bool - */ - public function verify($tag) - { - $builder = $this->git->getProcessBuilder() - ->add('tag') - ->add('-v'); - - if (!is_array($tag) && !($tag instanceof \Traversable)) { - $tag = array($tag); - } - - foreach ($tag as $value) { - $builder->add($value); - } - - $this->git->run($builder->getProcess()); - - return true; - } - - /** - * {@inheritdoc} - * - * - **annotate** (_boolean_) Make an unsigned, annotated tag object - * - **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key - * - **force** (_boolean_) Replace an existing tag with the given name (instead of failing) - */ - public function setDefaultOptions(OptionsResolverInterface $resolver) - { - $resolver->setDefaults(array( - 'annotate' => false, - 'sign' => false, - 'force' => false, - )); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php b/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php deleted file mode 100644 index ea1040a6a..000000000 --- a/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php +++ /dev/null @@ -1,70 +0,0 @@ -<?php - -namespace PHPGit\Command; - -use PHPGit\Command; - -/** - * List the contents of a tree object - `git ls-tree` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class TreeCommand extends Command -{ - - /** - * Returns the contents of a tree object - * - * ``` php - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * $tree = $git->tree('master'); - * ``` - * - * ##### Output Example - * - * ``` php - * [ - * ['mode' => '100644', 'type' => 'blob', 'hash' => '1f100ce9855b66111d34b9807e47a73a9e7359f3', 'file' => '.gitignore', 'sort' => '2:.gitignore'], - * ['mode' => '100644', 'type' => 'blob', 'hash' => 'e0bfe494537037451b09c32636c8c2c9795c05c0', 'file' => '.travis.yml', 'sort' => '2:.travis.yml'], - * ['mode' => '040000', 'type' => 'tree', 'hash' => '8d5438e79f77cd72de80c49a413f4edde1f3e291', 'file' => 'bin', 'sort' => '1:.bin'], - * ] - * ``` - * - * @param string $branch The commit - * @param string $path The path - * - * @return array - */ - public function __invoke($branch = 'master', $path = '') - { - $objects = array(); - $builder = $this->git->getProcessBuilder(); - $process = $builder->add('ls-tree')->add($branch . ':' . $path)->getProcess(); - $output = $this->git->run($process); - $lines = $this->split($output); - - $types = array( - 'submodule' => 0, - 'tree' => 1, - 'blob' => 2 - ); - - foreach ($lines as $line) { - list($meta, $file) = explode("\t", $line); - list($mode, $type, $hash) = explode(" ", $meta); - - $objects[] = array( - 'sort' => sprintf('%d:%s', $types[$type], $file), - 'mode' => $mode, - 'type' => $type, - 'hash' => $hash, - 'file' => $file - ); - } - - return $objects; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Exception/GitException.php b/library/kzykhys/git/src/PHPGit/Exception/GitException.php deleted file mode 100644 index f5901010c..000000000 --- a/library/kzykhys/git/src/PHPGit/Exception/GitException.php +++ /dev/null @@ -1,39 +0,0 @@ -<?php - -namespace PHPGit\Exception; - -/** - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class GitException extends \Exception -{ - - /** - * @var string - */ - protected $commandLine; - - /** - * Construct the exception. Note: The message is NOT binary safe. - * - * @param string $message [optional] The Exception message to throw. - * @param int $code [optional] The Exception code. - * @param string $commandLine [optional] Command-line - * @param \Exception $previous [optional] The previous exception used for the exception chaining. Since 5.3.0 - */ - public function __construct($message = "", $code = 0, $commandLine = null, \Exception $previous = null) - { - parent::__construct($message, $code, $previous); - - $this->commandLine = $commandLine; - } - - /** - * @return null|string - */ - public function getCommandLine() - { - return $this->commandLine; - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Git.php b/library/kzykhys/git/src/PHPGit/Git.php deleted file mode 100644 index f952d6f1f..000000000 --- a/library/kzykhys/git/src/PHPGit/Git.php +++ /dev/null @@ -1,308 +0,0 @@ -<?php - -namespace PHPGit; - -use PHPGit\Command; -use PHPGit\Exception\GitException; -use Symfony\Component\Process\Process; -use Symfony\Component\Process\ProcessBuilder; - -/** - * PHPGit - A Git wrapper for PHP5.3+ - * ================================== - * - * [![Latest Unstable Version](https://poser.pugx.org/kzykhys/git/v/unstable.png)](https://packagist.org/packages/kzykhys/git) - * [![Build Status](https://travis-ci.org/kzykhys/PHPGit.png?branch=master)](https://travis-ci.org/kzykhys/PHPGit) - * [![Coverage Status](https://coveralls.io/repos/kzykhys/PHPGit/badge.png)](https://coveralls.io/r/kzykhys/PHPGit) - * [![SensioLabsInsight](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f/mini.png)](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f) - * - * Requirements - * ------------ - * - * * PHP5.3 - * * Git - * - * Installation - * ------------ - * - * Update your composer.json and run `composer update` - * - * ``` json - * { - * "require": { - * "kzykhys/git": "dev-master" - * } - * } - * ``` - * - * Basic Usage - * ----------- - * - * ``` php - * <?php - * - * require __DIR__ . '/vendor/autoload.php'; - * - * $git = new PHPGit\Git(); - * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); - * $git->setRepository('/path/to/repo'); - * $git->remote->add('production', 'git://example.com/your/repo.git'); - * $git->add('README.md'); - * $git->commit('Adds README.md'); - * $git->checkout('release'); - * $git->merge('master'); - * $git->push(); - * $git->push('production', 'release'); - * $git->tag->create('v1.0.1', 'release'); - * - * foreach ($git->tree('release') as $object) { - * if ($object['type'] == 'blob') { - * echo $git->show($object['file']); - * } - * } - * ``` - * - * @author Kazuyuki Hayashi <hayashi@valnur.net> - * @license MIT - * - * @method add($file, $options = array()) Add file contents to the index - * @method archive($file, $tree = null, $path = null, $options = array()) Create an archive of files from a named tree - * @method branch($options = array()) List both remote-tracking branches and local branches - * @method checkout($branch, $options = array()) Checkout a branch or paths to the working tree - * @method clone($repository, $path = null, $options = array()) Clone a repository into a new directory - * @method commit($message = '', $options = array()) Record changes to the repository - * @method config($options = array()) List all variables set in config file - * @method describe($committish = null, $options = array()) Returns the most recent tag that is reachable from a commit - * @method fetch($repository, $refspec = null, $options = array()) Fetches named heads or tags from one or more other repositories - * @method init($path, $options = array()) Create an empty git repository or reinitialize an existing one - * @method log($path = null, $options = array()) Returns the commit logs - * @method merge($commit, $message = null, $options = array()) Incorporates changes from the named commits into the current branch - * @method mv($source, $destination, $options = array()) Move or rename a file, a directory, or a symlink - * @method pull($repository = null, $refspec = null, $options = array()) Fetch from and merge with another repository or a local branch - * @method push($repository = null, $refspec = null, $options = array()) Update remote refs along with associated objects - * @method rebase($upstream = null, $branch = null, $options = array()) Forward-port local commits to the updated upstream head - * @method remote() Returns an array of existing remotes - * @method reset($commit = null, $paths = array()) Resets the index entries for all <paths> to their state at <commit> - * @method rm($file, $options = array()) Remove files from the working tree and from the index - * @method shortlog($commits = array()) Summarize 'git log' output - * @method show($object, $options = array()) Shows one or more objects (blobs, trees, tags and commits) - * @method stash() Save your local modifications to a new stash, and run git reset --hard to revert them - * @method status($options = array()) Show the working tree status - * @method tag() Returns an array of tags - * @method tree($branch = 'master', $path = '') List the contents of a tree object - */ -class Git -{ - - /** @var Command\AddCommand */ - public $add; - - /** @var Command\ArchiveCommand */ - public $archive; - - /** @var Command\BranchCommand */ - public $branch; - - /** @var Command\CatCommand */ - public $cat; - - /** @var Command\CheckoutCommand */ - public $checkout; - - /** @var Command\CloneCommand */ - public $clone; - - /** @var Command\CommitCommand */ - public $commit; - - /** @var Command\ConfigCommand */ - public $config; - - /** @var Command\DescribeCommand */ - public $describe; - - // Not implemented yet - public $diff; - - /** @var Command\FetchCommand */ - public $fetch; - - /** @var Command\InitCommand */ - public $init; - - /** @var Command\LogCommand */ - public $log; - - /** @var Command\MergeCommand */ - public $merge; - - /** @var Command\MvCommand */ - public $mv; - - /** @var Command\PullCommand */ - public $pull; - - /** @var Command\PushCommand */ - public $push; - - /** @var Command\RebaseCommand */ - public $rebase; - - /** @var Command\RemoteCommand */ - public $remote; - - /** @var Command\ResetCommand */ - public $reset; - - /** @var Command\RmCommand */ - public $rm; - - /** @var Command\ShortlogCommand */ - public $shortlog; - - /** @var Command\ShowCommand */ - public $show; - - /** @var Command\StashCommand */ - public $stash; - - /** @var Command\StatusCommand */ - public $status; - - /** @var Command\TagCommand */ - public $tag; - - /** @var Command\TreeCommand */ - public $tree; - - /** @var string */ - private $bin = 'git'; - - /** @var string */ - private $directory = '.'; - - /** - * Initializes sub-commands - */ - public function __construct() - { - $this->add = new Command\AddCommand($this); - $this->archive = new Command\ArchiveCommand($this); - $this->branch = new Command\BranchCommand($this); - $this->cat = new Command\CatCommand($this); - $this->checkout = new Command\CheckoutCommand($this); - $this->clone = new Command\CloneCommand($this); - $this->commit = new Command\CommitCommand($this); - $this->config = new Command\ConfigCommand($this); - $this->describe = new Command\DescribeCommand($this); - $this->fetch = new Command\FetchCommand($this); - $this->init = new Command\InitCommand($this); - $this->log = new Command\LogCommand($this); - $this->merge = new Command\MergeCommand($this); - $this->mv = new Command\MvCommand($this); - $this->pull = new Command\PullCommand($this); - $this->push = new Command\PushCommand($this); - $this->rebase = new Command\RebaseCommand($this); - $this->remote = new Command\RemoteCommand($this); - $this->reset = new Command\ResetCommand($this); - $this->rm = new Command\RmCommand($this); - $this->shortlog = new Command\ShortlogCommand($this); - $this->show = new Command\ShowCommand($this); - $this->stash = new Command\StashCommand($this); - $this->status = new Command\StatusCommand($this); - $this->tag = new Command\TagCommand($this); - $this->tree = new Command\TreeCommand($this); - } - - /** - * Calls sub-commands - * - * @param string $name The name of a property - * @param array $arguments An array of arguments - * - * @throws \BadMethodCallException - * @return mixed - */ - public function __call($name, $arguments) - { - if (isset($this->{$name}) && is_callable($this->{$name})) { - return call_user_func_array($this->{$name}, $arguments); - } - - throw new \BadMethodCallException(sprintf('Call to undefined method PHPGit\Git::%s()', $name)); - } - - /** - * Sets the Git binary path - * - * @param string $bin - * - * @return Git - */ - public function setBin($bin) - { - $this->bin = $bin; - - return $this; - } - - /** - * Sets the Git repository path - * - * @var string $directory - * - * @return Git - */ - public function setRepository($directory) - { - $this->directory = $directory; - - return $this; - } - - /** - * Returns version number - * - * @return mixed - */ - public function getVersion() - { - $process = $this->getProcessBuilder() - ->add('--version') - ->getProcess(); - - return $this->run($process); - } - - /** - * Returns an instance of ProcessBuilder - * - * @return ProcessBuilder - */ - public function getProcessBuilder() - { - return ProcessBuilder::create() - ->setPrefix($this->bin) - ->setWorkingDirectory($this->directory); - } - - /** - * Executes a process - * - * @param Process $process The process to run - * - * @throws Exception\GitException - * @return mixed - */ - public function run(Process $process) - { - $process->run(); - - if (!$process->isSuccessful()) { - throw new GitException($process->getErrorOutput(), $process->getExitCode(), $process->getCommandLine()); - } - - return $process->getOutput(); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/BaseTestCase.php b/library/kzykhys/git/test/PHPGit/BaseTestCase.php deleted file mode 100644 index df69b216e..000000000 --- a/library/kzykhys/git/test/PHPGit/BaseTestCase.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -use Symfony\Component\Filesystem\Filesystem; - -/** - * @author Kazuyuki Hayashi <hayashi@siance.co.jp> - */ -abstract class BaseTestCase extends PHPUnit_Framework_TestCase -{ - - /** - * @var string - */ - protected $directory; - - /** - * {@inheritdoc} - */ - public function setUp() - { - $this->directory = __DIR__.'/../../build/' . strtolower(get_class($this)); - } - - /** - * {@inheritdoc} - */ - public function tearDown() - { - $filesystem = new Filesystem(); - $filesystem->remove($this->directory); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php deleted file mode 100644 index 1fad08417..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php +++ /dev/null @@ -1,42 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -/** - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class AddCommandTest extends BaseTestCase -{ - - public function testAdd() - { - $filesystem = new Filesystem(); - $filesystem->mkdir($this->directory); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $filesystem->dumpFile($this->directory . '/test.md', '**foo**'); - - $this->assertTrue($git->add('test.txt')); - $this->assertTrue($git->add(array('test.md'), array('force' => true))); - } - - /** - * @expectedException \PHPGit\Exception\GitException - * @expectedExceptionCode 128 - */ - public function testException() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->add('foo'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php deleted file mode 100644 index 982c8f7c7..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -/** - * @author Kazuyuki Hayashi <hayashi@valnur.net> - */ -class ArchiveCommandTest extends BaseTestCase -{ - - public function testArchive() - { - $filesystem = new Filesystem(); - $filesystem->mkdir($this->directory); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'hello'); - $git->add('test.txt'); - $git->commit('Initial commit'); - - $git->archive($this->directory . '/test.zip', 'master', null, array('format' => 'zip', 'prefix' => 'test/')); - - $this->assertFileExists($this->directory . '/test.zip'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php deleted file mode 100644 index 4deeea367..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class BranchCommandTest extends BaseTestCase -{ - - public function setUp() - { - parent::setUp(); - - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', ''); - $git->add('test.txt'); - $git->commit('Initial commit'); - } - - public function testBranch() - { - $git = new Git(); - $git->setRepository($this->directory); - - $branches = $git->branch(); - - $this->assertCount(1, $branches); - $this->assertEquals('master', $branches['master']['name']); - $this->assertTrue($branches['master']['current']); - $this->assertEquals('Initial commit', $branches['master']['title']); - } - - public function testAllBranch() - { - $git = new Git(); - $git->clone('file://' . realpath($this->directory), $this->directory.'2'); - $git->setRepository($this->directory.'2'); - - $branches = $git->branch(array('remotes' => true)); - $this->assertArrayHasKey('origin/master', $branches); - - $branches = $git->branch(array('all' => true)); - $this->assertArrayHasKey('master', $branches); - $this->assertArrayHasKey('remotes/origin/master', $branches); - - $filesystem = new Filesystem(); - $filesystem->remove($this->directory.'2'); - } - - public function testBranchCreate() - { - $git = new Git(); - $git->setRepository($this->directory); - - $git->branch->create('1.0'); - $branches = $git->branch(); - $this->assertCount(2, $branches); - - $git->branch->create('1.0-fix', '1.0', array('force' => true)); - $branches = $git->branch(); - $this->assertCount(3, $branches); - $this->assertArrayHasKey('1.0', $branches); - $this->assertArrayHasKey('1.0-fix', $branches); - } - - public function testBranchMove() - { - $git = new Git(); - $git->setRepository($this->directory); - $git->branch->create('1.0'); - $git->branch->move('1.0', '1.0.x'); - $branches = $git->branch(); - $this->assertCount(2, $branches); - $this->assertArrayHasKey('1.0.x', $branches); - - $git->branch->move('1.0.x', '2.x', array('force' => true)); - $branches = $git->branch(); - $this->assertCount(2, $branches); - $this->assertArrayHasKey('2.x', $branches); - } - - public function testBranchDelete() - { - $git = new Git(); - $git->setRepository($this->directory); - $git->branch->create('1.0'); - $git->branch->create('2.0'); - $branches = $git->branch(); - $this->assertCount(3, $branches); - - $git->branch->delete('1.0'); - $branches = $git->branch(); - $this->assertCount(2, $branches); - - $git->branch->delete('2.0', array('force' => true)); - $branches = $git->branch(); - $this->assertCount(1, $branches); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php deleted file mode 100644 index 945924ccb..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class CatCommandTest extends BaseTestCase -{ - - public function testCatBlob() - { - $filesystem = new Filesystem(); - $filesystem->mkdir($this->directory); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('Initial commit'); - - $tree = $git->tree(); - - $this->assertEquals('foo', $git->cat->blob($tree[0]['hash'])); - } - - public function testCatType() - { - $filesystem = new Filesystem(); - $filesystem->mkdir($this->directory); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('Initial commit'); - - $tree = $git->tree(); - - $this->assertEquals('blob', $git->cat->type($tree[0]['hash'])); - } - - public function testCatSize() - { - $filesystem = new Filesystem(); - $filesystem->mkdir($this->directory); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('Initial commit'); - - $tree = $git->tree(); - - $this->assertEquals(3, $git->cat->size($tree[0]['hash'])); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php deleted file mode 100644 index c306ea407..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class CheckoutCommandTest extends BaseTestCase -{ - - public function setUp() - { - parent::setUp(); - - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', ''); - $git->add('test.txt'); - $git->commit('Initial commit'); - } - - public function testCheckout() - { - $git = new Git(); - $git->setRepository($this->directory); - $git->branch->create('next'); - $git->checkout('next'); - - $branches = $git->branch(); - $this->assertArrayHasKey('next', $branches); - $this->assertTrue($branches['next']['current']); - } - - public function testCheckoutCreate() - { - $git = new Git(); - $git->setRepository($this->directory); - $git->checkout->create('next'); - - $branches = $git->branch(); - $this->assertArrayHasKey('next', $branches); - $this->assertTrue($branches['next']['current']); - - $git->checkout->create('develop', 'next'); - - $branches = $git->branch(); - $this->assertArrayHasKey('develop', $branches); - $this->assertTrue($branches['develop']['current']); - } - - public function testCheckoutOrphan() - { - $git = new Git(); - $git->setRepository($this->directory); - $git->checkout->orphan('gh-pages', 'master', array('force' => true)); - - $status = $git->status(); - $this->assertEquals('gh-pages', $status['branch']); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php deleted file mode 100644 index d6a4d26ff..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class CloneCommandTest extends BaseTestCase -{ - - public function testClone() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $this->assertFileExists($this->directory . '/.git'); - - $filesystem = new Filesystem(); - $filesystem->remove($this->directory); - - $git->setRepository('.'); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory, array('shared' => true)); - - $this->assertFileExists($this->directory . '/.git'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php deleted file mode 100644 index 01b50ad8d..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class CommitCommandTest extends BaseTestCase -{ - - public function testCommit() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem = new Filesystem(); - $filesystem->dumpFile($this->directory . '/test.txt', ''); - $git->add('test.txt'); - $git->commit('Initial commit'); - $logs = $git->log('test.txt'); - - $this->assertCount(1, $logs); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php deleted file mode 100644 index fba2fbf76..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class ConfigCommandTest extends BaseTestCase -{ - - public function testConfigSetAndList() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $before = $git->config(); - - $git->config->set('user.name', 'John Doe'); - - $config = $git->config(); - $this->assertArrayHasKey('user.name', $config); - - $expected = 'John Doe'; - - if (isset($before['user.name'])) { - $expected = $before['user.name'] . "\n" . $expected; - } - - $this->assertEquals($expected, $config['user.name']); - } - - public function testConfigAdd() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $before = $git->config(); - - $git->config->set('user.name', 'John Doe'); - $git->config->add('user.name', 'Foo'); - - $config = $git->config(); - $this->assertArrayHasKey('user.name', $config); - - $expected = "John Doe\nFoo"; - - if (isset($before['user.name'])) { - $expected = $before['user.name'] . "\n" . $expected; - } - - $this->assertEquals($expected, $config['user.name']); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php deleted file mode 100644 index 04d3bd3b0..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class DescribeCommandTest extends BaseTestCase -{ - - public function testDescribeTags() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('README.md'); - $git->commit('Initial commit'); - $git->tag->create('v1.0.0'); - $version = $git->describe->tags('HEAD'); - - $this->assertEquals('v1.0.0', $version); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello2'); - $git->add('README.md'); - $git->commit('Fixes README'); - $version = $git->describe->tags('HEAD'); - - $this->assertStringStartsWith('v1.0.0', $version); - $this->assertStringEndsNotWith('v1.0.0', $version); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php deleted file mode 100644 index f52943099..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class FetchCommandTest extends BaseTestCase -{ - - public function testFetch() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->fetch('origin', '+refs/heads/*:refs/remotes/origin/*'); - - $tags = $git->tag(); - $this->assertContains('v1.0.0', $tags); - } - - public function testFetchAll() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->fetch->all(); - - $tags = $git->tag(); - $this->assertContains('v1.0.0', $tags); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php deleted file mode 100644 index 208461523..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php +++ /dev/null @@ -1,101 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class MergeCommandTest extends BaseTestCase -{ - - public function testMerge() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('master'); - - $git->checkout->create('develop'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('develop'); - - $git->checkout('master'); - - $this->assertEquals('foo', file_get_contents($this->directory . '/test.txt')); - - $git->merge('develop'); - - $this->assertEquals('bar', file_get_contents($this->directory . '/test.txt')); - } - - /** - * @expectedException \PHPGit\Exception\GitException - */ - public function testMergeFail() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - // branch:master - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('master'); - - // branch:develop - $git->checkout->create('develop'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('develop'); - - // branch:master - $git->checkout('master'); - $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); - $git->merge('develop'); - } - - public function testMergeAbort() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - // branch:master - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('master'); - - // branch:develop - $git->checkout->create('develop'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('develop'); - - // branch:master - $git->checkout('master'); - $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); - $git->add('test.txt'); - $git->commit('master'); - - try { - $git->merge('develop'); - $this->fail('$git->merge("develop") should fail'); - } catch (Exception $e) { - } - - $git->merge->abort(); - - $this->assertEquals('baz', file_get_contents($this->directory . '/test.txt')); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php deleted file mode 100644 index dd5f46c55..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class MvCommandTest extends BaseTestCase -{ - - public function testMv() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('Initial commit'); - $git->mv('test.txt', 'test2.txt'); - - $this->assertFileExists($this->directory . '/test2.txt'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php deleted file mode 100644 index 89dec75a9..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class PullCommandTest extends BaseTestCase -{ - - public function testPull() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->pull('origin', 'master'); - - $this->assertFileExists($this->directory . '/README.md'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php deleted file mode 100644 index 11424cebc..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php +++ /dev/null @@ -1,34 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class PushCommandTest extends BaseTestCase -{ - - public function testPush() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory, array('shared' => true, 'bare' => true)); - - $git->clone('file://' . realpath($this->directory), $this->directory.'2'); - $git->setRepository($this->directory.'2'); - - $filesystem->dumpFile($this->directory.'2/test.txt', 'foobar'); - $git->add('test.txt'); - $git->commit('test'); - $git->push('origin', 'master'); - - $git->clone('file://' . realpath($this->directory), $this->directory.'3'); - - $this->assertFileExists($this->directory.'3/test.txt'); - - $filesystem->remove($this->directory.'2'); - $filesystem->remove($this->directory.'3'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php deleted file mode 100644 index af7e87a19..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php +++ /dev/null @@ -1,154 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class RebaseCommandTest extends BaseTestCase -{ - - public function testRebase() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', '123'); - $git->add('test.txt'); - $git->commit('initial commit'); - - $git->checkout->create('next'); - $filesystem->dumpFile($this->directory . '/test2.txt', '123'); - $git->add('test2.txt'); - $git->commit('test'); - - $git->checkout('master'); - $git->rebase('next', 'master'); - - $this->assertFileExists($this->directory. '/test2.txt'); - } - - public function testRebaseOnto() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/test.txt', '123'); - $git->add('test.txt'); - $git->commit('initial commit'); - - $git->checkout->create('next'); - $filesystem->dumpFile($this->directory . '/test2.txt', '123'); - $git->add('test2.txt'); - $git->commit('test'); - - $git->checkout->create('topic', 'next'); - $filesystem->dumpFile($this->directory . '/test3.txt', '123'); - $git->add('test3.txt'); - $git->commit('test'); - - $git->rebase('next', null, array('onto' => 'master')); - $this->assertFileNotExists($this->directory . '/test2.txt'); - } - - public function testRebaseContinue() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('initial commit'); - - $git->checkout->create('next'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('next commit'); - - $git->checkout('master'); - $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); - $git->add('test.txt'); - $git->commit('master commit'); - - try { - $git->rebase('next'); - $this->fail('GitException should be thrown'); - } catch (\PHPGit\Exception\GitException $e) { - } - - $filesystem->dumpFile($this->directory . '/test.txt', 'foobar'); - $git->add('test.txt'); - $git->rebase->continues(); - } - - public function testRebaseAbort() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('initial commit'); - - $git->checkout->create('next'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('next commit'); - - $git->checkout('master'); - $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); - $git->add('test.txt'); - $git->commit('master commit'); - - try { - $git->rebase('next'); - $this->fail('GitException should be thrown'); - } catch (\PHPGit\Exception\GitException $e) { - } - - $git->rebase->abort(); - } - - public function testRebaseSkip() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); - $git->add('test.txt'); - $git->commit('initial commit'); - - $git->checkout->create('next'); - $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); - $git->add('test.txt'); - $git->commit('next commit'); - - $git->checkout('master'); - $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); - $git->add('test.txt'); - $git->commit('master commit'); - - try { - $git->rebase('next'); - $this->fail('GitException should be thrown'); - } catch (\PHPGit\Exception\GitException $e) { - } - - $git->rebase->skip(); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php deleted file mode 100644 index 4f428f832..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../../BaseTestCase.php'; - -class SetBranchesCommandTest extends BaseTestCase -{ - - public function testSetBranches() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $git->remote->branches('origin', array('master')); - } - - public function testSetBranchesAdd() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $git->remote->branches->add('origin', array('gh-pages')); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php deleted file mode 100644 index 679c2976f..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php +++ /dev/null @@ -1,56 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../../BaseTestCase.php'; - -class SetHeadCommandTest extends BaseTestCase -{ - - public function testSetHead() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $before = $git->branch(array('all' => true)); - - $git->remote->head('origin', 'master'); - - $after = $git->branch(array('all' => true)); - - $this->assertEquals($before, $after); - } - - public function testSetHeadDelete() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $before = $git->branch(array('all' => true)); - - $git->remote->head->delete('origin'); - - $after = $git->branch(array('all' => true)); - - $this->assertNotEquals($before, $after); - } - - public function testSetHeadRemote() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $before = $git->branch(array('all' => true)); - - $git->remote->head->delete('origin'); - $git->remote->head->remote('origin'); - - $after = $git->branch(array('all' => true)); - - $this->assertEquals($before, $after); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php deleted file mode 100644 index b70b67d40..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../../BaseTestCase.php'; - -class SetUrlCommandTest extends BaseTestCase -{ - - public function testSetUrl() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'http://example.com/test.git'); - $git->remote->url('origin', 'https://github.com/kzykhys/Text.git', 'http://example.com/test.git'); - - $remotes = $git->remote(); - - $this->assertEquals('https://github.com/kzykhys/Text.git', $remotes['origin']['fetch']); - } - - public function testSetUrlAdd() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'http://example.com/test.git'); - $git->remote->url->add('origin', 'https://github.com/kzykhys/Text.git'); - } - - public function testSetUrlDelete() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'http://example.com/test.git'); - $git->remote->url->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->remote->url->delete('origin', 'https://github.com'); - - $remotes = $git->remote(); - - $this->assertEquals('http://example.com/test.git', $remotes['origin']['fetch']); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php deleted file mode 100644 index 78aa81309..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -use PHPGit\Git; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class RemoteCommandTest extends BaseTestCase -{ - - public function testRemote() - { - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $remotes = $git->remote(); - - $this->assertEquals(array( - 'origin' => array( - 'fetch' => 'https://github.com/kzykhys/Text.git', - 'push' => 'https://github.com/kzykhys/Text.git' - ) - ), $remotes); - } - - public function testRemoteAdd() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - - $remotes = $git->remote(); - - $this->assertEquals(array( - 'origin' => array( - 'fetch' => 'https://github.com/kzykhys/Text.git', - 'push' => 'https://github.com/kzykhys/Text.git' - ) - ), $remotes); - } - - public function testRemoteRename() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->remote->rename('origin', 'upstream'); - - $remotes = $git->remote(); - $this->assertEquals(array( - 'upstream' => array( - 'fetch' => 'https://github.com/kzykhys/Text.git', - 'push' => 'https://github.com/kzykhys/Text.git' - ) - ), $remotes); - } - - public function testRemoteRm() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->remote->rm('origin'); - - $remotes = $git->remote(); - $this->assertEquals(array(), $remotes); - } - - public function testRemoteShow() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - - $this->assertNotEmpty($git->remote->show('origin')); - } - - public function testRemotePrune() - { - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); - $git->remote->prune('origin'); - } - - /** - * @expectedException \BadMethodCallException - */ - public function testBadMethodCall() - { - $git = new Git(); - $git->remote->foo(); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php deleted file mode 100644 index 777e48512..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php +++ /dev/null @@ -1,128 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - - -class ResetCommandTest extends BaseTestCase -{ - - public function testReset() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('README.md'); - - $git->reset('README.md', 'HEAD'); - } - - public function testResetSoft() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->soft(); - } - - public function testResetMixed() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->mixed(); - } - - public function testResetHard() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->hard('HEAD'); - } - - public function testResetMerge() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->merge(); - } - - public function testResetKeep() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->keep(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testResetInvalidMode() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - - $git->reset->mode('foo'); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php deleted file mode 100644 index 34996cc12..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php +++ /dev/null @@ -1,51 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class RmCommandTest extends BaseTestCase -{ - - public function testRm() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $filesystem->dumpFile($this->directory . '/bin/test.php', 'foo'); - $git->add(array('README.md', 'bin/test.php')); - $git->commit('Initial commit'); - - $git->rm('README.md'); - $git->rm('bin', array('recursive' => true)); - - $this->assertFileNotExists($this->directory . '/README.md'); - } - - public function testRmCached() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/README.md', 'foo'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $git->rm->cached('README.md'); - $git->commit('Delete README.md'); - - $this->assertFileExists($this->directory . '/README.md'); - - $tree = $git->tree(); - $this->assertEquals(array(), $tree); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php deleted file mode 100644 index 48967cab1..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class ShortlogCommandTest extends BaseTestCase -{ - - public function testShortlog() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->config->set('user.name', 'Name One'); - $git->config->set('user.email', 'one@example.com'); - $filesystem->dumpFile($this->directory . '/test.txt', ''); - $git->add('test.txt'); - $git->commit('1'); - $filesystem->dumpFile($this->directory . '/test2.txt', ''); - $git->add('test2.txt'); - $git->commit('2'); - - $git->config->set('user.name', 'Name Two'); - $git->config->set('user.email', 'two@example.com'); - $filesystem->dumpFile($this->directory . '/test3.txt', ''); - $git->add('test3.txt'); - $git->commit('3'); - - $shortlog = $git->shortlog(); - - $this->assertCount(2, $shortlog); - $this->assertCount(2, $shortlog['Name One <one@example.com>']); - $this->assertCount(1, $shortlog['Name Two <two@example.com>']); - $this->assertEquals('1', $shortlog['Name One <one@example.com>'][0]['subject']); - } - - public function testShortlogSummary() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $git->config->set('user.name', 'Name One'); - $git->config->set('user.email', 'one@example.com'); - $filesystem->dumpFile($this->directory . '/test.txt', ''); - $git->add('test.txt'); - $git->commit('1'); - $filesystem->dumpFile($this->directory . '/test2.txt', ''); - $git->add('test2.txt'); - $git->commit('2'); - - $git->config->set('user.name', 'Name Two'); - $git->config->set('user.email', 'two@example.com'); - $filesystem->dumpFile($this->directory . '/test3.txt', ''); - $git->add('test3.txt'); - $git->commit('3'); - - $summary = $git->shortlog->summary(); - - $this->assertEquals(array( - 'Name One <one@example.com>' => 2, - 'Name Two <two@example.com>' => 1 - ), $summary); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php deleted file mode 100644 index 25b22fe4f..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class ShowCommandTest extends BaseTestCase -{ - - public function testShow() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/README.md', 'foobar'); - $git->add('README.md'); - $git->commit('Initial commit'); - - $git->show('master', array('format' => 'oneline')); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php deleted file mode 100644 index bb87e48ea..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php +++ /dev/null @@ -1,204 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class StashCommandTest extends BaseTestCase -{ - - public function testStash() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - - $this->assertEquals('hello', file_get_contents($this->directory.'/README.md')); - } - - public function testStashSave() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash->save('stash test'); - - $this->assertEquals('hello', file_get_contents($this->directory.'/README.md')); - } - - public function testStashList() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - - $stashes = $git->stash->lists(); - - $this->assertCount(1, $stashes); - $this->assertEquals('master', $stashes[0]['branch']); - $this->assertStringEndsWith('Initial commit', $stashes[0]['message']); - } - - public function testStashShow() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - $git->stash->show('stash@{0}'); - } - - public function testStashDrop() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - $git->stash->drop(); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - $git->stash->drop('stash@{0}'); - - $this->assertCount(0, $git->stash->lists()); - } - - public function testStashPop() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash->save('stash#1'); - - $filesystem->dumpFile($this->directory . '/README.md', 'bar'); - $git->stash->save('stash#2'); - $git->stash->pop('stash@{1}'); - - $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); - $this->assertCount(1, $git->stash->lists()); - } - - public function testStashApply() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash->save('stash#1'); - - $filesystem->dumpFile($this->directory . '/README.md', 'bar'); - $git->stash->save('stash#2'); - $git->stash->apply('stash@{1}'); - - $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); - $this->assertCount(2, $git->stash->lists()); - } - - public function testStashBranch() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - - $git->stash->branch('dev', 'stash@{0}'); - $status = $git->status(); - - $this->assertEquals('dev', $status['branch']); - $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); - } - - public function testStashClear() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $git->stash(); - $git->stash->clear(); - - $this->assertCount(0, $git->stash->lists()); - } - - public function testStashCreate() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - - $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); - $object = $git->stash->create(); - - $this->assertNotEmpty($object); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php deleted file mode 100644 index ad04a74c0..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php - -use PHPGit\Command\StatusCommand; -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class StatusCommandTest extends BaseTestCase -{ - - public function testStatus() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/item1.txt', '1'); - $filesystem->dumpFile($this->directory . '/item2.txt', '2'); - $filesystem->dumpFile($this->directory . '/item3.txt', '3'); - - $git->add('item1.txt'); - $git->add('item2.txt'); - - $filesystem->dumpFile($this->directory . '/item1.txt', '1-1'); - - $status = $git->status(); - - $this->assertEquals(array( - 'branch' => 'master', - 'changes' => array( - array('file' => 'item1.txt', 'index' => StatusCommand::ADDED, 'work_tree' => StatusCommand::MODIFIED), - array('file' => 'item2.txt', 'index' => StatusCommand::ADDED, 'work_tree' => StatusCommand::UNMODIFIED), - array('file' => 'item3.txt', 'index' => StatusCommand::UNTRACKED, 'work_tree' => StatusCommand::UNTRACKED), - ) - ), $status); - } - - public function testDetachedHeadStatus() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/item1.txt', '1'); - $git->add('item1.txt'); - $git->commit('initial commit'); - $logs = $git->log(); - $hash = $logs[0]['hash']; - - $git->checkout($hash); - $status = $git->status(); - $this->assertEquals(null, $status['branch']); - } - - public function testTrackingBranchStatus() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->clone('https://github.com/kzykhys/Text.git', $this->directory); - $git->setRepository($this->directory); - - $filesystem->dumpFile($this->directory . '/test.txt', '1'); - $git->add('test.txt'); - $git->commit('test'); - - $status = $git->status(); - $this->assertEquals('master', $status['branch']); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php deleted file mode 100644 index 5715ba92e..000000000 --- a/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -use PHPGit\Git; -use Symfony\Component\Filesystem\Filesystem; - -require_once __DIR__ . '/../BaseTestCase.php'; - -class TagCommandTest extends BaseTestCase -{ - - public function testTagDelete() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - $git->tag->create('v1.0.0'); - $git->tag->delete('v1.0.0'); - $this->assertCount(0, $git->tag()); - } - - /** - * @expectedException \PHPGit\Exception\GitException - */ - public function testTagVerify() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - $git->tag->create('v1.0.0'); - $git->tag->verify('v1.0.0'); - } - - public function testCreateTagFromCommit() - { - $filesystem = new Filesystem(); - - $git = new Git(); - $git->init($this->directory); - $git->setRepository($this->directory); - $filesystem->dumpFile($this->directory . '/README.md', 'hello'); - $git->add('.'); - $git->commit('Initial commit'); - $log = $git->log(null, null, array('limit' => 1)); - $git->tag->create('v1.0.0', $log[0]['hash']); - $this->assertCount(1, $git->tag()); - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php b/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php deleted file mode 100644 index 154d6b906..000000000 --- a/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -use PHPGit\Exception\GitException; -use PHPGit\Git; - -class GitExceptionTest extends PHPUnit_Framework_TestCase -{ - - public function testException() - { - $git = new Git(); - $git->setRepository(sys_get_temp_dir()); - try { - $git->status(); - $this->fail('Previous operation should fail'); - } catch (GitException $e) { - $command = $e->getCommandLine(); - $command = str_replace(array('"', "'"), '', $command); - $this->assertStringEndsWith('status --porcelain -s -b --null', $command); - } - } - -} \ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/GitTest.php b/library/kzykhys/git/test/PHPGit/GitTest.php deleted file mode 100644 index c9aceeb13..000000000 --- a/library/kzykhys/git/test/PHPGit/GitTest.php +++ /dev/null @@ -1,33 +0,0 @@ -<?php - -use PHPGit\Git; - -class GitTest extends PHPUnit_Framework_TestCase -{ - - public function testGetVersion() - { - $git = new Git(); - $this->assertNotEmpty($git->getVersion()); - } - - /** - * @expectedException \PHPGit\Exception\GitException - */ - public function testInvalidGitBinary() - { - $git = new Git(); - $git->setBin('/foo/bar'); - $git->getVersion(); - } - - /** - * @expectedException \BadMethodCallException - */ - public function testBadMethodCall() - { - $git = new Git(); - $git->foo(); - } - -} \ No newline at end of file -- cgit v1.2.3 From b117cf9dc71a2042b27420b9a713ac69514f469e Mon Sep 17 00:00:00 2001 From: Harald Eilertsen <haraldei@anduin.net> Date: Wed, 9 Oct 2024 23:38:01 +0200 Subject: emove another PHPGit related file. --- library/PHPGit.autoload.php | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 library/PHPGit.autoload.php diff --git a/library/PHPGit.autoload.php b/library/PHPGit.autoload.php deleted file mode 100644 index 7ad2971da..000000000 --- a/library/PHPGit.autoload.php +++ /dev/null @@ -1,7 +0,0 @@ -<?php - -// autoload.php @generated by Composer - -require_once __DIR__ . '/composer' . '/autoload_real.php'; - -return ComposerAutoloaderInit929ad7f4e2f44798d12d2ab06db7b39b::getLoader(); \ No newline at end of file -- cgit v1.2.3