I7j4?<'l[X5}[W?UKa^Lk|_J /i;\U쎇 z^KBO8 UMevzsX1.RO,R2bky_{߇dUy3FVltB-HZ 4gnʘB pz]IvZϙ @2%MEg_]a(vCjBoOIXFC[Wۀ*tzlc]7!?Vp#` P)IQ*Y`DW)& Q!2l0oKL2 D$-UGȷx3>.VJzΒ(5(+}5r(AwK Ņf cMf*xČ :2M~zsYAi'3xpFRZ-/D'.*wt=>#-`רx cm ;{bڊ07@h]oHXP5fzx3"ٔYF293R϶qda;(nMNeC~D/#^k 7O~4pbZ6~oif l_)̳x} ) 1xjfZHJM͠7/^:wص_?҄h8i*F3/F)'0ԐQ1m_nɽny'xIrJ tOQTl_XEԾtERxahFeSb̻J}+w@RƟ; t 6b1Z28 `K| ASr ڙr?Aۉ;[Wt>}eoq q y®7Wx"t('F{5^I&H{Q),I3)fЍNcSʍ<M=BE]c3GnZ'Lu?+hb hgF>6|1!mL_'[T7M a:1*a;7KSƃX| *=\ca2ځ H OvӇӞp;OqSㅍhjO-vGpÀ8m`'NM3 E8[ӯCv瘒("f]mZqDC+%iN9MVל@LT;a??K!z -`Z@wr bwG`:MW(_Uo{ r ,_ph%M*#:S*;Ze9VLVoEs̋>/e) GM֣Y(P U'   mkw&^-XǺT?N{{z &̡|M~B|T-] }`S&ez3G|K|F};~4bW2+P/fRk?0'epk ^<BH9 0UXX@ÆnY0dh-nHRuVl;,FH=':xL]ij#?;@Iʜ[ rqo!z~.Ax|L.yĪV,-LXބ *iGѳ#4M+Bۊ$G?N>ܫ9uO"mtMMܻ#4u|.;B7S#\` ǯ0Nh^Zbą:.b Ў}v B1~犞ZjS a_|_^E]^F> m*r{;!'@w%(q|Hw/02TJםeQ[uu3R_Œ E jb MȆTa9׸`1g9hs諷k>|\MN,t&Zݐ\4 m~Ad,^ ^~; P$kP$j_~InmBމpLpsD,D#6"RHL5"ƾY|@zûk-~)ZCKiyt{w ;^1B':BŢ"+8'68 I=R\)WbxJ`[/ W|^ yfkJ% LJbَ)h1ݰNcQMv$k7%%XCHPm@H,nNB$5(H1 aW!ͮ E9$Q˝9=֣@ ɥDńC G bB mBR8EZLE }rg? "v\y57⃁s~*KCϬ5ĭ8Jq}QqU6uI/+}*3ĉlf6"{4RJuI&bZgP&}ٸ)#Z韒]Si?ho?F dLZ`Gdրu2GOBIU.ZoOun##=SG%K7EdڐSxSAsg3:һ2]TY1s6MLg;C F_նo śx}OZmDg-FESxR eUtDϔipu@a;SlȎRiRWEY b]A smJE%~is?'0nx˻ބaqf@r ϔV! 8l#A+Z| +_wpc}"I$4#|y&ЙhqR={׭_B>`ֱ׈yۙ"%`% _+IRםWٗyHBdu4܌u OSAal,r9au`׈yۙ"%u |~n2,F:OMVxfgH>|!UKIO15A@KJ e K)SICqek"VE>PR:9{D'4̳u)U\)I1Ls)?yX:L>p X%TS)ŜѹۊlznK7EdڐSx~aU<'M5)@oLu Tf#]= j-]`"xj70wc& N&VmYϔp5=f[gCv%C Xu%ި1ܛs 0u27 8Ǽ1[#EHi Y--d=]ğ%_>6Xu<i%԰e nd gB=Ɯ)<5LsԲŻurn substr_count($this->data, "\n", 0, min($this->char, $this->EOF)) + 1; } /** * @deprecated */ public function getCurrentLine() { return $this->currentLine(); } /** * Returns the current column of the current line that the tokenizer is at. * Newlines are column 0. The first char after a newline is column 1. * * @return int The column number. */ public function columnOffset() { // Short circuit for the first char. if (0 === $this->char) { return 0; } // 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. $backwardFrom = $this->char - 1 - strlen($this->data); $lastLine = strrpos($this->data, "\n", $backwardFrom); // 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 (false !== $lastLine) { $findLengthOf = substr($this->data, $lastLine + 1, $this->char - 1 - $lastLine); } else { // After a newline. $findLengthOf = substr($this->data, 0, $this->char); } return UTF8Utils::countChars($findLengthOf); } /** * @deprecated */ public function getColumnOffset() { return $this->columnOffset(); } /** * Get the current character. * * @return string The current character. */ public function current() { return $this->data[$this->char]; } /** * Advance the pointer. * This is part of the Iterator interface. */ public function next() { ++$this->char; } /** * Rewind to the start of the string. */ public function rewind() { $this->char = 0; } /** * Is the current pointer location valid. * * @return bool Whether the current pointer location is valid. */ public function valid() { return $this->char < $this->EOF; } /** * Get all characters until EOF. * * This reads to the end of the file, and sets the read marker at the * end of the file. * * Note this performs bounds checking. * * @return string Returns the remaining text. If called when the InputStream is * already exhausted, it returns an empty string. */ public function remainingChars() { if ($this->char < $this->EOF) { $data = substr($this->data, $this->char); $this->char = $this->EOF; return $data; } return ''; // false; } /** * Read to a particular match (or until $max bytes are consumed). * * This operates on byte sequences, not characters. * * Matches as far as possible until we reach a certain set of bytes * and returns the matched substring. * * @param string $bytes Bytes to match. * @param int $max Maximum number of bytes to scan. * * @return mixed Index or false if no match is found. You should use strong * equality when checking the result, since index could be 0. */ public function charsUntil($bytes, $max = null) { if ($this->char >= $this->EOF) { return false; } if (0 === $max || $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; } /** * Returns the string so long as $bytes matches. * * Matches as far as possible with a certain set of bytes * and returns the matched substring. * * @param string $bytes A mask of bytes to match. If ANY byte in this mask matches the * current char, the pointer advances and the char is part of the * substring. * @param int $max The max number of chars to read. * * @return string */ public function charsWhile($bytes, $max = null) { if ($this->char >= $this->EOF) { return false; } if (0 === $max || $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; } /** * Unconsume characters. * * @param int $howMany The number of characters to unconsume. */ public function unconsume($howMany = 1) { if (($this->char - $howMany) >= 0) { $this->char -= $howMany; } } /** * Look ahead without moving cursor. */ public function peek() { if (($this->char + 1) <= $this->EOF) { return $this->data[$this->char + 1]; } return false; } public function key() { return $this->char; } }