Source for file less.php

Documentation is available at less.php

  1. <?php
  2. /**
  3.  * @package     FrameworkOnFramework
  4.  * @subpackage  less
  5.  * @copyright   Copyright (C) 2010 - 2012 Akeeba Ltd. All rights reserved.
  6.  * @license     GNU General Public License version 2 or later; see LICENSE.txt
  7.  */
  8. // Protect from unauthorized access
  9. defined('_JEXEC'or die;
  10.  
  11. /**
  12.  * This class is taken near verbatim (changes marked with **FOF** comment markers) from:
  13.  *
  14.  * lessphp v0.3.9
  15.  * http://leafo.net/lessphp
  16.  *
  17.  * LESS css compiler, adapted from http://lesscss.org
  18.  *
  19.  * Copyright 2012, Leaf Corcoran <leafot@gmail.com>
  20.  * Licensed under MIT or GPLv3, see LICENSE
  21.  *
  22.  * THIS IS THIRD PARTY CODE. Code comments are mostly useless placeholders to
  23.  * stop phpcs from complaining...
  24.  *
  25.  * @package  FrameworkOnFramework
  26.  * @since    2.0
  27.  */
  28. class FOFLess
  29. {
  30.     public static $VERSION "v0.3.9";
  31.  
  32.     protected static $TRUE array("keyword""true");
  33.  
  34.     protected static $FALSE array("keyword""false");
  35.  
  36.     protected $libFunctions = array();
  37.  
  38.     protected $registeredVars = array();
  39.  
  40.     protected $preserveComments = false;
  41.  
  42.     /**
  43.      * Prefix of abstract properties
  44.      *
  45.      * @var  string 
  46.      */
  47.     public $vPrefix = '@';
  48.  
  49.     /**
  50.      * Prefix of abstract blocks
  51.      *
  52.      * @var  string 
  53.      */
  54.     public $mPrefix = '$';
  55.  
  56.     public $parentSelector = '&';
  57.  
  58.     public $importDisabled = false;
  59.  
  60.     public $importDir = '';
  61.  
  62.     protected $numberPrecision = null;
  63.  
  64.     /**
  65.      * Set to the parser that generated the current line when compiling
  66.      * so we know how to create error messages
  67.      *
  68.      * @var  FOFLessParser 
  69.      */
  70.     protected $sourceParser = null;
  71.  
  72.     protected $sourceLoc = null;
  73.  
  74.     public static $defaultValue array("keyword""");
  75.  
  76.     /**
  77.      * Uniquely identify imports
  78.      *
  79.      * @var  integer 
  80.      */
  81.     protected static $nextImportId 0;
  82.  
  83.     /**
  84.      * Attempts to find the path of an import url, returns null for css files
  85.      *
  86.      * @param   string  $url  The URL of the import
  87.      *
  88.      * @return  string|null
  89.      */
  90.     protected function findImport($url)
  91.     {
  92.         foreach ((array) $this->importDir as $dir)
  93.         {
  94.             $full $dir (substr($dir-1!= '/' '/' ''$url;
  95.  
  96.             if ($this->fileExists($file $full '.less'|| $this->fileExists($file $full))
  97.             {
  98.                 return $file;
  99.             }
  100.         }
  101.  
  102.         return null;
  103.     }
  104.  
  105.     /**
  106.      * Does file $name exists? It's a simple proxy to JFile for now
  107.      *
  108.      * @param   string  $name  The file we check for existence
  109.      *
  110.      * @return  boolean 
  111.      */
  112.     protected function fileExists($name)
  113.     {
  114.         /** FOF - BEGIN CHANGE * */
  115.         JLoader::import('joomla.filesystem.file');
  116.  
  117.         return JFile::exists($name);
  118.         /** FOF - END CHANGE * */
  119.     }
  120.  
  121.     /**
  122.      * Compresslist
  123.      *
  124.      * @param   array   $items  Items
  125.      * @param   string  $delim  Delimiter
  126.      *
  127.      * @return  array 
  128.      */
  129.     public static function compressList($items$delim)
  130.     {
  131.         if (!isset($items[1]&& isset($items[0]))
  132.         {
  133.             return $items[0];
  134.         }
  135.         else
  136.         {
  137.             return array('list'$delim$items);
  138.         }
  139.     }
  140.  
  141.     /**
  142.      * Quote for regular expression
  143.      *
  144.      * @param   string  $what  What to quote
  145.      *
  146.      * @return  string  Quoted string
  147.      */
  148.     public static function preg_quote($what)
  149.     {
  150.         return preg_quote($what'/');
  151.     }
  152.  
  153.     /**
  154.      * Try import
  155.      *
  156.      * @param   string     $importPath   Import path
  157.      * @param   stdObject  $parentBlock  Parent block
  158.      * @param   string     $out          Out
  159.      *
  160.      * @return  boolean 
  161.      */
  162.     protected function tryImport($importPath$parentBlock$out)
  163.     {
  164.         if ($importPath[0== "function" && $importPath[1== "url")
  165.         {
  166.             $importPath $this->flattenList($importPath[2]);
  167.         }
  168.  
  169.         $str $this->coerceString($importPath);
  170.  
  171.         if ($str === null)
  172.         {
  173.             return false;
  174.         }
  175.  
  176.         $url $this->compileValue($this->lib_e($str));
  177.  
  178.         // Don't import if it ends in css
  179.         if (substr_compare($url'.css'-44=== 0)
  180.         {
  181.             return false;
  182.         }
  183.  
  184.         $realPath $this->findImport($url);
  185.  
  186.         if ($realPath === null)
  187.         {
  188.             return false;
  189.         }
  190.  
  191.         if ($this->importDisabled)
  192.         {
  193.             return array(false"/* import disabled */");
  194.         }
  195.  
  196.         $this->addParsedFile($realPath);
  197.         $parser $this->makeParser($realPath);
  198.         $root $parser->parse(file_get_contents($realPath));
  199.  
  200.         // Set the parents of all the block props
  201.         foreach ($root->props as $prop)
  202.         {
  203.             if ($prop[0== "block")
  204.             {
  205.                 $prop[1]->parent $parentBlock;
  206.             }
  207.         }
  208.  
  209.         /**
  210.          * Copy mixins into scope, set their parents, bring blocks from import
  211.          * into current block
  212.          * TODO: need to mark the source parser    these came from this file
  213.          */
  214.         foreach ($root->children as $childName => $child)
  215.         {
  216.             if (isset($parentBlock->children[$childName]))
  217.             {
  218.                 $parentBlock->children[$childNamearray_merge(
  219.                     $parentBlock->children[$childName]$child
  220.                 );
  221.             }
  222.             else
  223.             {
  224.                 $parentBlock->children[$childName$child;
  225.             }
  226.         }
  227.  
  228.         $pi pathinfo($realPath);
  229.         $dir $pi["dirname"];
  230.  
  231.         list($top$bottom$this->sortProps($root->propstrue);
  232.         $this->compileImportedProps($top$parentBlock$out$parser$dir);
  233.  
  234.         return array(true$bottom$parser$dir);
  235.     }
  236.  
  237.     /**
  238.      * Compile Imported Props
  239.      *
  240.      * @param   array          $props         Props
  241.      * @param   stdClass       $block         Block
  242.      * @param   string         $out           Out
  243.      * @param   FOFLessParser  $sourceParser  Source parser
  244.      * @param   string         $importDir     Import dir
  245.      *
  246.      * @return  void 
  247.      */
  248.     protected function compileImportedProps($props$block$out$sourceParser$importDir)
  249.     {
  250.         $oldSourceParser $this->sourceParser;
  251.  
  252.         $oldImport $this->importDir;
  253.  
  254.         // TODO: this is because the importDir api is stupid
  255.         $this->importDir = (array) $this->importDir;
  256.         array_unshift($this->importDir$importDir);
  257.  
  258.         foreach ($props as $prop)
  259.         {
  260.             $this->compileProp($prop$block$out);
  261.         }
  262.  
  263.         $this->importDir = $oldImport;
  264.         $this->sourceParser = $oldSourceParser;
  265.     }
  266.  
  267.     /**
  268.      * Recursively compiles a block.
  269.      *
  270.      * A block is analogous to a CSS block in most cases. A single LESS document
  271.      * is encapsulated in a block when parsed, but it does not have parent tags
  272.      * so all of it's children appear on the root level when compiled.
  273.      *
  274.      * Blocks are made up of props and children.
  275.      *
  276.      * Props are property instructions, array tuples which describe an action
  277.      * to be taken, eg. write a property, set a variable, mixin a block.
  278.      *
  279.      * The children of a block are just all the blocks that are defined within.
  280.      * This is used to look up mixins when performing a mixin.
  281.      *
  282.      * Compiling the block involves pushing a fresh environment on the stack,
  283.      * and iterating through the props, compiling each one.
  284.      *
  285.      * @param   stdClass  $block  Block
  286.      *
  287.      * @see  FOFLess::compileProp()
  288.      *
  289.      * @return  void 
  290.      */
  291.     protected function compileBlock($block)
  292.     {
  293.         switch ($block->type)
  294.         {
  295.             case "root":
  296.                 $this->compileRoot($block);
  297.                 break;
  298.             case null:
  299.                 $this->compileCSSBlock($block);
  300.                 break;
  301.             case "media":
  302.                 $this->compileMedia($block);
  303.                 break;
  304.             case "directive":
  305.                 $name "@" $block->name;
  306.  
  307.                 if (!empty($block->value))
  308.                 {
  309.                     $name .= " " $this->compileValue($this->reduce($block->value));
  310.                 }
  311.  
  312.                 $this->compileNestedBlock($blockarray($name));
  313.                 break;
  314.             default:
  315.                 $this->throwError("unknown block type: $block->type\n");
  316.         }
  317.     }
  318.  
  319.     /**
  320.      * Compile CSS block
  321.      *
  322.      * @param   stdClass  $block  Block to compile
  323.      *
  324.      * @return  void 
  325.      */
  326.     protected function compileCSSBlock($block)
  327.     {
  328.         $env $this->pushEnv();
  329.  
  330.         $selectors $this->compileSelectors($block->tags);
  331.         $env->selectors $this->multiplySelectors($selectors);
  332.         $out $this->makeOutputBlock(null$env->selectors);
  333.  
  334.         $this->scope->children[$out;
  335.         $this->compileProps($block$out);
  336.  
  337.         // Mixins carry scope with them!
  338.         $block->scope $env;
  339.         $this->popEnv();
  340.     }
  341.  
  342.     /**
  343.      * Compile media
  344.      *
  345.      * @param   stdClass  $media  Media
  346.      *
  347.      * @return  void 
  348.      */
  349.     protected function compileMedia($media)
  350.     {
  351.         $env $this->pushEnv($media);
  352.         $parentScope $this->mediaParent($this->scope);
  353.  
  354.         $query $this->compileMediaQuery($this->multiplyMedia($env));
  355.  
  356.         $this->scope $this->makeOutputBlock($media->typearray($query));
  357.         $parentScope->children[$this->scope;
  358.  
  359.         $this->compileProps($media$this->scope);
  360.  
  361.         if (count($this->scope->lines0)
  362.         {
  363.             $orphanSelelectors $this->findClosestSelectors();
  364.  
  365.             if (!is_null($orphanSelelectors))
  366.             {
  367.                 $orphan $this->makeOutputBlock(null$orphanSelelectors);
  368.                 $orphan->lines $this->scope->lines;
  369.                 array_unshift($this->scope->children$orphan);
  370.                 $this->scope->lines array();
  371.             }
  372.         }
  373.  
  374.         $this->scope $this->scope->parent;
  375.         $this->popEnv();
  376.     }
  377.  
  378.     /**
  379.      * Media parent
  380.      *
  381.      * @param   stdClass  $scope  Scope
  382.      *
  383.      * @return  stdClass 
  384.      */
  385.     protected function mediaParent($scope)
  386.     {
  387.         while (!empty($scope->parent))
  388.         {
  389.             if (!empty($scope->type&& $scope->type != "media")
  390.             {
  391.                 break;
  392.             }
  393.  
  394.             $scope $scope->parent;
  395.         }
  396.  
  397.         return $scope;
  398.     }
  399.  
  400.     /**
  401.      * Compile nested block
  402.      *
  403.      * @param   stdClass  $block      Block
  404.      * @param   array     $selectors  Selectors
  405.      *
  406.      * @return  void 
  407.      */
  408.     protected function compileNestedBlock($block$selectors)
  409.     {
  410.         $this->pushEnv($block);
  411.         $this->scope $this->makeOutputBlock($block->type$selectors);
  412.         $this->scope->parent->children[$this->scope;
  413.  
  414.         $this->compileProps($block$this->scope);
  415.  
  416.         $this->scope $this->scope->parent;
  417.         $this->popEnv();
  418.     }
  419.  
  420.     /**
  421.      * Compile root
  422.      *
  423.      * @param   stdClass  $root  Root
  424.      *
  425.      * @return  void 
  426.      */
  427.     protected function compileRoot($root)
  428.     {
  429.         $this->pushEnv();
  430.         $this->scope $this->makeOutputBlock($root->type);
  431.         $this->compileProps($root$this->scope);
  432.         $this->popEnv();
  433.     }
  434.  
  435.     /**
  436.      * Compile props
  437.      *
  438.      * @param   type  $block  Something
  439.      * @param   type  $out    Something
  440.      *
  441.      * @return  void 
  442.      */
  443.     protected function compileProps($block$out)
  444.     {
  445.         foreach ($this->sortProps($block->propsas $prop)
  446.         {
  447.             $this->compileProp($prop$block$out);
  448.         }
  449.     }
  450.  
  451.     /**
  452.      * Sort props
  453.      *
  454.      * @param   type  $props  X
  455.      * @param   type  $split  X
  456.      *
  457.      * @return  type 
  458.      */
  459.     protected function sortProps($props$split false)
  460.     {
  461.         $vars    array();
  462.         $imports array();
  463.         $other   array();
  464.  
  465.         foreach ($props as $prop)
  466.         {
  467.             switch ($prop[0])
  468.             {
  469.                 case "assign":
  470.                     if (isset($prop[1][0]&& $prop[1][0== $this->vPrefix)
  471.                     {
  472.                         $vars[$prop;
  473.                     }
  474.                     else
  475.                     {
  476.                         $other[$prop;
  477.                     }
  478.                     break;
  479.                 case "import":
  480.                     $id        self::$nextImportId++;
  481.                     $prop[]    $id;
  482.                     $imports[$prop;
  483.                     $other[]   array("import_mixin"$id);
  484.                     break;
  485.                 default:
  486.                     $other[$prop;
  487.             }
  488.         }
  489.  
  490.         if ($split)
  491.         {
  492.             return array(array_merge($vars$imports)$other);
  493.         }
  494.         else
  495.         {
  496.             return array_merge($vars$imports$other);
  497.         }
  498.     }
  499.  
  500.     /**
  501.      * Compile media query
  502.      *
  503.      * @param   type  $queries  Queries
  504.      *
  505.      * @return  string 
  506.      */
  507.     protected function compileMediaQuery($queries)
  508.     {
  509.         $compiledQueries array();
  510.  
  511.         foreach ($queries as $query)
  512.         {
  513.             $parts array();
  514.  
  515.             foreach ($query as $q)
  516.             {
  517.                 switch ($q[0])
  518.                 {
  519.                     case "mediaType":
  520.                         $parts[implode(" "array_slice($q1));
  521.                         break;
  522.                     case "mediaExp":
  523.                         if (isset($q[2]))
  524.                         {
  525.                             $parts["($q[1].
  526.                                 $this->compileValue($this->reduce($q[2])) ")";
  527.                         }
  528.                         else
  529.                         {
  530.                             $parts["($q[1])";
  531.                         }
  532.                         break;
  533.                     case "variable":
  534.                         $parts[$this->compileValue($this->reduce($q));
  535.                         break;
  536.                 }
  537.             }
  538.  
  539.             if (count($parts0)
  540.             {
  541.                 $compiledQueries[implode(" and "$parts);
  542.             }
  543.         }
  544.  
  545.         $out "@media";
  546.  
  547.         if (!empty($parts))
  548.         {
  549.             $out .= " " .
  550.                 implode($this->formatter->selectorSeparator$compiledQueries);
  551.         }
  552.  
  553.         return $out;
  554.     }
  555.  
  556.     /**
  557.      * Multiply media
  558.      *
  559.      * @param   type  $env           X
  560.      * @param   type  $childQueries  X
  561.      *
  562.      * @return  type 
  563.      */
  564.     protected function multiplyMedia($env$childQueries null)
  565.     {
  566.         if (is_null($env)
  567.             || !empty($env->block->type)
  568.             && $env->block->type != "media")
  569.         {
  570.             return $childQueries;
  571.         }
  572.  
  573.         // Plain old block, skip
  574.         if (empty($env->block->type))
  575.         {
  576.             return $this->multiplyMedia($env->parent$childQueries);
  577.         }
  578.  
  579.         $out array();
  580.         $queries $env->block->queries;
  581.  
  582.         if (is_null($childQueries))
  583.         {
  584.             $out $queries;
  585.         }
  586.         else
  587.         {
  588.             foreach ($queries as $parent)
  589.             {
  590.                 foreach ($childQueries as $child)
  591.                 {
  592.                     $out[array_merge($parent$child);
  593.                 }
  594.             }
  595.         }
  596.  
  597.         return $this->multiplyMedia($env->parent$out);
  598.     }
  599.  
  600.     /**
  601.      * Expand parent selectors
  602.      *
  603.      * @param   type  &$tag     Tag
  604.      * @param   type  $replace  Replace
  605.      *
  606.      * @return  type 
  607.      */
  608.     protected function expandParentSelectors(&$tag$replace)
  609.     {
  610.         $parts explode("$&$"$tag);
  611.         $count 0;
  612.  
  613.         foreach ($parts as &$part)
  614.         {
  615.             $part str_replace($this->parentSelector$replace$part$c);
  616.             $count += $c;
  617.         }
  618.  
  619.         $tag implode($this->parentSelector$parts);
  620.  
  621.         return $count;
  622.     }
  623.  
  624.     /**
  625.      * Find closest selectors
  626.      *
  627.      * @return  array 
  628.      */
  629.     protected function findClosestSelectors()
  630.     {
  631.         $env $this->env;
  632.         $selectors null;
  633.  
  634.         while ($env !== null)
  635.         {
  636.             if (isset($env->selectors))
  637.             {
  638.                 $selectors $env->selectors;
  639.                 break;
  640.             }
  641.  
  642.             $env $env->parent;
  643.         }
  644.  
  645.         return $selectors;
  646.     }
  647.  
  648.     /**
  649.      * Multiply $selectors against the nearest selectors in env
  650.      *
  651.      * @param   array  $selectors  The selectors
  652.      *
  653.      * @return  array 
  654.      */
  655.     protected function multiplySelectors($selectors)
  656.     {
  657.         // Find parent selectors
  658.  
  659.         $parentSelectors $this->findClosestSelectors();
  660.  
  661.         if (is_null($parentSelectors))
  662.         {
  663.             // Kill parent reference in top level selector
  664.             foreach ($selectors as &$s)
  665.             {
  666.                 $this->expandParentSelectors($s"");
  667.             }
  668.  
  669.             return $selectors;
  670.         }
  671.  
  672.         $out array();
  673.  
  674.         foreach ($parentSelectors as $parent)
  675.         {
  676.             foreach ($selectors as $child)
  677.             {
  678.                 $count $this->expandParentSelectors($child$parent);
  679.  
  680.                 // Don't prepend the parent tag if & was used
  681.                 if ($count 0)
  682.                 {
  683.                     $out[trim($child);
  684.                 }
  685.                 else
  686.                 {
  687.                     $out[trim($parent ' ' $child);
  688.                 }
  689.             }
  690.         }
  691.  
  692.         return $out;
  693.     }
  694.  
  695.     /**
  696.      * Reduces selector expressions
  697.      *
  698.      * @param   array  $selectors  The selector expressions
  699.      *
  700.      * @return  array 
  701.      */
  702.     protected function compileSelectors($selectors)
  703.     {
  704.         $out array();
  705.  
  706.         foreach ($selectors as $s)
  707.         {
  708.             if (is_array($s))
  709.             {
  710.                 list($value$s;
  711.                 $out[trim($this->compileValue($this->reduce($value)));
  712.             }
  713.             else
  714.             {
  715.                 $out[$s;
  716.             }
  717.         }
  718.  
  719.         return $out;
  720.     }
  721.  
  722.     /**
  723.      * Equality check
  724.      *
  725.      * @param   mixed  $left   Left operand
  726.      * @param   mixed  $right  Right operand
  727.      *
  728.      * @return  boolean  True if equal
  729.      */
  730.     protected function eq($left$right)
  731.     {
  732.         return $left == $right;
  733.     }
  734.  
  735.     /**
  736.      * Pattern match
  737.      *
  738.      * @param   type  $block        X
  739.      * @param   type  $callingArgs  X
  740.      *
  741.      * @return  boolean 
  742.      */
  743.     protected function patternMatch($block$callingArgs)
  744.     {
  745.         /**
  746.          * Match the guards if it has them
  747.          * any one of the groups must have all its guards pass for a match
  748.          */
  749.         if (!empty($block->guards))
  750.         {
  751.             $groupPassed false;
  752.  
  753.             foreach ($block->guards as $guardGroup)
  754.             {
  755.                 foreach ($guardGroup as $guard)
  756.                 {
  757.                     $this->pushEnv();
  758.                     $this->zipSetArgs($block->args$callingArgs);
  759.  
  760.                     $negate false;
  761.  
  762.                     if ($guard[0== "negate")
  763.                     {
  764.                         $guard $guard[1];
  765.                         $negate true;
  766.                     }
  767.  
  768.                     $passed $this->reduce($guard== self::$TRUE;
  769.  
  770.                     if ($negate)
  771.                     {
  772.                         $passed !$passed;
  773.                     }
  774.  
  775.                     $this->popEnv();
  776.  
  777.                     if ($passed)
  778.                     {
  779.                         $groupPassed true;
  780.                     }
  781.                     else
  782.                     {
  783.                         $groupPassed false;
  784.                         break;
  785.                     }
  786.                 }
  787.  
  788.                 if ($groupPassed)
  789.                 {
  790.                     break;
  791.                 }
  792.             }
  793.  
  794.             if (!$groupPassed)
  795.             {
  796.                 return false;
  797.             }
  798.         }
  799.  
  800.         $numCalling count($callingArgs);
  801.  
  802.         if (empty($block->args))
  803.         {
  804.             return $block->isVararg || $numCalling == 0;
  805.         }
  806.  
  807.         // No args
  808.         $i = -1;
  809.  
  810.         // Try to match by arity or by argument literal
  811.         foreach ($block->args as $i => $arg)
  812.         {
  813.             switch ($arg[0])
  814.             {
  815.                 case "lit":
  816.                     if (empty($callingArgs[$i]|| !$this->eq($arg[1]$callingArgs[$i]))
  817.                     {
  818.                         return false;
  819.                     }
  820.                     break;
  821.                 case "arg":
  822.                     // No arg and no default value
  823.                     if (!isset($callingArgs[$i]&& !isset($arg[2]))
  824.                     {
  825.                         return false;
  826.                     }
  827.                     break;
  828.                 case "rest":
  829.                     // Rest can be empty
  830.                     $i--;
  831.                     break 2;
  832.             }
  833.         }
  834.  
  835.         if ($block->isVararg)
  836.         {
  837.             // Not having enough is handled above
  838.             return true;
  839.         }
  840.         else
  841.         {
  842.             $numMatched $i 1;
  843.  
  844.             // Greater than becuase default values always match
  845.             return $numMatched >= $numCalling;
  846.         }
  847.     }
  848.  
  849.     /**
  850.      * Pattern match all
  851.      *
  852.      * @param   type  $blocks       X
  853.      * @param   type  $callingArgs  X
  854.      *
  855.      * @return  type 
  856.      */
  857.     protected function patternMatchAll($blocks$callingArgs)
  858.     {
  859.         $matches null;
  860.  
  861.         foreach ($blocks as $block)
  862.         {
  863.             if ($this->patternMatch($block$callingArgs))
  864.             {
  865.                 $matches[$block;
  866.             }
  867.         }
  868.  
  869.         return $matches;
  870.     }
  871.  
  872.     /**
  873.      * Attempt to find blocks matched by path and args
  874.      *
  875.      * @param   array   $searchIn  Block to search in
  876.      * @param   string  $path      The path to search for
  877.      * @param   array   $args      Arguments
  878.      * @param   array   $seen      Your guess is as good as mine; that's third party code
  879.      *
  880.      * @return  null 
  881.      */
  882.     protected function findBlocks($searchIn$path$args$seen array())
  883.     {
  884.         if ($searchIn == null)
  885.         {
  886.             return null;
  887.         }
  888.  
  889.         if (isset($seen[$searchIn->id]))
  890.         {
  891.             return null;
  892.         }
  893.  
  894.         $seen[$searchIn->idtrue;
  895.  
  896.         $name $path[0];
  897.  
  898.         if (isset($searchIn->children[$name]))
  899.         {
  900.             $blocks $searchIn->children[$name];
  901.  
  902.             if (count($path== 1)
  903.             {
  904.                 $matches $this->patternMatchAll($blocks$args);
  905.  
  906.                 if (!empty($matches))
  907.                 {
  908.                     // This will return all blocks that match in the closest
  909.                     // scope that has any matching block, like lessjs
  910.                     return $matches;
  911.                 }
  912.             }
  913.             else
  914.             {
  915.                 $matches array();
  916.  
  917.                 foreach ($blocks as $subBlock)
  918.                 {
  919.                     $subMatches $this->findBlocks($subBlockarray_slice($path1)$args$seen);
  920.  
  921.                     if (!is_null($subMatches))
  922.                     {
  923.                         foreach ($subMatches as $sm)
  924.                         {
  925.                             $matches[$sm;
  926.                         }
  927.                     }
  928.                 }
  929.  
  930.                 return count($matches$matches null;
  931.             }
  932.         }
  933.  
  934.         if ($searchIn->parent === $searchIn)
  935.         {
  936.             return null;
  937.         }
  938.  
  939.         return $this->findBlocks($searchIn->parent$path$args$seen);
  940.     }
  941.  
  942.     /**
  943.      * Sets all argument names in $args to either the default value
  944.      * or the one passed in through $values
  945.      *
  946.      * @param   array  $args    Arguments
  947.      * @param   array  $values  Values
  948.      *
  949.      * @return  void 
  950.      */
  951.     protected function zipSetArgs($args$values)
  952.     {
  953.         $i 0;
  954.         $assignedValues array();
  955.  
  956.         foreach ($args as $a)
  957.         {
  958.             if ($a[0== "arg")
  959.             {
  960.                 if ($i count($values&& !is_null($values[$i]))
  961.                 {
  962.                     $value $values[$i];
  963.                 }
  964.                 elseif (isset($a[2]))
  965.                 {
  966.                     $value $a[2];
  967.                 }
  968.                 else
  969.                 {
  970.                     $value null;
  971.                 }
  972.  
  973.                 $value $this->reduce($value);
  974.                 $this->set($a[1]$value);
  975.                 $assignedValues[$value;
  976.             }
  977.  
  978.             $i++;
  979.         }
  980.  
  981.         // Check for a rest
  982.         $last end($args);
  983.  
  984.         if ($last[0== "rest")
  985.         {
  986.             $rest array_slice($valuescount($args1);
  987.             $this->set($last[1]$this->reduce(array("list"" "$rest)));
  988.         }
  989.  
  990.         $this->env->arguments $assignedValues;
  991.     }
  992.  
  993.     /**
  994.      * Compile a prop and update $lines or $blocks appropriately
  995.      *
  996.      * @param   array     $prop   Prop
  997.      * @param   stdClass  $block  Block
  998.      * @param   string    $out    Out
  999.      *
  1000.      * @return  void 
  1001.      */
  1002.     protected function compileProp($prop$block$out)
  1003.     {
  1004.         // Set error position context
  1005.         $this->sourceLoc = isset($prop[-1]$prop[-1: -1;
  1006.  
  1007.         switch ($prop[0])
  1008.         {
  1009.             case 'assign':
  1010.                 list($name$value$prop;
  1011.  
  1012.                 if ($name[0== $this->vPrefix)
  1013.                 {
  1014.                     $this->set($name$value);
  1015.                 }
  1016.                 else
  1017.                 {
  1018.                     $out->lines[$this->formatter->property($name$this->compileValue($this->reduce($value)));
  1019.                 }
  1020.                 break;
  1021.             case 'block':
  1022.                 list($child$prop;
  1023.                 $this->compileBlock($child);
  1024.                 break;
  1025.             case 'mixin':
  1026.                 list($path$args$suffix$prop;
  1027.  
  1028.                 $args array_map(array($this"reduce")(array) $args);
  1029.                 $mixins $this->findBlocks($block$path$args);
  1030.  
  1031.                 if ($mixins === null)
  1032.                 {
  1033.                     // Throw error here??
  1034.                     break;
  1035.                 }
  1036.  
  1037.                 foreach ($mixins as $mixin)
  1038.                 {
  1039.                     $haveScope false;
  1040.  
  1041.                     if (isset($mixin->parent->scope))
  1042.                     {
  1043.                         $haveScope true;
  1044.                         $mixinParentEnv $this->pushEnv();
  1045.                         $mixinParentEnv->storeParent $mixin->parent->scope;
  1046.                     }
  1047.  
  1048.                     $haveArgs false;
  1049.  
  1050.                     if (isset($mixin->args))
  1051.                     {
  1052.                         $haveArgs true;
  1053.                         $this->pushEnv();
  1054.                         $this->zipSetArgs($mixin->args$args);
  1055.                     }
  1056.  
  1057.                     $oldParent $mixin->parent;
  1058.  
  1059.                     if ($mixin != $block)
  1060.                     {
  1061.                         $mixin->parent $block;
  1062.                     }
  1063.  
  1064.                     foreach ($this->sortProps($mixin->propsas $subProp)
  1065.                     {
  1066.                         if ($suffix !== null
  1067.                             && $subProp[0== "assign"
  1068.                             && is_string($subProp[1])
  1069.                             && $subProp[1]{0!= $this->vPrefix)
  1070.                         {
  1071.                             $subProp[2array(
  1072.                                 'list'' ',
  1073.                                 array($subProp[2]array('keyword'$suffix))
  1074.                             );
  1075.                         }
  1076.  
  1077.                         $this->compileProp($subProp$mixin$out);
  1078.                     }
  1079.  
  1080.                     $mixin->parent $oldParent;
  1081.  
  1082.                     if ($haveArgs)
  1083.                     {
  1084.                         $this->popEnv();
  1085.                     }
  1086.  
  1087.                     if ($haveScope)
  1088.                     {
  1089.                         $this->popEnv();
  1090.                     }
  1091.                 }
  1092.  
  1093.                 break;
  1094.             case 'raw':
  1095.                 $out->lines[$prop[1];
  1096.                 break;
  1097.             case "directive":
  1098.                 list($name$value$prop;
  1099.                 $out->lines["@$name $this->compileValue($this->reduce($value)) ';';
  1100.                 break;
  1101.             case "comment":
  1102.                 $out->lines[$prop[1];
  1103.                 break;
  1104.             case "import";
  1105.                 list($importPath$importId$prop;
  1106.                 $importPath $this->reduce($importPath);
  1107.  
  1108.                 if (!isset($this->env->imports))
  1109.                 {
  1110.                     $this->env->imports array();
  1111.                 }
  1112.  
  1113.                 $result $this->tryImport($importPath$block$out);
  1114.  
  1115.                 $this->env->imports[$importId$result === false ?
  1116.                     array(false"@import " $this->compileValue($importPath";":
  1117.                     $result;
  1118.  
  1119.                 break;
  1120.             case "import_mixin":
  1121.                 list($importId$prop;
  1122.                 $import $this->env->imports[$importId];
  1123.  
  1124.                 if ($import[0=== false)
  1125.                 {
  1126.                     $out->lines[$import[1];
  1127.                 }
  1128.                 else
  1129.                 {
  1130.                     list($bottom$parser$importDir$import;
  1131.                     $this->compileImportedProps($bottom$block$out$parser$importDir);
  1132.                 }
  1133.  
  1134.                 break;
  1135.             default:
  1136.                 $this->throwError("unknown op: {$prop[0]}\n");
  1137.         }
  1138.     }
  1139.  
  1140.     /**
  1141.      * Compiles a primitive value into a CSS property value.
  1142.      *
  1143.      * Values in lessphp are typed by being wrapped in arrays, their format is
  1144.      * typically:
  1145.      *
  1146.      *     array(type, contents [, additional_contents]*)
  1147.      *
  1148.      * The input is expected to be reduced. This function will not work on
  1149.      * things like expressions and variables.
  1150.      *
  1151.      * @param   array  $value  Value
  1152.      *
  1153.      * @return  void 
  1154.      */
  1155.     protected function compileValue($value)
  1156.     {
  1157.         switch ($value[0])
  1158.         {
  1159.             case 'list':
  1160.                 // [1] - delimiter
  1161.                 // [2] - array of values
  1162.                 return implode($value[1]array_map(array($this'compileValue')$value[2]));
  1163.             case 'raw_color':
  1164.                 if (!empty($this->formatter->compressColors))
  1165.                 {
  1166.                     return $this->compileValue($this->coerceColor($value));
  1167.                 }
  1168.  
  1169.                 return $value[1];
  1170.             case 'keyword':
  1171.                 // [1] - the keyword
  1172.                 return $value[1];
  1173.             case 'number':
  1174.                 // Format: [1] - the number -- [2] - the unit
  1175.                 list($num$unit$value;
  1176.  
  1177.                 if ($this->numberPrecision !== null)
  1178.                 {
  1179.                     $num round($num$this->numberPrecision);
  1180.                 }
  1181.  
  1182.                 return $num $unit;
  1183.             case 'string':
  1184.                 // [1] - contents of string (includes quotes)
  1185.                 list($delim$content$value;
  1186.  
  1187.                 foreach ($content as &$part)
  1188.                 {
  1189.                     if (is_array($part))
  1190.                     {
  1191.                         $part $this->compileValue($part);
  1192.                     }
  1193.                 }
  1194.  
  1195.                 return $delim implode($content$delim;
  1196.             case 'color':
  1197.                 /**
  1198.                  * Format:
  1199.                  *
  1200.                  * [1] - red component (either number or a %)
  1201.                  * [2] - green component
  1202.                  * [3] - blue component
  1203.                  * [4] - optional alpha component
  1204.                  */
  1205.                 list($r$g$b$value;
  1206.                 $r round($r);
  1207.                 $g round($g);
  1208.                 $b round($b);
  1209.  
  1210.                 if (count($value== && $value[4!= 1)
  1211.                 {
  1212.                     // Return an rgba value
  1213.                     return 'rgba(' $r ',' $g ',' $b ',' $value[4')';
  1214.                 }
  1215.  
  1216.                 $h sprintf("#%02x%02x%02x"$r$g$b);
  1217.  
  1218.                 if (!empty($this->formatter->compressColors))
  1219.                 {
  1220.                     // Converting hex color to short notation (e.g. #003399 to #039)
  1221.                     if ($h[1=== $h[2&& $h[3=== $h[4&& $h[5=== $h[6])
  1222.                     {
  1223.                         $h '#' $h[1$h[3$h[5];
  1224.                     }
  1225.                 }
  1226.  
  1227.                 return $h;
  1228.  
  1229.             case 'function':
  1230.                 list($name$args$value;
  1231.  
  1232.                 return $name '(' $this->compileValue($args')';
  1233.  
  1234.             default:
  1235.                 // Assumed to be unit
  1236.                 $this->throwError("unknown value type: $value[0]");
  1237.         }
  1238.     }
  1239.  
  1240.     /**
  1241.      * Lib is number
  1242.      *
  1243.      * @param   type  $value  X
  1244.      *
  1245.      * @return  boolean 
  1246.      */
  1247.     protected function lib_isnumber($value)
  1248.     {
  1249.         return $this->toBool($value[0== "number");
  1250.     }
  1251.  
  1252.     /**
  1253.      * Lib is string
  1254.      *
  1255.      * @param   type  $value  X
  1256.      *
  1257.      * @return  boolean 
  1258.      */
  1259.     protected function lib_isstring($value)
  1260.     {
  1261.         return $this->toBool($value[0== "string");
  1262.     }
  1263.  
  1264.     /**
  1265.      * Lib is color
  1266.      *
  1267.      * @param   type  $value  X
  1268.      *
  1269.      * @return  boolean 
  1270.      */
  1271.     protected function lib_iscolor($value)
  1272.     {
  1273.         return $this->toBool($this->coerceColor($value));
  1274.     }
  1275.  
  1276.     /**
  1277.      * Lib is keyword
  1278.      *
  1279.      * @param   type  $value  X
  1280.      *
  1281.      * @return  boolean 
  1282.      */
  1283.     protected function lib_iskeyword($value)
  1284.     {
  1285.         return $this->toBool($value[0== "keyword");
  1286.     }
  1287.  
  1288.     /**
  1289.      * Lib is pixel
  1290.      *
  1291.      * @param   type  $value  X
  1292.      *
  1293.      * @return  boolean 
  1294.      */
  1295.     protected function lib_ispixel($value)
  1296.     {
  1297.         return $this->toBool($value[0== "number" && $value[2== "px");
  1298.     }
  1299.  
  1300.     /**
  1301.      * Lib is percentage
  1302.      *
  1303.      * @param   type  $value  X
  1304.      *
  1305.      * @return  boolean 
  1306.      */
  1307.     protected function lib_ispercentage($value)
  1308.     {
  1309.         return $this->toBool($value[0== "number" && $value[2== "%");
  1310.     }
  1311.  
  1312.     /**
  1313.      * Lib is em
  1314.      *
  1315.      * @param   type  $value  X
  1316.      *
  1317.      * @return  boolean 
  1318.      */
  1319.     protected function lib_isem($value)
  1320.     {
  1321.         return $this->toBool($value[0== "number" && $value[2== "em");
  1322.     }
  1323.  
  1324.     /**
  1325.      * Lib is rem
  1326.      *
  1327.      * @param   type  $value  X
  1328.      *
  1329.      * @return  boolean 
  1330.      */
  1331.     protected function lib_isrem($value)
  1332.     {
  1333.         return $this->toBool($value[0== "number" && $value[2== "rem");
  1334.     }
  1335.  
  1336.     /**
  1337.      * LIb rgba hex
  1338.      *
  1339.      * @param   type  $color  X
  1340.      *
  1341.      * @return  boolean 
  1342.      */
  1343.     protected function lib_rgbahex($color)
  1344.     {
  1345.         $color $this->coerceColor($color);
  1346.  
  1347.         if (is_null($color))
  1348.         {
  1349.             $this->throwError("color expected for rgbahex");
  1350.         }
  1351.  
  1352.         return sprintf("#%02x%02x%02x%02x"isset($color[4]$color[4255 255$color[1]$color[2]$color[3]);
  1353.     }
  1354.  
  1355.     /**
  1356.      * Lib argb
  1357.      *
  1358.      * @param   type  $color  X
  1359.      *
  1360.      * @return  type 
  1361.      */
  1362.     protected function lib_argb($color)
  1363.     {
  1364.         return $this->lib_rgbahex($color);
  1365.     }
  1366.  
  1367.     /**
  1368.      * Utility func to unquote a string
  1369.      *
  1370.      * @param   string  $arg  Arg
  1371.      *
  1372.      * @return  string 
  1373.      */
  1374.     protected function lib_e($arg)
  1375.     {
  1376.         switch ($arg[0])
  1377.         {
  1378.             case "list":
  1379.                 $items $arg[2];
  1380.  
  1381.                 if (isset($items[0]))
  1382.                 {
  1383.                     return $this->lib_e($items[0]);
  1384.                 }
  1385.  
  1386.                 return self::$defaultValue;
  1387.  
  1388.             case "string":
  1389.                 $arg[1"";
  1390.  
  1391.                 return $arg;
  1392.  
  1393.             case "keyword":
  1394.                 return $arg;
  1395.  
  1396.             default:
  1397.                 return array("keyword"$this->compileValue($arg));
  1398.         }
  1399.     }
  1400.  
  1401.     /**
  1402.      * Lib sprintf
  1403.      *
  1404.      * @param   type  $args  X
  1405.      *
  1406.      * @return  type 
  1407.      */
  1408.     protected function lib__sprintf($args)
  1409.     {
  1410.         if ($args[0!= "list")
  1411.         {
  1412.             return $args;
  1413.         }
  1414.  
  1415.         $values $args[2];
  1416.         $string array_shift($values);
  1417.         $template $this->compileValue($this->lib_e($string));
  1418.  
  1419.         $i 0;
  1420.  
  1421.         if (preg_match_all('/%[dsa]/'$template$m))
  1422.         {
  1423.             foreach ($m[0as $match)
  1424.             {
  1425.                 $val = isset($values[$i]?
  1426.                     $this->reduce($values[$i]array('keyword''');
  1427.  
  1428.                 // Lessjs compat, renders fully expanded color, not raw color
  1429.                 if ($color $this->coerceColor($val))
  1430.                 {
  1431.                     $val $color;
  1432.                 }
  1433.  
  1434.                 $i++;
  1435.                 $rep $this->compileValue($this->lib_e($val));
  1436.                 $template preg_replace('/' self::preg_quote($match'/'$rep$template1);
  1437.             }
  1438.         }
  1439.  
  1440.         $d $string[0== "string" $string[1'"';
  1441.  
  1442.         return array("string"$darray($template));
  1443.     }
  1444.  
  1445.     /**
  1446.      * Lib floor
  1447.      *
  1448.      * @param   type  $arg  X
  1449.      *
  1450.      * @return  array 
  1451.      */
  1452.     protected function lib_floor($arg)
  1453.     {
  1454.         $value $this->assertNumber($arg);
  1455.  
  1456.         return array("number"floor($value)$arg[2]);
  1457.     }
  1458.  
  1459.     /**
  1460.      * Lib ceil
  1461.      *
  1462.      * @param   type  $arg  X
  1463.      *
  1464.      * @return  array 
  1465.      */
  1466.     protected function lib_ceil($arg)
  1467.     {
  1468.         $value $this->assertNumber($arg);
  1469.  
  1470.         return array("number"ceil($value)$arg[2]);
  1471.     }
  1472.  
  1473.     /**
  1474.      * Lib round
  1475.      *
  1476.      * @param   type  $arg  X
  1477.      *
  1478.      * @return  array 
  1479.      */
  1480.     protected function lib_round($arg)
  1481.     {
  1482.         $value $this->assertNumber($arg);
  1483.  
  1484.         return array("number"round($value)$arg[2]);
  1485.     }
  1486.  
  1487.     /**
  1488.      * Lib unit
  1489.      *
  1490.      * @param   type  $arg  X
  1491.      *
  1492.      * @return  array 
  1493.      */
  1494.     protected function lib_unit($arg)
  1495.     {
  1496.         if ($arg[0== "list")
  1497.         {
  1498.             list($number$newUnit$arg[2];
  1499.             return array("number"$this->assertNumber($number)$this->compileValue($this->lib_e($newUnit)));
  1500.         }
  1501.         else
  1502.         {
  1503.             return array("number"$this->assertNumber($arg)"");
  1504.         }
  1505.     }
  1506.  
  1507.     /**
  1508.      * Helper function to get arguments for color manipulation functions.
  1509.      * takes a list that contains a color like thing and a percentage
  1510.      *
  1511.      * @param   array  $args  Args
  1512.      *
  1513.      * @return  array 
  1514.      */
  1515.     protected function colorArgs($args)
  1516.     {
  1517.         if ($args[0!= 'list' || count($args[2]2)
  1518.         {
  1519.             return array(array('color'000)0);
  1520.         }
  1521.  
  1522.         list($color$delta$args[2];
  1523.         $color $this->assertColor($color);
  1524.         $delta floatval($delta[1]);
  1525.  
  1526.         return array($color$delta);
  1527.     }
  1528.  
  1529.     /**
  1530.      * Lib darken
  1531.      *
  1532.      * @param   type  $args  X
  1533.      *
  1534.      * @return  type 
  1535.      */
  1536.     protected function lib_darken($args)
  1537.     {
  1538.         list($color$delta$this->colorArgs($args);
  1539.  
  1540.         $hsl $this->toHSL($color);
  1541.         $hsl[3$this->clamp($hsl[3$delta100);
  1542.  
  1543.         return $this->toRGB($hsl);
  1544.     }
  1545.  
  1546.     /**
  1547.      * Lib lighten
  1548.      *
  1549.      * @param   type  $args  X
  1550.      *
  1551.      * @return  type 
  1552.      */
  1553.     protected function lib_lighten($args)
  1554.     {
  1555.         list($color$delta$this->colorArgs($args);
  1556.  
  1557.         $hsl $this->toHSL($color);
  1558.         $hsl[3$this->clamp($hsl[3$delta100);
  1559.  
  1560.         return $this->toRGB($hsl);
  1561.     }
  1562.  
  1563.     /**
  1564.      * Lib saturate
  1565.      *
  1566.      * @param   type  $args  X
  1567.      *
  1568.      * @return  type 
  1569.      */
  1570.     protected function lib_saturate($args)
  1571.     {
  1572.         list($color$delta$this->colorArgs($args);
  1573.  
  1574.         $hsl $this->toHSL($color);
  1575.         $hsl[2$this->clamp($hsl[2$delta100);
  1576.  
  1577.         return $this->toRGB($hsl);
  1578.     }
  1579.  
  1580.     /**
  1581.      * Lib desaturate
  1582.      *
  1583.      * @param   type  $args  X
  1584.      *
  1585.      * @return  type 
  1586.      */
  1587.     protected function lib_desaturate($args)
  1588.     {
  1589.         list($color$delta$this->colorArgs($args);
  1590.  
  1591.         $hsl $this->toHSL($color);
  1592.         $hsl[2$this->clamp($hsl[2$delta100);
  1593.  
  1594.         return $this->toRGB($hsl);
  1595.     }
  1596.  
  1597.     /**
  1598.      * Lib spin
  1599.      *
  1600.      * @param   type  $args  X
  1601.      *
  1602.      * @return  type 
  1603.      */
  1604.     protected function lib_spin($args)
  1605.     {
  1606.         list($color$delta$this->colorArgs($args);
  1607.  
  1608.         $hsl $this->toHSL($color);
  1609.  
  1610.         $hsl[1$hsl[1$delta 360;
  1611.  
  1612.         if ($hsl[10)
  1613.         {
  1614.             $hsl[1+= 360;
  1615.         }
  1616.  
  1617.         return $this->toRGB($hsl);
  1618.     }
  1619.  
  1620.     /**
  1621.      * Lib fadeout
  1622.      *
  1623.      * @param   type  $args  X
  1624.      *
  1625.      * @return  type 
  1626.      */
  1627.     protected function lib_fadeout($args)
  1628.     {
  1629.         list($color$delta$this->colorArgs($args);
  1630.         $color[4$this->clamp((isset($color[4]$color[41$delta 100);
  1631.  
  1632.         return $color;
  1633.     }
  1634.  
  1635.     /**
  1636.      * Lib fadein
  1637.      *
  1638.      * @param   type  $args  X
  1639.      *
  1640.      * @return  type 
  1641.      */
  1642.     protected function lib_fadein($args)
  1643.     {
  1644.         list($color$delta$this->colorArgs($args);
  1645.         $color[4$this->clamp((isset($color[4]$color[41$delta 100);
  1646.  
  1647.         return $color;
  1648.     }
  1649.  
  1650.     /**
  1651.      * Lib hue
  1652.      *
  1653.      * @param   type  $color  X
  1654.      *
  1655.      * @return  type 
  1656.      */
  1657.     protected function lib_hue($color)
  1658.     {
  1659.         $hsl $this->toHSL($this->assertColor($color));
  1660.  
  1661.         return round($hsl[1]);
  1662.     }
  1663.  
  1664.     /**
  1665.      * Lib saturation
  1666.      *
  1667.      * @param   type  $color  X
  1668.      *
  1669.      * @return  type 
  1670.      */
  1671.     protected function lib_saturation($color)
  1672.     {
  1673.         $hsl $this->toHSL($this->assertColor($color));
  1674.  
  1675.         return round($hsl[2]);
  1676.     }
  1677.  
  1678.     /**
  1679.      * Lib lightness
  1680.      *
  1681.      * @param   type  $color  X
  1682.      *
  1683.      * @return  type 
  1684.      */
  1685.     protected function lib_lightness($color)
  1686.     {
  1687.         $hsl $this->toHSL($this->assertColor($color));
  1688.  
  1689.         return round($hsl[3]);
  1690.     }
  1691.  
  1692.     /**
  1693.      * Get the alpha of a color
  1694.      * Defaults to 1 for non-colors or colors without an alpha
  1695.      *
  1696.      * @param   string  $value  Value
  1697.      *
  1698.      * @return  string 
  1699.      */
  1700.     protected function lib_alpha($value)
  1701.     {
  1702.         if (!is_null($color $this->coerceColor($value)))
  1703.         {
  1704.             return isset($color[4]$color[41;
  1705.         }
  1706.     }
  1707.  
  1708.     /**
  1709.      * Set the alpha of the color
  1710.      *
  1711.      * @param   array  $args  Args
  1712.      *
  1713.      * @return  string 
  1714.      */
  1715.     protected function lib_fade($args)
  1716.     {
  1717.         list($color$alpha$this->colorArgs($args);
  1718.         $color[4$this->clamp($alpha 100.0);
  1719.  
  1720.         return $color;
  1721.     }
  1722.  
  1723.     /**
  1724.      * Third party code; your guess is as good as mine
  1725.      *
  1726.      * @param   array  $arg  Arg
  1727.      *
  1728.      * @return  string 
  1729.      */
  1730.     protected function lib_percentage($arg)
  1731.     {
  1732.         $num $this->assertNumber($arg);
  1733.  
  1734.         return array("number"$num 100"%");
  1735.     }
  1736.  
  1737.     /**
  1738.      * mixes two colors by weight
  1739.      * mix(@color1, @color2, @weight);
  1740.      * http://sass-lang.com/docs/yardoc/Sass/Script/Functions.html#mix-instance_method
  1741.      *
  1742.      * @param   array  $args  Args
  1743.      *
  1744.      * @return  string 
  1745.      */
  1746.     protected function lib_mix($args)
  1747.     {
  1748.         if ($args[0!= "list" || count($args[2]3)
  1749.         {
  1750.             $this->throwError("mix expects (color1, color2, weight)");
  1751.         }
  1752.  
  1753.         list($first$second$weight$args[2];
  1754.         $first $this->assertColor($first);
  1755.         $second $this->assertColor($second);
  1756.  
  1757.         $first_a $this->lib_alpha($first);
  1758.         $second_a $this->lib_alpha($second);
  1759.         $weight $weight[1100.0;
  1760.  
  1761.         $w $weight 1;
  1762.         $a $first_a $second_a;
  1763.  
  1764.         $w1 (($w $a == -$w ($w $a($w $a)) 12.0;
  1765.         $w2 1.0 $w1;
  1766.  
  1767.         $new array('color',
  1768.             $w1 $first[1$w2 $second[1],
  1769.             $w1 $first[2$w2 $second[2],
  1770.             $w1 $first[3$w2 $second[3],
  1771.         );
  1772.  
  1773.         if ($first_a != 1.0 || $second_a != 1.0)
  1774.         {
  1775.             $new[$first_a $weight $second_a ($weight 1);
  1776.         }
  1777.  
  1778.         return $this->fixColor($new);
  1779.     }
  1780.  
  1781.     /**
  1782.      * Third party code; your guess is as good as mine
  1783.      *
  1784.      * @param   array  $arg  Arg
  1785.      *
  1786.      * @return  string 
  1787.      */
  1788.     protected function lib_contrast($args)
  1789.     {
  1790.         if ($args[0!= 'list' || count($args[2]3)
  1791.         {
  1792.             return array(array('color'000)0);
  1793.         }
  1794.  
  1795.         list($inputColor$darkColor$lightColor$args[2];
  1796.  
  1797.         $inputColor $this->assertColor($inputColor);
  1798.         $darkColor $this->assertColor($darkColor);
  1799.         $lightColor $this->assertColor($lightColor);
  1800.         $hsl $this->toHSL($inputColor);
  1801.  
  1802.         if ($hsl[350)
  1803.         {
  1804.             return $darkColor;
  1805.         }
  1806.  
  1807.         return $lightColor;
  1808.     }
  1809.  
  1810.     /**
  1811.      * Assert color
  1812.      *
  1813.      * @param   type  $value  X
  1814.      * @param   type  $error  X
  1815.      *
  1816.      * @return  type 
  1817.      */
  1818.     protected function assertColor($value$error "expected color value")
  1819.     {
  1820.         $color $this->coerceColor($value);
  1821.  
  1822.         if (is_null($color))
  1823.         {
  1824.             $this->throwError($error);
  1825.         }
  1826.  
  1827.         return $color;
  1828.     }
  1829.  
  1830.     /**
  1831.      * Assert number
  1832.      *
  1833.      * @param   type  $value  X
  1834.      * @param   type  $error  X
  1835.      *
  1836.      * @return  type 
  1837.      */
  1838.     protected function assertNumber($value$error "expecting number")
  1839.     {
  1840.         if ($value[0== "number")
  1841.         {
  1842.             return $value[1];
  1843.         }
  1844.  
  1845.         $this->throwError($error);
  1846.     }
  1847.  
  1848.     /**
  1849.      * To HSL
  1850.      *
  1851.      * @param   type  $color  X
  1852.      *
  1853.      * @return  type 
  1854.      */
  1855.     protected function toHSL($color)
  1856.     {
  1857.         if ($color[0== 'hsl')
  1858.         {
  1859.             return $color;
  1860.         }
  1861.  
  1862.         $r $color[1255;
  1863.         $g $color[2255;
  1864.         $b $color[3255;
  1865.  
  1866.         $min min($r$g$b);
  1867.         $max max($r$g$b);
  1868.  
  1869.         $L ($min $max2;
  1870.  
  1871.         if ($min == $max)
  1872.         {
  1873.             $S $H 0;
  1874.         }
  1875.         else
  1876.         {
  1877.             if ($L 0.5)
  1878.             {
  1879.                 $S ($max $min($max $min);
  1880.             }
  1881.             else
  1882.             {
  1883.                 $S ($max $min(2.0 $max $min);
  1884.             }
  1885.  
  1886.             if ($r == $max)
  1887.             {
  1888.                 $H ($g $b($max $min);
  1889.             }
  1890.             elseif ($g == $max)
  1891.             {
  1892.                 $H 2.0 ($b $r($max $min);
  1893.             }
  1894.             elseif ($b == $max)
  1895.             {
  1896.                 $H 4.0 ($r $g($max $min);
  1897.             }
  1898.         }
  1899.  
  1900.         $out array('hsl',
  1901.             ($H $H $H60,
  1902.             $S 100,
  1903.             $L 100,
  1904.         );
  1905.  
  1906.         if (count($color4)
  1907.         {
  1908.             // Copy alpha
  1909.             $out[$color[4];
  1910.         }
  1911.  
  1912.         return $out;
  1913.     }
  1914.  
  1915.     /**
  1916.      * To RGB helper
  1917.      *
  1918.      * @param   type  $comp   X
  1919.      * @param   type  $temp1  X
  1920.      * @param   type  $temp2  X
  1921.      *
  1922.      * @return  type 
  1923.      */
  1924.     protected function toRGB_helper($comp$temp1$temp2)
  1925.     {
  1926.         if ($comp 0)
  1927.         {
  1928.             $comp += 1.0;
  1929.         }
  1930.         elseif ($comp 1)
  1931.         {
  1932.             $comp -= 1.0;
  1933.         }
  1934.  
  1935.         if ($comp 1)
  1936.         {
  1937.             return $temp1 ($temp2 $temp1$comp;
  1938.         }
  1939.  
  1940.         if ($comp 1)
  1941.         {
  1942.             return $temp2;
  1943.         }
  1944.  
  1945.         if ($comp 2)
  1946.         {
  1947.             return $temp1 ($temp2 $temp1((3$comp6;
  1948.         }
  1949.  
  1950.         return $temp1;
  1951.     }
  1952.  
  1953.     /**
  1954.      * Converts a hsl array into a color value in rgb.
  1955.      * Expects H to be in range of 0 to 360, S and L in 0 to 100
  1956.      *
  1957.      * @param   type  $color  X
  1958.      *
  1959.      * @return  type 
  1960.      */
  1961.     protected function toRGB($color)
  1962.     {
  1963.         if ($color == 'color')
  1964.         {
  1965.             return $color;
  1966.         }
  1967.  
  1968.         $H $color[1360;
  1969.         $S $color[2100;
  1970.         $L $color[3100;
  1971.  
  1972.         if ($S == 0)
  1973.         {
  1974.             $r $g $b $L;
  1975.         }
  1976.         else
  1977.         {
  1978.             $temp2 $L 0.5 ?
  1979.                 $L (1.0 $S:
  1980.                 $L $S $L $S;
  1981.  
  1982.             $temp1 2.0 $L $temp2;
  1983.  
  1984.             $r $this->toRGB_helper($H 3$temp1$temp2);
  1985.             $g $this->toRGB_helper($H$temp1$temp2);
  1986.             $b $this->toRGB_helper($H 3$temp1$temp2);
  1987.         }
  1988.  
  1989.         // $out = array('color', round($r*255), round($g*255), round($b*255));
  1990.         $out array('color'$r 255$g 255$b 255);
  1991.  
  1992.         if (count($color4)
  1993.         {
  1994.             // Copy alpha
  1995.             $out[$color[4];
  1996.         }
  1997.  
  1998.         return $out;
  1999.     }
  2000.  
  2001.     /**
  2002.      * Clamp
  2003.      *
  2004.      * @param   type  $v    X
  2005.      * @param   type  $max  X
  2006.      * @param   type  $min  X
  2007.      *
  2008.      * @return  type 
  2009.      */
  2010.     protected function clamp($v$max 1$min 0)
  2011.     {
  2012.         return min($maxmax($min$v));
  2013.     }
  2014.  
  2015.     /**
  2016.      * Convert the rgb, rgba, hsl color literals of function type
  2017.      * as returned by the parser into values of color type.
  2018.      *
  2019.      * @param   type  $func  X
  2020.      *
  2021.      * @return  type 
  2022.      */
  2023.     protected function funcToColor($func)
  2024.     {
  2025.         $fname $func[1];
  2026.  
  2027.         if ($func[2][0!= 'list')
  2028.         {
  2029.             // Need a list of arguments
  2030.             return false;
  2031.         }
  2032.  
  2033.         $rawComponents $func[2][2];
  2034.  
  2035.         if ($fname == 'hsl' || $fname == 'hsla')
  2036.         {
  2037.             $hsl array('hsl');
  2038.             $i 0;
  2039.  
  2040.             foreach ($rawComponents as $c)
  2041.             {
  2042.                 $val $this->reduce($c);
  2043.                 $val = isset($val[1]floatval($val[1]0;
  2044.  
  2045.                 if ($i == 0)
  2046.                 {
  2047.                     $clamp 360;
  2048.                 }
  2049.                 elseif ($i 3)
  2050.                 {
  2051.                     $clamp 100;
  2052.                 }
  2053.                 else
  2054.                 {
  2055.                     $clamp 1;
  2056.                 }
  2057.  
  2058.                 $hsl[$this->clamp($val$clamp);
  2059.                 $i++;
  2060.             }
  2061.  
  2062.             while (count($hsl4)
  2063.             {
  2064.                 $hsl[0;
  2065.             }
  2066.  
  2067.             return $this->toRGB($hsl);
  2068.         }
  2069.         elseif ($fname == 'rgb' || $fname == 'rgba')
  2070.         {
  2071.             $components array();
  2072.             $i 1;
  2073.  
  2074.             foreach ($rawComponents as $c)
  2075.             {
  2076.                 $c $this->reduce($c);
  2077.  
  2078.                 if ($i 4)
  2079.                 {
  2080.                     if ($c[0== "number" && $c[2== "%")
  2081.                     {
  2082.                         $components[255 ($c[1100);
  2083.                     }
  2084.                     else
  2085.                     {
  2086.                         $components[floatval($c[1]);
  2087.                     }
  2088.                 }
  2089.                 elseif ($i == 4)
  2090.                 {
  2091.                     if ($c[0== "number" && $c[2== "%")
  2092.                     {
  2093.                         $components[1.0 ($c[1100);
  2094.                     }
  2095.                     else
  2096.                     {
  2097.                         $components[floatval($c[1]);
  2098.                     }
  2099.                 }
  2100.                 else
  2101.                 {
  2102.                     break;
  2103.                 }
  2104.  
  2105.                 $i++;
  2106.             }
  2107.  
  2108.             while (count($components3)
  2109.             {
  2110.                 $components[0;
  2111.             }
  2112.  
  2113.             array_unshift($components'color');
  2114.  
  2115.             return $this->fixColor($components);
  2116.         }
  2117.  
  2118.         return false;
  2119.     }
  2120.  
  2121.     /**
  2122.      * Reduce
  2123.      *
  2124.      * @param   type  $value          X
  2125.      * @param   type  $forExpression  X
  2126.      *
  2127.      * @return  type 
  2128.      */
  2129.     protected function reduce($value$forExpression false)
  2130.     {
  2131.         switch ($value[0])
  2132.         {
  2133.             case "interpolate":
  2134.                 $reduced $this->reduce($value[1]);
  2135.                 $var     $this->compileValue($reduced);
  2136.                 $res     $this->reduce(array("variable"$this->vPrefix . $var));
  2137.  
  2138.                 if (empty($value[2]))
  2139.                 {
  2140.                     $res $this->lib_e($res);
  2141.                 }
  2142.  
  2143.                 return $res;
  2144.             case "variable":
  2145.                 $key $value[1];
  2146.                 if (is_array($key))
  2147.                 {
  2148.                     $key $this->reduce($key);
  2149.                     $key $this->vPrefix . $this->compileValue($this->lib_e($key));
  2150.                 }
  2151.  
  2152.                 $seen $this->env->seenNames;
  2153.  
  2154.                 if (!empty($seen[$key]))
  2155.                 {
  2156.                     $this->throwError("infinite loop detected: $key");
  2157.                 }
  2158.  
  2159.                 $seen[$keytrue;
  2160.                 $out $this->reduce($this->get($keyself::$defaultValue));
  2161.                 $seen[$keyfalse;
  2162.  
  2163.                 return $out;
  2164.             case "list":
  2165.                 foreach ($value[2as &$item)
  2166.                 {
  2167.                     $item $this->reduce($item$forExpression);
  2168.                 }
  2169.  
  2170.                 return $value;
  2171.             case "expression":
  2172.                 return $this->evaluate($value);
  2173.             case "string":
  2174.                 foreach ($value[2as &$part)
  2175.                 {
  2176.                     if (is_array($part))
  2177.                     {
  2178.                         $strip $part[0== "variable";
  2179.                         $part $this->reduce($part);
  2180.  
  2181.                         if ($strip)
  2182.                         {
  2183.                             $part $this->lib_e($part);
  2184.                         }
  2185.                     }
  2186.                 }
  2187.  
  2188.                 return $value;
  2189.             case "escape":
  2190.                 list($inner$value;
  2191.  
  2192.                 return $this->lib_e($this->reduce($inner));
  2193.             case "function":
  2194.                 $color $this->funcToColor($value);
  2195.  
  2196.                 if ($color)
  2197.                 {
  2198.                     return $color;
  2199.                 }
  2200.  
  2201.                 list($name$args$value;
  2202.  
  2203.                 if ($name == "%")
  2204.                 {
  2205.                     $name "_sprintf";
  2206.                 }
  2207.  
  2208.                 $f = isset($this->libFunctions[$name]?
  2209.                     $this->libFunctions[$namearray($this'lib_' $name);
  2210.  
  2211.                 if (is_callable($f))
  2212.                 {
  2213.                     if ($args[0== 'list')
  2214.                     {
  2215.                         $args self::compressList($args[2]$args[1]);
  2216.                     }
  2217.  
  2218.                     $ret call_user_func($f$this->reduce($argstrue)$this);
  2219.  
  2220.                     if (is_null($ret))
  2221.                     {
  2222.                         return array("string"""array(
  2223.                                 $name"("$args")"
  2224.                             ));
  2225.                     }
  2226.  
  2227.                     // Convert to a typed value if the result is a php primitive
  2228.                     if (is_numeric($ret))
  2229.                     {
  2230.                         $ret array('number'$ret"");
  2231.                     }
  2232.                     elseif (!is_array($ret))
  2233.                     {
  2234.                         $ret array('keyword'$ret);
  2235.                     }
  2236.  
  2237.                     return $ret;
  2238.                 }
  2239.  
  2240.                 // Plain function, reduce args
  2241.                 $value[2$this->reduce($value[2]);
  2242.  
  2243.                 return $value;
  2244.             case "unary":
  2245.                 list($op$exp$value;
  2246.                 $exp $this->reduce($exp);
  2247.  
  2248.                 if ($exp[0== "number")
  2249.                 {
  2250.                     switch ($op)
  2251.                     {
  2252.                         case "+":
  2253.                             return $exp;
  2254.                         case "-":
  2255.                             $exp[1*= -1;
  2256.  
  2257.                             return $exp;
  2258.                     }
  2259.                 }
  2260.  
  2261.                 return array("string"""array($op$exp));
  2262.         }
  2263.  
  2264.         if ($forExpression)
  2265.         {
  2266.             switch ($value[0])
  2267.             {
  2268.                 case "keyword":
  2269.                     if ($color $this->coerceColor($value))
  2270.                     {
  2271.                         return $color;
  2272.                     }
  2273.                     break;
  2274.                 case "raw_color":
  2275.                     return $this->coerceColor($value);
  2276.             }
  2277.         }
  2278.  
  2279.         return $value;
  2280.     }
  2281.  
  2282.     /**
  2283.      * Coerce a value for use in color operation
  2284.      *
  2285.      * @param   type  $value  X
  2286.      *
  2287.      * @return  null 
  2288.      */
  2289.     protected function coerceColor($value)
  2290.     {
  2291.         switch ($value[0])
  2292.         {
  2293.             case 'color':
  2294.                 return $value;
  2295.             case 'raw_color':
  2296.                 $c array("color"000);
  2297.                 $colorStr substr($value[1]1);
  2298.                 $num hexdec($colorStr);
  2299.                 $width strlen($colorStr== 16 256;
  2300.  
  2301.                 for ($i 3$i 0$i--)
  2302.                 {
  2303.                     // It's 3 2 1
  2304.                     $t $num $width;
  2305.                     $num /= $width;
  2306.  
  2307.                     $c[$i$t (256 $width$t floor(16 $width);
  2308.                 }
  2309.  
  2310.                 return $c;
  2311.             case 'keyword':
  2312.                 $name $value[1];
  2313.  
  2314.                 if (isset(self::$cssColors[$name]))
  2315.                 {
  2316.                     $rgba explode(','self::$cssColors[$name]);
  2317.  
  2318.                     if (isset($rgba[3]))
  2319.                     {
  2320.                         return array('color'$rgba[0]$rgba[1]$rgba[2]$rgba[3]);
  2321.                     }
  2322.  
  2323.                     return array('color'$rgba[0]$rgba[1]$rgba[2]);
  2324.                 }
  2325.  
  2326.                 return null;
  2327.         }
  2328.     }
  2329.  
  2330.     /**
  2331.      * Make something string like into a string
  2332.      *
  2333.      * @param   type  $value  X
  2334.      *
  2335.      * @return  null 
  2336.      */
  2337.     protected function coerceString($value)
  2338.     {
  2339.         switch ($value[0])
  2340.         {
  2341.             case "string":
  2342.                 return $value;
  2343.             case "keyword":
  2344.                 return array("string"""array($value[1]));
  2345.         }
  2346.  
  2347.         return null;
  2348.     }
  2349.  
  2350.     /**
  2351.      * Turn list of length 1 into value type
  2352.      *
  2353.      * @param   type  $value  X
  2354.      *
  2355.      * @return  type 
  2356.      */
  2357.     protected function flattenList($value)
  2358.     {
  2359.         if ($value[0== "list" && count($value[2]== 1)
  2360.         {
  2361.             return $this->flattenList($value[2][0]);
  2362.         }
  2363.  
  2364.         return $value;
  2365.     }
  2366.  
  2367.     /**
  2368.      * To bool
  2369.      *
  2370.      * @param   type  $a  X
  2371.      *
  2372.      * @return  type 
  2373.      */
  2374.     protected function toBool($a)
  2375.     {
  2376.         if ($a)
  2377.         {
  2378.             return self::$TRUE;
  2379.         }
  2380.         else
  2381.         {
  2382.             return self::$FALSE;
  2383.         }
  2384.     }
  2385.  
  2386.     /**
  2387.      * Evaluate an expression
  2388.      *
  2389.      * @param   type  $exp  X
  2390.      *
  2391.      * @return  type 
  2392.      */
  2393.     protected function evaluate($exp)
  2394.     {
  2395.         list($op$left$right$whiteBefore$whiteAfter$exp;
  2396.  
  2397.         $left $this->reduce($lefttrue);
  2398.         $right $this->reduce($righttrue);
  2399.  
  2400.         if ($leftColor $this->coerceColor($left))
  2401.         {
  2402.             $left $leftColor;
  2403.         }
  2404.  
  2405.         if ($rightColor $this->coerceColor($right))
  2406.         {
  2407.             $right $rightColor;
  2408.         }
  2409.  
  2410.         $ltype $left[0];
  2411.         $rtype $right[0];
  2412.  
  2413.         // Operators that work on all types
  2414.         if ($op == "and")
  2415.         {
  2416.             return $this->toBool($left == self::$TRUE && $right == self::$TRUE);
  2417.         }
  2418.  
  2419.         if ($op == "=")
  2420.         {
  2421.             return $this->toBool($this->eq($left$right));
  2422.         }
  2423.  
  2424.         if ($op == "+" && !is_null($str $this->stringConcatenate($left$right)))
  2425.         {
  2426.             return $str;
  2427.         }
  2428.  
  2429.         // Type based operators
  2430.         $fname "op_${ltype}_${rtype}";
  2431.  
  2432.         if (is_callable(array($this$fname)))
  2433.         {
  2434.             $out $this->$fname($op$left$right);
  2435.  
  2436.             if (!is_null($out))
  2437.             {
  2438.                 return $out;
  2439.             }
  2440.         }
  2441.  
  2442.         // Make the expression look it did before being parsed
  2443.         $paddedOp $op;
  2444.  
  2445.         if ($whiteBefore)
  2446.         {
  2447.             $paddedOp " " $paddedOp;
  2448.         }
  2449.  
  2450.         if ($whiteAfter)
  2451.         {
  2452.             $paddedOp .= " ";
  2453.         }
  2454.  
  2455.         return array("string"""array($left$paddedOp$right));
  2456.     }
  2457.  
  2458.     /**
  2459.      * String concatenate
  2460.      *
  2461.      * @param   type    $left   X
  2462.      * @param   string  $right  X
  2463.      *
  2464.      * @return  string 
  2465.      */
  2466.     protected function stringConcatenate($left$right)
  2467.     {
  2468.         if ($strLeft $this->coerceString($left))
  2469.         {
  2470.             if ($right[0== "string")
  2471.             {
  2472.                 $right[1"";
  2473.             }
  2474.  
  2475.             $strLeft[2][$right;
  2476.  
  2477.             return $strLeft;
  2478.         }
  2479.  
  2480.         if ($strRight $this->coerceString($right))
  2481.         {
  2482.             array_unshift($strRight[2]$left);
  2483.  
  2484.             return $strRight;
  2485.         }
  2486.     }
  2487.  
  2488.     /**
  2489.      * Make sure a color's components don't go out of bounds
  2490.      *
  2491.      * @param   type  $c  X
  2492.      *
  2493.      * @return  int 
  2494.      */
  2495.     protected function fixColor($c)
  2496.     {
  2497.         foreach (range(13as $i)
  2498.         {
  2499.             if ($c[$i0)
  2500.             {
  2501.                 $c[$i0;
  2502.             }
  2503.  
  2504.             if ($c[$i255)
  2505.             {
  2506.                 $c[$i255;
  2507.             }
  2508.         }
  2509.  
  2510.         return $c;
  2511.     }
  2512.  
  2513.     /**
  2514.      * Op number color
  2515.      *
  2516.      * @param   type  $op   X
  2517.      * @param   type  $lft  X
  2518.      * @param   type  $rgt  X
  2519.      *
  2520.      * @return  type 
  2521.      */
  2522.     protected function op_number_color($op$lft$rgt)
  2523.     {
  2524.         if ($op == '+' || $op == '*')
  2525.         {
  2526.             return $this->op_color_number($op$rgt$lft);
  2527.         }
  2528.     }
  2529.  
  2530.     /**
  2531.      * Op color number
  2532.      *
  2533.      * @param   type  $op   X
  2534.      * @param   type  $lft  X
  2535.      * @param   int   $rgt  X
  2536.      *
  2537.      * @return  type 
  2538.      */
  2539.     protected function op_color_number($op$lft$rgt)
  2540.     {
  2541.         if ($rgt[0== '%')
  2542.         {
  2543.             $rgt[1/= 100;
  2544.         }
  2545.  
  2546.         return $this->op_color_color($op$lftarray_fill(1count($lft1$rgt[1]));
  2547.     }
  2548.  
  2549.     /**
  2550.      * Op color color
  2551.      *
  2552.      * @param   type  $op     X
  2553.      * @param   type  $left   X
  2554.      * @param   type  $right  X
  2555.      *
  2556.      * @return  type 
  2557.      */
  2558.     protected function op_color_color($op$left$right)
  2559.     {
  2560.         $out array('color');
  2561.         $max count($leftcount($rightcount($leftcount($right);
  2562.  
  2563.         foreach (range(1$max 1as $i)
  2564.         {
  2565.             $lval = isset($left[$i]$left[$i0;
  2566.             $rval = isset($right[$i]$right[$i0;
  2567.  
  2568.             switch ($op)
  2569.             {
  2570.                 case '+':
  2571.                     $out[$lval $rval;
  2572.                     break;
  2573.                 case '-':
  2574.                     $out[$lval $rval;
  2575.                     break;
  2576.                 case '*':
  2577.                     $out[$lval $rval;
  2578.                     break;
  2579.                 case '%':
  2580.                     $out[$lval $rval;
  2581.                     break;
  2582.                 case '/':
  2583.                     if ($rval == 0)
  2584.                     {
  2585.                         $this->throwError("evaluate error: can't divide by zero");
  2586.                     }
  2587.  
  2588.                     $out[$lval $rval;
  2589.                     break;
  2590.                 default:
  2591.                     $this->throwError('evaluate error: color op number failed on op ' $op);
  2592.             }
  2593.         }
  2594.  
  2595.         return $this->fixColor($out);
  2596.     }
  2597.  
  2598.     /**
  2599.      * Lib red
  2600.      *
  2601.      * @param   type  $color  X
  2602.      *
  2603.      * @return  type 
  2604.      */
  2605.     public function lib_red($color)
  2606.     {
  2607.         $color $this->coerceColor($color);
  2608.  
  2609.         if (is_null($color))
  2610.         {
  2611.             $this->throwError('color expected for red()');
  2612.         }
  2613.  
  2614.         return $color[1];
  2615.     }
  2616.  
  2617.     /**
  2618.      * Lib green
  2619.      *
  2620.      * @param   type  $color  X
  2621.      *
  2622.      * @return  type 
  2623.      */
  2624.     public function lib_green($color)
  2625.     {
  2626.         $color $this->coerceColor($color);
  2627.  
  2628.         if (is_null($color))
  2629.         {
  2630.             $this->throwError('color expected for green()');
  2631.         }
  2632.  
  2633.         return $color[2];
  2634.     }
  2635.  
  2636.     /**
  2637.      * Lib blue
  2638.      *
  2639.      * @param   type  $color  X
  2640.      *
  2641.      * @return  type 
  2642.      */
  2643.     public function lib_blue($color)
  2644.     {
  2645.         $color $this->coerceColor($color);
  2646.  
  2647.         if (is_null($color))
  2648.         {
  2649.             $this->throwError('color expected for blue()');
  2650.         }
  2651.  
  2652.         return $color[3];
  2653.     }
  2654.  
  2655.     /**
  2656.      * Operator on two numbers
  2657.      *
  2658.      * @param   type  $op     X
  2659.      * @param   type  $left   X
  2660.      * @param   type  $right  X
  2661.      *
  2662.      * @return  type 
  2663.      */
  2664.     protected function op_number_number($op$left$right)
  2665.     {
  2666.         $unit empty($left[2]$right[2$left[2];
  2667.  
  2668.         $value 0;
  2669.  
  2670.         switch ($op)
  2671.         {
  2672.             case '+':
  2673.                 $value $left[1$right[1];
  2674.                 break;
  2675.             case '*':
  2676.                 $value $left[1$right[1];
  2677.                 break;
  2678.             case '-':
  2679.                 $value $left[1$right[1];
  2680.                 break;
  2681.             case '%':
  2682.                 $value $left[1$right[1];
  2683.                 break;
  2684.             case '/':
  2685.                 if ($right[1== 0)
  2686.                 {
  2687.                     $this->throwError('parse error: divide by zero');
  2688.                 }
  2689.  
  2690.                 $value $left[1$right[1];
  2691.                 break;
  2692.             case '<':
  2693.                 return $this->toBool($left[1$right[1]);
  2694.             case '>':
  2695.                 return $this->toBool($left[1$right[1]);
  2696.             case '>=':
  2697.                 return $this->toBool($left[1>= $right[1]);
  2698.             case '=<':
  2699.                 return $this->toBool($left[1<= $right[1]);
  2700.             default:
  2701.                 $this->throwError('parse error: unknown number operator: ' $op);
  2702.         }
  2703.  
  2704.         return array("number"$value$unit);
  2705.     }
  2706.  
  2707.     /**
  2708.      * Make output block
  2709.      *
  2710.      * @param   type  $type       X
  2711.      * @param   type  $selectors  X
  2712.      *
  2713.      * @return  stdclass 
  2714.      */
  2715.     protected function makeOutputBlock($type$selectors null)
  2716.     {
  2717.         $b new stdclass;
  2718.         $b->lines array();
  2719.         $b->children array();
  2720.         $b->selectors $selectors;
  2721.         $b->type $type;
  2722.         $b->parent $this->scope;
  2723.  
  2724.         return $b;
  2725.     }
  2726.  
  2727.     /**
  2728.      * The state of execution
  2729.      *
  2730.      * @param   type  $block  X
  2731.      *
  2732.      * @return  stdclass 
  2733.      */
  2734.     protected function pushEnv($block null)
  2735.     {
  2736.         $e new stdclass;
  2737.         $e->parent $this->env;
  2738.         $e->store array();
  2739.         $e->block $block;
  2740.  
  2741.         $this->env $e;
  2742.  
  2743.         return $e;
  2744.     }
  2745.  
  2746.     /**
  2747.      * Pop something off the stack
  2748.      *
  2749.      * @return  type 
  2750.      */
  2751.     protected function popEnv()
  2752.     {
  2753.         $old $this->env;
  2754.         $this->env $this->env->parent;
  2755.  
  2756.         return $old;
  2757.     }
  2758.  
  2759.     /**
  2760.      * Set something in the current env
  2761.      *
  2762.      * @param   type  $name   X
  2763.      * @param   type  $value  X
  2764.      *
  2765.      * @return  void 
  2766.      */
  2767.     protected function set($name$value)
  2768.     {
  2769.         $this->env->store[$name$value;
  2770.     }
  2771.  
  2772.     /**
  2773.      * Get the highest occurrence entry for a name
  2774.      *
  2775.      * @param   type  $name     X
  2776.      * @param   type  $default  X
  2777.      *
  2778.      * @return  type 
  2779.      */
  2780.     protected function get($name$default null)
  2781.     {
  2782.         $current $this->env;
  2783.  
  2784.         $isArguments $name == $this->vPrefix . 'arguments';
  2785.  
  2786.         while ($current)
  2787.         {
  2788.             if ($isArguments && isset($current->arguments))
  2789.             {
  2790.                 return array('list'' '$current->arguments);
  2791.             }
  2792.  
  2793.             if (isset($current->store[$name]))
  2794.             {
  2795.                 return $current->store[$name];
  2796.             }
  2797.             else
  2798.             {
  2799.                 $current = isset($current->storeParent?
  2800.                     $current->storeParent $current->parent;
  2801.             }
  2802.         }
  2803.  
  2804.         return $default;
  2805.     }
  2806.  
  2807.     /**
  2808.      * Inject array of unparsed strings into environment as variables
  2809.      *
  2810.      * @param   type  $args  X
  2811.      *
  2812.      * @return  void 
  2813.      *
  2814.      * @throws  Exception
  2815.      */
  2816.     protected function injectVariables($args)
  2817.     {
  2818.         $this->pushEnv();
  2819.         /** FOF -- BEGIN CHANGE * */
  2820.         $parser new FOFLessParser($this__METHOD__);
  2821.         /** FOF -- END CHANGE * */
  2822.         foreach ($args as $name => $strValue)
  2823.         {
  2824.             if ($name{0!= '@')
  2825.             {
  2826.                 $name '@' $name;
  2827.             }
  2828.  
  2829.             $parser->count 0;
  2830.             $parser->buffer = (string) $strValue;
  2831.  
  2832.             if (!$parser->propertyValue($value))
  2833.             {
  2834.                 throw new Exception("failed to parse passed in variable $name$strValue");
  2835.             }
  2836.  
  2837.             $this->set($name$value);
  2838.         }
  2839.     }
  2840.  
  2841.     /**
  2842.      * Initialize any static state, can initialize parser for a file
  2843.      *
  2844.      * @param   type  $fname  X
  2845.      */
  2846.     public function __construct($fname null)
  2847.     {
  2848.         if ($fname !== null)
  2849.         {
  2850.             // Used for deprecated parse method
  2851.             $this->_parseFile $fname;
  2852.         }
  2853.     }
  2854.  
  2855.     /**
  2856.      * Compile
  2857.      *
  2858.      * @param   type  $string  X
  2859.      * @param   type  $name    X
  2860.      *
  2861.      * @return  type 
  2862.      */
  2863.     public function compile($string$name null)
  2864.     {
  2865.         $locale setlocale(LC_NUMERIC0);
  2866.         setlocale(LC_NUMERIC"C");
  2867.  
  2868.         $this->parser $this->makeParser($name);
  2869.         $root $this->parser->parse($string);
  2870.  
  2871.         $this->env null;
  2872.         $this->scope null;
  2873.  
  2874.         $this->formatter $this->newFormatter();
  2875.  
  2876.         if (!empty($this->registeredVars))
  2877.         {
  2878.             $this->injectVariables($this->registeredVars);
  2879.         }
  2880.  
  2881.         // Used for error messages
  2882.         $this->sourceParser = $this->parser;
  2883.         $this->compileBlock($root);
  2884.  
  2885.         ob_start();
  2886.         $this->formatter->block($this->scope);
  2887.         $out ob_get_clean();
  2888.         setlocale(LC_NUMERIC$locale);
  2889.  
  2890.         return $out;
  2891.     }
  2892.  
  2893.     /**
  2894.      * Compile file
  2895.      *
  2896.      * @param   type  $fname     X
  2897.      * @param   type  $outFname  X
  2898.      *
  2899.      * @return  type 
  2900.      *
  2901.      * @throws  Exception
  2902.      */
  2903.     public function compileFile($fname$outFname null)
  2904.     {
  2905.         if (!is_readable($fname))
  2906.         {
  2907.             throw new Exception('load error: failed to find ' $fname);
  2908.         }
  2909.  
  2910.         $pi pathinfo($fname);
  2911.  
  2912.         $oldImport $this->importDir;
  2913.  
  2914.         $this->importDir = (array) $this->importDir;
  2915.         $this->importDir[$pi['dirname''/';
  2916.  
  2917.         $this->allParsedFiles array();
  2918.         $this->addParsedFile($fname);
  2919.  
  2920.         $out $this->compile(file_get_contents($fname)$fname);
  2921.  
  2922.         $this->importDir = $oldImport;
  2923.  
  2924.         if ($outFname !== null)
  2925.         {
  2926.             /** FOF - BEGIN CHANGE * */
  2927.             JLoader::import('joomla.filesystem.file');
  2928.  
  2929.             return JFile::write($outFname$out);
  2930.             /** FOF - END CHANGE * */
  2931.         }
  2932.  
  2933.         return $out;
  2934.     }
  2935.  
  2936.     /**
  2937.      * Compile only if changed input has changed or output doesn't exist
  2938.      *
  2939.      * @param   type  $in   X
  2940.      * @param   type  $out  X
  2941.      *
  2942.      * @return  boolean 
  2943.      */
  2944.     public function checkedCompile($in$out)
  2945.     {
  2946.         if (!is_file($out|| filemtime($infilemtime($out))
  2947.         {
  2948.             $this->compileFile($in$out);
  2949.  
  2950.             return true;
  2951.         }
  2952.  
  2953.         return false;
  2954.     }
  2955.  
  2956.     /**
  2957.      * Execute lessphp on a .less file or a lessphp cache structure
  2958.      *
  2959.      * The lessphp cache structure contains information about a specific
  2960.      * less file having been parsed. It can be used as a hint for future
  2961.      * calls to determine whether or not a rebuild is required.
  2962.      *
  2963.      * The cache structure contains two important keys that may be used
  2964.      * externally:
  2965.      *
  2966.      * compiled: The final compiled CSS
  2967.      * updated: The time (in seconds) the CSS was last compiled
  2968.      *
  2969.      * The cache structure is a plain-ol' PHP associative array and can
  2970.      * be serialized and unserialized without a hitch.
  2971.      *
  2972.      * @param   mixed  $in     Input
  2973.      * @param   bool   $force  Force rebuild?
  2974.      *
  2975.      * @return  array  lessphp cache structure
  2976.      */
  2977.     public function cachedCompile($in$force false)
  2978.     {
  2979.         // Assume no root
  2980.         $root null;
  2981.  
  2982.         if (is_string($in))
  2983.         {
  2984.             $root $in;
  2985.         }
  2986.         elseif (is_array($inand isset($in['root']))
  2987.         {
  2988.             if ($force or !isset($in['files']))
  2989.             {
  2990.                 /**
  2991.                  * If we are forcing a recompile or if for some reason the
  2992.                  * structure does not contain any file information we should
  2993.                  * specify the root to trigger a rebuild.
  2994.                  */
  2995.                 $root $in['root'];
  2996.             }
  2997.             elseif (isset($in['files']and is_array($in['files']))
  2998.             {
  2999.                 foreach ($in['files'as $fname => $ftime)
  3000.                 {
  3001.                     if (!file_exists($fnameor filemtime($fname$ftime)
  3002.                     {
  3003.                         /**
  3004.                          * One of the files we knew about previously has changed
  3005.                          * so we should look at our incoming root again.
  3006.                          */
  3007.                         $root $in['root'];
  3008.                         break;
  3009.                     }
  3010.                 }
  3011.             }
  3012.         }
  3013.         else
  3014.         {
  3015.             /**
  3016.              * TODO: Throw an exception? We got neither a string nor something
  3017.              * that looks like a compatible lessphp cache structure.
  3018.              */
  3019.             return null;
  3020.         }
  3021.  
  3022.         if ($root !== null)
  3023.         {
  3024.             // If we have a root value which means we should rebuild.
  3025.             $out array();
  3026.             $out['root'$root;
  3027.             $out['compiled'$this->compileFile($root);
  3028.             $out['files'$this->allParsedFiles();
  3029.             $out['updated'time();
  3030.  
  3031.             return $out;
  3032.         }
  3033.         else
  3034.         {
  3035.             // No changes, pass back the structure
  3036.             // we were given initially.
  3037.             return $in;
  3038.         }
  3039.     }
  3040.  
  3041.     //
  3042.     // This is deprecated
  3043.     /**
  3044.      * Parse and compile buffer
  3045.      *
  3046.      * @param   null  $str               X
  3047.      * @param   type  $initialVariables  X
  3048.      *
  3049.      * @return  type 
  3050.      *
  3051.      * @throws  Exception
  3052.      *
  3053.      * @deprecated  2.0
  3054.      */
  3055.     public function parse($str null$initialVariables null)
  3056.     {
  3057.         if (is_array($str))
  3058.         {
  3059.             $initialVariables $str;
  3060.             $str null;
  3061.         }
  3062.  
  3063.         $oldVars $this->registeredVars;
  3064.  
  3065.         if ($initialVariables !== null)
  3066.         {
  3067.             $this->setVariables($initialVariables);
  3068.         }
  3069.  
  3070.         if ($str == null)
  3071.         {
  3072.             if (empty($this->_parseFile))
  3073.             {
  3074.                 throw new exception("nothing to parse");
  3075.             }
  3076.  
  3077.             $out $this->compileFile($this->_parseFile);
  3078.         }
  3079.         else
  3080.         {
  3081.             $out $this->compile($str);
  3082.         }
  3083.  
  3084.         $this->registeredVars = $oldVars;
  3085.  
  3086.         return $out;
  3087.     }
  3088.  
  3089.     /**
  3090.      * Make parser
  3091.      *
  3092.      * @param   type  $name  X
  3093.      *
  3094.      * @return  FOFLessParser 
  3095.      */
  3096.     protected function makeParser($name)
  3097.     {
  3098.         /** FOF -- BEGIN CHANGE * */
  3099.         $parser new FOFLessParser($this$name);
  3100.         /** FOF -- END CHANGE * */
  3101.         $parser->writeComments $this->preserveComments;
  3102.  
  3103.         return $parser;
  3104.     }
  3105.  
  3106.     /**
  3107.      * Set Formatter
  3108.      *
  3109.      * @param   type  $name  X
  3110.      *
  3111.      * @return  void 
  3112.      */
  3113.     public function setFormatter($name)
  3114.     {
  3115.         $this->formatterName $name;
  3116.     }
  3117.  
  3118.     /**
  3119.      * New formatter
  3120.      *
  3121.      * @return  FOFLessFormatterLessjs 
  3122.      */
  3123.     protected function newFormatter()
  3124.     {
  3125.         /** FOF -- BEGIN CHANGE * */
  3126.         $className "FOFLessFormatterLessjs";
  3127.         /** FOF -- END CHANGE * */
  3128.         if (!empty($this->formatterName))
  3129.         {
  3130.             if (!is_string($this->formatterName))
  3131.                 return $this->formatterName;
  3132.             /** FOF -- BEGIN CHANGE * */
  3133.             $className "FOFLessFormatter" ucfirst($this->formatterName);
  3134.             /** FOF -- END CHANGE * */
  3135.         }
  3136.  
  3137.         return new $className;
  3138.     }
  3139.  
  3140.     /**
  3141.      * Set preserve comments
  3142.      *
  3143.      * @param   type  $preserve  X
  3144.      *
  3145.      * @return  void 
  3146.      */
  3147.     public function setPreserveComments($preserve)
  3148.     {
  3149.         $this->preserveComments = $preserve;
  3150.     }
  3151.  
  3152.     /**
  3153.      * Register function
  3154.      *
  3155.      * @param   type  $name  X
  3156.      * @param   type  $func  X
  3157.      *
  3158.      * @return  void 
  3159.      */
  3160.     public function registerFunction($name$func)
  3161.     {
  3162.         $this->libFunctions[$name$func;
  3163.     }
  3164.  
  3165.     /**
  3166.      * Unregister function
  3167.      *
  3168.      * @param   type  $name  X
  3169.      *
  3170.      * @return  void 
  3171.      */
  3172.     public function unregisterFunction($name)
  3173.     {
  3174.         unset($this->libFunctions[$name]);
  3175.     }
  3176.  
  3177.     /**
  3178.      * Set variables
  3179.      *
  3180.      * @param   type  $variables  X
  3181.      *
  3182.      * @return  void 
  3183.      */
  3184.     public function setVariables($variables)
  3185.     {
  3186.         $this->registeredVars = array_merge($this->registeredVars$variables);
  3187.     }
  3188.  
  3189.     /**
  3190.      * Unset variable
  3191.      *
  3192.      * @param   type  $name  X
  3193.      *
  3194.      * @return  void 
  3195.      */
  3196.     public function unsetVariable($name)
  3197.     {
  3198.         unset($this->registeredVars[$name]);
  3199.     }
  3200.  
  3201.     /**
  3202.      * Set import dir
  3203.      *
  3204.      * @param   type  $dirs  X
  3205.      *
  3206.      * @return  void 
  3207.      */
  3208.     public function setImportDir($dirs)
  3209.     {
  3210.         $this->importDir = (array) $dirs;
  3211.     }
  3212.  
  3213.     /**
  3214.      * Add import dir
  3215.      *
  3216.      * @param   type  $dir  X
  3217.      *
  3218.      * @return  void 
  3219.      */
  3220.     public function addImportDir($dir)
  3221.     {
  3222.         $this->importDir = (array) $this->importDir;
  3223.         $this->importDir[$dir;
  3224.     }
  3225.  
  3226.     /**
  3227.      * All parsed files
  3228.      *
  3229.      * @return  type 
  3230.      */
  3231.     public function allParsedFiles()
  3232.     {
  3233.         return $this->allParsedFiles;
  3234.     }
  3235.  
  3236.     /**
  3237.      * Add parsed file
  3238.      *
  3239.      * @param   type  $file  X
  3240.      *
  3241.      * @return  void 
  3242.      */
  3243.     protected function addParsedFile($file)
  3244.     {
  3245.         $this->allParsedFiles[realpath($file)filemtime($file);
  3246.     }
  3247.  
  3248.     /**
  3249.      * Uses the current value of $this->count to show line and line number
  3250.      *
  3251.      * @param   type  $msg  X
  3252.      *
  3253.      * @return  void 
  3254.      */
  3255.     protected function throwError($msg null)
  3256.     {
  3257.         if ($this->sourceLoc >= 0)
  3258.         {
  3259.             $this->sourceParser->throwError($msg$this->sourceLoc);
  3260.         }
  3261.  
  3262.         throw new exception($msg);
  3263.     }
  3264.  
  3265.     /**
  3266.      * Compile file $in to file $out if $in is newer than $out
  3267.      * Returns true when it compiles, false otherwise
  3268.      *
  3269.      * @param   type  $in    X
  3270.      * @param   type  $out   X
  3271.      * @param   self  $less  X
  3272.      *
  3273.      * @return  type 
  3274.      */
  3275.     public static function ccompile($in$out$less null)
  3276.     {
  3277.         if ($less === null)
  3278.         {
  3279.             $less new self;
  3280.         }
  3281.  
  3282.         return $less->checkedCompile($in$out);
  3283.     }
  3284.  
  3285.     /**
  3286.      * Compile execute
  3287.      *
  3288.      * @param   type  $in     X
  3289.      * @param   type  $force  X
  3290.      * @param   self  $less   X
  3291.      *
  3292.      * @return  type 
  3293.      */
  3294.     public static function cexecute($in$force false$less null)
  3295.     {
  3296.         if ($less === null)
  3297.         {
  3298.             $less new self;
  3299.         }
  3300.  
  3301.         return $less->cachedCompile($in$force);
  3302.     }
  3303.  
  3304.     protected static $cssColors array(
  3305.         'aliceblue'                 => '240,248,255',
  3306.         'antiquewhite'             => '250,235,215',
  3307.         'aqua'                     => '0,255,255',
  3308.         'aquamarine'             => '127,255,212',
  3309.         'azure'                     => '240,255,255',
  3310.         'beige'                     => '245,245,220',
  3311.         'bisque'                 => '255,228,196',
  3312.         'black'                     => '0,0,0',
  3313.         'blanchedalmond'         => '255,235,205',
  3314.         'blue'                     => '0,0,255',
  3315.         'blueviolet'             => '138,43,226',
  3316.         'brown'                     => '165,42,42',
  3317.         'burlywood'                 => '222,184,135',
  3318.         'cadetblue'                 => '95,158,160',
  3319.         'chartreuse'             => '127,255,0',
  3320.         'chocolate'                 => '210,105,30',
  3321.         'coral'                     => '255,127,80',
  3322.         'cornflowerblue'         => '100,149,237',
  3323.         'cornsilk'                 => '255,248,220',
  3324.         'crimson'                 => '220,20,60',
  3325.         'cyan'                     => '0,255,255',
  3326.         'darkblue'                 => '0,0,139',
  3327.         'darkcyan'                 => '0,139,139',
  3328.         'darkgoldenrod'             => '184,134,11',
  3329.         'darkgray'                 => '169,169,169',
  3330.         'darkgreen'                 => '0,100,0',
  3331.         'darkgrey'                 => '169,169,169',
  3332.         'darkkhaki'                 => '189,183,107',
  3333.         'darkmagenta'             => '139,0,139',
  3334.         'darkolivegreen'         => '85,107,47',
  3335.         'darkorange'             => '255,140,0',
  3336.         'darkorchid'             => '153,50,204',
  3337.         'darkred'                 => '139,0,0',
  3338.         'darksalmon'             => '233,150,122',
  3339.         'darkseagreen'             => '143,188,143',
  3340.         'darkslateblue'             => '72,61,139',
  3341.         'darkslategray'             => '47,79,79',
  3342.         'darkslategrey'             => '47,79,79',
  3343.         'darkturquoise'             => '0,206,209',
  3344.         'darkviolet'             => '148,0,211',
  3345.         'deeppink'                 => '255,20,147',
  3346.         'deepskyblue'             => '0,191,255',
  3347.         'dimgray'                 => '105,105,105',
  3348.         'dimgrey'                 => '105,105,105',
  3349.         'dodgerblue'             => '30,144,255',
  3350.         'firebrick'                 => '178,34,34',
  3351.         'floralwhite'             => '255,250,240',
  3352.         'forestgreen'             => '34,139,34',
  3353.         'fuchsia'                 => '255,0,255',
  3354.         'gainsboro'                 => '220,220,220',
  3355.         'ghostwhite'             => '248,248,255',
  3356.         'gold'                     => '255,215,0',
  3357.         'goldenrod'                 => '218,165,32',
  3358.         'gray'                     => '128,128,128',
  3359.         'green'                     => '0,128,0',
  3360.         'greenyellow'             => '173,255,47',
  3361.         'grey'                     => '128,128,128',
  3362.         'honeydew'                 => '240,255,240',
  3363.         'hotpink'                 => '255,105,180',
  3364.         'indianred'                 => '205,92,92',
  3365.         'indigo'                 => '75,0,130',
  3366.         'ivory'                     => '255,255,240',
  3367.         'khaki'                     => '240,230,140',
  3368.         'lavender'                 => '230,230,250',
  3369.         'lavenderblush'             => '255,240,245',
  3370.         'lawngreen'                 => '124,252,0',
  3371.         'lemonchiffon'             => '255,250,205',
  3372.         'lightblue'                 => '173,216,230',
  3373.         'lightcoral'             => '240,128,128',
  3374.         'lightcyan'                 => '224,255,255',
  3375.         'lightgoldenrodyellow'     => '250,250,210',
  3376.         'lightgray'                 => '211,211,211',
  3377.         'lightgreen'             => '144,238,144',
  3378.         'lightgrey'                 => '211,211,211',
  3379.         'lightpink'                 => '255,182,193',
  3380.         'lightsalmon'             => '255,160,122',
  3381.         'lightseagreen'             => '32,178,170',
  3382.         'lightskyblue'             => '135,206,250',
  3383.         'lightslategray'         => '119,136,153',
  3384.         'lightslategrey'         => '119,136,153',
  3385.         'lightsteelblue'         => '176,196,222',
  3386.         'lightyellow'             => '255,255,224',
  3387.         'lime'                     => '0,255,0',
  3388.         'limegreen'                 => '50,205,50',
  3389.         'linen'                     => '250,240,230',
  3390.         'magenta'                 => '255,0,255',
  3391.         'maroon'                 => '128,0,0',
  3392.         'mediumaquamarine'         => '102,205,170',
  3393.         'mediumblue'             => '0,0,205',
  3394.         'mediumorchid'             => '186,85,211',
  3395.         'mediumpurple'             => '147,112,219',
  3396.         'mediumseagreen'         => '60,179,113',
  3397.         'mediumslateblue'         => '123,104,238',
  3398.         'mediumspringgreen'         => '0,250,154',
  3399.         'mediumturquoise'         => '72,209,204',
  3400.         'mediumvioletred'         => '199,21,133',
  3401.         'midnightblue'             => '25,25,112',
  3402.         'mintcream'                 => '245,255,250',
  3403.         'mistyrose'                 => '255,228,225',
  3404.         'moccasin'                 => '255,228,181',
  3405.         'navajowhite'             => '255,222,173',
  3406.         'navy'                     => '0,0,128',
  3407.         'oldlace'                 => '253,245,230',
  3408.         'olive'                     => '128,128,0',
  3409.         'olivedrab'                 => '107,142,35',
  3410.         'orange'                 => '255,165,0',
  3411.         'orangered'                 => '255,69,0',
  3412.         'orchid'                 => '218,112,214',
  3413.         'palegoldenrod'             => '238,232,170',
  3414.         'palegreen'                 => '152,251,152',
  3415.         'paleturquoise'             => '175,238,238',
  3416.         'palevioletred'             => '219,112,147',
  3417.         'papayawhip'             => '255,239,213',
  3418.         'peachpuff'                 => '255,218,185',
  3419.         'peru'                     => '205,133,63',
  3420.         'pink'                     => '255,192,203',
  3421.         'plum'                     => '221,160,221',
  3422.         'powderblue'             => '176,224,230',
  3423.         'purple'                 => '128,0,128',
  3424.         'red'                     => '255,0,0',
  3425.         'rosybrown'                 => '188,143,143',
  3426.         'royalblue'                 => '65,105,225',
  3427.         'saddlebrown'             => '139,69,19',
  3428.         'salmon'                 => '250,128,114',
  3429.         'sandybrown'             => '244,164,96',
  3430.         'seagreen'                 => '46,139,87',
  3431.         'seashell'                 => '255,245,238',
  3432.         'sienna'                 => '160,82,45',
  3433.         'silver'                 => '192,192,192',
  3434.         'skyblue'                 => '135,206,235',
  3435.         'slateblue'                 => '106,90,205',
  3436.         'slategray'                 => '112,128,144',
  3437.         'slategrey'                 => '112,128,144',
  3438.         'snow'                     => '255,250,250',
  3439.         'springgreen'             => '0,255,127',
  3440.         'steelblue'                 => '70,130,180',
  3441.         'tan'                     => '210,180,140',
  3442.         'teal'                     => '0,128,128',
  3443.         'thistle'                 => '216,191,216',
  3444.         'tomato'                 => '255,99,71',
  3445.         'transparent'             => '0,0,0,0',
  3446.         'turquoise'                 => '64,224,208',
  3447.         'violet'                 => '238,130,238',
  3448.         'wheat'                     => '245,222,179',
  3449.         'white'                     => '255,255,255',
  3450.         'whitesmoke'             => '245,245,245',
  3451.         'yellow'                 => '255,255,0',
  3452.         'yellowgreen'             => '154,205,50'
  3453.     );
  3454. }

Documentation generated on Tue, 19 Nov 2013 15:06:58 +0100 by phpDocumentor 1.4.3