/I^Ec:?X9ɀ v73??d҅FA9qF|l+}N=w:T$<%.Ig|oZO{+)2t7E–iryj)>D+ˋs**St&Bt8\~IlsFkA@XCVfˢCeGU k+GIk?_G7oLB3]\[K&&ˎ I;v7ܝ_~LYE!ix&F3t{/\j G77'?z@k|;IsRoS/phW]f{;   tzo:]cСOKԵQ0tSx-q xg& %.;B,aӧ|2$9,msMtnA 31.>&s6ڈlG~IM )d`p̬c\iNk?T]%. h3噴Bf7bESė1$wޝ+E ڻFss?9x-s7i@ǩ O7vDkGkC3;vAêSmUeB2F!q|8ޘ4W\WRkH'Ψ?u iO30@rF@_şP+ɛ)/ 1S AW]hD/|ڛgssaD!d@+ `f |=cy]uQk+cܤ iU]Q'7\ld5y-/Y:MJ?<5tMLK!]]vPDv^t;YYvÀ N%,%#JBNƺI؛l!'sv:5J za|ԃ3RQ TFEَ&tI;ad`o(6 O,'YƒW$AV+ȱLbCnEj9qqR\ȋS%-xqѸsgYP0P_m_Xx4I;ZxFj47v-YIϗ6{$^Ɣd=s> d-]3^rjģ<|j,ǽW,^%jc)/ϓcT!_͂:n@qɀ{LOr9L@OL 1(\޾lL\B9ƦL%ޗnT ')Uq3,9@yK\@E(8uxЭ X.d NNANƵz"\CG%R!I0D[ER ]g?ߘ{s_VC}9uea8,%tOC8÷c1ީ*r`pB~ ў`k-S!89įsvGz"ᢽɒi (M0(hm\Dӫ8br2?" ܚrU+@d#pB;̈Haip{DK ƾs7 wcN?)>tk[2!T#O &~q#.fa}j370v,8+fV/5Glbꀥ& Aed*ŦlHm216>pO?jA&p*FW9'˱ػ tj\qъym\u7Cp%yIh XJ~%ċx'{Tu ;.F[,zifO~A$㬪vr$ˎBT8v'{ns nuY;gt2`s}%T]EW(<hUz_%fZo2;4*bYT4G-4_^<_8F! 40wJ14%T[WL3Rq6 CwR^cE@ͬ\L;a'1? @pH`~ԼY 3Nzgr<@/Upթx$b撯~*_EScޝpYF ر~VReO1FBkxG`_f,gCXή3"U~Hz*JQz*ɮ\-J~m"BjNp8-b8MyRhZzNO2aggϐrZU]jOD-`)n2P"+:&:<=e[  vI4e)}8_NԨ?Dht `e:[⺡'Gx{3Qvwb\8~ CwjϾy>  ZM=lvsIaI?Sft! Rfm(a2㧢 Mdasjq,0Ζ]jcJߘ֥ǠIY&MFw:3 W{Ehϴӯ{H=-` GҌ#Mj0$ia'i).b>%or&>{ 6&|05Qxg-";Ďf6K!"oҥR[*S4n*t9  lTQ2ʫQCMݾ3=!Vע#1%=&\2} bhvY&2Ħ˨PLK!u g\=2.qDvԲlx V̬hqϓa$f3ײx0|257J K}VsDF.-``dsW!+>yiG4%Ўx D'݉ѩrj(t겻WaZ:ܶ|r!9_V9Y_j/Y03rhV-doj buAJ4Vw=̩0z<&6~҃qT +4NYb;TKtj'-) FU+ +}=݈;zG j8 #k@+846s`ɮ 0◸`TY'O"v'uyUFs~Bn4=N3V<{;cbzedn؇c!E®.1{%ͳ^JaƀNm”++md/m3IK LЭu_i'B}kx]<c;oω''Cy+{oV Deo7wDF4F5.7@X/M f4Cbf[Vae\Ӣ8Nr8׻8tΟL_x'ac\Ud(B~# Eu0o.9cFXkL2S/SYԥ-FScDŽ|r S^<_rxQ{(M6US@,2ƣ[x nT(N=94j:S#!۾uJ|5uH K+xyТPXW-"2&C8w!/5l~KUUޢ |g0nEKq[Bf%Üߏc<;ɟ ̆gViwX/qc%kn?k VOUA(lKZV+uQ]{Q >il1KU(Ln!,_E'fD€3i!߈; }O ֪) ,n>pK椈6M4S2ז]3\M~ݢTPI{r8p*M4 ܧAt_ZjW}%|9=_!ZѷkúmSTkT9™A;CeY@K kFWU2 NXipX_UylҢ 2wD&9ׯڮc%;Zܞ*~hZb6tbs'Gpe^0D(N2<f,θZIY2g`Wzh Y4J gF6:or$wby$D-ѽ!sB7Sr$yYW2z=2BX '\m˗gych`:;ѷ@ncwFޗ=" x]L B3Nj_l6#,h(hg 5uii\`Gqhd2N,'K{#ܿlFz[E4Bt /;Vի[jWy/xǜG";JGc*:WЋay~bHR7YژI kVB-GD:3֮NAƍl'R_Qr4KHaZ_Wڊ#Cr2 ?0B-e?-GT6=2 ĉ_b|,*}R^`{{l}+o$ 5í} 씒yMN>nzhM//(B#)Z~vU/Z[kѹ>RPz)WG䁮j1!㋣7&ڻMA)3;fR*R ?_#X_Ν#YL)PtfwP(Y/lN{Ǯ [s\.k_a ~X=1Q/HfjpQGv~9~`|n)["#]>fNБLg kXH>8Tf)=AXjՓk]e2Gԋ^ ag`K[Ikb <]$w1V5=y7p.bNYA>:lvHƚ(eCv@eS!z:_-ENeDJod]Uչ/)JM<.5Ehf2f+|ו_{(qGy_"j ߱lئ*;~NڈåYͮhkcZsG, BHgQ/J7D$mL)f[uuQ0[~3:F>zKWG`#]_ Z3E;gaN,ޟ"gdw7.x|R琜{q]'"\:-LNJNv0_:64O:[@/9 U<]D'L U*uvxG.CC6]is=%MG'xb0rW26Dz6 ]BsM|1h^B5wgBٵE1sfd3S0HƳ+؈VIO?g9]̩A'B!Dx|+\FzrлMl2=CrpD~j65ڝE%XR mCt/BC'&EeSx3#X,X]`wSMtYPiaQ+{3p(.( ԌU d;d|d!_3mi?xjoVLÐ :3 }^ų>)H{6jؘd mu*a~;b7--P{%RCp[1K_d&yl?! q;GV̖wڎ۠x [y98"ÃK.ˀei=:F͠DL {o38*ˆ_ D)n53DNFKv\_ЩHZD^ h!8AM+Oo(6O9rϛK* tԇU¢C\SsV)( chVC\3v DJ}=+m-3 68v=ܭ$?ZD Zѓn>X u5iCq8Zp,"e6g #ݛkBnbH 0wN3-xho[PWkٝV,"/ ߏ]AQ^-.eܷL{|GUhbk kvǎ=qN3>{% r? K!qb4ph8?X-* AUxeEMPq1/犈1}vPD8m̮<'A5Ҁ-T', 'REPLACE', 'REVERSE', 'RIGHT', 'ROUND', 'ROW_COUNT', 'RPAD', 'RTRIM', 'SCHEMA', 'SECOND', 'SEC_TO_TIME', 'SESSION_USER', 'SHA', 'SHA1', 'SIGN', 'SIN', 'SLEEP', 'SOUNDEX', 'SPACE', 'SQRT', 'SRID', 'STARTPOINT', 'STD', 'STDDEV', 'STDDEV_POP', 'STDDEV_SAMP', 'STRCMP', 'STR_TO_DATE', 'SUBDATE', 'SUBSTR', 'SUBSTRING', 'SUBSTRING_INDEX', 'SUBTIME', 'SUM', 'SYMDIFFERENCE', 'SYSDATE', 'SYSTEM_USER', 'TAN', 'TIME', 'TIMEDIFF', 'TIMESTAMP', 'TIMESTAMPADD', 'TIMESTAMPDIFF', 'TIME_FORMAT', 'TIME_TO_SEC', 'TOUCHES', 'TO_DAYS', 'TRIM', 'TRUNCATE', 'UCASE', 'UNCOMPRESS', 'UNCOMPRESSED_LENGTH', 'UNHEX', 'UNIQUE_USERS', 'UNIX_TIMESTAMP', 'UPDATEXML', 'UPPER', 'USER', 'UTC_DATE', 'UTC_TIME', 'UTC_TIMESTAMP', 'UUID', 'VARIANCE', 'VAR_POP', 'VAR_SAMP', 'VERSION', 'WEEK', 'WEEKDAY', 'WEEKOFYEAR', 'WITHIN', 'X', 'Y', 'YEAR', 'YEARWEEK' ); // Punctuation that can be used as a boundary between other tokens protected static $boundaries = array(',', ';',':', ')', '(', '.', '=', '<', '>', '+', '-', '*', '/', '!', '^', '%', '|', '&', '#'); // For HTML syntax highlighting // Styles applied to different token types public static $quote_attributes = 'style="color: blue;"'; public static $backtick_quote_attributes = 'style="color: purple;"'; public static $reserved_attributes = 'style="font-weight:bold;"'; public static $boundary_attributes = ''; public static $number_attributes = 'style="color: green;"'; public static $word_attributes = 'style="color: #333;"'; public static $error_attributes = 'style="background-color: red;"'; public static $comment_attributes = 'style="color: #aaa;"'; public static $variable_attributes = 'style="color: orange;"'; public static $pre_attributes = 'style="color: black; background-color: white;"'; // Boolean - whether or not the current environment is the CLI // This affects the type of syntax highlighting // If not defined, it will be determined automatically public static $cli; // For CLI syntax highlighting public static $cli_quote = "\x1b[34;1m"; public static $cli_backtick_quote = "\x1b[35;1m"; public static $cli_reserved = "\x1b[37m"; public static $cli_boundary = ""; public static $cli_number = "\x1b[32;1m"; public static $cli_word = ""; public static $cli_error = "\x1b[31;1;7m"; public static $cli_comment = "\x1b[30;1m"; public static $cli_functions = "\x1b[37m"; public static $cli_variable = "\x1b[36;1m"; // The tab character to use when formatting SQL public static $tab = ' '; // This flag tells us if queries need to be enclosed in
 tags
    public static $use_pre = true;

    // This flag tells us if SqlFormatted has been initialized
    protected static $init;

    // Regular expressions for tokenizing
    protected static $regex_boundaries;
    protected static $regex_reserved;
    protected static $regex_reserved_newline;
    protected static $regex_reserved_toplevel;
    protected static $regex_function;

    // Cache variables
    // Only tokens shorter than this size will be cached.  Somewhere between 10 and 20 seems to work well for most cases.
    public static $max_cachekey_size = 15;
    protected static $token_cache = array();
    protected static $cache_hits = 0;
    protected static $cache_misses = 0;

    /**
     * Get stats about the token cache
     * @return Array An array containing the keys 'hits', 'misses', 'entries', and 'size' in bytes
     */
    public static function getCacheStats()
    {
        return array(
            'hits'=>self::$cache_hits,
            'misses'=>self::$cache_misses,
            'entries'=>count(self::$token_cache),
            'size'=>strlen(serialize(self::$token_cache))
        );
    }

    /**
     * Stuff that only needs to be done once.  Builds regular expressions and sorts the reserved words.
     */
    protected static function init()
    {
        if (self::$init) return;

        // Sort reserved word list from longest word to shortest, 3x faster than usort
        $reservedMap = array_combine(self::$reserved, array_map('strlen', self::$reserved));
        arsort($reservedMap);
        self::$reserved = array_keys($reservedMap);

        // Set up regular expressions
        self::$regex_boundaries = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$boundaries)).')';
        self::$regex_reserved = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved)).')';
        self::$regex_reserved_toplevel = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_toplevel)).')');
        self::$regex_reserved_newline = str_replace(' ','\\s+','('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$reserved_newline)).')');

        self::$regex_function = '('.implode('|',array_map(array(__CLASS__, 'quote_regex'),self::$functions)).')';

        self::$init = true;
    }

    /**
     * Return the next token and token type in a SQL string.
     * Quoted strings, comments, reserved words, whitespace, and punctuation are all their own tokens.
     *
     * @param String $string   The SQL string
     * @param array  $previous The result of the previous getNextToken() call
     *
     * @return Array An associative array containing the type and value of the token.
     */
    protected static function getNextToken($string, $previous = null)
    {
        // Whitespace
        if (preg_match('/^\s+/',$string,$matches)) {
            return array(
                self::TOKEN_VALUE => $matches[0],
                self::TOKEN_TYPE=>self::TOKEN_TYPE_WHITESPACE
            );
        }

        // Comment
        if ($string[0] === '#' || (isset($string[1])&&($string[0]==='-'&&$string[1]==='-') || ($string[0]==='/'&&$string[1]==='*'))) {
            // Comment until end of line
            if ($string[0] === '-' || $string[0] === '#') {
                $last = strpos($string, "\n");
                $type = self::TOKEN_TYPE_COMMENT;
            } else { // Comment until closing comment tag
                $last = strpos($string, "*/", 2) + 2;
                $type = self::TOKEN_TYPE_BLOCK_COMMENT;
            }

            if ($last === false) {
                $last = strlen($string);
            }

            return array(
                self::TOKEN_VALUE => substr($string, 0, $last),
                self::TOKEN_TYPE  => $type
            );
        }

        // Quoted String
        if ($string[0]==='"' || $string[0]==='\'' || $string[0]==='`') {
            $return = array(
                self::TOKEN_TYPE => ($string[0]==='`'? self::TOKEN_TYPE_BACKTICK_QUOTE : self::TOKEN_TYPE_QUOTE),
                self::TOKEN_VALUE => self::getQuotedString($string)
            );

            return $return;
        }

        // User-defined Variable
        if ($string[0] === '@' && isset($string[1])) {
            $ret = array(
                self::TOKEN_VALUE => null,
                self::TOKEN_TYPE => self::TOKEN_TYPE_VARIABLE
            );
            
            // If the variable name is quoted
            if ($string[1]==='"' || $string[1]==='\'' || $string[1]==='`') {
                $ret[self::TOKEN_VALUE] = '@'.self::getQuotedString(substr($string,1));
            }
            // Non-quoted variable name
            else {
                preg_match('/^(@[a-zA-Z0-9\._\$]+)/',$string,$matches);
                if ($matches) {
                    $ret[self::TOKEN_VALUE] = $matches[1];
                }
            }
            
            if($ret[self::TOKEN_VALUE] !== null) return $ret;
        }

        // Number (decimal, binary, or hex)
        if (preg_match('/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|'.self::$regex_boundaries.')/',$string,$matches)) {
            return array(
                self::TOKEN_VALUE => $matches[1],
                self::TOKEN_TYPE=>self::TOKEN_TYPE_NUMBER
            );
        }

        // Boundary Character (punctuation and symbols)
        if (preg_match('/^('.self::$regex_boundaries.')/',$string,$matches)) {
            return array(
                self::TO::p]X"˄k46fN5&B|s^15/QpEdTEKVo3V8Z(dsWg2/oK}1OyVG4\4[P6TJ[h+{gZx DsYU >Skw܅
'US4v
	TAN9MJzPbHmObkSIݘ:®کXZWΏDk1aF_qu5`HO?B"`I{(J)2{GI3E
xY 8^D)A$kamy5EFx+"ml̇*\KǪlP7:פNE#pml+fO^Bl/~3'ZB&`4%ᅘ*;;)lӆX	ma(
JUL}qӫ?h9idVSB5iF7_e
`E`ߝ\Xy{ն)@_
!]^iC\"[ᘃiDaN9Lf4Kygb8T$tV6c{y]8zy'JfCi{n03ۑJxe'	jpģ5HwImI' ]Z)n*{VL9)`%W~t9^~RT
D]	6rQc;s'7ZLGn'5Lf>`ѝvނ=HX#]IEǑQIAY5B}|4nS,{9Og zj0Ca6xMb߉ަCy_.nx]
`ѺxYdZޱF^nΔ潝Q񡤠Y33rF<#)O`U9SoƄ!e\]ά6@}|/Wh;ߟa>Ҵ,LY3!GXL]e/Hom8;eR6v/(@2'SyxY\V0tXx_;gd7Hª_JG\}Uß
ܸmguSUR񙵝~k?OѮ$*Lsn>fDT1ͯWِJ)Ck,,v*pxGe*
Ѥ"+<]*Vn>-J6'ݚEKr!Olh2u
,J{2/5mP[_]'ٺ#	[vP:ۛ2]4Fj5cىgB
\9-Gͪޘ9b@!assv(sdi!yD]Pm\˳r
(=UꠏJsjy;Q, ogjD0";_CnyEл3wjM7z&05$[$Vy6JfH3 ZEQ\ޡR+q
t0~wՈ/ާxs~)H,U9"|y)5>)T(^uZAM(k#XQ|	Yo/ҿ$wew*ku@3t<ʝ6kvtzbUyoS8M+mt#^	|W(mᓒ|>[{p,Nz"i@H;J]+K,Db	ws%L?C{'-?r5^?r3ꎭ:?[km_o4;BGj%y]0E&<_q2w5vrGX`WF<篬e\+k;:gkuzYEZS=
WƲR.mĺVS<[KaNW}a J9s+zv͙N	3Ѻ;a
.qh),r}уǘinPrkAH؀Mz*`;Lǔ)tt0.kGw*3)qe~TV-
60`6(+6:G48%e:/sDA ob6Iy5cpdl%?1!FfrK={G\'>5gzs0nz\Q$ga@47ev堸6kNrܪد(CqPn8*
k8eߦk#ڇc}oL]YL1_ABJN`#EeA8R2AQb`~E	)>,hzT̄XRC+GBHV N ?]AjBv?sa)WU#Rr$h@(qpb5lyɣ~^cqyˈ8ر'{Ɉp{S]iyo"Ž٘U6pu!A%}҆gŝ"œɊ|e̘[;^7[o?1Qf޹lQOřS`+MaB`s%Wœ+0PHJ/ 0xؚgvw/+"CWctJߗ. HʏY<>(S_f#j8oS0|ic}88Qi+v#J^3;H+T!(]M!y+u"-WU6/]Lvn^#ֹ
nF8.v:38sy~FFG1ZKe9ɲiDȃYf[krR6	Oh^#]X>~rXlX?lkyL4D$	y[-Ad/(epFeV7EyQ)gSgN0Uk#Jv2iH*iҵNu/oxq#J	j
^Ы/-8	!v@,jaś90dCc(pRgx#K"T\8Y8;'{LµT?+CˢU6vC㒄K_6d-Ox
YS
3lm&$"=B!AIUL 0nM	(>l#W93Ȉa>|ZƟln.<vfnf2kX9:9U-'+VX<ܕlS>fz48c/ddϴ%b)R 
k`cxbxfvgQNxЭǦv97-ʐAm2PMeA&DQOz5Y?{n)i(G!ǔ^'ݿN03T(ѺcĎ-#T܁<]K`'+ŮuS ZOG@7o'`ޥjVQ.JyCkdw@V;,)#8F:KAfCws*B/˰r4妄NR*o2Iz'6ܴ0q
݅	Kݿ7{̏8'.gX(`Nﮒ-@PXwDv*f1qg CGz QJ*
'nba3PB!?a~};=νs$}UG+Dl4o_Wը@zU
LnS$8{=p
LKqXJבQf/O)Fb
;OT^a+Fa}%K$9&f5C8ҵGI߲R
70ZAMT@j!0ZEmv0_auF4#\$pBwp^xޝ\jHYC9fl\,t.,.C0HbLųJ#QhiUeP0֬m=KRo3gz#Gy"o%:*|J`gybt;i9)C;h`B'
EzJ48[i|]>L)^4NzQxHZü@QN`n}!k/~?cd`%]f~AʞaL~>lgzm4^PpT(U
mWg.sw]$|~C'k`X{ELCNk,Y;rr,2PrJ'dexhP>
%-O+6BUH$hb(
JpJz֡nd)]bdFz,E'g)EPԇd"n|WBAԩsNk>R)B cMܯ*	862%At )ڃs]5_Dqꊻ[cr*BYj?O#%lW_${'`ś6ŵ	ˬ*1,h+D\MTj8z7zaX7(:kdOU+!zAk.
C/jV;qh6kH9@c;L= 30) {
                        $inline_count = 0;
                        $newline = true;
                    }
                }

                $inline_count += strlen($token[self::TOKEN_VALUE]);
            }

            // Opening parentheses increase the block indent level and start a new line
            if ($token[self::TOKEN_VALUE] === '(') {
                // First check if this should be an inline parentheses block
                // Examples are "NOW()", "COUNT(*)", "int(10)", key(`somecolumn`), DECIMAL(7,2)
                // Allow up to 3 non-whitespace tokens inside inline parentheses
                $length = 0;
                for ($j=1;$j<=250;$j++) {
                    // Reached end of string
                    if (!isset($tokens[$i+$j])) break;

                    $next = $tokens[$i+$j];

                    // Reached closing parentheses, able to inline it
                    if ($next[self::TOKEN_VALUE] === ')') {
                        $inline_parentheses = true;
                        $inline_count = 0;
                        $inline_indented = false;
                        break;
                    }

                    // Reached an invalid token for inline parentheses
                    if ($next[self::TOKEN_VALUE]===';' || $next[self::TOKEN_VALUE]==='(') {
                        break;
                    }

                    // Reached an invalid token type for inline parentheses
                    if ($next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_TOPLEVEL || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_RESERVED_NEWLINE || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_COMMENT || $next[self::TOKEN_TYPE]===self::TOKEN_TYPE_BLOCK_COMMENT) {
                        break;
                    }

                    $length += strlen($next[self::TOKEN_VALUE]);
                }

                if ($inline_parentheses && $length > 30) {
                    $increase_block_indent = true;
                    $inline_indented = true;
                    $newline = true;
                }

                // Take out the preceding space unless there was whitespace there in the original query
                if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
                    $return = rtrim($return,' ');
                }

                if (!$inline_parentheses) {
                    $increase_block_indent = true;
                    // Add a newline after the parentheses
                    $newline = true;
                }

            }

            // Closing parentheses decrease the block indent level
            elseif ($token[self::TOKEN_VALUE] === ')') {
                // Remove whitespace before the closing parentheses
                $return = rtrim($return,' ');

                $indent_level--;

                // Reset indent level
                while ($j=array_shift($indent_types)) {
                    if ($j==='special') {
                        $indent_level--;
                    } else {
                        break;
                    }
                }

                if ($indent_level < 0) {
                    // This is an error
                    $indent_level = 0;

                    if ($highlight) {
                        $return .= "\n".self::highlightError($token[self::TOKEN_VALUE]);
                        continue;
                    }
                }

                // Add a newline before the closing parentheses (if not already added)
                if (!$added_newline) {
                    $return .= "\n" . str_repeat($tab, $indent_level);
                }
            }

            // Top level reserved words start a new line and increase the special indent level
            elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_TOPLEVEL) {
                $increase_special_indent = true;

                // If the last indent type was 'special', decrease the special indent for this round
                reset($indent_types);
                if (current($indent_types)==='special') {
                    $indent_level--;
                    array_shift($indent_types);
                }

                // Add a newline after the top level reserved word
                $newline = true;
                // Add a newline before the top level reserved word (if not already added)
                if (!$added_newline) {
                    $return .= "\n" . str_repeat($tab, $indent_level);
                }
                // If we already added a newline, redo the indentation since it may be different now
                else {
                    $return = rtrim($return,$tab).str_repeat($tab, $indent_level);
                }

                // If the token may have extra whitespace
                if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
                    $highlighted = preg_replace('/\s+/',' ',$highlighted);
                }
                //if SQL 'LIMIT' clause, start variable to reset newline
                if ($token[self::TOKEN_VALUE] === 'LIMIT' && !$inline_parentheses) {
                    $clause_limit = true;
                }
            }

            // Checks if we are out of the limit clause
            elseif ($clause_limit && $token[self::TOKEN_VALUE] !== "," && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_NUMBER && $token[self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
                $clause_limit = false;
            }

            // Commas start a new line (unless within inline parentheses or SQL 'LIMIT' clause)
            elseif ($token[self::TOKEN_VALUE] === ',' && !$inline_parentheses) {
                //If the previous TOKEN_VALUE is 'LIMIT', resets new line
                if ($clause_limit === true) {
                    $newline = false;
                    $clause_limit = false;
                }
                // All other cases of commas
                else {
                    $newline = true;
                }
            }

            // Newline reserved words start a new line
            elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_RESERVED_NEWLINE) {
                // Add a newline before the reserved word (if not already added)
                if (!$added_newline) {
                    $return .= "\n" . str_repeat($tab, $indent_level);
                }

                // If the token may have extra whitespace
                if (strpos($token[self::TOKEN_VALUE],' ')!==false || strpos($token[self::TOKEN_VALUE],"\n")!==false || strpos($token[self::TOKEN_VALUE],"\t")!==false) {
                    $highlighted = preg_replace('/\s+/',' ',$highlighted);
                }
            }

            // Multiple boundary characters in a row should not have spaces between them (not including parentheses)
            elseif ($token[self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
                if (isset($tokens[$i-1]) && $tokens[$i-1][self::TOKEN_TYPE] === self::TOKEN_TYPE_BOUNDARY) {
                    if (isset($original_tokens[$token['i']-1]) && $original_tokens[$token['i']-1][self::TOKEN_TYPE] !== self::TOKEN_TYPE_WHITESPACE) {
                        $return = rtrim($return,' ');
                    }
                }
            }

      RU~"oUOl7Qu%EF`d]1dtirse>)[WvM
),Ib$B_T£$.t3h]:}bG?ZAsi5N/F<͑;ºoYPv~oH;hNVNPk1nIY*˥M_9cnC-_On^1?Y̞w'xHh5E,̅i,b2w^^=p6acR	IS8í0++X.s>,
zB]!	Cp0M20y9j
qPEAx,-PD|ɷ)4Ka5hM*q$Vo%EDDV=k\GBqHfo3aꅖ=}~HtIQ^#2^\+--,{d}ha!IԂ`+DsB:ٵ2r UD
vsyg[t'4bި7|RUFΒSh#3df6Oyd&1xSyQp(rvI]=>RMnяG)#y$'R
~e29,ҭTۋ,R"oZ@.ۦA8k6$̷}K~9HjxsKSYmPOXCNAcsފ2̑i[[yr)d(gqy46_E)LLKC
jP/8;xIAo^=cӏ#pca%C6qc||R{:%l㌣u,\}'Pa\\^i7)_+UYIz{YRiAk2Y&>BJқ<>8XzQ!|uC$a(>+]S&m%=.*$1:&l7׈h%d֋&'K!xx.gEHjHC&2|
AԚ(D71-4F&	L,q*Y-hysm}MFE
{@Dq
B)_sEx~x%fzil̈Żef	u>R #u<^*v.gTFkN]X<8#`/Cg-ɏ8g\.{Ǥ>*bL3'
Hw]˩:P*F"דgڢ#x#epFtfTH0V=y|$vylO{SU#ݮcyIsL9]N)=rMYNlG{QkſqHU,g9Eg r~HTxFJe,1잗'޺F*YP6n
:o+W5
&S8|_|j48?QRXwv6J\˅R6	tEi@JbC/OKS)u$:-@td)P$@myrM^ƶ~|;P~Z-#|x[!`OmR1Kc	JQ0VH{-݊#.nu.M1(>3$trT:yEB=?Oc&i3w-^&;`@J\:a9,K5!MDi1?$İ$Kq]/kTG^u
B?9MgM%~Cb1QLu	Ǹ/FpLt'\h-IF/p:H VӼ2YZngۈ7+G&Y}@
'{a^[mU1ۜbV>HS7]fڽX F%23ulRO'p
co]Gx4D{::X]+d9{~owu1p3(h
⸀Qd\_oچkOEqB4YZEzN2g{F$i4HB嘜ږt{E{gGNZ]8A(X,Ӷ,.r;dOEQX@bP@4^?)Ob,ԍr(04FA=~K˔C	Lq1.D.Fu--k\]'TQkrkB88
zoK>^d.jdsy{W{a3вJBofNTg(^K\`E|ggn	jQ2IpdvlTȵwG9EX<'4
HXUoFcd{MM]@)F:7itB4jJ$ۚd~^$W{0CJT/rMk'<úLa
k	^RՔE7@xx4zbȍIp̭BG$i'贋0'xs̛
nq%( Y*7P`ϰfh۩KZq:E;w͝d.+q"miWfr Y/VkJ7pPbb.CiEQvFؐ^_MAn31 Uh]V*j/5-΢!eb_.ACk(Ah}䊸=ԼPlIikRrs^oGitՖ)0#^l_Tczr3>WOe8ls̥K2tF 	V
|	B
жTEdTL"weD#
:2q:m1'7D'^Ɨ`?k?Eޱ5=Q٠sjY/01>:X6,]d!?9sqzMs_lyLy{ZE慚EU*1#[d2;HkVN)6#~Wn?ȐY[W˯F<=n[ytrk$w*d3j])E򼷞
iݤ6|(]qxpED{da`S܂7]0!
34žKpE]s:H6tv!Y:p/BoŤ,#gt>{pظ%xG)?|}+,%(dDK쓫Nm+3EWBXt OH?vїo|yg܄<5KȞ'
	iBФ`Rh
4E''0oU TQ8VB)[*%WIu"c>5/40(0'0⯩2avR^=݀LL[9,argا4,!Cp&83noJu^uJ"wn-#wvu:mqƔ|'4Wtu)U3t{(+mto/!u[Q48ʌ&*ti
5t7%)!QSu{61AsPH+AK:Jcj;\5^ؗy܈lzH_1h8ʩ,3s_XVd$$mSċg.!~W/GTC*f9tCW'9cDCCd6]w<|Pwİ8ƚF2	2ڑeT&rbfQ撖PfiER\Pxi}62i	Oy+ûvrOLآ+~7
]wq.̟!	5q%&Rlx~-gh
Fw<":QN$ßָ6:\ 5C;EX#d5
S:Ϯ6oڎn TvPnUr;.^FΧyM:^M.7zzAgNylU=}d0FO4Ggl8O,`̘wIHJwOs }gз#hgƬ'
+p?!4-Dk]YXf\?OGֻVsyb?n˧#!2`1kPH"K`7/gJ%
؇)
	|jHaa9i
N%SI6Ssjub@W#Oe};pq8+0+
Y1C
|Ngo%ET5C/v#~&[dI*XNP7>H6dnO(MLo!qZcaW0x\Idx{*[1VCca10+X
gjVtܣ+HZDky0ߣY&Y?5h-}&A]x{`c`˩wxDZTP6̇=:' . $value . '';
        }
    }

    /**
     * Highlights a boundary token
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightBoundary($value)
    {
        if ($value==='(' || $value===')') return $value;

        if (self::is_cli()) {
            return self::$cli_boundary . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Highlights a number
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightNumber($value)
    {
        if (self::is_cli()) {
            return self::$cli_number . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Highlights an error
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightError($value)
    {
        if (self::is_cli()) {
            return self::$cli_error . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Highlights a comment
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightComment($value)
    {
        if (self::is_cli()) {
            return self::$cli_comment . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Highlights a word token
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightWord($value)
    {
        if (self::is_cli()) {
            return self::$cli_word . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Highlights a variable token
     *
     * @param String $value The token's value
     *
     * @return String HTML code of the highlighted token.
     */
    protected static function highlightVariable($value)
    {
        if (self::is_cli()) {
            return self::$cli_variable . $value . "\x1b[0m";
        } else {
            return '' . $value . '';
        }
    }

    /**
     * Helper function for building regular expressions for reserved words and boundary characters
     *
     * @param String $a The string to be quoted
     *
     * @return String The quoted string
     */
    private static function quote_regex($a)
    {
        return preg_quote($a,'/');
    }

    /**
     * Helper function for building string output
     *
     * @param String $string The string to be quoted
     *
     * @return String The quoted string
     */
    private static function output($string)
    {
        if (self::is_cli()) {
            return $string."\n";
        } else {
            $string=trim($string);
            if (!self::$use_pre) {
                return $string;
            }

            return '
' . $string . '
'; } } private static function is_cli() { if (isset(self::$cli)) return self::$cli; else return php_sapi_name() === 'cli'; } } # 6v[<';_:FJʸeL3|V(wPw4ɇﵔkFrIxPc1_[W4b] G(RK =p&c ~i{ ] $kJwQ}5DqmuCtǰww]4R8zjdB?JnDbvmdL|s}x,l&wBGKR"Q`gjkH8mW`ݯPK#L)9k,Pij'|q]Q#(NpJa01>ͳ>KQ}tK%Dm^as.<Z?$K .#>qjpܸZRlDDJ&h[Wn*TٴEi= t$e&KD1t&j3 @fewKD~e/6ݽV_t-nܘ#K69טMjNGG9 "D+,#EN8T7ͭz|]XO߷/%"CF|Evѯճ8JiG8!Gl0чI˞HewHn,8Zv6 Ggv:<mL8e(>nTu W^dXK]ˬ1xb&,j>o#Lܞh??iAxfwӘk?VC62^;yˁOxD? ‚mSwbbZʍU)67\xA9E6L.P^nSjj䙛^hhPWOWy)+~Y _ a|;ę ۳~jCz|.9Ber,?Ɓbv\^BvmTԔ-43vahöd:0.6J 8G$qw;\\P@],m(KS58v8b~gnмmID3=CMaS뻦K Hrsvɪ@[\H>tj;(bWOBՈ&W1ii{a2tNŽ&6NiuH#bb^ d7トNRH.SqvDαg;1YDӕzaCP÷NLX_'x8wЅjE 洄)/A{y*'ZO yae >;yr48 #Fs)*xג@5Zv]ypMOt. i4'u{K[Wieէ;q/x}AadbjqAH*&uC벺R|#~)t!z($H(