.gitignore000066400000000000000000000003421516067305400130540ustar00rootroot00000000000000cache/ *.diff *.err *.orig *.log *.rej *.swo *.swp *.zip *.vi *~ *.sass-cache .DS_Store ._* Thumbs.db .cache .project .settings .tmproj *.esproj nbproject *.sublime-project *.sublime-workspace .hg .svn .CVS .idea node_modules .htaccess000066400000000000000000000003361516067305400126650ustar00rootroot00000000000000 Options -MultiViews RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] order allow,deny deny from all .travis.yml000066400000000000000000000000631516067305400131750ustar00rootroot00000000000000language: php php: - 5.3 - 5.4 script: phpunit LICENSE.txt000066400000000000000000000027051516067305400127140ustar00rootroot00000000000000Copyright (c) 2012, Klaus Silveira and contributors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of GitList nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. README.md000066400000000000000000000065461516067305400123570ustar00rootroot00000000000000# GitList: an elegant and modern git repository viewer [![Build Status](https://secure.travis-ci.org/klaussilveira/gitlist.png)](http://travis-ci.org/klaussilveira/gitlist) GitList is an elegant and modern web interface for interacting with multiple git repositories. It allows you to browse repositories using your favorite browser, viewing files under different revisions, commit history, diffs. It also generates RSS feeds for each repository, allowing you to stay up-to-date with the latest changes anytime, anywhere. GitList was written in PHP, on top of the [Silex](http://silex.sensiolabs.org/) microframework and powered by the Twig template engine. This means that GitList is easy to install and easy to customize. Also, the GitList gorgeous interface was made possible due to [Bootstrap](http://twitter.github.com/bootstrap/). ## Features * Multiple repository support * Multiple branch support * Multiple tag support * Commit history, blame, diff * RSS feeds * Syntax highlighting * Repository statistics ## Screenshots [![GitList Screenshot](http://dl.dropbox.com/u/62064441/th1.jpg)](http://cloud.github.com/downloads/klaussilveira/gitlist/1.jpg) [![GitList Screenshot](http://dl.dropbox.com/u/62064441/th2.jpg)](http://cloud.github.com/downloads/klaussilveira/gitlist/2.jpg) [![GitList Screenshot](http://dl.dropbox.com/u/62064441/th3.jpg)](http://cloud.github.com/downloads/klaussilveira/gitlist/3.jpg) [![GitList Screenshot](http://dl.dropbox.com/u/62064441/th4.jpg)](http://cloud.github.com/downloads/klaussilveira/gitlist/4.jpg) [![GitList Screenshot](http://dl.dropbox.com/u/62064441/th5.jpg)](http://cloud.github.com/downloads/klaussilveira/gitlist/5.jpg) You can also see a live demo [here](http://git.gofedora.com). ## Authors and contributors * [Klaus Silveira](http://www.klaussilveira.com) (Creator, developer) ## License [New BSD license](http://www.opensource.org/licenses/bsd-license.php) ## Todo * improve the current test code coverage * test the interface * error handling can be greatly improved during parsing * submodule support * multilanguage support ## Requirements In order to run GitList on your server, you'll need: * git * Apache and mod_rewrite enabled * PHP 5.3.3 ## Installing Download the GitList latest package and decompress to your `/var/www/gitlist` folder, or anywhere else you want to place GitList. You can also clone the repository: ``` git clone https://github.com/klaussilveira/gitlist.git /var/www/gitlist ``` Now open up the `config.ini` and configure your installation. You'll have to provide where your repositories are located and the base GitList URL (in our case, http://localhost/gitlist). Now, let's create the cache folder and give the correct permissions: ``` cd /var/www/gitlist mkdir cache chmod 777 cache ``` That's it, installation complete! If you're having problems, check this [tutorial](http://gofedora.com/insanely-awesome-web-interface-git-repos/) by Kulbir Saini or the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page. ## Further information If you want to know more about customizing GitList, check the [Customization](https://github.com/klaussilveira/gitlist/wiki/Customizing) page on the wiki. Also, if you're having problems with GitList, check the [Troubleshooting](https://github.com/klaussilveira/gitlist/wiki/Troubleshooting) page. Don't forget to report issues and suggest new features! :) config.ini000066400000000000000000000003461516067305400130360ustar00rootroot00000000000000[git] client = '/usr/bin/git' ; Your git executable path repositories = '/home/git/' ; Path to your repositories (with ending slash) [app] baseurl = 'http://localhost/gitlist' ; Base URL of the application (without ending slash) controllers/000077500000000000000000000000001516067305400134335ustar00rootroot00000000000000controllers/blobController.php000066400000000000000000000024721516067305400171330ustar00rootroot00000000000000get('{repo}/blob/{branch}/{file}/', function($repo, $branch, $file) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $blob = $repository->getBlob("$branch:$file"); $breadcrumbs = $app['utils']->getBreadcrumbs("$repo/tree/$branch/$file"); $fileType = $app['utils']->getFileType($file); return $app['twig']->render('file.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'files', 'file' => $file, 'fileType' => $fileType, 'blob' => $blob->output(), 'repo' => $repo, 'branch' => $branch, 'breadcrumbs' => $breadcrumbs, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), )); })->assert('file', '.+') ->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+'); $app->get('{repo}/raw/{branch}/{file}', function($repo, $branch, $file) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $blob = $repository->getBlob("$branch:$file")->output(); return new Symfony\Component\HttpFoundation\Response($blob, 200, array('Content-Type' => 'text/plain')); })->assert('file', '.+') ->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+');controllers/commitController.php000066400000000000000000000061601516067305400175030ustar00rootroot00000000000000get('{repo}/commits/{branch}', function($repo, $branch) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $pager = $app['utils']->getPager($app['request']->get('page'), $repository->getTotalCommits()); $commits = $repository->getCommits($branch, $pager['current']); foreach ($commits as $commit) { $date = $commit->getDate(); $date = $date->format('m/d/Y'); $categorized[$date][] = $commit; } return $app['twig']->render('commits.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'commits', 'pager' => $pager, 'repo' => $repo, 'branch' => $branch, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), 'commits' => $categorized, )); })->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+') ->value('branch', 'master'); $app->get('{repo}/commits/{branch}/{file}/', function($repo, $branch, $file) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $pager = $app['utils']->getPager($app['request']->get('page'), $repository->getTotalCommits($file)); $commits = $repository->getCommits($file, $pager['current']); foreach ($commits as $commit) { $date = $commit->getDate(); $date = $date->format('m/d/Y'); $categorized[$date][] = $commit; } return $app['twig']->render('commits.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'commits', 'pager' => $pager, 'repo' => $repo, 'branch' => $branch, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), 'commits' => $categorized, )); })->assert('repo', '[\w-._]+') ->assert('file', '.+') ->assert('branch', '[\w-._]+'); $app->get('{repo}/commit/{commit}/', function($repo, $commit) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $commit = $repository->getCommit($commit); return $app['twig']->render('commit.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'commits', 'branch' => 'master', 'repo' => $repo, 'commit' => $commit, )); })->assert('repo', '[\w-._]+') ->assert('commit', '[a-f0-9]+'); $app->get('{repo}/blame/{branch}/{file}/', function($repo, $branch, $file) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $blames = $repository->getBlame($file); return $app['twig']->render('blame.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'commits', 'file' => $file, 'repo' => $repo, 'branch' => $branch, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), 'blames' => $blames, )); })->assert('repo', '[\w-._]+') ->assert('file', '.+') ->assert('branch', '[\w-._]+'); controllers/indexController.php000066400000000000000000000004131516067305400173150ustar00rootroot00000000000000get('/', function() use($app) { $repositories = $app['git']->getRepositories($app['git.repos']); return $app['twig']->render('index.twig', array( 'baseurl' => $app['baseurl'], 'repositories' => $repositories, )); });controllers/rssController.php000066400000000000000000000011271516067305400170200ustar00rootroot00000000000000get('{repo}/{branch}/rss/', function($repo, $branch) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $commits = $repository->getCommits($branch); $html = $app['twig']->render('rss.twig', array( 'baseurl' => $app['baseurl'], 'repo' => $repo, 'branch' => $branch, 'commits' => $commits, )); return new Symfony\Component\HttpFoundation\Response($html, 200, array('Content-Type' => 'application/rss+xml')); })->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+');controllers/statsController.php000066400000000000000000000013521516067305400173470ustar00rootroot00000000000000get('{repo}/stats/{branch}', function($repo, $branch) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $stats = $repository->getStatistics($branch); $authors = $repository->getAuthorStatistics(); return $app['twig']->render('stats.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'stats', 'repo' => $repo, 'branch' => $branch, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), 'stats' => $stats, 'authors' => $authors, )); })->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+') ->value('branch', 'master');controllers/treeController.php000066400000000000000000000047531516067305400171600ustar00rootroot00000000000000get('{repo}/', function($repo) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $tree = $repository->getTree('master'); $breadcrumbs = $app['utils']->getBreadcrumbs("$repo/"); return $app['twig']->render('tree.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'files', 'files' => $tree->output(), 'repo' => $repo, 'branch' => 'master', 'path' => '', 'parent' => '', 'breadcrumbs' => $breadcrumbs, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), )); })->assert('repo', '[\w-._]+'); $app->get('{repo}/tree/{branch}/', function($repo, $branch) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $tree = $repository->getTree($branch); $breadcrumbs = $app['utils']->getBreadcrumbs("$repo/"); return $app['twig']->render('tree.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'files', 'files' => $tree->output(), 'repo' => $repo, 'branch' => $branch, 'path' => '', 'parent' => '', 'breadcrumbs' => $breadcrumbs, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), )); })->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+'); $app->get('{repo}/tree/{branch}/{tree}/', function($repo, $branch, $tree) use($app) { $repository = $app['git']->getRepository($app['git.repos'] . $repo); $files = $repository->getTree("$branch:$tree/"); $breadcrumbs = $app['utils']->getBreadcrumbs("$repo/tree/$branch/$tree"); if (($slash = strrpos($tree, '/')) !== false) { $parent = '/' . substr($tree, 0, $slash); } else { $parent = '/'; } return $app['twig']->render('tree.twig', array( 'baseurl' => $app['baseurl'], 'page' => 'files', 'files' => $files->output(), 'repo' => $repo, 'branch' => $branch, 'path' => "$tree/", 'parent' => $parent, 'breadcrumbs' => $breadcrumbs, 'branches' => $repository->getBranches(), 'tags' => $repository->getTags(), )); })->assert('tree', '.+') ->assert('repo', '[\w-._]+') ->assert('branch', '[\w-._]+');index.php000066400000000000000000000030761516067305400127130ustar00rootroot00000000000000registerNamespace('Git', __DIR__.'/lib'); $app['autoloader']->registerNamespace('Application', __DIR__.'/lib'); $app->register(new Silex\Provider\TwigServiceProvider(), array( 'twig.path' => __DIR__.'/views', 'twig.class_path' => __DIR__.'/vendor', 'twig.options' => array('cache' => __DIR__.'/cache'), )); $app->register(new Git\GitServiceProvider(), array( 'git.client' => $config['git']['client'], 'git.repos' => $config['git']['repositories'], )); $app->register(new Application\UtilsServiceProvider()); // Add the md5() function to Twig scope $app['twig']->addFilter('md5', new Twig_Filter_Function('md5')); // Load controllers include 'controllers/indexController.php'; include 'controllers/treeController.php'; include 'controllers/blobController.php'; include 'controllers/commitController.php'; include 'controllers/statsController.php'; include 'controllers/rssController.php'; // Error handling $app->error(function (\Exception $e, $code) use ($app) { return $app['twig']->render('error.twig', array( 'baseurl' => $app['baseurl'], 'message' => $e->getMessage(), )); }); $app->run(); lib/000077500000000000000000000000001516067305400116335ustar00rootroot00000000000000lib/Application/000077500000000000000000000000001516067305400140765ustar00rootroot00000000000000lib/Application/Utils.php000066400000000000000000000146761516067305400157250ustar00rootroot00000000000000 $pageNumber, 'next' => $nextPage, 'previous' => $previousPage, 'last' => $lastPage, 'total' => $totalCommits, ); } }lib/Application/UtilsServiceProvider.php000066400000000000000000000007571516067305400207540ustar00rootroot00000000000000setPath($path); } /** * Creates a new repository on the specified path * * @param string $path Path where the new repository will be created * @return Repository Instance of Repository */ public function createRepository($path) { if (file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) { throw new \RuntimeException('A GIT repository already exists at ' . $path); } $repository = new Repository($path, $this); return $repository->create(); } /** * Opens a repository at the specified path * * @param string $path Path where the repository is located * @return Repository Instance of Repository */ public function getRepository($path) { if (!file_exists($path) || !file_exists($path . '/.git/HEAD') && !file_exists($path . '/HEAD')) { throw new \RuntimeException('There is no GIT repository at ' . $path); } return new Repository($path, $this); } /** * Searches for valid repositories on the specified path * * @param string $path Path where repositories will be searched * @return array Found repositories, containing their name, path and description */ public function getRepositories($path) { $repositories = $this->recurseDirectory($path); if (empty($repositories)) { throw new \RuntimeException('There are no GIT repositories in ' . $path); } sort($repositories); return $repositories; } private function recurseDirectory($path) { $dir = new \DirectoryIterator($path); $repositories = array(); foreach ($dir as $file) { if ($file->isDot()) { continue; } if (($pos = strrpos($file->getFilename(), '.')) === 0) { continue; } $isBare = file_exists($file->getPathname() . '/HEAD'); $isRepository = file_exists($file->getPathname() . '/.git/HEAD'); if ($file->isDir() && $isRepository || $isBare) { if ($isBare) { $description = file_get_contents($file->getPathname() . '/description'); } else { $description = file_get_contents($file->getPathname() . '/.git/description'); } $repositories[] = array('name' => $file->getFilename(), 'path' => $file->getPathname(), 'description' => $description); continue; } } return $repositories; } /** * Execute a git command on the repository being manipulated * * This method will start a new process on the current machine and * run git commands. Once the command has been run, the method will * return the command line output. * * @param Repository $repository Repository where the command will be run * @param string $command Git command to be run * @return string Returns the command output */ public function run(Repository $repository, $command) { $descriptors = array(0 => array("pipe", "r"), 1 => array("pipe", "w")); $process = proc_open($this->getPath() . ' ' . $command, $descriptors, $pipes, $repository->getPath()); if (is_resource($process)) { $stdout = stream_get_contents($pipes[1]); fclose($pipes[1]); proc_close($process); return $stdout; } } /** * Get the current Git binary path * * @return string Path where the Git binary is located */ protected function getPath() { return $this->path; } /** * Set the current Git binary path * * @param string $path Path where the Git binary is located */ protected function setPath($path) { $this->path = $path; } } lib/Git/Commit/000077500000000000000000000000001516067305400136065ustar00rootroot00000000000000lib/Git/Commit/Author.php000066400000000000000000000010031516067305400155530ustar00rootroot00000000000000setName($name); $this->setEmail($email); } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function getEmail() { return $this->email; } public function setEmail($email) { $this->email = $email; } }lib/Git/Commit/Commit.php000066400000000000000000000052501516067305400155510ustar00rootroot00000000000000setHash($data['hash']); $this->setShortHash($data['short_hash']); $this->setTreeHash($data['tree']); $this->setParentHash($data['parent']); $this->setAuthor( new Author($data['author'], $data['author_email']) ); $this->setDate( new \DateTime('@' . $data['date']) ); $this->setCommiter( new Author($data['commiter'], $data['commiter_email']) ); $this->setCommiterDate( new \DateTime('@' . $data['commiter_date']) ); $this->setMessage($data['message']); } public function getHash() { return $this->hash; } public function setHash($hash) { $this->hash = $hash; } public function getShortHash() { return $this->shortHash; } public function setShortHash($shortHash) { $this->shortHash = $shortHash; } public function getTreeHash() { return $this->treeHash; } public function setTreeHash($treeHash) { $this->treeHash = $treeHash; } public function getParentHash() { return $this->parentHash; } public function setParentHash($parentHash) { $this->parentHash = $parentHash; } public function getAuthor() { return $this->author; } public function setAuthor($author) { $this->author = $author; } public function getDate() { return $this->date; } public function setDate($date) { $this->date = $date; } public function getCommiter() { return $this->commiter; } public function setCommiter($commiter) { $this->commiter = $commiter; } public function getCommiterDate() { return $this->commiterDate; } public function setCommiterDate($commiterDate) { $this->commiterDate = $commiterDate; } public function getMessage() { return $this->message; } public function setMessage($message) { $this->message = $message; } public function getDiffs() { return $this->diffs; } public function setDiffs($diffs) { $this->diffs = $diffs; } public function getChangedFiles() { return sizeof($this->diffs); } }lib/Git/GitServiceProvider.php000066400000000000000000000011141516067305400166430ustar00rootroot00000000000000setClient($client); $this->setRepository($repository); $this->setHash($hash); } public function output() { $data = $this->getClient()->run($this->getRepository(), 'show ' . $this->getHash()); return $data; } public function getMode() { return $this->mode; } public function setMode($mode) { $this->mode = $mode; } public function getHash() { return $this->hash; } public function setHash($hash) { $this->hash = $hash; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function getSize() { return $this->size; } public function setSize($size) { $this->size = $size; } }lib/Git/Model/Diff.php000066400000000000000000000015601516067305400150010ustar00rootroot00000000000000lines[] = new Line($line); } public function getLines() { return $this->lines; } public function setIndex($index) { $this->index = $index; } public function getIndex() { return $this->index; } public function setOld($old) { $this->old = $old; } public function getOld() { return $this->old; } public function setNew($new) { $this->new = $new; $this->file = substr($new, 6); } public function getNew() { return $this->new; } public function getFile() { return $this->file; } }lib/Git/Model/Line.php000066400000000000000000000014041516067305400150150ustar00rootroot00000000000000setType('chunk'); } if ($data[0] == '-') { $this->setType('old'); } if ($data[0] == '+') { $this->setType('new'); } } $this->setLine($data); } public function getLine() { return $this->line; } public function setLine($line) { $this->line = $line; } public function getType() { return $this->type; } public function setType($type) { $this->type = $type; } }lib/Git/Model/Symlink.php000066400000000000000000000011421516067305400155530ustar00rootroot00000000000000mode; } public function setMode($mode) { $this->mode = $mode; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function getPath() { return $this->path; } public function setPath($path) { $this->path = $path; } }lib/Git/Model/Tree.php000066400000000000000000000104001516067305400150210ustar00rootroot00000000000000setClient($client); $this->setRepository($repository); $this->setHash($hash); } public function parse() { $data = $this->getClient()->run($this->getRepository(), 'ls-tree -l ' . $this->getHash()); $lines = explode("\n", $data); $files = array(); $root = array(); foreach ($lines as $key => $line) { if (empty($line)) { unset($lines[$key]); continue; } $files[] = preg_split("/[\s]+/", $line); } foreach ($files as $file) { if ($file[1] == 'commit') { // submodule continue; } if ($file[0] == '120000') { $show = $this->getClient()->run($this->getRepository(), 'show ' . $file[2]); $tree = new Symlink; $tree->setMode($file[0]); $tree->setName($file[4]); $tree->setPath($show); $root[] = $tree; continue; } if ($file[1] == 'blob') { $blob = new Blob($file[2], $this->getClient(), $this->getRepository()); $blob->setMode($file[0]); $blob->setName($file[4]); $blob->setSize($file[3]); $root[] = $blob; continue; } $tree = new Tree($file[2], $this->getClient(), $this->getRepository()); $tree->setMode($file[0]); $tree->setName($file[4]); $root[] = $tree; } $this->data = $root; } public function output() { $files = $folders = array(); foreach ($this as $node) { if ($node instanceof Blob) { $file['type'] = 'blob'; $file['name'] = $node->getName(); $file['size'] = $node->getSize(); $file['mode'] = $node->getMode(); $file['hash'] = $node->getHash(); $files[] = $file; continue; } if ($node instanceof Tree) { $folder['type'] = 'folder'; $folder['name'] = $node->getName(); $folder['size'] = ''; $folder['mode'] = $node->getMode(); $folder['hash'] = $node->getHash(); $folders[] = $folder; continue; } if ($node instanceof Symlink) { $folder['type'] = 'symlink'; $folder['name'] = $node->getName(); $folder['size'] = ''; $folder['mode'] = $node->getMode(); $folder['hash'] = ''; $folder['path'] = $node->getPath(); $folders[] = $folder; } } // Little hack to make folders appear before files $files = array_merge($folders, $files); return $files; } public function valid() { return isset($this->data[$this->position]); } public function hasChildren() { return is_array($this->data[$this->position]); } public function next() { $this->position++; } public function current() { return $this->data[$this->position]; } public function getChildren() { return $this->data[$this->position]; } public function rewind() { $this->position = 0; } public function key() { return $this->position; } public function getMode() { return $this->mode; } public function setMode($mode) { $this->mode = $mode; } public function getHash() { return $this->hash; } public function setHash($hash) { $this->hash = $hash; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } }lib/Git/Repository.php000066400000000000000000000306561516067305400152600ustar00rootroot00000000000000setPath($path); $this->setClient($client); } public function setClient(Client $client) { $this->client = $client; } public function getClient() { return $this->client; } public function create() { mkdir($this->getPath()); $this->getClient()->run($this, 'init'); return $this; } public function getConfig($key) { $key = $this->getClient()->run($this, 'config ' . $key); return trim($key); } public function setConfig($key, $value) { $this->getClient()->run($this, "config $key \"$value\""); return $this; } /** * Add untracked files * * @access public * @param mixed $files Files to be added to the repository */ public function add($files = '.') { if(is_array($files)) { $files = implode(' ', $files); } $this->getClient()->run($this, "add $files"); return $this; } /** * Add all untracked files * * @access public */ public function addAll() { $this->getClient()->run($this, "add -A"); return $this; } /** * Commit changes to the repository * * @access public * @param string $message Description of the changes made */ public function commit($message) { $this->getClient()->run($this, "commit -m '$message'"); return $this; } /** * Checkout a branch * * @access public * @param string $branch Branch to be checked out */ public function checkout($branch) { $this->getClient()->run($this, "checkout $branch"); return $this; } /** * Pull repository changes * * @access public */ public function pull() { $this->getClient()->run($this, "pull"); return $this; } /** * Update remote references * * @access public * @param string $repository Repository to be pushed * @param string $refspec Refspec for the push */ public function push($repository = null, $refspec = null) { $command = "push"; if($repository) { $command .= " $repository"; } if($refspec) { $command .= " $refspec"; } $this->getClient()->run($this, $command); return $this; } /** * Show a list of the repository branches * * @access public * @return array List of branches */ public function getBranches() { $branches = $this->getClient()->run($this, "branch"); $branches = explode("\n", $branches); $branches = array_filter(preg_replace('/[\*\s]/', '', $branches)); return $branches; } /** * Show the current repository branch * * @access public * @return string Current repository branch */ public function getCurrentBranch() { $branches = $this->getClient()->run($this, "branch"); $branches = explode("\n", $branches); foreach($branches as $branch) { if($branch[0] == '*') { return substr($branch, 2); } } } /** * Check if a specified branch exists * * @access public * @param string $branch Branch to be checked * @return boolean True if the branch exists */ public function hasBranch($branch) { $branches = $this->getBranches(); $status = in_array($branch, $branches); return $status; } /** * Create a new repository branch * * @access public * @param string $branch Branch name */ public function createBranch($branch) { $this->getClient()->run($this, "branch $branch"); } /** * Show a list of the repository tags * * @access public * @return array List of tags */ public function getTags() { $tags = $this->getClient()->run($this, "tag"); $tags = explode("\n", $tags); if (empty($tags[0])) { return NULL; } return $tags; } /** * Show the amount of commits on the repository * * @access public * @return integer Total number of commits */ public function getTotalCommits($file = null) { $command = "rev-list --all --count"; if ($file) { $command .= " $file"; } $commits = $this->getClient()->run($this, $command); return $commits; } /** * Show the repository commit log * * @access public * @return array Commit log */ public function getCommits($file = null, $page = 0) { $page = 15 * $page; $pager = "--skip=$page --max-count=15"; $command = 'log ' . $pager . ' --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\''; if ($file) { $command .= " $file"; } $logs = $this->getClient()->run($this, $command); if (empty($logs)) { throw new \RuntimeException('No commit log available'); } $logs = str_replace("\n", ',', $logs); $logs = json_decode("{ $logs }", true); foreach ($logs as $log) { $log['message'] = str_replace('-', ' ', $log['message']); $commit = new Commit; $commit->importData($log); $commits[] = $commit; } return $commits; } public function getRelatedCommits($hash) { $logs = $this->getClient()->run($this, 'log --pretty=format:\'"%h": {"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\''); if (empty($logs)) { throw new \RuntimeException('No commit log available'); } $logs = str_replace("\n", ',', $logs); $logs = json_decode("{ $logs }", true); foreach ($logs as $log) { $log['message'] = str_replace('-', ' ', $log['message']); $logTree = $this->getClient()->run($this, 'diff-tree -t -r ' . $log['hash']); $lines = explode("\n", $logTree); array_shift($lines); $files = array(); foreach ($lines as $key => $line) { if (empty($line)) { unset($lines[$key]); continue; } $files[] = preg_split("/[\s]+/", $line); } // Now let's find the commits who have our hash within them foreach ($files as $file) { if ($file[1] == 'commit') { continue; } if ($file[3] == $hash) { $commit = new Commit; $commit->importData($log); $commits[] = $commit; break; } } } return $commits; } public function getCommit($commit) { $logs = $this->getClient()->run($this, 'show --pretty=format:\'{"hash": "%H", "short_hash": "%h", "tree": "%T", "parent": "%P", "author": "%an", "author_email": "%ae", "date": "%at", "commiter": "%cn", "commiter_email": "%ce", "commiter_date": "%ct", "message": "%f"}\' ' . $commit); if (empty($logs)) { throw new \RuntimeException('No commit log available'); } $logs = explode("\n", $logs); // Read commit metadata $data = json_decode($logs[0], true); $data['message'] = str_replace('-', ' ', $data['message']); $commit = new Commit; $commit->importData($data); unset($logs[0]); // Read diff logs foreach ($logs as $log) { if ('diff' === substr($log, 0, 4)) { if (isset($diff)) { $diffs[] = $diff; } $diff = new Diff; continue; } if ('index' === substr($log, 0, 5)) { $diff->setIndex($log); continue; } if ('---' === substr($log, 0, 3)) { $diff->setOld($log); continue; } if ('+++' === substr($log, 0, 3)) { $diff->setNew($log); continue; } $diff->addLine($log); } if (isset($diff)) { $diffs[] = $diff; } $commit->setDiffs($diffs); return $commit; } public function getAuthorStatistics() { $logs = $this->getClient()->run($this, 'log --pretty=format:\'%an||%ae\''); if (empty($logs)) { throw new \RuntimeException('No statistics available'); } $logs = explode("\n", $logs); $logs = array_count_values($logs); arsort($logs); foreach ($logs as $user => $count) { $user = explode('||', $user); $data[] = array('name' => $user[0], 'email' => $user[1], 'commits' => $count); } return $data; } public function getStatistics($branch) { // Calculate amount of files, extensions and file size $logs = $this->getClient()->run($this, 'ls-tree -r -l ' . $branch); $lines = explode("\n", $logs); $files = array(); $data['extensions'] = array(); $data['size'] = 0; $data['files'] = 0; foreach ($lines as $key => $line) { if (empty($line)) { unset($lines[$key]); continue; } $files[] = preg_split("/[\s]+/", $line); } foreach ($files as $file) { if ($file[1] == 'blob') { $data['files']++; } if (is_numeric($file[3])) { $data['size'] += $file[3]; } if (($pos = strrpos($file[4], '.')) !== FALSE) { $data['extensions'][] = substr($file[4], $pos); } } $data['extensions'] = array_count_values($data['extensions']); arsort($data['extensions']); return $data; } /** * Get the Tree for the provided folder * * @param string $tree Folder that will be parsed * @return Tree Instance of Tree for the provided folder */ public function getTree($tree) { $tree = new Tree($tree, $this->getClient(), $this); $tree->parse(); return $tree; } /** * Get the Blob for the provided file * * @param string $blob File that will be parsed * @return Blob Instance of Blob for the provided file */ public function getBlob($blob) { return new Blob($blob, $this->getClient(), $this); } /** * Blames the provided file and parses the output * * @param string $file File that will be blamed * @return array Commits hashes containing the lines */ public function getBlame($file) { $logs = $this->getClient()->run($this, "blame -s $file"); $logs = explode("\n", $logs); foreach ($logs as $log) { if ($log == '') { continue; } $split = preg_split("/[a-zA-Z0-9^]{8}[\s]+[0-9]+\)/", $log); preg_match_all("/([a-zA-Z0-9^]{8})[\s]+([0-9]+)\)/", $log, $match); $commit = $match[1][0]; if (!isset($blame[$commit]['line'])) { $blame[$commit]['line'] = ''; } $blame[$commit]['line'] .= PHP_EOL . $split[1]; } return $blame; } /** * Get the current Repository path * * @return string Path where the repository is located */ public function getPath() { return $this->path; } /** * Set the current Repository path * * @param string $path Path where the repository is located */ public function setPath($path) { $this->path = $path; } } lib/Git/ScopeAware.php000066400000000000000000000006741516067305400151270ustar00rootroot00000000000000client = $client; } public function getClient() { return $this->client; } public function getRepository() { return $this->repository; } public function setRepository($repository) { $this->repository = $repository; } }nginx/000077500000000000000000000000001516067305400122105ustar00rootroot00000000000000nginx/server.conf000066400000000000000000000020331516067305400143630ustar00rootroot00000000000000server { server_name MYSERVER; access_log /var/log/nginx/MYSERVER.access_log main; error_log /var/log/nginx/MYSERVER.error_log debug_http; root /var/www/DIR; index index.php; # auth_basic "Restricted"; # auth_basic_user_file rhtpasswd; location = /robots.txt { allow all; log_not_found off; access_log off; } location ~* ^/index.php.*$ { fastcgi_pass 127.0.0.1:9000; include fastcgi.conf; } location / { try_files $uri @gitlist; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { add_header Vary "Accept-Encoding"; expires max; try_files $uri @gitlist; tcp_nodelay off; tcp_nopush on; } # location ~* \.(git|svn|patch|htaccess|log|route|plist|inc|json|pl|po|sh|ini|sample|kdev4)$ { # deny all; # } location @gitlist { rewrite ^/.*$ /index.php; } } phpunit.xml.dist000066400000000000000000000010031516067305400142320ustar00rootroot00000000000000 ./tests/ tests/000077500000000000000000000000001516067305400122275ustar00rootroot00000000000000tests/ClientTest.php000066400000000000000000000363301516067305400150230ustar00rootroot00000000000000markTestSkipped('There are no write permissions in order to create test repositories.'); } $this->client = new Client('/usr/bin/git'); } /** * @expectedException RuntimeException */ public function testIsNotFindingRepositories() { $this->client->getRepositories($this->repoPath); } /** * @expectedException RuntimeException */ public function testIsNotAbleToGetUnexistingRepository() { $this->client->getRepository($this->repoPath); } public function testIsCreatingRepository() { $repository = $this->client->createRepository($this->repoPath); $this->assertRegExp("/nothing to commit/", $repository->getClient()->run($repository, 'status')); } /** * @expectedException RuntimeException */ public function testIsNotAbleToCreateRepositoryDueToExistingOne() { $this->client->createRepository($this->repoPath); } public function testIsListingRepositories() { $this->client->createRepository($this->repoPath . '/../anothertestrepo'); $this->client->createRepository($this->repoPath . '/../bigbadrepo'); $repositories = $this->client->getRepositories($this->repoPath . '/../'); $this->assertEquals($repositories[0]['name'], 'anothertestrepo'); $this->assertEquals($repositories[1]['name'], 'bigbadrepo'); $this->assertEquals($repositories[2]['name'], 'testrepo'); } public function testIsConfiguratingRepository() { $repository = $this->client->getRepository($this->repoPath); $repository->setConfig('user.name', 'Luke Skywalker'); $repository->setConfig('user.email', 'luke@republic.com'); $this->assertEquals($repository->getConfig('user.name'), 'Luke Skywalker'); $this->assertEquals($repository->getConfig('user.email'), 'luke@republic.com'); } /** * @depends testIsCreatingRepository */ public function testIsAdding() { $repository = $this->client->getRepository($this->repoPath); file_put_contents($this->repoPath . '/test_file.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); $repository->add('test_file.txt'); $this->assertRegExp("/new file: test_file.txt/", $repository->getClient()->run($repository, 'status')); } /** * @depends testIsAdding */ public function testIsAddingDot() { $repository = $this->client->getRepository($this->repoPath); file_put_contents($this->repoPath . '/test_file1.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file2.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file3.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); $repository->add(); $this->assertRegExp("/new file: test_file1.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file2.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file3.txt/", $repository->getClient()->run($repository, 'status')); } /** * @depends testIsAddingDot */ public function testIsAddingAll() { $repository = $this->client->getRepository($this->repoPath); file_put_contents($this->repoPath . '/test_file4.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file5.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file6.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); $repository->addAll(); $this->assertRegExp("/new file: test_file4.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file5.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file6.txt/", $repository->getClient()->run($repository, 'status')); } /** * @depends testIsAddingAll */ public function testIsAddingArrayOfFiles() { $repository = $this->client->getRepository($this->repoPath); file_put_contents($this->repoPath . '/test_file7.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file8.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); file_put_contents($this->repoPath . '/test_file9.txt', 'Your mother is so ugly, glCullFace always returns TRUE.'); $repository->add(array('test_file7.txt', 'test_file8.txt', 'test_file9.txt')); $this->assertRegExp("/new file: test_file7.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file8.txt/", $repository->getClient()->run($repository, 'status')); $this->assertRegExp("/new file: test_file9.txt/", $repository->getClient()->run($repository, 'status')); } /** * @depends testIsAddingArrayOfFiles */ public function testIsCommiting() { $repository = $this->client->getRepository($this->repoPath); $repository->commit("The truth unveiled"); $this->assertRegExp("/The truth unveiled/", $repository->getClient()->run($repository, 'log')); } public function testIsCreatingBranches() { $repository = $this->client->getRepository($this->repoPath); $repository->createBranch('issue12'); $repository->createBranch('issue42'); $branches = $repository->getBranches(); $this->assertContains('issue12', $branches); $this->assertContains('issue42', $branches); $this->assertContains('master', $branches); } public function testIsGettingCurrentBranch() { $repository = $this->client->getRepository($this->repoPath); $branch = $repository->getCurrentBranch(); $this->assertTrue($branch === 'master'); } /** * @depends testIsCommiting */ public function testIsGettingCommits() { $repository = $this->client->getRepository($this->repoPath); $commits = $repository->getCommits(); foreach ($commits as $commit) { $this->assertInstanceOf('Git\Commit\Commit', $commit); $this->assertTrue($commit->getMessage() === 'The truth unveiled'); $this->assertInstanceOf('Git\Commit\Author', $commit->getAuthor()); $this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker'); $this->assertEquals($commit->getAuthor()->getEmail(), 'luke@republic.com'); $this->assertEquals($commit->getCommiter()->getName(), 'Luke Skywalker'); $this->assertEquals($commit->getCommiter()->getEmail(), 'luke@republic.com'); $this->assertEquals($commit->getParentHash(), ''); $this->assertInstanceOf('DateTime', $commit->getDate()); $this->assertInstanceOf('DateTime', $commit->getCommiterDate()); $this->assertRegExp('/[a-f0-9]+/', $commit->getHash()); $this->assertRegExp('/[a-f0-9]+/', $commit->getShortHash()); $this->assertRegExp('/[a-f0-9]+/', $commit->getTreeHash()); } } /** * @depends testIsGettingCommits */ public function testIsGettingCommitsFromSpecificFile() { $repository = $this->client->getRepository($this->repoPath); $commits = $repository->getCommits('test_file4.txt'); foreach ($commits as $commit) { $this->assertInstanceOf('Git\Commit\Commit', $commit); $this->assertTrue($commit->getMessage() === 'The truth unveiled'); $this->assertInstanceOf('Git\Commit\Author', $commit->getAuthor()); $this->assertEquals($commit->getAuthor()->getName(), 'Luke Skywalker'); $this->assertEquals($commit->getAuthor()->getEmail(), 'luke@republic.com'); } } public function testIsGettingTree() { $repository = $this->client->getRepository($this->repoPath); $files = $repository->getTree('master'); foreach ($files as $file) { $this->assertInstanceOf('Git\Model\Blob', $file); $this->assertRegExp('/test_file[0-9]*.txt/', $file->getName()); $this->assertEquals($file->getSize(), '55'); $this->assertEquals($file->getMode(), '100644'); $this->assertRegExp('/[a-f0-9]+/', $file->getHash()); } } public function testIsGettingTreeOutput() { $repository = $this->client->getRepository($this->repoPath); $files = $repository->getTree('master')->output(); foreach ($files as $file) { $this->assertEquals('blob', $file['type']); $this->assertRegExp('/test_file[0-9]*.txt/', $file['name']); $this->assertEquals($file['size'], '55'); $this->assertEquals($file['mode'], '100644'); $this->assertRegExp('/[a-f0-9]+/', $file['hash']); } } public function testIsGettingTreesWithinTree() { $repository = $this->client->getRepository($this->repoPath); // Creating folders mkdir($this->repoPath . '/MyFolder'); mkdir($this->repoPath . '/MyTest'); mkdir($this->repoPath . '/MyFolder/Tests'); // Populating created folders file_put_contents($this->repoPath . '/MyFolder/crazy.php', 'Lorem ipsum dolor sit amet'); file_put_contents($this->repoPath . '/MyFolder/skywalker.php', 'Lorem ipsum dolor sit amet'); file_put_contents($this->repoPath . '/MyTest/fortytwo.php', 'Lorem ipsum dolor sit amet'); file_put_contents($this->repoPath . '/MyFolder/Tests/web.php', 'Lorem ipsum dolor sit amet'); file_put_contents($this->repoPath . '/MyFolder/Tests/cli.php', 'Lorem ipsum dolor sit amet'); // Adding and commiting $repository->addAll(); $repository->commit("Creating folders for testIsGettingTreesWithinTrees"); // Checking tree $files = $repository->getTree('master')->output(); $this->assertEquals('folder', $files[0]['type']); $this->assertEquals('MyFolder', $files[0]['name']); $this->assertEquals('', $files[0]['size']); $this->assertEquals('040000', $files[0]['mode']); $this->assertEquals('4143e982237f3bdf56b5350f862c334054aad69e', $files[0]['hash']); $this->assertEquals('folder', $files[1]['type']); $this->assertEquals('MyTest', $files[1]['name']); $this->assertEquals('', $files[1]['size']); $this->assertEquals('040000', $files[1]['mode']); $this->assertEquals('632240595eabd59e4217d196d6c12efb81f9c011', $files[1]['hash']); $this->assertEquals('blob', $files[2]['type']); $this->assertEquals('test_file.txt', $files[2]['name']); $this->assertEquals('55', $files[2]['size']); $this->assertEquals('100644', $files[2]['mode']); $this->assertEquals('a773bfc0fda6f878e3d17d78c667d18297c8831f', $files[2]['hash']); } public function testIsGettingBlobsWithinTrees() { $repository = $this->client->getRepository($this->repoPath); $files = $repository->getTree('master:MyFolder/')->output(); $this->assertEquals('folder', $files[0]['type']); $this->assertEquals('Tests', $files[0]['name']); $this->assertEquals('', $files[0]['size']); $this->assertEquals('040000', $files[0]['mode']); $this->assertEquals('8542f67d011ff2ea5ec49a729ba81a52935676d1', $files[0]['hash']); $this->assertEquals('blob', $files[1]['type']); $this->assertEquals('crazy.php', $files[1]['name']); $this->assertEquals('26', $files[1]['size']); $this->assertEquals('100644', $files[1]['mode']); $this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[1]['hash']); $this->assertEquals('blob', $files[2]['type']); $this->assertEquals('skywalker.php', $files[2]['name']); $this->assertEquals('26', $files[2]['size']); $this->assertEquals('100644', $files[2]['mode']); $this->assertEquals('d781006b2d05cc31751954a0fb920c990e825aad', $files[2]['hash']); } public function testIsGettingBlobOutput() { $repository = $this->client->getRepository($this->repoPath); $blob = $repository->getBlob('master:MyFolder/crazy.php')->output(); $this->assertEquals('Lorem ipsum dolor sit amet', $blob); $blob = $repository->getBlob('master:test_file4.txt')->output(); $this->assertEquals('Your mother is so ugly, glCullFace always returns TRUE.', $blob); } public function testIsGettingStatistics() { $repository = $this->client->getRepository($this->repoPath); $stats = $repository->getStatistics('master'); $this->assertEquals('10', $stats['extensions']['.txt']); $this->assertEquals('5', $stats['extensions']['.php']); $this->assertEquals('680', $stats['size']); $this->assertEquals('15', $stats['files']); } public function testIsGettingAuthorStatistics() { $repository = $this->client->getRepository($this->repoPath); $stats = $repository->getAuthorStatistics(); $this->assertEquals('Luke Skywalker', $stats[0]['name']); $this->assertEquals('luke@republic.com', $stats[0]['email']); $this->assertEquals('2', $stats[0]['commits']); $repository->setConfig('user.name', 'Princess Leia'); $repository->setConfig('user.email', 'sexyleia@republic.com'); file_put_contents($this->repoPath . '/MyFolder/crazy.php', 'Lorem ipsum dolor sit AMET'); $repository->addAll(); $repository->commit("Fixing AMET case"); $stats = $repository->getAuthorStatistics(); $this->assertEquals('Luke Skywalker', $stats[0]['name']); $this->assertEquals('luke@republic.com', $stats[0]['email']); $this->assertEquals('2', $stats[0]['commits']); $this->assertEquals('Princess Leia', $stats[1]['name']); $this->assertEquals('sexyleia@republic.com', $stats[1]['email']); $this->assertEquals('1', $stats[1]['commits']); } public static function tearDownAfterClass() { recursiveDelete('/tmp/gitlist'); } } vendor/000077500000000000000000000000001516067305400123625ustar00rootroot00000000000000vendor/Twig/000077500000000000000000000000001516067305400132745ustar00rootroot00000000000000vendor/Twig/Autoloader.php000066400000000000000000000020341516067305400161030ustar00rootroot00000000000000 */ class Twig_Autoloader { /** * Registers Twig_Autoloader as an SPL autoloader. */ static public function register() { ini_set('unserialize_callback_func', 'spl_autoload_call'); spl_autoload_register(array(new self, 'autoload')); } /** * Handles autoloading of classes. * * @param string $class A class name. * * @return boolean Returns true if the class has been loaded */ static public function autoload($class) { if (0 !== strpos($class, 'Twig')) { return; } if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) { require $file; } } } vendor/Twig/Compiler.php000066400000000000000000000132221516067305400155570ustar00rootroot00000000000000 */ class Twig_Compiler implements Twig_CompilerInterface { protected $lastLine; protected $source; protected $indentation; protected $env; protected $debugInfo; protected $sourceOffset; protected $sourceLine; /** * Constructor. * * @param Twig_Environment $env The twig environment instance */ public function __construct(Twig_Environment $env) { $this->env = $env; $this->debugInfo = array(); } /** * Returns the environment instance related to this compiler. * * @return Twig_Environment The environment instance */ public function getEnvironment() { return $this->env; } /** * Gets the current PHP code after compilation. * * @return string The PHP code */ public function getSource() { return $this->source; } /** * Compiles a node. * * @param Twig_NodeInterface $node The node to compile * @param integer $indentation The current indentation * * @return Twig_Compiler The current compiler instance */ public function compile(Twig_NodeInterface $node, $indentation = 0) { $this->lastLine = null; $this->source = ''; $this->sourceOffset = 0; $this->sourceLine = 0; $this->indentation = $indentation; $node->compile($this); return $this; } public function subcompile(Twig_NodeInterface $node, $raw = true) { if (false === $raw) { $this->addIndentation(); } $node->compile($this); return $this; } /** * Adds a raw string to the compiled code. * * @param string $string The string * * @return Twig_Compiler The current compiler instance */ public function raw($string) { $this->source .= $string; return $this; } /** * Writes a string to the compiled code by adding indentation. * * @return Twig_Compiler The current compiler instance */ public function write() { $strings = func_get_args(); foreach ($strings as $string) { $this->addIndentation(); $this->source .= $string; } return $this; } public function addIndentation() { $this->source .= str_repeat(' ', $this->indentation * 4); return $this; } /** * Adds a quoted string to the compiled code. * * @param string $value The string * * @return Twig_Compiler The current compiler instance */ public function string($value) { $this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\")); return $this; } /** * Returns a PHP representation of a given value. * * @param mixed $value The value to convert * * @return Twig_Compiler The current compiler instance */ public function repr($value) { if (is_int($value) || is_float($value)) { if (false !== $locale = setlocale(LC_NUMERIC, 0)) { setlocale(LC_NUMERIC, 'C'); } $this->raw($value); if (false !== $locale) { setlocale(LC_NUMERIC, $locale); } } elseif (null === $value) { $this->raw('null'); } elseif (is_bool($value)) { $this->raw($value ? 'true' : 'false'); } elseif (is_array($value)) { $this->raw('array('); $i = 0; foreach ($value as $key => $value) { if ($i++) { $this->raw(', '); } $this->repr($key); $this->raw(' => '); $this->repr($value); } $this->raw(')'); } else { $this->string($value); } return $this; } /** * Adds debugging information. * * @param Twig_NodeInterface $node The related twig node * * @return Twig_Compiler The current compiler instance */ public function addDebugInfo(Twig_NodeInterface $node) { if ($node->getLine() != $this->lastLine) { $this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset); $this->sourceOffset = strlen($this->source); $this->debugInfo[$this->sourceLine] = $node->getLine(); $this->lastLine = $node->getLine(); $this->write("// line {$node->getLine()}\n"); } return $this; } public function getDebugInfo() { return $this->debugInfo; } /** * Indents the generated code. * * @param integer $step The number of indentation to add * * @return Twig_Compiler The current compiler instance */ public function indent($step = 1) { $this->indentation += $step; return $this; } /** * Outdents the generated code. * * @param integer $step The number of indentation to remove * * @return Twig_Compiler The current compiler instance */ public function outdent($step = 1) { $this->indentation -= $step; if ($this->indentation < 0) { throw new Twig_Error('Unable to call outdent() as the indentation would become negative'); } return $this; } } vendor/Twig/CompilerInterface.php000066400000000000000000000013451516067305400174030ustar00rootroot00000000000000 */ interface Twig_CompilerInterface { /** * Compiles a node. * * @param Twig_NodeInterface $node The node to compile * * @return Twig_CompilerInterface The current compiler instance */ function compile(Twig_NodeInterface $node); /** * Gets the current PHP code after compilation. * * @return string The PHP code */ function getSource(); } vendor/Twig/Environment.php000066400000000000000000000747011516067305400163220ustar00rootroot00000000000000 */ class Twig_Environment { const VERSION = '1.8.0'; protected $charset; protected $loader; protected $debug; protected $autoReload; protected $cache; protected $lexer; protected $parser; protected $compiler; protected $baseTemplateClass; protected $extensions; protected $parsers; protected $visitors; protected $filters; protected $tests; protected $functions; protected $globals; protected $runtimeInitialized; protected $loadedTemplates; protected $strictVariables; protected $unaryOperators; protected $binaryOperators; protected $templateClassPrefix = '__TwigTemplate_'; protected $functionCallbacks; protected $filterCallbacks; protected $staging; /** * Constructor. * * Available options: * * * debug: When set to `true`, the generated templates have a __toString() * method that you can use to display the generated nodes (default to * false). * * * charset: The charset used by the templates (default to utf-8). * * * base_template_class: The base template class to use for generated * templates (default to Twig_Template). * * * cache: An absolute path where to store the compiled templates, or * false to disable compilation cache (default). * * * auto_reload: Whether to reload the template is the original source changed. * If you don't provide the auto_reload option, it will be * determined automatically base on the debug value. * * * strict_variables: Whether to ignore invalid variables in templates * (default to false). * * * autoescape: Whether to enable auto-escaping (default to html): * * false: disable auto-escaping * * true: equivalent to html * * html, js: set the autoescaping to one of the supported strategies * * PHP callback: a PHP callback that returns an escaping strategy based on the template "filename" * * * optimizations: A flag that indicates which optimizations to apply * (default to -1 which means that all optimizations are enabled; * set it to 0 to disable). * * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance * @param array $options An array of options */ public function __construct(Twig_LoaderInterface $loader = null, $options = array()) { if (null !== $loader) { $this->setLoader($loader); } $options = array_merge(array( 'debug' => false, 'charset' => 'UTF-8', 'base_template_class' => 'Twig_Template', 'strict_variables' => false, 'autoescape' => 'html', 'cache' => false, 'auto_reload' => null, 'optimizations' => -1, ), $options); $this->debug = (bool) $options['debug']; $this->charset = $options['charset']; $this->baseTemplateClass = $options['base_template_class']; $this->autoReload = null === $options['auto_reload'] ? $this->debug : (bool) $options['auto_reload']; $this->extensions = array( 'core' => new Twig_Extension_Core(), 'escaper' => new Twig_Extension_Escaper($options['autoescape']), 'optimizer' => new Twig_Extension_Optimizer($options['optimizations']), ); $this->strictVariables = (bool) $options['strict_variables']; $this->runtimeInitialized = false; $this->setCache($options['cache']); $this->functionCallbacks = array(); $this->filterCallbacks = array(); $this->staging = array( 'functions' => array(), 'filters' => array(), 'tests' => array(), 'token_parsers' => array(), 'visitors' => array(), 'globals' => array(), ); } /** * Gets the base template class for compiled templates. * * @return string The base template class name */ public function getBaseTemplateClass() { return $this->baseTemplateClass; } /** * Sets the base template class for compiled templates. * * @param string $class The base template class name */ public function setBaseTemplateClass($class) { $this->baseTemplateClass = $class; } /** * Enables debugging mode. */ public function enableDebug() { $this->debug = true; } /** * Disables debugging mode. */ public function disableDebug() { $this->debug = false; } /** * Checks if debug mode is enabled. * * @return Boolean true if debug mode is enabled, false otherwise */ public function isDebug() { return $this->debug; } /** * Enables the auto_reload option. */ public function enableAutoReload() { $this->autoReload = true; } /** * Disables the auto_reload option. */ public function disableAutoReload() { $this->autoReload = false; } /** * Checks if the auto_reload option is enabled. * * @return Boolean true if auto_reload is enabled, false otherwise */ public function isAutoReload() { return $this->autoReload; } /** * Enables the strict_variables option. */ public function enableStrictVariables() { $this->strictVariables = true; } /** * Disables the strict_variables option. */ public function disableStrictVariables() { $this->strictVariables = false; } /** * Checks if the strict_variables option is enabled. * * @return Boolean true if strict_variables is enabled, false otherwise */ public function isStrictVariables() { return $this->strictVariables; } /** * Gets the cache directory or false if cache is disabled. * * @return string|false */ public function getCache() { return $this->cache; } /** * Sets the cache directory or false if cache is disabled. * * @param string|false $cache The absolute path to the compiled templates, * or false to disable cache */ public function setCache($cache) { $this->cache = $cache ? $cache : false; } /** * Gets the cache filename for a given template. * * @param string $name The template name * * @return string The cache file name */ public function getCacheFilename($name) { if (false === $this->cache) { return false; } $class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix)); return $this->getCache().'/'.substr($class, 0, 2).'/'.substr($class, 2, 2).'/'.substr($class, 4).'.php'; } /** * Gets the template class associated with the given string. * * @param string $name The name for which to calculate the template class name * @param integer $index The index if it is an embedded template * * @return string The template class name */ public function getTemplateClass($name, $index = null) { return $this->templateClassPrefix.md5($this->loader->getCacheKey($name)).(null === $index ? '' : '_'.$index); } /** * Gets the template class prefix. * * @return string The template class prefix */ public function getTemplateClassPrefix() { return $this->templateClassPrefix; } /** * Renders a template. * * @param string $name The template name * @param array $context An array of parameters to pass to the template * * @return string The rendered template */ public function render($name, array $context = array()) { return $this->loadTemplate($name)->render($context); } /** * Displays a template. * * @param string $name The template name * @param array $context An array of parameters to pass to the template */ public function display($name, array $context = array()) { $this->loadTemplate($name)->display($context); } /** * Loads a template by name. * * @param string $name The template name * @param integer $index The index if it is an embedded template * * @return Twig_TemplateInterface A template instance representing the given template name */ public function loadTemplate($name, $index = null) { $cls = $this->getTemplateClass($name, $index); if (isset($this->loadedTemplates[$cls])) { return $this->loadedTemplates[$cls]; } if (!class_exists($cls, false)) { if (false === $cache = $this->getCacheFilename($name)) { eval('?>'.$this->compileSource($this->loader->getSource($name), $name)); } else { if (!is_file($cache) || ($this->isAutoReload() && !$this->isTemplateFresh($name, filemtime($cache)))) { $this->writeCacheFile($cache, $this->compileSource($this->loader->getSource($name), $name)); } require_once $cache; } } if (!$this->runtimeInitialized) { $this->initRuntime(); } return $this->loadedTemplates[$cls] = new $cls($this); } /** * Returns true if the template is still fresh. * * Besides checking the loader for freshness information, * this method also checks if the enabled extensions have * not changed. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template * * @return Boolean true if the template is fresh, false otherwise */ public function isTemplateFresh($name, $time) { foreach ($this->extensions as $extension) { $r = new ReflectionObject($extension); if (filemtime($r->getFileName()) > $time) { return false; } } return $this->loader->isFresh($name, $time); } public function resolveTemplate($names) { if (!is_array($names)) { $names = array($names); } foreach ($names as $name) { if ($name instanceof Twig_Template) { return $name; } try { return $this->loadTemplate($name); } catch (Twig_Error_Loader $e) { } } if (1 === count($names)) { throw $e; } throw new Twig_Error_Loader(sprintf('Unable to find one of the following templates: "%s".', implode('", "', $names))); } /** * Clears the internal template cache. */ public function clearTemplateCache() { $this->loadedTemplates = array(); } /** * Clears the template cache files on the filesystem. */ public function clearCacheFiles() { if (false === $this->cache) { return; } foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->cache), RecursiveIteratorIterator::LEAVES_ONLY) as $file) { if ($file->isFile()) { @unlink($file->getPathname()); } } } /** * Gets the Lexer instance. * * @return Twig_LexerInterface A Twig_LexerInterface instance */ public function getLexer() { if (null === $this->lexer) { $this->lexer = new Twig_Lexer($this); } return $this->lexer; } /** * Sets the Lexer instance. * * @param Twig_LexerInterface A Twig_LexerInterface instance */ public function setLexer(Twig_LexerInterface $lexer) { $this->lexer = $lexer; } /** * Tokenizes a source code. * * @param string $source The template source code * @param string $name The template name * * @return Twig_TokenStream A Twig_TokenStream instance */ public function tokenize($source, $name = null) { return $this->getLexer()->tokenize($source, $name); } /** * Gets the Parser instance. * * @return Twig_ParserInterface A Twig_ParserInterface instance */ public function getParser() { if (null === $this->parser) { $this->parser = new Twig_Parser($this); } return $this->parser; } /** * Sets the Parser instance. * * @param Twig_ParserInterface A Twig_ParserInterface instance */ public function setParser(Twig_ParserInterface $parser) { $this->parser = $parser; } /** * Parses a token stream. * * @param Twig_TokenStream $tokens A Twig_TokenStream instance * * @return Twig_Node_Module A Node tree */ public function parse(Twig_TokenStream $tokens) { return $this->getParser()->parse($tokens); } /** * Gets the Compiler instance. * * @return Twig_CompilerInterface A Twig_CompilerInterface instance */ public function getCompiler() { if (null === $this->compiler) { $this->compiler = new Twig_Compiler($this); } return $this->compiler; } /** * Sets the Compiler instance. * * @param Twig_CompilerInterface $compiler A Twig_CompilerInterface instance */ public function setCompiler(Twig_CompilerInterface $compiler) { $this->compiler = $compiler; } /** * Compiles a Node. * * @param Twig_NodeInterface $node A Twig_NodeInterface instance * * @return string The compiled PHP source code */ public function compile(Twig_NodeInterface $node) { return $this->getCompiler()->compile($node)->getSource(); } /** * Compiles a template source code. * * @param string $source The template source code * @param string $name The template name * * @return string The compiled PHP source code */ public function compileSource($source, $name = null) { try { return $this->compile($this->parse($this->tokenize($source, $name))); } catch (Twig_Error $e) { $e->setTemplateFile($name); throw $e; } catch (Exception $e) { throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the compilation of a template ("%s").', $e->getMessage()), -1, $name, $e); } } /** * Sets the Loader instance. * * @param Twig_LoaderInterface $loader A Twig_LoaderInterface instance */ public function setLoader(Twig_LoaderInterface $loader) { $this->loader = $loader; } /** * Gets the Loader instance. * * @return Twig_LoaderInterface A Twig_LoaderInterface instance */ public function getLoader() { return $this->loader; } /** * Sets the default template charset. * * @param string $charset The default charset */ public function setCharset($charset) { $this->charset = $charset; } /** * Gets the default template charset. * * @return string The default charset */ public function getCharset() { return $this->charset; } /** * Initializes the runtime environment. */ public function initRuntime() { $this->runtimeInitialized = true; foreach ($this->getExtensions() as $extension) { $extension->initRuntime($this); } } /** * Returns true if the given extension is registered. * * @param string $name The extension name * * @return Boolean Whether the extension is registered or not */ public function hasExtension($name) { return isset($this->extensions[$name]); } /** * Gets an extension by name. * * @param string $name The extension name * * @return Twig_ExtensionInterface A Twig_ExtensionInterface instance */ public function getExtension($name) { if (!isset($this->extensions[$name])) { throw new Twig_Error_Runtime(sprintf('The "%s" extension is not enabled.', $name)); } return $this->extensions[$name]; } /** * Registers an extension. * * @param Twig_ExtensionInterface $extension A Twig_ExtensionInterface instance */ public function addExtension(Twig_ExtensionInterface $extension) { $this->extensions[$extension->getName()] = $extension; $this->parsers = null; $this->visitors = null; $this->filters = null; $this->tests = null; $this->functions = null; $this->globals = null; } /** * Removes an extension by name. * * @param string $name The extension name */ public function removeExtension($name) { unset($this->extensions[$name]); $this->parsers = null; $this->visitors = null; $this->filters = null; $this->tests = null; $this->functions = null; $this->globals = null; } /** * Registers an array of extensions. * * @param array $extensions An array of extensions */ public function setExtensions(array $extensions) { foreach ($extensions as $extension) { $this->addExtension($extension); } } /** * Returns all registered extensions. * * @return array An array of extensions */ public function getExtensions() { return $this->extensions; } /** * Registers a Token Parser. * * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance */ public function addTokenParser(Twig_TokenParserInterface $parser) { $this->staging['token_parsers'][] = $parser; $this->parsers = null; } /** * Gets the registered Token Parsers. * * @return Twig_TokenParserBrokerInterface A broker containing token parsers */ public function getTokenParsers() { if (null === $this->parsers) { $this->parsers = new Twig_TokenParserBroker(); if (isset($this->staging['token_parsers'])) { foreach ($this->staging['token_parsers'] as $parser) { $this->parsers->addTokenParser($parser); } } foreach ($this->getExtensions() as $extension) { $parsers = $extension->getTokenParsers(); foreach($parsers as $parser) { if ($parser instanceof Twig_TokenParserInterface) { $this->parsers->addTokenParser($parser); } elseif ($parser instanceof Twig_TokenParserBrokerInterface) { $this->parsers->addTokenParserBroker($parser); } else { throw new Twig_Error_Runtime('getTokenParsers() must return an array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances'); } } } } return $this->parsers; } /** * Gets registered tags. * * Be warned that this method cannot return tags defined by Twig_TokenParserBrokerInterface classes. * * @return Twig_TokenParserInterface[] An array of Twig_TokenParserInterface instances */ public function getTags() { $tags = array(); foreach ($this->getTokenParsers()->getParsers() as $parser) { if ($parser instanceof Twig_TokenParserInterface) { $tags[$parser->getTag()] = $parser; } } return $tags; } /** * Registers a Node Visitor. * * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance */ public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) { $this->staging['visitors'][] = $visitor; $this->visitors = null; } /** * Gets the registered Node Visitors. * * @return Twig_NodeVisitorInterface[] An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { if (null === $this->visitors) { foreach ($this->getExtensions() as $extension) { foreach ($extension->getNodeVisitors() as $visitor) { $this->addNodeVisitor($visitor); } } $this->visitors = $this->staging['visitors']; } return $this->visitors; } /** * Registers a Filter. * * @param string $name The filter name * @param Twig_FilterInterface $filter A Twig_FilterInterface instance */ public function addFilter($name, Twig_FilterInterface $filter) { $this->staging['filters'][$name] = $filter; $this->filters = null; } /** * Get a filter by name. * * Subclasses may override this method and load filters differently; * so no list of filters is available. * * @param string $name The filter name * * @return Twig_Filter|false A Twig_Filter instance or false if the filter does not exists */ public function getFilter($name) { if (null === $this->filters) { $this->getFilters(); } if (isset($this->filters[$name])) { return $this->filters[$name]; } foreach ($this->filters as $pattern => $filter) { $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); if ($count) { if (preg_match('#^'.$pattern.'$#', $name, $matches)) { array_shift($matches); $filter->setArguments($matches); return $filter; } } } foreach ($this->filterCallbacks as $callback) { if (false !== $filter = call_user_func($callback, $name)) { return $filter; } } return false; } public function registerUndefinedFilterCallback($callable) { $this->filterCallbacks[] = $callable; } /** * Gets the registered Filters. * * Be warned that this method cannot return filters defined with registerUndefinedFunctionCallback. * * @return Twig_FilterInterface[] An array of Twig_FilterInterface instances * * @see registerUndefinedFilterCallback */ public function getFilters() { if (null === $this->filters) { foreach ($this->getExtensions() as $extension) { foreach ($extension->getFilters() as $name => $filter) { $this->addFilter($name, $filter); } } $this->filters = $this->staging['filters']; } return $this->filters; } /** * Registers a Test. * * @param string $name The test name * @param Twig_TestInterface $test A Twig_TestInterface instance */ public function addTest($name, Twig_TestInterface $test) { $this->staging['tests'][$name] = $test; $this->tests = null; } /** * Gets the registered Tests. * * @return Twig_TestInterface[] An array of Twig_TestInterface instances */ public function getTests() { if (null === $this->tests) { foreach ($this->getExtensions() as $extension) { foreach ($extension->getTests() as $name => $test) { $this->addTest($name, $test); } } $this->tests = $this->staging['tests']; } return $this->tests; } /** * Registers a Function. * * @param string $name The function name * @param Twig_FunctionInterface $function A Twig_FunctionInterface instance */ public function addFunction($name, Twig_FunctionInterface $function) { $this->staging['functions'][$name] = $function; $this->functions = null; } /** * Get a function by name. * * Subclasses may override this method and load functions differently; * so no list of functions is available. * * @param string $name function name * * @return Twig_Function|false A Twig_Function instance or false if the function does not exists */ public function getFunction($name) { if (null === $this->functions) { $this->getFunctions(); } if (isset($this->functions[$name])) { return $this->functions[$name]; } foreach ($this->functions as $pattern => $function) { $pattern = str_replace('\\*', '(.*?)', preg_quote($pattern, '#'), $count); if ($count) { if (preg_match('#^'.$pattern.'$#', $name, $matches)) { array_shift($matches); $function->setArguments($matches); return $function; } } } foreach ($this->functionCallbacks as $callback) { if (false !== $function = call_user_func($callback, $name)) { return $function; } } return false; } public function registerUndefinedFunctionCallback($callable) { $this->functionCallbacks[] = $callable; } /** * Gets registered functions. * * Be warned that this method cannot return functions defined with registerUndefinedFunctionCallback. * * @return Twig_FunctionInterface[] An array of Twig_FunctionInterface instances * * @see registerUndefinedFunctionCallback */ public function getFunctions() { if (null === $this->functions) { foreach ($this->getExtensions() as $extension) { foreach ($extension->getFunctions() as $name => $function) { $this->addFunction($name, $function); } } $this->functions = $this->staging['functions']; } return $this->functions; } /** * Registers a Global. * * @param string $name The global name * @param mixed $value The global value */ public function addGlobal($name, $value) { $this->staging['globals'][$name] = $value; $this->globals = null; } /** * Gets the registered Globals. * * @return array An array of globals */ public function getGlobals() { if (null === $this->globals) { $this->globals = isset($this->staging['globals']) ? $this->staging['globals'] : array(); foreach ($this->getExtensions() as $extension) { $this->globals = array_merge($this->globals, $extension->getGlobals()); } } return $this->globals; } /** * Merges a context with the defined globals. * * @param array $context An array representing the context * * @return array The context merged with the globals */ public function mergeGlobals(array $context) { // we don't use array_merge as the context being generally // bigger than globals, this code is faster. foreach ($this->getGlobals() as $key => $value) { if (!array_key_exists($key, $context)) { $context[$key] = $value; } } return $context; } /** * Gets the registered unary Operators. * * @return array An array of unary operators */ public function getUnaryOperators() { if (null === $this->unaryOperators) { $this->initOperators(); } return $this->unaryOperators; } /** * Gets the registered binary Operators. * * @return array An array of binary operators */ public function getBinaryOperators() { if (null === $this->binaryOperators) { $this->initOperators(); } return $this->binaryOperators; } public function computeAlternatives($name, $items) { $alternatives = array(); foreach ($items as $item) { $lev = levenshtein($name, $item); if ($lev <= strlen($name) / 3 || false !== strpos($item, $name)) { $alternatives[$item] = $lev; } } asort($alternatives); return array_keys($alternatives); } protected function initOperators() { $this->unaryOperators = array(); $this->binaryOperators = array(); foreach ($this->getExtensions() as $extension) { $operators = $extension->getOperators(); if (!$operators) { continue; } if (2 !== count($operators)) { throw new InvalidArgumentException(sprintf('"%s::getOperators()" does not return a valid operators array.', get_class($extension))); } $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); } } protected function writeCacheFile($file, $content) { $dir = dirname($file); if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true) && !is_dir($dir)) { throw new RuntimeException(sprintf("Unable to create the cache directory (%s).", $dir)); } } elseif (!is_writable($dir)) { throw new RuntimeException(sprintf("Unable to write in the cache directory (%s).", $dir)); } $tmpFile = tempnam(dirname($file), basename($file)); if (false !== @file_put_contents($tmpFile, $content)) { // rename does not work on Win32 before 5.2.6 if (@rename($tmpFile, $file) || (@copy($tmpFile, $file) && unlink($tmpFile))) { @chmod($file, 0644); return; } } throw new Twig_Error_Runtime(sprintf('Failed to write cache file "%s".', $file)); } } vendor/Twig/Error.php000066400000000000000000000122711516067305400151010ustar00rootroot00000000000000 */ class Twig_Error extends Exception { protected $lineno; protected $filename; protected $rawMessage; protected $previous; /** * Constructor. * * @param string $message The error message * @param integer $lineno The template line where the error occurred * @param string $filename The template file name where the error occurred * @param Exception $previous The previous exception */ public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null) { if (version_compare(PHP_VERSION, '5.3.0', '<')) { $this->previous = $previous; parent::__construct(''); } else { parent::__construct('', 0, $previous); } $this->lineno = $lineno; $this->filename = $filename; if (-1 === $this->lineno || null === $this->filename) { $this->guessTemplateInfo(); } $this->rawMessage = $message; $this->updateRepr(); } /** * Gets the raw message. * * @return string The raw message */ public function getRawMessage() { return $this->rawMessage; } /** * Gets the filename where the error occurred. * * @return string The filename */ public function getTemplateFile() { return $this->filename; } /** * Sets the filename where the error occurred. * * @param string $filename The filename */ public function setTemplateFile($filename) { $this->filename = $filename; $this->updateRepr(); } /** * Gets the template line where the error occurred. * * @return integer The template line */ public function getTemplateLine() { return $this->lineno; } /** * Sets the template line where the error occurred. * * @param integer $lineno The template line */ public function setTemplateLine($lineno) { $this->lineno = $lineno; $this->updateRepr(); } /** * For PHP < 5.3.0, provides access to the getPrevious() method. * * @param string $method The method name * @param array $arguments The parameters to be passed to the method * * @return Exception The previous exception or null */ public function __call($method, $arguments) { if ('getprevious' == strtolower($method)) { return $this->previous; } throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method)); } protected function updateRepr() { $this->message = $this->rawMessage; $dot = false; if ('.' === substr($this->message, -1)) { $this->message = substr($this->message, 0, -1); $dot = true; } if (null !== $this->filename) { if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) { $filename = sprintf('"%s"', $this->filename); } else { $filename = json_encode($this->filename); } $this->message .= sprintf(' in %s', $filename); } if ($this->lineno >= 0) { $this->message .= sprintf(' at line %d', $this->lineno); } if ($dot) { $this->message .= '.'; } } protected function guessTemplateInfo() { $template = null; foreach (debug_backtrace() as $trace) { if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) { $template = $trace['object']; // update template filename if (null === $this->filename) { $this->filename = $template->getTemplateName(); } break; } } if (null === $template || $this->lineno > -1) { return; } $r = new ReflectionObject($template); $file = $r->getFileName(); $exceptions = array($e = $this); while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) { $exceptions[] = $e; } while ($e = array_pop($exceptions)) { $traces = $e->getTrace(); while ($trace = array_shift($traces)) { if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { continue; } foreach ($template->getDebugInfo() as $codeLine => $templateLine) { if ($codeLine <= $trace['line']) { // update template line $this->lineno = $templateLine; return; } } } } } } vendor/Twig/Error/000077500000000000000000000000001516067305400143655ustar00rootroot00000000000000vendor/Twig/Error/Loader.php000066400000000000000000000006241516067305400163060ustar00rootroot00000000000000 */ class Twig_Error_Loader extends Twig_Error { } vendor/Twig/Error/Runtime.php000066400000000000000000000006431516067305400165240ustar00rootroot00000000000000 */ class Twig_Error_Runtime extends Twig_Error { } vendor/Twig/Error/Syntax.php000066400000000000000000000007041516067305400163650ustar00rootroot00000000000000 */ class Twig_Error_Syntax extends Twig_Error { } vendor/Twig/ExpressionParser.php000066400000000000000000000440671516067305400173340ustar00rootroot00000000000000 */ class Twig_ExpressionParser { const OPERATOR_LEFT = 1; const OPERATOR_RIGHT = 2; protected $parser; protected $unaryOperators; protected $binaryOperators; public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators) { $this->parser = $parser; $this->unaryOperators = $unaryOperators; $this->binaryOperators = $binaryOperators; } public function parseExpression($precedence = 0) { $expr = $this->getPrimary(); $token = $this->parser->getCurrentToken(); while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) { $op = $this->binaryOperators[$token->getValue()]; $this->parser->getStream()->next(); if (isset($op['callable'])) { $expr = call_user_func($op['callable'], $this->parser, $expr); } else { $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); $class = $op['class']; $expr = new $class($expr, $expr1, $token->getLine()); } $token = $this->parser->getCurrentToken(); } if (0 === $precedence) { return $this->parseConditionalExpression($expr); } return $expr; } protected function getPrimary() { $token = $this->parser->getCurrentToken(); if ($this->isUnary($token)) { $operator = $this->unaryOperators[$token->getValue()]; $this->parser->getStream()->next(); $expr = $this->parseExpression($operator['precedence']); $class = $operator['class']; return $this->parsePostfixExpression(new $class($expr, $token->getLine())); } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $this->parser->getStream()->next(); $expr = $this->parseExpression(); $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); return $this->parsePostfixExpression($expr); } return $this->parsePrimaryExpression(); } protected function parseConditionalExpression($expr) { while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) { $this->parser->getStream()->next(); $expr2 = $this->parseExpression(); $this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'The ternary operator must have a default value'); $expr3 = $this->parseExpression(); $expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); } return $expr; } protected function isUnary(Twig_Token $token) { return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); } protected function isBinary(Twig_Token $token) { return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); } public function parsePrimaryExpression() { $token = $this->parser->getCurrentToken(); switch ($token->getType()) { case Twig_Token::NAME_TYPE: $this->parser->getStream()->next(); switch ($token->getValue()) { case 'true': case 'TRUE': $node = new Twig_Node_Expression_Constant(true, $token->getLine()); break; case 'false': case 'FALSE': $node = new Twig_Node_Expression_Constant(false, $token->getLine()); break; case 'none': case 'NONE': case 'null': case 'NULL': $node = new Twig_Node_Expression_Constant(null, $token->getLine()); break; default: if ('(' === $this->parser->getCurrentToken()->getValue()) { $node = $this->getFunctionNode($token->getValue(), $token->getLine()); } else { $node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine()); } } break; case Twig_Token::NUMBER_TYPE: $this->parser->getStream()->next(); $node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); break; case Twig_Token::STRING_TYPE: case Twig_Token::INTERPOLATION_START_TYPE: $node = $this->parseStringExpression(); break; default: if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) { $node = $this->parseArrayExpression(); } elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) { $node = $this->parseHashExpression(); } else { throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine()); } } return $this->parsePostfixExpression($node); } public function parseStringExpression() { $stream = $this->parser->getStream(); $nodes = array(); // a string cannot be followed by another string in a single expression $nextCanBeString = true; while (true) { if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) { $token = $stream->next(); $nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); $nextCanBeString = false; } elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) { $stream->next(); $nodes[] = $this->parseExpression(); $stream->expect(Twig_Token::INTERPOLATION_END_TYPE); $nextCanBeString = true; } else { break; } } $expr = array_shift($nodes); foreach ($nodes as $node) { $expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine()); } return $expr; } public function parseArrayExpression() { $stream = $this->parser->getStream(); $stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected'); $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); $first = true; while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { if (!$first) { $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma'); // trailing ,? if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { break; } } $first = false; $node->addElement($this->parseExpression()); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed'); return $node; } public function parseHashExpression() { $stream = $this->parser->getStream(); $stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected'); $node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine()); $first = true; while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { if (!$first) { $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma'); // trailing ,? if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) { break; } } $first = false; // a hash key can be: // // * a number -- 12 // * a string -- 'a' // * a name, which is equivalent to a string -- a // * an expression, which must be enclosed in parentheses -- (1 + 2) if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) { $token = $stream->next(); $key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); } elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $key = $this->parseExpression(); } else { $current = $stream->getCurrent(); throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine()); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)'); $value = $this->parseExpression(); $node->addElement($value, $key); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed'); return $node; } public function parsePostfixExpression($node) { while (true) { $token = $this->parser->getCurrentToken(); if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) { if ('.' == $token->getValue() || '[' == $token->getValue()) { $node = $this->parseSubscriptExpression($node); } elseif ('|' == $token->getValue()) { $node = $this->parseFilterExpression($node); } else { break; } } else { break; } } return $node; } public function getFunctionNode($name, $line) { $args = $this->parseArguments(); switch ($name) { case 'parent': if (!count($this->parser->getBlockStack())) { throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line); } if (!$this->parser->getParent() && !$this->parser->hasTraits()) { throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line); } return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line); case 'block': return new Twig_Node_Expression_BlockReference($args->getNode(0), false, $line); case 'attribute': if (count($args) < 2) { throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line); } return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line); default: if (null !== $alias = $this->parser->getImportedFunction($name)) { $arguments = new Twig_Node_Expression_Array(array(), $line); foreach ($args as $n) { $arguments->addElement($n); } $node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line); $node->setAttribute('safe', true); return $node; } $class = $this->getFunctionNodeClass($name); return new $class($name, $args, $line); } } public function parseSubscriptExpression($node) { $stream = $this->parser->getStream(); $token = $stream->next(); $lineno = $token->getLine(); $arguments = new Twig_Node_Expression_Array(array(), $lineno); $type = Twig_TemplateInterface::ANY_CALL; if ($token->getValue() == '.') { $token = $stream->next(); if ( $token->getType() == Twig_Token::NAME_TYPE || $token->getType() == Twig_Token::NUMBER_TYPE || ($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue())) ) { $arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno); if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $type = Twig_TemplateInterface::METHOD_CALL; foreach ($this->parseArguments() as $n) { $arguments->addElement($n); } } } else { throw new Twig_Error_Syntax('Expected name or number', $lineno); } } else { $type = Twig_TemplateInterface::ARRAY_CALL; $arg = $this->parseExpression(); // slice? if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) { $stream->next(); if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) { $length = new Twig_Node_Expression_Constant(null, $token->getLine()); } else { $length = $this->parseExpression(); } $class = $this->getFilterNodeClass('slice'); $arguments = new Twig_Node(array($arg, $length)); $filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine()); $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); return $filter; } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ']'); } return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno); } public function parseFilterExpression($node) { $this->parser->getStream()->next(); return $this->parseFilterExpressionRaw($node); } public function parseFilterExpressionRaw($node, $tag = null) { while (true) { $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE); $name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine()); if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $arguments = new Twig_Node(); } else { $arguments = $this->parseArguments(); } $class = $this->getFilterNodeClass($name->getAttribute('value')); $node = new $class($node, $name, $arguments, $token->getLine(), $tag); if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) { break; } $this->parser->getStream()->next(); } return $node; } public function parseArguments() { $args = array(); $stream = $this->parser->getStream(); $stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must be opened by a parenthesis'); while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) { if (!empty($args)) { $stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); } $args[] = $this->parseExpression(); } $stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); return new Twig_Node($args); } public function parseAssignmentExpression() { $targets = array(); while (true) { $token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to'); if (in_array($token->getValue(), array('true', 'false', 'none'))) { throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine()); } $targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine()); if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } $this->parser->getStream()->next(); } return new Twig_Node($targets); } public function parseMultitargetExpression() { $targets = array(); while (true) { $targets[] = $this->parseExpression(); if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } $this->parser->getStream()->next(); } return new Twig_Node($targets); } protected function getFunctionNodeClass($name) { $functionMap = $this->parser->getEnvironment()->getFunctions(); if (isset($functionMap[$name]) && $functionMap[$name] instanceof Twig_Function_Node) { return $functionMap[$name]->getClass(); } return 'Twig_Node_Expression_Function'; } protected function getFilterNodeClass($name) { $filterMap = $this->parser->getEnvironment()->getFilters(); if (isset($filterMap[$name]) && $filterMap[$name] instanceof Twig_Filter_Node) { return $filterMap[$name]->getClass(); } return 'Twig_Node_Expression_Filter'; } } vendor/Twig/Extension.php000066400000000000000000000040761516067305400157700ustar00rootroot00000000000000dateFormats[0] = $format; } if (null !== $dateIntervalFormat) { $this->dateFormats[1] = $dateIntervalFormat; } } /** * Gets the default format to be used by the date filter. * * @return array The default date format string and the default date interval format string */ public function getDateFormat() { return $this->dateFormats; } /** * Sets the default timezone to be used by the date filter. * * @param DateTimeZone|string $timezone The default timezone string or a DateTimeZone object */ public function setTimezone($timezone) { $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); } /** * Gets the default timezone to be used by the date filter. * * @return DateTimeZone The default timezone currently in use */ public function getTimezone() { return $this->timezone; } /** * Sets the default format to be used by the number_format filter. * * @param integer $decimal The number of decimal places to use. * @param string $decimalPoint The character(s) to use for the decimal point. * @param string $thousandSep The character(s) to use for the thousands separator. */ public function setNumberFormat($decimal, $decimalPoint, $thousandSep) { $this->numberFormat = array($decimal, $decimalPoint, $thousandSep); } /** * Get the default format used by the number_format filter. * * @return array The arguments for number_format() */ public function getNumberFormat() { return $this->numberFormat; } /** * Returns the token parser instance to add to the existing list. * * @return array An array of Twig_TokenParser instances */ public function getTokenParsers() { return array( new Twig_TokenParser_For(), new Twig_TokenParser_If(), new Twig_TokenParser_Extends(), new Twig_TokenParser_Include(), new Twig_TokenParser_Block(), new Twig_TokenParser_Use(), new Twig_TokenParser_Filter(), new Twig_TokenParser_Macro(), new Twig_TokenParser_Import(), new Twig_TokenParser_From(), new Twig_TokenParser_Set(), new Twig_TokenParser_Spaceless(), new Twig_TokenParser_Flush(), new Twig_TokenParser_Do(), new Twig_TokenParser_Embed(), ); } /** * Returns a list of filters to add to the existing list. * * @return array An array of filters */ public function getFilters() { $filters = array( // formatting filters 'date' => new Twig_Filter_Function('twig_date_format_filter', array('needs_environment' => true)), 'format' => new Twig_Filter_Function('sprintf'), 'replace' => new Twig_Filter_Function('strtr'), 'number_format' => new Twig_Filter_Function('twig_number_format_filter', array('needs_environment' => true)), // encoding 'url_encode' => new Twig_Filter_Function('twig_urlencode_filter'), 'json_encode' => new Twig_Filter_Function('twig_jsonencode_filter'), 'convert_encoding' => new Twig_Filter_Function('twig_convert_encoding'), // string filters 'title' => new Twig_Filter_Function('twig_title_string_filter', array('needs_environment' => true)), 'capitalize' => new Twig_Filter_Function('twig_capitalize_string_filter', array('needs_environment' => true)), 'upper' => new Twig_Filter_Function('strtoupper'), 'lower' => new Twig_Filter_Function('strtolower'), 'striptags' => new Twig_Filter_Function('strip_tags'), 'trim' => new Twig_Filter_Function('trim'), 'nl2br' => new Twig_Filter_Function('nl2br', array('pre_escape' => 'html', 'is_safe' => array('html'))), // array helpers 'join' => new Twig_Filter_Function('twig_join_filter'), 'sort' => new Twig_Filter_Function('twig_sort_filter'), 'merge' => new Twig_Filter_Function('twig_array_merge'), // string/array filters 'reverse' => new Twig_Filter_Function('twig_reverse_filter', array('needs_environment' => true)), 'length' => new Twig_Filter_Function('twig_length_filter', array('needs_environment' => true)), 'slice' => new Twig_Filter_Function('twig_slice', array('needs_environment' => true)), // iteration and runtime 'default' => new Twig_Filter_Node('Twig_Node_Expression_Filter_Default'), '_default' => new Twig_Filter_Function('_twig_default_filter'), 'keys' => new Twig_Filter_Function('twig_get_array_keys_filter'), // escaping 'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), 'e' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true, 'is_safe_callback' => 'twig_escape_filter_is_safe')), ); if (function_exists('mb_get_info')) { $filters['upper'] = new Twig_Filter_Function('twig_upper_filter', array('needs_environment' => true)); $filters['lower'] = new Twig_Filter_Function('twig_lower_filter', array('needs_environment' => true)); } return $filters; } /** * Returns a list of global functions to add to the existing list. * * @return array An array of global functions */ public function getFunctions() { return array( 'range' => new Twig_Function_Function('range'), 'constant' => new Twig_Function_Function('constant'), 'cycle' => new Twig_Function_Function('twig_cycle'), 'random' => new Twig_Function_Function('twig_random', array('needs_environment' => true)), 'date' => new Twig_Function_Function('twig_date_converter', array('needs_environment' => true)), ); } /** * Returns a list of tests to add to the existing list. * * @return array An array of tests */ public function getTests() { return array( 'even' => new Twig_Test_Node('Twig_Node_Expression_Test_Even'), 'odd' => new Twig_Test_Node('Twig_Node_Expression_Test_Odd'), 'defined' => new Twig_Test_Node('Twig_Node_Expression_Test_Defined'), 'sameas' => new Twig_Test_Node('Twig_Node_Expression_Test_Sameas'), 'none' => new Twig_Test_Node('Twig_Node_Expression_Test_Null'), 'null' => new Twig_Test_Node('Twig_Node_Expression_Test_Null'), 'divisibleby' => new Twig_Test_Node('Twig_Node_Expression_Test_Divisibleby'), 'constant' => new Twig_Test_Node('Twig_Node_Expression_Test_Constant'), 'empty' => new Twig_Test_Function('twig_test_empty'), 'iterable' => new Twig_Test_Function('twig_test_iterable'), ); } /** * Returns a list of operators to add to the existing list. * * @return array An array of operators */ public function getOperators() { return array( array( 'not' => array('precedence' => 50, 'class' => 'Twig_Node_Expression_Unary_Not'), '-' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Neg'), '+' => array('precedence' => 500, 'class' => 'Twig_Node_Expression_Unary_Pos'), ), array( 'b-and' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseAnd', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'b-xor' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseXor', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'b-or' => array('precedence' => 5, 'class' => 'Twig_Node_Expression_Binary_BitwiseOr', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'or' => array('precedence' => 10, 'class' => 'Twig_Node_Expression_Binary_Or', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'and' => array('precedence' => 15, 'class' => 'Twig_Node_Expression_Binary_And', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '==' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Equal', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '!=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '<' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Less', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '>' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_Greater', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '>=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_GreaterEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '<=' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_LessEqual', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'not in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_NotIn', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'in' => array('precedence' => 20, 'class' => 'Twig_Node_Expression_Binary_In', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '..' => array('precedence' => 25, 'class' => 'Twig_Node_Expression_Binary_Range', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '+' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Add', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '-' => array('precedence' => 30, 'class' => 'Twig_Node_Expression_Binary_Sub', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '~' => array('precedence' => 40, 'class' => 'Twig_Node_Expression_Binary_Concat', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '*' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mul', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '/' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Div', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '//' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_FloorDiv', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '%' => array('precedence' => 60, 'class' => 'Twig_Node_Expression_Binary_Mod', 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'is' => array('precedence' => 100, 'callable' => array($this, 'parseTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), 'is not' => array('precedence' => 100, 'callable' => array($this, 'parseNotTestExpression'), 'associativity' => Twig_ExpressionParser::OPERATOR_LEFT), '**' => array('precedence' => 200, 'class' => 'Twig_Node_Expression_Binary_Power', 'associativity' => Twig_ExpressionParser::OPERATOR_RIGHT), ), ); } public function parseNotTestExpression(Twig_Parser $parser, $node) { return new Twig_Node_Expression_Unary_Not($this->parseTestExpression($parser, $node), $parser->getCurrentToken()->getLine()); } public function parseTestExpression(Twig_Parser $parser, $node) { $stream = $parser->getStream(); $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $arguments = null; if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) { $arguments = $parser->getExpressionParser()->parseArguments(); } $class = $this->getTestNodeClass($parser->getEnvironment(), $name); return new $class($node, $name, $arguments, $parser->getCurrentToken()->getLine()); } protected function getTestNodeClass(Twig_Environment $env, $name) { $testMap = $env->getTests(); if (isset($testMap[$name]) && $testMap[$name] instanceof Twig_Test_Node) { return $testMap[$name]->getClass(); } return 'Twig_Node_Expression_Test'; } /** * Returns the name of the extension. * * @return string The extension name */ public function getName() { return 'core'; } } /** * Cycles over a value. * * @param ArrayAccess|array $values An array or an ArrayAccess instance * @param integer $i The cycle value * * @return string The next value in the cycle */ function twig_cycle($values, $i) { if (!is_array($values) && !$values instanceof ArrayAccess) { return $values; } return $values[$i % count($values)]; } /** * Returns a random value depending on the supplied parameter type: * - a random item from a Traversable or array * - a random character from a string * - a random integer between 0 and the integer parameter * * @param Twig_Environment $env A Twig_Environment instance * @param Traversable|array|int|string $values The values to pick a random item from * * @throws Twig_Error_Runtime When $values is an empty array (does not apply to an empty string which is returned as is). * * @return mixed A random value from the given sequence */ function twig_random(Twig_Environment $env, $values = null) { if (null === $values) { return mt_rand(); } if (is_int($values) || is_float($values)) { return $values < 0 ? mt_rand($values, 0) : mt_rand(0, $values); } if ($values instanceof Traversable) { $values = iterator_to_array($values); } elseif (is_string($values)) { if ('' === $values) { return ''; } if (null !== $charset = $env->getCharset()) { if ('UTF-8' != $charset) { $values = twig_convert_encoding($values, 'UTF-8', $charset); } // unicode version of str_split() // split at all positions, but not after the start and not before the end $values = preg_split('/(? $value) { $values[$i] = twig_convert_encoding($value, $charset, 'UTF-8'); } } } else { return $values[mt_rand(0, strlen($values) - 1)]; } } if (!is_array($values)) { return $values; } if (0 === count($values)) { throw new Twig_Error_Runtime('The random function cannot pick from an empty array.'); } return $values[array_rand($values, 1)]; } /** * Converts a date to the given format. * *
 *   {{ post.published_at|date("m/d/Y") }}
 * 
* * @param Twig_Environment $env A Twig_Environment instance * @param DateTime|DateInterval|string $date A date * @param string $format A format * @param DateTimeZone|string $timezone A timezone * * @return string The formatter date */ function twig_date_format_filter(Twig_Environment $env, $date, $format = null, $timezone = null) { if (null === $format) { $formats = $env->getExtension('core')->getDateFormat(); $format = $date instanceof DateInterval ? $formats[1] : $formats[0]; } if ($date instanceof DateInterval || $date instanceof DateTime) { if (null !== $timezone) { $date = clone $date; $date->setTimezone($timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone)); } return $date->format($format); } return twig_date_converter($env, $date, $timezone)->format($format); } /** * Converts an input to a DateTime instance. * *
 *    {% if date(user.created_at) < date('+2days') %}
 *      {# do something #}
 *    {% endif %}
 * 
* * @param Twig_Environment $env A Twig_Environment instance * @param DateTime|string $date A date * @param DateTimeZone|string $timezone A timezone * * @return DateTime A DateTime instance */ function twig_date_converter(Twig_Environment $env, $date = null, $timezone = null) { if ($date instanceof DateTime) { return $date; } $asString = (string) $date; if (ctype_digit($asString) || (!empty($asString) && '-' === $asString[0] && ctype_digit(substr($asString, 1)))) { $date = new DateTime('@'.$date); $date->setTimezone(new DateTimeZone(date_default_timezone_get())); } else { $date = new DateTime($date); } // set Timezone if (null !== $timezone) { if (!$timezone instanceof DateTimeZone) { $timezone = new DateTimeZone($timezone); } $date->setTimezone($timezone); } elseif (($timezone = $env->getExtension('core')->getTimezone()) instanceof DateTimeZone) { $date->setTimezone($timezone); } return $date; } /** * Number format filter. * * All of the formatting options can be left null, in that case the defaults will * be used. Supplying any of the parameters will override the defaults set in the * environment object. * * @param Twig_Environment $env A Twig_Environment instance * @param mixed $number A float/int/string of the number to format * @param int $decimal The number of decimal points to display. * @param string $decimalPoint The character(s) to use for the decimal point. * @param string $thousandSep The character(s) to use for the thousands separator. * * @return string The formatted number */ function twig_number_format_filter(Twig_Environment $env, $number, $decimal = null, $decimalPoint = null, $thousandSep = null) { $defaults = $env->getExtension('core')->getNumberFormat(); if (null === $decimal) { $decimal = $defaults[0]; } if (null === $decimalPoint) { $decimalPoint = $defaults[1]; } if (null === $thousandSep) { $thousandSep = $defaults[2]; } return number_format((float) $number, $decimal, $decimalPoint, $thousandSep); } /** * URL encodes a string. * * @param string $url A URL * @param bool $raw true to use rawurlencode() instead of urlencode * * @return string The URL encoded value */ function twig_urlencode_filter($url, $raw = false) { if ($raw) { return rawurlencode($url); } return urlencode($url); } if (version_compare(PHP_VERSION, '5.3.0', '<')) { /** * JSON encodes a variable. * * @param mixed $value The value to encode. * @param integer $options Not used on PHP 5.2.x * * @return mixed The JSON encoded value */ function twig_jsonencode_filter($value, $options = 0) { if ($value instanceof Twig_Markup) { $value = (string) $value; } elseif (is_array($value)) { array_walk_recursive($value, '_twig_markup2string'); } return json_encode($value); } } else { /** * JSON encodes a variable. * * @param mixed $value The value to encode. * @param integer $options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT * * @return mixed The JSON encoded value */ function twig_jsonencode_filter($value, $options = 0) { if ($value instanceof Twig_Markup) { $value = (string) $value; } elseif (is_array($value)) { array_walk_recursive($value, '_twig_markup2string'); } return json_encode($value, $options); } } function _twig_markup2string(&$value) { if ($value instanceof Twig_Markup) { $value = (string) $value; } } /** * Merges an array with another one. * *
 *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
 *
 *  {% set items = items|merge({ 'peugeot': 'car' }) %}
 *
 *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
 * 
* * @param array $arr1 An array * @param array $arr2 An array * * @return array The merged array */ function twig_array_merge($arr1, $arr2) { if (!is_array($arr1) || !is_array($arr2)) { throw new Twig_Error_Runtime('The merge filter only works with arrays or hashes.'); } return array_merge($arr1, $arr2); } /** * Slices a variable. * * @param Twig_Environment $env A Twig_Environment instance * @param mixed $item A variable * @param integer $start Start of the slice * @param integer $length Size of the slice * @param Boolean $preserveKeys Whether to preserve key or not (when the input is an array) * * @return mixed The sliced variable */ function twig_slice(Twig_Environment $env, $item, $start, $length = null, $preserveKeys = false) { if ($item instanceof Traversable) { $item = iterator_to_array($item, false); } if (is_array($item)) { return array_slice($item, $start, $length, $preserveKeys); } $item = (string) $item; if (function_exists('mb_get_info') && null !== $charset = $env->getCharset()) { return mb_substr($item, $start, null === $length ? mb_strlen($item, $charset) - $start : $length, $charset); } return null === $length ? substr($item, $start) : substr($item, $start, $length); } /** * Joins the values to a string. * * The separator between elements is an empty string per default, you can define it with the optional parameter. * *
 *  {{ [1, 2, 3]|join('|') }}
 *  {# returns 1|2|3 #}
 *
 *  {{ [1, 2, 3]|join }}
 *  {# returns 123 #}
 * 
* * @param array $value An array * @param string $glue The separator * * @return string The concatenated string */ function twig_join_filter($value, $glue = '') { if ($value instanceof Traversable) { $value = iterator_to_array($value, false); } return implode($glue, (array) $value); } // The '_default' filter is used internally to avoid using the ternary operator // which costs a lot for big contexts (before PHP 5.4). So, on average, // a function call is cheaper. function _twig_default_filter($value, $default = '') { if (twig_test_empty($value)) { return $default; } return $value; } /** * Returns the keys for the given array. * * It is useful when you want to iterate over the keys of an array: * *
 *  {% for key in array|keys %}
 *      {# ... #}
 *  {% endfor %}
 * 
* * @param array $array An array * * @return array The keys */ function twig_get_array_keys_filter($array) { if (is_object($array) && $array instanceof Traversable) { return array_keys(iterator_to_array($array)); } if (!is_array($array)) { return array(); } return array_keys($array); } /** * Reverses a variable. * * @param Twig_Environment $env A Twig_Environment instance * @param array|Traversable|string $item An array, a Traversable instance, or a string * @param Boolean $preserveKeys Whether to preserve key or not * * @return mixed The reversed input */ function twig_reverse_filter(Twig_Environment $env, $item, $preserveKeys = false) { if (is_object($item) && $item instanceof Traversable) { return array_reverse(iterator_to_array($item), $preserveKeys); } if (is_array($item)) { return array_reverse($item, $preserveKeys); } if (null !== $charset = $env->getCharset()) { $string = (string) $item; if ('UTF-8' != $charset) { $item = twig_convert_encoding($string, 'UTF-8', $charset); } preg_match_all('/./us', $item, $matches); $string = implode('', array_reverse($matches[0])); if ('UTF-8' != $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } return $string; } return strrev((string) $item); } /** * Sorts an array. * * @param array $array An array */ function twig_sort_filter($array) { asort($array); return $array; } /* used internally */ function twig_in_filter($value, $compare) { if (is_array($compare)) { return in_array($value, $compare); } elseif (is_string($compare)) { if (!strlen((string) $value)) { return empty($compare); } return false !== strpos($compare, (string) $value); } elseif (is_object($compare) && $compare instanceof Traversable) { return in_array($value, iterator_to_array($compare, false)); } return false; } /** * Escapes a string. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string The value to be escaped * @param string $strategy The escaping strategy * @param string $charset The charset * @param Boolean $autoescape Whether the function is called by the auto-escaping feature (true) or by the developer (false) */ function twig_escape_filter(Twig_Environment $env, $string, $strategy = 'html', $charset = null, $autoescape = false) { if ($autoescape && is_object($string) && $string instanceof Twig_Markup) { return $string; } if (!is_string($string) && !(is_object($string) && method_exists($string, '__toString'))) { return $string; } if (null === $charset) { $charset = $env->getCharset(); } $string = (string) $string; switch ($strategy) { case 'js': // escape all non-alphanumeric characters // into their \xHH or \uHHHH representations if ('UTF-8' != $charset) { $string = twig_convert_encoding($string, 'UTF-8', $charset); } if (null === $string = preg_replace_callback('#[^\p{L}\p{N} ]#u', '_twig_escape_js_callback', $string)) { throw new Twig_Error_Runtime('The string to escape is not a valid UTF-8 string.'); } if ('UTF-8' != $charset) { $string = twig_convert_encoding($string, $charset, 'UTF-8'); } return $string; case 'html': // see http://php.net/htmlspecialchars // Using a static variable to avoid initializing the array // each time the function is called. Moving the declaration on the // top of the function slow downs other escaping strategies. static $htmlspecialcharsCharsets = array( 'iso-8859-1' => true, 'iso8859-1' => true, 'iso-8859-15' => true, 'iso8859-15' => true, 'utf-8' => true, 'cp866' => true, 'ibm866' => true, '866' => true, 'cp1251' => true, 'windows-1251' => true, 'win-1251' => true, '1251' => true, 'cp1252' => true, 'windows-1252' => true, '1252' => true, 'koi8-r' => true, 'koi8-ru' => true, 'koi8r' => true, 'big5' => true, '950' => true, 'gb2312' => true, '936' => true, 'big5-hkscs' => true, 'shift_jis' => true, 'sjis' => true, '932' => true, 'euc-jp' => true, 'eucjp' => true, 'iso8859-5' => true, 'iso-8859-5' => true, 'macroman' => true, ); if (isset($htmlspecialcharsCharsets[strtolower($charset)])) { return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, $charset); } $string = twig_convert_encoding($string, 'UTF-8', $charset); $string = htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); return twig_convert_encoding($string, $charset, 'UTF-8'); default: throw new Twig_Error_Runtime(sprintf('Invalid escaping strategy "%s" (valid ones: html, js).', $strategy)); } } /* used internally */ function twig_escape_filter_is_safe(Twig_Node $filterArgs) { foreach ($filterArgs as $arg) { if ($arg instanceof Twig_Node_Expression_Constant) { return array($arg->getAttribute('value')); } return array(); } return array('html'); } if (function_exists('iconv')) { function twig_convert_encoding($string, $to, $from) { return iconv($from, $to, $string); } } elseif (function_exists('mb_convert_encoding')) { function twig_convert_encoding($string, $to, $from) { return mb_convert_encoding($string, $to, $from); } } else { function twig_convert_encoding($string, $to, $from) { throw new Twig_Error_Runtime('No suitable convert encoding function (use UTF-8 as your encoding or install the iconv or mbstring extension).'); } } function _twig_escape_js_callback($matches) { $char = $matches[0]; // \xHH if (!isset($char[1])) { return '\\x'.substr('00'.bin2hex($char), -2); } // \uHHHH $char = twig_convert_encoding($char, 'UTF-16BE', 'UTF-8'); return '\\u'.substr('0000'.bin2hex($char), -4); } // add multibyte extensions if possible if (function_exists('mb_get_info')) { /** * Returns the length of a variable. * * @param Twig_Environment $env A Twig_Environment instance * @param mixed $thing A variable * * @return integer The length of the value */ function twig_length_filter(Twig_Environment $env, $thing) { return is_scalar($thing) ? mb_strlen($thing, $env->getCharset()) : count($thing); } /** * Converts a string to uppercase. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The uppercased string */ function twig_upper_filter(Twig_Environment $env, $string) { if (null !== ($charset = $env->getCharset())) { return mb_strtoupper($string, $charset); } return strtoupper($string); } /** * Converts a string to lowercase. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The lowercased string */ function twig_lower_filter(Twig_Environment $env, $string) { if (null !== ($charset = $env->getCharset())) { return mb_strtolower($string, $charset); } return strtolower($string); } /** * Returns a titlecased string. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The titlecased string */ function twig_title_string_filter(Twig_Environment $env, $string) { if (null !== ($charset = $env->getCharset())) { return mb_convert_case($string, MB_CASE_TITLE, $charset); } return ucwords(strtolower($string)); } /** * Returns a capitalized string. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The capitalized string */ function twig_capitalize_string_filter(Twig_Environment $env, $string) { if (null !== ($charset = $env->getCharset())) { return mb_strtoupper(mb_substr($string, 0, 1, $charset), $charset). mb_strtolower(mb_substr($string, 1, mb_strlen($string, $charset), $charset), $charset); } return ucfirst(strtolower($string)); } } // and byte fallback else { /** * Returns the length of a variable. * * @param Twig_Environment $env A Twig_Environment instance * @param mixed $thing A variable * * @return integer The length of the value */ function twig_length_filter(Twig_Environment $env, $thing) { return is_scalar($thing) ? strlen($thing) : count($thing); } /** * Returns a titlecased string. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The titlecased string */ function twig_title_string_filter(Twig_Environment $env, $string) { return ucwords(strtolower($string)); } /** * Returns a capitalized string. * * @param Twig_Environment $env A Twig_Environment instance * @param string $string A string * * @return string The capitalized string */ function twig_capitalize_string_filter(Twig_Environment $env, $string) { return ucfirst(strtolower($string)); } } /* used internally */ function twig_ensure_traversable($seq) { if ($seq instanceof Traversable || is_array($seq)) { return $seq; } return array(); } /** * Checks if a variable is empty. * *
 * {# evaluates to true if the foo variable is null, false, or the empty string #}
 * {% if foo is empty %}
 *     {# ... #}
 * {% endif %}
 * 
* * @param mixed $value A variable * * @return Boolean true if the value is empty, false otherwise */ function twig_test_empty($value) { if ($value instanceof Countable) { return 0 == count($value); } return false === $value || (empty($value) && '0' != $value); } /** * Checks if a variable is traversable. * *
 * {# evaluates to true if the foo variable is an array or a traversable object #}
 * {% if foo is traversable %}
 *     {# ... #}
 * {% endif %}
 * 
* * @param mixed $value A variable * * @return Boolean true if the value is traversable */ function twig_test_iterable($value) { return $value instanceof Traversable || is_array($value); } vendor/Twig/Extension/Debug.php000066400000000000000000000031351516067305400170110ustar00rootroot00000000000000 new Twig_Function_Function('twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)), ); } /** * Returns the name of the extension. * * @return string The extension name */ public function getName() { return 'debug'; } } function twig_var_dump(Twig_Environment $env, $context) { if (!$env->isDebug()) { return; } ob_start(); $count = func_num_args(); if (2 === $count) { $vars = array(); foreach ($context as $key => $value) { if (!$value instanceof Twig_Template) { $vars[$key] = $value; } } var_dump($vars); } else { for ($i = 2; $i < $count; $i++) { var_dump(func_get_arg($i)); } } return ob_get_clean(); } vendor/Twig/Extension/Escaper.php000066400000000000000000000050511516067305400173440ustar00rootroot00000000000000setDefaultStrategy($defaultStrategy); } /** * Returns the token parser instances to add to the existing list. * * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances */ public function getTokenParsers() { return array(new Twig_TokenParser_AutoEscape()); } /** * Returns the node visitor instances to add to the existing list. * * @return array An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Escaper()); } /** * Returns a list of filters to add to the existing list. * * @return array An array of filters */ public function getFilters() { return array( 'raw' => new Twig_Filter_Function('twig_raw_filter', array('is_safe' => array('all'))), ); } /** * Sets the default strategy to use when not defined by the user. * * The strategy can be a valid PHP callback that takes the template * "filename" as an argument and returns the strategy to use. * * @param mixed $defaultStrategy An escaping strategy */ public function setDefaultStrategy($defaultStrategy) { // for BC if (true === $defaultStrategy) { $defaultStrategy = 'html'; } $this->defaultStrategy = $defaultStrategy; } /** * Gets the default strategy to use when not defined by the user. * * @param string $filename The template "filename" * * @return string The default strategy to use for the template */ public function getDefaultStrategy($filename) { if (is_callable($this->defaultStrategy)) { return call_user_func($this->defaultStrategy, $filename); } return $this->defaultStrategy; } /** * Returns the name of the extension. * * @return string The extension name */ public function getName() { return 'escaper'; } } /** * Marks a variable as being safe. * * @param string $string A PHP variable */ function twig_raw_filter($string) { return $string; } vendor/Twig/Extension/Optimizer.php000066400000000000000000000012301516067305400177370ustar00rootroot00000000000000optimizers = $optimizers; } /** * {@inheritdoc} */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Optimizer($this->optimizers)); } /** * {@inheritdoc} */ public function getName() { return 'optimizer'; } } vendor/Twig/Extension/Sandbox.php000066400000000000000000000050661516067305400173660ustar00rootroot00000000000000policy = $policy; $this->sandboxedGlobally = $sandboxed; } /** * Returns the token parser instances to add to the existing list. * * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances */ public function getTokenParsers() { return array(new Twig_TokenParser_Sandbox()); } /** * Returns the node visitor instances to add to the existing list. * * @return array An array of Twig_NodeVisitorInterface instances */ public function getNodeVisitors() { return array(new Twig_NodeVisitor_Sandbox()); } public function enableSandbox() { $this->sandboxed = true; } public function disableSandbox() { $this->sandboxed = false; } public function isSandboxed() { return $this->sandboxedGlobally || $this->sandboxed; } public function isSandboxedGlobally() { return $this->sandboxedGlobally; } public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy) { $this->policy = $policy; } public function getSecurityPolicy() { return $this->policy; } public function checkSecurity($tags, $filters, $functions) { if ($this->isSandboxed()) { $this->policy->checkSecurity($tags, $filters, $functions); } } public function checkMethodAllowed($obj, $method) { if ($this->isSandboxed()) { $this->policy->checkMethodAllowed($obj, $method); } } public function checkPropertyAllowed($obj, $method) { if ($this->isSandboxed()) { $this->policy->checkPropertyAllowed($obj, $method); } } public function ensureToStringAllowed($obj) { if (is_object($obj)) { $this->policy->checkMethodAllowed($obj, '__toString'); } return $obj; } /** * Returns the name of the extension. * * @return string The extension name */ public function getName() { return 'sandbox'; } } vendor/Twig/ExtensionInterface.php000066400000000000000000000037561516067305400176150ustar00rootroot00000000000000 */ interface Twig_ExtensionInterface { /** * Initializes the runtime environment. * * This is where you can load some file that contains filter functions for instance. * * @param Twig_Environment $environment The current Twig_Environment instance */ function initRuntime(Twig_Environment $environment); /** * Returns the token parser instances to add to the existing list. * * @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances */ function getTokenParsers(); /** * Returns the node visitor instances to add to the existing list. * * @return array An array of Twig_NodeVisitorInterface instances */ function getNodeVisitors(); /** * Returns a list of filters to add to the existing list. * * @return array An array of filters */ function getFilters(); /** * Returns a list of tests to add to the existing list. * * @return array An array of tests */ function getTests(); /** * Returns a list of functions to add to the existing list. * * @return array An array of functions */ function getFunctions(); /** * Returns a list of operators to add to the existing list. * * @return array An array of operators */ function getOperators(); /** * Returns a list of global variables to add to the existing list. * * @return array An array of global variables */ function getGlobals(); /** * Returns the name of the extension. * * @return string The extension name */ function getName(); } vendor/Twig/Filter.php000066400000000000000000000032041516067305400152310ustar00rootroot00000000000000 */ abstract class Twig_Filter implements Twig_FilterInterface { protected $options; protected $arguments = array(); public function __construct(array $options = array()) { $this->options = array_merge(array( 'needs_environment' => false, 'needs_context' => false, 'pre_escape' => null, 'preserves_safety' => null, ), $options); } public function setArguments($arguments) { $this->arguments = $arguments; } public function getArguments() { return $this->arguments; } public function needsEnvironment() { return $this->options['needs_environment']; } public function needsContext() { return $this->options['needs_context']; } public function getSafe(Twig_Node $filterArgs) { if (isset($this->options['is_safe'])) { return $this->options['is_safe']; } if (isset($this->options['is_safe_callback'])) { return call_user_func($this->options['is_safe_callback'], $filterArgs); } return null; } public function getPreservesSafety() { return $this->options['preserves_safety']; } public function getPreEscape() { return $this->options['pre_escape']; } } vendor/Twig/Filter/000077500000000000000000000000001516067305400145215ustar00rootroot00000000000000vendor/Twig/Filter/Function.php000066400000000000000000000012031516067305400170130ustar00rootroot00000000000000 */ class Twig_Filter_Function extends Twig_Filter { protected $function; public function __construct($function, array $options = array()) { parent::__construct($options); $this->function = $function; } public function compile() { return $this->function; } } vendor/Twig/Filter/Method.php000066400000000000000000000014321516067305400164520ustar00rootroot00000000000000 */ class Twig_Filter_Method extends Twig_Filter { protected $extension, $method; public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) { parent::__construct($options); $this->extension = $extension; $this->method = $method; } public function compile() { return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); } } vendor/Twig/Filter/Node.php000066400000000000000000000012351516067305400161200ustar00rootroot00000000000000 */ class Twig_Filter_Node extends Twig_Filter { protected $class; public function __construct($class, array $options = array()) { parent::__construct($options); $this->class = $class; } public function getClass() { return $this->class; } public function compile() { } } vendor/Twig/FilterInterface.php000066400000000000000000000013301516067305400170500ustar00rootroot00000000000000 */ interface Twig_FilterInterface { /** * Compiles a filter. * * @return string The PHP code for the filter */ function compile(); function needsEnvironment(); function needsContext(); function getSafe(Twig_Node $filterArgs); function getPreservesSafety(); function getPreEscape(); function setArguments($arguments); function getArguments(); } vendor/Twig/Function.php000066400000000000000000000025711516067305400155770ustar00rootroot00000000000000 */ abstract class Twig_Function implements Twig_FunctionInterface { protected $options; protected $arguments = array(); public function __construct(array $options = array()) { $this->options = array_merge(array( 'needs_environment' => false, 'needs_context' => false, ), $options); } public function setArguments($arguments) { $this->arguments = $arguments; } public function getArguments() { return $this->arguments; } public function needsEnvironment() { return $this->options['needs_environment']; } public function needsContext() { return $this->options['needs_context']; } public function getSafe(Twig_Node $functionArgs) { if (isset($this->options['is_safe'])) { return $this->options['is_safe']; } if (isset($this->options['is_safe_callback'])) { return call_user_func($this->options['is_safe_callback'], $functionArgs); } return array(); } } vendor/Twig/Function/000077500000000000000000000000001516067305400150615ustar00rootroot00000000000000vendor/Twig/Function/Function.php000066400000000000000000000012451516067305400173610ustar00rootroot00000000000000 */ class Twig_Function_Function extends Twig_Function { protected $function; public function __construct($function, array $options = array()) { parent::__construct($options); $this->function = $function; } public function compile() { return $this->function; } } vendor/Twig/Function/Method.php000066400000000000000000000014741516067305400170200ustar00rootroot00000000000000 */ class Twig_Function_Method extends Twig_Function { protected $extension, $method; public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array()) { parent::__construct($options); $this->extension = $extension; $this->method = $method; } public function compile() { return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); } } vendor/Twig/Function/Node.php000066400000000000000000000012411516067305400164550ustar00rootroot00000000000000 */ class Twig_Function_Node extends Twig_Filter { protected $class; public function __construct($class, array $options = array()) { parent::__construct($options); $this->class = $class; } public function getClass() { return $this->class; } public function compile() { } } vendor/Twig/FunctionInterface.php000066400000000000000000000012721516067305400174150ustar00rootroot00000000000000 */ interface Twig_FunctionInterface { /** * Compiles a function. * * @return string The PHP code for the function */ function compile(); function needsEnvironment(); function needsContext(); function getSafe(Twig_Node $filterArgs); function setArguments($arguments); function getArguments(); } vendor/Twig/Lexer.php000066400000000000000000000371641516067305400150770ustar00rootroot00000000000000 */ class Twig_Lexer implements Twig_LexerInterface { protected $tokens; protected $code; protected $cursor; protected $lineno; protected $end; protected $state; protected $states; protected $brackets; protected $env; protected $filename; protected $options; protected $regexes; const STATE_DATA = 0; const STATE_BLOCK = 1; const STATE_VAR = 2; const STATE_STRING = 3; const STATE_INTERPOLATION = 4; const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A'; const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A'; const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As'; const REGEX_DQ_STRING_DELIM = '/"/A'; const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As'; const PUNCTUATION = '()[]{}?:.,|'; public function __construct(Twig_Environment $env, array $options = array()) { $this->env = $env; $this->options = array_merge(array( 'tag_comment' => array('{#', '#}'), 'tag_block' => array('{%', '%}'), 'tag_variable' => array('{{', '}}'), 'whitespace_trim' => '-', 'interpolation' => array('#{', '}'), ), $options); $this->regexes = array( 'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A', 'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A', 'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*endraw\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s', 'operator' => $this->getOperatorRegex(), 'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s', 'lex_block_raw' => '/\s*raw\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As', 'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As', 'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s', 'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A', 'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A', ); } /** * Tokenizes a source code. * * @param string $code The source code * @param string $filename A unique identifier for the source code * * @return Twig_TokenStream A token stream instance */ public function tokenize($code, $filename = null) { if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) { $mbEncoding = mb_internal_encoding(); mb_internal_encoding('ASCII'); } $this->code = str_replace(array("\r\n", "\r"), "\n", $code); $this->filename = $filename; $this->cursor = 0; $this->lineno = 1; $this->end = strlen($this->code); $this->tokens = array(); $this->state = self::STATE_DATA; $this->states = array(); $this->brackets = array(); $this->position = -1; // find all token starts in one go preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE); $this->positions = $matches; while ($this->cursor < $this->end) { // dispatch to the lexing functions depending // on the current state switch ($this->state) { case self::STATE_DATA: $this->lexData(); break; case self::STATE_BLOCK: $this->lexBlock(); break; case self::STATE_VAR: $this->lexVar(); break; case self::STATE_STRING: $this->lexString(); break; case self::STATE_INTERPOLATION: $this->lexInterpolation(); break; } } $this->pushToken(Twig_Token::EOF_TYPE); if (!empty($this->brackets)) { list($expect, $lineno) = array_pop($this->brackets); throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); } if (isset($mbEncoding)) { mb_internal_encoding($mbEncoding); } return new Twig_TokenStream($this->tokens, $this->filename); } protected function lexData() { // if no matches are left we return the rest of the template as simple text token if ($this->position == count($this->positions[0]) - 1) { $this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor)); $this->cursor = $this->end; return; } // Find the first token after the current cursor $position = $this->positions[0][++$this->position]; while ($position[1] < $this->cursor) { if ($this->position == count($this->positions[0]) - 1) { return; } $position = $this->positions[0][++$this->position]; } // push the template text first $text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor); if (isset($this->positions[2][$this->position][0])) { $text = rtrim($text); } $this->pushToken(Twig_Token::TEXT_TYPE, $text); $this->moveCursor($textContent.$position[0]); switch ($this->positions[1][$this->position][0]) { case $this->options['tag_comment'][0]: $this->lexComment(); break; case $this->options['tag_block'][0]: // raw data? if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) { $this->moveCursor($match[0]); $this->lexRawData(); // {% line \d+ %} } elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) { $this->moveCursor($match[0]); $this->lineno = (int) $match[1]; } else { $this->pushToken(Twig_Token::BLOCK_START_TYPE); $this->pushState(self::STATE_BLOCK); } break; case $this->options['tag_variable'][0]: $this->pushToken(Twig_Token::VAR_START_TYPE); $this->pushState(self::STATE_VAR); break; } } protected function lexBlock() { if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) { $this->pushToken(Twig_Token::BLOCK_END_TYPE); $this->moveCursor($match[0]); $this->popState(); } else { $this->lexExpression(); } } protected function lexVar() { if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) { $this->pushToken(Twig_Token::VAR_END_TYPE); $this->moveCursor($match[0]); $this->popState(); } else { $this->lexExpression(); } } protected function lexExpression() { // whitespace if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) { $this->moveCursor($match[0]); if ($this->cursor >= $this->end) { throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->lineno, $this->filename); } } // operators if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) { $this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]); $this->moveCursor($match[0]); } // names elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) { $this->pushToken(Twig_Token::NAME_TYPE, $match[0]); $this->moveCursor($match[0]); } // numbers elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) { $number = (float) $match[0]; // floats if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) { $number = (int) $match[0]; // integers lower than the maximum } $this->pushToken(Twig_Token::NUMBER_TYPE, $number); $this->moveCursor($match[0]); } // punctuation elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) { // opening bracket if (false !== strpos('([{', $this->code[$this->cursor])) { $this->brackets[] = array($this->code[$this->cursor], $this->lineno); } // closing bracket elseif (false !== strpos(')]}', $this->code[$this->cursor])) { if (empty($this->brackets)) { throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); } list($expect, $lineno) = array_pop($this->brackets); if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); } } $this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); ++$this->cursor; } // strings elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) { $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1))); $this->moveCursor($match[0]); } // opening double quoted string elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { $this->brackets[] = array('"', $this->lineno); $this->pushState(self::STATE_STRING); $this->moveCursor($match[0]); } // unlexable else { throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename); } } protected function lexRawData() { if (!preg_match($this->regexes['lex_raw_data'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "block"'), $this->lineno, $this->filename); } $text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor); $this->moveCursor($text.$match[0][0]); if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) { $text = rtrim($text); } $this->pushToken(Twig_Token::TEXT_TYPE, $text); } protected function lexComment() { if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) { throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename); } $this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]); } protected function lexString() { if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) { $this->brackets[] = array($this->options['interpolation'][0], $this->lineno); $this->pushToken(Twig_Token::INTERPOLATION_START_TYPE); $this->moveCursor($match[0]); $this->pushState(self::STATE_INTERPOLATION); } elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) { $this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0])); $this->moveCursor($match[0]); } elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) { list($expect, $lineno) = array_pop($this->brackets); if ($this->code[$this->cursor] != '"') { throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename); } $this->popState(); ++$this->cursor; return; } } protected function lexInterpolation() { $bracket = end($this->brackets); if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) { array_pop($this->brackets); $this->pushToken(Twig_Token::INTERPOLATION_END_TYPE); $this->moveCursor($match[0]); $this->popState(); } else { $this->lexExpression(); } } protected function pushToken($type, $value = '') { // do not push empty text tokens if (Twig_Token::TEXT_TYPE === $type && '' === $value) { return; } $this->tokens[] = new Twig_Token($type, $value, $this->lineno); } protected function moveCursor($text) { $this->cursor += strlen($text); $this->lineno += substr_count($text, "\n"); } protected function getOperatorRegex() { $operators = array_merge( array('='), array_keys($this->env->getUnaryOperators()), array_keys($this->env->getBinaryOperators()) ); $operators = array_combine($operators, array_map('strlen', $operators)); arsort($operators); $regex = array(); foreach ($operators as $operator => $length) { // an operator that ends with a character must be followed by // a whitespace or a parenthesis if (ctype_alpha($operator[$length - 1])) { $regex[] = preg_quote($operator, '/').'(?=[\s()])'; } else { $regex[] = preg_quote($operator, '/'); } } return '/'.implode('|', $regex).'/A'; } protected function pushState($state) { $this->states[] = $this->state; $this->state = $state; } protected function popState() { if (0 === count($this->states)) { throw new Exception('Cannot pop state without a previous state'); } $this->state = array_pop($this->states); } } vendor/Twig/LexerInterface.php000066400000000000000000000012161516067305400167050ustar00rootroot00000000000000 */ interface Twig_LexerInterface { /** * Tokenizes a source code. * * @param string $code The source code * @param string $filename A unique identifier for the source code * * @return Twig_TokenStream A token stream instance */ function tokenize($code, $filename = null); } vendor/Twig/Loader/000077500000000000000000000000001516067305400145025ustar00rootroot00000000000000vendor/Twig/Loader/Array.php000066400000000000000000000053711516067305400162770ustar00rootroot00000000000000 */ class Twig_Loader_Array implements Twig_LoaderInterface { protected $templates; /** * Constructor. * * @param array $templates An array of templates (keys are the names, and values are the source code) * * @see Twig_Loader */ public function __construct(array $templates) { $this->templates = array(); foreach ($templates as $name => $template) { $this->templates[$name] = $template; } } /** * Adds or overrides a template. * * @param string $name The template name * @param string $template The template source */ public function setTemplate($name, $template) { $this->templates[(string) $name] = $template; } /** * Gets the source code of a template, given its name. * * @param string $name The name of the template to load * * @return string The template source code */ public function getSource($name) { $name = (string) $name; if (!isset($this->templates[$name])) { throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } return $this->templates[$name]; } /** * Gets the cache key to use for the cache for a given template name. * * @param string $name The name of the template to load * * @return string The cache key */ public function getCacheKey($name) { $name = (string) $name; if (!isset($this->templates[$name])) { throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } return $this->templates[$name]; } /** * Returns true if the template is still fresh. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template */ public function isFresh($name, $time) { $name = (string) $name; if (!isset($this->templates[$name])) { throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } return true; } } vendor/Twig/Loader/Chain.php000066400000000000000000000047271516067305400162470ustar00rootroot00000000000000 */ class Twig_Loader_Chain implements Twig_LoaderInterface { protected $loaders; /** * Constructor. * * @param Twig_LoaderInterface[] $loaders An array of loader instances */ public function __construct(array $loaders = array()) { $this->loaders = array(); foreach ($loaders as $loader) { $this->addLoader($loader); } } /** * Adds a loader instance. * * @param Twig_LoaderInterface $loader A Loader instance */ public function addLoader(Twig_LoaderInterface $loader) { $this->loaders[] = $loader; } /** * Gets the source code of a template, given its name. * * @param string $name The name of the template to load * * @return string The template source code */ public function getSource($name) { foreach ($this->loaders as $loader) { try { return $loader->getSource($name); } catch (Twig_Error_Loader $e) { } } throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } /** * Gets the cache key to use for the cache for a given template name. * * @param string $name The name of the template to load * * @return string The cache key */ public function getCacheKey($name) { foreach ($this->loaders as $loader) { try { return $loader->getCacheKey($name); } catch (Twig_Error_Loader $e) { } } throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } /** * Returns true if the template is still fresh. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template */ public function isFresh($name, $time) { foreach ($this->loaders as $loader) { try { return $loader->isFresh($name, $time); } catch (Twig_Error_Loader $e) { } } throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name)); } } vendor/Twig/Loader/Filesystem.php000066400000000000000000000073611516067305400173460ustar00rootroot00000000000000 */ class Twig_Loader_Filesystem implements Twig_LoaderInterface { protected $paths; protected $cache; /** * Constructor. * * @param string|array $paths A path or an array of paths where to look for templates */ public function __construct($paths) { $this->setPaths($paths); } /** * Returns the paths to the templates. * * @return array The array of paths where to look for templates */ public function getPaths() { return $this->paths; } /** * Sets the paths where templates are stored. * * @param string|array $paths A path or an array of paths where to look for templates */ public function setPaths($paths) { if (!is_array($paths)) { $paths = array($paths); } $this->paths = array(); foreach ($paths as $path) { $this->addPath($path); } } /** * Adds a path where templates are stored. * * @param string $path A path where to look for templates */ public function addPath($path) { // invalidate the cache $this->cache = array(); if (!is_dir($path)) { throw new Twig_Error_Loader(sprintf('The "%s" directory does not exist.', $path)); } $this->paths[] = $path; } /** * Gets the source code of a template, given its name. * * @param string $name The name of the template to load * * @return string The template source code */ public function getSource($name) { return file_get_contents($this->findTemplate($name)); } /** * Gets the cache key to use for the cache for a given template name. * * @param string $name The name of the template to load * * @return string The cache key */ public function getCacheKey($name) { return $this->findTemplate($name); } /** * Returns true if the template is still fresh. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template */ public function isFresh($name, $time) { return filemtime($this->findTemplate($name)) <= $time; } protected function findTemplate($name) { // normalize name $name = preg_replace('#/{2,}#', '/', strtr($name, '\\', '/')); if (isset($this->cache[$name])) { return $this->cache[$name]; } $this->validateName($name); foreach ($this->paths as $path) { if (is_file($path.'/'.$name)) { return $this->cache[$name] = $path.'/'.$name; } } throw new Twig_Error_Loader(sprintf('Unable to find template "%s" (looked into: %s).', $name, implode(', ', $this->paths))); } protected function validateName($name) { if (false !== strpos($name, "\0")) { throw new Twig_Error_Loader('A template name cannot contain NUL bytes.'); } $parts = explode('/', $name); $level = 0; foreach ($parts as $part) { if ('..' === $part) { --$level; } elseif ('.' !== $part) { ++$level; } if ($level < 0) { throw new Twig_Error_Loader(sprintf('Looks like you try to load a template outside configured directories (%s).', $name)); } } } } vendor/Twig/Loader/String.php000066400000000000000000000030031516067305400164550ustar00rootroot00000000000000 */ class Twig_Loader_String implements Twig_LoaderInterface { /** * Gets the source code of a template, given its name. * * @param string $name The name of the template to load * * @return string The template source code */ public function getSource($name) { return $name; } /** * Gets the cache key to use for the cache for a given template name. * * @param string $name The name of the template to load * * @return string The cache key */ public function getCacheKey($name) { return $name; } /** * Returns true if the template is still fresh. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template */ public function isFresh($name, $time) { return true; } } vendor/Twig/LoaderInterface.php000066400000000000000000000024731516067305400170420ustar00rootroot00000000000000 */ interface Twig_LoaderInterface { /** * Gets the source code of a template, given its name. * * @param string $name The name of the template to load * * @return string The template source code * * @throws Twig_Error_Loader When $name is not found */ function getSource($name); /** * Gets the cache key to use for the cache for a given template name. * * @param string $name The name of the template to load * * @return string The cache key * * @throws Twig_Error_Loader When $name is not found */ function getCacheKey($name); /** * Returns true if the template is still fresh. * * @param string $name The template name * @param timestamp $time The last modification time of the cached template * * @return Boolean true if the template is fresh, false otherwise * * @throws Twig_Error_Loader When $name is not found */ function isFresh($name, $time); } vendor/Twig/Markup.php000066400000000000000000000014241516067305400152450ustar00rootroot00000000000000 */ class Twig_Markup implements Countable { protected $content; protected $charset; public function __construct($content, $charset) { $this->content = (string) $content; $this->charset = $charset; } public function __toString() { return $this->content; } public function count() { return function_exists('mb_get_info') ? mb_strlen($this->content, $this->charset) : strlen($this->content); } } vendor/Twig/Node.php000066400000000000000000000133121516067305400146720ustar00rootroot00000000000000 */ class Twig_Node implements Twig_NodeInterface { protected $nodes; protected $attributes; protected $lineno; protected $tag; /** * Constructor. * * The nodes are automatically made available as properties ($this->node). * The attributes are automatically made available as array items ($this['name']). * * @param array $nodes An array of named nodes * @param array $attributes An array of attributes (should not be nodes) * @param integer $lineno The line number * @param string $tag The tag name associated with the Node */ public function __construct(array $nodes = array(), array $attributes = array(), $lineno = 0, $tag = null) { $this->nodes = $nodes; $this->attributes = $attributes; $this->lineno = $lineno; $this->tag = $tag; } public function __toString() { $attributes = array(); foreach ($this->attributes as $name => $value) { $attributes[] = sprintf('%s: %s', $name, str_replace("\n", '', var_export($value, true))); } $repr = array(get_class($this).'('.implode(', ', $attributes)); if (count($this->nodes)) { foreach ($this->nodes as $name => $node) { $len = strlen($name) + 4; $noderepr = array(); foreach (explode("\n", (string) $node) as $line) { $noderepr[] = str_repeat(' ', $len).$line; } $repr[] = sprintf(' %s: %s', $name, ltrim(implode("\n", $noderepr))); } $repr[] = ')'; } else { $repr[0] .= ')'; } return implode("\n", $repr); } public function toXml($asDom = false) { $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = true; $dom->appendChild($xml = $dom->createElement('twig')); $xml->appendChild($node = $dom->createElement('node')); $node->setAttribute('class', get_class($this)); foreach ($this->attributes as $name => $value) { $node->appendChild($attribute = $dom->createElement('attribute')); $attribute->setAttribute('name', $name); $attribute->appendChild($dom->createTextNode($value)); } foreach ($this->nodes as $name => $n) { if (null === $n) { continue; } $child = $n->toXml(true)->getElementsByTagName('node')->item(0); $child = $dom->importNode($child, true); $child->setAttribute('name', $name); $node->appendChild($child); } return $asDom ? $dom : $dom->saveXml(); } public function compile(Twig_Compiler $compiler) { foreach ($this->nodes as $node) { $node->compile($compiler); } } public function getLine() { return $this->lineno; } public function getNodeTag() { return $this->tag; } /** * Returns true if the attribute is defined. * * @param string The attribute name * * @return Boolean true if the attribute is defined, false otherwise */ public function hasAttribute($name) { return array_key_exists($name, $this->attributes); } /** * Gets an attribute. * * @param string The attribute name * * @return mixed The attribute value */ public function getAttribute($name) { if (!array_key_exists($name, $this->attributes)) { throw new Twig_Error_Runtime(sprintf('Attribute "%s" does not exist for Node "%s".', $name, get_class($this))); } return $this->attributes[$name]; } /** * Sets an attribute. * * @param string The attribute name * @param mixed The attribute value */ public function setAttribute($name, $value) { $this->attributes[$name] = $value; } /** * Removes an attribute. * * @param string The attribute name */ public function removeAttribute($name) { unset($this->attributes[$name]); } /** * Returns true if the node with the given identifier exists. * * @param string The node name * * @return Boolean true if the node with the given name exists, false otherwise */ public function hasNode($name) { return array_key_exists($name, $this->nodes); } /** * Gets a node by name. * * @param string The node name * * @return Twig_Node A Twig_Node instance */ public function getNode($name) { if (!array_key_exists($name, $this->nodes)) { throw new Twig_Error_Runtime(sprintf('Node "%s" does not exist for Node "%s".', $name, get_class($this))); } return $this->nodes[$name]; } /** * Sets a node. * * @param string The node name * @param Twig_Node A Twig_Node instance */ public function setNode($name, $node = null) { $this->nodes[$name] = $node; } /** * Removes a node by name. * * @param string The node name */ public function removeNode($name) { unset($this->nodes[$name]); } public function count() { return count($this->nodes); } public function getIterator() { return new ArrayIterator($this->nodes); } } vendor/Twig/Node/000077500000000000000000000000001516067305400141615ustar00rootroot00000000000000vendor/Twig/Node/AutoEscape.php000066400000000000000000000017161516067305400167300ustar00rootroot00000000000000 */ class Twig_Node_AutoEscape extends Twig_Node { public function __construct($value, Twig_NodeInterface $body, $lineno, $tag = 'autoescape') { parent::__construct(array('body' => $body), array('value' => $value), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('body')); } } vendor/Twig/Node/Block.php000066400000000000000000000021201516067305400157170ustar00rootroot00000000000000 */ class Twig_Node_Block extends Twig_Node { public function __construct($name, Twig_NodeInterface $body, $lineno, $tag = null) { parent::__construct(array('body' => $body), array('name' => $name), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write(sprintf("public function block_%s(\$context, array \$blocks = array())\n", $this->getAttribute('name')), "{\n") ->indent() ; $compiler ->subcompile($this->getNode('body')) ->outdent() ->write("}\n\n") ; } } vendor/Twig/Node/BlockReference.php000066400000000000000000000016531516067305400175500ustar00rootroot00000000000000 */ class Twig_Node_BlockReference extends Twig_Node implements Twig_NodeOutputInterface { public function __construct($name, $lineno, $tag = null) { parent::__construct(array(), array('name' => $name), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write(sprintf("\$this->displayBlock('%s', \$context, \$blocks);\n", $this->getAttribute('name'))) ; } } vendor/Twig/Node/Body.php000066400000000000000000000005511516067305400155700ustar00rootroot00000000000000 */ class Twig_Node_Body extends Twig_Node { } vendor/Twig/Node/Do.php000066400000000000000000000015371516067305400152420ustar00rootroot00000000000000 */ class Twig_Node_Do extends Twig_Node { public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) { parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('') ->subcompile($this->getNode('expr')) ->raw(";\n") ; } } vendor/Twig/Node/Embed.php000066400000000000000000000022651516067305400157130ustar00rootroot00000000000000 */ class Twig_Node_Embed extends Twig_Node_Include { // we don't inject the module to avoid node visitors to traverse it twice (as it will be already visited in the main module) public function __construct($filename, $index, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) { parent::__construct(new Twig_Node_Expression_Constant('not_used', $lineno), $variables, $only, $ignoreMissing, $lineno, $tag); $this->setAttribute('filename', $filename); $this->setAttribute('index', $index); } protected function addGetTemplate(Twig_Compiler $compiler) { $compiler ->write("\$this->env->loadTemplate(") ->string($this->getAttribute('filename')) ->raw(', ') ->string($this->getAttribute('index')) ->raw(")") ; } } vendor/Twig/Node/Expression.php000066400000000000000000000006671516067305400170420ustar00rootroot00000000000000 */ abstract class Twig_Node_Expression extends Twig_Node { } vendor/Twig/Node/Expression/000077500000000000000000000000001516067305400163205ustar00rootroot00000000000000vendor/Twig/Node/Expression/Array.php000066400000000000000000000044561516067305400201200ustar00rootroot00000000000000index = -1; foreach ($this->getKeyValuePairs() as $pair) { if ($pair['key'] instanceof Twig_Node_Expression_Constant && ctype_digit((string) $pair['key']->getAttribute('value')) && $pair['key']->getAttribute('value') > $this->index) { $this->index = $pair['key']->getAttribute('value'); } } } public function getKeyValuePairs() { $pairs = array(); foreach (array_chunk($this->nodes, 2) as $pair) { $pairs[] = array( 'key' => $pair[0], 'value' => $pair[1], ); } return $pairs; } public function hasElement(Twig_Node_Expression $key) { foreach ($this->getKeyValuePairs() as $pair) { // we compare the string representation of the keys // to avoid comparing the line numbers which are not relevant here. if ((string) $key == (string) $pair['key']) { return true; } } return false; } public function addElement(Twig_Node_Expression $value, Twig_Node_Expression $key = null) { if (null === $key) { $key = new Twig_Node_Expression_Constant(++$this->index, $value->getLine()); } array_push($this->nodes, $key, $value); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->raw('array('); $first = true; foreach ($this->getKeyValuePairs() as $pair) { if (!$first) { $compiler->raw(', '); } $first = false; $compiler ->subcompile($pair['key']) ->raw(' => ') ->subcompile($pair['value']) ; } $compiler->raw(')'); } } vendor/Twig/Node/Expression/AssignName.php000066400000000000000000000011501516067305400210530ustar00rootroot00000000000000raw('$context[') ->string($this->getAttribute('name')) ->raw(']') ; } } vendor/Twig/Node/Expression/Binary.php000066400000000000000000000020041516067305400202510ustar00rootroot00000000000000 $left, 'right' => $right), array(), $lineno); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->raw('(') ->subcompile($this->getNode('left')) ->raw(' ') ; $this->operator($compiler); $compiler ->raw(' ') ->subcompile($this->getNode('right')) ->raw(')') ; } abstract public function operator(Twig_Compiler $compiler); } vendor/Twig/Node/Expression/Binary/000077500000000000000000000000001516067305400175445ustar00rootroot00000000000000vendor/Twig/Node/Expression/Binary/Add.php000066400000000000000000000006351516067305400207510ustar00rootroot00000000000000raw('+'); } } vendor/Twig/Node/Expression/Binary/And.php000066400000000000000000000006361516067305400207640ustar00rootroot00000000000000raw('&&'); } } vendor/Twig/Node/Expression/Binary/BitwiseAnd.php000066400000000000000000000006441516067305400223120ustar00rootroot00000000000000raw('&'); } } vendor/Twig/Node/Expression/Binary/BitwiseOr.php000066400000000000000000000006431516067305400221670ustar00rootroot00000000000000raw('|'); } } vendor/Twig/Node/Expression/Binary/BitwiseXor.php000066400000000000000000000006441516067305400223600ustar00rootroot00000000000000raw('^'); } } vendor/Twig/Node/Expression/Binary/Concat.php000066400000000000000000000006401516067305400214640ustar00rootroot00000000000000raw('.'); } } vendor/Twig/Node/Expression/Binary/Div.php000066400000000000000000000006351516067305400210030ustar00rootroot00000000000000raw('/'); } } vendor/Twig/Node/Expression/Binary/Equal.php000066400000000000000000000006051516067305400213250ustar00rootroot00000000000000raw('=='); } } vendor/Twig/Node/Expression/Binary/FloorDiv.php000066400000000000000000000012411516067305400217770ustar00rootroot00000000000000raw('intval(floor('); parent::compile($compiler); $compiler->raw('))'); } public function operator(Twig_Compiler $compiler) { return $compiler->raw('/'); } } vendor/Twig/Node/Expression/Binary/Greater.php000066400000000000000000000006061516067305400216500ustar00rootroot00000000000000raw('>'); } } vendor/Twig/Node/Expression/Binary/GreaterEqual.php000066400000000000000000000006141516067305400226370ustar00rootroot00000000000000raw('>='); } } vendor/Twig/Node/Expression/Binary/In.php000066400000000000000000000014041516067305400206220ustar00rootroot00000000000000raw('twig_in_filter(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; } public function operator(Twig_Compiler $compiler) { return $compiler->raw('in'); } } vendor/Twig/Node/Expression/Binary/Less.php000066400000000000000000000006031516067305400211620ustar00rootroot00000000000000raw('<'); } } vendor/Twig/Node/Expression/Binary/LessEqual.php000066400000000000000000000006111516067305400221510ustar00rootroot00000000000000raw('<='); } } vendor/Twig/Node/Expression/Binary/Mod.php000066400000000000000000000006351516067305400210000ustar00rootroot00000000000000raw('%'); } } vendor/Twig/Node/Expression/Binary/Mul.php000066400000000000000000000006351516067305400210160ustar00rootroot00000000000000raw('*'); } } vendor/Twig/Node/Expression/Binary/NotEqual.php000066400000000000000000000006101516067305400220020ustar00rootroot00000000000000raw('!='); } } vendor/Twig/Node/Expression/Binary/NotIn.php000066400000000000000000000014141516067305400213040ustar00rootroot00000000000000raw('!twig_in_filter(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; } public function operator(Twig_Compiler $compiler) { return $compiler->raw('not in'); } } vendor/Twig/Node/Expression/Binary/Or.php000066400000000000000000000006351516067305400206410ustar00rootroot00000000000000raw('||'); } } vendor/Twig/Node/Expression/Binary/Power.php000066400000000000000000000013741516067305400213560ustar00rootroot00000000000000raw('pow(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; } public function operator(Twig_Compiler $compiler) { return $compiler->raw('**'); } } vendor/Twig/Node/Expression/Binary/Range.php000066400000000000000000000013761516067305400213200ustar00rootroot00000000000000raw('range(') ->subcompile($this->getNode('left')) ->raw(', ') ->subcompile($this->getNode('right')) ->raw(')') ; } public function operator(Twig_Compiler $compiler) { return $compiler->raw('..'); } } vendor/Twig/Node/Expression/Binary/Sub.php000066400000000000000000000006351516067305400210120ustar00rootroot00000000000000raw('-'); } } vendor/Twig/Node/Expression/BlockReference.php000066400000000000000000000026061516067305400217060ustar00rootroot00000000000000 */ class Twig_Node_Expression_BlockReference extends Twig_Node_Expression { public function __construct(Twig_NodeInterface $name, $asString = false, $lineno, $tag = null) { parent::__construct(array('name' => $name), array('as_string' => $asString, 'output' => false), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('as_string')) { $compiler->raw('(string) '); } if ($this->getAttribute('output')) { $compiler ->addDebugInfo($this) ->write("\$this->displayBlock(") ->subcompile($this->getNode('name')) ->raw(", \$context, \$blocks);\n") ; } else { $compiler ->raw("\$this->renderBlock(") ->subcompile($this->getNode('name')) ->raw(", \$context, \$blocks)") ; } } } vendor/Twig/Node/Expression/Conditional.php000066400000000000000000000016061516067305400212770ustar00rootroot00000000000000 $expr1, 'expr2' => $expr2, 'expr3' => $expr3), array(), $lineno); } public function compile(Twig_Compiler $compiler) { $compiler ->raw('((') ->subcompile($this->getNode('expr1')) ->raw(') ? (') ->subcompile($this->getNode('expr2')) ->raw(') : (') ->subcompile($this->getNode('expr3')) ->raw('))') ; } } vendor/Twig/Node/Expression/Constant.php000066400000000000000000000010551516067305400206230ustar00rootroot00000000000000 $value), $lineno); } public function compile(Twig_Compiler $compiler) { $compiler->repr($this->getAttribute('value')); } } vendor/Twig/Node/Expression/ExtensionReference.php000066400000000000000000000014761516067305400226340ustar00rootroot00000000000000 */ class Twig_Node_Expression_ExtensionReference extends Twig_Node_Expression { public function __construct($name, $lineno, $tag = null) { parent::__construct(array(), array('name' => $name), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->raw(sprintf("\$this->env->getExtension('%s')", $this->getAttribute('name'))); } } vendor/Twig/Node/Expression/Filter.php000066400000000000000000000037241516067305400202640ustar00rootroot00000000000000 $node, 'filter' => $filterName, 'arguments' => $arguments), array(), $lineno, $tag); } public function compile(Twig_Compiler $compiler) { $name = $this->getNode('filter')->getAttribute('value'); if (false === $filter = $compiler->getEnvironment()->getFilter($name)) { $message = sprintf('The filter "%s" does not exist', $name); if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFilters()))) { $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); } throw new Twig_Error_Syntax($message, $this->getLine()); } $this->compileFilter($compiler, $filter); } protected function compileFilter(Twig_Compiler $compiler, Twig_FilterInterface $filter) { $compiler ->raw($filter->compile().'(') ->raw($filter->needsEnvironment() ? '$this->env, ' : '') ->raw($filter->needsContext() ? '$context, ' : '') ; foreach ($filter->getArguments() as $argument) { $compiler ->string($argument) ->raw(', ') ; } $compiler->subcompile($this->getNode('node')); foreach ($this->getNode('arguments') as $node) { $compiler ->raw(', ') ->subcompile($node) ; } $compiler->raw(')'); } } vendor/Twig/Node/Expression/Filter/000077500000000000000000000000001516067305400175455ustar00rootroot00000000000000vendor/Twig/Node/Expression/Filter/Default.php000066400000000000000000000031021516067305400216360ustar00rootroot00000000000000 * {{ var.foo|default('foo item on var is not defined') }} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Filter_Default extends Twig_Node_Expression_Filter { public function __construct(Twig_NodeInterface $node, Twig_Node_Expression_Constant $filterName, Twig_NodeInterface $arguments, $lineno, $tag = null) { $default = new Twig_Node_Expression_Filter($node, new Twig_Node_Expression_Constant('_default', $node->getLine()), $arguments, $node->getLine()); if ('default' === $filterName->getAttribute('value') && ($node instanceof Twig_Node_Expression_Name || $node instanceof Twig_Node_Expression_GetAttr)) { $test = new Twig_Node_Expression_Test_Defined(clone $node, 'defined', new Twig_Node(), $node->getLine()); $false = count($arguments) ? $arguments->getNode(0) : new Twig_Node_Expression_Constant('', $node->getLine()); $node = new Twig_Node_Expression_Conditional($test, $default, $false, $node->getLine()); } else { $node = $default; } parent::__construct($node, $filterName, $arguments, $lineno, $tag); } public function compile(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('node')); } } vendor/Twig/Node/Expression/Function.php000066400000000000000000000036311516067305400206210ustar00rootroot00000000000000 $arguments), array('name' => $name), $lineno); } public function compile(Twig_Compiler $compiler) { $name = $this->getAttribute('name'); if (false === $function = $compiler->getEnvironment()->getFunction($name)) { $message = sprintf('The function "%s" does not exist', $name); if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getFunctions()))) { $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); } throw new Twig_Error_Syntax($message, $this->getLine()); } $compiler->raw($function->compile().'('); $first = true; if ($function->needsEnvironment()) { $compiler->raw('$this->env'); $first = false; } if ($function->needsContext()) { if (!$first) { $compiler->raw(', '); } $compiler->raw('$context'); $first = false; } foreach ($function->getArguments() as $argument) { if (!$first) { $compiler->raw(', '); } $compiler->string($argument); $first = false; } foreach ($this->getNode('arguments') as $node) { if (!$first) { $compiler->raw(', '); } $compiler->subcompile($node); $first = false; } $compiler->raw(')'); } } vendor/Twig/Node/Expression/GetAttr.php000066400000000000000000000042171516067305400204070ustar00rootroot00000000000000 $node, 'attribute' => $attribute, 'arguments' => $arguments), array('type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false), $lineno); } public function compile(Twig_Compiler $compiler) { if (function_exists('twig_template_get_attributes')) { $compiler->raw('twig_template_get_attributes($this, '); } else { $compiler->raw('$this->getAttribute('); } if ($this->getAttribute('ignore_strict_check')) { $this->getNode('node')->setAttribute('ignore_strict_check', true); } $compiler->subcompile($this->getNode('node')); $compiler->raw(', ')->subcompile($this->getNode('attribute')); if (count($this->getNode('arguments')) || Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { $compiler->raw(', ')->subcompile($this->getNode('arguments')); if (Twig_TemplateInterface::ANY_CALL !== $this->getAttribute('type') || $this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { $compiler->raw(', ')->repr($this->getAttribute('type')); } if ($this->getAttribute('is_defined_test') || $this->getAttribute('ignore_strict_check')) { $compiler->raw(', '.($this->getAttribute('is_defined_test') ? 'true' : 'false')); } if ($this->getAttribute('ignore_strict_check')) { $compiler->raw(', '.($this->getAttribute('ignore_strict_check') ? 'true' : 'false')); } } $compiler->raw(')'); } } vendor/Twig/Node/Expression/MethodCall.php000066400000000000000000000020651516067305400210500ustar00rootroot00000000000000 $node, 'arguments' => $arguments), array('method' => $method, 'safe' => false), $lineno); } public function compile(Twig_Compiler $compiler) { $compiler ->subcompile($this->getNode('node')) ->raw('->') ->raw($this->getAttribute('method')) ->raw('(') ; $first = true; foreach ($this->getNode('arguments')->getKeyValuePairs() as $pair) { if (!$first) { $compiler->raw(', '); } $first = false; $compiler->subcompile($pair['value']); } $compiler->raw(')'); } } vendor/Twig/Node/Expression/Name.php000066400000000000000000000046341516067305400177200ustar00rootroot00000000000000 '$this', '_context' => '$context', '_charset' => '$this->env->getCharset()', ); public function __construct($name, $lineno) { parent::__construct(array(), array('name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false), $lineno); } public function compile(Twig_Compiler $compiler) { $name = $this->getAttribute('name'); if ($this->getAttribute('is_defined_test')) { if ($this->isSpecial()) { $compiler->repr(true); } else { $compiler->raw('array_key_exists(')->repr($name)->raw(', $context)'); } } elseif ($this->isSpecial()) { $compiler->raw($this->specialVars[$name]); } else { // remove the non-PHP 5.4 version when PHP 5.3 support is dropped // as the non-optimized version is just a workaround for slow ternary operator // when the context has a lot of variables if (version_compare(phpversion(), '5.4.0RC1', '>=') && ($this->getAttribute('ignore_strict_check') || !$compiler->getEnvironment()->isStrictVariables())) { // PHP 5.4 ternary operator performance was optimized $compiler ->raw('(isset($context[') ->string($name) ->raw(']) ? $context[') ->string($name) ->raw('] : null)') ; } else { $compiler ->raw('$this->getContext($context, ') ->string($name) ; if ($this->getAttribute('ignore_strict_check')) { $compiler->raw(', true'); } $compiler ->raw(')') ; } } } public function isSpecial() { return isset($this->specialVars[$this->getAttribute('name')]); } public function isSimple() { return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); } } vendor/Twig/Node/Expression/Parent.php000066400000000000000000000023461516067305400202670ustar00rootroot00000000000000 */ class Twig_Node_Expression_Parent extends Twig_Node_Expression { public function __construct($name, $lineno, $tag = null) { parent::__construct(array(), array('output' => false, 'name' => $name), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('output')) { $compiler ->addDebugInfo($this) ->write("\$this->displayParentBlock(") ->string($this->getAttribute('name')) ->raw(", \$context, \$blocks);\n") ; } else { $compiler ->raw("\$this->renderParentBlock(") ->string($this->getAttribute('name')) ->raw(", \$context, \$blocks)") ; } } } vendor/Twig/Node/Expression/TempName.php000066400000000000000000000010421516067305400205340ustar00rootroot00000000000000 $name), $lineno); } public function compile(Twig_Compiler $compiler) { $compiler->raw('$_')->raw($this->getAttribute('name'))->raw('_'); } } vendor/Twig/Node/Expression/Test.php000066400000000000000000000033061516067305400177520ustar00rootroot00000000000000 $node, 'arguments' => $arguments), array('name' => $name), $lineno); } public function compile(Twig_Compiler $compiler) { $name = $this->getAttribute('name'); $testMap = $compiler->getEnvironment()->getTests(); if (!isset($testMap[$name])) { $message = sprintf('The test "%s" does not exist', $name); if ($alternatives = $compiler->getEnvironment()->computeAlternatives($name, array_keys($compiler->getEnvironment()->getTests()))) { $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); } throw new Twig_Error_Syntax($message, $this->getLine()); } $name = $this->getAttribute('name'); $node = $this->getNode('node'); $compiler ->raw($testMap[$name]->compile().'(') ->subcompile($node) ; if (null !== $this->getNode('arguments')) { $compiler->raw(', '); $max = count($this->getNode('arguments')) - 1; foreach ($this->getNode('arguments') as $i => $arg) { $compiler->subcompile($arg); if ($i != $max) { $compiler->raw(', '); } } } $compiler->raw(')'); } } vendor/Twig/Node/Expression/Test/000077500000000000000000000000001516067305400172375ustar00rootroot00000000000000vendor/Twig/Node/Expression/Test/Constant.php000066400000000000000000000015561516067305400215500ustar00rootroot00000000000000 * {% if post.status is constant('Post::PUBLISHED') %} * the status attribute is exactly the same as Post::PUBLISHED * {% endif %} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Constant extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(') ->subcompile($this->getNode('node')) ->raw(' === constant(') ->subcompile($this->getNode('arguments')->getNode(0)) ->raw('))') ; } } vendor/Twig/Node/Expression/Test/Defined.php000066400000000000000000000031311516067305400213040ustar00rootroot00000000000000 * {# defined works with variable names and variable attributes #} * {% if foo is defined %} * {# ... #} * {% endif %} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Defined extends Twig_Node_Expression_Test { public function __construct(Twig_NodeInterface $node, $name, Twig_NodeInterface $arguments = null, $lineno) { parent::__construct($node, $name, $arguments, $lineno); if ($node instanceof Twig_Node_Expression_Name) { $node->setAttribute('is_defined_test', true); } elseif ($node instanceof Twig_Node_Expression_GetAttr) { $node->setAttribute('is_defined_test', true); $this->changeIgnoreStrictCheck($node); } else { throw new Twig_Error_Syntax('The "defined" test only works with simple variables', $this->getLine()); } } protected function changeIgnoreStrictCheck(Twig_Node_Expression_GetAttr $node) { $node->setAttribute('ignore_strict_check', true); if ($node->getNode('node') instanceof Twig_Node_Expression_GetAttr) { $this->changeIgnoreStrictCheck($node->getNode('node')); } } public function compile(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('node')); } } vendor/Twig/Node/Expression/Test/Divisibleby.php000066400000000000000000000013751516067305400222230ustar00rootroot00000000000000 * {% if loop.index is divisibleby(3) %} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Divisibleby extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(0 == ') ->subcompile($this->getNode('node')) ->raw(' % ') ->subcompile($this->getNode('arguments')->getNode(0)) ->raw(')') ; } } vendor/Twig/Node/Expression/Test/Even.php000066400000000000000000000012161516067305400206450ustar00rootroot00000000000000 * {{ var is even }} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Even extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(') ->subcompile($this->getNode('node')) ->raw(' % 2 == 0') ->raw(')') ; } } vendor/Twig/Node/Expression/Test/Null.php000066400000000000000000000011741516067305400206650ustar00rootroot00000000000000 * {{ var is none }} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Null extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(null === ') ->subcompile($this->getNode('node')) ->raw(')') ; } } vendor/Twig/Node/Expression/Test/Odd.php000066400000000000000000000012131516067305400204530ustar00rootroot00000000000000 * {{ var is odd }} * * * @package twig * @author Fabien Potencier */ class Twig_Node_Expression_Test_Odd extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(') ->subcompile($this->getNode('node')) ->raw(' % 2 == 1') ->raw(')') ; } } vendor/Twig/Node/Expression/Test/Sameas.php000066400000000000000000000013041516067305400211570ustar00rootroot00000000000000 */ class Twig_Node_Expression_Test_Sameas extends Twig_Node_Expression_Test { public function compile(Twig_Compiler $compiler) { $compiler ->raw('(') ->subcompile($this->getNode('node')) ->raw(' === ') ->subcompile($this->getNode('arguments')->getNode(0)) ->raw(')') ; } } vendor/Twig/Node/Expression/Unary.php000066400000000000000000000013621516067305400201310ustar00rootroot00000000000000 $node), array(), $lineno); } public function compile(Twig_Compiler $compiler) { $compiler->raw('('); $this->operator($compiler); $compiler ->subcompile($this->getNode('node')) ->raw(')') ; } abstract public function operator(Twig_Compiler $compiler); } vendor/Twig/Node/Expression/Unary/000077500000000000000000000000001516067305400174165ustar00rootroot00000000000000vendor/Twig/Node/Expression/Unary/Neg.php000066400000000000000000000006241516067305400206420ustar00rootroot00000000000000raw('-'); } } vendor/Twig/Node/Expression/Unary/Not.php000066400000000000000000000006241516067305400206710ustar00rootroot00000000000000raw('!'); } } vendor/Twig/Node/Expression/Unary/Pos.php000066400000000000000000000006241516067305400206720ustar00rootroot00000000000000raw('+'); } } vendor/Twig/Node/Flush.php000066400000000000000000000013631516067305400157560ustar00rootroot00000000000000 */ class Twig_Node_Flush extends Twig_Node { public function __construct($lineno, $tag) { parent::__construct(array(), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write("flush();\n") ; } } vendor/Twig/Node/For.php000066400000000000000000000104631516067305400154240ustar00rootroot00000000000000 */ class Twig_Node_For extends Twig_Node { protected $loop; public function __construct(Twig_Node_Expression_AssignName $keyTarget, Twig_Node_Expression_AssignName $valueTarget, Twig_Node_Expression $seq, Twig_Node_Expression $ifexpr = null, Twig_NodeInterface $body, Twig_NodeInterface $else = null, $lineno, $tag = null) { $body = new Twig_Node(array($body, $this->loop = new Twig_Node_ForLoop($lineno, $tag))); if (null !== $ifexpr) { $body = new Twig_Node_If(new Twig_Node(array($ifexpr, $body)), null, $lineno, $tag); } parent::__construct(array('key_target' => $keyTarget, 'value_target' => $valueTarget, 'seq' => $seq, 'body' => $body, 'else' => $else), array('with_loop' => true, 'ifexpr' => null !== $ifexpr), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) // the (array) cast bypasses a PHP 5.2.6 bug ->write("\$context['_parent'] = (array) \$context;\n") ->write("\$context['_seq'] = twig_ensure_traversable(") ->subcompile($this->getNode('seq')) ->raw(");\n") ; if (null !== $this->getNode('else')) { $compiler->write("\$context['_iterated'] = false;\n"); } if ($this->getAttribute('with_loop')) { $compiler ->write("\$context['loop'] = array(\n") ->write(" 'parent' => \$context['_parent'],\n") ->write(" 'index0' => 0,\n") ->write(" 'index' => 1,\n") ->write(" 'first' => true,\n") ->write(");\n") ; if (!$this->getAttribute('ifexpr')) { $compiler ->write("if (is_array(\$context['_seq']) || (is_object(\$context['_seq']) && \$context['_seq'] instanceof Countable)) {\n") ->indent() ->write("\$length = count(\$context['_seq']);\n") ->write("\$context['loop']['revindex0'] = \$length - 1;\n") ->write("\$context['loop']['revindex'] = \$length;\n") ->write("\$context['loop']['length'] = \$length;\n") ->write("\$context['loop']['last'] = 1 === \$length;\n") ->outdent() ->write("}\n") ; } } $this->loop->setAttribute('else', null !== $this->getNode('else')); $this->loop->setAttribute('with_loop', $this->getAttribute('with_loop')); $this->loop->setAttribute('ifexpr', $this->getAttribute('ifexpr')); $compiler ->write("foreach (\$context['_seq'] as ") ->subcompile($this->getNode('key_target')) ->raw(" => ") ->subcompile($this->getNode('value_target')) ->raw(") {\n") ->indent() ->subcompile($this->getNode('body')) ->outdent() ->write("}\n") ; if (null !== $this->getNode('else')) { $compiler ->write("if (!\$context['_iterated']) {\n") ->indent() ->subcompile($this->getNode('else')) ->outdent() ->write("}\n") ; } $compiler->write("\$_parent = \$context['_parent'];\n"); // remove some "private" loop variables (needed for nested loops) $compiler->write('unset($context[\'_seq\'], $context[\'_iterated\'], $context[\''.$this->getNode('key_target')->getAttribute('name').'\'], $context[\''.$this->getNode('value_target')->getAttribute('name').'\'], $context[\'_parent\'], $context[\'loop\']);'."\n"); // keep the values set in the inner context for variables defined in the outer context $compiler->write("\$context = array_merge(\$_parent, array_intersect_key(\$context, \$_parent));\n"); } } vendor/Twig/Node/ForLoop.php000066400000000000000000000031571516067305400162600ustar00rootroot00000000000000 */ class Twig_Node_ForLoop extends Twig_Node { public function __construct($lineno, $tag = null) { parent::__construct(array(), array('with_loop' => false, 'ifexpr' => false, 'else' => false), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { if ($this->getAttribute('else')) { $compiler->write("\$context['_iterated'] = true;\n"); } if ($this->getAttribute('with_loop')) { $compiler ->write("++\$context['loop']['index0'];\n") ->write("++\$context['loop']['index'];\n") ->write("\$context['loop']['first'] = false;\n") ; if (!$this->getAttribute('ifexpr')) { $compiler ->write("if (isset(\$context['loop']['length'])) {\n") ->indent() ->write("--\$context['loop']['revindex0'];\n") ->write("--\$context['loop']['revindex'];\n") ->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n") ->outdent() ->write("}\n") ; } } } } vendor/Twig/Node/If.php000066400000000000000000000033021516067305400152260ustar00rootroot00000000000000 */ class Twig_Node_If extends Twig_Node { public function __construct(Twig_NodeInterface $tests, Twig_NodeInterface $else = null, $lineno, $tag = null) { parent::__construct(array('tests' => $tests, 'else' => $else), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); for ($i = 0; $i < count($this->getNode('tests')); $i += 2) { if ($i > 0) { $compiler ->outdent() ->write("} elseif (") ; } else { $compiler ->write('if (') ; } $compiler ->subcompile($this->getNode('tests')->getNode($i)) ->raw(") {\n") ->indent() ->subcompile($this->getNode('tests')->getNode($i + 1)) ; } if ($this->hasNode('else') && null !== $this->getNode('else')) { $compiler ->outdent() ->write("} else {\n") ->indent() ->subcompile($this->getNode('else')) ; } $compiler ->outdent() ->write("}\n"); } } vendor/Twig/Node/Import.php000066400000000000000000000024411516067305400161450ustar00rootroot00000000000000 */ class Twig_Node_Import extends Twig_Node { public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $var, $lineno, $tag = null) { parent::__construct(array('expr' => $expr, 'var' => $var), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('') ->subcompile($this->getNode('var')) ->raw(' = ') ; if ($this->getNode('expr') instanceof Twig_Node_Expression_Name && '_self' === $this->getNode('expr')->getAttribute('name')) { $compiler->raw("\$this"); } else { $compiler ->raw('$this->env->loadTemplate(') ->subcompile($this->getNode('expr')) ->raw(")") ; } $compiler->raw(";\n"); } } vendor/Twig/Node/Include.php000066400000000000000000000055511516067305400162630ustar00rootroot00000000000000 */ class Twig_Node_Include extends Twig_Node implements Twig_NodeOutputInterface { public function __construct(Twig_Node_Expression $expr, Twig_Node_Expression $variables = null, $only = false, $ignoreMissing = false, $lineno, $tag = null) { parent::__construct(array('expr' => $expr, 'variables' => $variables), array('only' => (Boolean) $only, 'ignore_missing' => (Boolean) $ignoreMissing), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); if ($this->getAttribute('ignore_missing')) { $compiler ->write("try {\n") ->indent() ; } $this->addGetTemplate($compiler); $compiler->raw('->display('); $this->addTemplateArguments($compiler); $compiler->raw(");\n"); if ($this->getAttribute('ignore_missing')) { $compiler ->outdent() ->write("} catch (Twig_Error_Loader \$e) {\n") ->indent() ->write("// ignore missing template\n") ->outdent() ->write("}\n\n") ; } } protected function addGetTemplate(Twig_Compiler $compiler) { if ($this->getNode('expr') instanceof Twig_Node_Expression_Constant) { $compiler ->write("\$this->env->loadTemplate(") ->subcompile($this->getNode('expr')) ->raw(")") ; } else { $compiler ->write("\$template = \$this->env->resolveTemplate(") ->subcompile($this->getNode('expr')) ->raw(");\n") ->write('$template') ; } } protected function addTemplateArguments(Twig_Compiler $compiler) { if (false === $this->getAttribute('only')) { if (null === $this->getNode('variables')) { $compiler->raw('$context'); } else { $compiler ->raw('array_merge($context, ') ->subcompile($this->getNode('variables')) ->raw(')') ; } } else { if (null === $this->getNode('variables')) { $compiler->raw('array()'); } else { $compiler->subcompile($this->getNode('variables')); } } } } vendor/Twig/Node/Macro.php000066400000000000000000000045731516067305400157440ustar00rootroot00000000000000 */ class Twig_Node_Macro extends Twig_Node { public function __construct($name, Twig_NodeInterface $body, Twig_NodeInterface $arguments, $lineno, $tag = null) { parent::__construct(array('body' => $body, 'arguments' => $arguments), array('name' => $name), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $arguments = array(); foreach ($this->getNode('arguments') as $argument) { $arguments[] = '$'.$argument->getAttribute('name').' = null'; } $compiler ->addDebugInfo($this) ->write(sprintf("public function get%s(%s)\n", $this->getAttribute('name'), implode(', ', $arguments)), "{\n") ->indent() ; if (!count($this->getNode('arguments'))) { $compiler->write("\$context = \$this->env->getGlobals();\n\n"); } else { $compiler ->write("\$context = \$this->env->mergeGlobals(array(\n") ->indent() ; foreach ($this->getNode('arguments') as $argument) { $compiler ->write('') ->string($argument->getAttribute('name')) ->raw(' => $'.$argument->getAttribute('name')) ->raw(",\n") ; } $compiler ->outdent() ->write("));\n\n") ; } $compiler ->write("\$blocks = array();\n\n") ->write("ob_start();\n") ->write("try {\n") ->indent() ->subcompile($this->getNode('body')) ->outdent() ->write("} catch(Exception \$e) {\n") ->indent() ->write("ob_end_clean();\n\n") ->write("throw \$e;\n") ->outdent() ->write("}\n\n") ->write("return ob_get_clean();\n") ->outdent() ->write("}\n\n") ; } } vendor/Twig/Node/Module.php000066400000000000000000000266011516067305400161240ustar00rootroot00000000000000 */ class Twig_Node_Module extends Twig_Node { public function __construct(Twig_NodeInterface $body, Twig_Node_Expression $parent = null, Twig_NodeInterface $blocks, Twig_NodeInterface $macros, Twig_NodeInterface $traits, $embeddedTemplates, $filename) { // embedded templates are set as attributes so that they are only visited once by the visitors parent::__construct(array('parent' => $parent, 'body' => $body, 'blocks' => $blocks, 'macros' => $macros, 'traits' => $traits), array('filename' => $filename, 'index' => null, 'embedded_templates' => $embeddedTemplates), 1); } public function setIndex($index) { $this->setAttribute('index', $index); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $this->compileTemplate($compiler); foreach ($this->getAttribute('embedded_templates') as $template) { $compiler->subcompile($template); } } protected function compileTemplate(Twig_Compiler $compiler) { if (!$this->getAttribute('index')) { $compiler->write('compileClassHeader($compiler); if (count($this->getNode('blocks')) || count($this->getNode('traits')) || null === $this->getNode('parent') || $this->getNode('parent') instanceof Twig_Node_Expression_Constant) { $this->compileConstructor($compiler); } $this->compileGetParent($compiler); $this->compileDisplayHeader($compiler); $this->compileDisplayBody($compiler); $this->compileDisplayFooter($compiler); $compiler->subcompile($this->getNode('blocks')); $this->compileMacros($compiler); $this->compileGetTemplateName($compiler); $this->compileIsTraitable($compiler); $this->compileDebugInfo($compiler); $this->compileClassFooter($compiler); } protected function compileGetParent(Twig_Compiler $compiler) { if (null === $this->getNode('parent')) { return; } $compiler ->write("protected function doGetParent(array \$context)\n", "{\n") ->indent() ->write("return ") ; if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { $compiler->subcompile($this->getNode('parent')); } else { $compiler ->raw("\$this->env->resolveTemplate(") ->subcompile($this->getNode('parent')) ->raw(")") ; } $compiler ->raw(";\n") ->outdent() ->write("}\n\n") ; } protected function compileDisplayBody(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('body')); if (null !== $this->getNode('parent')) { if ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { $compiler->write("\$this->parent"); } else { $compiler->write("\$this->getParent(\$context)"); } $compiler->raw("->display(\$context, array_merge(\$this->blocks, \$blocks));\n"); } } protected function compileClassHeader(Twig_Compiler $compiler) { $compiler ->write("\n\n") // if the filename contains */, add a blank to avoid a PHP parse error ->write("/* ".str_replace('*/', '* /', $this->getAttribute('filename'))." */\n") ->write('class '.$compiler->getEnvironment()->getTemplateClass($this->getAttribute('filename'), $this->getAttribute('index'))) ->raw(sprintf(" extends %s\n", $compiler->getEnvironment()->getBaseTemplateClass())) ->write("{\n") ->indent() ; } protected function compileConstructor(Twig_Compiler $compiler) { $compiler ->write("public function __construct(Twig_Environment \$env)\n", "{\n") ->indent() ->write("parent::__construct(\$env);\n\n") ; // parent if (null === $this->getNode('parent')) { $compiler->write("\$this->parent = false;\n\n"); } elseif ($this->getNode('parent') instanceof Twig_Node_Expression_Constant) { $compiler ->write("\$this->parent = \$this->env->loadTemplate(") ->subcompile($this->getNode('parent')) ->raw(");\n\n") ; } $countTraits = count($this->getNode('traits')); if ($countTraits) { // traits foreach ($this->getNode('traits') as $i => $trait) { $this->compileLoadTemplate($compiler, $trait->getNode('template'), sprintf('$_trait_%s', $i)); $compiler ->addDebugInfo($trait->getNode('template')) ->write(sprintf("if (!\$_trait_%s->isTraitable()) {\n", $i)) ->indent() ->write("throw new Twig_Error_Runtime('Template \"'.") ->subcompile($trait->getNode('template')) ->raw(".'\" cannot be used as a trait.');\n") ->outdent() ->write("}\n") ->write(sprintf("\$_trait_%s_blocks = \$_trait_%s->getBlocks();\n\n", $i, $i)) ; foreach ($trait->getNode('targets') as $key => $value) { $compiler ->write(sprintf("\$_trait_%s_blocks[", $i)) ->subcompile($value) ->raw(sprintf("] = \$_trait_%s_blocks[", $i)) ->string($key) ->raw(sprintf("]; unset(\$_trait_%s_blocks[", $i)) ->string($key) ->raw("]);\n\n") ; } } if ($countTraits > 1) { $compiler ->write("\$this->traits = array_merge(\n") ->indent() ; for ($i = 0; $i < $countTraits; $i++) { $compiler ->write(sprintf("\$_trait_%s_blocks".($i == $countTraits - 1 ? '' : ',')."\n", $i)) ; } $compiler ->outdent() ->write(");\n\n") ; } else { $compiler ->write("\$this->traits = \$_trait_0_blocks;\n\n") ; } $compiler ->write("\$this->blocks = array_merge(\n") ->indent() ->write("\$this->traits,\n") ->write("array(\n") ; } else { $compiler ->write("\$this->blocks = array(\n") ; } // blocks $compiler ->indent() ; foreach ($this->getNode('blocks') as $name => $node) { $compiler ->write(sprintf("'%s' => array(\$this, 'block_%s'),\n", $name, $name)) ; } if ($countTraits) { $compiler ->outdent() ->write(")\n") ; } $compiler ->outdent() ->write(");\n") ->outdent() ->write("}\n\n"); ; } protected function compileDisplayHeader(Twig_Compiler $compiler) { $compiler ->write("protected function doDisplay(array \$context, array \$blocks = array())\n", "{\n") ->indent() ; } protected function compileDisplayFooter(Twig_Compiler $compiler) { $compiler ->outdent() ->write("}\n\n") ; } protected function compileClassFooter(Twig_Compiler $compiler) { $compiler ->outdent() ->write("}\n") ; } protected function compileMacros(Twig_Compiler $compiler) { $compiler->subcompile($this->getNode('macros')); } protected function compileGetTemplateName(Twig_Compiler $compiler) { $compiler ->write("public function getTemplateName()\n", "{\n") ->indent() ->write('return ') ->repr($this->getAttribute('filename')) ->raw(";\n") ->outdent() ->write("}\n\n") ; } protected function compileIsTraitable(Twig_Compiler $compiler) { // A template can be used as a trait if: // * it has no parent // * it has no macros // * it has no body // // Put another way, a template can be used as a trait if it // only contains blocks and use statements. $traitable = null === $this->getNode('parent') && 0 === count($this->getNode('macros')); if ($traitable) { if ($this->getNode('body') instanceof Twig_Node_Body) { $nodes = $this->getNode('body')->getNode(0); } else { $nodes = $this->getNode('body'); } if (!count($nodes)) { $nodes = new Twig_Node(array($nodes)); } foreach ($nodes as $node) { if (!count($node)) { continue; } if ($node instanceof Twig_Node_Text && ctype_space($node->getAttribute('data'))) { continue; } if ($node instanceof Twig_Node_BlockReference) { continue; } $traitable = false; break; } } if ($traitable) { return; } $compiler ->write("public function isTraitable()\n", "{\n") ->indent() ->write(sprintf("return %s;\n", $traitable ? 'true' : 'false')) ->outdent() ->write("}\n\n") ; } protected function compileDebugInfo(Twig_Compiler $compiler) { $compiler ->write("public function getDebugInfo()\n", "{\n") ->indent() ->write(sprintf("return %s;\n", str_replace("\n", '', var_export(array_reverse($compiler->getDebugInfo(), true), true)))) ->outdent() ->write("}\n") ; } protected function compileLoadTemplate(Twig_Compiler $compiler, $node, $var) { if ($node instanceof Twig_Node_Expression_Constant) { $compiler ->write(sprintf("%s = \$this->env->loadTemplate(", $var)) ->subcompile($node) ->raw(");\n") ; } else { $compiler ->write(sprintf("%s = ", $var)) ->subcompile($node) ->raw(";\n") ->write(sprintf("if (!%s", $var)) ->raw(" instanceof Twig_Template) {\n") ->indent() ->write(sprintf("%s = \$this->env->loadTemplate(%s);\n", $var, $var)) ->outdent() ->write("}\n") ; } } } vendor/Twig/Node/Print.php000066400000000000000000000016761516067305400160000ustar00rootroot00000000000000 */ class Twig_Node_Print extends Twig_Node implements Twig_NodeOutputInterface { public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) { parent::__construct(array('expr' => $expr), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('echo ') ->subcompile($this->getNode('expr')) ->raw(";\n") ; } } vendor/Twig/Node/Sandbox.php000066400000000000000000000024031516067305400162670ustar00rootroot00000000000000 */ class Twig_Node_Sandbox extends Twig_Node { public function __construct(Twig_NodeInterface $body, $lineno, $tag = null) { parent::__construct(array('body' => $body), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write("\$sandbox = \$this->env->getExtension('sandbox');\n") ->write("if (!\$alreadySandboxed = \$sandbox->isSandboxed()) {\n") ->indent() ->write("\$sandbox->enableSandbox();\n") ->outdent() ->write("}\n") ->subcompile($this->getNode('body')) ->write("if (!\$alreadySandboxed) {\n") ->indent() ->write("\$sandbox->disableSandbox();\n") ->outdent() ->write("}\n") ; } } vendor/Twig/Node/SandboxedModule.php000066400000000000000000000040151516067305400177470ustar00rootroot00000000000000 */ class Twig_Node_SandboxedModule extends Twig_Node_Module { protected $usedFilters; protected $usedTags; protected $usedFunctions; public function __construct(Twig_Node_Module $node, array $usedFilters, array $usedTags, array $usedFunctions) { parent::__construct($node->getNode('body'), $node->getNode('parent'), $node->getNode('blocks'), $node->getNode('macros'), $node->getNode('traits'), $node->getAttribute('embedded_templates'), $node->getAttribute('filename'), $node->getLine(), $node->getNodeTag()); $this->setAttribute('index', $node->getAttribute('index')); $this->usedFilters = $usedFilters; $this->usedTags = $usedTags; $this->usedFunctions = $usedFunctions; } protected function compileDisplayBody(Twig_Compiler $compiler) { $compiler->write("\$this->checkSecurity();\n"); parent::compileDisplayBody($compiler); } protected function compileDisplayFooter(Twig_Compiler $compiler) { parent::compileDisplayFooter($compiler); $compiler ->write("protected function checkSecurity() {\n") ->indent() ->write("\$this->env->getExtension('sandbox')->checkSecurity(\n") ->indent() ->write(!$this->usedTags ? "array(),\n" : "array('".implode('\', \'', $this->usedTags)."'),\n") ->write(!$this->usedFilters ? "array(),\n" : "array('".implode('\', \'', $this->usedFilters)."'),\n") ->write(!$this->usedFunctions ? "array()\n" : "array('".implode('\', \'', $this->usedFunctions)."')\n") ->outdent() ->write(");\n") ->outdent() ->write("}\n\n") ; } } vendor/Twig/Node/SandboxedPrint.php000066400000000000000000000031251516067305400176170ustar00rootroot00000000000000 */ class Twig_Node_SandboxedPrint extends Twig_Node_Print { public function __construct(Twig_Node_Expression $expr, $lineno, $tag = null) { parent::__construct($expr, $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('echo $this->env->getExtension(\'sandbox\')->ensureToStringAllowed(') ->subcompile($this->getNode('expr')) ->raw(");\n") ; } /** * Removes node filters. * * This is mostly needed when another visitor adds filters (like the escaper one). * * @param Twig_Node $node A Node */ protected function removeNodeFilter($node) { if ($node instanceof Twig_Node_Expression_Filter) { return $this->removeNodeFilter($node->getNode('node')); } return $node; } } vendor/Twig/Node/Set.php000066400000000000000000000062601516067305400154310ustar00rootroot00000000000000 */ class Twig_Node_Set extends Twig_Node { public function __construct($capture, Twig_NodeInterface $names, Twig_NodeInterface $values, $lineno, $tag = null) { parent::__construct(array('names' => $names, 'values' => $values), array('capture' => $capture, 'safe' => false), $lineno, $tag); /* * Optimizes the node when capture is used for a large block of text. * * {% set foo %}foo{% endset %} is compiled to $context['foo'] = new Twig_Markup("foo"); */ if ($this->getAttribute('capture')) { $this->setAttribute('safe', true); $values = $this->getNode('values'); if ($values instanceof Twig_Node_Text) { $this->setNode('values', new Twig_Node_Expression_Constant($values->getAttribute('data'), $values->getLine())); $this->setAttribute('capture', false); } } } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler->addDebugInfo($this); if (count($this->getNode('names')) > 1) { $compiler->write('list('); foreach ($this->getNode('names') as $idx => $node) { if ($idx) { $compiler->raw(', '); } $compiler->subcompile($node); } $compiler->raw(')'); } else { if ($this->getAttribute('capture')) { $compiler ->write("ob_start();\n") ->subcompile($this->getNode('values')) ; } $compiler->subcompile($this->getNode('names'), false); if ($this->getAttribute('capture')) { $compiler->raw(" = ('' === \$tmp = ob_get_clean()) ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())"); } } if (!$this->getAttribute('capture')) { $compiler->raw(' = '); if (count($this->getNode('names')) > 1) { $compiler->write('array('); foreach ($this->getNode('values') as $idx => $value) { if ($idx) { $compiler->raw(', '); } $compiler->subcompile($value); } $compiler->raw(')'); } else { if ($this->getAttribute('safe')) { $compiler ->raw("('' === \$tmp = ") ->subcompile($this->getNode('values')) ->raw(") ? '' : new Twig_Markup(\$tmp, \$this->env->getCharset())") ; } else { $compiler->subcompile($this->getNode('values')); } } } $compiler->raw(";\n"); } } vendor/Twig/Node/SetTemp.php000066400000000000000000000015101516067305400162500ustar00rootroot00000000000000 $name), $lineno); } public function compile(Twig_Compiler $compiler) { $name = $this->getAttribute('name'); $compiler ->addDebugInfo($this) ->write('if (isset($context[') ->string($name) ->raw('])) { $_') ->raw($name) ->raw('_ = $context[') ->repr($name) ->raw(']; } else { $_') ->raw($name) ->raw("_ = null; }\n") ; } } vendor/Twig/Node/Spaceless.php000066400000000000000000000017441516067305400166220ustar00rootroot00000000000000 */ class Twig_Node_Spaceless extends Twig_Node { public function __construct(Twig_NodeInterface $body, $lineno, $tag = 'spaceless') { parent::__construct(array('body' => $body), array(), $lineno, $tag); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write("ob_start();\n") ->subcompile($this->getNode('body')) ->write("echo trim(preg_replace('/>\s+<', ob_get_clean()));\n") ; } } vendor/Twig/Node/Text.php000066400000000000000000000016001516067305400156130ustar00rootroot00000000000000 */ class Twig_Node_Text extends Twig_Node implements Twig_NodeOutputInterface { public function __construct($data, $lineno) { parent::__construct(array(), array('data' => $data), $lineno); } /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ public function compile(Twig_Compiler $compiler) { $compiler ->addDebugInfo($this) ->write('echo ') ->string($this->getAttribute('data')) ->raw(";\n") ; } } vendor/Twig/NodeInterface.php000066400000000000000000000011331516067305400165110ustar00rootroot00000000000000 */ interface Twig_NodeInterface extends Countable, IteratorAggregate { /** * Compiles the node to PHP. * * @param Twig_Compiler A Twig_Compiler instance */ function compile(Twig_Compiler $compiler); function getLine(); function getNodeTag(); } vendor/Twig/NodeOutputInterface.php000066400000000000000000000005671516067305400177440ustar00rootroot00000000000000 */ interface Twig_NodeOutputInterface { } vendor/Twig/NodeTraverser.php000066400000000000000000000044631516067305400165770ustar00rootroot00000000000000 */ class Twig_NodeTraverser { protected $env; protected $visitors; /** * Constructor. * * @param Twig_Environment $env A Twig_Environment instance * @param array $visitors An array of Twig_NodeVisitorInterface instances */ public function __construct(Twig_Environment $env, array $visitors = array()) { $this->env = $env; $this->visitors = array(); foreach ($visitors as $visitor) { $this->addVisitor($visitor); } } /** * Adds a visitor. * * @param Twig_NodeVisitorInterface $visitor A Twig_NodeVisitorInterface instance */ public function addVisitor(Twig_NodeVisitorInterface $visitor) { if (!isset($this->visitors[$visitor->getPriority()])) { $this->visitors[$visitor->getPriority()] = array(); } $this->visitors[$visitor->getPriority()][] = $visitor; } /** * Traverses a node and calls the registered visitors. * * @param Twig_NodeInterface $node A Twig_NodeInterface instance */ public function traverse(Twig_NodeInterface $node) { ksort($this->visitors); foreach ($this->visitors as $visitors) { foreach ($visitors as $visitor) { $node = $this->traverseForVisitor($visitor, $node); } } return $node; } protected function traverseForVisitor(Twig_NodeVisitorInterface $visitor, Twig_NodeInterface $node = null) { if (null === $node) { return null; } $node = $visitor->enterNode($node, $this->env); foreach ($node as $k => $n) { if (false !== $n = $this->traverseForVisitor($visitor, $n)) { $node->setNode($k, $n); } else { $node->removeNode($k); } } return $visitor->leaveNode($node, $this->env); } } vendor/Twig/NodeVisitor/000077500000000000000000000000001516067305400155415ustar00rootroot00000000000000vendor/Twig/NodeVisitor/Escaper.php000066400000000000000000000121041516067305400176320ustar00rootroot00000000000000 */ class Twig_NodeVisitor_Escaper implements Twig_NodeVisitorInterface { protected $statusStack = array(); protected $blocks = array(); protected $safeAnalysis; protected $traverser; protected $defaultStrategy = false; public function __construct() { $this->safeAnalysis = new Twig_NodeVisitor_SafeAnalysis(); } /** * Called before child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { if ($env->hasExtension('escaper') && $defaultStrategy = $env->getExtension('escaper')->getDefaultStrategy($node->getAttribute('filename'))) { $this->defaultStrategy = $defaultStrategy; } } elseif ($node instanceof Twig_Node_AutoEscape) { $this->statusStack[] = $node->getAttribute('value'); } elseif ($node instanceof Twig_Node_Block) { $this->statusStack[] = isset($this->blocks[$node->getAttribute('name')]) ? $this->blocks[$node->getAttribute('name')] : $this->needEscaping($env); } return $node; } /** * Called after child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { $this->defaultStrategy = false; } elseif ($node instanceof Twig_Node_Expression_Filter) { return $this->preEscapeFilterNode($node, $env); } elseif ($node instanceof Twig_Node_Print) { return $this->escapePrintNode($node, $env, $this->needEscaping($env)); } if ($node instanceof Twig_Node_AutoEscape || $node instanceof Twig_Node_Block) { array_pop($this->statusStack); } elseif ($node instanceof Twig_Node_BlockReference) { $this->blocks[$node->getAttribute('name')] = $this->needEscaping($env); } return $node; } protected function escapePrintNode(Twig_Node_Print $node, Twig_Environment $env, $type) { if (false === $type) { return $node; } $expression = $node->getNode('expr'); if ($this->isSafeFor($type, $expression, $env)) { return $node; } $class = get_class($node); return new $class( $this->getEscaperFilter($type, $expression), $node->getLine() ); } protected function preEscapeFilterNode(Twig_Node_Expression_Filter $filter, Twig_Environment $env) { $name = $filter->getNode('filter')->getAttribute('value'); if (false !== $f = $env->getFilter($name)) { $type = $f->getPreEscape(); if (null === $type) { return $filter; } $node = $filter->getNode('node'); if ($this->isSafeFor($type, $node, $env)) { return $filter; } $filter->setNode('node', $this->getEscaperFilter($type, $node)); return $filter; } return $filter; } protected function isSafeFor($type, Twig_NodeInterface $expression, $env) { $safe = $this->safeAnalysis->getSafe($expression); if (null === $safe) { if (null === $this->traverser) { $this->traverser = new Twig_NodeTraverser($env, array($this->safeAnalysis)); } $this->traverser->traverse($expression); $safe = $this->safeAnalysis->getSafe($expression); } return in_array($type, $safe) || in_array('all', $safe); } protected function needEscaping(Twig_Environment $env) { if (count($this->statusStack)) { return $this->statusStack[count($this->statusStack) - 1]; } return $this->defaultStrategy ? $this->defaultStrategy : false; } protected function getEscaperFilter($type, Twig_NodeInterface $node) { $line = $node->getLine(); $name = new Twig_Node_Expression_Constant('escape', $line); $args = new Twig_Node(array(new Twig_Node_Expression_Constant((string) $type, $line), new Twig_Node_Expression_Constant(null, $line), new Twig_Node_Expression_Constant(true, $line))); return new Twig_Node_Expression_Filter($node, $name, $args, $line); } /** * {@inheritdoc} */ public function getPriority() { return 0; } } vendor/Twig/NodeVisitor/Optimizer.php000066400000000000000000000171021516067305400202350ustar00rootroot00000000000000 */ class Twig_NodeVisitor_Optimizer implements Twig_NodeVisitorInterface { const OPTIMIZE_ALL = -1; const OPTIMIZE_NONE = 0; const OPTIMIZE_FOR = 2; const OPTIMIZE_RAW_FILTER = 4; const OPTIMIZE_VAR_ACCESS = 8; protected $loops = array(); protected $optimizers; protected $prependedNodes = array(); protected $inABody = false; /** * Constructor. * * @param integer $optimizers The optimizer mode */ public function __construct($optimizers = -1) { if (!is_int($optimizers) || $optimizers > 2) { throw new InvalidArgumentException(sprintf('Optimizer mode "%s" is not valid.', $optimizers)); } $this->optimizers = $optimizers; } /** * {@inheritdoc} */ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { $this->enterOptimizeFor($node, $env); } if (!version_compare(phpversion(), '5.4.0RC1', '>=') && self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { if ($this->inABody) { if (!$node instanceof Twig_Node_Expression) { if (get_class($node) !== 'Twig_Node') { array_unshift($this->prependedNodes, array()); } } else { $node = $this->optimizeVariables($node, $env); } } elseif ($node instanceof Twig_Node_Body) { $this->inABody = true; } } return $node; } /** * {@inheritdoc} */ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { $expression = $node instanceof Twig_Node_Expression; if (self::OPTIMIZE_FOR === (self::OPTIMIZE_FOR & $this->optimizers)) { $this->leaveOptimizeFor($node, $env); } if (self::OPTIMIZE_RAW_FILTER === (self::OPTIMIZE_RAW_FILTER & $this->optimizers)) { $node = $this->optimizeRawFilter($node, $env); } $node = $this->optimizePrintNode($node, $env); if (self::OPTIMIZE_VAR_ACCESS === (self::OPTIMIZE_VAR_ACCESS & $this->optimizers) && !$env->isStrictVariables() && !$env->hasExtension('sandbox')) { if ($node instanceof Twig_Node_Body) { $this->inABody = false; } elseif ($this->inABody) { if (!$expression && get_class($node) !== 'Twig_Node' && $prependedNodes = array_shift($this->prependedNodes)) { $nodes = array(); foreach (array_unique($prependedNodes) as $name) { $nodes[] = new Twig_Node_SetTemp($name, $node->getLine()); } $nodes[] = $node; $node = new Twig_Node($nodes); } } } return $node; } protected function optimizeVariables($node, $env) { if ('Twig_Node_Expression_Name' === get_class($node) && $node->isSimple()) { $this->prependedNodes[0][] = $node->getAttribute('name'); return new Twig_Node_Expression_TempName($node->getAttribute('name'), $node->getLine()); } return $node; } /** * Optimizes print nodes. * * It replaces: * * * "echo $this->render(Parent)Block()" with "$this->display(Parent)Block()" * * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ protected function optimizePrintNode($node, $env) { if (!$node instanceof Twig_Node_Print) { return $node; } if ( $node->getNode('expr') instanceof Twig_Node_Expression_BlockReference || $node->getNode('expr') instanceof Twig_Node_Expression_Parent ) { $node->getNode('expr')->setAttribute('output', true); return $node->getNode('expr'); } return $node; } /** * Removes "raw" filters. * * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ protected function optimizeRawFilter($node, $env) { if ($node instanceof Twig_Node_Expression_Filter && 'raw' == $node->getNode('filter')->getAttribute('value')) { return $node->getNode('node'); } return $node; } /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. * * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ protected function enterOptimizeFor($node, $env) { if ($node instanceof Twig_Node_For) { // disable the loop variable by default $node->setAttribute('with_loop', false); array_unshift($this->loops, $node); } elseif (!$this->loops) { // we are outside a loop return; } // when do we need to add the loop variable back? // the loop variable is referenced for the current loop elseif ($node instanceof Twig_Node_Expression_Name && 'loop' === $node->getAttribute('name')) { $this->addLoopToCurrent(); } // block reference elseif ($node instanceof Twig_Node_BlockReference || $node instanceof Twig_Node_Expression_BlockReference) { $this->addLoopToCurrent(); } // include without the only attribute elseif ($node instanceof Twig_Node_Include && !$node->getAttribute('only')) { $this->addLoopToAll(); } // the loop variable is referenced via an attribute elseif ($node instanceof Twig_Node_Expression_GetAttr && (!$node->getNode('attribute') instanceof Twig_Node_Expression_Constant || 'parent' === $node->getNode('attribute')->getAttribute('value') ) && (true === $this->loops[0]->getAttribute('with_loop') || ($node->getNode('node') instanceof Twig_Node_Expression_Name && 'loop' === $node->getNode('node')->getAttribute('name') ) ) ) { $this->addLoopToAll(); } } /** * Optimizes "for" tag by removing the "loop" variable creation whenever possible. * * @param Twig_NodeInterface $node A Node * @param Twig_Environment $env The current Twig environment */ protected function leaveOptimizeFor($node, $env) { if ($node instanceof Twig_Node_For) { array_shift($this->loops); } } protected function addLoopToCurrent() { $this->loops[0]->setAttribute('with_loop', true); } protected function addLoopToAll() { foreach ($this->loops as $loop) { $loop->setAttribute('with_loop', true); } } /** * {@inheritdoc} */ public function getPriority() { return 255; } } vendor/Twig/NodeVisitor/SafeAnalysis.php000066400000000000000000000074511516067305400206430ustar00rootroot00000000000000data[$hash])) { foreach($this->data[$hash] as $bucket) { if ($bucket['key'] === $node) { return $bucket['value']; } } } return null; } protected function setSafe(Twig_NodeInterface $node, array $safe) { $hash = spl_object_hash($node); if (isset($this->data[$hash])) { foreach($this->data[$hash] as &$bucket) { if ($bucket['key'] === $node) { $bucket['value'] = $safe; return; } } } $this->data[$hash][] = array( 'key' => $node, 'value' => $safe, ); } public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { return $node; } public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Expression_Constant) { // constants are marked safe for all $this->setSafe($node, array('all')); } elseif ($node instanceof Twig_Node_Expression_BlockReference) { // blocks are safe by definition $this->setSafe($node, array('all')); } elseif ($node instanceof Twig_Node_Expression_Parent) { // parent block is safe by definition $this->setSafe($node, array('all')); } elseif ($node instanceof Twig_Node_Expression_Conditional) { // intersect safeness of both operands $safe = $this->intersectSafe($this->getSafe($node->getNode('expr2')), $this->getSafe($node->getNode('expr3'))); $this->setSafe($node, $safe); } elseif ($node instanceof Twig_Node_Expression_Filter) { // filter expression is safe when the filter is safe $name = $node->getNode('filter')->getAttribute('value'); $args = $node->getNode('arguments'); if (false !== $filter = $env->getFilter($name)) { $safe = $filter->getSafe($args); if (null === $safe) { $safe = $this->intersectSafe($this->getSafe($node->getNode('node')), $filter->getPreservesSafety()); } $this->setSafe($node, $safe); } else { $this->setSafe($node, array()); } } elseif ($node instanceof Twig_Node_Expression_Function) { // function expression is safe when the function is safe $name = $node->getAttribute('name'); $args = $node->getNode('arguments'); $function = $env->getFunction($name); if (false !== $function) { $this->setSafe($node, $function->getSafe($args)); } else { $this->setSafe($node, array()); } } elseif ($node instanceof Twig_Node_Expression_MethodCall) { if ($node->getAttribute('safe')) { $this->setSafe($node, array('all')); } else { $this->setSafe($node, array()); } } else { $this->setSafe($node, array()); } return $node; } protected function intersectSafe(array $a = null, array $b = null) { if (null === $a || null === $b) { return array(); } if (in_array('all', $a)) { return $b; } if (in_array('all', $b)) { return $a; } return array_intersect($a, $b); } /** * {@inheritdoc} */ public function getPriority() { return 0; } } vendor/Twig/NodeVisitor/Sandbox.php000066400000000000000000000062111516067305400176500ustar00rootroot00000000000000 */ class Twig_NodeVisitor_Sandbox implements Twig_NodeVisitorInterface { protected $inAModule = false; protected $tags; protected $filters; protected $functions; /** * Called before child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { // in a sandbox tag, only include tags are allowed if ($node instanceof Twig_Node_Sandbox && !$node->getNode('body') instanceof Twig_Node_Include) { foreach ($node->getNode('body') as $n) { if ($n instanceof Twig_Node_Text && ctype_space($n->getAttribute('data'))) { continue; } if (!$n instanceof Twig_Node_Include) { throw new Twig_Error_Syntax('Only "include" tags are allowed within a "sandbox" section', $n->getLine()); } } } if ($node instanceof Twig_Node_Module) { $this->inAModule = true; $this->tags = array(); $this->filters = array(); $this->functions = array(); return $node; } elseif ($this->inAModule) { // look for tags if ($node->getNodeTag()) { $this->tags[] = $node->getNodeTag(); } // look for filters if ($node instanceof Twig_Node_Expression_Filter) { $this->filters[] = $node->getNode('filter')->getAttribute('value'); } // look for functions if ($node instanceof Twig_Node_Expression_Function) { $this->functions[] = $node->getAttribute('name'); } // wrap print to check __toString() calls if ($node instanceof Twig_Node_Print) { return new Twig_Node_SandboxedPrint($node->getNode('expr'), $node->getLine(), $node->getNodeTag()); } } return $node; } /** * Called after child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { if ($node instanceof Twig_Node_Module) { $this->inAModule = false; return new Twig_Node_SandboxedModule($node, array_unique($this->filters), array_unique($this->tags), array_unique($this->functions)); } return $node; } /** * {@inheritdoc} */ public function getPriority() { return 0; } } vendor/Twig/NodeVisitorInterface.php000066400000000000000000000024101516067305400200700ustar00rootroot00000000000000 */ interface Twig_NodeVisitorInterface { /** * Called before child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ function enterNode(Twig_NodeInterface $node, Twig_Environment $env); /** * Called after child nodes are visited. * * @param Twig_NodeInterface $node The node to visit * @param Twig_Environment $env The Twig environment instance * * @return Twig_NodeInterface The modified node */ function leaveNode(Twig_NodeInterface $node, Twig_Environment $env); /** * Returns the priority for this visitor. * * Priority should be between -10 and 10 (0 is the default). * * @return integer The priority level */ function getPriority(); } vendor/Twig/Parser.php000066400000000000000000000265701516067305400152530ustar00rootroot00000000000000 */ class Twig_Parser implements Twig_ParserInterface { protected $stack = array(); protected $stream; protected $parent; protected $handlers; protected $visitors; protected $expressionParser; protected $blocks; protected $blockStack; protected $macros; protected $env; protected $reservedMacroNames; protected $importedFunctions; protected $tmpVarCount; protected $traits; protected $embeddedTemplates = array(); /** * Constructor. * * @param Twig_Environment $env A Twig_Environment instance */ public function __construct(Twig_Environment $env) { $this->env = $env; } public function getEnvironment() { return $this->env; } public function getVarName() { return sprintf('__internal_%s_%d', substr($this->env->getTemplateClass($this->stream->getFilename()), strlen($this->env->getTemplateClassPrefix())), ++$this->tmpVarCount); } /** * Converts a token stream to a node tree. * * @param Twig_TokenStream $stream A token stream instance * * @return Twig_Node_Module A node tree */ public function parse(Twig_TokenStream $stream, $test = null, $dropNeedle = false) { // push all variables into the stack to keep the current state of the parser $vars = get_object_vars($this); unset($vars['stack'], $vars['env'], $vars['handlers'], $vars['visitors'], $vars['expressionParser']); $this->stack[] = $vars; $this->tmpVarCount = 0; // tag handlers if (null === $this->handlers) { $this->handlers = $this->env->getTokenParsers(); $this->handlers->setParser($this); } // node visitors if (null === $this->visitors) { $this->visitors = $this->env->getNodeVisitors(); } if (null === $this->expressionParser) { $this->expressionParser = new Twig_ExpressionParser($this, $this->env->getUnaryOperators(), $this->env->getBinaryOperators()); } $this->stream = $stream; $this->parent = null; $this->blocks = array(); $this->macros = array(); $this->traits = array(); $this->blockStack = array(); $this->importedFunctions = array(array()); $this->embeddedTemplates = array(); try { $body = $this->subparse($test, $dropNeedle); if (null !== $this->parent) { if (null === $body = $this->filterBodyNodes($body)) { $body = new Twig_Node(); } } } catch (Twig_Error_Syntax $e) { if (null === $e->getTemplateFile()) { $e->setTemplateFile($this->stream->getFilename()); } throw $e; } $node = new Twig_Node_Module(new Twig_Node_Body(array($body)), $this->parent, new Twig_Node($this->blocks), new Twig_Node($this->macros), new Twig_Node($this->traits), $this->embeddedTemplates, $this->stream->getFilename()); $traverser = new Twig_NodeTraverser($this->env, $this->visitors); $node = $traverser->traverse($node); // restore previous stack so previous parse() call can resume working foreach (array_pop($this->stack) as $key => $val) { $this->$key = $val; } return $node; } public function subparse($test, $dropNeedle = false) { $lineno = $this->getCurrentToken()->getLine(); $rv = array(); while (!$this->stream->isEOF()) { switch ($this->getCurrentToken()->getType()) { case Twig_Token::TEXT_TYPE: $token = $this->stream->next(); $rv[] = new Twig_Node_Text($token->getValue(), $token->getLine()); break; case Twig_Token::VAR_START_TYPE: $token = $this->stream->next(); $expr = $this->expressionParser->parseExpression(); $this->stream->expect(Twig_Token::VAR_END_TYPE); $rv[] = new Twig_Node_Print($expr, $token->getLine()); break; case Twig_Token::BLOCK_START_TYPE: $this->stream->next(); $token = $this->getCurrentToken(); if ($token->getType() !== Twig_Token::NAME_TYPE) { throw new Twig_Error_Syntax('A block must start with a tag name', $token->getLine(), $this->stream->getFilename()); } if (null !== $test && call_user_func($test, $token)) { if ($dropNeedle) { $this->stream->next(); } if (1 === count($rv)) { return $rv[0]; } return new Twig_Node($rv, array(), $lineno); } $subparser = $this->handlers->getTokenParser($token->getValue()); if (null === $subparser) { if (null !== $test) { throw new Twig_Error_Syntax(sprintf('Unexpected tag name "%s" (expecting closing tag for the "%s" tag defined near line %s)', $token->getValue(), $test[0]->getTag(), $lineno), $token->getLine(), $this->stream->getFilename()); } $message = sprintf('Unknown tag name "%s"', $token->getValue()); if ($alternatives = $this->env->computeAlternatives($token->getValue(), array_keys($this->env->getTags()))) { $message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives)); } throw new Twig_Error_Syntax($message, $token->getLine(), $this->stream->getFilename()); } $this->stream->next(); $node = $subparser->parse($token); if (null !== $node) { $rv[] = $node; } break; default: throw new Twig_Error_Syntax('Lexer or parser ended up in unsupported state.', -1, $this->stream->getFilename()); } } if (1 === count($rv)) { return $rv[0]; } return new Twig_Node($rv, array(), $lineno); } public function addHandler($name, $class) { $this->handlers[$name] = $class; } public function addNodeVisitor(Twig_NodeVisitorInterface $visitor) { $this->visitors[] = $visitor; } public function getBlockStack() { return $this->blockStack; } public function peekBlockStack() { return $this->blockStack[count($this->blockStack) - 1]; } public function popBlockStack() { array_pop($this->blockStack); } public function pushBlockStack($name) { $this->blockStack[] = $name; } public function hasBlock($name) { return isset($this->blocks[$name]); } public function getBlock($name) { return $this->blocks[$name]; } public function setBlock($name, $value) { $this->blocks[$name] = new Twig_Node_Body(array($value), array(), $value->getLine()); } public function hasMacro($name) { return isset($this->macros[$name]); } public function setMacro($name, Twig_Node_Macro $node) { if (null === $this->reservedMacroNames) { $this->reservedMacroNames = array(); $r = new ReflectionClass($this->env->getBaseTemplateClass()); foreach ($r->getMethods() as $method) { $this->reservedMacroNames[] = $method->getName(); } } if (in_array($name, $this->reservedMacroNames)) { throw new Twig_Error_Syntax(sprintf('"%s" cannot be used as a macro name as it is a reserved keyword', $name), $node->getLine()); } $this->macros[$name] = $node; } public function addTrait($trait) { $this->traits[] = $trait; } public function hasTraits() { return count($this->traits) > 0; } public function embedTemplate(Twig_Node_Module $template) { $template->setIndex(count($this->embeddedTemplates) + 1); $this->embeddedTemplates[] = $template; } public function addImportedFunction($alias, $name, Twig_Node_Expression $node) { $this->importedFunctions[0][$alias] = array('name' => $name, 'node' => $node); } public function getImportedFunction($alias) { foreach ($this->importedFunctions as $functions) { if (isset($functions[$alias])) { return $functions[$alias]; } } } public function isMainScope() { return 1 === count($this->importedFunctions); } public function pushLocalScope() { array_unshift($this->importedFunctions, array()); } public function popLocalScope() { array_shift($this->importedFunctions); } /** * Gets the expression parser. * * @return Twig_ExpressionParser The expression parser */ public function getExpressionParser() { return $this->expressionParser; } public function getParent() { return $this->parent; } public function setParent($parent) { $this->parent = $parent; } /** * Gets the token stream. * * @return Twig_TokenStream The token stream */ public function getStream() { return $this->stream; } /** * Gets the current token. * * @return Twig_Token The current token */ public function getCurrentToken() { return $this->stream->getCurrent(); } protected function filterBodyNodes(Twig_NodeInterface $node) { // check that the body does not contain non-empty output nodes if ( ($node instanceof Twig_Node_Text && !ctype_space($node->getAttribute('data'))) || (!$node instanceof Twig_Node_Text && !$node instanceof Twig_Node_BlockReference && $node instanceof Twig_NodeOutputInterface) ) { if (false !== strpos((string) $node, chr(0xEF).chr(0xBB).chr(0xBF))) { throw new Twig_Error_Syntax('A template that extends another one cannot have a body but a byte order mark (BOM) has been detected; it must be removed.', $node->getLine(), $this->stream->getFilename()); } throw new Twig_Error_Syntax('A template that extends another one cannot have a body.', $node->getLine(), $this->stream->getFilename()); } // bypass "set" nodes as they "capture" the output if ($node instanceof Twig_Node_Set) { return $node; } if ($node instanceof Twig_NodeOutputInterface) { return; } foreach ($node as $k => $n) { if (null !== $n && null === $n = $this->filterBodyNodes($n)) { $node->removeNode($k); } } return $node; } } vendor/Twig/ParserInterface.php000066400000000000000000000011231516067305400170570ustar00rootroot00000000000000 */ interface Twig_ParserInterface { /** * Converts a token stream to a node tree. * * @param Twig_TokenStream $stream A token stream instance * * @return Twig_Node_Module A node tree */ function parse(Twig_TokenStream $stream); } vendor/Twig/Sandbox/000077500000000000000000000000001516067305400146725ustar00rootroot00000000000000vendor/Twig/Sandbox/SecurityError.php000066400000000000000000000006301516067305400202230ustar00rootroot00000000000000 */ class Twig_Sandbox_SecurityError extends Twig_Error { } vendor/Twig/Sandbox/SecurityPolicy.php000066400000000000000000000072241516067305400203770ustar00rootroot00000000000000 */ class Twig_Sandbox_SecurityPolicy implements Twig_Sandbox_SecurityPolicyInterface { protected $allowedTags; protected $allowedFilters; protected $allowedMethods; protected $allowedProperties; protected $allowedFunctions; public function __construct(array $allowedTags = array(), array $allowedFilters = array(), array $allowedMethods = array(), array $allowedProperties = array(), array $allowedFunctions = array()) { $this->allowedTags = $allowedTags; $this->allowedFilters = $allowedFilters; $this->setAllowedMethods($allowedMethods); $this->allowedProperties = $allowedProperties; $this->allowedFunctions = $allowedFunctions; } public function setAllowedTags(array $tags) { $this->allowedTags = $tags; } public function setAllowedFilters(array $filters) { $this->allowedFilters = $filters; } public function setAllowedMethods(array $methods) { $this->allowedMethods = array(); foreach ($methods as $class => $m) { $this->allowedMethods[$class] = array_map('strtolower', is_array($m) ? $m : array($m)); } } public function setAllowedProperties(array $properties) { $this->allowedProperties = $properties; } public function setAllowedFunctions(array $functions) { $this->allowedFunctions = $functions; } public function checkSecurity($tags, $filters, $functions) { foreach ($tags as $tag) { if (!in_array($tag, $this->allowedTags)) { throw new Twig_Sandbox_SecurityError(sprintf('Tag "%s" is not allowed.', $tag)); } } foreach ($filters as $filter) { if (!in_array($filter, $this->allowedFilters)) { throw new Twig_Sandbox_SecurityError(sprintf('Filter "%s" is not allowed.', $filter)); } } foreach ($functions as $function) { if (!in_array($function, $this->allowedFunctions)) { throw new Twig_Sandbox_SecurityError(sprintf('Function "%s" is not allowed.', $function)); } } } public function checkMethodAllowed($obj, $method) { if ($obj instanceof Twig_TemplateInterface || $obj instanceof Twig_Markup) { return true; } $allowed = false; $method = strtolower($method); foreach ($this->allowedMethods as $class => $methods) { if ($obj instanceof $class) { $allowed = in_array($method, $methods); break; } } if (!$allowed) { throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, get_class($obj))); } } public function checkPropertyAllowed($obj, $property) { $allowed = false; foreach ($this->allowedProperties as $class => $properties) { if ($obj instanceof $class) { $allowed = in_array($property, is_array($properties) ? $properties : array($properties)); break; } } if (!$allowed) { throw new Twig_Sandbox_SecurityError(sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, get_class($obj))); } } } vendor/Twig/Sandbox/SecurityPolicyInterface.php000066400000000000000000000010631516067305400222130ustar00rootroot00000000000000 */ interface Twig_Sandbox_SecurityPolicyInterface { function checkSecurity($tags, $filters, $functions); function checkMethodAllowed($obj, $method); function checkPropertyAllowed($obj, $method); } vendor/Twig/Template.php000066400000000000000000000335471516067305400155740ustar00rootroot00000000000000 */ abstract class Twig_Template implements Twig_TemplateInterface { static protected $cache = array(); protected $parent; protected $parents; protected $env; protected $blocks; protected $traits; /** * Constructor. * * @param Twig_Environment $env A Twig_Environment instance */ public function __construct(Twig_Environment $env) { $this->env = $env; $this->blocks = array(); $this->traits = array(); } /** * Returns the template name. * * @return string The template name */ abstract public function getTemplateName(); /** * {@inheritdoc} */ public function getEnvironment() { return $this->env; } /** * Returns the parent template. * * This method is for internal use only and should never be called * directly. * * @return Twig_TemplateInterface|false The parent template or false if there is no parent */ public function getParent(array $context) { if (null !== $this->parent) { return $this->parent; } $parent = $this->doGetParent($context); if (false === $parent) { return false; } elseif ($parent instanceof Twig_Template) { $name = $parent->getTemplateName(); $this->parents[$name] = $parent; $parent = $name; } elseif (!isset($this->parents[$parent])) { $this->parents[$parent] = $this->env->loadTemplate($parent); } return $this->parents[$parent]; } protected function doGetParent(array $context) { return false; } public function isTraitable() { return true; } /** * Displays a parent block. * * This method is for internal use only and should never be called * directly. * * @param string $name The block name to display from the parent * @param array $context The context * @param array $blocks The current set of blocks */ public function displayParentBlock($name, array $context, array $blocks = array()) { $name = (string) $name; if (isset($this->traits[$name])) { $this->traits[$name][0]->displayBlock($name, $context, $blocks); } elseif (false !== $parent = $this->getParent($context)) { $parent->displayBlock($name, $context, $blocks); } else { throw new Twig_Error_Runtime(sprintf('The template has no parent and no traits defining the "%s" block', $name), -1, $this->getTemplateName()); } } /** * Displays a block. * * This method is for internal use only and should never be called * directly. * * @param string $name The block name to display * @param array $context The context * @param array $blocks The current set of blocks */ public function displayBlock($name, array $context, array $blocks = array()) { $name = (string) $name; if (isset($blocks[$name])) { $b = $blocks; unset($b[$name]); call_user_func($blocks[$name], $context, $b); } elseif (isset($this->blocks[$name])) { call_user_func($this->blocks[$name], $context, $blocks); } elseif (false !== $parent = $this->getParent($context)) { $parent->displayBlock($name, $context, array_merge($this->blocks, $blocks)); } } /** * Renders a parent block. * * This method is for internal use only and should never be called * directly. * * @param string $name The block name to render from the parent * @param array $context The context * @param array $blocks The current set of blocks * * @return string The rendered block */ public function renderParentBlock($name, array $context, array $blocks = array()) { ob_start(); $this->displayParentBlock($name, $context, $blocks); return ob_get_clean(); } /** * Renders a block. * * This method is for internal use only and should never be called * directly. * * @param string $name The block name to render * @param array $context The context * @param array $blocks The current set of blocks * * @return string The rendered block */ public function renderBlock($name, array $context, array $blocks = array()) { ob_start(); $this->displayBlock($name, $context, $blocks); return ob_get_clean(); } /** * Returns whether a block exists or not. * * This method is for internal use only and should never be called * directly. * * This method does only return blocks defined in the current template * or defined in "used" traits. * * It does not return blocks from parent templates as the parent * template name can be dynamic, which is only known based on the * current context. * * @param string $name The block name * * @return Boolean true if the block exists, false otherwise */ public function hasBlock($name) { return isset($this->blocks[(string) $name]); } /** * Returns all block names. * * This method is for internal use only and should never be called * directly. * * @return array An array of block names * * @see hasBlock */ public function getBlockNames() { return array_keys($this->blocks); } /** * Returns all blocks. * * This method is for internal use only and should never be called * directly. * * @return array An array of blocks * * @see hasBlock */ public function getBlocks() { return $this->blocks; } /** * {@inheritdoc} */ public function display(array $context, array $blocks = array()) { $this->displayWithErrorHandling($this->env->mergeGlobals($context), $blocks); } /** * {@inheritdoc} */ public function render(array $context) { $level = ob_get_level(); ob_start(); try { $this->display($context); } catch (Exception $e) { while (ob_get_level() > $level) { ob_end_clean(); } throw $e; } return ob_get_clean(); } protected function displayWithErrorHandling(array $context, array $blocks = array()) { try { $this->doDisplay($context, $blocks); } catch (Twig_Error $e) { throw $e; } catch (Exception $e) { throw new Twig_Error_Runtime(sprintf('An exception has been thrown during the rendering of a template ("%s").', $e->getMessage()), -1, null, $e); } } /** * Auto-generated method to display the template with the given context. * * @param array $context An array of parameters to pass to the template * @param array $blocks An array of blocks to pass to the template */ abstract protected function doDisplay(array $context, array $blocks = array()); /** * Returns a variable from the context. * * This method is for internal use only and should never be called * directly. * * This method should not be overriden in a sub-class as this is an * implementation detail that has been introduced to optimize variable * access for versions of PHP before 5.4. This is not a way to override * the way to get a variable value. * * @param array $context The context * @param string $item The variable to return from the context * @param Boolean $ignoreStrictCheck Whether to ignore the strict variable check or not * * @return The content of the context variable * * @throws Twig_Error_Runtime if the variable does not exist and Twig is running in strict mode */ final protected function getContext($context, $item, $ignoreStrictCheck = false) { if (!array_key_exists($item, $context)) { if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } throw new Twig_Error_Runtime(sprintf('Variable "%s" does not exist', $item)); } return $context[$item]; } /** * Returns the attribute value for a given array/object. * * @param mixed $object The object or array from where to get the item * @param mixed $item The item to get from the array or object * @param array $arguments An array of arguments to pass if the item is an object method * @param string $type The type of attribute (@see Twig_TemplateInterface) * @param Boolean $isDefinedTest Whether this is only a defined check * @param Boolean $ignoreStrictCheck Whether to ignore the strict attribute check or not * * @return mixed The attribute value, or a Boolean when $isDefinedTest is true, or null when the attribute is not set and $ignoreStrictCheck is true * * @throws Twig_Error_Runtime if the attribute does not exist and Twig is running in strict mode and $isDefinedTest is false */ protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false) { $item = (string) $item; // array if (Twig_TemplateInterface::METHOD_CALL !== $type) { if ((is_array($object) && array_key_exists($item, $object)) || ($object instanceof ArrayAccess && isset($object[$item])) ) { if ($isDefinedTest) { return true; } return $object[$item]; } if (Twig_TemplateInterface::ARRAY_CALL === $type) { if ($isDefinedTest) { return false; } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } if (is_object($object)) { throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object))); } elseif (is_array($object)) { throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object)))); } else { throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object))); } } } if (!is_object($object)) { if ($isDefinedTest) { return false; } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object)); } $class = get_class($object); // object property if (Twig_TemplateInterface::METHOD_CALL !== $type) { /* apparently, this is not needed as this is already covered by the array_key_exists() call below if (!isset(self::$cache[$class]['properties'])) { foreach (get_object_vars($object) as $k => $v) { self::$cache[$class]['properties'][$k] = true; } } */ if (isset($object->$item) || array_key_exists($item, $object)) { if ($isDefinedTest) { return true; } if ($this->env->hasExtension('sandbox')) { $this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item); } return $object->$item; } } // object method if (!isset(self::$cache[$class]['methods'])) { self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object))); } $lcItem = strtolower($item); if (isset(self::$cache[$class]['methods'][$lcItem])) { $method = $item; } elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) { $method = 'get'.$item; } elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) { $method = 'is'.$item; } elseif (isset(self::$cache[$class]['methods']['__call'])) { $method = $item; } else { if ($isDefinedTest) { return false; } if ($ignoreStrictCheck || !$this->env->isStrictVariables()) { return null; } throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object))); } if ($isDefinedTest) { return true; } if ($this->env->hasExtension('sandbox')) { $this->env->getExtension('sandbox')->checkMethodAllowed($object, $method); } $ret = call_user_func_array(array($object, $method), $arguments); // hack to be removed when macro calls are refactored if ($object instanceof Twig_TemplateInterface) { return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset()); } return $ret; } /** * This method is only useful when testing Twig. Do not use it. */ static public function clearCache() { self::$cache = array(); } } vendor/Twig/TemplateInterface.php000066400000000000000000000022501516067305400174000ustar00rootroot00000000000000 */ interface Twig_TemplateInterface { const ANY_CALL = 'any'; const ARRAY_CALL = 'array'; const METHOD_CALL = 'method'; /** * Renders the template with the given context and returns it as string. * * @param array $context An array of parameters to pass to the template * * @return string The rendered template */ function render(array $context); /** * Displays the template with the given context. * * @param array $context An array of parameters to pass to the template * @param array $blocks An array of blocks to pass to the template */ function display(array $context, array $blocks = array()); /** * Returns the bound environment for this template. * * @return Twig_Environment The current environment */ function getEnvironment(); } vendor/Twig/Test/000077500000000000000000000000001516067305400142135ustar00rootroot00000000000000vendor/Twig/Test/Function.php000066400000000000000000000011071516067305400165100ustar00rootroot00000000000000 */ class Twig_Test_Function implements Twig_TestInterface { protected $function; public function __construct($function) { $this->function = $function; } public function compile() { return $this->function; } } vendor/Twig/Test/Method.php000066400000000000000000000013361516067305400161470ustar00rootroot00000000000000 */ class Twig_Test_Method implements Twig_TestInterface { protected $extension, $method; public function __construct(Twig_ExtensionInterface $extension, $method) { $this->extension = $extension; $this->method = $method; } public function compile() { return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method); } } vendor/Twig/Test/Node.php000066400000000000000000000011411516067305400156060ustar00rootroot00000000000000 */ class Twig_Test_Node implements Twig_TestInterface { protected $class; public function __construct($class) { $this->class = $class; } public function getClass() { return $this->class; } public function compile() { } } vendor/Twig/TestInterface.php000066400000000000000000000007321516067305400165470ustar00rootroot00000000000000 */ interface Twig_TestInterface { /** * Compiles a test. * * @return string The PHP code for the test */ function compile(); } vendor/Twig/Token.php000066400000000000000000000143451516067305400150740ustar00rootroot00000000000000 */ class Twig_Token { protected $value; protected $type; protected $lineno; const EOF_TYPE = -1; const TEXT_TYPE = 0; const BLOCK_START_TYPE = 1; const VAR_START_TYPE = 2; const BLOCK_END_TYPE = 3; const VAR_END_TYPE = 4; const NAME_TYPE = 5; const NUMBER_TYPE = 6; const STRING_TYPE = 7; const OPERATOR_TYPE = 8; const PUNCTUATION_TYPE = 9; const INTERPOLATION_START_TYPE = 10; const INTERPOLATION_END_TYPE = 11; /** * Constructor. * * @param integer $type The type of the token * @param string $value The token value * @param integer $lineno The line position in the source */ public function __construct($type, $value, $lineno) { $this->type = $type; $this->value = $value; $this->lineno = $lineno; } /** * Returns a string representation of the token. * * @return string A string representation of the token */ public function __toString() { return sprintf('%s(%s)', self::typeToString($this->type, true, $this->lineno), $this->value); } /** * Tests the current token for a type and/or a value. * * Parameters may be: * * just type * * type and value (or array of possible values) * * just value (or array of possible values) (NAME_TYPE is used as type) * * @param array|integer $type The type to test * @param array|string|null $values The token value * * @return Boolean */ public function test($type, $values = null) { if (null === $values && !is_int($type)) { $values = $type; $type = self::NAME_TYPE; } return ($this->type === $type) && ( null === $values || (is_array($values) && in_array($this->value, $values)) || $this->value == $values ); } /** * Gets the line. * * @return integer The source line */ public function getLine() { return $this->lineno; } /** * Gets the token type. * * @return integer The token type */ public function getType() { return $this->type; } /** * Gets the token value. * * @return string The token value */ public function getValue() { return $this->value; } /** * Returns the constant representation (internal) of a given type. * * @param integer $type The type as an integer * @param Boolean $short Whether to return a short representation or not * @param integer $line The code line * * @return string The string representation */ static public function typeToString($type, $short = false, $line = -1) { switch ($type) { case self::EOF_TYPE: $name = 'EOF_TYPE'; break; case self::TEXT_TYPE: $name = 'TEXT_TYPE'; break; case self::BLOCK_START_TYPE: $name = 'BLOCK_START_TYPE'; break; case self::VAR_START_TYPE: $name = 'VAR_START_TYPE'; break; case self::BLOCK_END_TYPE: $name = 'BLOCK_END_TYPE'; break; case self::VAR_END_TYPE: $name = 'VAR_END_TYPE'; break; case self::NAME_TYPE: $name = 'NAME_TYPE'; break; case self::NUMBER_TYPE: $name = 'NUMBER_TYPE'; break; case self::STRING_TYPE: $name = 'STRING_TYPE'; break; case self::OPERATOR_TYPE: $name = 'OPERATOR_TYPE'; break; case self::PUNCTUATION_TYPE: $name = 'PUNCTUATION_TYPE'; break; case self::INTERPOLATION_START_TYPE: $name = 'INTERPOLATION_START_TYPE'; break; case self::INTERPOLATION_END_TYPE: $name = 'INTERPOLATION_END_TYPE'; break; default: throw new Twig_Error_Syntax(sprintf('Token of type "%s" does not exist.', $type), $line); } return $short ? $name : 'Twig_Token::'.$name; } /** * Returns the english representation of a given type. * * @param integer $type The type as an integer * @param integer $line The code line * * @return string The string representation */ static public function typeToEnglish($type, $line = -1) { switch ($type) { case self::EOF_TYPE: return 'end of template'; case self::TEXT_TYPE: return 'text'; case self::BLOCK_START_TYPE: return 'begin of statement block'; case self::VAR_START_TYPE: return 'begin of print statement'; case self::BLOCK_END_TYPE: return 'end of statement block'; case self::VAR_END_TYPE: return 'end of print statement'; case self::NAME_TYPE: return 'name'; case self::NUMBER_TYPE: return 'number'; case self::STRING_TYPE: return 'string'; case self::OPERATOR_TYPE: return 'operator'; case self::PUNCTUATION_TYPE: return 'punctuation'; case self::INTERPOLATION_START_TYPE: return 'begin of string interpolation'; case self::INTERPOLATION_END_TYPE: return 'end of string interpolation'; default: throw new Twig_Error_Syntax(sprintf('Token of type "%s" does not exist.', $type), $line); } } } vendor/Twig/TokenParser.php000066400000000000000000000012501516067305400162400ustar00rootroot00000000000000 */ abstract class Twig_TokenParser implements Twig_TokenParserInterface { /** * @var Twig_Parser */ protected $parser; /** * Sets the parser associated with this token parser * * @param $parser A Twig_Parser instance */ public function setParser(Twig_Parser $parser) { $this->parser = $parser; } } vendor/Twig/TokenParser/000077500000000000000000000000001516067305400155315ustar00rootroot00000000000000vendor/Twig/TokenParser/AutoEscape.php000066400000000000000000000050021516067305400202700ustar00rootroot00000000000000 * {% autoescape true %} * Everything will be automatically escaped in this block * {% endautoescape %} * * {% autoescape false %} * Everything will be outputed as is in this block * {% endautoescape %} * * {% autoescape true js %} * Everything will be automatically escaped in this block * using the js escaping strategy * {% endautoescape %} * */ class Twig_TokenParser_AutoEscape extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); if ($this->parser->getStream()->test(Twig_Token::BLOCK_END_TYPE)) { $value = 'html'; } else { $expr = $this->parser->getExpressionParser()->parseExpression(); if (!$expr instanceof Twig_Node_Expression_Constant) { throw new Twig_Error_Syntax('An escaping strategy must be a string or a Boolean.', $lineno); } $value = $expr->getAttribute('value'); $compat = true === $value || false === $value; if (true === $value) { $value = 'html'; } if ($compat && $this->parser->getStream()->test(Twig_Token::NAME_TYPE)) { if (false === $value) { throw new Twig_Error_Syntax('Unexpected escaping strategy as you set autoescaping to false.', $lineno); } $value = $this->parser->getStream()->next()->getValue(); } } $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_AutoEscape($value, $body, $lineno, $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endautoescape'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'autoescape'; } } vendor/Twig/TokenParser/Block.php000066400000000000000000000047661516067305400173110ustar00rootroot00000000000000 * {% block head %} * * {% block title %}{% endblock %} - My Webpage * {% endblock %} * */ class Twig_TokenParser_Block extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); if ($this->parser->hasBlock($name)) { throw new Twig_Error_Syntax(sprintf("The block '$name' has already been defined line %d", $this->parser->getBlock($name)->getLine()), $lineno); } $this->parser->setBlock($name, $block = new Twig_Node_Block($name, new Twig_Node(array()), $lineno)); $this->parser->pushLocalScope(); $this->parser->pushBlockStack($name); if ($stream->test(Twig_Token::BLOCK_END_TYPE)) { $stream->next(); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); if ($stream->test(Twig_Token::NAME_TYPE)) { $value = $stream->next()->getValue(); if ($value != $name) { throw new Twig_Error_Syntax(sprintf("Expected endblock for block '$name' (but %s given)", $value), $lineno); } } } else { $body = new Twig_Node(array( new Twig_Node_Print($this->parser->getExpressionParser()->parseExpression(), $lineno), )); } $stream->expect(Twig_Token::BLOCK_END_TYPE); $block->setNode('body', $body); $this->parser->popBlockStack(); $this->parser->popLocalScope(); return new Twig_Node_BlockReference($name, $lineno, $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endblock'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'block'; } } vendor/Twig/TokenParser/Do.php000066400000000000000000000017241516067305400166100ustar00rootroot00000000000000parser->getExpressionParser()->parseExpression(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Do($expr, $token->getLine(), $this->getTag()); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'do'; } } vendor/Twig/TokenParser/Embed.php000066400000000000000000000036331516067305400172630ustar00rootroot00000000000000parser->getStream(); $parent = $this->parser->getExpressionParser()->parseExpression(); list($variables, $only, $ignoreMissing) = $this->parseArguments(); // inject a fake parent to make the parent() function work $stream->injectTokens(array( new Twig_Token(Twig_Token::BLOCK_START_TYPE, '', $token->getLine()), new Twig_Token(Twig_Token::NAME_TYPE, 'extends', $token->getLine()), new Twig_Token(Twig_Token::STRING_TYPE, '__parent__', $token->getLine()), new Twig_Token(Twig_Token::BLOCK_END_TYPE, '', $token->getLine()), )); $module = $this->parser->parse($stream, array($this, 'decideBlockEnd'), true); // override the parent with the correct one $module->setNode('parent', $parent); $this->parser->embedTemplate($module); $stream->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Embed($module->getAttribute('filename'), $module->getAttribute('index'), $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endembed'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'embed'; } } vendor/Twig/TokenParser/Extends.php000066400000000000000000000024451516067305400176610ustar00rootroot00000000000000 * {% extends "base.html" %} * */ class Twig_TokenParser_Extends extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { if (!$this->parser->isMainScope()) { throw new Twig_Error_Syntax('Cannot extend from a block', $token->getLine()); } if (null !== $this->parser->getParent()) { throw new Twig_Error_Syntax('Multiple extends tags are forbidden', $token->getLine()); } $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return null; } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'extends'; } } vendor/Twig/TokenParser/Filter.php000066400000000000000000000032461516067305400174740ustar00rootroot00000000000000 * {% filter upper %} * This text becomes uppercase * {% endfilter %} * */ class Twig_TokenParser_Filter extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $name = $this->parser->getVarName(); $ref = new Twig_Node_Expression_BlockReference(new Twig_Node_Expression_Constant($name, $token->getLine()), true, $token->getLine(), $this->getTag()); $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref, $this->getTag()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $block = new Twig_Node_Block($name, $body, $token->getLine()); $this->parser->setBlock($name, $block); return new Twig_Node_Print($filter, $token->getLine(), $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endfilter'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'filter'; } } vendor/Twig/TokenParser/Flush.php000066400000000000000000000016111516067305400173220ustar00rootroot00000000000000parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Flush($token->getLine(), $this->getTag()); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'flush'; } } vendor/Twig/TokenParser/For.php000066400000000000000000000055151516067305400167760ustar00rootroot00000000000000 *
    * {% for user in users %} *
  • {{ user.username|e }}
  • * {% endfor %} *
* */ class Twig_TokenParser_For extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); $this->parser->getStream()->expect(Twig_Token::OPERATOR_TYPE, 'in'); $seq = $this->parser->getExpressionParser()->parseExpression(); $ifexpr = null; if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE, 'if')) { $this->parser->getStream()->next(); $ifexpr = $this->parser->getExpressionParser()->parseExpression(); } $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideForFork')); if ($this->parser->getStream()->next()->getValue() == 'else') { $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $else = $this->parser->subparse(array($this, 'decideForEnd'), true); } else { $else = null; } $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); if (count($targets) > 1) { $keyTarget = $targets->getNode(0); $keyTarget = new Twig_Node_Expression_AssignName($keyTarget->getAttribute('name'), $keyTarget->getLine()); $valueTarget = $targets->getNode(1); $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); } else { $keyTarget = new Twig_Node_Expression_AssignName('_key', $lineno); $valueTarget = $targets->getNode(0); $valueTarget = new Twig_Node_Expression_AssignName($valueTarget->getAttribute('name'), $valueTarget->getLine()); } return new Twig_Node_For($keyTarget, $valueTarget, $seq, $ifexpr, $body, $else, $lineno, $this->getTag()); } public function decideForFork(Twig_Token $token) { return $token->test(array('else', 'endfor')); } public function decideForEnd(Twig_Token $token) { return $token->test('endfor'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'for'; } } vendor/Twig/TokenParser/From.php000066400000000000000000000034621516067305400171520ustar00rootroot00000000000000 * {% from 'forms.html' import forms %} * */ class Twig_TokenParser_From extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); $stream = $this->parser->getStream(); $stream->expect('import'); $targets = array(); do { $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $alias = $name; if ($stream->test('as')) { $stream->next(); $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); } $targets[$name] = $alias; if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } $stream->next(); } while (true); $stream->expect(Twig_Token::BLOCK_END_TYPE); $node = new Twig_Node_Import($macro, new Twig_Node_Expression_AssignName($this->parser->getVarName(), $token->getLine()), $token->getLine(), $this->getTag()); foreach($targets as $name => $alias) { $this->parser->addImportedFunction($alias, 'get'.$name, $node->getNode('var')); } return $node; } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'from'; } } vendor/Twig/TokenParser/If.php000066400000000000000000000052201516067305400165770ustar00rootroot00000000000000 * {% if users %} *
    * {% for user in users %} *
  • {{ user.username|e }}
  • * {% endfor %} *
* {% endif %} * */ class Twig_TokenParser_If extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $expr = $this->parser->getExpressionParser()->parseExpression(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideIfFork')); $tests = array($expr, $body); $else = null; $end = false; while (!$end) { switch ($this->parser->getStream()->next()->getValue()) { case 'else': $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $else = $this->parser->subparse(array($this, 'decideIfEnd')); break; case 'elseif': $expr = $this->parser->getExpressionParser()->parseExpression(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideIfFork')); $tests[] = $expr; $tests[] = $body; break; case 'endif': $end = true; break; default: throw new Twig_Error_Syntax(sprintf('Unexpected end of template. Twig was looking for the following tags "else", "elseif", or "endif" to close the "if" block started at line %d)', $lineno), -1); } } $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_If(new Twig_Node($tests), $else, $lineno, $this->getTag()); } public function decideIfFork(Twig_Token $token) { return $token->test(array('elseif', 'else', 'endif')); } public function decideIfEnd(Twig_Token $token) { return $token->test(array('endif')); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'if'; } } vendor/Twig/TokenParser/Import.php000066400000000000000000000022751516067305400175220ustar00rootroot00000000000000 * {% import 'forms.html' as forms %} * */ class Twig_TokenParser_Import extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $macro = $this->parser->getExpressionParser()->parseExpression(); $this->parser->getStream()->expect('as'); $var = new Twig_Node_Expression_AssignName($this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(), $token->getLine()); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Import($macro, $var, $token->getLine(), $this->getTag()); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'import'; } } vendor/Twig/TokenParser/Include.php000066400000000000000000000036111516067305400176260ustar00rootroot00000000000000 * {% include 'header.html' %} * Body * {% include 'footer.html' %} * */ class Twig_TokenParser_Include extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $expr = $this->parser->getExpressionParser()->parseExpression(); list($variables, $only, $ignoreMissing) = $this->parseArguments(); return new Twig_Node_Include($expr, $variables, $only, $ignoreMissing, $token->getLine(), $this->getTag()); } protected function parseArguments() { $stream = $this->parser->getStream(); $ignoreMissing = false; if ($stream->test(Twig_Token::NAME_TYPE, 'ignore')) { $stream->next(); $stream->expect(Twig_Token::NAME_TYPE, 'missing'); $ignoreMissing = true; } $variables = null; if ($stream->test(Twig_Token::NAME_TYPE, 'with')) { $stream->next(); $variables = $this->parser->getExpressionParser()->parseExpression(); } $only = false; if ($stream->test(Twig_Token::NAME_TYPE, 'only')) { $stream->next(); $only = true; } $stream->expect(Twig_Token::BLOCK_END_TYPE); return array($variables, $only, $ignoreMissing); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'include'; } } vendor/Twig/TokenParser/Macro.php000066400000000000000000000037611516067305400173120ustar00rootroot00000000000000 * {% macro input(name, value, type, size) %} * * {% endmacro %} * */ class Twig_TokenParser_Macro extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $name = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE)->getValue(); $arguments = $this->parser->getExpressionParser()->parseArguments(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->pushLocalScope(); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); if ($this->parser->getStream()->test(Twig_Token::NAME_TYPE)) { $value = $this->parser->getStream()->next()->getValue(); if ($value != $name) { throw new Twig_Error_Syntax(sprintf("Expected endmacro for macro '$name' (but %s given)", $value), $lineno); } } $this->parser->popLocalScope(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->setMacro($name, new Twig_Node_Macro($name, new Twig_Node_Body(array($body)), $arguments, $lineno, $this->getTag())); return null; } public function decideBlockEnd(Twig_Token $token) { return $token->test('endmacro'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'macro'; } } vendor/Twig/TokenParser/Sandbox.php000066400000000000000000000025601516067305400176430ustar00rootroot00000000000000 * {% sandbox %} * {% include 'user.html' %} * {% endsandbox %} * * * @see http://www.twig-project.org/doc/api.html#sandbox-extension for details */ class Twig_TokenParser_Sandbox extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideBlockEnd'), true); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Sandbox($body, $token->getLine(), $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endsandbox'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'sandbox'; } } vendor/Twig/TokenParser/Set.php000066400000000000000000000042501516067305400167760ustar00rootroot00000000000000 * {% set foo = 'foo' %} * * {% set foo = [1, 2] %} * * {% set foo = {'foo': 'bar'} %} * * {% set foo = 'foo' ~ 'bar' %} * * {% set foo, bar = 'foo', 'bar' %} * * {% set foo %}Some content{% endset %} * */ class Twig_TokenParser_Set extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $stream = $this->parser->getStream(); $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); $capture = false; if ($stream->test(Twig_Token::OPERATOR_TYPE, '=')) { $stream->next(); $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); $stream->expect(Twig_Token::BLOCK_END_TYPE); if (count($names) !== count($values)) { throw new Twig_Error_Syntax("When using set, you must have the same number of variables and assignements.", $lineno); } } else { $capture = true; if (count($names) > 1) { throw new Twig_Error_Syntax("When using set with a block, you cannot have a multi-target.", $lineno); } $stream->expect(Twig_Token::BLOCK_END_TYPE); $values = $this->parser->subparse(array($this, 'decideBlockEnd'), true); $stream->expect(Twig_Token::BLOCK_END_TYPE); } return new Twig_Node_Set($capture, $names, $values, $lineno, $this->getTag()); } public function decideBlockEnd(Twig_Token $token) { return $token->test('endset'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'set'; } } vendor/Twig/TokenParser/Spaceless.php000066400000000000000000000025601516067305400201670ustar00rootroot00000000000000 * {% spaceless %} *
* foo *
* {% endspaceless %} * * {# output will be
foo
#} * */ class Twig_TokenParser_Spaceless extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $lineno = $token->getLine(); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); $body = $this->parser->subparse(array($this, 'decideSpacelessEnd'), true); $this->parser->getStream()->expect(Twig_Token::BLOCK_END_TYPE); return new Twig_Node_Spaceless($body, $lineno, $this->getTag()); } public function decideSpacelessEnd(Twig_Token $token) { return $token->test('endspaceless'); } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'spaceless'; } } vendor/Twig/TokenParser/Use.php000066400000000000000000000042471516067305400170050ustar00rootroot00000000000000 * {% extends "base.html" %} * * {% use "blocks.html" %} * * {% block title %}{% endblock %} * {% block content %}{% endblock %} * * * @see http://www.twig-project.org/doc/templates.html#horizontal-reuse for details. */ class Twig_TokenParser_Use extends Twig_TokenParser { /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ public function parse(Twig_Token $token) { $template = $this->parser->getExpressionParser()->parseExpression(); if (!$template instanceof Twig_Node_Expression_Constant) { throw new Twig_Error_Syntax('The template references in a "use" statement must be a string.', $token->getLine()); } $stream = $this->parser->getStream(); $targets = array(); if ($stream->test('with')) { $stream->next(); do { $name = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); $alias = $name; if ($stream->test('as')) { $stream->next(); $alias = $stream->expect(Twig_Token::NAME_TYPE)->getValue(); } $targets[$name] = new Twig_Node_Expression_Constant($alias, -1); if (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ',')) { break; } $stream->next(); } while (true); } $stream->expect(Twig_Token::BLOCK_END_TYPE); $this->parser->addTrait(new Twig_Node(array('template' => $template, 'targets' => new Twig_Node($targets)))); return null; } /** * Gets the tag name associated with this token parser. * * @return string The tag name */ public function getTag() { return 'use'; } } vendor/Twig/TokenParserBroker.php000066400000000000000000000060621516067305400174130ustar00rootroot00000000000000 */ class Twig_TokenParserBroker implements Twig_TokenParserBrokerInterface { protected $parser; protected $parsers = array(); protected $brokers = array(); /** * Constructor. * * @param array|Traversable $parsers A Traversable of Twig_TokenParserInterface instances * @param array|Traversable $brokers A Traversable of Twig_TokenParserBrokerInterface instances */ public function __construct($parsers = array(), $brokers = array()) { foreach ($parsers as $parser) { if (!$parser instanceof Twig_TokenParserInterface) { throw new Twig_Error('$parsers must a an array of Twig_TokenParserInterface'); } $this->parsers[$parser->getTag()] = $parser; } foreach ($brokers as $broker) { if (!$broker instanceof Twig_TokenParserBrokerInterface) { throw new Twig_Error('$brokers must a an array of Twig_TokenParserBrokerInterface'); } $this->brokers[] = $broker; } } /** * Adds a TokenParser. * * @param Twig_TokenParserInterface $parser A Twig_TokenParserInterface instance */ public function addTokenParser(Twig_TokenParserInterface $parser) { $this->parsers[$parser->getTag()] = $parser; } /** * Adds a TokenParserBroker. * * @param Twig_TokenParserBroker $broker A Twig_TokenParserBroker instance */ public function addTokenParserBroker(Twig_TokenParserBroker $broker) { $this->brokers[] = $broker; } /** * Gets a suitable TokenParser for a tag. * * First looks in parsers, then in brokers. * * @param string $tag A tag name * * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found */ public function getTokenParser($tag) { if (isset($this->parsers[$tag])) { return $this->parsers[$tag]; } $broker = end($this->brokers); while (false !== $broker) { $parser = $broker->getTokenParser($tag); if (null !== $parser) { return $parser; } $broker = prev($this->brokers); } return null; } public function getParsers() { return $this->parsers; } public function getParser() { return $this->parser; } public function setParser(Twig_ParserInterface $parser) { $this->parser = $parser; foreach ($this->parsers as $tokenParser) { $tokenParser->setParser($parser); } foreach ($this->brokers as $broker) { $broker->setParser($parser); } } } vendor/Twig/TokenParserBrokerInterface.php000066400000000000000000000023031516067305400212260ustar00rootroot00000000000000 */ interface Twig_TokenParserBrokerInterface { /** * Gets a TokenParser suitable for a tag. * * @param string $tag A tag name * * @return null|Twig_TokenParserInterface A Twig_TokenParserInterface or null if no suitable TokenParser was found */ function getTokenParser($tag); /** * Calls Twig_TokenParserInterface::setParser on all parsers the implementation knows of. * * @param Twig_ParserInterface $parser A Twig_ParserInterface interface */ function setParser(Twig_ParserInterface $parser); /** * Gets the Twig_ParserInterface. * * @return null|Twig_ParserInterface A Twig_ParserInterface instance of null */ function getParser(); } vendor/Twig/TokenParserInterface.php000066400000000000000000000016161516067305400200670ustar00rootroot00000000000000 */ interface Twig_TokenParserInterface { /** * Sets the parser associated with this token parser * * @param $parser A Twig_Parser instance */ function setParser(Twig_Parser $parser); /** * Parses a token and returns a node. * * @param Twig_Token $token A Twig_Token instance * * @return Twig_NodeInterface A Twig_NodeInterface instance */ function parse(Twig_Token $token); /** * Gets the tag name associated with this token parser. * * @return string The tag name */ function getTag(); } vendor/Twig/TokenStream.php000066400000000000000000000067111516067305400162460ustar00rootroot00000000000000 */ class Twig_TokenStream { protected $tokens; protected $current; protected $filename; /** * Constructor. * * @param array $tokens An array of tokens * @param string $filename The name of the filename which tokens are associated with */ public function __construct(array $tokens, $filename = null) { $this->tokens = $tokens; $this->current = 0; $this->filename = $filename; } /** * Returns a string representation of the token stream. * * @return string */ public function __toString() { return implode("\n", $this->tokens); } public function injectTokens(array $tokens) { $this->tokens = array_merge(array_slice($this->tokens, 0, $this->current), $tokens, array_slice($this->tokens, $this->current)); } /** * Sets the pointer to the next token and returns the old one. * * @return Twig_Token */ public function next() { if (!isset($this->tokens[++$this->current])) { throw new Twig_Error_Syntax('Unexpected end of template', -1, $this->filename); } return $this->tokens[$this->current - 1]; } /** * Tests a token and returns it or throws a syntax error. * * @return Twig_Token */ public function expect($type, $value = null, $message = null) { $token = $this->tokens[$this->current]; if (!$token->test($type, $value)) { $line = $token->getLine(); throw new Twig_Error_Syntax(sprintf('%sUnexpected token "%s" of value "%s" ("%s" expected%s)', $message ? $message.'. ' : '', Twig_Token::typeToEnglish($token->getType(), $line), $token->getValue(), Twig_Token::typeToEnglish($type, $line), $value ? sprintf(' with value "%s"', $value) : ''), $line, $this->filename ); } $this->next(); return $token; } /** * Looks at the next token. * * @param integer $number * * @return Twig_Token */ public function look($number = 1) { if (!isset($this->tokens[$this->current + $number])) { throw new Twig_Error_Syntax('Unexpected end of template', -1, $this->filename); } return $this->tokens[$this->current + $number]; } /** * Tests the current token * * @return bool */ public function test($primary, $secondary = null) { return $this->tokens[$this->current]->test($primary, $secondary); } /** * Checks if end of stream was reached * * @return bool */ public function isEOF() { return $this->tokens[$this->current]->getType() === Twig_Token::EOF_TYPE; } /** * Gets the current token * * @return Twig_Token */ public function getCurrent() { return $this->tokens[$this->current]; } /** * Gets the filename associated with this stream * * @return string */ public function getFilename() { return $this->filename; } } vendor/silex.phar000066400000000000000000017415001516067305400143720ustar00rootroot00000000000000 * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ Phar::mapPhar('silex.phar'); require_once 'phar://silex.phar/vendor/autoload.php'; if ('cli' === php_sapi_name() && basename(__FILE__) === basename($_SERVER['argv'][0]) && isset($_SERVER['argv'][1])) { switch ($_SERVER['argv'][1]) { case 'update': $remoteFilename = 'http://silex.sensiolabs.org/get/silex.phar'; $localFilename = __DIR__.'/silex.phar'; file_put_contents($localFilename, file_get_contents($remoteFilename)); break; case 'check': $latest = trim(file_get_contents('http://silex.sensiolabs.org/get/version')); if ($latest != Silex\Application::VERSION) { printf("A newer Silex version is available (%s).\n", $latest); } else { print("You are using the latest Silex version.\n"); } break; case 'version': printf("Silex version %s\n", Silex\Application::VERSION); break; default: printf("Unknown command '%s' (available commands: version, check, and update).\n", $_SERVER['argv'][1]); } exit(0); } __HALT_COMPILER(); ?> ijü silex.pharsrc/Silex/Application.php)8H¥O)˜q':¶src/Silex/Controller.php)8H¥O)EŠ ê¶"src/Silex/ControllerCollection.phpæ8H¥OæÉbê¶)src/Silex/ControllerProviderInterface.php|8H¥O|—Õ×4¶ src/Silex/ControllerResolver.php 8H¥O Ä–2¶1src/Silex/Exception/ControllerFrozenException.phpo8H¥OoRŠ¡¶src/Silex/ExceptionHandler.php8H¥OO¤›Ð¶&src/Silex/GetResponseForErrorEvent.php¬8H¥O¬úIq¶src/Silex/HttpCache.phpc8H¥Ocb;b¶src/Silex/LazyUrlMatcher.phpj8H¥Oj6μ»¶.src/Silex/Provider/DoctrineServiceProvider.php 8H¥O 9Å:¬¶*src/Silex/Provider/FormServiceProvider.php8H¥OÚþPo¶/src/Silex/Provider/HttpCacheServiceProvider.php8H¥OSÝ×¶-src/Silex/Provider/MonologServiceProvider.phpÂ8H¥OÂ6F]¶-src/Silex/Provider/SessionServiceProvider.php¿8H¥O¿õî?t¶1src/Silex/Provider/SwiftmailerServiceProvider.php{ 8H¥O{ +]Ö>¶4src/Silex/Provider/SymfonyBridgesServiceProvider.php™8H¥O™*Shƶ1src/Silex/Provider/TranslationServiceProvider.php«8H¥O«†P+¸¶(src/Silex/Provider/TwigCoreExtension.php8H¥O?šü÷¶*src/Silex/Provider/TwigServiceProvider.phpó8H¥Oó§…î¶2src/Silex/Provider/UrlGeneratorServiceProvider.php¯8H¥O¯,åÎ{¶/src/Silex/Provider/ValidatorServiceProvider.php8H¥O;oy¶$src/Silex/RedirectableUrlMatcher.php€8H¥O€|6.Ù¶&src/Silex/ServiceProviderInterface.phpx8H¥OxÕJçà¶src/Silex/SilexEvents.php»8H¥O»nÒǶ%src/Silex/StringResponseConverter.php 8H¥O E=Vð¶src/Silex/WebTestCase.phpæ8H¥OæÜ‹¶Ó¶#vendor/pimple/pimple/lib/Pimple.phpO8H¥OO\)Å›¶Lvendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcClassLoader.php,8H¥O,×~¶Uvendor/symfony/class-loader/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php?8H¥O?é¢Ï¶Svendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassCollectionLoader.php… 8H¥O… 4Öyš¶Ivendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassLoader.php’8H¥O’OÇ”š¶Ovendor/symfony/class-loader/Symfony/Component/ClassLoader/ClassMapGenerator.php~8H¥O~6³ 8¶Nvendor/symfony/class-loader/Symfony/Component/ClassLoader/DebugClassLoader.php”8H¥O”ý…ß¶Wvendor/symfony/class-loader/Symfony/Component/ClassLoader/DebugUniversalClassLoader.php 8H¥O iµà1¶Lvendor/symfony/class-loader/Symfony/Component/ClassLoader/MapClassLoader.phpt8H¥OtÁj¶Rvendor/symfony/class-loader/Symfony/Component/ClassLoader/UniversalClassLoader.phpz 8H¥Oz Ð}z{¶Ovendor/symfony/class-loader/Symfony/Component/ClassLoader/XcacheClassLoader.phpU8H¥OUÍWVS¶cvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/ContainerAwareEventDispatcher.phpú 8H¥Oú ÒoÅú¶mvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.phpÃ8H¥OãU™¡¶Kvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/Event.php‚8H¥O‚\1P¶Uvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcher.phpU 8H¥OU “õ[N¶^vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventDispatcherInterface.php!8H¥O!¡‚,¶^vendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/EventSubscriberInterface.php­8H¥O­åX¾V¶Rvendor/symfony/event-dispatcher/Symfony/Component/EventDispatcher/GenericEvent.php'8H¥O'×ÄɶQvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/ApacheRequest.phpC8H¥OCrp»¶Jvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Cookie.php«8H¥O«Ñ•Ñ/¶hvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/Exception/AccessDeniedException.phpý8H¥Oý—šÓ6¶`vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/Exception/FileException.phpƒ8H¥Oƒ‰Ž!¶hvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/Exception/FileNotFoundException.phpø8H¥Oø¦ár¶jvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/Exception/UnexpectedTypeException.phpK8H¥OK¼Ë¤¶bvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/Exception/UploadException.php8H¥OT‹¶Mvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/File.php›8H¥O›ø#¯¶bvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.phpó8H¥Oó¥†rh¶kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesserInterface.php—8H¥O—½Çʶkvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.phpã8H¥OãYbSå¶ivendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php¸8H¥O¸8¥¶jvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.phpdk8H¥OdklÈ? ¶avendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php)8H¥O)Pµõ ¶jvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesserInterface.php˜8H¥O˜aÅ(¶Uvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/File/UploadedFile.phpw8H¥OwlpÈ$¶Kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/FileBag.php¬8H¥O¬Óâæ—¶Mvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/HeaderBag.phpÒ8H¥OÒ?0ÎܶPvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/JsonResponse.phpò8H¥Oò¦›‘ƶPvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/ParameterBag.php¹ 8H¥O¹ ò!šy¶Tvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/RedirectResponse.phpa8H¥Oasj¢b¶Kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Request.phpXM8H¥OXMÚ|i‰¶Rvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/RequestMatcher.phpÕ 8H¥OÕ C~ü¶[vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/RequestMatcherInterface.php—8H¥O—wÌë ¶kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php28H¥O2Ðîa¶Lvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Response.php18H¥O1R»)=¶Uvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/ResponseHeaderBag.phpò8H¥OòC³kè¶Mvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/ServerBag.php“8H¥O“H‹Íè¶bvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php;8H¥O;³xj¶kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php§8H¥O§û‰.u¶lvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php½8H¥O½Aö¾¶dvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.phpØ8H¥OØ Þ¶Zvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.phpœ8H¥OœfªJ1¶cvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php8H¥OI¥¦¶Svendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Session.phpè8H¥OèÜܶ_vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/SessionBagInterface.phpç8H¥OçMñÿO¶\vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/SessionInterface.php÷8H¥O÷o:>e¶svendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php:8H¥O:%0v˶rvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php 8H¥O 9šø¶qvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php}8H¥O}5Ëb¶tvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.phpµ8H¥Oµö',¶yvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.phpÊ8H¥OÊB*}í¶xvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandler.php58H¥O5Zþmd¶uvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeRedisSessionHandler.php8H¥OÃúyZ¶pvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.phpî8H¥Oîe è_¶vvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandler.phpÉ8H¥OÉRJ³b¶nvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.phpì8H¥Oì3Î"¶mvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.phpÛ8H¥OÛ­G\¶_vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/MetadataBag.php#8H¥O#æâ©¶kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.phpâ 8H¥Oâ #)¶jvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php-8H¥O- -0¶hvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php8H¥O¡¥ò¶gvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php8H¥ON»ý+¶evendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php8H¥O‹®±¶mvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php!8H¥O!RM#ƒ¶kvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php‡8H¥O‡³^–¶Tvendor/symfony/http-foundation/Symfony/Component/HttpFoundation/StreamedResponse.phpz8H¥OzнC{¶Ivendor/symfony/http-kernel/Symfony/Component/HttpKernel/Bundle/Bundle.phpì 8H¥Oì .ñ·¶Rvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Bundle/BundleInterface.php­8H¥O­3%ï{¶^vendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheClearer/CacheClearerInterface.php8H¥O•µ\ˆ¶Zvendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheClearer/ChainCacheClearer.phpÉ8H¥OɃï’:¶Svendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.phpÅ8H¥OÅÃmË7¶\vendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerAggregate.php?8H¥O?RMÞ¶\vendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmerInterface.php¨8H¥O¨7þ7¶Yvendor/symfony/http-kernel/Symfony/Component/HttpKernel/CacheWarmer/WarmableInterface.php‹8H¥O‹LÝ?¶Bvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Client.php 8H¥O !´Y‡¶Nvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Config/FileLocator.php£8H¥O£/°Ri¶Yvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolver.php¿ 8H¥O¿ @—.á¶bvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Controller/ControllerResolverInterface.php(8H¥O(0¨í ¶]vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php¨8H¥O¨” ºí¶Wvendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/DataCollector.phpp8H¥Opýg}Ƕ`vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/DataCollectorInterface.php€8H¥O€ù‡éC¶\vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/EventDataCollector.phpm8H¥Omg®£&¶`vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/ExceptionDataCollector.phpð8H¥Oð;ôÓ€¶]vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/LoggerDataCollector.phpß8H¥Oß>mn‚¶]vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/MemoryDataCollector.phpù8H¥Où Ķ^vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.phpV8H¥OVèŒT<¶[vendor/symfony/http-kernel/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php68H¥O6ÒWæ¶hvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/ContainerAwareTraceableEventDispatcher.php 8H¥O E›$¦¶Nvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/ErrorHandler.php8H¥Oλ#ý¶Rvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/ExceptionHandler.php“ 8H¥O“ tw.Û¶Kvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/Stopwatch.php 8H¥O :=ÆÌ¶Pvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Debug/StopwatchEvent.php°8H¥O°÷«Ï¶evendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/AddClassesToCachePass.php98H¥O9òCGs¶evendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/ConfigurableExtension.phpù8H¥OùÏ&”¶Yvendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/Extension.phpT8H¥OTæ•Þ-¶ovendor/symfony/http-kernel/Symfony/Component/HttpKernel/DependencyInjection/MergeExtensionConfigurationPass.phpÀ8H¥OÀ¤ås¶Wvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/FilterControllerEvent.phpÿ8H¥OÿS¤Ž£¶Uvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/FilterResponseEvent.phpŠ8H¥OŠV×h¹¶Rvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/GetResponseEvent.phpÁ8H¥OÁÓè¶evendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/GetResponseForControllerResultEvent.php<8H¥O<u8kM¶^vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/GetResponseForExceptionEvent.phpm8H¥Om2DÄ­¶Mvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/KernelEvent.phpÀ8H¥OÀ>ÂLæ¶Svendor/symfony/http-kernel/Symfony/Component/HttpKernel/Event/PostResponseEvent.phpÚ8H¥OÚ£‚ð¶Uvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/EsiListener.phpy8H¥Oy[¿òk¶[vendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/ExceptionListener.phpä 8H¥Oä ÙO ¶Xvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/LocaleListener.phpï8H¥Oïr4Þ3¶Zvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php# 8H¥O# ‚&Z~¶Zvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/ResponseListener.phpp8H¥OpQ©‹£¶Xvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/RouterListener.php¼ 8H¥O¼ Ú¡¹~¶bvendor/symfony/http-kernel/Symfony/Component/HttpKernel/EventListener/StreamedResponseListener.php+8H¥O+[`2a¶_vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/AccessDeniedHttpException.php"8H¥O"ŒÒÇå¶Vvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/FlattenException.phpq8H¥OqH?ï»¶Svendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/HttpException.php*8H¥O*WmK©¶\vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/HttpExceptionInterface.php©8H¥O©MÓ#¶cvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/MethodNotAllowedHttpException.phpv8H¥Ov-u{F¶[vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Exception/NotFoundHttpException.php8H¥Oº¶Ivendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/Esi.php¼8H¥O¼fðAõ¶^vendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategy.phpb8H¥Obí©„ý¶gvendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/EsiResponseCacheStrategyInterface.phpÿ8H¥OÿGaZé¶Ovendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/HttpCache.phpZ'8H¥OZ'õˆsÛ¶Kvendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/Store.phpj8H¥Oj<ŸÙ±¶Tvendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpCache/StoreInterface.phpç8H¥Oç à±¶Fvendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernel.php78H¥O7rÿ«ˆ¶Ovendor/symfony/http-kernel/Symfony/Component/HttpKernel/HttpKernelInterface.phpS8H¥OSg?zè¶Bvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Kernel.phpp18H¥Op1÷×¼w¶Hvendor/symfony/http-kernel/Symfony/Component/HttpKernel/KernelEvents.php8H¥O1›¶Kvendor/symfony/http-kernel/Symfony/Component/HttpKernel/KernelInterface.phpê8H¥Oê–˶Tvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Log/DebugLoggerInterface.php 8H¥O ßs˜Œ¶Ovendor/symfony/http-kernel/Symfony/Component/HttpKernel/Log/LoggerInterface.php8H¥O´|¼¶Jvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Log/NullLogger.php¶8H¥O¶<ÿ(ž¶`vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/BaseMemcacheProfilerStorage.phpý8H¥Oý=^Ç€¶Xvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.phpå8H¥Oåqý€¶]vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/MemcachedProfilerStorage.php%8H¥O%ÉàY¶\vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/MemcacheProfilerStorage.phpŒ8H¥OŒ‚ù!z¶[vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/MongoDbProfilerStorage.php¾8H¥O¾F=ð¶Yvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/MysqlProfilerStorage.php´8H¥O´5Þ\¶Wvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/PdoProfilerStorage.php8H¥O› ¶Lvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/Profile.phpè8H¥OèS¢ ¶¶Mvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/Profiler.phpF 8H¥OF ‰s¶]vendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/ProfilerStorageInterface.php8H¥O!)…ª¶Yvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/RedisProfilerStorage.phpô8H¥OôëѓȶZvendor/symfony/http-kernel/Symfony/Component/HttpKernel/Profiler/SqliteProfilerStorage.phpY 8H¥OY ÎÊ.ˆ¶Ovendor/symfony/http-kernel/Symfony/Component/HttpKernel/TerminableInterface.php8H¥O´z¶Evendor/symfony/routing/Symfony/Component/Routing/Annotation/Route.php 8H¥O w}<^¶Bvendor/symfony/routing/Symfony/Component/Routing/CompiledRoute.php8H¥Oõ“•˶Qvendor/symfony/routing/Symfony/Component/Routing/Exception/ExceptionInterface.phph8H¥Oh“a‹Ÿ¶Xvendor/symfony/routing/Symfony/Component/Routing/Exception/InvalidParameterException.php«8H¥O«àgj0¶Xvendor/symfony/routing/Symfony/Component/Routing/Exception/MethodNotAllowedException.phpì8H¥Oìæç™¶bvendor/symfony/routing/Symfony/Component/Routing/Exception/MissingMandatoryParametersException.php¶8H¥O¶A^ r¶Xvendor/symfony/routing/Symfony/Component/Routing/Exception/ResourceNotFoundException.php¥8H¥O¥ªJç#¶Uvendor/symfony/routing/Symfony/Component/Routing/Exception/RouteNotFoundException.php¨8H¥O¨Á\ó²¶Uvendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumper.phpc8H¥Oc=“/%¶^vendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/GeneratorDumperInterface.phpö8H¥Oö¶‡®þ¶Xvendor/symfony/routing/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.phpâ8H¥Oâÿ3AF¶Kvendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGenerator.phpI 8H¥OI †Ñ¶Tvendor/symfony/routing/Symfony/Component/Routing/Generator/UrlGeneratorInterface.phpa8H¥OaRšL¶Qvendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationClassLoader.phpÔ 8H¥OÔ hÑ€¶Uvendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.phpÚ8H¥OÚ{4zͶPvendor/symfony/routing/Symfony/Component/Routing/Loader/AnnotationFileLoader.php&8H¥O&-ÆK´¶Ivendor/symfony/routing/Symfony/Component/Routing/Loader/ClosureLoader.php~8H¥O~ŠÓŽþ¶Ivendor/symfony/routing/Symfony/Component/Routing/Loader/PhpFileLoader.php…8H¥O…`ÀضIvendor/symfony/routing/Symfony/Component/Routing/Loader/XmlFileLoader.phpê8H¥Oêßf;¶Jvendor/symfony/routing/Symfony/Component/Routing/Loader/YamlFileLoader.phpn 8H¥On þ¶žJ¶Mvendor/symfony/routing/Symfony/Component/Routing/Matcher/ApacheUrlMatcher.php]8H¥O]óßN9¶Wvendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/ApacheMatcherDumper.php& 8H¥O& K©¤¶Qvendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumper.phpb8H¥Obò^è¶Zvendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/MatcherDumperInterface.phpÀ8H¥OÀ >ÁI¶Tvendor/symfony/routing/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php“8H¥O“ª?̶Svendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcher.phpŸ8H¥OŸN\¶l¶\vendor/symfony/routing/Symfony/Component/Routing/Matcher/RedirectableUrlMatcherInterface.php°8H¥O°)å½¶Pvendor/symfony/routing/Symfony/Component/Routing/Matcher/TraceableUrlMatcher.php– 8H¥O– ›Ùcë¶Gvendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcher.phpø 8H¥Oø ³Ä¯þ¶Pvendor/symfony/routing/Symfony/Component/Routing/Matcher/UrlMatcherInterface.phpy8H¥OydÀËâ¶Cvendor/symfony/routing/Symfony/Component/Routing/RequestContext.php& 8H¥O& L\ŶQvendor/symfony/routing/Symfony/Component/Routing/RequestContextAwareInterface.php¸8H¥O¸¢-L ¶:vendor/symfony/routing/Symfony/Component/Routing/Route.phpp8H¥Opæô¶Dvendor/symfony/routing/Symfony/Component/Routing/RouteCollection.php-8H¥O-T°"l¶Bvendor/symfony/routing/Symfony/Component/Routing/RouteCompiler.phpZ 8H¥OZ x·‡¶Kvendor/symfony/routing/Symfony/Component/Routing/RouteCompilerInterface.php‡8H¥O‡dþú¶;vendor/symfony/routing/Symfony/Component/Routing/Router.phpM8H¥OMÕäB¶Dvendor/symfony/routing/Symfony/Component/Routing/RouterInterface.php-8H¥O-_¤î¾¶Bvendor/symfony/browser-kit/Symfony/Component/BrowserKit/Client.php°8H¥O°á N¶Bvendor/symfony/browser-kit/Symfony/Component/BrowserKit/Cookie.phpÈ8H¥OÈt±€G¶Evendor/symfony/browser-kit/Symfony/Component/BrowserKit/CookieJar.phpc 8H¥Oc B*W«¶Cvendor/symfony/browser-kit/Symfony/Component/BrowserKit/History.php08H¥O0¥¥¶Cvendor/symfony/browser-kit/Symfony/Component/BrowserKit/Request.phpø8H¥Oøy^åü¶Dvendor/symfony/browser-kit/Symfony/Component/BrowserKit/Response.php8H¥OÚ{³¶Ivendor/symfony/css-selector/Symfony/Component/CssSelector/CssSelector.php×8H¥O× ¿÷²¶Vvendor/symfony/css-selector/Symfony/Component/CssSelector/Exception/ParseException.phpx8H¥OxH%¶Mvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/AttribNode.phpA 8H¥OA –Ðdä¶Lvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ClassNode.php¤8H¥O¤wLî³¶Wvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/CombinedSelectorNode.php‚8H¥O‚ Ôe8¶Nvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/ElementNode.php8H¥OŠžÝ¶Ovendor/symfony/css-selector/Symfony/Component/CssSelector/Node/FunctionNode.php8H¥O^wŸ@¶Kvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/HashNode.php68H¥O6­ã²¶Pvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/NodeInterface.php™8H¥O™ü%º¶Ivendor/symfony/css-selector/Symfony/Component/CssSelector/Node/OrNode.phpæ8H¥Oærì¦ê¶Mvendor/symfony/css-selector/Symfony/Component/CssSelector/Node/PseudoNode.phpÝ 8H¥OÝ AÉ'¶Cvendor/symfony/css-selector/Symfony/Component/CssSelector/Token.phpÛ8H¥OÛÉMú>¶Gvendor/symfony/css-selector/Symfony/Component/CssSelector/Tokenizer.phpÍ 8H¥OÍ àG¶¶Ivendor/symfony/css-selector/Symfony/Component/CssSelector/TokenStream.phpc8H¥OcŠ˜f¶Gvendor/symfony/css-selector/Symfony/Component/CssSelector/XPathExpr.php4 8H¥O4 |©µ¶Ivendor/symfony/css-selector/Symfony/Component/CssSelector/XPathExprOr.php–8H¥O–Žßs[¶Cvendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Crawler.phpì8H¥OìÛ ¯.¶Qvendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Field/ChoiceFormField.php8H¥O »B¶Ovendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Field/FileFormField.phpù8H¥OùRæ¶Kvendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Field/FormField.phpö8H¥Oögrª¶Pvendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Field/InputFormField.phpŽ8H¥OŽ÷*Q¶Svendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Field/TextareaFormField.phpÆ8H¥OÆëÇ}ʶ@vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Form.php98H¥O9ìÎ/{¶@vendor/symfony/dom-crawler/Symfony/Component/DomCrawler/Link.phpM8H¥OMSÁ¾r¶LICENSE$8H¥O$ÍY¶vendor/autoload.php8H¥Oœ°a[¶vendor/composer/ClassLoader.phpA 8H¥OA Âs_…¶'vendor/composer/autoload_namespaces.php8H¥O²&÷¶%vendor/composer/autoload_classmap.phpZ8H¥OZë¦á–¶share(function () { $loader = new UniversalClassLoader(); $loader->register(); return $loader; }); $this['routes'] = $this->share(function () { return new RouteCollection(); }); $this['controllers'] = $this->share(function () use ($app) { return new ControllerCollection(); }); $this['exception_handler'] = $this->share(function () { return new ExceptionHandler(); }); $this['dispatcher'] = $this->share(function () use ($app) { $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber($app); $urlMatcher = new LazyUrlMatcher(function () use ($app) { return $app['url_matcher']; }); $dispatcher->addSubscriber(new RouterListener($urlMatcher)); return $dispatcher; }); $this['resolver'] = $this->share(function () use ($app) { return new ControllerResolver($app); }); $this['kernel'] = $this->share(function () use ($app) { return new HttpKernel($app['dispatcher'], $app['resolver']); }); $this['request_context'] = $this->share(function () use ($app) { $context = new RequestContext(); $context->setHttpPort($app['request.http_port']); $context->setHttpsPort($app['request.https_port']); return $context; }); $this['url_matcher'] = $this->share(function () use ($app) { return new RedirectableUrlMatcher($app['routes'], $app['request_context']); }); $this['route_middlewares_trigger'] = $this->protect(function (KernelEvent $event) use ($app) { foreach ($event->getRequest()->attributes->get('_middlewares', array()) as $callback) { $ret = call_user_func($callback, $event->getRequest()); if ($ret instanceof Response) { $event->setResponse($ret); return; } elseif (null !== $ret) { throw new \RuntimeException('Middleware for route "'.$event->getRequest()->attributes->get('_route').'" returned an invalid response value. Must return null or an instance of Response.'); } } }); $this['request.default_locale'] = 'en'; $this['request'] = function () { throw new \RuntimeException('Accessed request service outside of request scope. Try moving that call to a before handler or controller.'); }; $this['request.http_port'] = 80; $this['request.https_port'] = 443; $this['debug'] = false; $this['charset'] = 'UTF-8'; } public function register(ServiceProviderInterface $provider, array $values = array()) { foreach ($values as $key => $value) { $this[$key] = $value; } $provider->register($this); } public function match($pattern, $to) { return $this['controllers']->match($pattern, $to); } public function get($pattern, $to) { return $this['controllers']->get($pattern, $to); } public function post($pattern, $to) { return $this['controllers']->post($pattern, $to); } public function put($pattern, $to) { return $this['controllers']->put($pattern, $to); } public function delete($pattern, $to) { return $this['controllers']->delete($pattern, $to); } public function before($callback, $priority = 0) { $this['dispatcher']->addListener(SilexEvents::BEFORE, function (GetResponseEvent $event) use ($callback) { $ret = call_user_func($callback, $event->getRequest()); if ($ret instanceof Response) { $event->setResponse($ret); } }, $priority); } public function after($callback, $priority = 0) { $this['dispatcher']->addListener(SilexEvents::AFTER, function (FilterResponseEvent $event) use ($callback) { call_user_func($callback, $event->getRequest(), $event->getResponse()); }, $priority); } public function finish($callback, $priority = 0) { $this['dispatcher']->addListener(SilexEvents::FINISH, function (PostResponseEvent $event) use ($callback) { call_user_func($callback, $event->getRequest(), $event->getResponse()); }, $priority); } public function abort($statusCode, $message = '', array $headers = array()) { throw new HttpException($statusCode, $message, null, $headers); } public function error($callback, $priority = 0) { $this['dispatcher']->addListener(SilexEvents::ERROR, function (GetResponseForErrorEvent $event) use ($callback) { $exception = $event->getException(); $code = $exception instanceof HttpExceptionInterface ? $exception->getStatusCode() : 500; $result = call_user_func($callback, $exception, $code); if (null !== $result) { $event->setStringResponse($result); } }, $priority); } public function flush($prefix = '') { $this['routes']->addCollection($this['controllers']->flush($prefix), $prefix); } public function redirect($url, $status = 302) { return new RedirectResponse($url, $status); } public function stream($callback = null, $status = 200, $headers = array()) { return new StreamedResponse($callback, $status, $headers); } public function escape($text, $flags = ENT_COMPAT, $charset = null, $doubleEncode = true) { return htmlspecialchars($text, $flags, $charset ?: $this['charset'], $doubleEncode); } public function json($data = array(), $status = 200, $headers = array()) { return new JsonResponse($data, $status, $headers); } public function mount($prefix, $app) { if ($app instanceof ControllerProviderInterface) { $app = $app->connect($this); } if (!$app instanceof ControllerCollection) { throw new \LogicException('The "mount" method takes either a ControllerCollection or a ControllerProviderInterface instance.'); } $this['routes']->addCollection($app->flush($prefix), $prefix); } public function run(Request $request = null) { if (null === $request) { $request = Request::createFromGlobals(); } $response = $this->handle($request); $response->send(); $this->terminate($request, $response); } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { $this->beforeDispatched = false; $this['request'] = $request; $this['request']->setDefaultLocale($this['request.default_locale']); $this->flush(); return $this['kernel']->handle($request, $type, $catch); } public function terminate(Request $request, Response $response) { $this['kernel']->terminate($request, $response); } public function onEarlyKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { if (isset($this['exception_handler'])) { $this['dispatcher']->addSubscriber($this['exception_handler']); } $this['dispatcher']->addSubscriber(new ResponseListener($this['charset'])); } } public function onKernelRequest(GetResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { $this->beforeDispatched = true; $this['dispatcher']->dispatch(SilexEvents::BEFORE, $event); $this['route_middlewares_trigger']($event); } } public function onKernelController(FilterControllerEvent $event) { $request = $event->getRequest(); $route = $this['routes']->get($request->attributes->get('_route')); if ($route && $converters = $route->getOption('_converters')) { foreach ($converters as $name => $callback) { $request->attributes->set($name, call_user_func($callback, $request->attributes->get($name, null), $request)); } } } public function onKernelView(GetResponseForControllerResultEvent $event) { $response = $event->getControllerResult(); $converter = new StringResponseConverter(); $event->setResponse($converter->convert($response)); } public function onKernelResponse(FilterResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { $this['dispatcher']->dispatch(SilexEvents::AFTER, $event); } } public function onKernelTerminate(PostResponseEvent $event) { $this['dispatcher']->dispatch(SilexEvents::FINISH, $event); } public function onKernelException(GetResponseForExceptionEvent $event) { if (!$this->beforeDispatched) { $this->beforeDispatched = true; $this['dispatcher']->dispatch(SilexEvents::BEFORE, $event); } $errorEvent = new GetResponseForErrorEvent($this, $event->getRequest(), $event->getRequestType(), $event->getException()); $this['dispatcher']->dispatch(SilexEvents::ERROR, $errorEvent); if ($errorEvent->hasResponse()) { $event->setResponse($errorEvent->getResponse()); } } static public function getSubscribedEvents() { return array( KernelEvents::REQUEST => array( array('onEarlyKernelRequest', 256), array('onKernelRequest') ), KernelEvents::CONTROLLER => 'onKernelController', KernelEvents::RESPONSE => 'onKernelResponse', KernelEvents::EXCEPTION => 'onKernelException', KernelEvents::TERMINATE => 'onKernelTerminate', KernelEvents::VIEW => array('onKernelView', -10), ); } } route = $route; } public function getRoute() { return $this->route; } public function getRouteName() { return $this->routeName; } public function bind($routeName) { if ($this->isFrozen) { throw new ControllerFrozenException(sprintf('Calling %s on frozen %s instance.', __METHOD__, __CLASS__)); } $this->routeName = $routeName; return $this; } public function assert($variable, $regexp) { $this->route->setRequirement($variable, $regexp); return $this; } public function value($variable, $default) { $this->route->setDefault($variable, $default); return $this; } public function convert($variable, $callback) { $converters = $this->route->getOption('_converters'); $converters[$variable] = $callback; $this->route->setOption('_converters', $converters); return $this; } public function method($method) { $this->route->setRequirement('_method', $method); return $this; } public function requireHttp() { $this->route->setRequirement('_scheme', 'http'); return $this; } public function requireHttps() { $this->route->setRequirement('_scheme', 'https'); return $this; } public function middleware($callback) { $middlewareCallbacks = $this->route->getDefault('_middlewares'); $middlewareCallbacks[] = $callback; $this->route->setDefault('_middlewares', $middlewareCallbacks); return $this; } public function freeze() { $this->isFrozen = true; } public function bindDefaultRouteName($prefix) { $requirements = $this->route->getRequirements(); $method = isset($requirements['_method']) ? $requirements['_method'] : ''; $routeName = $prefix.$method.$this->route->getPattern(); $routeName = str_replace(array('/', ':', '|', '-'), '_', $routeName); $routeName = preg_replace('/[^a-z0-9A-Z_.]+/', '', $routeName); $this->routeName = $routeName; } } $to)); $controller = new Controller($route); $this->add($controller); return $controller; } public function get($pattern, $to) { return $this->match($pattern, $to)->method('GET'); } public function post($pattern, $to) { return $this->match($pattern, $to)->method('POST'); } public function put($pattern, $to) { return $this->match($pattern, $to)->method('PUT'); } public function delete($pattern, $to) { return $this->match($pattern, $to)->method('DELETE'); } public function add(Controller $controller) { $this->controllers[] = $controller; } public function flush($prefix = '') { $routes = new RouteCollection(); foreach ($this->controllers as $controller) { if (!$controller->getRouteName()) { $controller->bindDefaultRouteName($prefix); } $routes->add($controller->getRouteName(), $controller->getRoute()); $controller->freeze(); } $this->controllers = array(); return $routes; } } app = $app; parent::__construct($logger); } protected function doGetArguments(Request $request, $controller, array $parameters) { foreach ($parameters as $param) { if ($param->getClass() && $param->getClass()->isInstance($this->app)) { $request->attributes->set($param->getName(), $this->app); break; } } return parent::doGetArguments($request, $controller, $parameters); } } getKernel(); $handler = new DebugExceptionHandler($app['debug']); $event->setResponse($handler->createResponse($event->getException())); } static public function getSubscribedEvents() { return array(SilexEvents::ERROR => array('onSilexError', -255)); } } setResponse($converter->convert($response)); } } handle($request)->send(); } } factory = $factory; } public function getUrlMatcher() { $urlMatcher = call_user_func($this->factory); if (!$urlMatcher instanceof UrlMatcherInterface) { throw new \LogicException("Factory supplied to LazyUrlMatcher must return implementation of UrlMatcherInterface."); } return $urlMatcher; } public function match($pathinfo) { return $this->getUrlMatcher()->match($pathinfo); } public function setContext(RequestContext $context) { $this->getUrlMatcher()->setContext($context); } public function getContext() { return $this->getUrlMatcher()->getContext(); } } 'pdo_mysql', 'dbname' => null, 'host' => 'localhost', 'user' => 'root', 'password' => null, ); $app['dbs.options.initializer'] = $app->protect(function () use ($app) { static $initialized = false; if ($initialized) { return; } $initialized = true; if (!isset($app['dbs.options'])) { $app['dbs.options'] = array('default' => isset($app['db.options']) ? $app['db.options'] : array()); } $tmp = $app['dbs.options']; foreach ($tmp as $name => &$options) { $options = array_replace($app['db.default_options'], $options); if (!isset($app['dbs.default'])) { $app['dbs.default'] = $name; } } $app['dbs.options'] = $tmp; }); $app['dbs'] = $app->share(function () use ($app) { $app['dbs.options.initializer'](); $dbs = new \Pimple(); foreach ($app['dbs.options'] as $name => $options) { if ($app['dbs.default'] === $name) { $config = $app['db.config']; $manager = $app['db.event_manager']; } else { $config = $app['dbs.config'][$name]; $manager = $app['dbs.event_manager'][$name]; } $dbs[$name] = DriverManager::getConnection($options, $config, $manager); } return $dbs; }); $app['dbs.config'] = $app->share(function () use ($app) { $app['dbs.options.initializer'](); $configs = new \Pimple(); foreach ($app['dbs.options'] as $name => $options) { $configs[$name] = new Configuration(); } return $configs; }); $app['dbs.event_manager'] = $app->share(function () use ($app) { $app['dbs.options.initializer'](); $managers = new \Pimple(); foreach ($app['dbs.options'] as $name => $options) { $managers[$name] = new EventManager(); } return $managers; }); $app['db'] = $app->share(function() use ($app) { $dbs = $app['dbs']; return $dbs[$app['dbs.default']]; }); $app['db.config'] = $app->share(function() use ($app) { $dbs = $app['dbs.config']; return $dbs[$app['dbs.default']]; }); $app['db.event_manager'] = $app->share(function() use ($app) { $dbs = $app['dbs.event_manager']; return $dbs[$app['dbs.default']]; }); if (isset($app['db.dbal.class_path'])) { $app['autoloader']->registerNamespace('Doctrine\\DBAL', $app['db.dbal.class_path']); } if (isset($app['db.common.class_path'])) { $app['autoloader']->registerNamespace('Doctrine\\Common', $app['db.common.class_path']); } } } share(function () use ($app) { $extensions = array( new CoreExtension(), new CsrfExtension($app['form.csrf_provider']), ); if (isset($app['validator'])) { $extensions[] = new FormValidatorExtension($app['validator']); } return new FormFactory($extensions); }); $app['form.csrf_provider'] = $app->share(function () use ($app) { if (isset($app['session'])) { return new SessionCsrfProvider($app['session'], $app['form.secret']); } return new DefaultCsrfProvider($app['form.secret']); }); if (isset($app['form.class_path'])) { $app['autoloader']->registerNamespace('Symfony\\Component\\Form', $app['form.class_path']); } } } share(function () use ($app) { return new HttpCache($app, $app['http_cache.store'], $app['http_cache.esi'], $app['http_cache.options']); }); $app['http_cache.esi'] = $app->share(function () use ($app) { return new Esi(); }); $app['http_cache.store'] = $app->share(function () use ($app) { return new Store($app['http_cache.cache_dir']); }); if (!isset($app['http_cache.options'])) { $app['http_cache.options'] = array(); } } } share(function () use ($app) { $log = new Logger(isset($app['monolog.name']) ? $app['monolog.name'] : 'myapp'); $app['monolog.configure']($log); return $log; }); $app['monolog.configure'] = $app->protect(function ($log) use ($app) { $log->pushHandler($app['monolog.handler']); }); $app['monolog.handler'] = function () use ($app) { return new StreamHandler($app['monolog.logfile'], $app['monolog.level']); }; if (!isset($app['monolog.level'])) { $app['monolog.level'] = function () { return Logger::DEBUG; }; } if (isset($app['monolog.class_path'])) { $app['autoloader']->registerNamespace('Monolog', $app['monolog.class_path']); } $app->before(function (Request $request) use ($app) { $app['monolog']->addInfo('> '.$request->getMethod().' '.$request->getRequestUri()); }); $app->error(function (\Exception $e) use ($app) { $app['monolog']->addError($e->getMessage()); }); $app->after(function (Request $request, Response $response) use ($app) { $app['monolog']->addInfo('< '.$response->getStatusCode()); }); } } app = $app; $app['session'] = $app->share(function () use ($app) { return new Session($app['session.storage']); }); $app['session.storage.handler'] = $app->share(function () use ($app) { return new NativeFileSessionHandler( isset($app['session.storage.save_path']) ? $app['session.storage.save_path'] : null ); }); $app['session.storage'] = $app->share(function () use ($app) { return new NativeSessionStorage( $app['session.storage.options'], $app['session.storage.handler'] ); }); $app['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'onKernelRequest'), 128); if (!isset($app['session.storage.options'])) { $app['session.storage.options'] = array(); } if (!isset($app['session.default_locale'])) { $app['session.default_locale'] = 'en'; } } public function onKernelRequest($event) { $request = $event->getRequest(); $request->setSession($this->app['session']); if ($request->hasPreviousSession()) { $request->getSession()->start(); } } } 'localhost', 'port' => 25, 'username' => '', 'password' => '', 'encryption' => null, 'auth_mode' => null, ), isset($app['swiftmailer.options']) ? $app['swiftmailer.options'] : array()); $app['mailer'] = $app->share(function () use ($app) { $r = new \ReflectionClass('Swift_Mailer'); require_once dirname($r->getFilename()).'/../../swift_init.php'; return new \Swift_Mailer($app['swiftmailer.spooltransport']); }); $app['swiftmailer.spooltransport'] = $app->share(function () use ($app) { return new \Swift_SpoolTransport(new \Swift_MemorySpool()); }); $app['swiftmailer.transport'] = $app->share(function () use ($app) { $transport = new \Swift_Transport_EsmtpTransport( $app['swiftmailer.transport.buffer'], array($app['swiftmailer.transport.authhandler']), $app['swiftmailer.transport.eventdispatcher'] ); $transport->setHost($app['swiftmailer.options']['host']); $transport->setPort($app['swiftmailer.options']['port']); $transport->setEncryption($app['swiftmailer.options']['encryption']); $transport->setUsername($app['swiftmailer.options']['username']); $transport->setPassword($app['swiftmailer.options']['password']); $transport->setAuthMode($app['swiftmailer.options']['auth_mode']); return $transport; }); $app['swiftmailer.transport.buffer'] = $app->share(function () { return new \Swift_Transport_StreamBuffer(new \Swift_StreamFilters_StringReplacementFilterFactory()); }); $app['swiftmailer.transport.authhandler'] = $app->share(function () { return new \Swift_Transport_Esmtp_AuthHandler(array( new \Swift_Transport_Esmtp_Auth_CramMd5Authenticator(), new \Swift_Transport_Esmtp_Auth_LoginAuthenticator(), new \Swift_Transport_Esmtp_Auth_PlainAuthenticator(), )); }); $app['swiftmailer.transport.eventdispatcher'] = $app->share(function () { return new \Swift_Events_SimpleEventDispatcher(); }); $app->finish(function () use ($app) { $app['swiftmailer.spooltransport']->getSpool()->flushQueue($app['swiftmailer.transport']); }); if (isset($app['swiftmailer.class_path'])) { require_once $app['swiftmailer.class_path'].'/Swift.php'; \Swift::registerAutoload($app['swiftmailer.class_path'].'/../swift_init.php'); } } } registerNamespace('Symfony\\Bridge', $app['symfony_bridges.class_path']); } } } share(function () use ($app) { $translator = new Translator(isset($app['locale']) ? $app['locale'] : 'en', $app['translator.message_selector']); if (isset($app['locale_fallback'])) { $translator->setFallbackLocale($app['locale_fallback']); } $translator->addLoader('array', $app['translator.loader']); foreach ($app['translator.messages'] as $locale => $messages) { $translator->addResource('array', $messages, $locale); } return $translator; }); $app['translator.loader'] = $app->share(function () { return new ArrayLoader(); }); $app['translator.message_selector'] = $app->share(function () { return new MessageSelector(); }); if (isset($app['translation.class_path'])) { $app['autoloader']->registerNamespace('Symfony\\Component\\Translation', $app['translation.class_path']); } } } new \Twig_Function_Method($this, 'render', array('needs_environment' => true, 'is_safe' => array('html'))), ); } public function render(\Twig_Environment $twig, $uri) { $globals = $twig->getGlobals(); $request = $globals['app']['request']; $subRequest = Request::create($uri, 'get', array(), $request->cookies->all(), array(), $request->server->all()); if ($request->getSession()) { $subRequest->setSession($request->getSession()); } $response = $globals['app']->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false); if (!$response->isSuccessful()) { throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $request->getUri(), $response->getStatusCode())); } return $response->getContent(); } public function getName() { return 'silex'; } } share(function () use ($app) { $app['twig.options'] = array_replace( array( 'charset' => $app['charset'], 'debug' => $app['debug'], 'strict_variables' => $app['debug'], ), isset($app['twig.options']) ? $app['twig.options'] : array() ); $twig = new \Twig_Environment($app['twig.loader'], $app['twig.options']); $twig->addGlobal('app', $app); $twig->addExtension(new TwigCoreExtension()); if (isset($app['symfony_bridges'])) { if (isset($app['url_generator'])) { $twig->addExtension(new TwigRoutingExtension($app['url_generator'])); } if (isset($app['translator'])) { $twig->addExtension(new TwigTranslationExtension($app['translator'])); } if (isset($app['form.factory'])) { if (!isset($app['twig.form.templates'])) { $app['twig.form.templates'] = array('form_div_layout.html.twig'); } $twig->addExtension(new TwigFormExtension($app['form.csrf_provider'], $app['twig.form.templates'])); $reflected = new \ReflectionClass('Symfony\Bridge\Twig\Extension\FormExtension'); $path = dirname($reflected->getFileName()).'/../Resources/views/Form'; $app['twig.loader']->addLoader(new \Twig_Loader_Filesystem($path)); } } if (isset($app['twig.configure'])) { $app['twig.configure']($twig); } return $twig; }); $app['twig.loader.filesystem'] = $app->share(function () use ($app) { return new \Twig_Loader_Filesystem(isset($app['twig.path']) ? $app['twig.path'] : array()); }); $app['twig.loader.array'] = $app->share(function () use ($app) { return new \Twig_Loader_Array(isset($app['twig.templates']) ? $app['twig.templates'] : array()); }); $app['twig.loader'] = $app->share(function () use ($app) { return new \Twig_Loader_Chain(array( $app['twig.loader.filesystem'], $app['twig.loader.array'], )); }); if (isset($app['twig.class_path'])) { $app['autoloader']->registerPrefix('Twig_', $app['twig.class_path']); } } } share(function () use ($app) { $app->flush(); return new UrlGenerator($app['routes'], $app['request_context']); }); } } share(function () use ($app) { return new Validator( $app['validator.mapping.class_metadata_factory'], $app['validator.validator_factory'] ); }); $app['validator.mapping.class_metadata_factory'] = $app->share(function () use ($app) { return new ClassMetadataFactory(new StaticMethodLoader()); }); $app['validator.validator_factory'] = $app->share(function () { return new ConstraintValidatorFactory(); }); if (isset($app['validator.class_path'])) { $app['autoloader']->registerNamespace('Symfony\\Component\\Validator', $app['validator.class_path']); } } } context->getBaseUrl().$path; if ($this->context->getHost()) { if ($scheme) { $port = ''; if ('http' === $scheme && 80 != $this->context->getHttpPort()) { $port = ':'.$this->context->getHttpPort(); } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) { $port = ':'.$this->context->getHttpsPort(); } $url = $scheme.'://'.$this->context->getHost().$port.$url; } } return array( '_controller' => function ($url) { return new RedirectResponse($url, 301); }, 'url' => $url, ); } } app = $this->createApplication(); } abstract public function createApplication(); public function createClient(array $options = array(), array $server = array()) { return new Client($this->app); } } values = $values; } function offsetSet($id, $value) { $this->values[$id] = $value; } function offsetGet($id) { if (!array_key_exists($id, $this->values)) { throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } return $this->values[$id] instanceof Closure ? $this->values[$id]($this) : $this->values[$id]; } function offsetExists($id) { return isset($this->values[$id]); } function offsetUnset($id) { unset($this->values[$id]); } function share(Closure $callable) { return function ($c) use ($callable) { static $object; if (is_null($object)) { $object = $callable($c); } return $object; }; } function protect(Closure $callable) { return function ($c) use ($callable) { return $callable; }; } function raw($id) { if (!array_key_exists($id, $this->values)) { throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } return $this->values[$id]; } function extend($id, Closure $callable) { if (!array_key_exists($id, $this->values)) { throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id)); } $factory = $this->values[$id]; if (!($factory instanceof Closure)) { throw new InvalidArgumentException(sprintf('Identifier "%s" does not contain an object definition.', $id)); } return $this->values[$id] = function ($c) use ($callable, $factory) { return $callable($factory($c), $c); }; } } prefix = $prefix; $this->classFinder = $classFinder; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; return true; } } public function findFile($class) { if (false === $file = apc_fetch($this->prefix.$class)) { apc_store($this->prefix.$class, $file = $this->classFinder->findFile($class)); } return $file; } } prefix = $prefix; } public function findFile($class) { if (false === $file = apc_fetch($this->prefix.$class)) { apc_store($this->prefix.$class, $file = parent::findFile($class)); } return $file; } } $time) { $reload = true; break; } } } } } if (!$reload && is_file($cache)) { require_once $cache; return; } $files = array(); $content = ''; foreach ($classes as $class) { if (!class_exists($class) && !interface_exists($class) && (!function_exists('trait_exists') || !trait_exists($class))) { throw new \InvalidArgumentException(sprintf('Unable to load class "%s"', $class)); } $r = new \ReflectionClass($class); $files[] = $r->getFileName(); $c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($r->getFileName())); if (!$r->inNamespace()) { $c = "\nnamespace\n{\n".self::stripComments($c)."\n}\n"; } else { $c = self::fixNamespaceDeclarations('prefixes; } public function getFallbackDirs() { return $this->fallbackDirs; } public function addPrefixes(array $prefixes) { foreach ($prefixes as $prefix => $path) { $this->addPrefix($prefix, $path); } } public function addPrefix($prefix, $paths) { if (!$prefix) { foreach ((array) $paths as $path) { $this->fallbackDirs[] = $path; } return; } if (isset($this->prefixes[$prefix])) { $this->prefixes[$prefix] = array_merge( $this->prefixes[$prefix], (array) $paths ); } else { $this->prefixes[$prefix] = (array) $paths; } } public function setUseIncludePath($useIncludePath) { $this->useIncludePath = $useIncludePath; } public function getUseIncludePath() { return $this->useIncludePath; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; return true; } } public function findFile($class) { if ('\\' == $class[0]) { $class = substr($class, 1); } if (false !== $pos = strrpos($class, '\\')) { $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR; $className = substr($class, $pos + 1); } else { $classPath = null; $className = $class; } $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; foreach ($this->prefixes as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { return $dir . DIRECTORY_SEPARATOR . $classPath; } } } } foreach ($this->fallbackDirs as $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { return $dir . DIRECTORY_SEPARATOR . $classPath; } } if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) { return $file; } } } isFile()) { continue; } $path = $file->getRealPath(); if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') { continue; } $classes = self::findClasses($path); foreach ($classes as $class) { $map[$class] = $path; } } return $map; } static private function findClasses($path) { $contents = file_get_contents($path); $tokens = token_get_all($contents); $T_TRAIT = version_compare(PHP_VERSION, '5.4', '<') ? -1 : T_TRAIT; $classes = array(); $namespace = ''; for ($i = 0, $max = count($tokens); $i < $max; $i++) { $token = $tokens[$i]; if (is_string($token)) { continue; } $class = ''; switch ($token[0]) { case T_NAMESPACE: $namespace = ''; while (($t = $tokens[++$i]) && is_array($t)) { if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) { $namespace .= $t[1]; } } $namespace .= '\\'; break; case T_CLASS: case T_INTERFACE: case $T_TRAIT: while (($t = $tokens[++$i]) && is_array($t)) { if (T_STRING === $t[0]) { $class .= $t[1]; } elseif ($class !== '' && T_WHITESPACE == $t[0]) { break; } } $classes[] = ltrim($namespace . $class, '\\'); break; default: break; } } return $classes; } } classFinder = $classFinder; } static public function enable() { if (!is_array($functions = spl_autoload_functions())) { return; } foreach ($functions as $function) { spl_autoload_unregister($function); } foreach ($functions as $function) { if (is_array($function) && method_exists($function[0], 'findFile')) { $function = array(new static($function[0]), 'loadClass'); } spl_autoload_register($function); } } public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } public function loadClass($class) { if ($file = $this->classFinder->findFile($class)) { require $file; if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) { throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file)); } return true; } } } registerNamespaceFallbacks($function[0]->getNamespaceFallbacks()); $loader->registerPrefixFallbacks($function[0]->getPrefixFallbacks()); $loader->registerNamespaces($function[0]->getNamespaces()); $loader->registerPrefixes($function[0]->getPrefixes()); $loader->useIncludePath($function[0]->getUseIncludePath()); $function[0] = $loader; } spl_autoload_register($function); } } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) { throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file)); } } } } map = $map; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function loadClass($class) { if ('\\' === $class[0]) { $class = substr($class, 1); } if (isset($this->map[$class])) { require $this->map[$class]; } } public function findFile($class) { if ('\\' === $class[0]) { $class = substr($class, 1); } if (isset($this->map[$class])) { return $this->map[$class]; } } } useIncludePath = $useIncludePath; } public function getUseIncludePath() { return $this->useIncludePath; } public function getNamespaces() { return $this->namespaces; } public function getPrefixes() { return $this->prefixes; } public function getNamespaceFallbacks() { return $this->namespaceFallbacks; } public function getPrefixFallbacks() { return $this->prefixFallbacks; } public function registerNamespaceFallbacks(array $dirs) { $this->namespaceFallbacks = $dirs; } public function registerNamespaceFallback($dir) { $this->namespaceFallbacks[] = $dir; } public function registerPrefixFallbacks(array $dirs) { $this->prefixFallbacks = $dirs; } public function registerPrefixFallback($dir) { $this->prefixFallbacks[] = $dir; } public function registerNamespaces(array $namespaces) { foreach ($namespaces as $namespace => $locations) { $this->namespaces[$namespace] = (array) $locations; } } public function registerNamespace($namespace, $paths) { $this->namespaces[$namespace] = (array) $paths; } public function registerPrefixes(array $classes) { foreach ($classes as $prefix => $locations) { $this->prefixes[$prefix] = (array) $locations; } } public function registerPrefix($prefix, $paths) { $this->prefixes[$prefix] = (array) $paths; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; } } public function findFile($class) { if ('\\' == $class[0]) { $class = substr($class, 1); } if (false !== $pos = strrpos($class, '\\')) { $namespace = substr($class, 0, $pos); $className = substr($class, $pos + 1); $normalizedClass = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php'; foreach ($this->namespaces as $ns => $dirs) { if (0 !== strpos($namespace, $ns)) { continue; } foreach ($dirs as $dir) { $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; if (is_file($file)) { return $file; } } } foreach ($this->namespaceFallbacks as $dir) { $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; if (is_file($file)) { return $file; } } } else { $normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php'; foreach ($this->prefixes as $prefix => $dirs) { if (0 !== strpos($class, $prefix)) { continue; } foreach ($dirs as $dir) { $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; if (is_file($file)) { return $file; } } } foreach ($this->prefixFallbacks as $dir) { $file = $dir.DIRECTORY_SEPARATOR.$normalizedClass; if (is_file($file)) { return $file; } } } if ($this->useIncludePath && $file = stream_resolve_include_path($normalizedClass)) { return $file; } } } prefix = $prefix; $this->classFinder = $classFinder; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; return true; } } public function findFile($class) { if (xcache_isset($this->prefix.$class)) { $file = xcache_get($this->prefix.$class); } else { xcache_set($this->prefix.$class, $file = $this->classFinder->findFile($class)); } return $file; } } container = $container; } public function addListenerService($eventName, $callback, $priority = 0) { if (!is_array($callback) || 2 !== count($callback)) { throw new \InvalidArgumentException('Expected an array("service", "method") argument'); } $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); } public function removeListener($eventName, $listener) { $this->lazyLoad($eventName); if (isset($this->listeners[$eventName])) { foreach ($this->listeners[$eventName] as $key => $l) { foreach ($this->listenerIds[$eventName] as $i => $args) { list($serviceId, $method, $priority) = $args; if ($key === $serviceId.'.'.$method) { if ($listener === array($l, $method)) { unset($this->listeners[$eventName][$key]); if (empty($this->listeners[$eventName])) { unset($this->listeners[$eventName]); } unset($this->listenerIds[$eventName][$i]); if (empty($this->listenerIds[$eventName])) { unset($this->listenerIds[$eventName]); } } } } } } parent::removeListener($eventName, $listener); } public function hasListeners($eventName = null) { if (null === $eventName) { return (Boolean) count($this->listenerIds) || (Boolean) count($this->listeners); } if (isset($this->listenerIds[$eventName])) { return true; } return parent::hasListeners($eventName); } public function getListeners($eventName = null) { if (null === $eventName) { foreach (array_keys($this->listenerIds) as $serviceEventName) { $this->lazyLoad($serviceEventName); } } else { $this->lazyLoad($eventName); } return parent::getListeners($eventName); } public function addSubscriberService($serviceId, $class) { foreach ($class::getSubscribedEvents() as $eventName => $params) { if (is_string($params)) { $this->listenerIds[$eventName][] = array($serviceId, $params, 0); } elseif (is_string($params[0])) { $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); } else { foreach ($params as $listener) { $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); } } } } public function dispatch($eventName, Event $event = null) { $this->lazyLoad($eventName); return parent::dispatch($eventName, $event); } public function getContainer() { return $this->container; } protected function lazyLoad($eventName) { if (isset($this->listenerIds[$eventName])) { foreach ($this->listenerIds[$eventName] as $args) { list($serviceId, $method, $priority) = $args; $listener = $this->container->get($serviceId); $key = $serviceId.'.'.$method; if (!isset($this->listeners[$eventName][$key])) { $this->addListener($eventName, array($listener, $method), $priority); } elseif ($listener !== $this->listeners[$eventName][$key]) { parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); $this->addListener($eventName, array($listener, $method), $priority); } $this->listeners[$eventName][$key] = $listener; } } } } propagationStopped; } public function stopPropagation() { $this->propagationStopped = true; } public function setDispatcher(EventDispatcher $dispatcher) { $this->dispatcher = $dispatcher; } public function getDispatcher() { return $this->dispatcher; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } } setDispatcher($this); $event->setName($eventName); if (!isset($this->listeners[$eventName])) { return $event; } $this->doDispatch($this->getListeners($eventName), $eventName, $event); return $event; } public function getListeners($eventName = null) { if (null !== $eventName) { if (!isset($this->sorted[$eventName])) { $this->sortListeners($eventName); } return $this->sorted[$eventName]; } foreach (array_keys($this->listeners) as $eventName) { if (!isset($this->sorted[$eventName])) { $this->sortListeners($eventName); } } return $this->sorted; } public function hasListeners($eventName = null) { return (Boolean) count($this->getListeners($eventName)); } public function addListener($eventName, $listener, $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; unset($this->sorted[$eventName]); } public function removeListener($eventName, $listener) { if (!isset($this->listeners[$eventName])) { return; } foreach ($this->listeners[$eventName] as $priority => $listeners) { if (false !== ($key = array_search($listener, $listeners))) { unset($this->listeners[$eventName][$priority][$key], $this->sorted[$eventName]); } } } public function addSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (is_string($params)) { $this->addListener($eventName, array($subscriber, $params)); } elseif (is_string($params[0])) { $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0); } else { foreach ($params as $listener) { $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0); } } } } public function removeSubscriber(EventSubscriberInterface $subscriber) { foreach ($subscriber->getSubscribedEvents() as $eventName => $params) { if (is_array($params) && is_array($params[0])) { foreach ($params as $listener) { $this->removeListener($eventName, array($subscriber, $listener[0])); } } else { $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0])); } } } protected function doDispatch($listeners, $eventName, Event $event) { foreach ($listeners as $listener) { call_user_func($listener, $event); if ($event->isPropagationStopped()) { break; } } } private function sortListeners($eventName) { $this->sorted[$eventName] = array(); if (isset($this->listeners[$eventName])) { krsort($this->listeners[$eventName]); $this->sorted[$eventName] = call_user_func_array('array_merge', $this->listeners[$eventName]); } } } subject = $subject; $this->arguments = $arguments; } public function getSubject() { return $this->subject; } public function getArgument($key) { if ($this->hasArgument($key)) { return $this->arguments[$key]; } throw new \InvalidArgumentException(sprintf('%s not found in %s', $key, $this->getName())); } public function setArgument($key, $value) { $this->arguments[$key] = $value; return $this; } public function getArguments() { return $this->arguments; } public function setArguments(array $args = array()) { $this->arguments = $args; return $this; } public function hasArgument($key) { return array_key_exists($key, $this->arguments); } public function offsetGet($key) { return $this->getArgument($key); } public function offsetSet($key, $value) { $this->setArgument($key, $value); } public function offsetUnset($key) { if ($this->hasArgument($key)) { unset($this->arguments[$key]); } } public function offsetExists($key) { return $this->hasArgument($key); } } server->get('REQUEST_URI'); } protected function prepareBaseUrl() { $baseUrl = $this->server->get('SCRIPT_NAME'); if (false === strpos($this->server->get('REQUEST_URI'), $baseUrl)) { return rtrim(dirname($baseUrl), '/\\'); } return $baseUrl; } protected function preparePathInfo() { return $this->server->get('PATH_INFO') ?: substr($this->prepareRequestUri(), strlen($this->prepareBaseUrl())) ?: '/'; } } format('U'); } elseif (!is_numeric($expire)) { $expire = strtotime($expire); if (false === $expire || -1 === $expire) { throw new \InvalidArgumentException('The cookie expiration time is not valid.'); } } $this->name = $name; $this->value = $value; $this->domain = $domain; $this->expire = $expire; $this->path = empty($path) ? '/' : $path; $this->secure = (Boolean) $secure; $this->httpOnly = (Boolean) $httpOnly; } public function __toString() { $str = urlencode($this->getName()).'='; if ('' === (string) $this->getValue()) { $str .= 'deleted; expires='.gmdate("D, d-M-Y H:i:s T", time() - 31536001); } else { $str .= urlencode($this->getValue()); if ($this->getExpiresTime() !== 0) { $str .= '; expires='.gmdate("D, d-M-Y H:i:s T", $this->getExpiresTime()); } } if ('/' !== $this->path) { $str .= '; path='.$this->path; } if (null !== $this->getDomain()) { $str .= '; domain='.$this->getDomain(); } if (true === $this->isSecure()) { $str .= '; secure'; } if (true === $this->isHttpOnly()) { $str .= '; httponly'; } return $str; } public function getName() { return $this->name; } public function getValue() { return $this->value; } public function getDomain() { return $this->domain; } public function getExpiresTime() { return $this->expire; } public function getPath() { return $this->path; } public function isSecure() { return $this->secure; } public function isHttpOnly() { return $this->httpOnly; } public function isCleared() { return $this->expire < time(); } } getMimeType(); $guesser = ExtensionGuesser::getInstance(); return $guesser->guess($type); } public function getMimeType() { $guesser = MimeTypeGuesser::getInstance(); return $guesser->guess($this->getPathname()); } public function getExtension() { return pathinfo($this->getBasename(), PATHINFO_EXTENSION); } public function move($directory, $name = null) { if (!is_dir($directory)) { if (false === @mkdir($directory, 0777, true)) { throw new FileException(sprintf('Unable to create the "%s" directory', $directory)); } } elseif (!is_writable($directory)) { throw new FileException(sprintf('Unable to write in the "%s" directory', $directory)); } $target = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : basename($name)); if (!@rename($this->getPathname(), $target)) { $error = error_get_last(); throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message']))); } chmod($target, 0666 & ~umask()); return new File($target); } } register(new MimeTypeExtensionGuesser()); } public function register(ExtensionGuesserInterface $guesser) { array_unshift($this->guessers, $guesser); } public function guess($mimeType) { foreach ($this->guessers as $guesser) { $extension = $guesser->guess($mimeType); if (null !== $extension) { break; } } return $extension; } } /dev/null') { $this->cmd = $cmd; } static public function isSupported() { return !defined('PHP_WINDOWS_VERSION_BUILD'); } public function guess($path) { if (!is_file($path)) { throw new FileNotFoundException($path); } if (!is_readable($path)) { throw new AccessDeniedException($path); } if (!self::isSupported()) { return null; } ob_start(); passthru(sprintf($this->cmd, escapeshellarg($path)), $return); if ($return > 0) { ob_end_clean(); return null; } $type = trim(ob_get_clean()); if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-]+)#i', $type, $match)) { return null; } return $match[1]; } } file($path); } } 'ez', 'application/applixware' => 'aw', 'application/atom+xml' => 'atom', 'application/atomcat+xml' => 'atomcat', 'application/atomsvc+xml' => 'atomsvc', 'application/ccxml+xml' => 'ccxml', 'application/cdmi-capability' => 'cdmia', 'application/cdmi-container' => 'cdmic', 'application/cdmi-domain' => 'cdmid', 'application/cdmi-object' => 'cdmio', 'application/cdmi-queue' => 'cdmiq', 'application/cu-seeme' => 'cu', 'application/davmount+xml' => 'davmount', 'application/dssc+der' => 'dssc', 'application/dssc+xml' => 'xdssc', 'application/ecmascript' => 'ecma', 'application/emma+xml' => 'emma', 'application/epub+zip' => 'epub', 'application/exi' => 'exi', 'application/font-tdpfr' => 'pfr', 'application/hyperstudio' => 'stk', 'application/inkml+xml' => 'ink', 'application/ipfix' => 'ipfix', 'application/java-archive' => 'jar', 'application/java-serialized-object' => 'ser', 'application/java-vm' => 'class', 'application/javascript' => 'js', 'application/json' => 'json', 'application/lost+xml' => 'lostxml', 'application/mac-binhex40' => 'hqx', 'application/mac-compactpro' => 'cpt', 'application/mads+xml' => 'mads', 'application/marc' => 'mrc', 'application/marcxml+xml' => 'mrcx', 'application/mathematica' => 'ma', 'application/mathml+xml' => 'mathml', 'application/mbox' => 'mbox', 'application/mediaservercontrol+xml' => 'mscml', 'application/metalink4+xml' => 'meta4', 'application/mets+xml' => 'mets', 'application/mods+xml' => 'mods', 'application/mp21' => 'm21', 'application/mp4' => 'mp4s', 'application/msword' => 'doc', 'application/mxf' => 'mxf', 'application/octet-stream' => 'bin', 'application/oda' => 'oda', 'application/oebps-package+xml' => 'opf', 'application/ogg' => 'ogx', 'application/onenote' => 'onetoc', 'application/oxps' => 'oxps', 'application/patch-ops-error+xml' => 'xer', 'application/pdf' => 'pdf', 'application/pgp-encrypted' => 'pgp', 'application/pgp-signature' => 'asc', 'application/pics-rules' => 'prf', 'application/pkcs10' => 'p10', 'application/pkcs7-mime' => 'p7m', 'application/pkcs7-signature' => 'p7s', 'application/pkcs8' => 'p8', 'application/pkix-attr-cert' => 'ac', 'application/pkix-cert' => 'cer', 'application/pkix-crl' => 'crl', 'application/pkix-pkipath' => 'pkipath', 'application/pkixcmp' => 'pki', 'application/pls+xml' => 'pls', 'application/postscript' => 'ai', 'application/prs.cww' => 'cww', 'application/pskc+xml' => 'pskcxml', 'application/rdf+xml' => 'rdf', 'application/reginfo+xml' => 'rif', 'application/relax-ng-compact-syntax' => 'rnc', 'application/resource-lists+xml' => 'rl', 'application/resource-lists-diff+xml' => 'rld', 'application/rls-services+xml' => 'rs', 'application/rpki-ghostbusters' => 'gbr', 'application/rpki-manifest' => 'mft', 'application/rpki-roa' => 'roa', 'application/rsd+xml' => 'rsd', 'application/rss+xml' => 'rss', 'application/rtf' => 'rtf', 'application/sbml+xml' => 'sbml', 'application/scvp-cv-request' => 'scq', 'application/scvp-cv-response' => 'scs', 'application/scvp-vp-request' => 'spq', 'application/scvp-vp-response' => 'spp', 'application/sdp' => 'sdp', 'application/set-payment-initiation' => 'setpay', 'application/set-registration-initiation' => 'setreg', 'application/shf+xml' => 'shf', 'application/smil+xml' => 'smi', 'application/sparql-query' => 'rq', 'application/sparql-results+xml' => 'srx', 'application/srgs' => 'gram', 'application/srgs+xml' => 'grxml', 'application/sru+xml' => 'sru', 'application/ssml+xml' => 'ssml', 'application/tei+xml' => 'tei', 'application/thraud+xml' => 'tfi', 'application/timestamped-data' => 'tsd', 'application/vnd.3gpp.pic-bw-large' => 'plb', 'application/vnd.3gpp.pic-bw-small' => 'psb', 'application/vnd.3gpp.pic-bw-var' => 'pvb', 'application/vnd.3gpp2.tcap' => 'tcap', 'application/vnd.3m.post-it-notes' => 'pwn', 'application/vnd.accpac.simply.aso' => 'aso', 'application/vnd.accpac.simply.imp' => 'imp', 'application/vnd.acucobol' => 'acu', 'application/vnd.acucorp' => 'atc', 'application/vnd.adobe.air-application-installer-package+zip' => 'air', 'application/vnd.adobe.fxp' => 'fxp', 'application/vnd.adobe.xdp+xml' => 'xdp', 'application/vnd.adobe.xfdf' => 'xfdf', 'application/vnd.ahead.space' => 'ahead', 'application/vnd.airzip.filesecure.azf' => 'azf', 'application/vnd.airzip.filesecure.azs' => 'azs', 'application/vnd.amazon.ebook' => 'azw', 'application/vnd.americandynamics.acc' => 'acc', 'application/vnd.amiga.ami' => 'ami', 'application/vnd.android.package-archive' => 'apk', 'application/vnd.anser-web-certificate-issue-initiation' => 'cii', 'application/vnd.anser-web-funds-transfer-initiation' => 'fti', 'application/vnd.antix.game-component' => 'atx', 'application/vnd.apple.installer+xml' => 'mpkg', 'application/vnd.apple.mpegurl' => 'm3u8', 'application/vnd.aristanetworks.swi' => 'swi', 'application/vnd.astraea-software.iota' => 'iota', 'application/vnd.audiograph' => 'aep', 'application/vnd.blueice.multipass' => 'mpm', 'application/vnd.bmi' => 'bmi', 'application/vnd.businessobjects' => 'rep', 'application/vnd.chemdraw+xml' => 'cdxml', 'application/vnd.chipnuts.karaoke-mmd' => 'mmd', 'application/vnd.cinderella' => 'cdy', 'application/vnd.claymore' => 'cla', 'application/vnd.cloanto.rp9' => 'rp9', 'application/vnd.clonk.c4group' => 'c4g', 'application/vnd.cluetrust.cartomobile-config' => 'c11amc', 'application/vnd.cluetrust.cartomobile-config-pkg' => 'c11amz', 'application/vnd.commonspace' => 'csp', 'application/vnd.contact.cmsg' => 'cdbcmsg', 'application/vnd.cosmocaller' => 'cmc', 'application/vnd.crick.clicker' => 'clkx', 'application/vnd.crick.clicker.keyboard' => 'clkk', 'application/vnd.crick.clicker.palette' => 'clkp', 'application/vnd.crick.clicker.template' => 'clkt', 'application/vnd.crick.clicker.wordbank' => 'clkw', 'application/vnd.criticaltools.wbs+xml' => 'wbs', 'application/vnd.ctc-posml' => 'pml', 'application/vnd.cups-ppd' => 'ppd', 'application/vnd.curl.car' => 'car', 'application/vnd.curl.pcurl' => 'pcurl', 'application/vnd.data-vision.rdz' => 'rdz', 'application/vnd.dece.data' => 'uvf', 'application/vnd.dece.ttml+xml' => 'uvt', 'application/vnd.dece.unspecified' => 'uvx', 'application/vnd.dece.zip' => 'uvz', 'application/vnd.denovo.fcselayout-link' => 'fe_launch', 'application/vnd.dna' => 'dna', 'application/vnd.dolby.mlp' => 'mlp', 'application/vnd.dpgraph' => 'dpg', 'application/vnd.dreamfactory' => 'dfac', 'application/vnd.dvb.ait' => 'ait', 'application/vnd.dvb.service' => 'svc', 'application/vnd.dynageo' => 'geo', 'application/vnd.ecowin.chart' => 'mag', 'application/vnd.enliven' => 'nml', 'application/vnd.epson.esf' => 'esf', 'application/vnd.epson.msf' => 'msf', 'application/vnd.epson.quickanime' => 'qam', 'application/vnd.epson.salt' => 'slt', 'application/vnd.epson.ssf' => 'ssf', 'application/vnd.eszigno3+xml' => 'es3', 'application/vnd.ezpix-album' => 'ez2', 'application/vnd.ezpix-package' => 'ez3', 'application/vnd.fdf' => 'fdf', 'application/vnd.fdsn.mseed' => 'mseed', 'application/vnd.fdsn.seed' => 'seed', 'application/vnd.flographit' => 'gph', 'application/vnd.fluxtime.clip' => 'ftc', 'application/vnd.framemaker' => 'fm', 'application/vnd.frogans.fnc' => 'fnc', 'application/vnd.frogans.ltf' => 'ltf', 'application/vnd.fsc.weblaunch' => 'fsc', 'application/vnd.fujitsu.oasys' => 'oas', 'application/vnd.fujitsu.oasys2' => 'oa2', 'application/vnd.fujitsu.oasys3' => 'oa3', 'application/vnd.fujitsu.oasysgp' => 'fg5', 'application/vnd.fujitsu.oasysprs' => 'bh2', 'application/vnd.fujixerox.ddd' => 'ddd', 'application/vnd.fujixerox.docuworks' => 'xdw', 'application/vnd.fujixerox.docuworks.binder' => 'xbd', 'application/vnd.fuzzysheet' => 'fzs', 'application/vnd.genomatix.tuxedo' => 'txd', 'application/vnd.geogebra.file' => 'ggb', 'application/vnd.geogebra.tool' => 'ggt', 'application/vnd.geometry-explorer' => 'gex', 'application/vnd.geonext' => 'gxt', 'application/vnd.geoplan' => 'g2w', 'application/vnd.geospace' => 'g3w', 'application/vnd.gmx' => 'gmx', 'application/vnd.google-earth.kml+xml' => 'kml', 'application/vnd.google-earth.kmz' => 'kmz', 'application/vnd.grafeq' => 'gqf', 'application/vnd.groove-account' => 'gac', 'application/vnd.groove-help' => 'ghf', 'application/vnd.groove-identity-message' => 'gim', 'application/vnd.groove-injector' => 'grv', 'application/vnd.groove-tool-message' => 'gtm', 'application/vnd.groove-tool-template' => 'tpl', 'application/vnd.groove-vcard' => 'vcg', 'application/vnd.hal+xml' => 'hal', 'application/vnd.handheld-entertainment+xml' => 'zmm', 'application/vnd.hbci' => 'hbci', 'application/vnd.hhe.lesson-player' => 'les', 'application/vnd.hp-hpgl' => 'hpgl', 'application/vnd.hp-hpid' => 'hpid', 'application/vnd.hp-hps' => 'hps', 'application/vnd.hp-jlyt' => 'jlt', 'application/vnd.hp-pcl' => 'pcl', 'application/vnd.hp-pclxl' => 'pclxl', 'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx', 'application/vnd.hzn-3d-crossword' => 'x3d', 'application/vnd.ibm.minipay' => 'mpy', 'application/vnd.ibm.modcap' => 'afp', 'application/vnd.ibm.rights-management' => 'irm', 'application/vnd.ibm.secure-container' => 'sc', 'application/vnd.iccprofile' => 'icc', 'application/vnd.igloader' => 'igl', 'application/vnd.immervision-ivp' => 'ivp', 'application/vnd.immervision-ivu' => 'ivu', 'application/vnd.insors.igm' => 'igm', 'application/vnd.intercon.formnet' => 'xpw', 'application/vnd.intergeo' => 'i2g', 'application/vnd.intu.qbo' => 'qbo', 'application/vnd.intu.qfx' => 'qfx', 'application/vnd.ipunplugged.rcprofile' => 'rcprofile', 'application/vnd.irepository.package+xml' => 'irp', 'application/vnd.is-xpr' => 'xpr', 'application/vnd.isac.fcs' => 'fcs', 'application/vnd.jam' => 'jam', 'application/vnd.jcp.javame.midlet-rms' => 'rms', 'application/vnd.jisp' => 'jisp', 'application/vnd.joost.joda-archive' => 'joda', 'application/vnd.kahootz' => 'ktz', 'application/vnd.kde.karbon' => 'karbon', 'application/vnd.kde.kchart' => 'chrt', 'application/vnd.kde.kformula' => 'kfo', 'application/vnd.kde.kivio' => 'flw', 'application/vnd.kde.kontour' => 'kon', 'application/vnd.kde.kpresenter' => 'kpr', 'application/vnd.kde.kspread' => 'ksp', 'application/vnd.kde.kword' => 'kwd', 'application/vnd.kenameaapp' => 'htke', 'application/vnd.kidspiration' => 'kia', 'application/vnd.kinar' => 'kne', 'application/vnd.koan' => 'skp', 'application/vnd.kodak-descriptor' => 'sse', 'application/vnd.las.las+xml' => 'lasxml', 'application/vnd.llamagraphics.life-balance.desktop' => 'lbd', 'application/vnd.llamagraphics.life-balance.exchange+xml' => 'lbe', 'application/vnd.lotus-1-2-3' => '123', 'application/vnd.lotus-approach' => 'apr', 'application/vnd.lotus-freelance' => 'pre', 'application/vnd.lotus-notes' => 'nsf', 'application/vnd.lotus-organizer' => 'org', 'application/vnd.lotus-screencam' => 'scm', 'application/vnd.lotus-wordpro' => 'lwp', 'application/vnd.macports.portpkg' => 'portpkg', 'application/vnd.mcd' => 'mcd', 'application/vnd.medcalcdata' => 'mc1', 'application/vnd.mediastation.cdkey' => 'cdkey', 'application/vnd.mfer' => 'mwf', 'application/vnd.mfmp' => 'mfm', 'application/vnd.micrografx.flo' => 'flo', 'application/vnd.micrografx.igx' => 'igx', 'application/vnd.mif' => 'mif', 'application/vnd.mobius.daf' => 'daf', 'application/vnd.mobius.dis' => 'dis', 'application/vnd.mobius.mbk' => 'mbk', 'application/vnd.mobius.mqy' => 'mqy', 'application/vnd.mobius.msl' => 'msl', 'application/vnd.mobius.plc' => 'plc', 'application/vnd.mobius.txf' => 'txf', 'application/vnd.mophun.application' => 'mpn', 'application/vnd.mophun.certificate' => 'mpc', 'application/vnd.mozilla.xul+xml' => 'xul', 'application/vnd.ms-artgalry' => 'cil', 'application/vnd.ms-cab-compressed' => 'cab', 'application/vnd.ms-excel' => 'xls', 'application/vnd.ms-excel.addin.macroenabled.12' => 'xlam', 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 'xlsb', 'application/vnd.ms-excel.sheet.macroenabled.12' => 'xlsm', 'application/vnd.ms-excel.template.macroenabled.12' => 'xltm', 'application/vnd.ms-fontobject' => 'eot', 'application/vnd.ms-htmlhelp' => 'chm', 'application/vnd.ms-ims' => 'ims', 'application/vnd.ms-lrm' => 'lrm', 'application/vnd.ms-officetheme' => 'thmx', 'application/vnd.ms-pki.seccat' => 'cat', 'application/vnd.ms-pki.stl' => 'stl', 'application/vnd.ms-powerpoint' => 'ppt', 'application/vnd.ms-powerpoint.addin.macroenabled.12' => 'ppam', 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'pptm', 'application/vnd.ms-powerpoint.slide.macroenabled.12' => 'sldm', 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'ppsm', 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'potm', 'application/vnd.ms-project' => 'mpp', 'application/vnd.ms-word.document.macroenabled.12' => 'docm', 'application/vnd.ms-word.template.macroenabled.12' => 'dotm', 'application/vnd.ms-works' => 'wps', 'application/vnd.ms-wpl' => 'wpl', 'application/vnd.ms-xpsdocument' => 'xps', 'application/vnd.mseq' => 'mseq', 'application/vnd.musician' => 'mus', 'application/vnd.muvee.style' => 'msty', 'application/vnd.mynfc' => 'taglet', 'application/vnd.neurolanguage.nlu' => 'nlu', 'application/vnd.noblenet-directory' => 'nnd', 'application/vnd.noblenet-sealer' => 'nns', 'application/vnd.noblenet-web' => 'nnw', 'application/vnd.nokia.n-gage.data' => 'ngdat', 'application/vnd.nokia.n-gage.symbian.install' => 'n-gage', 'application/vnd.nokia.radio-preset' => 'rpst', 'application/vnd.nokia.radio-presets' => 'rpss', 'application/vnd.novadigm.edm' => 'edm', 'application/vnd.novadigm.edx' => 'edx', 'application/vnd.novadigm.ext' => 'ext', 'application/vnd.oasis.opendocument.chart' => 'odc', 'application/vnd.oasis.opendocument.chart-template' => 'otc', 'application/vnd.oasis.opendocument.database' => 'odb', 'application/vnd.oasis.opendocument.formula' => 'odf', 'application/vnd.oasis.opendocument.formula-template' => 'odft', 'application/vnd.oasis.opendocument.graphics' => 'odg', 'application/vnd.oasis.opendocument.graphics-template' => 'otg', 'application/vnd.oasis.opendocument.image' => 'odi', 'application/vnd.oasis.opendocument.image-template' => 'oti', 'application/vnd.oasis.opendocument.presentation' => 'odp', 'application/vnd.oasis.opendocument.presentation-template' => 'otp', 'application/vnd.oasis.opendocument.spreadsheet' => 'ods', 'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots', 'application/vnd.oasis.opendocument.text' => 'odt', 'application/vnd.oasis.opendocument.text-master' => 'odm', 'application/vnd.oasis.opendocument.text-template' => 'ott', 'application/vnd.oasis.opendocument.text-web' => 'oth', 'application/vnd.olpc-sugar' => 'xo', 'application/vnd.oma.dd2+xml' => 'dd2', 'application/vnd.openofficeorg.extension' => 'oxt', 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx', 'application/vnd.openxmlformats-officedocument.presentationml.slide' => 'sldx', 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx', 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'potx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx', 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'xltx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx', 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx', 'application/vnd.osgeo.mapguide.package' => 'mgp', 'application/vnd.osgi.dp' => 'dp', 'application/vnd.palm' => 'pdb', 'application/vnd.pawaafile' => 'paw', 'application/vnd.pg.format' => 'str', 'application/vnd.pg.osasli' => 'ei6', 'application/vnd.picsel' => 'efif', 'application/vnd.pmi.widget' => 'wg', 'application/vnd.pocketlearn' => 'plf', 'application/vnd.powerbuilder6' => 'pbd', 'application/vnd.previewsystems.box' => 'box', 'application/vnd.proteus.magazine' => 'mgz', 'application/vnd.publishare-delta-tree' => 'qps', 'application/vnd.pvi.ptid1' => 'ptid', 'application/vnd.quark.quarkxpress' => 'qxd', 'application/vnd.realvnc.bed' => 'bed', 'application/vnd.recordare.musicxml' => 'mxl', 'application/vnd.recordare.musicxml+xml' => 'musicxml', 'application/vnd.rig.cryptonote' => 'cryptonote', 'application/vnd.rim.cod' => 'cod', 'application/vnd.rn-realmedia' => 'rm', 'application/vnd.route66.link66+xml' => 'link66', 'application/vnd.sailingtracker.track' => 'st', 'application/vnd.seemail' => 'see', 'application/vnd.sema' => 'sema', 'application/vnd.semd' => 'semd', 'application/vnd.semf' => 'semf', 'application/vnd.shana.informed.formdata' => 'ifm', 'application/vnd.shana.informed.formtemplate' => 'itp', 'application/vnd.shana.informed.interchange' => 'iif', 'application/vnd.shana.informed.package' => 'ipk', 'application/vnd.simtech-mindmapper' => 'twd', 'application/vnd.smaf' => 'mmf', 'application/vnd.smart.teacher' => 'teacher', 'application/vnd.solent.sdkm+xml' => 'sdkm', 'application/vnd.spotfire.dxp' => 'dxp', 'application/vnd.spotfire.sfs' => 'sfs', 'application/vnd.stardivision.calc' => 'sdc', 'application/vnd.stardivision.draw' => 'sda', 'application/vnd.stardivision.impress' => 'sdd', 'application/vnd.stardivision.math' => 'smf', 'application/vnd.stardivision.writer' => 'sdw', 'application/vnd.stardivision.writer-global' => 'sgl', 'application/vnd.stepmania.package' => 'smzip', 'application/vnd.stepmania.stepchart' => 'sm', 'application/vnd.sun.xml.calc' => 'sxc', 'application/vnd.sun.xml.calc.template' => 'stc', 'application/vnd.sun.xml.draw' => 'sxd', 'application/vnd.sun.xml.draw.template' => 'std', 'application/vnd.sun.xml.impress' => 'sxi', 'application/vnd.sun.xml.impress.template' => 'sti', 'application/vnd.sun.xml.math' => 'sxm', 'application/vnd.sun.xml.writer' => 'sxw', 'application/vnd.sun.xml.writer.global' => 'sxg', 'application/vnd.sun.xml.writer.template' => 'stw', 'application/vnd.sus-calendar' => 'sus', 'application/vnd.svd' => 'svd', 'application/vnd.symbian.install' => 'sis', 'application/vnd.syncml+xml' => 'xsm', 'application/vnd.syncml.dm+wbxml' => 'bdm', 'application/vnd.syncml.dm+xml' => 'xdm', 'application/vnd.tao.intent-module-archive' => 'tao', 'application/vnd.tcpdump.pcap' => 'pcap', 'application/vnd.tmobile-livetv' => 'tmo', 'application/vnd.trid.tpt' => 'tpt', 'application/vnd.triscape.mxs' => 'mxs', 'application/vnd.trueapp' => 'tra', 'application/vnd.ufdl' => 'ufd', 'application/vnd.uiq.theme' => 'utz', 'application/vnd.umajin' => 'umj', 'application/vnd.unity' => 'unityweb', 'application/vnd.uoml+xml' => 'uoml', 'application/vnd.vcx' => 'vcx', 'application/vnd.visio' => 'vsd', 'application/vnd.visionary' => 'vis', 'application/vnd.vsf' => 'vsf', 'application/vnd.wap.wbxml' => 'wbxml', 'application/vnd.wap.wmlc' => 'wmlc', 'application/vnd.wap.wmlscriptc' => 'wmlsc', 'application/vnd.webturbo' => 'wtb', 'application/vnd.wolfram.player' => 'nbp', 'application/vnd.wordperfect' => 'wpd', 'application/vnd.wqd' => 'wqd', 'application/vnd.wt.stf' => 'stf', 'application/vnd.xara' => 'xar', 'application/vnd.xfdl' => 'xfdl', 'application/vnd.yamaha.hv-dic' => 'hvd', 'application/vnd.yamaha.hv-script' => 'hvs', 'application/vnd.yamaha.hv-voice' => 'hvp', 'application/vnd.yamaha.openscoreformat' => 'osf', 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => 'osfpvg', 'application/vnd.yamaha.smaf-audio' => 'saf', 'application/vnd.yamaha.smaf-phrase' => 'spf', 'application/vnd.yellowriver-custom-menu' => 'cmp', 'application/vnd.zul' => 'zir', 'application/vnd.zzazz.deck+xml' => 'zaz', 'application/voicexml+xml' => 'vxml', 'application/widget' => 'wgt', 'application/winhlp' => 'hlp', 'application/wsdl+xml' => 'wsdl', 'application/wspolicy+xml' => 'wspolicy', 'application/x-7z-compressed' => '7z', 'application/x-abiword' => 'abw', 'application/x-ace-compressed' => 'ace', 'application/x-authorware-bin' => 'aab', 'application/x-authorware-map' => 'aam', 'application/x-authorware-seg' => 'aas', 'application/x-bcpio' => 'bcpio', 'application/x-bittorrent' => 'torrent', 'application/x-bzip' => 'bz', 'application/x-bzip2' => 'bz2', 'application/x-cdlink' => 'vcd', 'application/x-chat' => 'chat', 'application/x-chess-pgn' => 'pgn', 'application/x-cpio' => 'cpio', 'application/x-csh' => 'csh', 'application/x-debian-package' => 'deb', 'application/x-director' => 'dir', 'application/x-doom' => 'wad', 'application/x-dtbncx+xml' => 'ncx', 'application/x-dtbook+xml' => 'dtb', 'application/x-dtbresource+xml' => 'res', 'application/x-dvi' => 'dvi', 'application/x-font-bdf' => 'bdf', 'application/x-font-ghostscript' => 'gsf', 'application/x-font-linux-psf' => 'psf', 'application/x-font-otf' => 'otf', 'application/x-font-pcf' => 'pcf', 'application/x-font-snf' => 'snf', 'application/x-font-ttf' => 'ttf', 'application/x-font-type1' => 'pfa', 'application/x-font-woff' => 'woff', 'application/x-futuresplash' => 'spl', 'application/x-gnumeric' => 'gnumeric', 'application/x-gtar' => 'gtar', 'application/x-hdf' => 'hdf', 'application/x-java-jnlp-file' => 'jnlp', 'application/x-latex' => 'latex', 'application/x-mobipocket-ebook' => 'prc', 'application/x-ms-application' => 'application', 'application/x-ms-wmd' => 'wmd', 'application/x-ms-wmz' => 'wmz', 'application/x-ms-xbap' => 'xbap', 'application/x-msaccess' => 'mdb', 'application/x-msbinder' => 'obd', 'application/x-mscardfile' => 'crd', 'application/x-msclip' => 'clp', 'application/x-msdownload' => 'exe', 'application/x-msmediaview' => 'mvb', 'application/x-msmetafile' => 'wmf', 'application/x-msmoney' => 'mny', 'application/x-mspublisher' => 'pub', 'application/x-msschedule' => 'scd', 'application/x-msterminal' => 'trm', 'application/x-mswrite' => 'wri', 'application/x-netcdf' => 'nc', 'application/x-pkcs12' => 'p12', 'application/x-pkcs7-certificates' => 'p7b', 'application/x-pkcs7-certreqresp' => 'p7r', 'application/x-rar-compressed' => 'rar', 'application/x-sh' => 'sh', 'application/x-shar' => 'shar', 'application/x-shockwave-flash' => 'swf', 'application/x-silverlight-app' => 'xap', 'application/x-stuffit' => 'sit', 'application/x-stuffitx' => 'sitx', 'application/x-sv4cpio' => 'sv4cpio', 'application/x-sv4crc' => 'sv4crc', 'application/x-tar' => 'tar', 'application/x-tcl' => 'tcl', 'application/x-tex' => 'tex', 'application/x-tex-tfm' => 'tfm', 'application/x-texinfo' => 'texinfo', 'application/x-ustar' => 'ustar', 'application/x-wais-source' => 'src', 'application/x-x509-ca-cert' => 'der', 'application/x-xfig' => 'fig', 'application/x-xpinstall' => 'xpi', 'application/xcap-diff+xml' => 'xdf', 'application/xenc+xml' => 'xenc', 'application/xhtml+xml' => 'xhtml', 'application/xml' => 'xml', 'application/xml-dtd' => 'dtd', 'application/xop+xml' => 'xop', 'application/xslt+xml' => 'xslt', 'application/xspf+xml' => 'xspf', 'application/xv+xml' => 'mxml', 'application/yang' => 'yang', 'application/yin+xml' => 'yin', 'application/zip' => 'zip', 'audio/adpcm' => 'adp', 'audio/basic' => 'au', 'audio/midi' => 'mid', 'audio/mp4' => 'mp4a', 'audio/mpeg' => 'mpga', 'audio/ogg' => 'oga', 'audio/vnd.dece.audio' => 'uva', 'audio/vnd.digital-winds' => 'eol', 'audio/vnd.dra' => 'dra', 'audio/vnd.dts' => 'dts', 'audio/vnd.dts.hd' => 'dtshd', 'audio/vnd.lucent.voice' => 'lvp', 'audio/vnd.ms-playready.media.pya' => 'pya', 'audio/vnd.nuera.ecelp4800' => 'ecelp4800', 'audio/vnd.nuera.ecelp7470' => 'ecelp7470', 'audio/vnd.nuera.ecelp9600' => 'ecelp9600', 'audio/vnd.rip' => 'rip', 'audio/webm' => 'weba', 'audio/x-aac' => 'aac', 'audio/x-aiff' => 'aif', 'audio/x-mpegurl' => 'm3u', 'audio/x-ms-wax' => 'wax', 'audio/x-ms-wma' => 'wma', 'audio/x-pn-realaudio' => 'ram', 'audio/x-pn-realaudio-plugin' => 'rmp', 'audio/x-wav' => 'wav', 'chemical/x-cdx' => 'cdx', 'chemical/x-cif' => 'cif', 'chemical/x-cmdf' => 'cmdf', 'chemical/x-cml' => 'cml', 'chemical/x-csml' => 'csml', 'chemical/x-xyz' => 'xyz', 'image/bmp' => 'bmp', 'image/cgm' => 'cgm', 'image/g3fax' => 'g3', 'image/gif' => 'gif', 'image/ief' => 'ief', 'image/jpeg' => 'jpeg', 'image/ktx' => 'ktx', 'image/png' => 'png', 'image/prs.btif' => 'btif', 'image/svg+xml' => 'svg', 'image/tiff' => 'tiff', 'image/vnd.adobe.photoshop' => 'psd', 'image/vnd.dece.graphic' => 'uvi', 'image/vnd.dvb.subtitle' => 'sub', 'image/vnd.djvu' => 'djvu', 'image/vnd.dwg' => 'dwg', 'image/vnd.dxf' => 'dxf', 'image/vnd.fastbidsheet' => 'fbs', 'image/vnd.fpx' => 'fpx', 'image/vnd.fst' => 'fst', 'image/vnd.fujixerox.edmics-mmr' => 'mmr', 'image/vnd.fujixerox.edmics-rlc' => 'rlc', 'image/vnd.ms-modi' => 'mdi', 'image/vnd.net-fpx' => 'npx', 'image/vnd.wap.wbmp' => 'wbmp', 'image/vnd.xiff' => 'xif', 'image/webp' => 'webp', 'image/x-cmu-raster' => 'ras', 'image/x-cmx' => 'cmx', 'image/x-freehand' => 'fh', 'image/x-icon' => 'ico', 'image/x-pcx' => 'pcx', 'image/x-pict' => 'pic', 'image/x-portable-anymap' => 'pnm', 'image/x-portable-bitmap' => 'pbm', 'image/x-portable-graymap' => 'pgm', 'image/x-portable-pixmap' => 'ppm', 'image/x-rgb' => 'rgb', 'image/x-xbitmap' => 'xbm', 'image/x-xpixmap' => 'xpm', 'image/x-xwindowdump' => 'xwd', 'message/rfc822' => 'eml', 'model/iges' => 'igs', 'model/mesh' => 'msh', 'model/vnd.collada+xml' => 'dae', 'model/vnd.dwf' => 'dwf', 'model/vnd.gdl' => 'gdl', 'model/vnd.gtw' => 'gtw', 'model/vnd.mts' => 'mts', 'model/vnd.vtu' => 'vtu', 'model/vrml' => 'wrl', 'text/calendar' => 'ics', 'text/css' => 'css', 'text/csv' => 'csv', 'text/html' => 'html', 'text/n3' => 'n3', 'text/plain' => 'txt', 'text/prs.lines.tag' => 'dsc', 'text/richtext' => 'rtx', 'text/sgml' => 'sgml', 'text/tab-separated-values' => 'tsv', 'text/troff' => 't', 'text/turtle' => 'ttl', 'text/uri-list' => 'uri', 'text/vcard' => 'vcard', 'text/vnd.curl' => 'curl', 'text/vnd.curl.dcurl' => 'dcurl', 'text/vnd.curl.scurl' => 'scurl', 'text/vnd.curl.mcurl' => 'mcurl', 'text/vnd.dvb.subtitle' => 'sub', 'text/vnd.fly' => 'fly', 'text/vnd.fmi.flexstor' => 'flx', 'text/vnd.graphviz' => 'gv', 'text/vnd.in3d.3dml' => '3dml', 'text/vnd.in3d.spot' => 'spot', 'text/vnd.sun.j2me.app-descriptor' => 'jad', 'text/vnd.wap.wml' => 'wml', 'text/vnd.wap.wmlscript' => 'wmls', 'text/x-asm' => 's', 'text/x-c' => 'c', 'text/x-fortran' => 'f', 'text/x-pascal' => 'p', 'text/x-java-source' => 'java', 'text/x-setext' => 'etx', 'text/x-uuencode' => 'uu', 'text/x-vcalendar' => 'vcs', 'text/x-vcard' => 'vcf', 'video/3gpp' => '3gp', 'video/3gpp2' => '3g2', 'video/h261' => 'h261', 'video/h263' => 'h263', 'video/h264' => 'h264', 'video/jpeg' => 'jpgv', 'video/jpm' => 'jpm', 'video/mj2' => 'mj2', 'video/mp4' => 'mp4', 'video/mpeg' => 'mpeg', 'video/ogg' => 'ogv', 'video/quicktime' => 'qt', 'video/vnd.dece.hd' => 'uvh', 'video/vnd.dece.mobile' => 'uvm', 'video/vnd.dece.pd' => 'uvp', 'video/vnd.dece.sd' => 'uvs', 'video/vnd.dece.video' => 'uvv', 'video/vnd.dvb.file' => 'dvb', 'video/vnd.fvt' => 'fvt', 'video/vnd.mpegurl' => 'mxu', 'video/vnd.ms-playready.media.pyv' => 'pyv', 'video/vnd.uvvu.mp4' => 'uvu', 'video/vnd.vivo' => 'viv', 'video/webm' => 'webm', 'video/x-f4v' => 'f4v', 'video/x-fli' => 'fli', 'video/x-flv' => 'flv', 'video/x-m4v' => 'm4v', 'video/x-ms-asf' => 'asf', 'video/x-ms-wm' => 'wm', 'video/x-ms-wmv' => 'wmv', 'video/x-ms-wmx' => 'wmx', 'video/x-ms-wvx' => 'wvx', 'video/x-msvideo' => 'avi', 'video/x-sgi-movie' => 'movie', 'x-conference/x-cooltalk' => 'ice', ); public function guess($mimeType) { return isset($this->defaultExtensions[$mimeType]) ? $this->defaultExtensions[$mimeType] : null; } } register(new FileBinaryMimeTypeGuesser()); } if (FileinfoMimeTypeGuesser::isSupported()) { $this->register(new FileinfoMimeTypeGuesser()); } } public function register(MimeTypeGuesserInterface $guesser) { array_unshift($this->guessers, $guesser); } public function guess($path) { if (!is_file($path)) { throw new FileNotFoundException($path); } if (!is_readable($path)) { throw new AccessDeniedException($path); } if (!$this->guessers) { throw new \LogicException('Unable to guess the mime type as no guessers are available (Did you enable the php_fileinfo extension?)'); } foreach ($this->guessers as $guesser) { if (null !== $mimeType = $guesser->guess($path)) { return $mimeType; } } } } originalName = basename($originalName); $this->mimeType = $mimeType ?: 'application/octet-stream'; $this->size = $size; $this->error = $error ?: UPLOAD_ERR_OK; $this->test = (Boolean) $test; parent::__construct($path, UPLOAD_ERR_OK === $this->error); } public function getClientOriginalName() { return $this->originalName; } public function getClientMimeType() { return $this->mimeType; } public function getClientSize() { return $this->size; } public function getError() { return $this->error; } public function isValid() { return $this->error === UPLOAD_ERR_OK; } public function move($directory, $name = null) { if ($this->isValid() && ($this->test || is_uploaded_file($this->getPathname()))) { return parent::move($directory, $name); } throw new FileException(sprintf('The file "%s" has not been uploaded via Http', $this->getPathname())); } static public function getMaxFilesize() { $max = trim(ini_get('upload_max_filesize')); if ('' === $max) { return PHP_INT_MAX; } switch (strtolower(substr($max, -1))) { case 'g': $max *= 1024; case 'm': $max *= 1024; case 'k': $max *= 1024; } return (integer) $max; } } replace($parameters); } public function replace(array $files = array()) { $this->parameters = array(); $this->add($files); } public function set($key, $value) { if (is_array($value) || $value instanceof UploadedFile) { parent::set($key, $this->convertFileInformation($value)); } else { throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.'); } } public function add(array $files = array()) { foreach ($files as $key => $file) { $this->set($key, $file); } } protected function convertFileInformation($file) { if ($file instanceof UploadedFile) { return $file; } $file = $this->fixPhpFilesArray($file); if (is_array($file)) { $keys = array_keys($file); sort($keys); if ($keys == self::$fileKeys) { if (UPLOAD_ERR_NO_FILE == $file['error']) { $file = null; } else { $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']); } } else { $file = array_map(array($this, 'convertFileInformation'), $file); } } return $file; } protected function fixPhpFilesArray($data) { if (!is_array($data)) { return $data; } $keys = array_keys($data); sort($keys); if (self::$fileKeys != $keys || !isset($data['name']) || !is_array($data['name'])) { return $data; } $files = $data; foreach (self::$fileKeys as $k) { unset($files[$k]); } foreach (array_keys($data['name']) as $key) { $files[$key] = $this->fixPhpFilesArray(array( 'error' => $data['error'][$key], 'name' => $data['name'][$key], 'type' => $data['type'][$key], 'tmp_name' => $data['tmp_name'][$key], 'size' => $data['size'][$key] )); } return $files; } } cacheControl = array(); $this->headers = array(); foreach ($headers as $key => $values) { $this->set($key, $values); } } public function __toString() { if (!$this->headers) { return ''; } $max = max(array_map('strlen', array_keys($this->headers))) + 1; $content = ''; ksort($this->headers); foreach ($this->headers as $name => $values) { $name = implode('-', array_map('ucfirst', explode('-', $name))); foreach ($values as $value) { $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value); } } return $content; } public function all() { return $this->headers; } public function keys() { return array_keys($this->headers); } public function replace(array $headers = array()) { $this->headers = array(); $this->add($headers); } public function add(array $headers) { foreach ($headers as $key => $values) { $this->set($key, $values); } } public function get($key, $default = null, $first = true) { $key = strtr(strtolower($key), '_', '-'); if (!array_key_exists($key, $this->headers)) { if (null === $default) { return $first ? null : array(); } return $first ? $default : array($default); } if ($first) { return count($this->headers[$key]) ? $this->headers[$key][0] : $default; } return $this->headers[$key]; } public function set($key, $values, $replace = true) { $key = strtr(strtolower($key), '_', '-'); $values = (array) $values; if (true === $replace || !isset($this->headers[$key])) { $this->headers[$key] = $values; } else { $this->headers[$key] = array_merge($this->headers[$key], $values); } if ('cache-control' === $key) { $this->cacheControl = $this->parseCacheControl($values[0]); } } public function has($key) { return array_key_exists(strtr(strtolower($key), '_', '-'), $this->headers); } public function contains($key, $value) { return in_array($value, $this->get($key, null, false)); } public function remove($key) { $key = strtr(strtolower($key), '_', '-'); unset($this->headers[$key]); if ('cache-control' === $key) { $this->cacheControl = array(); } } public function getDate($key, \DateTime $default = null) { if (null === $value = $this->get($key)) { return $default; } if (false === $date = \DateTime::createFromFormat(DATE_RFC2822, $value)) { throw new \RuntimeException(sprintf('The %s HTTP header is not parseable (%s).', $key, $value)); } return $date; } public function addCacheControlDirective($key, $value = true) { $this->cacheControl[$key] = $value; $this->set('Cache-Control', $this->getCacheControlHeader()); } public function hasCacheControlDirective($key) { return array_key_exists($key, $this->cacheControl); } public function getCacheControlDirective($key) { return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null; } public function removeCacheControlDirective($key) { unset($this->cacheControl[$key]); $this->set('Cache-Control', $this->getCacheControlHeader()); } public function getIterator() { return new \ArrayIterator($this->headers); } public function count() { return count($this->headers); } protected function getCacheControlHeader() { $parts = array(); ksort($this->cacheControl); foreach ($this->cacheControl as $key => $value) { if (true === $value) { $parts[] = $key; } else { if (preg_match('#[^a-zA-Z0-9._-]#', $value)) { $value = '"'.$value.'"'; } $parts[] = "$key=$value"; } } return implode(', ', $parts); } protected function parseCacheControl($header) { $cacheControl = array(); preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $cacheControl[strtolower($match[1])] = isset($match[2]) && $match[2] ? $match[2] : (isset($match[3]) ? $match[3] : true); } return $cacheControl; } } setData($data); } static public function create($data = array(), $status = 200, $headers = array()) { return new static($data, $status, $headers); } public function setCallback($callback = null) { if ($callback) { $pattern = '/^[$_\p{L}][$_\p{L}\p{Mn}\p{Mc}\p{Nd}\p{Pc}\x{200C}\x{200D}]*+$/u'; if (!preg_match($pattern, $callback)) { throw new \InvalidArgumentException('The callback name is not valid.'); } } $this->callback = $callback; return $this->update(); } public function setData($data = array()) { if (is_array($data) && 0 === count($data)) { $data = new \ArrayObject(); } $this->data = json_encode($data); return $this->update(); } protected function update() { if ($this->callback) { $this->headers->set('Content-Type', 'text/javascript', true); return $this->setContent(sprintf('%s(%s);', $this->callback, $this->data)); } $this->headers->set('Content-Type', 'application/json', false); return $this->setContent($this->data); } } parameters = $parameters; } public function all() { return $this->parameters; } public function keys() { return array_keys($this->parameters); } public function replace(array $parameters = array()) { $this->parameters = $parameters; } public function add(array $parameters = array()) { $this->parameters = array_replace($this->parameters, $parameters); } public function get($path, $default = null, $deep = false) { if (!$deep || false === $pos = strpos($path, '[')) { return array_key_exists($path, $this->parameters) ? $this->parameters[$path] : $default; } $root = substr($path, 0, $pos); if (!array_key_exists($root, $this->parameters)) { return $default; } $value = $this->parameters[$root]; $currentKey = null; for ($i = $pos, $c = strlen($path); $i < $c; $i++) { $char = $path[$i]; if ('[' === $char) { if (null !== $currentKey) { throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "[" at position %d.', $i)); } $currentKey = ''; } elseif (']' === $char) { if (null === $currentKey) { throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "]" at position %d.', $i)); } if (!is_array($value) || !array_key_exists($currentKey, $value)) { return $default; } $value = $value[$currentKey]; $currentKey = null; } else { if (null === $currentKey) { throw new \InvalidArgumentException(sprintf('Malformed path. Unexpected "%s" at position %d.', $char, $i)); } $currentKey .= $char; } } if (null !== $currentKey) { throw new \InvalidArgumentException(sprintf('Malformed path. Path must end with "]".')); } return $value; } public function set($key, $value) { $this->parameters[$key] = $value; } public function has($key) { return array_key_exists($key, $this->parameters); } public function remove($key) { unset($this->parameters[$key]); } public function getAlpha($key, $default = '', $deep = false) { return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default, $deep)); } public function getAlnum($key, $default = '', $deep = false) { return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default, $deep)); } public function getDigits($key, $default = '', $deep = false) { return str_replace(array('-', '+'), '', $this->filter($key, $default, $deep, FILTER_SANITIZE_NUMBER_INT)); } public function getInt($key, $default = 0, $deep = false) { return (int) $this->get($key, $default, $deep); } public function filter($key, $default = null, $deep = false, $filter=FILTER_DEFAULT, $options=array()) { $value = $this->get($key, $default, $deep); if (!is_array($options) && $options) { $options = array('flags' => $options); } if (is_array($value) && !isset($options['flags'])) { $options['flags'] = FILTER_REQUIRE_ARRAY; } return filter_var($value, $filter, $options); } public function getIterator() { return new \ArrayIterator($this->parameters); } public function count() { return count($this->parameters); } } targetUrl = $url; parent::__construct( sprintf(' Redirecting to %1$s Redirecting to %1$s. ', htmlspecialchars($url, ENT_QUOTES, 'UTF-8')), $status, array_merge($headers, array('Location' => $url)) ); if (!$this->isRedirect()) { throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status)); } } static public function create($url = '', $status = 302, $headers = array()) { return new static($url, $status, $headers); } public function getTargetUrl() { return $this->targetUrl; } } initialize($query, $request, $attributes, $cookies, $files, $server, $content); } public function initialize(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null) { $this->request = new ParameterBag($request); $this->query = new ParameterBag($query); $this->attributes = new ParameterBag($attributes); $this->cookies = new ParameterBag($cookies); $this->files = new FileBag($files); $this->server = new ServerBag($server); $this->headers = new HeaderBag($this->server->getHeaders()); $this->content = $content; $this->languages = null; $this->charsets = null; $this->acceptableContentTypes = null; $this->pathInfo = null; $this->requestUri = null; $this->baseUrl = null; $this->basePath = null; $this->method = null; $this->format = null; } static public function createFromGlobals() { $request = new static($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER); if (0 === strpos($request->server->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded') && in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH')) ) { parse_str($request->getContent(), $data); $request->request = new ParameterBag($data); } return $request; } static public function create($uri, $method = 'GET', $parameters = array(), $cookies = array(), $files = array(), $server = array(), $content = null) { $defaults = array( 'SERVER_NAME' => 'localhost', 'SERVER_PORT' => 80, 'HTTP_HOST' => 'localhost', 'HTTP_USER_AGENT' => 'Symfony/2.X', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'REMOTE_ADDR' => '127.0.0.1', 'SCRIPT_NAME' => '', 'SCRIPT_FILENAME' => '', 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_TIME' => time(), ); $components = parse_url($uri); if (isset($components['host'])) { $defaults['SERVER_NAME'] = $components['host']; $defaults['HTTP_HOST'] = $components['host']; } if (isset($components['scheme'])) { if ('https' === $components['scheme']) { $defaults['HTTPS'] = 'on'; $defaults['SERVER_PORT'] = 443; } } if (isset($components['port'])) { $defaults['SERVER_PORT'] = $components['port']; $defaults['HTTP_HOST'] = $defaults['HTTP_HOST'].':'.$components['port']; } if (isset($components['user'])) { $defaults['PHP_AUTH_USER'] = $components['user']; } if (isset($components['pass'])) { $defaults['PHP_AUTH_PW'] = $components['pass']; } if (!isset($components['path'])) { $components['path'] = ''; } switch (strtoupper($method)) { case 'POST': case 'PUT': case 'DELETE': $defaults['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; case 'PATCH': $request = $parameters; $query = array(); break; default: $request = array(); $query = $parameters; break; } if (isset($components['query'])) { $queryString = html_entity_decode($components['query']); parse_str($queryString, $qs); if (is_array($qs)) { $query = array_replace($qs, $query); } } $queryString = http_build_query($query); $uri = $components['path'].($queryString ? '?'.$queryString : ''); $server = array_replace($defaults, $server, array( 'REQUEST_METHOD' => strtoupper($method), 'PATH_INFO' => '', 'REQUEST_URI' => $uri, 'QUERY_STRING' => $queryString, )); return new static($query, $request, array(), $cookies, $files, $server, $content); } public function duplicate(array $query = null, array $request = null, array $attributes = null, array $cookies = null, array $files = null, array $server = null) { $dup = clone $this; if ($query !== null) { $dup->query = new ParameterBag($query); } if ($request !== null) { $dup->request = new ParameterBag($request); } if ($attributes !== null) { $dup->attributes = new ParameterBag($attributes); } if ($cookies !== null) { $dup->cookies = new ParameterBag($cookies); } if ($files !== null) { $dup->files = new FileBag($files); } if ($server !== null) { $dup->server = new ServerBag($server); $dup->headers = new HeaderBag($dup->server->getHeaders()); } $dup->languages = null; $dup->charsets = null; $dup->acceptableContentTypes = null; $dup->pathInfo = null; $dup->requestUri = null; $dup->baseUrl = null; $dup->basePath = null; $dup->method = null; $dup->format = null; return $dup; } public function __clone() { $this->query = clone $this->query; $this->request = clone $this->request; $this->attributes = clone $this->attributes; $this->cookies = clone $this->cookies; $this->files = clone $this->files; $this->server = clone $this->server; $this->headers = clone $this->headers; } public function __toString() { return sprintf('%s %s %s', $this->getMethod(), $this->getRequestUri(), $this->server->get('SERVER_PROTOCOL'))."\r\n". $this->headers."\r\n". $this->getContent(); } public function overrideGlobals() { $_GET = $this->query->all(); $_POST = $this->request->all(); $_SERVER = $this->server->all(); $_COOKIE = $this->cookies->all(); foreach ($this->headers->all() as $key => $value) { $key = strtoupper(str_replace('-', '_', $key)); if (in_array($key, array('CONTENT_TYPE', 'CONTENT_LENGTH'))) { $_SERVER[$key] = implode(', ', $value); } else { $_SERVER['HTTP_'.$key] = implode(', ', $value); } } $_REQUEST = array_merge($_GET, $_POST); } static public function trustProxyData() { self::$trustProxy = true; } static public function isProxyTrusted() { return self::$trustProxy; } public function get($key, $default = null, $deep = false) { return $this->query->get($key, $this->attributes->get($key, $this->request->get($key, $default, $deep), $deep), $deep); } public function getSession() { return $this->session; } public function hasPreviousSession() { $sessionName = $this->hasSession() ? $this->session->getName() : null; return $this->cookies->has($sessionName) && $this->hasSession(); } public function hasSession() { return null !== $this->session; } public function setSession(SessionInterface $session) { $this->session = $session; } public function getClientIp() { if (self::$trustProxy) { if ($this->server->has('HTTP_CLIENT_IP')) { return $this->server->get('HTTP_CLIENT_IP'); } elseif ($this->server->has('HTTP_X_FORWARDED_FOR')) { $clientIp = explode(',', $this->server->get('HTTP_X_FORWARDED_FOR'), 2); return isset($clientIp[0]) ? trim($clientIp[0]) : ''; } } return $this->server->get('REMOTE_ADDR'); } public function getScriptName() { return $this->server->get('SCRIPT_NAME', $this->server->get('ORIG_SCRIPT_NAME', '')); } public function getPathInfo() { if (null === $this->pathInfo) { $this->pathInfo = $this->preparePathInfo(); } return $this->pathInfo; } public function getBasePath() { if (null === $this->basePath) { $this->basePath = $this->prepareBasePath(); } return $this->basePath; } public function getBaseUrl() { if (null === $this->baseUrl) { $this->baseUrl = $this->prepareBaseUrl(); } return $this->baseUrl; } public function getScheme() { return $this->isSecure() ? 'https' : 'http'; } public function getPort() { if (self::$trustProxy && $this->headers->has('X-Forwarded-Port')) { return $this->headers->get('X-Forwarded-Port'); } return $this->server->get('SERVER_PORT'); } public function getUser() { return $this->server->get('PHP_AUTH_USER'); } public function getPassword() { return $this->server->get('PHP_AUTH_PW'); } public function getHttpHost() { $scheme = $this->getScheme(); $port = $this->getPort(); if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) { return $this->getHost(); } return $this->getHost().':'.$port; } public function getRequestUri() { if (null === $this->requestUri) { $this->requestUri = $this->prepareRequestUri(); } return $this->requestUri; } public function getUri() { $qs = $this->getQueryString(); if (null !== $qs) { $qs = '?'.$qs; } $auth = ''; if ($user = $this->getUser()) { $auth = $user; } if ($pass = $this->getPassword()) { $auth .= ":$pass"; } if ('' !== $auth) { $auth .= '@'; } return $this->getScheme().'://'.$auth.$this->getHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs; } public function getUriForPath($path) { return $this->getScheme().'://'.$this->getHttpHost().$this->getBaseUrl().$path; } public function getQueryString() { if (!$qs = $this->server->get('QUERY_STRING')) { return null; } $parts = array(); $order = array(); foreach (explode('&', $qs) as $segment) { if (false === strpos($segment, '=')) { $parts[] = $segment; $order[] = $segment; } else { $tmp = explode('=', rawurldecode($segment), 2); $parts[] = rawurlencode($tmp[0]).'='.rawurlencode($tmp[1]); $order[] = $tmp[0]; } } array_multisort($order, SORT_ASC, $parts); return implode('&', $parts); } public function isSecure() { return ( (strtolower($this->server->get('HTTPS')) == 'on' || $this->server->get('HTTPS') == 1) || (self::$trustProxy && strtolower($this->headers->get('SSL_HTTPS')) == 'on' || $this->headers->get('SSL_HTTPS') == 1) || (self::$trustProxy && strtolower($this->headers->get('X_FORWARDED_PROTO')) == 'https') ); } public function getHost() { if (self::$trustProxy && $host = $this->headers->get('X_FORWARDED_HOST')) { $elements = explode(',', $host); $host = trim($elements[count($elements) - 1]); } else { if (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { $host = $this->server->get('SERVER_ADDR', ''); } } } $host = preg_replace('/:\d+$/', '', $host); return trim(strtolower($host)); } public function setMethod($method) { $this->method = null; $this->server->set('REQUEST_METHOD', $method); } public function getMethod() { if (null === $this->method) { $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET')); if ('POST' === $this->method) { $this->method = strtoupper($this->headers->get('X-HTTP-METHOD-OVERRIDE', $this->request->get('_method', 'POST'))); } } return $this->method; } public function getMimeType($format) { if (null === static::$formats) { static::initializeFormats(); } return isset(static::$formats[$format]) ? static::$formats[$format][0] : null; } public function getFormat($mimeType) { if (false !== $pos = strpos($mimeType, ';')) { $mimeType = substr($mimeType, 0, $pos); } if (null === static::$formats) { static::initializeFormats(); } foreach (static::$formats as $format => $mimeTypes) { if (in_array($mimeType, (array) $mimeTypes)) { return $format; } } return null; } public function setFormat($format, $mimeTypes) { if (null === static::$formats) { static::initializeFormats(); } static::$formats[$format] = is_array($mimeTypes) ? $mimeTypes : array($mimeTypes); } public function getRequestFormat($default = 'html') { if (null === $this->format) { $this->format = $this->get('_format', $default); } return $this->format; } public function setRequestFormat($format) { $this->format = $format; } public function getContentType() { return $this->getFormat($this->server->get('CONTENT_TYPE')); } public function setDefaultLocale($locale) { $this->setPhpDefaultLocale($this->defaultLocale = $locale); } public function setLocale($locale) { $this->setPhpDefaultLocale($this->locale = $locale); } public function getLocale() { return null === $this->locale ? $this->defaultLocale : $this->locale; } public function isMethod($method) { return $this->getMethod() === strtoupper($method); } public function isMethodSafe() { return in_array($this->getMethod(), array('GET', 'HEAD')); } public function getContent($asResource = false) { if (false === $this->content || (true === $asResource && null !== $this->content)) { throw new \LogicException('getContent() can only be called once when using the resource return type.'); } if (true === $asResource) { $this->content = false; return fopen('php://input', 'rb'); } if (null === $this->content) { $this->content = file_get_contents('php://input'); } return $this->content; } public function getETags() { return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, PREG_SPLIT_NO_EMPTY); } public function isNoCache() { return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma'); } public function getPreferredLanguage(array $locales = null) { $preferredLanguages = $this->getLanguages(); if (empty($locales)) { return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null; } if (!$preferredLanguages) { return $locales[0]; } $preferredLanguages = array_values(array_intersect($preferredLanguages, $locales)); return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0]; } public function getLanguages() { if (null !== $this->languages) { return $this->languages; } $languages = $this->splitHttpAcceptHeader($this->headers->get('Accept-Language')); $this->languages = array(); foreach ($languages as $lang => $q) { if (strstr($lang, '-')) { $codes = explode('-', $lang); if ($codes[0] == 'i') { if (count($codes) > 1) { $lang = $codes[1]; } } else { for ($i = 0, $max = count($codes); $i < $max; $i++) { if ($i == 0) { $lang = strtolower($codes[0]); } else { $lang .= '_'.strtoupper($codes[$i]); } } } } $this->languages[] = $lang; } return $this->languages; } public function getCharsets() { if (null !== $this->charsets) { return $this->charsets; } return $this->charsets = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept-Charset'))); } public function getAcceptableContentTypes() { if (null !== $this->acceptableContentTypes) { return $this->acceptableContentTypes; } return $this->acceptableContentTypes = array_keys($this->splitHttpAcceptHeader($this->headers->get('Accept'))); } public function isXmlHttpRequest() { return 'XMLHttpRequest' == $this->headers->get('X-Requested-With'); } public function splitHttpAcceptHeader($header) { if (!$header) { return array(); } $values = array(); foreach (array_filter(explode(',', $header)) as $value) { if (preg_match('/;\s*(q=.*$)/', $value, $match)) { $q = (float) substr(trim($match[1]), 2); $value = trim(substr($value, 0, -strlen($match[0]))); } else { $q = 1; } if (0 < $q) { $values[trim($value)] = $q; } } arsort($values); reset($values); return $values; } protected function prepareRequestUri() { $requestUri = ''; if ($this->headers->has('X_REWRITE_URL') && false !== stripos(PHP_OS, 'WIN')) { $requestUri = $this->headers->get('X_REWRITE_URL'); } elseif ($this->server->get('IIS_WasUrlRewritten') == '1' && $this->server->get('UNENCODED_URL') != '') { $requestUri = $this->server->get('UNENCODED_URL'); } elseif ($this->server->has('REQUEST_URI')) { $requestUri = $this->server->get('REQUEST_URI'); $schemeAndHttpHost = $this->getScheme().'://'.$this->getHttpHost(); if (strpos($requestUri, $schemeAndHttpHost) === 0) { $requestUri = substr($requestUri, strlen($schemeAndHttpHost)); } } elseif ($this->server->has('ORIG_PATH_INFO')) { $requestUri = $this->server->get('ORIG_PATH_INFO'); if ($this->server->get('QUERY_STRING')) { $requestUri .= '?'.$this->server->get('QUERY_STRING'); } } return $requestUri; } protected function prepareBaseUrl() { $filename = basename($this->server->get('SCRIPT_FILENAME')); if (basename($this->server->get('SCRIPT_NAME')) === $filename) { $baseUrl = $this->server->get('SCRIPT_NAME'); } elseif (basename($this->server->get('PHP_SELF')) === $filename) { $baseUrl = $this->server->get('PHP_SELF'); } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) { $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); } else { $path = $this->server->get('PHP_SELF', ''); $file = $this->server->get('SCRIPT_FILENAME', ''); $segs = explode('/', trim($file, '/')); $segs = array_reverse($segs); $index = 0; $last = count($segs); $baseUrl = ''; do { $seg = $segs[$index]; $baseUrl = '/'.$seg.$baseUrl; ++$index; } while (($last > $index) && (false !== ($pos = strpos($path, $baseUrl))) && (0 != $pos)); } $requestUri = $this->getRequestUri(); if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { return $prefix; } if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, dirname($baseUrl))) { return rtrim($prefix, '/'); } $truncatedRequestUri = $requestUri; if (($pos = strpos($requestUri, '?')) !== false) { $truncatedRequestUri = substr($requestUri, 0, $pos); } $basename = basename($baseUrl); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { return ''; } if ((strlen($requestUri) >= strlen($baseUrl)) && ((false !== ($pos = strpos($requestUri, $baseUrl))) && ($pos !== 0))) { $baseUrl = substr($requestUri, 0, $pos + strlen($baseUrl)); } return rtrim($baseUrl, '/'); } protected function prepareBasePath() { $filename = basename($this->server->get('SCRIPT_FILENAME')); $baseUrl = $this->getBaseUrl(); if (empty($baseUrl)) { return ''; } if (basename($baseUrl) === $filename) { $basePath = dirname($baseUrl); } else { $basePath = $baseUrl; } if ('\\' === DIRECTORY_SEPARATOR) { $basePath = str_replace('\\', '/', $basePath); } return rtrim($basePath, '/'); } protected function preparePathInfo() { $baseUrl = $this->getBaseUrl(); if (null === ($requestUri = $this->getRequestUri())) { return '/'; } $pathInfo = '/'; if ($pos = strpos($requestUri, '?')) { $requestUri = substr($requestUri, 0, $pos); } if ((null !== $baseUrl) && (false === ($pathInfo = substr($requestUri, strlen($baseUrl))))) { return '/'; } elseif (null === $baseUrl) { return $requestUri; } return (string) $pathInfo; } static protected function initializeFormats() { static::$formats = array( 'html' => array('text/html', 'application/xhtml+xml'), 'txt' => array('text/plain'), 'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'), 'css' => array('text/css'), 'json' => array('application/json', 'application/x-json'), 'xml' => array('text/xml', 'application/xml', 'application/x-xml'), 'rdf' => array('application/rdf+xml'), 'atom' => array('application/atom+xml'), 'rss' => array('application/rss+xml'), ); } private function setPhpDefaultLocale($locale) { try { if (class_exists('Locale', false)) { \Locale::setDefault($locale); } } catch (\Exception $e) { } } private function getUrlencodedPrefix($string, $prefix) { if (0 !== strpos(rawurldecode($string), $prefix)) { return false; } $len = strlen($prefix); if (preg_match("#^(%[[:xdigit:]]{2}|.){{$len}}#", $string, $match)) { return $match[0]; } return false; } } path = $path; $this->host = $host; $this->methods = $methods; $this->ip = $ip; $this->attributes = $attributes; } public function matchHost($regexp) { $this->host = $regexp; } public function matchPath($regexp) { $this->path = $regexp; } public function matchIp($ip) { $this->ip = $ip; } public function matchMethod($method) { $this->methods = array_map('strtoupper', is_array($method) ? $method : array($method)); } public function matchAttribute($key, $regexp) { $this->attributes[$key] = $regexp; } public function matches(Request $request) { if (null !== $this->methods && !in_array($request->getMethod(), $this->methods)) { return false; } foreach ($this->attributes as $key => $pattern) { if (!preg_match('#'.str_replace('#', '\\#', $pattern).'#', $request->attributes->get($key))) { return false; } } if (null !== $this->path) { $path = str_replace('#', '\\#', $this->path); if (!preg_match('#'.$path.'#', rawurldecode($request->getPathInfo()))) { return false; } } if (null !== $this->host && !preg_match('#'.str_replace('#', '\\#', $this->host).'#', $request->getHost())) { return false; } if (null !== $this->ip && !$this->checkIp($request->getClientIp(), $this->ip)) { return false; } return true; } protected function checkIp($requestIp, $ip) { if (false !== strpos($requestIp, ':')) { return $this->checkIp6($requestIp, $ip); } else { return $this->checkIp4($requestIp, $ip); } } protected function checkIp4($requestIp, $ip) { if (false !== strpos($ip, '/')) { list($address, $netmask) = explode('/', $ip, 2); if ($netmask < 1 || $netmask > 32) { return false; } } else { $address = $ip; $netmask = 32; } return 0 === substr_compare(sprintf('%032b', ip2long($requestIp)), sprintf('%032b', ip2long($address)), 0, $netmask); } protected function checkIp6($requestIp, $ip) { if (!defined('AF_INET6')) { throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".'); } list($address, $netmask) = explode('/', $ip, 2); $bytesAddr = unpack("n*", inet_pton($address)); $bytesTest = unpack("n*", inet_pton($requestIp)); for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; $i++) { $left = $netmask - 16 * ($i-1); $left = ($left <= 16) ? $left : 16; $mask = ~(0xffff >> $left) & 0xffff; if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) { return false; } } return true; } } 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 208 => 'Already Reported', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Reserved', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Reserved for WebDAV advanced collections expired proposal', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates (Experimental)', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required', ); public function __construct($content = '', $status = 200, $headers = array()) { $this->headers = new ResponseHeaderBag($headers); $this->setContent($content); $this->setStatusCode($status); $this->setProtocolVersion('1.0'); if (!$this->headers->has('Date')) { $this->setDate(new \DateTime(null, new \DateTimeZone('UTC'))); } } static public function create($content = '', $status = 200, $headers = array()) { return new static($content, $status, $headers); } public function __toString() { return sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)."\r\n". $this->headers."\r\n". $this->getContent(); } public function __clone() { $this->headers = clone $this->headers; } public function prepare(Request $request) { $headers = $this->headers; if ($this->isInformational() || in_array($this->statusCode, array(204, 304))) { $this->setContent(''); } if (!$headers->has('Content-Type')) { $format = $request->getRequestFormat(); if (null !== $format && $mimeType = $request->getMimeType($format)) { $headers->set('Content-Type', $mimeType); } } $charset = $this->charset ?: 'UTF-8'; if (!$headers->has('Content-Type')) { $headers->set('Content-Type', 'text/html; charset='.$charset); } elseif (0 === strpos($headers->get('Content-Type'), 'text/') && false === strpos($headers->get('Content-Type'), 'charset')) { $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset); } if ($headers->has('Transfer-Encoding')) { $headers->remove('Content-Length'); } if ('HEAD' === $request->getMethod()) { $length = $headers->get('Content-Length'); $this->setContent(''); if ($length) { $headers->set('Content-Length', $length); } } return $this; } public function sendHeaders() { if (headers_sent()) { return $this; } header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText)); foreach ($this->headers->all() as $name => $values) { foreach ($values as $value) { header($name.': '.$value, false); } } foreach ($this->headers->getCookies() as $cookie) { setcookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); } return $this; } public function sendContent() { echo $this->content; return $this; } public function send() { $this->sendHeaders(); $this->sendContent(); if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } return $this; } public function setContent($content) { if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable(array($content, '__toString'))) { throw new \UnexpectedValueException('The Response content must be a string or object implementing __toString(), "'.gettype($content).'" given.'); } $this->content = (string) $content; return $this; } public function getContent() { return $this->content; } public function setProtocolVersion($version) { $this->version = $version; return $this; } public function getProtocolVersion() { return $this->version; } public function setStatusCode($code, $text = null) { $this->statusCode = (int) $code; if ($this->isInvalid()) { throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); } $this->statusText = false === $text ? '' : (null === $text ? self::$statusTexts[$this->statusCode] : $text); return $this; } public function getStatusCode() { return $this->statusCode; } public function setCharset($charset) { $this->charset = $charset; return $this; } public function getCharset() { return $this->charset; } public function isCacheable() { if (!in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) { return false; } if ($this->headers->hasCacheControlDirective('no-store') || $this->headers->getCacheControlDirective('private')) { return false; } return $this->isValidateable() || $this->isFresh(); } public function isFresh() { return $this->getTtl() > 0; } public function isValidateable() { return $this->headers->has('Last-Modified') || $this->headers->has('ETag'); } public function setPrivate() { $this->headers->removeCacheControlDirective('public'); $this->headers->addCacheControlDirective('private'); return $this; } public function setPublic() { $this->headers->addCacheControlDirective('public'); $this->headers->removeCacheControlDirective('private'); return $this; } public function mustRevalidate() { return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->has('must-proxy-revalidate'); } public function getDate() { return $this->headers->getDate('Date'); } public function setDate(\DateTime $date) { $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT'); return $this; } public function getAge() { if ($age = $this->headers->get('Age')) { return $age; } return max(time() - $this->getDate()->format('U'), 0); } public function expire() { if ($this->isFresh()) { $this->headers->set('Age', $this->getMaxAge()); } return $this; } public function getExpires() { return $this->headers->getDate('Expires'); } public function setExpires(\DateTime $date = null) { if (null === $date) { $this->headers->remove('Expires'); } else { $date = clone $date; $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); } return $this; } public function getMaxAge() { if ($age = $this->headers->getCacheControlDirective('s-maxage')) { return $age; } if ($age = $this->headers->getCacheControlDirective('max-age')) { return $age; } if (null !== $this->getExpires()) { return $this->getExpires()->format('U') - $this->getDate()->format('U'); } return null; } public function setMaxAge($value) { $this->headers->addCacheControlDirective('max-age', $value); return $this; } public function setSharedMaxAge($value) { $this->setPublic(); $this->headers->addCacheControlDirective('s-maxage', $value); return $this; } public function getTtl() { if ($maxAge = $this->getMaxAge()) { return $maxAge - $this->getAge(); } return null; } public function setTtl($seconds) { $this->setSharedMaxAge($this->getAge() + $seconds); return $this; } public function setClientTtl($seconds) { $this->setMaxAge($this->getAge() + $seconds); return $this; } public function getLastModified() { return $this->headers->getDate('Last-Modified'); } public function setLastModified(\DateTime $date = null) { if (null === $date) { $this->headers->remove('Last-Modified'); } else { $date = clone $date; $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); } return $this; } public function getEtag() { return $this->headers->get('ETag'); } public function setEtag($etag = null, $weak = false) { if (null === $etag) { $this->headers->remove('Etag'); } else { if (0 !== strpos($etag, '"')) { $etag = '"'.$etag.'"'; } $this->headers->set('ETag', (true === $weak ? 'W/' : '').$etag); } return $this; } public function setCache(array $options) { if ($diff = array_diff(array_keys($options), array('etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public'))) { throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', array_values($diff)))); } if (isset($options['etag'])) { $this->setEtag($options['etag']); } if (isset($options['last_modified'])) { $this->setLastModified($options['last_modified']); } if (isset($options['max_age'])) { $this->setMaxAge($options['max_age']); } if (isset($options['s_maxage'])) { $this->setSharedMaxAge($options['s_maxage']); } if (isset($options['public'])) { if ($options['public']) { $this->setPublic(); } else { $this->setPrivate(); } } if (isset($options['private'])) { if ($options['private']) { $this->setPrivate(); } else { $this->setPublic(); } } return $this; } public function setNotModified() { $this->setStatusCode(304); $this->setContent(null); foreach (array('Allow', 'Content-Encoding', 'Content-Language', 'Content-Length', 'Content-MD5', 'Content-Type', 'Last-Modified') as $header) { $this->headers->remove($header); } return $this; } public function hasVary() { return (Boolean) $this->headers->get('Vary'); } public function getVary() { if (!$vary = $this->headers->get('Vary')) { return array(); } return is_array($vary) ? $vary : preg_split('/[\s,]+/', $vary); } public function setVary($headers, $replace = true) { $this->headers->set('Vary', $headers, $replace); return $this; } public function isNotModified(Request $request) { $lastModified = $request->headers->get('If-Modified-Since'); $notModified = false; if ($etags = $request->getEtags()) { $notModified = (in_array($this->getEtag(), $etags) || in_array('*', $etags)) && (!$lastModified || $this->headers->get('Last-Modified') == $lastModified); } elseif ($lastModified) { $notModified = $lastModified == $this->headers->get('Last-Modified'); } if ($notModified) { $this->setNotModified(); } return $notModified; } public function isInvalid() { return $this->statusCode < 100 || $this->statusCode >= 600; } public function isInformational() { return $this->statusCode >= 100 && $this->statusCode < 200; } public function isSuccessful() { return $this->statusCode >= 200 && $this->statusCode < 300; } public function isRedirection() { return $this->statusCode >= 300 && $this->statusCode < 400; } public function isClientError() { return $this->statusCode >= 400 && $this->statusCode < 500; } public function isServerError() { return $this->statusCode >= 500 && $this->statusCode < 600; } public function isOk() { return 200 === $this->statusCode; } public function isForbidden() { return 403 === $this->statusCode; } public function isNotFound() { return 404 === $this->statusCode; } public function isRedirect($location = null) { return in_array($this->statusCode, array(201, 301, 302, 303, 307)) && (null === $location ?: $location == $this->headers->get('Location')); } public function isEmpty() { return in_array($this->statusCode, array(201, 204, 304)); } } headers['cache-control'])) { $this->set('cache-control', ''); } } public function __toString() { $cookies = ''; foreach ($this->getCookies() as $cookie) { $cookies .= 'Set-Cookie: '.$cookie."\r\n"; } return parent::__toString().$cookies; } public function replace(array $headers = array()) { parent::replace($headers); if (!isset($this->headers['cache-control'])) { $this->set('cache-control', ''); } } public function set($key, $values, $replace = true) { parent::set($key, $values, $replace); if (in_array(strtr(strtolower($key), '_', '-'), array('cache-control', 'etag', 'last-modified', 'expires'))) { $computed = $this->computeCacheControlValue(); $this->headers['cache-control'] = array($computed); $this->computedCacheControl = $this->parseCacheControl($computed); } } public function remove($key) { parent::remove($key); if ('cache-control' === strtr(strtolower($key), '_', '-')) { $this->computedCacheControl = array(); } } public function hasCacheControlDirective($key) { return array_key_exists($key, $this->computedCacheControl); } public function getCacheControlDirective($key) { return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null; } public function setCookie(Cookie $cookie) { $this->cookies[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; } public function removeCookie($name, $path = '/', $domain = null) { if (null === $path) { $path = '/'; } unset($this->cookies[$domain][$path][$name]); if (empty($this->cookies[$domain][$path])) { unset($this->cookies[$domain][$path]); if (empty($this->cookies[$domain])) { unset($this->cookies[$domain]); } } } public function getCookies($format = self::COOKIES_FLAT) { if (!in_array($format, array(self::COOKIES_FLAT, self::COOKIES_ARRAY))) { throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', array(self::COOKIES_FLAT, self::COOKIES_ARRAY)))); } if (self::COOKIES_ARRAY === $format) { return $this->cookies; } $flattenedCookies = array(); foreach ($this->cookies as $path) { foreach ($path as $cookies) { foreach ($cookies as $cookie) { $flattenedCookies[] = $cookie; } } } return $flattenedCookies; } public function clearCookie($name, $path = '/', $domain = null) { $this->setCookie(new Cookie($name, null, 1, $path, $domain)); } public function makeDisposition($disposition, $filename, $filenameFallback = '') { if (!in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) { throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); } if (!$filenameFallback) { $filenameFallback = $filename; } if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); } if (false !== strpos($filenameFallback, '%')) { throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); } if (preg_match('#[/\\\\]#', $filename) || preg_match('#[/\\\\]#', $filenameFallback)) { throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); } $output = sprintf('%s; filename="%s"', $disposition, str_replace(array('\\', '"'), array('\\\\', '\\"'), $filenameFallback)); if ($filename != $filenameFallback) { $output .= sprintf("; filename*=utf-8''%s", str_replace(array("'", '(', ')', '*'), array('%27', '%28', '%29', '%2A'), urlencode($filename))); } return $output; } protected function computeCacheControlValue() { if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) { return 'no-cache'; } if (!$this->cacheControl) { return 'private, must-revalidate'; } $header = $this->getCacheControlHeader(); if (isset($this->cacheControl['public']) || isset($this->cacheControl['private'])) { return $header; } if (!isset($this->cacheControl['s-maxage'])) { return $header.', private'; } return $header; } } parameters as $key => $value) { if (0 === strpos($key, 'HTTP_')) { $headers[substr($key, 5)] = $value; } elseif (in_array($key, array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'))) { $headers[$key] = $value; } } if (isset($this->parameters['PHP_AUTH_USER'])) { $pass = isset($this->parameters['PHP_AUTH_PW']) ? $this->parameters['PHP_AUTH_PW'] : ''; $headers['AUTHORIZATION'] = 'Basic '.base64_encode($this->parameters['PHP_AUTH_USER'].':'.$pass); } return $headers; } } storageKey = $storageKey; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function initialize(array &$attributes) { $this->attributes = &$attributes; } public function getStorageKey() { return $this->storageKey; } public function has($name) { return array_key_exists($name, $this->attributes); } public function get($name, $default = null) { return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } public function set($name, $value) { $this->attributes[$name] = $value; } public function all() { return $this->attributes; } public function replace(array $attributes) { $this->attributes = array(); foreach ($attributes as $key => $value) { $this->set($key, $value); } } public function remove($name) { $retval = null; if (array_key_exists($name, $this->attributes)) { $retval = $this->attributes[$name]; unset($this->attributes[$name]); } return $retval; } public function clear() { $return = $this->attributes; $this->attributes = array(); return $return; } public function getIterator() { return new \ArrayIterator($this->attributes); } public function count() { return count($this->attributes); } } namespaceCharacter = $namespaceCharacter; parent::__construct($storageKey); } public function has($name) { $attributes = $this->resolveAttributePath($name); $name = $this->resolveKey($name); return array_key_exists($name, $attributes); } public function get($name, $default = null) { $attributes = $this->resolveAttributePath($name); $name = $this->resolveKey($name); return array_key_exists($name, $attributes) ? $attributes[$name] : $default; } public function set($name, $value) { $attributes = & $this->resolveAttributePath($name, true); $name = $this->resolveKey($name); $attributes[$name] = $value; } public function remove($name) { $retval = null; $attributes = & $this->resolveAttributePath($name); $name = $this->resolveKey($name); if (array_key_exists($name, $attributes)) { $retval = $attributes[$name]; unset($attributes[$name]); } return $retval; } protected function &resolveAttributePath($name, $writeContext = false) { $array = & $this->attributes; $name = (strpos($name, $this->namespaceCharacter) === 0) ? substr($name, 1) : $name; if (!$name) { return $array; } $parts = explode($this->namespaceCharacter, $name); if (count($parts) < 2) { if (!$writeContext) { return $array; } $array[$parts[0]] = array(); return $array; } unset($parts[count($parts)-1]); foreach ($parts as $part) { if (!array_key_exists($part, $array)) { if (!$writeContext) { return $array; } $array[$part] = array(); } $array = & $array[$part]; } return $array; } protected function resolveKey($name) { if (strpos($name, $this->namespaceCharacter) !== false) { $name = substr($name, strrpos($name, $this->namespaceCharacter)+1, strlen($name)); } return $name; } } storageKey = $storageKey; $this->flashes = array('display' => array(), 'new' => array()); } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function initialize(array &$flashes) { $this->flashes = &$flashes; $this->flashes['display'] = array_key_exists('new', $this->flashes) ? $this->flashes['new'] : array(); $this->flashes['new'] = array(); } public function add($type, $message) { $this->flashes['new'][$type][] = $message; } public function peek($type, array $default = array()) { return $this->has($type) ? $this->flashes['display'][$type] : $default; } public function peekAll() { return array_key_exists('display', $this->flashes) ? (array)$this->flashes['display'] : array(); } public function get($type, array $default = array()) { $return = $default; if (!$this->has($type)) { return $return; } if (isset($this->flashes['display'][$type])) { $return = $this->flashes['display'][$type]; unset($this->flashes['display'][$type]); } return $return; } public function all() { $return = $this->flashes['display']; $this->flashes = array('new' => array(), 'display' => array()); return $return; } public function setAll(array $messages) { $this->flashes['new'] = $messages; } public function set($type, $messages) { $this->flashes['new'][$type] = (array)$messages; } public function has($type) { return array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type]; } public function keys() { return array_keys($this->flashes['display']); } public function getStorageKey() { return $this->storageKey; } public function clear() { return $this->all(); } } storageKey = $storageKey; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function initialize(array &$flashes) { $this->flashes = &$flashes; } public function add($type, $message) { $this->flashes[$type][] = $message; } public function peek($type, array $default =array()) { return $this->has($type) ? $this->flashes[$type] : $default; } public function peekAll() { return $this->flashes; } public function get($type, array $default = array()) { if (!$this->has($type)) { return $default; } $return = $this->flashes[$type]; unset($this->flashes[$type]); return $return; } public function all() { $return = $this->peekAll(); $this->flashes = array(); return $return; } public function set($type, $messages) { $this->flashes[$type] = (array) $messages; } public function setAll(array $messages) { $this->flashes = $messages; } public function has($type) { return array_key_exists($type, $this->flashes) && $this->flashes[$type]; } public function keys() { return array_keys($this->flashes); } public function getStorageKey() { return $this->storageKey; } public function clear() { return $this->all(); } public function getIterator() { return new \ArrayIterator($this->all()); } public function count() { return count($this->flashes); } } storage = $storage ?: new NativeSessionStorage(); $attributes = $attributes ?: new AttributeBag(); $this->attributeName = $attributes->getName(); $this->registerBag($attributes); $flashes = $flashes ?: new FlashBag(); $this->flashName = $flashes->getName(); $this->registerBag($flashes); } public function start() { return $this->storage->start(); } public function has($name) { return $this->storage->getBag($this->attributeName)->has($name); } public function get($name, $default = null) { return $this->storage->getBag($this->attributeName)->get($name, $default); } public function set($name, $value) { $this->storage->getBag($this->attributeName)->set($name, $value); } public function all() { return $this->storage->getBag($this->attributeName)->all(); } public function replace(array $attributes) { $this->storage->getBag($this->attributeName)->replace($attributes); } public function remove($name) { return $this->storage->getBag($this->attributeName)->remove($name); } public function clear() { $this->storage->getBag($this->attributeName)->clear(); } public function getIterator() { return new \ArrayIterator($this->storage->getBag($this->attributeName)->all()); } public function count() { return count($this->storage->getBag($this->attributeName)->all()); } public function invalidate($lifetime = null) { $this->storage->clear(); return $this->migrate(true, $lifetime); } public function migrate($destroy = false, $lifetime = null) { return $this->storage->regenerate($destroy, $lifetime); } public function save() { $this->storage->save(); } public function getId() { return $this->storage->getId(); } public function setId($id) { $this->storage->setId($id); } public function getName() { return $this->storage->getName(); } public function setName($name) { $this->storage->setName($name); } public function getMetadataBag() { return $this->storage->getMetadataBag(); } public function registerBag(SessionBagInterface $bag) { $this->storage->registerBag($bag); } public function getBag($name) { return $this->storage->getBag($name); } public function getFlashBag() { return $this->getBag($this->flashName); } public function getFlashes() { $all = $this->getBag($this->flashName)->all(); $return = array(); if ($all) { foreach ($all as $name => $array) { if (is_numeric(key($array))) { $return[$name] = reset($array); } else { $return[$name] = $array; } } } return $return; } public function setFlashes($values) { foreach ($values as $name => $value) { $this->getBag($this->flashName)->set($name, $value); } } public function getFlash($name, $default = null) { $return = $this->getBag($this->flashName)->get($name); return empty($return) ? $default : reset($return); } public function setFlash($name, $value) { $this->getBag($this->flashName)->set($name, $value); } public function hasFlash($name) { return $this->getBag($this->flashName)->has($name); } public function removeFlash($name) { $this->getBag($this->flashName)->get($name); } public function clearFlashes() { return $this->getBag($this->flashName)->clear(); } } memcached = $memcached; if (!isset($memcachedOptions['serverpool'])) { $memcachedOptions['serverpool'][] = array( 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 1); } $memcachedOptions['expiretime'] = isset($memcachedOptions['expiretime']) ? (int)$memcachedOptions['expiretime'] : 86400; $this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, isset($memcachedOptions['prefix']) ? $memcachedOptions['prefix'] : 'sf2s'); $this->memcachedOptions = $memcachedOptions; } public function open($savePath, $sessionName) { return $this->memcached->addServers($this->memcachedOptions['serverpool']); } public function close() { return true; } public function read($sessionId) { return $this->memcached->get($sessionId) ?: ''; } public function write($sessionId, $data) { return $this->memcached->set($sessionId, $data, $this->memcachedOptions['expiretime']); } public function destroy($sessionId) { return $this->memcached->delete($sessionId); } public function gc($lifetime) { return true; } protected function addServer(array $server) { if (array_key_exists('host', $server)) { throw new \InvalidArgumentException('host key must be set'); } $server['port'] = isset($server['port']) ? (int)$server['port'] : 11211; $server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1; $server['presistent'] = isset($server['presistent']) ? (bool)$server['presistent'] : false; $server['weight'] = isset($server['weight']) ? (bool)$server['weight'] : 1; } } memcache = $memcache; if (!isset($memcacheOptions['serverpool'])) { $memcacheOptions['serverpool'] = array(array( 'host' => '127.0.0.1', 'port' => 11211, 'timeout' => 1, 'persistent' => false, 'weight' => 1, 'retry_interval' => 15, )); } $memcacheOptions['expiretime'] = isset($memcacheOptions['expiretime']) ? (int)$memcacheOptions['expiretime'] : 86400; $this->prefix = isset($memcacheOptions['prefix']) ? $memcacheOptions['prefix'] : 'sf2s'; $this->memcacheOptions = $memcacheOptions; } protected function addServer(array $server) { if (!array_key_exists('host', $server)) { throw new \InvalidArgumentException('host key must be set'); } $server['port'] = isset($server['port']) ? (int)$server['port'] : 11211; $server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1; $server['persistent'] = isset($server['persistent']) ? (bool)$server['persistent'] : false; $server['weight'] = isset($server['weight']) ? (int)$server['weight'] : 1; $server['retry_interval'] = isset($server['retry_interval']) ? (int)$server['retry_interval'] : 15; $this->memcache->addserver($server['host'], $server['port'], $server['persistent'],$server['weight'],$server['timeout'],$server['retry_interval']); } public function open($savePath, $sessionName) { foreach ($this->memcacheOptions['serverpool'] as $server) { $this->addServer($server); } return true; } public function close() { return $this->memcache->close(); } public function read($sessionId) { return $this->memcache->get($this->prefix.$sessionId) ?: ''; } public function write($sessionId, $data) { if (!$this->memcache->replace($this->prefix.$sessionId, $data, 0, $this->memcacheOptions['expiretime'])) { return $this->memcache->set($this->prefix.$sessionId, $data, 0, $this->memcacheOptions['expiretime']); } return true; } public function destroy($sessionId) { return $this->memcache->delete($this->prefix.$sessionId); } public function gc($lifetime) { return true; } } mongo = $mongo; $this->options = array_merge(array( 'id_field' => 'sess_id', 'data_field' => 'sess_data', 'time_field' => 'sess_time', ), $options); } public function open($savePath, $sessionName) { return true; } public function close() { return true; } public function destroy($sessionId) { $this->getCollection()->remove( array($this->options['id_field'] => $sessionId), array('justOne' => true) ); return true; } public function gc($lifetime) { $time = new \MongoTimestamp(time() - $lifetime); $this->getCollection()->remove(array( $this->options['time_field'] => array('$lt' => $time), )); } public function write($sessionId, $data) { $data = array( $this->options['id_field'] => $sessionId, $this->options['data_field'] => new \MongoBinData($data), $this->options['time_field'] => new \MongoTimestamp() ); $this->getCollection()->update( array($this->options['id_field'] => $sessionId), array('$set' => $data), array('upsert' => true) ); return true; } public function read($sessionId) { $dbData = $this->getCollection()->findOne(array( $this->options['id_field'] => $sessionId, )); return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin; } private function getCollection() { if (null === $this->collection) { $this->collection = $this->mongo->selectDB($this->options['database'])->selectCollection($this->options['collection']); } return $this->collection; } }setOptions($options); } protected function setOptions(array $options) { $validOptions = array_flip(array( 'memcached.sess_locking', 'memcached.sess_lock_wait', 'memcached.sess_prefix', 'memcached.compression_type', 'memcached.compression_factor', 'memcached.compression_threshold', 'memcached.serializer', )); foreach ($options as $key => $value) { if (isset($validOptions[$key])) { ini_set($key, $value); } } } } setOptions($options); } protected function setOptions(array $options) { $validOptions = array_flip(array( 'memcache.allow_failover', 'memcache.max_failover_attempts', 'memcache.chunk_size', 'memcache.default_port', 'memcache.hash_strategy', 'memcache.hash_function', 'memcache.protocol', 'memcache.redundancy', 'memcache.session_redundancy', 'memcache.compress_threshold', 'memcache.lock_timeout', )); foreach ($options as $key => $value) { if (isset($validOptions[$key])) { ini_set($key, $value); } } } } =')) { class NativeSessionHandler extends \SessionHandler {} } else { class NativeSessionHandler {} } setOptions($options); } protected function setOptions(array $options) { foreach ($options as $key => $value) { if (in_array($key, array('sqlite.assoc_case'))) { ini_set($key, $value); } } } } pdo = $pdo; $this->dbOptions = array_merge(array( 'db_id_col' => 'sess_id', 'db_data_col' => 'sess_data', 'db_time_col' => 'sess_time', ), $dbOptions); } public function open($path, $name) { return true; } public function close() { return true; } public function destroy($id) { $dbTable = $this->dbOptions['db_table']; $dbIdCol = $this->dbOptions['db_id_col']; $sql = "DELETE FROM $dbTable WHERE $dbIdCol = :id"; try { $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->execute(); } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e); } return true; } public function gc($lifetime) { $dbTable = $this->dbOptions['db_table']; $dbTimeCol = $this->dbOptions['db_time_col']; $sql = "DELETE FROM $dbTable WHERE $dbTimeCol < (:time - $lifetime)"; try { $stmt = $this->pdo->prepare($sql); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); $stmt->execute(); } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e); } return true; } public function read($id) { $dbTable = $this->dbOptions['db_table']; $dbDataCol = $this->dbOptions['db_data_col']; $dbIdCol = $this->dbOptions['db_id_col']; try { $sql = "SELECT $dbDataCol FROM $dbTable WHERE $dbIdCol = :id"; $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->execute(); $sessionRows = $stmt->fetchAll(\PDO::FETCH_NUM); if (count($sessionRows) == 1) { return base64_decode($sessionRows[0][0]); } $this->createNewSession($id); return ''; } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e); } } public function write($id, $data) { $dbTable = $this->dbOptions['db_table']; $dbDataCol = $this->dbOptions['db_data_col']; $dbIdCol = $this->dbOptions['db_id_col']; $dbTimeCol = $this->dbOptions['db_time_col']; $sql = ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME)) ? "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) " ."ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = CASE WHEN $dbTimeCol = :time THEN (VALUES($dbTimeCol) + 1) ELSE VALUES($dbTimeCol) END" : "UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id"; try { $encoded = base64_encode($data); $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); $stmt->execute(); if (!$stmt->rowCount()) { $this->createNewSession($id, $data); } } catch (\PDOException $e) { throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e); } return true; } private function createNewSession($id, $data = '') { $dbTable = $this->dbOptions['db_table']; $dbDataCol = $this->dbOptions['db_data_col']; $dbIdCol = $this->dbOptions['db_id_col']; $dbTimeCol = $this->dbOptions['db_time_col']; $sql = "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time)"; $encoded = base64_encode($data); $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $id, \PDO::PARAM_STR); $stmt->bindParam(':data', $encoded, \PDO::PARAM_STR); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); $stmt->execute(); return true; } } storageKey = $storageKey; $this->meta = array(self::CREATED => 0, self::UPDATED => 0, self::LIFETIME => 0); } public function initialize(array &$array) { $this->meta = &$array; if (isset($array[self::CREATED])) { $this->lastUsed = $this->meta[self::UPDATED]; $this->meta[self::UPDATED] = time(); } else { $this->stampCreated(); } } public function getLifetime() { return $this->meta[self::LIFETIME]; } public function stampNew($lifetime = null) { $this->stampCreated($lifetime); } public function getStorageKey() { return $this->storageKey; } public function getCreated() { return $this->meta[self::CREATED]; } public function getLastUsed() { return $this->lastUsed; } public function clear() { } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } private function stampCreated($lifetime = null) { $timeStamp = time(); $this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp; $this->meta[self::LIFETIME] = (null === $lifetime) ? ini_get('session.cookie_lifetime') : $lifetime; } } name = $name; $this->setMetadataBag($metaBag); } public function setSessionData(array $array) { $this->data = $array; } public function start() { if ($this->started && !$this->closed) { return true; } if (empty($this->id)) { $this->id = $this->generateId(); } $this->loadSession(); return true; } public function regenerate($destroy = false, $lifetime = null) { if (!$this->started) { $this->start(); } $this->metadataBag->stampNew($lifetime); $this->id = $this->generateId(); return true; } public function getId() { return $this->id; } public function setId($id) { if ($this->started) { throw new \LogicException('Cannot set session ID after the session has started.'); } $this->id = $id; } public function getName() { return $this->name; } public function setName($name) { $this->name = $name; } public function save() { $this->closed = false; } public function clear() { foreach ($this->bags as $bag) { $bag->clear(); } $this->data = array(); $this->loadSession(); } public function registerBag(SessionBagInterface $bag) { $this->bags[$bag->getName()] = $bag; } public function getBag($name) { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); } if (!$this->started) { $this->start(); } return $this->bags[$name]; } public function setMetadataBag(MetadataBag $bag = null) { if (null === $bag) { $bag = new MetadataBag(); } $this->metadataBag = $bag; } public function getMetadataBag() { return $this->metadataBag; } protected function generateId() { return sha1(uniqid(mt_rand())); } protected function loadSession() { $bags = array_merge($this->bags, array($this->metadataBag)); foreach ($bags as $bag) { $key = $bag->getStorageKey(); $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : array(); $bag->initialize($this->data[$key]); } $this->started = true; $this->closed = false; } } savePath = $savePath; parent::__construct($name); } public function start() { if ($this->started) { return true; } if (!$this->id) { $this->id = $this->generateId(); } $this->read(); $this->started = true; return true; } public function regenerate($destroy = false, $lifetime = null) { if (!$this->started) { $this->start(); } if ($destroy) { $this->destroy(); } return parent::regenerate($destroy, $lifetime); } public function save() { file_put_contents($this->getFilePath(), serialize($this->data)); } private function destroy() { if (is_file($this->getFilePath())) { unlink($this->getFilePath()); } } private function getFilePath() { return $this->savePath.'/'.$this->id.'.mocksess'; } private function read() { $filePath = $this->getFilePath(); $this->data = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array(); $this->loadSession(); } } =')) { session_register_shutdown(); } else { register_shutdown_function('session_write_close'); } $this->setMetadataBag($metaBag); $this->setOptions($options); $this->setSaveHandler($handler); } public function getSaveHandler() { return $this->saveHandler; } public function start() { if ($this->started && !$this->closed) { return true; } if (!$this->started && !$this->closed && $this->saveHandler->isActive() && $this->saveHandler->isSessionHandlerInterface()) { $this->loadSession(); return true; } if (ini_get('session.use_cookies') && headers_sent()) { throw new \RuntimeException('Failed to start the session because headers have already been sent.'); } if (!session_start()) { throw new \RuntimeException('Failed to start the session'); } $this->loadSession(); if (!$this->saveHandler->isWrapper() && !$this->saveHandler->isSessionHandlerInterface()) { $this->saveHandler->setActive(false); } return true; } public function getId() { if (!$this->started) { return ''; } return $this->saveHandler->getId(); } public function setId($id) { return $this->saveHandler->setId($id); } public function getName() { return $this->saveHandler->getName(); } public function setName($name) { $this->saveHandler->setName($name); } public function regenerate($destroy = false, $lifetime = null) { if (null !== $lifetime) { ini_set('session.cookie_lifetime', $lifetime); } if ($destroy) { $this->metadataBag->stampNew(); } return session_regenerate_id($destroy); } public function save() { session_write_close(); if (!$this->saveHandler->isWrapper() && !$this->getSaveHandler()->isSessionHandlerInterface()) { $this->saveHandler->setActive(false); } $this->closed = true; } public function clear() { foreach ($this->bags as $bag) { $bag->clear(); } $_SESSION = array(); $this->loadSession(); } public function registerBag(SessionBagInterface $bag) { $this->bags[$bag->getName()] = $bag; } public function getBag($name) { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); } if (ini_get('session.auto_start') && !$this->started) { $this->start(); } elseif ($this->saveHandler->isActive() && !$this->started) { $this->loadSession(); } return $this->bags[$name]; } public function setMetadataBag(MetadataBag $metaBag = null) { if (null === $metaBag) { $metaBag = new MetadataBag(); } $this->metadataBag = $metaBag; } public function getMetadataBag() { return $this->metadataBag; } public function setOptions(array $options) { $validOptions = array_flip(array( 'auto_start', 'cache_limiter', 'cookie_domain', 'cookie_httponly', 'cookie_lifetime', 'cookie_path', 'cookie_secure', 'entropy_file', 'entropy_length', 'gc_divisor', 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', 'hash_function', 'name', 'referer_check', 'serialize_handler', 'use_cookies', 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', 'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags', )); foreach ($options as $key => $value) { if (isset($validOptions[$key])) { ini_set('session.'.$key, $value); } } } public function setSaveHandler($saveHandler = null) { if (!$saveHandler instanceof AbstractProxy && $saveHandler instanceof \SessionHandlerInterface) { $saveHandler = new SessionHandlerProxy($saveHandler); } elseif (!$saveHandler instanceof AbstractProxy) { $saveHandler = new NativeProxy($saveHandler); } $this->saveHandler = $saveHandler; if ($this->saveHandler instanceof \SessionHandlerInterface) { if (version_compare(phpversion(), '5.4.0', '>=')) { session_set_save_handler($this->saveHandler, false); } else { session_set_save_handler( array($this->saveHandler, 'open'), array($this->saveHandler, 'close'), array($this->saveHandler, 'read'), array($this->saveHandler, 'write'), array($this->saveHandler, 'destroy'), array($this->saveHandler, 'gc') ); } } } protected function loadSession(array &$session = null) { if (null === $session) { $session = &$_SESSION; } $bags = array_merge($this->bags, array($this->metadataBag)); foreach ($bags as $bag) { $key = $bag->getStorageKey(); $session[$key] = isset($session[$key]) ? $session[$key] : array(); $bag->initialize($session[$key]); } $this->started = true; $this->closed = false; } } saveHandlerName; } public function isSessionHandlerInterface() { return ($this instanceof \SessionHandlerInterface); } public function isWrapper() { return $this->wrapper; } public function isActive() { return $this->active; } public function setActive($flag) { $this->active = (bool) $flag; } public function getId() { return session_id(); } public function setId($id) { if ($this->isActive()) { throw new \LogicException('Cannot change the ID of an active session'); } session_id($id); } public function getName() { return session_name(); } public function setName($name) { if ($this->isActive()) { throw new \LogicException('Cannot change the name of an active session'); } session_name($name); } } saveHandlerName = ini_get('session.save_handler'); } public function isWrapper() { return false; } } handler = $handler; $this->wrapper = ($handler instanceof \SessionHandler); $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; } public function open($savePath, $sessionName) { $return = (bool)$this->handler->open($savePath, $sessionName); if (true === $return) { $this->active = true; } return $return; } public function close() { $this->active = false; return (bool) $this->handler->close(); } public function read($id) { return (string) $this->handler->read($id); } public function write($id, $data) { return (bool) $this->handler->write($id, $data); } public function destroy($id) { return (bool) $this->handler->destroy($id); } public function gc($maxlifetime) { return (bool) $this->handler->gc($maxlifetime); } } setCallback($callback); } $this->streamed = false; } public static function create($callback = null, $status = 200, $headers = array()) { return new static($callback, $status, $headers); } public function setCallback($callback) { if (!is_callable($callback)) { throw new \LogicException('The Response callback must be a valid PHP callable.'); } $this->callback = $callback; } public function prepare(Request $request) { if ('1.0' != $request->server->get('SERVER_PROTOCOL')) { $this->setProtocolVersion('1.1'); } $this->headers->set('Cache-Control', 'no-cache'); return parent::prepare($request); } public function sendContent() { if ($this->streamed) { return; } $this->streamed = true; if (null === $this->callback) { throw new \LogicException('The Response callback must not be null.'); } call_user_func($this->callback); } public function setContent($content) { if (null !== $content) { throw new \LogicException('The content cannot be set on a StreamedResponse instance.'); } } public function getContent() { return false; } } extension) { $basename = preg_replace('/Bundle$/', '', $this->getName()); $class = $this->getNamespace().'\\DependencyInjection\\'.$basename.'Extension'; if (class_exists($class)) { $extension = new $class(); $expectedAlias = Container::underscore($basename); if ($expectedAlias != $extension->getAlias()) { throw new \LogicException(sprintf( 'The extension alias for the default extension of a '. 'bundle must be the underscored version of the '. 'bundle name ("%s" instead of "%s")', $expectedAlias, $extension->getAlias() )); } $this->extension = $extension; } else { $this->extension = false; } } if ($this->extension) { return $this->extension; } } public function getNamespace() { if (null === $this->reflected) { $this->reflected = new \ReflectionObject($this); } return $this->reflected->getNamespaceName(); } public function getPath() { if (null === $this->reflected) { $this->reflected = new \ReflectionObject($this); } return dirname($this->reflected->getFileName()); } public function getParent() { return null; } final public function getName() { if (null !== $this->name) { return $this->name; } $name = get_class($this); $pos = strrpos($name, '\\'); return $this->name = false === $pos ? $name : substr($name, $pos + 1); } public function registerCommands(Application $application) { if (!$dir = realpath($this->getPath().'/Command')) { return; } $finder = new Finder(); $finder->files()->name('*Command.php')->in($dir); $prefix = $this->getNamespace().'\\Command'; foreach ($finder as $file) { $ns = $prefix; if ($relativePath = $file->getRelativePath()) { $ns .= '\\'.strtr($relativePath, '/', '\\'); } $r = new \ReflectionClass($ns.'\\'.$file->getBasename('.php')); if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) { $application->add($r->newInstance()); } } } } clearers = $clearers; } public function clear($cacheDir) { foreach ($this->clearers as $clearer) { $clearer->clear($cacheDir); } } public function add(CacheClearerInterface $clearer) { $this->clearers[] = $clearer; } } setWarmers($warmers); $this->optionalsEnabled = false; } public function enableOptionalWarmers() { $this->optionalsEnabled = true; } public function warmUp($cacheDir) { foreach ($this->warmers as $warmer) { if (!$this->optionalsEnabled && $warmer->isOptional()) { continue; } $warmer->warmUp($cacheDir); } } public function isOptional() { return false; } public function setWarmers(array $warmers) { $this->warmers = array(); foreach ($warmers as $warmer) { $this->add($warmer); } } public function add(CacheWarmerInterface $warmer) { $this->warmers[] = $warmer; } } kernel = $kernel; parent::__construct($server, $history, $cookieJar); $this->followRedirects = false; } protected function doRequest($request) { $response = $this->kernel->handle($request); if ($this->kernel instanceof TerminableInterface) { $this->kernel->terminate($request, $response); } return $response; } protected function getScript($request) { $kernel = str_replace("'", "\\'", serialize($this->kernel)); $request = str_replace("'", "\\'", serialize($request)); $r = new \ReflectionClass('\\Symfony\\Component\\ClassLoader\\UniversalClassLoader'); $requirePath = str_replace("'", "\\'", $r->getFileName()); $symfonyPath = str_replace("'", "\\'", realpath(__DIR__.'/../../..')); return <<registerNamespaces(array('Symfony' => '$symfonyPath')); \$loader->register(); \$kernel = unserialize('$kernel'); echo serialize(\$kernel->handle(unserialize('$request'))); EOF; } protected function filterRequest(DomRequest $request) { $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent()); $httpRequest->files->replace($this->filterFiles($httpRequest->files->all())); return $httpRequest; } protected function filterFiles(array $files) { $filtered = array(); foreach ($files as $key => $value) { if (is_array($value)) { $filtered[$key] = $this->filterFiles($value); } elseif ($value instanceof UploadedFile) { if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) { $filtered[$key] = new UploadedFile( '', $value->getClientOriginalName(), $value->getClientMimeType(), 0, UPLOAD_ERR_INI_SIZE, true ); } else { $filtered[$key] = new UploadedFile( $value->getPathname(), $value->getClientOriginalName(), $value->getClientMimeType(), $value->getClientSize(), $value->getError(), true ); } } else { $filtered[$key] = $value; } } return $filtered; } protected function filterResponse($response) { $headers = $response->headers->all(); if ($response->headers->getCookies()) { $cookies = array(); foreach ($response->headers->getCookies() as $cookie) { $cookies[] = new DomCookie($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); } $headers['Set-Cookie'] = $cookies; } return new DomResponse($response->getContent(), $response->getStatusCode(), $headers); } } kernel = $kernel; $this->path = $path; $paths[] = $path; parent::__construct($paths); } public function locate($file, $currentPath = null, $first = true) { if ('@' === $file[0]) { return $this->kernel->locateResource($file, $this->path, $first); } return parent::locate($file, $currentPath, $first); } } logger = $logger; } public function getController(Request $request) { if (!$controller = $request->attributes->get('_controller')) { if (null !== $this->logger) { $this->logger->warn('Unable to look for the controller as the "_controller" parameter is missing'); } return false; } if (is_array($controller) || (is_object($controller) && method_exists($controller, '__invoke'))) { return $controller; } if (false === strpos($controller, ':')) { if (method_exists($controller, '__invoke')) { return new $controller; } elseif (function_exists($controller)) { return $controller; } } list($controller, $method) = $this->createController($controller); if (!method_exists($controller, $method)) { throw new \InvalidArgumentException(sprintf('Method "%s::%s" does not exist.', get_class($controller), $method)); } return array($controller, $method); } public function getArguments(Request $request, $controller) { if (is_array($controller)) { $r = new \ReflectionMethod($controller[0], $controller[1]); } elseif (is_object($controller) && !$controller instanceof \Closure) { $r = new \ReflectionObject($controller); $r = $r->getMethod('__invoke'); } else { $r = new \ReflectionFunction($controller); } return $this->doGetArguments($request, $controller, $r->getParameters()); } protected function doGetArguments(Request $request, $controller, array $parameters) { $attributes = $request->attributes->all(); $arguments = array(); foreach ($parameters as $param) { if (array_key_exists($param->getName(), $attributes)) { $arguments[] = $attributes[$param->getName()]; } elseif ($param->getClass() && $param->getClass()->isInstance($request)) { $arguments[] = $request; } elseif ($param->isDefaultValueAvailable()) { $arguments[] = $param->getDefaultValue(); } else { if (is_array($controller)) { $repr = sprintf('%s::%s()', get_class($controller[0]), $controller[1]); } elseif (is_object($controller)) { $repr = get_class($controller); } else { $repr = $controller; } throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->getName())); } } return $arguments; } protected function createController($controller) { if (false === strpos($controller, '::')) { throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller)); } list($class, $method) = explode('::', $controller, 2); if (!class_exists($class)) { throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); } return array(new $class(), $method); } } kernel = $kernel; } public function collect(Request $request, Response $response, \Exception $exception = null) { $this->data = array( 'token' => $response->headers->get('X-Debug-Token'), 'symfony_version' => Kernel::VERSION, 'name' => $this->kernel->getName(), 'env' => $this->kernel->getEnvironment(), 'debug' => $this->kernel->isDebug(), 'php_version' => PHP_VERSION, 'xdebug_enabled' => extension_loaded('xdebug'), 'eaccel_enabled' => extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'), 'apc_enabled' => extension_loaded('apc') && ini_get('apc.enabled'), 'xcache_enabled' => extension_loaded('xcache') && ini_get('xcache.cacher'), 'bundles' => array(), ); foreach ($this->kernel->getBundles() as $name => $bundle) { $this->data['bundles'][$name] = $bundle->getPath(); } } public function getToken() { return $this->data['token']; } public function getSymfonyVersion() { return $this->data['symfony_version']; } public function getPhpVersion() { return $this->data['php_version']; } public function getAppName() { return $this->data['name']; } public function getEnv() { return $this->data['env']; } public function isDebug() { return $this->data['debug']; } public function hasXDebug() { return $this->data['xdebug_enabled']; } public function hasEAccelerator() { return $this->data['eaccel_enabled']; } public function hasApc() { return $this->data['apc_enabled']; } public function hasXCache() { return $this->data['xcache_enabled']; } public function hasAccelerator() { return $this->hasApc() || $this->hasEAccelerator() || $this->hasXCache(); } public function getBundles() { return $this->data['bundles']; } public function getName() { return 'config'; } } data); } public function unserialize($data) { $this->data = unserialize($data); } } dispatcher = $dispatcher; } } public function collect(Request $request, Response $response, \Exception $exception = null) { $this->data = array( 'called_listeners' => null !== $this->dispatcher ? $this->dispatcher->getCalledListeners() : array(), 'not_called_listeners' => null !== $this->dispatcher ? $this->dispatcher->getNotCalledListeners() : array(), ); } public function getCalledListeners() { return $this->data['called_listeners']; } public function getNotCalledListeners() { return $this->data['not_called_listeners']; } public function getName() { return 'events'; } } setStatusCode($exception->getStatusCode()); } $this->data = array( 'exception' => $flattenException, ); } } public function hasException() { return isset($this->data['exception']); } public function getException() { return $this->data['exception']; } public function getMessage() { return $this->data['exception']->getMessage(); } public function getCode() { return $this->data['exception']->getCode(); } public function getStatusCode() { return $this->data['exception']->getStatusCode(); } public function getTrace() { return $this->data['exception']->getTrace(); } public function getName() { return 'exception'; } } logger = $logger; } } public function collect(Request $request, Response $response, \Exception $exception = null) { if (null !== $this->logger) { $this->data = array( 'error_count' => $this->logger->countErrors(), 'logs' => $this->sanitizeLogs($this->logger->getLogs()), ); } } public function countErrors() { return isset($this->data['error_count']) ? $this->data['error_count'] : 0; } public function getLogs() { return isset($this->data['logs']) ? $this->data['logs'] : array(); } public function getName() { return 'logger'; } private function sanitizeLogs($logs) { foreach ($logs as $i => $log) { $logs[$i]['context'] = $this->sanitizeContext($log['context']); } return $logs; } private function sanitizeContext($context) { if (is_array($context)) { foreach ($context as $key => $value) { $context[$key] = $this->sanitizeContext($value); } return $context; } if (is_resource($context)) { return sprintf('Resource(%s)', get_resource_type($context)); } if (is_object($context)) { return sprintf('Object(%s)', get_class($context)); } return $context; } } data = array( 'memory' => memory_get_peak_usage(true), ); } public function getMemory() { return $this->data['memory']; } public function getName() { return 'memory'; } } headers->all(); $cookies = array(); foreach ($response->headers->getCookies() as $cookie) { $cookies[] = $this->getCookieHeader($cookie->getName(), $cookie->getValue(), $cookie->getExpiresTime(), $cookie->getPath(), $cookie->getDomain(), $cookie->isSecure(), $cookie->isHttpOnly()); } if (count($cookies) > 0) { $responseHeaders['Set-Cookie'] = $cookies; } $attributes = array(); foreach ($request->attributes->all() as $key => $value) { if (is_object($value)) { $attributes[$key] = sprintf('Object(%s)', get_class($value)); if (is_callable(array($value, '__toString'))) { $attributes[$key] .= sprintf(' = %s', (string) $value); } } else { $attributes[$key] = $value; } } $content = null; try { $content = $request->getContent(); } catch (\LogicException $e) { $content = false; } $this->data = array( 'format' => $request->getRequestFormat(), 'content' => $content, 'content_type' => $response->headers->get('Content-Type') ? $response->headers->get('Content-Type') : 'text/html', 'status_code' => $response->getStatusCode(), 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), 'request_headers' => $request->headers->all(), 'request_server' => $request->server->all(), 'request_cookies' => $request->cookies->all(), 'request_attributes' => $attributes, 'response_headers' => $responseHeaders, 'session_attributes' => $request->hasSession() ? $request->getSession()->all() : array(), 'flashes' => $request->hasSession() ? $request->getSession()->getFlashBag()->peekAll() : array(), 'path_info' => $request->getPathInfo(), ); } public function getPathInfo() { return $this->data['path_info']; } public function getRequestRequest() { return new ParameterBag($this->data['request_request']); } public function getRequestQuery() { return new ParameterBag($this->data['request_query']); } public function getRequestHeaders() { return new HeaderBag($this->data['request_headers']); } public function getRequestServer() { return new ParameterBag($this->data['request_server']); } public function getRequestCookies() { return new ParameterBag($this->data['request_cookies']); } public function getRequestAttributes() { return new ParameterBag($this->data['request_attributes']); } public function getResponseHeaders() { return new ResponseHeaderBag($this->data['response_headers']); } public function getSessionAttributes() { return $this->data['session_attributes']; } public function getFlashes() { return $this->data['flashes']; } public function getContent() { return $this->data['content']; } public function getContentType() { return $this->data['content_type']; } public function getStatusCode() { return $this->data['status_code']; } public function getFormat() { return $this->data['format']; } public function getName() { return 'request'; } private function getCookieHeader($name, $value, $expires, $path, $domain, $secure, $httponly) { $cookie = sprintf('%s=%s', $name, urlencode($value)); if (0 !== $expires) { if (is_numeric($expires)) { $expires = (int) $expires; } elseif ($expires instanceof \DateTime) { $expires = $expires->getTimestamp(); } else { $expires = strtotime($expires); if (false === $expires || -1 == $expires) { throw new \InvalidArgumentException(sprintf('The "expires" cookie parameter is not valid.', $expires)); } } $cookie .= '; expires='.substr(\DateTime::createFromFormat('U', $expires, new \DateTimeZone('UTC'))->format('D, d-M-Y H:i:s T'), 0, -5); } if ($domain) { $cookie .= '; domain='.$domain; } $cookie .= '; path='.$path; if ($secure) { $cookie .= '; secure'; } if ($httponly) { $cookie .= '; httponly'; } return $cookie; } } kernel = $kernel; } public function collect(Request $request, Response $response, \Exception $exception = null) { $this->data = array( 'start_time' => (null !== $this->kernel ? $this->kernel->getStartTime() : $_SERVER['REQUEST_TIME']) * 1000, 'events' => array(), ); } public function setEvents(array $events) { foreach ($events as $event) { $event->ensureStopped(); } $this->data['events'] = $events; } public function getEvents() { return $this->data['events']; } public function getTotalTime() { $lastEvent = $this->data['events']['__section__']; return $lastEvent->getOrigin() + $lastEvent->getTotalTime() - $this->data['start_time']; } public function getInitTime() { return $this->data['events']['__section__']->getOrigin() - $this->getStartTime(); } public function getStartTime() { return $this->data['start_time']; } public function getName() { return 'time'; } } stopwatch = $stopwatch; $this->logger = $logger; $this->called = array(); } public function dispatch($eventName, Event $event = null) { switch ($eventName) { case 'kernel.request': $this->stopwatch->openSection(); break; case 'kernel.view': case 'kernel.response': try { $this->stopwatch->stop('controller'); } catch (\LogicException $e) { } break; case 'kernel.terminate': $token = $event->getResponse()->headers->get('X-Debug-Token'); $this->stopwatch->openSection($token); break; } $e1 = $this->stopwatch->start($eventName, 'section'); parent::dispatch($eventName, $event); $e1->stop(); switch ($eventName) { case 'kernel.controller': $this->stopwatch->start('controller', 'section'); break; case 'kernel.response': $token = $event->getResponse()->headers->get('X-Debug-Token'); $this->stopwatch->stopSection($token); if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { $this->updateProfiles($token, true); } break; case 'kernel.terminate': $this->stopwatch->stopSection($token); $this->updateProfiles($token, false); break; } return $event; } public function addListener($eventName, $listener, $priority = 0) { if (!is_callable($listener)) { throw new \RuntimeException(sprintf('The given callback (%s) for event "%s" is not callable.', $this->getListenerAsString($listener), $eventName)); } $this->priorities[$eventName.'_'.$this->getListenerAsString($listener)] = $priority; parent::addListener($eventName, $listener, $priority); } protected function doDispatch($listeners, $eventName, Event $event) { foreach ($listeners as $listener) { $info = $this->getListenerInfo($listener, $eventName); if (null !== $this->logger) { $this->logger->debug(sprintf('Notified event "%s" to listener "%s".', $eventName, $info['pretty'])); } $this->called[$eventName.'.'.$info['pretty']] = $info; $e2 = $this->stopwatch->start(isset($info['class']) ? substr($info['class'], strrpos($info['class'], '\\') + 1) : $info['type'], 'event_listener'); call_user_func($listener, $event); $e2->stop(); if ($event->isPropagationStopped()) { if (null !== $this->logger) { $this->logger->debug(sprintf('Listener "%s" stopped propagation of the event "%s".', $info['pretty'], $eventName)); $skippedListeners = $this->getListeners($eventName); $skipped = false; foreach ($skippedListeners as $skippedListener) { if ($skipped) { $info = $this->getListenerInfo($skippedListener, $eventName); $this->logger->debug(sprintf('Listener "%s" was not called for event "%s".', $info['pretty'], $eventName)); } if ($skippedListener === $listener) { $skipped = true; } } } break; } } } protected function lazyLoad($eventName) { $e = $this->stopwatch->start($eventName.'.loading', 'event_listener_loading'); parent::lazyLoad($eventName); $e->stop(); } public function getCalledListeners() { return $this->called; } public function getNotCalledListeners() { $notCalled = array(); foreach ($this->getListeners() as $name => $listeners) { foreach ($listeners as $listener) { $info = $this->getListenerInfo($listener, $name); if (!isset($this->called[$name.'.'.$info['pretty']])) { $notCalled[$name.'.'.$info['pretty']] = $info; } } } return $notCalled; } private function getListenerInfo($listener, $eventName) { $info = array( 'event' => $eventName, 'priority' => $this->priorities[$eventName.'_'.$this->getListenerAsString($listener)], ); if ($listener instanceof \Closure) { $info += array( 'type' => 'Closure', 'pretty' => 'closure' ); } elseif (is_string($listener)) { try { $r = new \ReflectionFunction($listener); $file = $r->getFileName(); $line = $r->getStartLine(); } catch (\ReflectionException $e) { $file = null; $line = null; } $info += array( 'type' => 'Function', 'function' => $listener, 'file' => $file, 'line' => $line, 'pretty' => $listener, ); } elseif (is_array($listener) || (is_object($listener) && is_callable($listener))) { if (!is_array($listener)) { $listener = array($listener, '__invoke'); } $class = is_object($listener[0]) ? get_class($listener[0]) : $listener[0]; try { $r = new \ReflectionMethod($class, $listener[1]); $file = $r->getFileName(); $line = $r->getStartLine(); } catch (\ReflectionException $e) { $file = null; $line = null; } $info += array( 'type' => 'Method', 'class' => $class, 'method' => $listener[1], 'file' => $file, 'line' => $line, 'pretty' => $class.'::'.$listener[1], ); } return $info; } private function updateProfiles($token, $updateChildren) { if (!$this->getContainer()->has('profiler')) { return; } $this->profiler = $this->getContainer()->get('profiler'); if (!$profile = $this->profiler->loadProfile($token)) { return; } $this->saveStopwatchInfoInProfile($profile, $updateChildren); } private function saveStopwatchInfoInProfile(Profile $profile, $updateChildren) { $profile->getCollector('time')->setEvents($this->stopwatch->getSectionEvents($profile->getToken())); $this->profiler->saveProfile($profile); if ($updateChildren) { foreach ($profile->getChildren() as $child) { $this->saveStopwatchInfoInProfile($child, true); } } } private function getListenerAsString($listener) { if (is_string($listener)) { return '[string] '.$listener; } elseif (is_array($listener)) { return '[array] '.(is_object($listener[0]) ? get_class($listener[0]) : $listener[0]).'::'.$listener[1]; } elseif (is_object($listener)) { return '[object] '.get_class($listener); } return '[?] '.var_export($listener, true); } } 'Warning', E_NOTICE => 'Notice', E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', E_STRICT => 'Runtime Notice', E_RECOVERABLE_ERROR => 'Catchable Fatal Error', E_DEPRECATED => 'Deprecated', E_USER_DEPRECATED => 'User Deprecated', ); private $level; static public function register($level = null) { $handler = new static(); $handler->setLevel($level); set_error_handler(array($handler, 'handle')); return $handler; } public function setLevel($level) { $this->level = null === $level ? error_reporting() : $level; } public function handle($level, $message, $file, $line, $context) { if (0 === $this->level) { return false; } if (error_reporting() & $level && $this->level & $level) { throw new \ErrorException(sprintf('%s: %s in %s line %d', isset($this->levels[$level]) ? $this->levels[$level] : $level, $message, $file, $line)); } return false; } } debug = $debug; $this->charset = $charset; } static public function register($debug = true) { $handler = new static($debug); set_exception_handler(array($handler, 'handle')); return $handler; } public function handle(\Exception $exception) { $this->createResponse($exception)->send(); } public function createResponse($exception) { $content = ''; $title = ''; try { if (!$exception instanceof FlattenException) { $exception = FlattenException::create($exception); } switch ($exception->getStatusCode()) { case 404: $title = 'Sorry, the page you are looking for could not be found.'; break; default: $title = 'Whoops, looks like something went wrong.'; } if ($this->debug) { $content = $this->getContent($exception); } } catch (\Exception $e) { if ($this->debug) { $title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($exception), $exception->getMessage()); } else { $title = 'Whoops, looks like something went wrong.'; } } return new Response($this->decorate($content, $title), $exception->getStatusCode()); } private function getContent($exception) { $message = nl2br($exception->getMessage()); $class = $this->abbrClass($exception->getClass()); $count = count($exception->getAllPrevious()); $content = ''; foreach ($exception->toArray() as $position => $e) { $ind = $count - $position + 1; $total = $count + 1; $class = $this->abbrClass($e['class']); $message = nl2br($e['message']); $content .= sprintf(<<

%d/%d %s: %s

    EOF , $ind, $total, $class, $message); foreach ($e['trace'] as $i => $trace) { $content .= '
  1. '; if ($trace['function']) { $content .= sprintf('at %s%s%s(%s)', $this->abbrClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); } if (isset($trace['file']) && isset($trace['line'])) { if ($linkFormat = ini_get('xdebug.file_link_format')) { $link = str_replace(array('%f', '%l'), array($trace['file'], $trace['line']), $linkFormat); $content .= sprintf(' in %s line %s', $link, $trace['file'], $trace['line']); } else { $content .= sprintf(' in %s line %s', $trace['file'], $trace['line']); } } $content .= "
  2. \n"; } $content .= "
\n
\n"; } return $content; } private function decorate($content, $title) { return << {$title}

$title

$content
EOF; } private function abbrClass($class) { $parts = explode('\\', $class); return sprintf("%s", $class, array_pop($parts)); } public function formatArgs(array $args) { $result = array(); foreach ($args as $key => $item) { if ('object' === $item[0]) { $formattedValue = sprintf("object(%s)", $this->abbrClass($item[1])); } elseif ('array' === $item[0]) { $formattedValue = sprintf("array(%s)", is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); } elseif ('string' === $item[0]) { $formattedValue = sprintf("'%s'", htmlspecialchars($item[1], ENT_QUOTES | ENT_SUBSTITUTE, $this->charset)); } elseif ('null' === $item[0]) { $formattedValue = 'null'; } elseif ('boolean' === $item[0]) { $formattedValue = ''.strtolower(var_export($item[1], true)).''; } elseif ('resource' === $item[0]) { $formattedValue = 'resource'; } else { $formattedValue = str_replace("\n", '', var_export(htmlspecialchars((string) $item[1], ENT_QUOTES | ENT_SUBSTITUTE, $this->charset), true)); } $result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue); } return implode(', ', $result); } } sections = $this->activeSections = array('__root__' => new Section('__root__')); } public function openSection($id = null) { $current = end($this->activeSections); if (null !== $id && null === $current->get($id)) { throw new \LogicException(sprintf('The section "%s" has been started at an other level and can not be opened.', $id)); } $this->start('__section__.child', 'section'); $this->activeSections[] = $current->open($id); $this->start('__section__'); } public function stopSection($id) { $this->stop('__section__'); if (1 == count($this->activeSections)) { throw new \LogicException('There is no started section to stop.'); } $this->sections[$id] = array_pop($this->activeSections)->setId($id); $this->stop('__section__.child'); } public function start($name, $category = null) { return end($this->activeSections)->startEvent($name, $category); } public function stop($name) { return end($this->activeSections)->stopEvent($name); } public function lap($name) { return end($this->activeSections)->stopEvent($name)->start(); } public function getSectionEvents($id) { return isset($this->sections[$id]) ? $this->sections[$id]->getEvents() : array(); } } class Section { private $events = array(); private $origin; private $id; private $children = array(); public function __construct($origin = null) { $this->origin = is_numeric($origin) ? $origin : null; } public function get($id) { foreach ($this->children as $child) { if ($id === $child->getId()) { return $child; } } return null; } public function open($id) { if (null === $session = $this->get($id)) { $session = $this->children[] = new self(microtime(true) * 1000); } return $session; } public function getId() { return $this->id; } public function setId($id) { $this->id = $id; return $this; } public function startEvent($name, $category) { if (!isset($this->events[$name])) { $this->events[$name] = new StopwatchEvent($this->origin ?: microtime(true) * 1000, $category); } return $this->events[$name]->start(); } public function stopEvent($name) { if (!isset($this->events[$name])) { throw new \LogicException(sprintf('Event "%s" is not started.', $name)); } return $this->events[$name]->stop(); } public function lap($name) { return $this->stop($name)->start(); } public function getEvents() { return $this->events; } } origin = $this->formatTime($origin); $this->category = is_string($category) ? $category : 'default'; $this->started = array(); $this->periods = array(); } public function getCategory() { return $this->category; } public function getOrigin() { return $this->origin; } public function start() { $this->started[] = $this->getNow(); return $this; } public function stop() { if (!count($this->started)) { throw new \LogicException('stop() called but start() has not been called before.'); } $this->periods[] = array(array_pop($this->started), $this->getNow()); return $this; } public function lap() { return $this->stop()->start(); } public function ensureStopped() { while (count($this->started)) { $this->stop(); } } public function getPeriods() { return $this->periods; } public function getStartTime() { return isset($this->periods[0]) ? $this->periods[0][0] : 0; } public function getEndTime() { return ($count = count($this->periods)) ? $this->periods[$count - 1][1] : 0; } public function getTotalTime() { $total = 0; foreach ($this->periods as $period) { $total += $period[1] - $period[0]; } return $this->formatTime($total); } protected function getNow() { return $this->formatTime(microtime(true) * 1000 - $this->origin); } private function formatTime($time) { if (!is_numeric($time)) { throw new \InvalidArgumentException('The time must be a numerical value'); } return round($time, 1); } } kernel = $kernel; } public function process(ContainerBuilder $container) { $classes = array(); foreach ($container->getExtensions() as $extension) { if ($extension instanceof Extension) { $classes = array_merge($classes, $extension->getClassesToCompile()); } } $this->kernel->setClassCache(array_unique($container->getParameterBag()->resolveValue($classes))); } } loadInternal($this->processConfiguration($this->getConfiguration(array(), $container), $configs), $container); } abstract protected function loadInternal(array $mergedConfig, ContainerBuilder $container); } classes; } public function addClassesToCompile(array $classes) { $this->classes = array_merge($this->classes, $classes); } public function getXsdValidationBasePath() { return false; } public function getNamespace() { return 'http://example.org/schema/dic/'.$this->getAlias(); } public function getAlias() { $className = get_class($this); if (substr($className, -9) != 'Extension') { throw new \BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.'); } $classBaseName = substr(strrchr($className, '\\'), 1, -9); return Container::underscore($classBaseName); } protected final function processConfiguration(ConfigurationInterface $configuration, array $configs) { $processor = new Processor(); return $processor->processConfiguration($configuration, $configs); } public function getConfiguration(array $config, ContainerBuilder $container) { $reflected = new \ReflectionClass($this); $namespace = $reflected->getNamespaceName(); $class = $namespace . '\\Configuration'; if (class_exists($class)) { if (!method_exists($class, '__construct')) { $configuration = new $class(); return $configuration; } } return null; } } extensions = $extensions; } public function process(ContainerBuilder $container) { foreach ($this->extensions as $extension) { if (!count($container->getExtensionConfig($extension))) { $container->loadFromExtension($extension, array()); } } parent::process($container); } } setController($controller); } public function getController() { return $this->controller; } public function setController($controller) { if (!is_callable($controller)) { throw new \LogicException(sprintf('The controller must be a callable (%s given).', $this->varToString($controller))); } $this->controller = $controller; } private function varToString($var) { if (is_object($var)) { return sprintf('Object(%s)', get_class($var)); } if (is_array($var)) { $a = array(); foreach ($var as $k => $v) { $a[] = sprintf('%s => %s', $k, $this->varToString($v)); } return sprintf("Array(%s)", implode(', ', $a)); } if (is_resource($var)) { return sprintf('Resource(%s)', get_resource_type($var)); } if (null === $var) { return 'null'; } if (false === $var) { return 'false'; } if (true === $var) { return 'true'; } return (string) $var; } } setResponse($response); } public function getResponse() { return $this->response; } public function setResponse(Response $response) { $this->response = $response; } } response; } public function setResponse(Response $response) { $this->response = $response; $this->stopPropagation(); } public function hasResponse() { return null !== $this->response; } } controllerResult = $controllerResult; } public function getControllerResult() { return $this->controllerResult; } } setException($e); } public function getException() { return $this->exception; } public function setException(\Exception $exception) { $this->exception = $exception; } } kernel = $kernel; $this->request = $request; $this->requestType = $requestType; } public function getKernel() { return $this->kernel; } public function getRequest() { return $this->request; } public function getRequestType() { return $this->requestType; } } kernel = $kernel; $this->request = $request; $this->response = $response; } public function getKernel() { return $this->kernel; } public function getRequest() { return $this->request; } public function getResponse() { return $this->response; } } esi = $esi; } public function onKernelResponse(FilterResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType() || null === $this->esi) { return; } $this->esi->addSurrogateControl($event->getResponse()); } static public function getSubscribedEvents() { return array( KernelEvents::RESPONSE => 'onKernelResponse', ); } } controller = $controller; $this->logger = $logger; } public function onKernelException(GetResponseForExceptionEvent $event) { static $handling; if (true === $handling) { return false; } $handling = true; $exception = $event->getException(); $request = $event->getRequest(); if (null !== $this->logger) { $message = sprintf('%s: %s (uncaught exception) at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine()); if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) { $this->logger->crit($message); } else { $this->logger->err($message); } } else { error_log(sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine())); } $logger = $this->logger instanceof DebugLoggerInterface ? $this->logger : null; $flattenException = FlattenException::create($exception); if ($exception instanceof HttpExceptionInterface) { $flattenException->setStatusCode($exception->getStatusCode()); $flattenException->setHeaders($exception->getHeaders()); } $attributes = array( '_controller' => $this->controller, 'exception' => $flattenException, 'logger' => $logger, 'format' => $request->getRequestFormat(), ); $request = $request->duplicate(null, null, $attributes); $request->setMethod('GET'); try { $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, true); } catch (\Exception $e) { $message = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage()); if (null !== $this->logger) { if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) { $this->logger->crit($message); } else { $this->logger->err($message); } } else { error_log($message); } $handling = false; throw $exception; } $event->setResponse($response); $handling = false; } static public function getSubscribedEvents() { return array( KernelEvents::EXCEPTION => array('onKernelException', -128), ); } } defaultLocale = $defaultLocale; $this->router = $router; } public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if ($request->hasPreviousSession()) { $request->setDefaultLocale($request->getSession()->get('_locale', $this->defaultLocale)); } else { $request->setDefaultLocale($this->defaultLocale); } if ($locale = $request->attributes->get('_locale')) { $request->setLocale($locale); if ($request->hasPreviousSession()) { $request->getSession()->set('_locale', $request->getLocale()); } } if (null !== $this->router) { $this->router->getContext()->setParameter('_locale', $request->getLocale()); } } static public function getSubscribedEvents() { return array( KernelEvents::REQUEST => array(array('onKernelRequest', 16)), ); } } profiler = $profiler; $this->matcher = $matcher; $this->onlyException = (Boolean) $onlyException; $this->onlyMasterRequests = (Boolean) $onlyMasterRequests; $this->children = new \SplObjectStorage(); $this->profiles = array(); } public function onKernelException(GetResponseForExceptionEvent $event) { if ($this->onlyMasterRequests && HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } $this->exception = $event->getException(); } public function onKernelRequest(GetResponseEvent $event) { $this->requests[] = $event->getRequest(); } public function onKernelResponse(FilterResponseEvent $event) { $master = HttpKernelInterface::MASTER_REQUEST === $event->getRequestType(); if ($this->onlyMasterRequests && !$master) { return; } if ($this->onlyException && null === $this->exception) { return; } $request = $event->getRequest(); $exception = $this->exception; $this->exception = null; if (null !== $this->matcher && !$this->matcher->matches($request)) { return; } if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { return; } $this->profiles[] = $profile; if (null !== $exception) { foreach ($this->profiles as $profile) { $this->profiler->saveProfile($profile); } return; } if (!$master) { array_pop($this->requests); $parent = end($this->requests); $profiles = isset($this->children[$parent]) ? $this->children[$parent] : array(); $profiles[] = $profile; $this->children[$parent] = $profiles; } if (isset($this->children[$request])) { foreach ($this->children[$request] as $child) { $profile->addChild($child); } $this->children[$request] = array(); } if ($master) { $this->saveProfiles($profile); } } static public function getSubscribedEvents() { return array( KernelEvents::REQUEST => array('onKernelRequest', 1024), KernelEvents::RESPONSE => array('onKernelResponse', -100), KernelEvents::EXCEPTION => 'onKernelException', ); } private function saveProfiles(Profile $profile) { $this->profiler->saveProfile($profile); foreach ($profile->getChildren() as $profile) { $this->saveProfiles($profile); } } } charset = $charset; } public function onKernelResponse(FilterResponseEvent $event) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { return; } $response = $event->getResponse(); if (null === $response->getCharset()) { $response->setCharset($this->charset); } $response->prepare($event->getRequest()); } static public function getSubscribedEvents() { return array( KernelEvents::RESPONSE => 'onKernelResponse', ); } } urlMatcher = $urlMatcher; $this->logger = $logger; } public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); if (HttpKernelInterface::MASTER_REQUEST === $event->getRequestType()) { $this->urlMatcher->getContext()->fromRequest($request); } if ($request->attributes->has('_controller')) { return; } try { $parameters = $this->urlMatcher->match($request->getPathInfo()); if (null !== $this->logger) { $this->logger->info(sprintf('Matched route "%s" (parameters: %s)', $parameters['_route'], $this->parametersToString($parameters))); } $request->attributes->add($parameters); unset($parameters['_route']); unset($parameters['_controller']); $request->attributes->set('_route_params', $parameters); } catch (ResourceNotFoundException $e) { $message = sprintf('No route found for "%s %s"', $request->getMethod(), $request->getPathInfo()); throw new NotFoundHttpException($message, $e); } catch (MethodNotAllowedException $e) { $message = sprintf('No route found for "%s %s": Method Not Allowed (Allow: %s)', $request->getMethod(), $request->getPathInfo(), strtoupper(implode(', ', $e->getAllowedMethods()))); throw new MethodNotAllowedHttpException($e->getAllowedMethods(), $message, $e); } } private function parametersToString(array $parameters) { $pieces = array(); foreach ($parameters as $key => $val) { $pieces[] = sprintf('"%s": "%s"', $key, (is_string($val) ? $val : json_encode($val))); } return implode(', ', $pieces); } static public function getSubscribedEvents() { return array( KernelEvents::REQUEST => array(array('onKernelRequest', 32)), ); } } getRequestType()) { return; } $response = $event->getResponse(); if ($response instanceof StreamedResponse) { $response->send(); } } static public function getSubscribedEvents() { return array( KernelEvents::RESPONSE => array('onKernelResponse', -1024), ); } } setMessage($exception->getMessage()); $e->setCode($exception->getCode()); if (null === $statusCode) { $statusCode = $exception instanceof HttpExceptionInterface ? $exception->getStatusCode() : 500; } $e->setStatusCode($statusCode); $e->setHeaders($headers); $e->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine()); $e->setClass(get_class($exception)); $e->setFile($exception->getFile()); $e->setLine($exception->getLine()); if ($exception->getPrevious()) { $e->setPrevious(static::create($exception->getPrevious())); } return $e; } public function toArray() { $exceptions = array(); foreach (array_merge(array($this), $this->getAllPrevious()) as $exception) { $exceptions[] = array( 'message' => $exception->getMessage(), 'class' => $exception->getClass(), 'trace' => $exception->getTrace(), ); } return $exceptions; } public function getStatusCode() { return $this->statusCode; } public function setStatusCode($code) { $this->statusCode = $code; } public function getHeaders() { return $this->headers; } public function setHeaders(array $headers) { $this->headers = $headers; } public function getClass() { return $this->class; } public function setClass($class) { $this->class = $class; } public function getFile() { return $this->file; } public function setFile($file) { $this->file = $file; } public function getLine() { return $this->line; } public function setLine($line) { $this->line = $line; } public function getMessage() { return $this->message; } public function setMessage($message) { $this->message = $message; } public function getCode() { return $this->code; } public function setCode($code) { $this->code = $code; } public function getPrevious() { return $this->previous; } public function setPrevious(FlattenException $previous) { $this->previous = $previous; } public function getAllPrevious() { $exceptions = array(); $e = $this; while ($e = $e->getPrevious()) { $exceptions[] = $e; } return $exceptions; } public function getTrace() { return $this->trace; } public function setTrace($trace, $file, $line) { $this->trace = array(); $this->trace[] = array( 'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => $file, 'line' => $line, 'args' => array(), ); foreach ($trace as $entry) { $class = ''; $namespace = ''; if (isset($entry['class'])) { $parts = explode('\\', $entry['class']); $class = array_pop($parts); $namespace = implode('\\', $parts); } $this->trace[] = array( 'namespace' => $namespace, 'short_class' => $class, 'class' => isset($entry['class']) ? $entry['class'] : '', 'type' => isset($entry['type']) ? $entry['type'] : '', 'function' => $entry['function'], 'file' => isset($entry['file']) ? $entry['file'] : null, 'line' => isset($entry['line']) ? $entry['line'] : null, 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(), ); } } private function flattenArgs($args, $level = 0) { $result = array(); foreach ($args as $key => $value) { if (is_object($value)) { $result[$key] = array('object', get_class($value)); } elseif (is_array($value)) { if ($level > 10) { $result[$key] = array('array', '*DEEP NESTED ARRAY*'); } else { $result[$key] = array('array', $this->flattenArgs($value, ++$level)); } } elseif (null === $value) { $result[$key] = array('null', null); } elseif (is_bool($value)) { $result[$key] = array('boolean', $value); } elseif (is_resource($value)) { $result[$key] = array('resource', get_resource_type($value)); } else { $result[$key] = array('string', (string) $value); } } return $result; } } statusCode = $statusCode; $this->headers = $headers; parent::__construct($message, $code, $previous); } public function getStatusCode() { return $this->statusCode; } public function getHeaders() { return $this->headers; } } strtoupper(implode(', ', $allow))); parent::__construct(405, $message, $previous, $headers, $code); } } contentTypes = $contentTypes; } public function createCacheStrategy() { return new EsiResponseCacheStrategy(); } public function hasSurrogateEsiCapability(Request $request) { if (null === $value = $request->headers->get('Surrogate-Capability')) { return false; } return false !== strpos($value, 'ESI/1.0'); } public function addSurrogateEsiCapability(Request $request) { $current = $request->headers->get('Surrogate-Capability'); $new = 'symfony2="ESI/1.0"'; $request->headers->set('Surrogate-Capability', $current ? $current.', '.$new : $new); } public function addSurrogateControl(Response $response) { if (false !== strpos($response->getContent(), 'headers->set('Surrogate-Control', 'content="ESI/1.0"'); } } public function needsEsiParsing(Response $response) { if (!$control = $response->headers->get('Surrogate-Control')) { return false; } return (Boolean) preg_match('#content="[^"]*ESI/1.0[^"]*"#', $control); } public function renderIncludeTag($uri, $alt = null, $ignoreErrors = true, $comment = '') { $html = sprintf('', $uri, $ignoreErrors ? ' onerror="continue"' : '', $alt ? sprintf(' alt="%s"', $alt) : '' ); if (!empty($comment)) { return sprintf("\n%s", $comment, $html); } return $html; } public function process(Request $request, Response $response) { $this->request = $request; $type = $response->headers->get('Content-Type'); if (empty($type)) { $type = 'text/html'; } $parts = explode(';', $type); if (!in_array($parts[0], $this->contentTypes)) { return $response; } $content = $response->getContent(); $content = str_replace(array('', ''), $content); $content = preg_replace_callback('##', array($this, 'handleEsiIncludeTag'), $content); $content = preg_replace('#]*(?:/|#', '', $content); $content = preg_replace('#.*?#', '', $content); $response->setContent($content); $response->headers->set('X-Body-Eval', 'ESI'); if ($response->headers->has('Surrogate-Control')) { $value = $response->headers->get('Surrogate-Control'); if ('content="ESI/1.0"' == $value) { $response->headers->remove('Surrogate-Control'); } elseif (preg_match('#,\s*content="ESI/1.0"#', $value)) { $response->headers->set('Surrogate-Control', preg_replace('#,\s*content="ESI/1.0"#', '', $value)); } elseif (preg_match('#content="ESI/1.0",\s*#', $value)) { $response->headers->set('Surrogate-Control', preg_replace('#content="ESI/1.0",\s*#', '', $value)); } } } public function handle(HttpCache $cache, $uri, $alt, $ignoreErrors) { $subRequest = Request::create($uri, 'get', array(), $cache->getRequest()->cookies->all(), array(), $cache->getRequest()->server->all()); try { $response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); if (!$response->isSuccessful()) { throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $subRequest->getUri(), $response->getStatusCode())); } return $response->getContent(); } catch (\Exception $e) { if ($alt) { return $this->handle($cache, $alt, '', $ignoreErrors); } if (!$ignoreErrors) { throw $e; } } } private function handleEsiIncludeTag($attributes) { $options = array(); preg_match_all('/(src|onerror|alt)="([^"]*?)"/', $attributes[1], $matches, PREG_SET_ORDER); foreach ($matches as $set) { $options[$set[1]] = $set[2]; } if (!isset($options['src'])) { throw new \RuntimeException('Unable to process an ESI tag without a "src" attribute.'); } return sprintf('esi->handle($this, \'%s\', \'%s\', %s) ?>'."\n", $options['src'], isset($options['alt']) ? $options['alt'] : null, isset($options['onerror']) && 'continue' == $options['onerror'] ? 'true' : 'false' ); } } isValidateable()) { $this->cacheable = false; } else { $this->ttls[] = $response->getTtl(); $this->maxAges[] = $response->getMaxAge(); } } public function update(Response $response) { if (1 === count($this->ttls)) { return; } if (!$this->cacheable) { $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); return; } if (null !== $maxAge = min($this->maxAges)) { $response->setSharedMaxAge($maxAge); $response->headers->set('Age', $maxAge - min($this->ttls)); } $response->setMaxAge(0); } } store = $store; $this->kernel = $kernel; register_shutdown_function(array($this->store, 'cleanup')); $this->options = array_merge(array( 'debug' => false, 'default_ttl' => 0, 'private_headers' => array('Authorization', 'Cookie'), 'allow_reload' => false, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, ), $options); $this->esi = $esi; $this->traces = array(); } public function getStore() { return $this->store; } public function getTraces() { return $this->traces; } public function getLog() { $log = array(); foreach ($this->traces as $request => $traces) { $log[] = sprintf('%s: %s', $request, implode(', ', $traces)); } return implode('; ', $log); } public function getRequest() { return $this->request; } public function getKernel() { return $this->kernel; } public function getEsi() { return $this->esi; } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { if (HttpKernelInterface::MASTER_REQUEST === $type) { $this->traces = array(); $this->request = $request; if (null !== $this->esi) { $this->esiCacheStrategy = $this->esi->createCacheStrategy(); } } $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { $path .= '?'.$qs; } $this->traces[$request->getMethod().' '.$path] = array(); if (!$request->isMethodSafe()) { $response = $this->invalidate($request, $catch); } elseif ($request->headers->has('expect')) { $response = $this->pass($request, $catch); } else { $response = $this->lookup($request, $catch); } $response->isNotModified($request); $this->restoreResponseBody($request, $response); $response->setDate(new \DateTime(null, new \DateTimeZone('UTC'))); if (HttpKernelInterface::MASTER_REQUEST === $type && $this->options['debug']) { $response->headers->set('X-Symfony-Cache', $this->getLog()); } if (null !== $this->esi) { $this->esiCacheStrategy->add($response); if (HttpKernelInterface::MASTER_REQUEST === $type) { $this->esiCacheStrategy->update($response); } } $response->prepare($request); return $response; } public function terminate(Request $request, Response $response) { if ($this->getKernel() instanceof TerminableInterface) { $this->getKernel()->terminate($request, $response); } } protected function pass(Request $request, $catch = false) { $this->record($request, 'pass'); return $this->forward($request, $catch); } protected function invalidate(Request $request, $catch = false) { $response = $this->pass($request, $catch); if ($response->isSuccessful() || $response->isRedirect()) { try { $this->store->invalidate($request, $catch); $this->record($request, 'invalidate'); } catch (\Exception $e) { $this->record($request, 'invalidate-failed'); if ($this->options['debug']) { throw $e; } } } return $response; } protected function lookup(Request $request, $catch = false) { if ($this->options['allow_reload'] && $request->isNoCache()) { $this->record($request, 'reload'); return $this->fetch($request); } try { $entry = $this->store->lookup($request); } catch (\Exception $e) { $this->record($request, 'lookup-failed'); if ($this->options['debug']) { throw $e; } return $this->pass($request, $catch); } if (null === $entry) { $this->record($request, 'miss'); return $this->fetch($request, $catch); } if (!$this->isFreshEnough($request, $entry)) { $this->record($request, 'stale'); return $this->validate($request, $entry, $catch); } $this->record($request, 'fresh'); $entry->headers->set('Age', $entry->getAge()); return $entry; } protected function validate(Request $request, Response $entry, $catch = false) { $subRequest = clone $request; $subRequest->setMethod('GET'); $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); $cachedEtags = $entry->getEtag() ? array($entry->getEtag()) : array(); $requestEtags = $request->getEtags(); if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) { $subRequest->headers->set('if_none_match', implode(', ', $etags)); } $response = $this->forward($subRequest, $catch, $entry); if (304 == $response->getStatusCode()) { $this->record($request, 'valid'); $etag = $response->getEtag(); if ($etag && in_array($etag, $requestEtags) && !in_array($etag, $cachedEtags)) { return $response; } $entry = clone $entry; $entry->headers->remove('Date'); foreach (array('Date', 'Expires', 'Cache-Control', 'ETag', 'Last-Modified') as $name) { if ($response->headers->has($name)) { $entry->headers->set($name, $response->headers->get($name)); } } $response = $entry; } else { $this->record($request, 'invalid'); } if ($response->isCacheable()) { $this->store($request, $response); } return $response; } protected function fetch(Request $request, $catch = false) { $subRequest = clone $request; $subRequest->setMethod('GET'); $subRequest->headers->remove('if_modified_since'); $subRequest->headers->remove('if_none_match'); $response = $this->forward($subRequest, $catch); if ($this->isPrivateRequest($request) && !$response->headers->hasCacheControlDirective('public')) { $response->setPrivate(true); } elseif ($this->options['default_ttl'] > 0 && null === $response->getTtl() && !$response->headers->getCacheControlDirective('must-revalidate')) { $response->setTtl($this->options['default_ttl']); } if ($response->isCacheable()) { $this->store($request, $response); } return $response; } protected function forward(Request $request, $catch = false, Response $entry = null) { if ($this->esi) { $this->esi->addSurrogateEsiCapability($request); } $response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $catch); if (null !== $entry && in_array($response->getStatusCode(), array(500, 502, 503, 504))) { if (null === $age = $entry->headers->getCacheControlDirective('stale-if-error')) { $age = $this->options['stale_if_error']; } if (abs($entry->getTtl()) < $age) { $this->record($request, 'stale-if-error'); return $entry; } } $this->processResponseBody($request, $response); return $response; } protected function isFreshEnough(Request $request, Response $entry) { if (!$entry->isFresh()) { return $this->lock($request, $entry); } if ($this->options['allow_revalidate'] && null !== $maxAge = $request->headers->getCacheControlDirective('max-age')) { return $maxAge > 0 && $maxAge >= $entry->getAge(); } return true; } protected function lock(Request $request, Response $entry) { $lock = $this->store->lock($request, $entry); if (true !== $lock) { if (null === $age = $entry->headers->getCacheControlDirective('stale-while-revalidate')) { $age = $this->options['stale_while_revalidate']; } if (abs($entry->getTtl()) < $age) { $this->record($request, 'stale-while-revalidate'); return true; } $wait = 0; while (is_file($lock) && $wait < 5000000) { usleep(50000); $wait += 50000; } if ($wait < 2000000) { $new = $this->lookup($request); $entry->headers = $new->headers; $entry->setContent($new->getContent()); $entry->setStatusCode($new->getStatusCode()); $entry->setProtocolVersion($new->getProtocolVersion()); foreach ($new->headers->getCookies() as $cookie) { $entry->headers->setCookie($cookie); } } else { $entry->setStatusCode(503); $entry->setContent('503 Service Unavailable'); $entry->headers->set('Retry-After', 10); } return true; } return false; } protected function store(Request $request, Response $response) { try { $this->store->write($request, $response); $this->record($request, 'store'); $response->headers->set('Age', $response->getAge()); } catch (\Exception $e) { $this->record($request, 'store-failed'); if ($this->options['debug']) { throw $e; } } $this->store->unlock($request); } private function restoreResponseBody(Request $request, Response $response) { if ('HEAD' === $request->getMethod() || 304 === $response->getStatusCode()) { $response->setContent(''); $response->headers->remove('X-Body-Eval'); $response->headers->remove('X-Body-File'); return; } if ($response->headers->has('X-Body-Eval')) { ob_start(); if ($response->headers->has('X-Body-File')) { include $response->headers->get('X-Body-File'); } else { eval('; ?>'.$response->getContent().'setContent(ob_get_clean()); $response->headers->remove('X-Body-Eval'); if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', strlen($response->getContent())); } } elseif ($response->headers->has('X-Body-File')) { $response->setContent(file_get_contents($response->headers->get('X-Body-File'))); } else { return; } $response->headers->remove('X-Body-File'); } protected function processResponseBody(Request $request, Response $response) { if (null !== $this->esi && $this->esi->needsEsiParsing($response)) { $this->esi->process($request, $response); } } private function isPrivateRequest(Request $request) { foreach ($this->options['private_headers'] as $key) { $key = strtolower(str_replace('HTTP_', '', $key)); if ('cookie' === $key) { if (count($request->cookies->all())) { return true; } } elseif ($request->headers->has($key)) { return true; } } return false; } private function record(Request $request, $event) { $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { $path .= '?'.$qs; } $this->traces[$request->getMethod().' '.$path][] = $event; } } root = $root; if (!is_dir($this->root)) { mkdir($this->root, 0777, true); } $this->keyCache = new \SplObjectStorage(); $this->locks = array(); } public function cleanup() { foreach ($this->locks as $lock) { @unlink($lock); } $error = error_get_last(); if (1 === $error['type'] && false === headers_sent()) { header('HTTP/1.0 503 Service Unavailable'); header('Retry-After: 10'); echo '503 Service Unavailable'; } } public function lock(Request $request) { if (false !== $lock = @fopen($path = $this->getPath($this->getCacheKey($request).'.lck'), 'x')) { fclose($lock); $this->locks[] = $path; return true; } return $path; } public function unlock(Request $request) { return @unlink($this->getPath($this->getCacheKey($request).'.lck')); } public function lookup(Request $request) { $key = $this->getCacheKey($request); if (!$entries = $this->getMetadata($key)) { return null; } $match = null; foreach ($entries as $entry) { if ($this->requestsMatch(isset($entry[1]['vary'][0]) ? $entry[1]['vary'][0] : '', $request->headers->all(), $entry[0])) { $match = $entry; break; } } if (null === $match) { return null; } list($req, $headers) = $match; if (is_file($body = $this->getPath($headers['x-content-digest'][0]))) { return $this->restoreResponse($headers, $body); } return null; } public function write(Request $request, Response $response) { $key = $this->getCacheKey($request); $storedEnv = $this->persistRequest($request); if (!$response->headers->has('X-Content-Digest')) { $digest = 'en'.sha1($response->getContent()); if (false === $this->save($digest, $response->getContent())) { throw new \RuntimeException('Unable to store the entity.'); } $response->headers->set('X-Content-Digest', $digest); if (!$response->headers->has('Transfer-Encoding')) { $response->headers->set('Content-Length', strlen($response->getContent())); } } $entries = array(); $vary = $response->headers->get('vary'); foreach ($this->getMetadata($key) as $entry) { if (!isset($entry[1]['vary'][0])) { $entry[1]['vary'] = array(''); } if ($vary != $entry[1]['vary'][0] || !$this->requestsMatch($vary, $entry[0], $storedEnv)) { $entries[] = $entry; } } $headers = $this->persistResponse($response); unset($headers['age']); array_unshift($entries, array($storedEnv, $headers)); if (false === $this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } return $key; } public function invalidate(Request $request) { $modified = false; $key = $this->getCacheKey($request); $entries = array(); foreach ($this->getMetadata($key) as $entry) { $response = $this->restoreResponse($entry[1]); if ($response->isFresh()) { $response->expire(); $modified = true; $entries[] = array($entry[0], $this->persistResponse($response)); } else { $entries[] = $entry; } } if ($modified) { if (false === $this->save($key, serialize($entries))) { throw new \RuntimeException('Unable to store the metadata.'); } } foreach (array('Location', 'Content-Location') as $header) { if ($uri = $request->headers->get($header)) { $subRequest = Request::create($uri, 'get', array(), array(), array(), $request->server->all()); $this->invalidate($subRequest); } } } private function requestsMatch($vary, $env1, $env2) { if (empty($vary)) { return true; } foreach (preg_split('/[\s,]+/', $vary) as $header) { $key = strtr(strtolower($header), '_', '-'); $v1 = isset($env1[$key]) ? $env1[$key] : null; $v2 = isset($env2[$key]) ? $env2[$key] : null; if ($v1 !== $v2) { return false; } } return true; } private function getMetadata($key) { if (false === $entries = $this->load($key)) { return array(); } return unserialize($entries); } public function purge($url) { if (is_file($path = $this->getPath($this->getCacheKey(Request::create($url))))) { unlink($path); return true; } return false; } private function load($key) { $path = $this->getPath($key); return is_file($path) ? file_get_contents($path) : false; } private function save($key, $data) { $path = $this->getPath($key); if (!is_dir(dirname($path)) && false === @mkdir(dirname($path), 0777, true)) { return false; } $tmpFile = tempnam(dirname($path), basename($path)); if (false === $fp = @fopen($tmpFile, 'wb')) { return false; } @fwrite($fp, $data); @fclose($fp); if ($data != file_get_contents($tmpFile)) { return false; } if (false === @rename($tmpFile, $path)) { return false; } chmod($path, 0666 & ~umask()); } public function getPath($key) { return $this->root.DIRECTORY_SEPARATOR.substr($key, 0, 2).DIRECTORY_SEPARATOR.substr($key, 2, 2).DIRECTORY_SEPARATOR.substr($key, 4, 2).DIRECTORY_SEPARATOR.substr($key, 6); } private function getCacheKey(Request $request) { if (isset($this->keyCache[$request])) { return $this->keyCache[$request]; } return $this->keyCache[$request] = 'md'.sha1($request->getUri()); } private function persistRequest(Request $request) { return $request->headers->all(); } private function persistResponse(Response $response) { $headers = $response->headers->all(); $headers['X-Status'] = array($response->getStatusCode()); return $headers; } private function restoreResponse($headers, $body = null) { $status = $headers['X-Status'][0]; unset($headers['X-Status']); if (null !== $body) { $headers['X-Body-File'] = array($body); } return new Response($body, $status, $headers); } } dispatcher = $dispatcher; $this->resolver = $resolver; } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { try { return $this->handleRaw($request, $type); } catch (\Exception $e) { if (false === $catch) { throw $e; } return $this->handleException($e, $request, $type); } } public function terminate(Request $request, Response $response) { $this->dispatcher->dispatch(KernelEvents::TERMINATE, new PostResponseEvent($this, $request, $response)); } private function handleRaw(Request $request, $type = self::MASTER_REQUEST) { $event = new GetResponseEvent($this, $request, $type); $this->dispatcher->dispatch(KernelEvents::REQUEST, $event); if ($event->hasResponse()) { return $this->filterResponse($event->getResponse(), $request, $type); } if (false === $controller = $this->resolver->getController($request)) { throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". Maybe you forgot to add the matching route in your routing configuration?', $request->getPathInfo())); } $event = new FilterControllerEvent($this, $controller, $request, $type); $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event); $controller = $event->getController(); $arguments = $this->resolver->getArguments($request, $controller); $response = call_user_func_array($controller, $arguments); if (!$response instanceof Response) { $event = new GetResponseForControllerResultEvent($this, $request, $type, $response); $this->dispatcher->dispatch(KernelEvents::VIEW, $event); if ($event->hasResponse()) { $response = $event->getResponse(); } if (!$response instanceof Response) { $msg = sprintf('The controller must return a response (%s given).', $this->varToString($response)); if (null === $response) { $msg .= ' Did you forget to add a return statement somewhere in your controller?'; } throw new \LogicException($msg); } } return $this->filterResponse($response, $request, $type); } private function filterResponse(Response $response, Request $request, $type) { $event = new FilterResponseEvent($this, $request, $type, $response); $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); return $event->getResponse(); } private function handleException(\Exception $e, $request, $type) { $event = new GetResponseForExceptionEvent($this, $request, $type, $e); $this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event); if (!$event->hasResponse()) { throw $e; } try { return $this->filterResponse($event->getResponse(), $request, $type); } catch (\Exception $e) { return $event->getResponse(); } } private function varToString($var) { if (is_object($var)) { return sprintf('Object(%s)', get_class($var)); } if (is_array($var)) { $a = array(); foreach ($var as $k => $v) { $a[] = sprintf('%s => %s', $k, $this->varToString($v)); } return sprintf("Array(%s)", implode(', ', $a)); } if (is_resource($var)) { return sprintf('Resource(%s)', get_resource_type($var)); } if (null === $var) { return 'null'; } if (false === $var) { return 'false'; } if (true === $var) { return 'true'; } return (string) $var; } } environment = $environment; $this->debug = (Boolean) $debug; $this->booted = false; $this->rootDir = $this->getRootDir(); $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir)); $this->classes = array(); if ($this->debug) { $this->startTime = microtime(true); } $this->init(); } public function init() { if ($this->debug) { ini_set('display_errors', 1); error_reporting(-1); DebugClassLoader::enable(); ErrorHandler::register($this->errorReportingLevel); if ('cli' !== php_sapi_name()) { ExceptionHandler::register(); } } else { ini_set('display_errors', 0); } } public function __clone() { if ($this->debug) { $this->startTime = microtime(true); } $this->booted = false; $this->container = null; } public function boot() { if (true === $this->booted) { return; } $this->initializeBundles(); $this->initializeContainer(); foreach ($this->getBundles() as $bundle) { $bundle->setContainer($this->container); $bundle->boot(); } $this->booted = true; } public function terminate(Request $request, Response $response) { if (false === $this->booted) { return; } if ($this->getHttpKernel() instanceof TerminableInterface) { $this->getHttpKernel()->terminate($request, $response); } } public function shutdown() { if (false === $this->booted) { return; } $this->booted = false; foreach ($this->getBundles() as $bundle) { $bundle->shutdown(); $bundle->setContainer(null); } $this->container = null; } public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { if (false === $this->booted) { $this->boot(); } return $this->getHttpKernel()->handle($request, $type, $catch); } protected function getHttpKernel() { return $this->container->get('http_kernel'); } public function getBundles() { return $this->bundles; } public function isClassInActiveBundle($class) { foreach ($this->getBundles() as $bundle) { if (0 === strpos($class, $bundle->getNamespace())) { return true; } } return false; } public function getBundle($name, $first = true) { if (!isset($this->bundleMap[$name])) { throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() function of your %s.php file?', $name, get_class($this))); } if (true === $first) { return $this->bundleMap[$name][0]; } return $this->bundleMap[$name]; } public function locateResource($name, $dir = null, $first = true) { if ('@' !== $name[0]) { throw new \InvalidArgumentException(sprintf('A resource name must start with @ ("%s" given).', $name)); } if (false !== strpos($name, '..')) { throw new \RuntimeException(sprintf('File name "%s" contains invalid characters (..).', $name)); } $bundleName = substr($name, 1); $path = ''; if (false !== strpos($bundleName, '/')) { list($bundleName, $path) = explode('/', $bundleName, 2); } $isResource = 0 === strpos($path, 'Resources') && null !== $dir; $overridePath = substr($path, 9); $resourceBundle = null; $bundles = $this->getBundle($bundleName, false); $files = array(); foreach ($bundles as $bundle) { if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) { if (null !== $resourceBundle) { throw new \RuntimeException(sprintf('"%s" resource is hidden by a resource from the "%s" derived bundle. Create a "%s" file to override the bundle resource.', $file, $resourceBundle, $dir.'/'.$bundles[0]->getName().$overridePath )); } if ($first) { return $file; } $files[] = $file; } if (file_exists($file = $bundle->getPath().'/'.$path)) { if ($first && !$isResource) { return $file; } $files[] = $file; $resourceBundle = $bundle->getName(); } } if (count($files) > 0) { return $first && $isResource ? $files[0] : $files; } throw new \InvalidArgumentException(sprintf('Unable to find file "%s".', $name)); } public function getName() { return $this->name; } public function getEnvironment() { return $this->environment; } public function isDebug() { return $this->debug; } public function getRootDir() { if (null === $this->rootDir) { $r = new \ReflectionObject($this); $this->rootDir = dirname($r->getFileName()); } return $this->rootDir; } public function getContainer() { return $this->container; } public function loadClassCache($name = 'classes', $extension = '.php') { if (!$this->booted && is_file($this->getCacheDir().'/classes.map')) { ClassCollectionLoader::load(include($this->getCacheDir().'/classes.map'), $this->getCacheDir(), $name, $this->debug, false, $extension); } } public function setClassCache(array $classes) { file_put_contents($this->getCacheDir().'/classes.map', sprintf('debug ? $this->startTime : -INF; } public function getCacheDir() { return $this->rootDir.'/cache/'.$this->environment; } public function getLogDir() { return $this->rootDir.'/logs'; } protected function initializeBundles() { $this->bundles = array(); $topMostBundles = array(); $directChildren = array(); foreach ($this->registerBundles() as $bundle) { $name = $bundle->getName(); if (isset($this->bundles[$name])) { throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name)); } $this->bundles[$name] = $bundle; if ($parentName = $bundle->getParent()) { if (isset($directChildren[$parentName])) { throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName])); } if ($parentName == $name) { throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name)); } $directChildren[$parentName] = $name; } else { $topMostBundles[$name] = $bundle; } } if (count($diff = array_values(array_diff(array_keys($directChildren), array_keys($this->bundles))))) { throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0])); } $this->bundleMap = array(); foreach ($topMostBundles as $name => $bundle) { $bundleMap = array($bundle); $hierarchy = array($name); while (isset($directChildren[$name])) { $name = $directChildren[$name]; array_unshift($bundleMap, $this->bundles[$name]); $hierarchy[] = $name; } foreach ($hierarchy as $bundle) { $this->bundleMap[$bundle] = $bundleMap; array_pop($bundleMap); } } } protected function getContainerClass() { return $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer'; } protected function getContainerBaseClass() { return 'Container'; } protected function initializeContainer() { $class = $this->getContainerClass(); $cache = new ConfigCache($this->getCacheDir().'/'.$class.'.php', $this->debug); $fresh = true; if (!$cache->isFresh()) { $container = $this->buildContainer(); $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass()); $fresh = false; } require_once $cache; $this->container = new $class(); $this->container->set('kernel', $this); if (!$fresh && $this->container->has('cache_warmer')) { $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir')); } } protected function getKernelParameters() { $bundles = array(); foreach ($this->bundles as $name => $bundle) { $bundles[$name] = get_class($bundle); } return array_merge( array( 'kernel.root_dir' => $this->rootDir, 'kernel.environment' => $this->environment, 'kernel.debug' => $this->debug, 'kernel.name' => $this->name, 'kernel.cache_dir' => $this->getCacheDir(), 'kernel.logs_dir' => $this->getLogDir(), 'kernel.bundles' => $bundles, 'kernel.charset' => 'UTF-8', 'kernel.container_class' => $this->getContainerClass(), ), $this->getEnvParameters() ); } protected function getEnvParameters() { $parameters = array(); foreach ($_SERVER as $key => $value) { if (0 === strpos($key, 'SYMFONY__')) { $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value; } } return $parameters; } protected function buildContainer() { foreach (array('cache' => $this->getCacheDir(), 'logs' => $this->getLogDir()) as $name => $dir) { if (!is_dir($dir)) { if (false === @mkdir($dir, 0777, true)) { throw new \RuntimeException(sprintf("Unable to create the %s directory (%s)\n", $name, $dir)); } } elseif (!is_writable($dir)) { throw new \RuntimeException(sprintf("Unable to write in the %s directory (%s)\n", $name, $dir)); } } $container = $this->getContainerBuilder(); $extensions = array(); foreach ($this->bundles as $bundle) { if ($extension = $bundle->getContainerExtension()) { $container->registerExtension($extension); $extensions[] = $extension->getAlias(); } if ($this->debug) { $container->addObjectResource($bundle); } } foreach ($this->bundles as $bundle) { $bundle->build($container); } $container->addObjectResource($this); $container->getCompilerPassConfig()->setMergePass(new MergeExtensionConfigurationPass($extensions)); if (null !== $cont = $this->registerContainerConfiguration($this->getContainerLoader($container))) { $container->merge($cont); } $container->addCompilerPass(new AddClassesToCachePass($this)); $container->compile(); return $container; } protected function getContainerBuilder() { return new ContainerBuilder(new ParameterBag($this->getKernelParameters())); } protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container, $class, $baseClass) { $dumper = new PhpDumper($container); $content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass)); if (!$this->debug) { $content = self::stripComments($content); } $cache->write($content, $container->getResources()); } protected function getContainerLoader(ContainerInterface $container) { $locator = new FileLocator($this); $resolver = new LoaderResolver(array( new XmlFileLoader($container, $locator), new YamlFileLoader($container, $locator), new IniFileLoader($container, $locator), new PhpFileLoader($container, $locator), new ClosureLoader($container), )); return new DelegatingLoader($resolver); } static public function stripComments($source) { if (!function_exists('token_get_all')) { return $source; } $output = ''; foreach (token_get_all($source) as $token) { if (is_string($token)) { $output .= $token; } elseif (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) { $output .= $token[1]; } } $output = preg_replace(array('/\s+$/Sm', '/\n+/S'), "\n", $output); return $output; } public function serialize() { return serialize(array($this->environment, $this->debug)); } public function unserialize($data) { list($environment, $debug) = unserialize($data); $this->__construct($environment, $debug); } } dsn = $dsn; $this->lifetime = (int) $lifetime; } public function find($ip, $url, $limit, $method) { $indexName = $this->getIndexName(); $indexContent = $this->getValue($indexName); if (!$indexContent) { return array(); } $profileList = explode("\n", $indexContent); $result = array(); foreach ($profileList as $item) { if ($limit === 0) { break; } if ($item=='') { continue; } list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = explode("\t", $item, 6); if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) { continue; } $result[$itemToken] = array( 'token' => $itemToken, 'ip' => $itemIp, 'method' => $itemMethod, 'url' => $itemUrl, 'time' => $itemTime, 'parent' => $itemParent, ); --$limit; } usort($result, function($a, $b) { if ($a['time'] === $b['time']) { return 0; } return $a['time'] > $b['time'] ? -1 : 1; }); return $result; } public function purge() { $this->flush(); } public function read($token) { if (empty($token)) { return false; } $profile = $this->getValue($this->getItemName($token)); if (false !== $profile) { $profile = $this->createProfileFromData($token, $profile); } return $profile; } public function write(Profile $profile) { $data = array( 'token' => $profile->getToken(), 'parent' => $profile->getParentToken(), 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), ); if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime)) { $indexName = $this->getIndexName(); $indexRow = implode("\t", array( $profile->getToken(), $profile->getIp(), $profile->getMethod(), $profile->getUrl(), $profile->getTime(), $profile->getParentToken(), ))."\n"; return $this->appendValue($indexName, $indexRow, $this->lifetime); } return false; } abstract protected function getValue($key); abstract protected function setValue($key, $value, $expiration = 0); abstract protected function flush(); abstract protected function appendValue($key, $value, $expiration = 0); private function createProfileFromData($token, $data, $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setCollectors($data['data']); if (!$parent && $data['parent']) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } foreach ($data['children'] as $token) { if (!$token) { continue; } if (!$childProfileData = $this->getValue($this->getItemName($token))) { continue; } $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile)); } return $profile; } private function getItemName($token) { $name = self::TOKEN_PREFIX . $token; if ($this->isItemNameValid($name)) { return $name; } return false; } private function getIndexName() { $name = self::TOKEN_PREFIX . 'index'; if ($this->isItemNameValid($name)) { return $name; } return false; } private function isItemNameValid($name) { $length = strlen($name); if ($length > 250) { throw new \RuntimeException(sprintf('The memcache item key "%s" is too long (%s bytes). Allowed maximum size is 250 bytes.', $name, $length)); } return true; } } dsn)); } $this->folder = substr($dsn, 5); if (!is_dir($this->folder)) { mkdir($this->folder); } } public function find($ip, $url, $limit, $method) { $file = $this->getIndexFilename(); if (!file_exists($file)) { return array(); } $file = fopen($file, 'r'); fseek($file, 0, SEEK_END); $result = array(); while ($limit > 0) { $line = $this->readLineFromFile($file); if (false === $line) { break; } if ($line === '') { continue; } list($csvToken, $csvIp, $csvMethod, $csvUrl, $csvTime, $csvParent) = str_getcsv($line); if ($ip && false === strpos($csvIp, $ip) || $url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method)) { continue; } $result[$csvToken] = array( 'token' => $csvToken, 'ip' => $csvIp, 'method' => $csvMethod, 'url' => $csvUrl, 'time' => $csvTime, 'parent' => $csvParent, ); --$limit; } fclose($file); return array_values($result); } public function purge() { $flags = \FilesystemIterator::SKIP_DOTS; $iterator = new \RecursiveDirectoryIterator($this->folder, $flags); $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST); foreach ($iterator as $file) { if (is_file($file)) { unlink($file); } else { rmdir($file); } } } public function read($token) { if (!$token || !file_exists($file = $this->getFilename($token))) { return null; } return $this->createProfileFromData($token, unserialize(file_get_contents($file))); } public function write(Profile $profile) { $file = $this->getFilename($profile->getToken()); $dir = dirname($file); if (!is_dir($dir)) { mkdir($dir, 0777, true); } $data = array( 'token' => $profile->getToken(), 'parent' => $profile->getParentToken(), 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), ); if (false === file_put_contents($file, serialize($data))) { return false; } if (false === $file = fopen($this->getIndexFilename(), 'a')) { return false; } fputcsv($file, array( $profile->getToken(), $profile->getIp(), $profile->getMethod(), $profile->getUrl(), $profile->getTime(), $profile->getParentToken(), )); fclose($file); return true; } protected function getFilename($token) { $folderA = substr($token, -2, 2); $folderB = substr($token, -4, 2); return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token; } protected function getIndexFilename() { return $this->folder.'/index.csv'; } protected function readLineFromFile($file) { if (ftell($file) === 0) { return false; } fseek($file, -1, SEEK_CUR); $str = ''; while (true) { $char = fgetc($file); if ($char === "\n") { fseek($file, -1, SEEK_CUR); break; } $str = $char.$str; if (ftell($file) === 1) { fseek($file, -1, SEEK_CUR); break; } fseek($file, -2, SEEK_CUR); } return $str === '' ? $this->readLineFromFile($file) : $str; } protected function createProfileFromData($token, $data, $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setCollectors($data['data']); if (!$parent && $data['parent']) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } foreach ($data['children'] as $token) { if (!$token || !file_exists($file = $this->getFilename($token))) { continue; } $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile)); } return $profile; } } memcached) { if (!preg_match('#^memcached://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Memcached with an invalid dsn "%s". The expected format is "memcached://[host]:port".', $this->dsn)); } $host = $matches[1] ?: $matches[2]; $port = $matches[3]; $memcached = new Memcached; $memcached->setOption(Memcached::OPT_COMPRESSION, false); $memcached->addServer($host, $port); $this->memcached = $memcached; } return $this->memcached; } protected function getValue($key) { return $this->getMemcached()->get($key); } protected function setValue($key, $value, $expiration = 0) { return $this->getMemcached()->set($key, $value, time() + $expiration); } protected function flush() { return $this->getMemcached()->flush(); } protected function appendValue($key, $value, $expiration = 0) { $memcached = $this->getMemcached(); if (!$result = $memcached->append($key, $value)) { return $memcached->set($key, $value, $expiration); } return $result; } } memcache) { if (!preg_match('#^memcache://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Memcache with an invalid dsn "%s". The expected format is "memcache://[host]:port".', $this->dsn)); } $host = $matches[1] ?: $matches[2]; $port = $matches[3]; $memcache = new Memcache; $memcache->addServer($host, $port); $this->memcache = $memcache; } return $this->memcache; } protected function getValue($key) { return $this->getMemcache()->get($key); } protected function setValue($key, $value, $expiration = 0) { return $this->getMemcache()->set($key, $value, false, time() + $expiration); } protected function flush() { return $this->getMemcache()->flush(); } protected function appendValue($key, $value, $expiration = 0) { $memcache = $this->getMemcache(); if (method_exists($memcache, 'append')) { if (!$result = $memcache->append($key, $value, false, $expiration)) { return $memcache->set($key, $value, false, $expiration); } return $result; } $content = $memcache->get($key); return $memcache->set($key, $content . $value, false, $expiration); } } dsn = $dsn; $this->lifetime = (int) $lifetime; } public function find($ip, $url, $limit, $method) { $cursor = $this->getMongo()->find($this->buildQuery($ip, $url, $method), array('_id', 'parent', 'ip', 'method', 'url', 'time'))->sort(array('time' => -1))->limit($limit); $tokens = array(); foreach ($cursor as $profile) { $tokens[] = $this->getData($profile); } return $tokens; } public function purge() { $this->getMongo()->remove(array()); } public function read($token) { $profile = $this->getMongo()->findOne(array('_id' => $token, 'data' => array('$exists' => true))); if (null !== $profile) { $profile = $this->createProfileFromData($this->getData($profile)); } return $profile; } public function write(Profile $profile) { $this->cleanup(); $record = array( '_id' => $profile->getToken(), 'parent' => $profile->getParentToken(), 'data' => serialize($profile->getCollectors()), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime() ); return $this->getMongo()->update(array('_id' => $profile->getToken()), array_filter($record, function ($v) { return !empty($v); }), array('upsert' => true)); } protected function getMongo() { if ($this->mongo === null) { if (preg_match('#^(mongodb://.*)/(.*)/(.*)$#', $this->dsn, $matches)) { $mongo = new \Mongo($matches[1]); $database = $matches[2]; $collection = $matches[3]; $this->mongo = $mongo->selectCollection($database, $collection); } else { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use MongoDB with an invalid dsn "%s". The expected format is "mongodb://user:pass@location/database/collection"', $this->dsn)); } } return $this->mongo; } protected function createProfileFromData(array $data) { $profile = $this->getProfile($data); if ($data['parent']) { $parent = $this->getMongo()->findOne(array('_id' => $data['parent'], 'data' => array('$exists' => true))); if ($parent) { $profile->setParent($this->getProfile($this->getData($parent))); } } $profile->setChildren($this->readChildren($data['token'])); return $profile; } protected function readChildren($token) { $profiles = array(); $cursor = $this->getMongo()->find(array('parent' => $token, 'data' => array('$exists' => true))); foreach ($cursor as $d) { $profiles[] = $this->getProfile($this->getData($d)); } return $profiles; } protected function cleanup() { $this->getMongo()->remove(array('time' => array('$lt' => time() - $this->lifetime))); } private function buildQuery($ip, $url, $method) { $query = array(); if (!empty($ip)) { $query['ip'] = $ip; } if (!empty($url)) { $query['url'] = $url; } if (!empty($method)) { $query['method'] = $method; } return $query; } private function getData(array $data) { return array( 'token' => $data['_id'], 'parent' => isset($data['parent']) ? $data['parent'] : null, 'ip' => isset($data['ip']) ? $data['ip'] : null, 'method' => isset($data['method']) ? $data['method'] : null, 'url' => isset($data['url']) ? $data['url'] : null, 'time' => isset($data['time']) ? $data['time'] : null, 'data' => isset($data['data']) ? $data['data'] : null, ); } private function getProfile(array $data) { $profile = new Profile($data['token']); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setCollectors(unserialize($data['data'])); return $profile; } } db) { if (0 !== strpos($this->dsn, 'mysql')) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Mysql with an invalid dsn "%s". The expected format is "mysql:dbname=database_name;host=host_name".', $this->dsn)); } if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) { throw new \RuntimeException('You need to enable PDO_Mysql extension for the profiler to run properly.'); } $db = new \PDO($this->dsn, $this->username, $this->password); $db->exec('CREATE TABLE IF NOT EXISTS sf_profiler_data (token VARCHAR(255) PRIMARY KEY, data LONGTEXT, ip VARCHAR(64), method VARCHAR(6), url VARCHAR(255), time INTEGER UNSIGNED, parent VARCHAR(255), created_at INTEGER UNSIGNED, KEY (created_at), KEY (ip), KEY (method), KEY (url), KEY (parent))'); $this->db = $db; } return $this->db; } protected function buildCriteria($ip, $url, $limit, $method) { $criteria = array(); $args = array(); if ($ip = preg_replace('/[^\d\.]/', '', $ip)) { $criteria[] = 'ip LIKE :ip'; $args[':ip'] = '%'.$ip.'%'; } if ($url) { $criteria[] = 'url LIKE :url'; $args[':url'] = '%'.addcslashes($url, '%_\\').'%'; } if ($method) { $criteria[] = 'method = :method'; $args[':method'] = $method; } return array($criteria, $args); } } dsn = $dsn; $this->username = $username; $this->password = $password; $this->lifetime = (int) $lifetime; } public function find($ip, $url, $limit, $method) { list($criteria, $args) = $this->buildCriteria($ip, $url, $limit, $method); $criteria = $criteria ? 'WHERE '.implode(' AND ', $criteria) : ''; $db = $this->initDb(); $tokens = $this->fetch($db, 'SELECT token, ip, method, url, time, parent FROM sf_profiler_data '.$criteria.' ORDER BY time DESC LIMIT '.((integer) $limit), $args); $this->close($db); return $tokens; } public function read($token) { $db = $this->initDb(); $args = array(':token' => $token); $data = $this->fetch($db, 'SELECT data, parent, ip, method, url, time FROM sf_profiler_data WHERE token = :token LIMIT 1', $args); $this->close($db); if (isset($data[0]['data'])) { return $this->createProfileFromData($token, $data[0]); } return null; } public function write(Profile $profile) { $db = $this->initDb(); $args = array( ':token' => $profile->getToken(), ':parent' => $profile->getParentToken(), ':data' => base64_encode(serialize($profile->getCollectors())), ':ip' => $profile->getIp(), ':method' => $profile->getMethod(), ':url' => $profile->getUrl(), ':time' => $profile->getTime(), ':created_at' => time(), ); try { if ($this->read($profile->getToken())) { $this->exec($db, 'UPDATE sf_profiler_data SET parent = :parent, data = :data, ip = :ip, method = :method, url = :url, time = :time, created_at = :created_at WHERE token = :token', $args); } else { $this->exec($db, 'INSERT INTO sf_profiler_data (token, parent, data, ip, method, url, time, created_at) VALUES (:token, :parent, :data, :ip, :method, :url, :time, :created_at)', $args); } $this->cleanup(); $status = true; } catch (\Exception $e) { $status = false; } $this->close($db); return $status; } public function purge() { $db = $this->initDb(); $this->exec($db, 'DELETE FROM sf_profiler_data'); $this->close($db); } abstract protected function buildCriteria($ip, $url, $limit, $method); abstract protected function initDb(); protected function cleanup() { $db = $this->initDb(); $this->exec($db, 'DELETE FROM sf_profiler_data WHERE created_at < :time', array(':time' => time() - $this->lifetime)); $this->close($db); } protected function exec($db, $query, array $args = array()) { $stmt = $this->prepareStatement($db, $query); foreach ($args as $arg => $val) { $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR); } $success = $stmt->execute(); if (!$success) { throw new \RuntimeException(sprintf('Error executing query "%s"', $query)); } } protected function prepareStatement($db, $query) { try { $stmt = $db->prepare($query); } catch (\Exception $e) { $stmt = false; } if (false === $stmt) { throw new \RuntimeException('The database cannot successfully prepare the statement'); } return $stmt; } protected function fetch($db, $query, array $args = array()) { $stmt = $this->prepareStatement($db, $query); foreach ($args as $arg => $val) { $stmt->bindValue($arg, $val, is_int($val) ? \PDO::PARAM_INT : \PDO::PARAM_STR); } $stmt->execute(); $return = $stmt->fetchAll(\PDO::FETCH_ASSOC); return $return; } protected function close($db) { } protected function createProfileFromData($token, $data, $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setCollectors(unserialize(base64_decode($data['data']))); if (!$parent && !empty($data['parent'])) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } $profile->setChildren($this->readChildren($token, $profile)); return $profile; } protected function readChildren($token, $parent) { $db = $this->initDb(); $data = $this->fetch($db, 'SELECT token, data, ip, method, url, time FROM sf_profiler_data WHERE parent = :token', array(':token' => $token)); $this->close($db); if (!$data) { return array(); } $profiles = array(); foreach ($data as $d) { $profiles[] = $this->createProfileFromData($d['token'], $d, $parent); } return $profiles; } } token = $token; $this->collectors = array(); $this->children = array(); } public function setToken($token) { $this->token = $token; } public function getToken() { return $this->token; } public function setParent(Profile $parent) { $this->parent = $parent; } public function getParent() { return $this->parent; } public function getParentToken() { return $this->parent ? $this->parent->getToken() : null; } public function getIp() { return $this->ip; } public function setIp($ip) { $this->ip = $ip; } public function getMethod() { return $this->method; } public function setMethod($method) { $this->method = $method; } public function getUrl() { return $this->url; } public function setUrl($url) { $this->url = $url; } public function getTime() { return $this->time; } public function setTime($time) { $this->time = $time; } public function getChildren() { return $this->children; } public function setChildren(array $children) { $this->children = array(); foreach ($children as $child) { $this->addChild($child); } } public function addChild(Profile $child) { $this->children[] = $child; $child->setParent($this); } public function getCollector($name) { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } public function getCollectors() { return $this->collectors; } public function setCollectors(array $collectors) { $this->collectors = array(); foreach ($collectors as $collector) { $this->addCollector($collector); } } public function addCollector(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } public function hasCollector($name) { return isset($this->collectors[$name]); } public function __sleep() { return array('token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time'); } } storage = $storage; $this->logger = $logger; $this->collectors = array(); $this->enabled = true; } public function disable() { $this->enabled = false; } public function loadProfileFromResponse(Response $response) { if (!$token = $response->headers->get('X-Debug-Token')) { return false; } return $this->loadProfile($token); } public function loadProfile($token) { return $this->storage->read($token); } public function saveProfile(Profile $profile) { if (!($ret = $this->storage->write($profile)) && null !== $this->logger) { $this->logger->warn('Unable to store the profiler information.'); } return $ret; } public function purge() { $this->storage->purge(); } public function export(Profile $profile) { return base64_encode(serialize($profile)); } public function import($data) { $profile = unserialize(base64_decode($data)); if ($this->storage->read($profile->getToken())) { return false; } $this->saveProfile($profile); return $profile; } public function find($ip, $url, $limit, $method) { return $this->storage->find($ip, $url, $limit, $method); } public function collect(Request $request, Response $response, \Exception $exception = null) { if (false === $this->enabled) { return; } $profile = new Profile(uniqid()); $profile->setTime(time()); $profile->setUrl($request->getUri()); $profile->setIp($request->server->get('REMOTE_ADDR')); $profile->setMethod($request->getMethod()); $response->headers->set('X-Debug-Token', $profile->getToken()); foreach ($this->collectors as $collector) { $collector->collect($request, $response, $exception); $profile->addCollector(unserialize(serialize($collector))); } return $profile; } public function all() { return $this->collectors; } public function set(array $collectors = array()) { $this->collectors = array(); foreach ($collectors as $collector) { $this->add($collector); } } public function add(DataCollectorInterface $collector) { $this->collectors[$collector->getName()] = $collector; } public function has($name) { return isset($this->collectors[$name]); } public function get($name) { if (!isset($this->collectors[$name])) { throw new \InvalidArgumentException(sprintf('Collector "%s" does not exist.', $name)); } return $this->collectors[$name]; } } dsn = $dsn; $this->lifetime = (int) $lifetime; } public function find($ip, $url, $limit, $method) { $indexName = $this->getIndexName(); if (!$indexContent = $this->getValue($indexName, Redis::SERIALIZER_NONE)) { return array(); } $profileList = explode("\n", $indexContent); $result = array(); foreach ($profileList as $item) { if ($limit === 0) { break; } if ($item == '') { continue; } list($itemToken, $itemIp, $itemMethod, $itemUrl, $itemTime, $itemParent) = explode("\t", $item, 6); if ($ip && false === strpos($itemIp, $ip) || $url && false === strpos($itemUrl, $url) || $method && false === strpos($itemMethod, $method)) { continue; } $result[$itemToken] = array( 'token' => $itemToken, 'ip' => $itemIp, 'method' => $itemMethod, 'url' => $itemUrl, 'time' => $itemTime, 'parent' => $itemParent, ); --$limit; } usort($result, function($a, $b) { if ($a['time'] === $b['time']) { return 0; } return $a['time'] > $b['time'] ? -1 : 1; }); return $result; } public function purge() { $indexName = $this->getIndexName(); $indexContent = $this->getValue($indexName, Redis::SERIALIZER_NONE); if (!$indexContent) { return false; } $profileList = explode("\n", $indexContent); $result = array(); foreach ($profileList as $item) { if ($item == '') { continue; } if (false !== $pos = strpos($item, "\t")) { $result[] = $this->getItemName(substr($item, 0, $pos)); } } $result[] = $indexName; return $this->delete($result); } public function read($token) { if (empty($token)) { return false; } $profile = $this->getValue($this->getItemName($token), Redis::SERIALIZER_PHP); if (false !== $profile) { $profile = $this->createProfileFromData($token, $profile); } return $profile; } public function write(Profile $profile) { $data = array( 'token' => $profile->getToken(), 'parent' => $profile->getParentToken(), 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()), 'data' => $profile->getCollectors(), 'ip' => $profile->getIp(), 'method' => $profile->getMethod(), 'url' => $profile->getUrl(), 'time' => $profile->getTime(), ); if ($this->setValue($this->getItemName($profile->getToken()), $data, $this->lifetime, Redis::SERIALIZER_PHP)) { $indexName = $this->getIndexName(); $indexRow = implode("\t", array( $profile->getToken(), $profile->getIp(), $profile->getMethod(), $profile->getUrl(), $profile->getTime(), $profile->getParentToken(), ))."\n"; return $this->appendValue($indexName, $indexRow, $this->lifetime); } return false; } protected function getRedis() { if (null === $this->redis) { if (!preg_match('#^redis://(?(?=\[.*\])\[(.*)\]|(.*)):(.*)$#', $this->dsn, $matches)) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Redis with an invalid dsn "%s". The expected format is "redis://[host]:port".', $this->dsn)); } $host = $matches[1] ?: $matches[2]; $port = $matches[3]; if (!extension_loaded('redis')) { throw new \RuntimeException('RedisProfilerStorage requires that the redis extension is loaded.'); } $redis = new Redis; $redis->connect($host, $port); $redis->setOption(Redis::OPT_PREFIX, self::TOKEN_PREFIX); $this->redis = $redis; } return $this->redis; } private function createProfileFromData($token, $data, $parent = null) { $profile = new Profile($token); $profile->setIp($data['ip']); $profile->setMethod($data['method']); $profile->setUrl($data['url']); $profile->setTime($data['time']); $profile->setCollectors($data['data']); if (!$parent && $data['parent']) { $parent = $this->read($data['parent']); } if ($parent) { $profile->setParent($parent); } foreach ($data['children'] as $token) { if (!$token) { continue; } if (!$childProfileData = $this->getValue($this->getItemName($token), Redis::SERIALIZER_PHP)) { continue; } $profile->addChild($this->createProfileFromData($token, $childProfileData, $profile)); } return $profile; } private function getItemName($token) { $name = $token; if ($this->isItemNameValid($name)) { return $name; } return false; } private function getIndexName() { $name = 'index'; if ($this->isItemNameValid($name)) { return $name; } return false; } private function isItemNameValid($name) { $length = strlen($name); if ($length > 2147483648) { throw new \RuntimeException(sprintf('The Redis item key "%s" is too long (%s bytes). Allowed maximum size is 2^31 bytes.', $name, $length)); } return true; } private function getValue($key, $serializer = Redis::SERIALIZER_NONE) { $redis = $this->getRedis(); $redis->setOption(Redis::OPT_SERIALIZER, $serializer); return $redis->get($key); } private function setValue($key, $value, $expiration = 0, $serializer = Redis::SERIALIZER_NONE) { $redis = $this->getRedis(); $redis->setOption(Redis::OPT_SERIALIZER, $serializer); return $redis->setex($key, $expiration, $value); } private function appendValue($key, $value, $expiration = 0) { $redis = $this->getRedis(); $redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); if ($redis->exists($key)) { $redis->append($key, $value); return $redis->setTimeout($key, $expiration); } return $redis->setex($key, $expiration, $value); } private function delete(array $keys) { return (bool) $this->getRedis()->delete($keys); } } db || $this->db instanceof \SQLite3) { if (0 !== strpos($this->dsn, 'sqlite')) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use Sqlite with an invalid dsn "%s". The expected format is "sqlite:/path/to/the/db/file".', $this->dsn)); } if (class_exists('SQLite3')) { $db = new \SQLite3(substr($this->dsn, 7, strlen($this->dsn)), \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE); if (method_exists($db, 'busyTimeout')) { $db->busyTimeout(1000); } } elseif (class_exists('PDO') && in_array('sqlite', \PDO::getAvailableDrivers(), true)) { $db = new \PDO($this->dsn); } else { throw new \RuntimeException('You need to enable either the SQLite3 or PDO_SQLite extension for the profiler to run properly.'); } $db->exec('PRAGMA temp_store=MEMORY; PRAGMA journal_mode=MEMORY;'); $db->exec('CREATE TABLE IF NOT EXISTS sf_profiler_data (token STRING, data STRING, ip STRING, method STRING, url STRING, time INTEGER, parent STRING, created_at INTEGER)'); $db->exec('CREATE INDEX IF NOT EXISTS data_created_at ON sf_profiler_data (created_at)'); $db->exec('CREATE INDEX IF NOT EXISTS data_ip ON sf_profiler_data (ip)'); $db->exec('CREATE INDEX IF NOT EXISTS data_method ON sf_profiler_data (method)'); $db->exec('CREATE INDEX IF NOT EXISTS data_url ON sf_profiler_data (url)'); $db->exec('CREATE INDEX IF NOT EXISTS data_parent ON sf_profiler_data (parent)'); $db->exec('CREATE UNIQUE INDEX IF NOT EXISTS data_token ON sf_profiler_data (token)'); $this->db = $db; } return $this->db; } protected function exec($db, $query, array $args = array()) { if ($db instanceof \SQLite3) { $stmt = $this->prepareStatement($db, $query); foreach ($args as $arg => $val) { $stmt->bindValue($arg, $val, is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT); } $res = $stmt->execute(); if (false === $res) { throw new \RuntimeException(sprintf('Error executing SQLite query "%s"', $query)); } $res->finalize(); } else { parent::exec($db, $query, $args); } } protected function fetch($db, $query, array $args = array()) { $return = array(); if ($db instanceof \SQLite3) { $stmt = $this->prepareStatement($db, $query, true); foreach ($args as $arg => $val) { $stmt->bindValue($arg, $val, is_int($val) ? \SQLITE3_INTEGER : \SQLITE3_TEXT); } $res = $stmt->execute(); while ($row = $res->fetchArray(\SQLITE3_ASSOC)) { $return[] = $row; } $res->finalize(); $stmt->close(); } else { $return = parent::fetch($db, $query, $args); } return $return; } protected function buildCriteria($ip, $url, $limit, $method) { $criteria = array(); $args = array(); if ($ip = preg_replace('/[^\d\.]/', '', $ip)) { $criteria[] = 'ip LIKE :ip'; $args[':ip'] = '%'.$ip.'%'; } if ($url) { $criteria[] = 'url LIKE :url ESCAPE "\"'; $args[':url'] = '%'.addcslashes($url, '%_\\').'%'; } if ($method) { $criteria[] = 'method = :method'; $args[':method'] = $method; } return array($criteria, $args); } protected function close($db) { if ($db instanceof \SQLite3) { $db->close(); } } } requirements = array(); $this->options = array(); $this->defaults = array(); if (isset($data['value'])) { $data['pattern'] = $data['value']; unset($data['value']); } foreach ($data as $key => $value) { $method = 'set'.$key; if (!method_exists($this, $method)) { throw new \BadMethodCallException(sprintf("Unknown property '%s' on annotation '%s'.", $key, get_class($this))); } $this->$method($value); } } public function setPattern($pattern) { $this->pattern = $pattern; } public function getPattern() { return $this->pattern; } public function setName($name) { $this->name = $name; } public function getName() { return $this->name; } public function setRequirements($requirements) { $this->requirements = $requirements; } public function getRequirements() { return $this->requirements; } public function setOptions($options) { $this->options = $options; } public function getOptions() { return $this->options; } public function setDefaults($defaults) { $this->defaults = $defaults; } public function getDefaults() { return $this->defaults; } } route = $route; $this->staticPrefix = $staticPrefix; $this->regex = $regex; $this->tokens = $tokens; $this->variables = $variables; } public function getRoute() { return $this->route; } public function getStaticPrefix() { return $this->staticPrefix; } public function getRegex() { return $this->regex; } public function getTokens() { return $this->tokens; } public function getVariables() { return $this->variables; } public function getPattern() { return $this->route->getPattern(); } public function getOptions() { return $this->route->getOptions(); } public function getDefaults() { return $this->route->getDefaults(); } public function getRequirements() { return $this->route->getRequirements(); } } allowedMethods = array_map('strtoupper', $allowedMethods); parent::__construct($message, $code, $previous); } public function getAllowedMethods() { return $this->allowedMethods; } } routes = $routes; } public function getRoutes() { return $this->routes; } } 'ProjectUrlGenerator', 'base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', ), $options); return <<generateDeclaredRoutes()}; /** * Constructor. */ public function __construct(RequestContext \$context) { \$this->context = \$context; } {$this->generateGenerateMethod()} } EOF; } private function generateDeclaredRoutes() { $routes = "array(\n"; foreach ($this->getRoutes()->all() as $name => $route) { $compiledRoute = $route->compile(); $properties = array(); $properties[] = $compiledRoute->getVariables(); $properties[] = $compiledRoute->getDefaults(); $properties[] = $compiledRoute->getRequirements(); $properties[] = $compiledRoute->getTokens(); $routes .= sprintf(" '%s' => %s,\n", $name, str_replace("\n", '', var_export($properties, true))); } $routes .= ' )'; return $routes; } private function generateGenerateMethod() { return <<doGenerate(\$variables, \$defaults, \$requirements, \$tokens, \$parameters, \$name, \$absolute); } EOF; } } '/', ); protected $routes; public function __construct(RouteCollection $routes, RequestContext $context) { $this->routes = $routes; $this->context = $context; } public function setContext(RequestContext $context) { $this->context = $context; } public function getContext() { return $this->context; } public function generate($name, $parameters = array(), $absolute = false) { if (null === $route = $this->routes->get($name)) { throw new RouteNotFoundException(sprintf('Route "%s" does not exist.', $name)); } $compiledRoute = $route->compile(); return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $absolute); } protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $absolute) { $variables = array_flip($variables); $originParameters = $parameters; $parameters = array_replace($this->context->getParameters(), $parameters); $tparams = array_replace($defaults, $parameters); if ($diff = array_diff_key($variables, $tparams)) { throw new MissingMandatoryParametersException(sprintf('The "%s" route has some missing mandatory parameters ("%s").', $name, implode('", "', array_keys($diff)))); } $url = ''; $optional = true; foreach ($tokens as $token) { if ('variable' === $token[0]) { if (false === $optional || !array_key_exists($token[3], $defaults) || (isset($parameters[$token[3]]) && (string) $parameters[$token[3]] != (string) $defaults[$token[3]])) { if (!$isEmpty = in_array($tparams[$token[3]], array(null, '', false), true)) { if ($tparams[$token[3]] && !preg_match('#^'.$token[2].'$#', $tparams[$token[3]])) { throw new InvalidParameterException(sprintf('Parameter "%s" for route "%s" must match "%s" ("%s" given).', $token[3], $name, $token[2], $tparams[$token[3]])); } } if (!$isEmpty || !$optional) { $url = $token[1].strtr(rawurlencode($tparams[$token[3]]), $this->decodedChars).$url; } $optional = false; } } elseif ('text' === $token[0]) { $url = $token[1].$url; $optional = false; } } if (!$url) { $url = '/'; } $extra = array_diff_key($originParameters, $variables, $defaults); if ($extra && $query = http_build_query($extra, '', '&')) { $url .= '?'.$query; } $url = $this->context->getBaseUrl().$url; if ($this->context->getHost()) { $scheme = $this->context->getScheme(); if (isset($requirements['_scheme']) && ($req = strtolower($requirements['_scheme'])) && $scheme != $req) { $absolute = true; $scheme = $req; } if ($absolute) { $port = ''; if ('http' === $scheme && 80 != $this->context->getHttpPort()) { $port = ':'.$this->context->getHttpPort(); } elseif ('https' === $scheme && 443 != $this->context->getHttpsPort()) { $port = ':'.$this->context->getHttpsPort(); } $url = $scheme.'://'.$this->context->getHost().$port.$url; } } return $url; } } reader = $reader; } public function setRouteAnnotationClass($class) { $this->routeAnnotationClass = $class; } public function load($class, $type = null) { if (!class_exists($class)) { throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); } $globals = array( 'pattern' => '', 'requirements' => array(), 'options' => array(), 'defaults' => array(), ); $class = new \ReflectionClass($class); if ($class->isAbstract()) { throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class)); } if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) { if (null !== $annot->getPattern()) { $globals['pattern'] = $annot->getPattern(); } if (null !== $annot->getRequirements()) { $globals['requirements'] = $annot->getRequirements(); } if (null !== $annot->getOptions()) { $globals['options'] = $annot->getOptions(); } if (null !== $annot->getDefaults()) { $globals['defaults'] = $annot->getDefaults(); } } $collection = new RouteCollection(); $collection->addResource(new FileResource($class->getFileName())); foreach ($class->getMethods() as $method) { $this->defaultRouteIndex = 0; foreach ($this->reader->getMethodAnnotations($method) as $annot) { if ($annot instanceof $this->routeAnnotationClass) { $this->addRoute($collection, $annot, $globals, $class, $method); } } } return $collection; } protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method) { $name = $annot->getName(); if (null === $name) { $name = $this->getDefaultRouteName($class, $method); } $defaults = array_merge($globals['defaults'], $annot->getDefaults()); $requirements = array_merge($globals['requirements'], $annot->getRequirements()); $options = array_merge($globals['options'], $annot->getOptions()); $route = new Route($globals['pattern'].$annot->getPattern(), $defaults, $requirements, $options); $this->configureRoute($route, $class, $method, $annot); $collection->add($name, $route); } public function supports($resource, $type = null) { return is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type); } public function setResolver(LoaderResolverInterface $resolver) { } public function getResolver() { } protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method) { $name = strtolower(str_replace('\\', '_', $class->getName()).'_'.$method->getName()); if ($this->defaultRouteIndex > 0) { $name .= '_'.$this->defaultRouteIndex; } $this->defaultRouteIndex++; return $name; } abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot); } locator->locate($path); $collection = new RouteCollection(); $collection->addResource(new DirectoryResource($dir, '/\.php$/')); $files = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::LEAVES_ONLY)); usort($files, function (\SplFileInfo $a, \SplFileInfo $b) { return (string) $a > (string) $b ? 1 : -1; }); foreach ($files as $file) { if (!$file->isFile() || '.php' !== substr($file->getFilename(), -4)) { continue; } if ($class = $this->findClass($file)) { $refl = new \ReflectionClass($class); if ($refl->isAbstract()) { continue; } $collection->addCollection($this->loader->load($class, $type)); } } return $collection; } public function supports($resource, $type = null) { try { $path = $this->locator->locate($resource); } catch (\Exception $e) { return false; } return is_string($resource) && is_dir($path) && (!$type || 'annotation' === $type); } } loader = $loader; } public function load($file, $type = null) { $path = $this->locator->locate($file); $collection = new RouteCollection(); if ($class = $this->findClass($path)) { $collection->addResource(new FileResource($path)); $collection->addCollection($this->loader->load($class, $type)); } return $collection; } public function supports($resource, $type = null) { return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type); } protected function findClass($file) { $class = false; $namespace = false; $tokens = token_get_all(file_get_contents($file)); for ($i = 0, $count = count($tokens); $i < $count; $i++) { $token = $tokens[$i]; if (!is_array($token)) { continue; } if (true === $class && T_STRING === $token[0]) { return $namespace.'\\'.$token[1]; } if (true === $namespace && T_STRING === $token[0]) { $namespace = ''; do { $namespace .= $token[1]; $token = $tokens[++$i]; } while ($i < $count && is_array($token) && in_array($token[0], array(T_NS_SEPARATOR, T_STRING))); } if (T_CLASS === $token[0]) { $class = true; } if (T_NAMESPACE === $token[0]) { $namespace = true; } } return false; } } locator->locate($file); $this->setCurrentDir(dirname($path)); $collection = include $path; $collection->addResource(new FileResource($path)); return $collection; } public function supports($resource, $type = null) { return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'php' === $type); } } locator->locate($file); $xml = $this->loadFile($path); $collection = new RouteCollection(); $collection->addResource(new FileResource($path)); foreach ($xml->documentElement->childNodes as $node) { if (!$node instanceof \DOMElement) { continue; } $this->parseNode($collection, $node, $path, $file); } return $collection; } protected function parseNode(RouteCollection $collection, \DOMElement $node, $path, $file) { switch ($node->tagName) { case 'route': $this->parseRoute($collection, $node, $path); break; case 'import': $resource = (string) $node->getAttribute('resource'); $type = (string) $node->getAttribute('type'); $prefix = (string) $node->getAttribute('prefix'); $defaults = array(); $requirements = array(); $options = array(); foreach ($node->childNodes as $n) { if (!$n instanceof \DOMElement) { continue; } switch ($n->tagName) { case 'default': $defaults[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue); break; case 'requirement': $requirements[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue); break; case 'option': $options[(string) $n->getAttribute('key')] = trim((string) $n->nodeValue); break; default: throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $n->tagName)); } } $this->setCurrentDir(dirname($path)); $collection->addCollection($this->import($resource, ('' !== $type ? $type : null), false, $file), $prefix, $defaults, $requirements, $options); break; default: throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName)); } } public function supports($resource, $type = null) { return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'xml' === $type); } protected function parseRoute(RouteCollection $collection, \DOMElement $definition, $file) { $defaults = array(); $requirements = array(); $options = array(); foreach ($definition->childNodes as $node) { if (!$node instanceof \DOMElement) { continue; } switch ($node->tagName) { case 'default': $defaults[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue); break; case 'option': $options[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue); break; case 'requirement': $requirements[(string) $node->getAttribute('key')] = trim((string) $node->nodeValue); break; default: throw new \InvalidArgumentException(sprintf('Unable to parse tag "%s"', $node->tagName)); } } $route = new Route((string) $definition->getAttribute('pattern'), $defaults, $requirements, $options); $collection->add((string) $definition->getAttribute('id'), $route); } protected function loadFile($file) { $dom = new \DOMDocument(); libxml_use_internal_errors(true); if (!$dom->load($file, defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0)) { throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors())); } $dom->validateOnParse = true; $dom->normalizeDocument(); libxml_use_internal_errors(false); $this->validate($dom); return $dom; } protected function validate(\DOMDocument $dom) { $location = __DIR__.'/schema/routing/routing-1.0.xsd'; $current = libxml_use_internal_errors(true); if (!$dom->schemaValidate($location)) { throw new \InvalidArgumentException(implode("\n", $this->getXmlErrors())); } libxml_use_internal_errors($current); } private function getXmlErrors() { $errors = array(); foreach (libxml_get_errors() as $error) { $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)', LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', $error->code, trim($error->message), $error->file ? $error->file : 'n/a', $error->line, $error->column ); } libxml_clear_errors(); return $errors; } } locator->locate($file); $config = Yaml::parse($path); $collection = new RouteCollection(); $collection->addResource(new FileResource($path)); if (null === $config) { $config = array(); } if (!is_array($config)) { throw new \InvalidArgumentException(sprintf('The file "%s" must contain a YAML array.', $file)); } foreach ($config as $name => $config) { $config = $this->normalizeRouteConfig($config); if (isset($config['resource'])) { $type = isset($config['type']) ? $config['type'] : null; $prefix = isset($config['prefix']) ? $config['prefix'] : null; $defaults = isset($config['defaults']) ? $config['defaults'] : array(); $requirements = isset($config['requirements']) ? $config['requirements'] : array(); $options = isset($config['options']) ? $config['options'] : array(); $this->setCurrentDir(dirname($path)); $collection->addCollection($this->import($config['resource'], $type, false, $file), $prefix, $defaults, $requirements, $options); } else { $this->parseRoute($collection, $name, $config, $path); } } return $collection; } public function supports($resource, $type = null) { return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'yaml' === $type); } protected function parseRoute(RouteCollection $collection, $name, $config, $file) { $defaults = isset($config['defaults']) ? $config['defaults'] : array(); $requirements = isset($config['requirements']) ? $config['requirements'] : array(); $options = isset($config['options']) ? $config['options'] : array(); if (!isset($config['pattern'])) { throw new \InvalidArgumentException(sprintf('You must define a "pattern" for the "%s" route.', $name)); } $route = new Route($config['pattern'], $defaults, $requirements, $options); $collection->add($name, $route); } private function normalizeRouteConfig(array $config) { foreach ($config as $key => $value) { if (!in_array($key, self::$availableKeys)) { throw new \InvalidArgumentException(sprintf( 'Yaml routing loader does not support given key: "%s". Expected one of the (%s).', $key, implode(', ', self::$availableKeys) )); } } return $config; } } $value) { $name = $key; if (0 === strpos($name, 'REDIRECT_')) { $name = substr($name, 9); } if (0 === strpos($name, '_ROUTING_')) { $name = substr($name, 9); } else { continue; } if ('_route' == $name) { $match = true; $parameters[$name] = $value; } elseif (0 === strpos($name, '_allow_')) { $allow[] = substr($name, 7); } else { $parameters[$name] = $value; } unset($_SERVER[$key]); } if ($match) { return $parameters; } elseif (0 < count($allow)) { throw new MethodNotAllowedException($allow); } else { return parent::match($pathinfo); } } } 'app.php', 'base_uri' => '', ), $options); $options['script_name'] = self::escape($options['script_name'], ' ', '\\'); $rules = array("# skip \"real\" requests\nRewriteCond %{REQUEST_FILENAME} -f\nRewriteRule .* - [QSA,L]"); $methodVars = array(); foreach ($this->getRoutes()->all() as $name => $route) { $compiledRoute = $route->compile(); $regex = $compiledRoute->getRegex(); $delimiter = $regex[0]; $regexPatternEnd = strrpos($regex, $delimiter); if (strlen($regex) < 2 || 0 === $regexPatternEnd) { throw new \LogicException('The "%s" route regex "%s" is invalid', $name, $regex); } $regex = preg_replace('/\?<.+?>/', '', substr($regex, 1, $regexPatternEnd - 1)); $regex = '^'.self::escape(preg_quote($options['base_uri']).substr($regex, 1), ' ', '\\'); $methods = array(); if ($req = $route->getRequirement('_method')) { $methods = explode('|', strtoupper($req)); if (in_array('GET', $methods) && !in_array('HEAD', $methods)) { $methods[] = 'HEAD'; } } $hasTrailingSlash = (!$methods || in_array('HEAD', $methods)) && '/$' === substr($regex, -2) && '^/$' !== $regex; $variables = array('E=_ROUTING__route:'.$name); foreach ($compiledRoute->getVariables() as $i => $variable) { $variables[] = 'E=_ROUTING_'.$variable.':%'.($i + 1); } foreach ($route->getDefaults() as $key => $value) { $variables[] = 'E=_ROUTING_'.$key.':'.strtr($value, array( ':' => '\\:', '=' => '\\=', '\\' => '\\\\', ' ' => '\\ ', )); } $variables = implode(',', $variables); $rule = array("# $name"); if ($req = $route->getRequirement('_method')) { $methods = explode('|', strtoupper($req)); if (in_array('GET', $methods) && !in_array('HEAD', $methods)) { $methods[] = 'HEAD'; } $allow = array(); foreach ($methods as $method) { $methodVars[] = $method; $allow[] = 'E=_ROUTING__allow_'.$method.':1'; } $rule[] = "RewriteCond %{REQUEST_URI} $regex"; $rule[] = sprintf("RewriteCond %%{REQUEST_METHOD} !^(%s)$ [NC]", implode('|', $methods)); $rule[] = sprintf('RewriteRule .* - [S=%d,%s]', $hasTrailingSlash ? 2 : 1, implode(',', $allow)); } if ($hasTrailingSlash) { $rule[] = 'RewriteCond %{REQUEST_URI} '.substr($regex, 0, -2).'$'; $rule[] = 'RewriteRule .* $0/ [QSA,L,R=301]'; } $rule[] = "RewriteCond %{REQUEST_URI} $regex"; $rule[] = "RewriteRule .* {$options['script_name']} [QSA,L,$variables]"; $rules[] = implode("\n", $rule); } if (0 < count($methodVars)) { $rule = array('# 405 Method Not Allowed'); $methodVars = array_values(array_unique($methodVars)); foreach ($methodVars as $i => $methodVar) { $rule[] = sprintf('RewriteCond %%{_ROUTING__allow_%s} !-z%s', $methodVar, isset($methodVars[$i + 1]) ? ' [OR]' : ''); } $rule[] = sprintf('RewriteRule .* %s [QSA,L]', $options['script_name']); $rules[] = implode("\n", $rule); } return implode("\n\n", $rules)."\n"; } static private function escape($string, $char, $with) { $escaped = false; $output = ''; foreach(str_split($string) as $symbol) { if ($escaped) { $output .= $symbol; $escaped = false; continue; } if ($symbol === $char) { $output .= $with.$char; continue; } if ($symbol === $with) { $escaped = true; } $output .= $symbol; } return $output; } } routes = $routes; } public function getRoutes() { return $this->routes; } } 'ProjectUrlMatcher', 'base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', ), $options); $interfaces = class_implements($options['base_class']); $supportsRedirections = isset($interfaces['Symfony\\Component\\Routing\\Matcher\\RedirectableUrlMatcherInterface']); return <<context = \$context; } {$this->generateMatchMethod($supportsRedirections)} } EOF; } private function generateMatchMethod($supportsRedirections) { $code = rtrim($this->compileRoutes($this->getRoutes(), $supportsRedirections), "\n"); return <<getPrefix(); $countDirectChildRoutes = $this->countDirectChildRoutes($routes); $countAllChildRoutes = count($routes->all()); $optimizable = '' !== $prefix && $prefix !== $parentPrefix && $countDirectChildRoutes > 0 && $countAllChildRoutes > 1 && false === strpos($prefix, '{'); if ($optimizable) { $code .= sprintf(" if (0 === strpos(\$pathinfo, %s)) {\n", var_export($prefix, true)); } foreach ($routes as $name => $route) { if ($route instanceof Route) { $code .= $this->compileRoute($route, $name, $supportsRedirections, 1 === $countAllChildRoutes ? null : $prefix)."\n"; } elseif ($countAllChildRoutes - $countDirectChildRoutes > 0) { $code .= $this->compileRoutes($route, $supportsRedirections, $prefix); } } if ($optimizable) { $code .= " }\n\n"; $code = preg_replace('/^.{2,}$/m', ' $0', $code); } return $code; } private function compileRoute(Route $route, $name, $supportsRedirections, $parentPrefix = null) { $code = ''; $compiledRoute = $route->compile(); $conditions = array(); $hasTrailingSlash = false; $matches = false; $methods = array(); if ($req = $route->getRequirement('_method')) { $methods = explode('|', strtoupper($req)); if (in_array('GET', $methods) && !in_array('HEAD', $methods)) { $methods[] = 'HEAD'; } } $supportsTrailingSlash = $supportsRedirections && (!$methods || in_array('HEAD', $methods)); if (!count($compiledRoute->getVariables()) && false !== preg_match('#^(.)\^(?.*?)\$\1#', $compiledRoute->getRegex(), $m)) { if ($supportsTrailingSlash && substr($m['url'], -1) === '/') { $conditions[] = sprintf("rtrim(\$pathinfo, '/') === %s", var_export(rtrim(str_replace('\\', '', $m['url']), '/'), true)); $hasTrailingSlash = true; } else { $conditions[] = sprintf("\$pathinfo === %s", var_export(str_replace('\\', '', $m['url']), true)); } } else { if ($compiledRoute->getStaticPrefix() && $compiledRoute->getStaticPrefix() !== $parentPrefix) { $conditions[] = sprintf("0 === strpos(\$pathinfo, %s)", var_export($compiledRoute->getStaticPrefix(), true)); } $regex = $compiledRoute->getRegex(); if ($supportsTrailingSlash && $pos = strpos($regex, '/$')) { $regex = substr($regex, 0, $pos).'/?$'.substr($regex, $pos + 2); $hasTrailingSlash = true; } $conditions[] = sprintf("preg_match(%s, \$pathinfo, \$matches)", var_export($regex, true)); $matches = true; } $conditions = implode(' && ', $conditions); $code .= <<context->getMethod() != '$methods[0]') { \$allow[] = '$methods[0]'; goto $gotoname; } EOF; } else { $methods = implode("', '", $methods); $code .= <<context->getMethod(), array('$methods'))) { \$allow = array_merge(\$allow, array('$methods')); goto $gotoname; } EOF; } } if ($hasTrailingSlash) { $code .= <<redirect(\$pathinfo.'/', '$name'); } EOF; } if ($scheme = $route->getRequirement('_scheme')) { if (!$supportsRedirections) { throw new \LogicException('The "_scheme" requirement is only supported for URL matchers that implement RedirectableUrlMatcherInterface.'); } $code .= <<context->getScheme() !== '$scheme') { return \$this->redirect(\$pathinfo, '$name', '$scheme'); } EOF; } if (true === $matches && $compiledRoute->getDefaults()) { $code .= sprintf(" return array_merge(\$this->mergeDefaults(\$matches, %s), array('_route' => '%s'));\n" , str_replace("\n", '', var_export($compiledRoute->getDefaults(), true)), $name); } elseif (true === $matches) { $code .= sprintf(" \$matches['_route'] = '%s';\n", $name); $code .= " return \$matches;\n"; } elseif ($compiledRoute->getDefaults()) { $code .= sprintf(" return %s;\n", str_replace("\n", '', var_export(array_merge($compiledRoute->getDefaults(), array('_route' => $name)), true))); } else { $code .= sprintf(" return array('_route' => '%s');\n", $name); } $code .= " }\n"; if ($methods) { $code .= " $gotoname:\n"; } return $code; } } redirect($pathinfo.'/', null); } catch (ResourceNotFoundException $e2) { throw $e; } } return $parameters; } protected function handleRouteRequirements($pathinfo, $name, Route $route) { $scheme = $route->getRequirement('_scheme'); if ($scheme && $this->context->getScheme() !== $scheme) { return array(self::ROUTE_MATCH, $this->redirect($pathinfo, $name, $scheme)); } return array(self::REQUIREMENT_MATCH, null); } } traces = array(); try { $this->match($pathinfo); } catch (ExceptionInterface $e) { } return $this->traces; } protected function matchCollection($pathinfo, RouteCollection $routes) { foreach ($routes as $name => $route) { if ($route instanceof RouteCollection) { if (!$ret = $this->matchCollection($pathinfo, $route)) { continue; } return true; } $compiledRoute = $route->compile(); if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) { $r = new Route($route->getPattern(), $route->getDefaults(), array(), $route->getOptions()); $cr = $r->compile(); if (!preg_match($cr->getRegex(), $pathinfo)) { $this->addTrace(sprintf('Pattern "%s" does not match', $route->getPattern()), self::ROUTE_DOES_NOT_MATCH, $name, $route); continue; } foreach ($route->getRequirements() as $n => $regex) { $r = new Route($route->getPattern(), $route->getDefaults(), array($n => $regex), $route->getOptions()); $cr = $r->compile(); if (in_array($n, $cr->getVariables()) && !preg_match($cr->getRegex(), $pathinfo)) { $this->addTrace(sprintf('Requirement for "%s" does not match (%s)', $n, $regex), self::ROUTE_ALMOST_MATCHES, $name, $route); continue 2; } } continue; } if ($req = $route->getRequirement('_method')) { if ('HEAD' === $method = $this->context->getMethod()) { $method = 'GET'; } if (!in_array($method, $req = explode('|', strtoupper($req)))) { $this->allow = array_merge($this->allow, $req); $this->addTrace(sprintf('Method "%s" does not match the requirement ("%s")', $this->context->getMethod(), implode(', ', $req)), self::ROUTE_ALMOST_MATCHES, $name, $route); continue; } } if ($scheme = $route->getRequirement('_scheme')) { if ($this->context->getScheme() !== $scheme) { $this->addTrace(sprintf('Scheme "%s" does not match the requirement ("%s"); the user will be redirected', $this->context->getScheme(), $scheme), self::ROUTE_ALMOST_MATCHES, $name, $route); return true; } } $this->addTrace('Route matches!', self::ROUTE_MATCHES, $name, $route); return true; } } private function addTrace($log, $level = self::ROUTE_DOES_NOT_MATCH, $name = null, $route = null) { $this->traces[] = array( 'log' => $log, 'name' => $name, 'level' => $level, 'pattern' => null !== $route ? $route->getPattern() : null, ); } } routes = $routes; $this->context = $context; } public function setContext(RequestContext $context) { $this->context = $context; } public function getContext() { return $this->context; } public function match($pathinfo) { $this->allow = array(); if ($ret = $this->matchCollection(rawurldecode($pathinfo), $this->routes)) { return $ret; } throw 0 < count($this->allow) ? new MethodNotAllowedException(array_unique(array_map('strtoupper', $this->allow))) : new ResourceNotFoundException(); } protected function matchCollection($pathinfo, RouteCollection $routes) { foreach ($routes as $name => $route) { if ($route instanceof RouteCollection) { if (false === strpos($route->getPrefix(), '{') && $route->getPrefix() !== substr($pathinfo, 0, strlen($route->getPrefix()))) { continue; } if (!$ret = $this->matchCollection($pathinfo, $route)) { continue; } return $ret; } $compiledRoute = $route->compile(); if ('' !== $compiledRoute->getStaticPrefix() && 0 !== strpos($pathinfo, $compiledRoute->getStaticPrefix())) { continue; } if (!preg_match($compiledRoute->getRegex(), $pathinfo, $matches)) { continue; } if ($req = $route->getRequirement('_method')) { if ('HEAD' === $method = $this->context->getMethod()) { $method = 'GET'; } if (!in_array($method, $req = explode('|', strtoupper($req)))) { $this->allow = array_merge($this->allow, $req); continue; } } $status = $this->handleRouteRequirements($pathinfo, $name, $route); if (self::ROUTE_MATCH === $status[0]) { return $status[1]; } if (self::REQUIREMENT_MISMATCH === $status[0]) { continue; } return array_merge($this->mergeDefaults($matches, $route->getDefaults()), array('_route' => $name)); } } protected function handleRouteRequirements($pathinfo, $name, Route $route) { $scheme = $route->getRequirement('_scheme'); $status = $scheme && $scheme !== $this->context->getScheme() ? self::REQUIREMENT_MISMATCH : self::REQUIREMENT_MATCH; return array($status, null); } protected function mergeDefaults($params, $defaults) { $parameters = $defaults; foreach ($params as $key => $value) { if (!is_int($key)) { $parameters[$key] = $value; } } return $parameters; } } baseUrl = $baseUrl; $this->method = strtoupper($method); $this->host = $host; $this->scheme = strtolower($scheme); $this->httpPort = $httpPort; $this->httpsPort = $httpsPort; $this->parameters = array(); } public function fromRequest(Request $request) { $this->setBaseUrl($request->getBaseUrl()); $this->setMethod($request->getMethod()); $this->setHost($request->getHost()); $this->setScheme($request->getScheme()); $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort()); $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort); } public function getBaseUrl() { return $this->baseUrl; } public function setBaseUrl($baseUrl) { $this->baseUrl = $baseUrl; } public function getMethod() { return $this->method; } public function setMethod($method) { $this->method = strtoupper($method); } public function getHost() { return $this->host; } public function setHost($host) { $this->host = $host; } public function getScheme() { return $this->scheme; } public function setScheme($scheme) { $this->scheme = strtolower($scheme); } public function getHttpPort() { return $this->httpPort; } public function setHttpPort($httpPort) { $this->httpPort = $httpPort; } public function getHttpsPort() { return $this->httpsPort; } public function setHttpsPort($httpsPort) { $this->httpsPort = $httpsPort; } public function getParameters() { return $this->parameters; } public function setParameters(array $parameters) { $this->parameters = $parameters; return $this; } public function getParameter($name) { return isset($this->parameters[$name]) ? $this->parameters[$name] : null; } public function hasParameter($name) { return array_key_exists($name, $this->parameters); } public function setParameter($name, $parameter) { $this->parameters[$name] = $parameter; } } setPattern($pattern); $this->setDefaults($defaults); $this->setRequirements($requirements); $this->setOptions($options); } public function __clone() { $this->compiled = null; } public function getPattern() { return $this->pattern; } public function setPattern($pattern) { $this->pattern = trim($pattern); if ('' === $this->pattern || '/' !== $this->pattern[0]) { $this->pattern = '/'.$this->pattern; } $this->compiled = null; return $this; } public function getOptions() { return $this->options; } public function setOptions(array $options) { $this->options = array( 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler', ); return $this->addOptions($options); } public function addOptions(array $options) { foreach ($options as $name => $option) { $this->options[(string) $name] = $option; } $this->compiled = null; return $this; } public function setOption($name, $value) { $this->options[$name] = $value; $this->compiled = null; return $this; } public function getOption($name) { return isset($this->options[$name]) ? $this->options[$name] : null; } public function getDefaults() { return $this->defaults; } public function setDefaults(array $defaults) { $this->defaults = array(); return $this->addDefaults($defaults); } public function addDefaults(array $defaults) { foreach ($defaults as $name => $default) { $this->defaults[(string) $name] = $default; } $this->compiled = null; return $this; } public function getDefault($name) { return isset($this->defaults[$name]) ? $this->defaults[$name] : null; } public function hasDefault($name) { return array_key_exists($name, $this->defaults); } public function setDefault($name, $default) { $this->defaults[(string) $name] = $default; $this->compiled = null; return $this; } public function getRequirements() { return $this->requirements; } public function setRequirements(array $requirements) { $this->requirements = array(); return $this->addRequirements($requirements); } public function addRequirements(array $requirements) { foreach ($requirements as $key => $regex) { $this->requirements[$key] = $this->sanitizeRequirement($key, $regex); } $this->compiled = null; return $this; } public function getRequirement($key) { return isset($this->requirements[$key]) ? $this->requirements[$key] : null; } public function setRequirement($key, $regex) { $this->requirements[$key] = $this->sanitizeRequirement($key, $regex); $this->compiled = null; return $this; } public function compile() { if (null !== $this->compiled) { return $this->compiled; } $class = $this->getOption('compiler_class'); if (!isset(self::$compilers[$class])) { self::$compilers[$class] = new $class; } return $this->compiled = self::$compilers[$class]->compile($this); } private function sanitizeRequirement($key, $regex) { if (!is_string($regex)) { throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" must be a string', $key)); } if ('' === $regex) { throw new \InvalidArgumentException(sprintf('Routing requirement for "%s" cannot be empty', $key)); } if ('^' === $regex[0]) { $regex = substr($regex, 1); } if ('$' === substr($regex, -1)) { $regex = substr($regex, 0, -1); } return $regex; } } routes = array(); $this->resources = array(); $this->prefix = ''; } public function __clone() { foreach ($this->routes as $name => $route) { $this->routes[$name] = clone $route; if ($route instanceof RouteCollection) { $this->routes[$name]->setParent($this); } } } public function getParent() { return $this->parent; } public function getRoot() { $parent = $this; while ($parent->getParent()) { $parent = $parent->getParent(); } return $parent; } public function getIterator() { return new \ArrayIterator($this->routes); } public function add($name, Route $route) { if (!preg_match('/^[a-z0-9A-Z_.]+$/', $name)) { throw new \InvalidArgumentException(sprintf('The provided route name "%s" contains non valid characters. A route name must only contain digits (0-9), letters (a-z and A-Z), underscores (_) and dots (.).', $name)); } $this->remove($name); $this->routes[$name] = $route; } public function all() { $routes = array(); foreach ($this->routes as $name => $route) { if ($route instanceof RouteCollection) { $routes = array_merge($routes, $route->all()); } else { $routes[$name] = $route; } } return $routes; } public function get($name) { if (isset($this->routes[$name])) { return $this->routes[$name] instanceof RouteCollection ? null : $this->routes[$name]; } foreach ($this->routes as $routes) { if ($routes instanceof RouteCollection && null !== $route = $routes->get($name)) { return $route; } } return null; } public function remove($name) { $root = $this->getRoot(); foreach ((array) $name as $n) { $root->removeRecursively($n); } } public function addCollection(RouteCollection $collection, $prefix = '', $defaults = array(), $requirements = array(), $options = array()) { $root = $this->getRoot(); if ($root === $collection || $root->hasCollection($collection)) { throw new \InvalidArgumentException('The RouteCollection already exists in the tree.'); } $this->remove(array_keys($collection->all())); $collection->setParent($this); $collection->addPrefix($this->getPrefix() . $prefix, $defaults, $requirements, $options); $this->routes[] = $collection; } public function addPrefix($prefix, $defaults = array(), $requirements = array(), $options = array()) { $prefix = rtrim($prefix, '/'); if ('' === $prefix && empty($defaults) && empty($requirements) && empty($options)) { return; } if ('' !== $prefix && '/' !== $prefix[0]) { $prefix = '/'.$prefix; } $this->prefix = $prefix.$this->prefix; foreach ($this->routes as $route) { if ($route instanceof RouteCollection) { $route->addPrefix($prefix, $defaults, $requirements, $options); } else { $route->setPattern($prefix.$route->getPattern()); $route->addDefaults($defaults); $route->addRequirements($requirements); $route->addOptions($options); } } } public function getPrefix() { return $this->prefix; } public function getResources() { $resources = $this->resources; foreach ($this as $routes) { if ($routes instanceof RouteCollection) { $resources = array_merge($resources, $routes->getResources()); } } return array_unique($resources); } public function addResource(ResourceInterface $resource) { $this->resources[] = $resource; } private function setParent(RouteCollection $parent) { $this->parent = $parent; } private function removeRecursively($name) { if (isset($this->routes[$name])) { unset($this->routes[$name]); return true; } foreach ($this->routes as $routes) { if ($routes instanceof RouteCollection && $routes->removeRecursively($name)) { return true; } } return false; } private function hasCollection(RouteCollection $collection) { foreach ($this->routes as $routes) { if ($routes === $collection || $routes instanceof RouteCollection && $routes->hasCollection($collection)) { return true; } } return false; } } getPattern(); $len = strlen($pattern); $tokens = array(); $variables = array(); $pos = 0; preg_match_all('#.\{([\w\d_]+)\}#', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); foreach ($matches as $match) { if ($text = substr($pattern, $pos, $match[0][1] - $pos)) { $tokens[] = array('text', $text); } $seps = array($pattern[$pos]); $pos = $match[0][1] + strlen($match[0][0]); $var = $match[1][0]; if ($req = $route->getRequirement($var)) { $regexp = $req; } else { if ($pos !== $len) { $seps[] = $pattern[$pos]; } $regexp = sprintf('[^%s]+?', preg_quote(implode('', array_unique($seps)), self::REGEX_DELIMITER)); } $tokens[] = array('variable', $match[0][0][0], $regexp, $var); if (in_array($var, $variables)) { throw new \LogicException(sprintf('Route pattern "%s" cannot reference variable name "%s" more than once.', $route->getPattern(), $var)); } $variables[] = $var; } if ($pos < $len) { $tokens[] = array('text', substr($pattern, $pos)); } $firstOptional = INF; for ($i = count($tokens) - 1; $i >= 0; $i--) { $token = $tokens[$i]; if ('variable' === $token[0] && $route->hasDefault($token[3])) { $firstOptional = $i; } else { break; } } $regexp = ''; for ($i = 0, $nbToken = count($tokens); $i < $nbToken; $i++) { $regexp .= $this->computeRegexp($tokens, $i, $firstOptional); } return new CompiledRoute( $route, 'text' === $tokens[0][0] ? $tokens[0][1] : '', self::REGEX_DELIMITER.'^'.$regexp.'$'.self::REGEX_DELIMITER.'s', array_reverse($tokens), $variables ); } private function computeRegexp(array $tokens, $index, $firstOptional) { $token = $tokens[$index]; if('text' === $token[0]) { return preg_quote($token[1], self::REGEX_DELIMITER); } else { if (0 === $index && 0 === $firstOptional && 1 == count($tokens)) { return sprintf('%s(?<%s>%s)?', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]); } else { $regexp = sprintf('%s(?<%s>%s)', preg_quote($token[1], self::REGEX_DELIMITER), $token[3], $token[2]); if ($index >= $firstOptional) { $regexp = "(?:$regexp"; $nbTokens = count($tokens); if ($nbTokens - 1 == $index) { $regexp .= str_repeat(")?", $nbTokens - $firstOptional); } } return $regexp; } } } } loader = $loader; $this->resource = $resource; $this->context = null === $context ? new RequestContext() : $context; $this->defaults = $defaults; $this->setOptions($options); } public function setOptions(array $options) { $this->options = array( 'cache_dir' => null, 'debug' => false, 'generator_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_base_class' => 'Symfony\\Component\\Routing\\Generator\\UrlGenerator', 'generator_dumper_class' => 'Symfony\\Component\\Routing\\Generator\\Dumper\\PhpGeneratorDumper', 'generator_cache_class' => 'ProjectUrlGenerator', 'matcher_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', 'matcher_base_class' => 'Symfony\\Component\\Routing\\Matcher\\UrlMatcher', 'matcher_dumper_class' => 'Symfony\\Component\\Routing\\Matcher\\Dumper\\PhpMatcherDumper', 'matcher_cache_class' => 'ProjectUrlMatcher', 'resource_type' => null, ); $invalid = array(); $isInvalid = false; foreach ($options as $key => $value) { if (array_key_exists($key, $this->options)) { $this->options[$key] = $value; } else { $isInvalid = true; $invalid[] = $key; } } if ($isInvalid) { throw new \InvalidArgumentException(sprintf('The Router does not support the following options: "%s".', implode('\', \'', $invalid))); } } public function setOption($key, $value) { if (!array_key_exists($key, $this->options)) { throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } $this->options[$key] = $value; } public function getOption($key) { if (!array_key_exists($key, $this->options)) { throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } return $this->options[$key]; } public function getRouteCollection() { if (null === $this->collection) { $this->collection = $this->loader->load($this->resource, $this->options['resource_type']); } return $this->collection; } public function setContext(RequestContext $context) { $this->context = $context; $this->getMatcher()->setContext($context); $this->getGenerator()->setContext($context); } public function getContext() { return $this->context; } public function generate($name, $parameters = array(), $absolute = false) { return $this->getGenerator()->generate($name, $parameters, $absolute); } public function match($pathinfo) { return $this->getMatcher()->match($pathinfo); } public function getMatcher() { if (null !== $this->matcher) { return $this->matcher; } if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) { return $this->matcher = new $this->options['matcher_class']($this->getRouteCollection(), $this->context, $this->defaults); } $class = $this->options['matcher_cache_class']; $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); if (!$cache->isFresh($class)) { $dumper = new $this->options['matcher_dumper_class']($this->getRouteCollection()); $options = array( 'class' => $class, 'base_class' => $this->options['matcher_base_class'], ); $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); } require_once $cache; return $this->matcher = new $class($this->context, $this->defaults); } public function getGenerator() { if (null !== $this->generator) { return $this->generator; } if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) { return $this->generator = new $this->options['generator_class']($this->getRouteCollection(), $this->context, $this->defaults); } $class = $this->options['generator_cache_class']; $cache = new ConfigCache($this->options['cache_dir'].'/'.$class.'.php', $this->options['debug']); if (!$cache->isFresh($class)) { $dumper = new $this->options['generator_dumper_class']($this->getRouteCollection()); $options = array( 'class' => $class, 'base_class' => $this->options['generator_base_class'], ); $cache->write($dumper->dump($options), $this->getRouteCollection()->getResources()); } require_once $cache; return $this->generator = new $class($this->context, $this->defaults); } } setServerParameters($server); $this->history = null === $history ? new History() : $history; $this->cookieJar = null === $cookieJar ? new CookieJar() : $cookieJar; $this->insulated = false; $this->followRedirects = true; } public function followRedirects($followRedirect = true) { $this->followRedirects = (Boolean) $followRedirect; } public function insulate($insulated = true) { if (!class_exists('Symfony\\Component\\Process\\Process')) { throw new \RuntimeException('Unable to isolate requests as the Symfony Process Component is not installed.'); } $this->insulated = (Boolean) $insulated; } public function setServerParameters(array $server) { $this->server = array_merge(array( 'HTTP_HOST' => 'localhost', 'HTTP_USER_AGENT' => 'Symfony2 BrowserKit', ), $server); } public function setServerParameter($key, $value) { $this->server[$key] = $value; } public function getServerParameter($key, $default = '') { return (isset($this->server[$key])) ? $this->server[$key] : $default; } public function getHistory() { return $this->history; } public function getCookieJar() { return $this->cookieJar; } public function getCrawler() { return $this->crawler; } public function getResponse() { return $this->response; } public function getRequest() { return $this->request; } public function click(Link $link) { if ($link instanceof Form) { return $this->submit($link); } return $this->request($link->getMethod(), $link->getUri()); } public function submit(Form $form, array $values = array()) { $form->setValues($values); return $this->request($form->getMethod(), $form->getUri(), $form->getPhpValues(), $form->getPhpFiles()); } public function request($method, $uri, array $parameters = array(), array $files = array(), array $server = array(), $content = null, $changeHistory = true) { $uri = $this->getAbsoluteUri($uri); $server = array_merge($this->server, $server); if (!$this->history->isEmpty()) { $server['HTTP_REFERER'] = $this->history->current()->getUri(); } $server['HTTP_HOST'] = parse_url($uri, PHP_URL_HOST); $server['HTTPS'] = 'https' == parse_url($uri, PHP_URL_SCHEME); $request = new Request($uri, $method, $parameters, $files, $this->cookieJar->allValues($uri), $server, $content); $this->request = $this->filterRequest($request); if (true === $changeHistory) { $this->history->add($request); } if ($this->insulated) { $this->response = $this->doRequestInProcess($this->request); } else { $this->response = $this->doRequest($this->request); } $response = $this->filterResponse($this->response); $this->cookieJar->updateFromResponse($response); $this->redirect = $response->getHeader('Location'); if ($this->followRedirects && $this->redirect) { return $this->crawler = $this->followRedirect(); } return $this->crawler = $this->createCrawlerFromContent($request->getUri(), $response->getContent(), $response->getHeader('Content-Type')); } protected function doRequestInProcess($request) { $process = new PhpProcess($this->getScript($request), null, array('TMPDIR' => sys_get_temp_dir(), 'TEMP' => sys_get_temp_dir())); $process->run(); if (!$process->isSuccessful() || !preg_match('/^O\:\d+\:/', $process->getOutput())) { throw new \RuntimeException('OUTPUT: '.$process->getOutput().' ERROR OUTPUT: '.$process->getErrorOutput()); } return unserialize($process->getOutput()); } abstract protected function doRequest($request); protected function getScript($request) { throw new \LogicException('To insulate requests, you need to override the getScript() method.'); } protected function filterRequest(Request $request) { return $request; } protected function filterResponse($response) { return $response; } protected function createCrawlerFromContent($uri, $content, $type) { if (!class_exists('Symfony\Component\DomCrawler\Crawler')) { return null; } $crawler = new Crawler(null, $uri); $crawler->addContent($content, $type); return $crawler; } public function back() { return $this->requestFromRequest($this->history->back(), false); } public function forward() { return $this->requestFromRequest($this->history->forward(), false); } public function reload() { return $this->requestFromRequest($this->history->current(), false); } public function followRedirect() { if (empty($this->redirect)) { throw new \LogicException('The request was not redirected.'); } return $this->request('get', $this->redirect); } public function restart() { $this->cookieJar->clear(); $this->history->clear(); } protected function getAbsoluteUri($uri) { if (0 === strpos($uri, 'http')) { return $uri; } if (!$this->history->isEmpty()) { $currentUri = $this->history->current()->getUri(); } else { $currentUri = sprintf('http%s://%s/', isset($this->server['HTTPS']) ? 's' : '', isset($this->server['HTTP_HOST']) ? $this->server['HTTP_HOST'] : 'localhost' ); } if (!$uri || '#' == $uri[0]) { return preg_replace('/#.*?$/', '', $currentUri).$uri; } if ('/' !== $uri[0]) { $path = parse_url($currentUri, PHP_URL_PATH); if ('/' !== substr($path, -1)) { $path = substr($path, 0, strrpos($path, '/') + 1); } $uri = $path.$uri; } return preg_replace('#^(.*?//[^/]+)\/.*$#', '$1', $currentUri).$uri; } protected function requestFromRequest(Request $request, $changeHistory = true) { return $this->request($request->getMethod(), $request->getUri(), $request->getParameters(), $request->getFiles(), $request->getServer(), $request->getContent(), $changeHistory); } } value = urldecode($value); $this->rawValue = $value; } else { $this->value = $value; $this->rawValue = urlencode($value); } $this->name = $name; $this->expires = null === $expires ? null : (integer) $expires; $this->path = empty($path) ? '/' : $path; $this->domain = $domain; $this->secure = (Boolean) $secure; $this->httponly = (Boolean) $httponly; } public function __toString() { $cookie = sprintf('%s=%s', $this->name, $this->rawValue); if (null !== $this->expires) { $cookie .= '; expires='.substr(\DateTime::createFromFormat('U', $this->expires, new \DateTimeZone('GMT'))->format(self::$dateFormats[0]), 0, -5); } if ('' !== $this->domain) { $cookie .= '; domain='.$this->domain; } if ('/' !== $this->path) { $cookie .= '; path='.$this->path; } if ($this->secure) { $cookie .= '; secure'; } if ($this->httponly) { $cookie .= '; httponly'; } return $cookie; } static public function fromString($cookie, $url = null) { $parts = explode(';', $cookie); if (false === strpos($parts[0], '=')) { throw new \InvalidArgumentException('The cookie string "%s" is not valid.'); } list($name, $value) = explode('=', array_shift($parts), 2); $values = array( 'name' => trim($name), 'value' => trim($value), 'expires' => null, 'path' => '/', 'domain' => '', 'secure' => false, 'httponly' => false, 'passedRawValue' => true, ); if (null !== $url) { if ((false === $urlParts = parse_url($url)) || !isset($urlParts['host']) || !isset($urlParts['path'])) { throw new \InvalidArgumentException(sprintf('The URL "%s" is not valid.', $url)); } $parts = array_merge($urlParts, $parts); $values['domain'] = $parts['host']; $values['path'] = substr($parts['path'], 0, strrpos($parts['path'], '/')); } foreach ($parts as $part) { $part = trim($part); if ('secure' === strtolower($part)) { if (!$url || !isset($urlParts['scheme']) || 'https' != $urlParts['scheme']) { continue; } $values['secure'] = true; continue; } if ('httponly' === strtolower($part)) { $values['httponly'] = true; continue; } if (2 === count($elements = explode('=', $part, 2))) { if ('expires' === strtolower($elements[0])) { $elements[1] = self::parseDate($elements[1]); } $values[strtolower($elements[0])] = $elements[1]; } } return new static( $values['name'], $values['value'], $values['expires'], $values['path'], $values['domain'], $values['secure'], $values['httponly'], $values['passedRawValue'] ); } private static function parseDate($dateValue) { if (($length = strlen($dateValue)) > 1 && "'" === $dateValue[0] && "'" === $dateValue[$length-1]) { $dateValue = substr($dateValue, 1, -1); } foreach (self::$dateFormats as $dateFormat) { if (false !== $date = \DateTime::createFromFormat($dateFormat, $dateValue, new \DateTimeZone('GMT'))) { return $date->getTimestamp(); } } throw new \InvalidArgumentException(sprintf('Could not parse date "%s".', $dateValue)); } public function getName() { return $this->name; } public function getValue() { return $this->value; } public function getRawValue() { return $this->rawValue; } public function getExpiresTime() { return $this->expires; } public function getPath() { return $this->path; } public function getDomain() { return $this->domain; } public function isSecure() { return $this->secure; } public function isHttpOnly() { return $this->httponly; } public function isExpired() { return null !== $this->expires && 0 !== $this->expires && $this->expires < time(); } } cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; } public function get($name, $path = '/', $domain = null) { $this->flushExpiredCookies(); return isset($this->cookieJar[$domain][$path][$name]) ? $this->cookieJar[$domain][$path][$name] : null; } public function expire($name, $path = '/', $domain = null) { if (null === $path) { $path = '/'; } unset($this->cookieJar[$domain][$path][$name]); if (empty($this->cookieJar[$domain][$path])) { unset($this->cookieJar[$domain][$path]); if (empty($this->cookieJar[$domain])) { unset($this->cookieJar[$domain]); } } } public function clear() { $this->cookieJar = array(); } public function updateFromResponse(Response $response, $uri = null) { $cookies = array(); foreach ($response->getHeader('Set-Cookie', false) as $cookie) { foreach (explode(',', $cookie) as $i => $part) { if (0 === $i || preg_match('/^(?P\s*[0-9A-Za-z!#\$%\&\'\*\+\-\.^_`\|~]+)=/', $part)) { $cookies[] = ltrim($part); } else { $cookies[count($cookies) - 1] .= ','.$part; } } } foreach ($cookies as $cookie) { $this->set(Cookie::fromString($cookie, $uri)); } } public function all() { $this->flushExpiredCookies(); $flattenedCookies = array(); foreach ($this->cookieJar as $path) { foreach ($path as $cookies) { foreach ($cookies as $cookie) { $flattenedCookies[] = $cookie; } } } return $flattenedCookies; } public function allValues($uri, $returnsRawValue = false) { $this->flushExpiredCookies(); $parts = array_replace(array('path' => '/'), parse_url($uri)); $cookies = array(); foreach ($this->cookieJar as $domain => $pathCookies) { if ($domain) { $domain = ltrim($domain, '.'); if ($domain != substr($parts['host'], -strlen($domain))) { continue; } } foreach ($pathCookies as $path => $namedCookies) { if ($path != substr($parts['path'], 0, strlen($path))) { continue; } foreach ($namedCookies as $cookie) { if ($cookie->isSecure() && 'https' != $parts['scheme']) { continue; } $cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue(); } } } return $cookies; } public function allRawValues($uri) { return $this->allValues($uri, true); } public function flushExpiredCookies() { foreach ($this->cookieJar as $domain => $pathCookies) { foreach ($pathCookies as $path => $namedCookies) { foreach ($namedCookies as $name => $cookie) { if ($cookie->isExpired()) { unset($this->cookieJar[$domain][$path][$name]); } } } } } } clear(); } public function clear() { $this->stack = array(); $this->position = -1; } public function add(Request $request) { $this->stack = array_slice($this->stack, 0, $this->position + 1); $this->stack[] = clone $request; $this->position = count($this->stack) - 1; } public function isEmpty() { return count($this->stack) == 0; } public function back() { if ($this->position < 1) { throw new \LogicException('You are already on the first page.'); } return clone $this->stack[--$this->position]; } public function forward() { if ($this->position > count($this->stack) - 2) { throw new \LogicException('You are already on the last page.'); } return clone $this->stack[++$this->position]; } public function current() { if (-1 == $this->position) { throw new \LogicException('The page history is empty.'); } return clone $this->stack[$this->position]; } } uri = $uri; $this->method = $method; $this->parameters = $parameters; $this->files = $files; $this->cookies = $cookies; $this->server = $server; $this->content = $content; } public function getUri() { return $this->uri; } public function getMethod() { return $this->method; } public function getParameters() { return $this->parameters; } public function getFiles() { return $this->files; } public function getCookies() { return $this->cookies; } public function getServer() { return $this->server; } public function getContent() { return $this->content; } } content = $content; $this->status = $status; $this->headers = $headers; } public function __toString() { $headers = ''; foreach ($this->headers as $name => $value) { if (is_string($value)) { $headers .= $this->buildHeader($name, $value); } else { foreach ($value as $headerValue) { $headers .= $this->buildHeader($name, $headerValue); } } } return $headers."\n".$this->content; } protected function buildHeader($name, $value) { return sprintf("%s: %s\n", $name, $value); } public function getContent() { return $this->content; } public function getStatus() { return $this->status; } public function getHeaders() { return $this->headers; } public function getHeader($header, $first = true) { foreach ($this->headers as $key => $value) { if (str_replace('-', '_', strtolower($key)) == str_replace('-', '_', strtolower($header))) { if ($first) { return is_array($value) ? (count($value) ? $value[0] : '') : $value; } return is_array($value) ? $value : array($value); } } return $first ? null : array(); } } parse($cssExpr); } $expr = $cssExpr->toXpath(); if (!$expr) { throw new ParseException(sprintf('Got None for xpath expression from %s.', $cssExpr)); } if ($prefix) { $expr->addPrefix($prefix); } return (string) $expr; } public function parse($string) { $tokenizer = new Tokenizer(); $stream = new TokenStream($tokenizer->tokenize($string), $string); try { return $this->parseSelectorGroup($stream); } catch (\Exception $e) { $class = get_class($e); throw new $class(sprintf('%s at %s -> %s', $e->getMessage(), implode($stream->getUsed(), ''), $stream->peek()), 0, $e); } } private function parseSelectorGroup($stream) { $result = array(); while (true) { $result[] = $this->parseSelector($stream); if ($stream->peek() == ',') { $stream->next(); } else { break; } } if (count($result) == 1) { return $result[0]; } return new Node\OrNode($result); } private function parseSelector($stream) { $result = $this->parseSimpleSelector($stream); while (true) { $peek = $stream->peek(); if (',' == $peek || null === $peek) { return $result; } elseif (in_array($peek, array('+', '>', '~'))) { $combinator = (string) $stream->next(); } else { $combinator = ' '; } $consumed = count($stream->getUsed()); $nextSelector = $this->parseSimpleSelector($stream); if ($consumed == count($stream->getUsed())) { throw new ParseException(sprintf("Expected selector, got '%s'", $stream->peek())); } $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector); } return $result; } private function parseSimpleSelector($stream) { $peek = $stream->peek(); if ('*' != $peek && !$peek->isType('Symbol')) { $element = $namespace = '*'; } else { $next = $stream->next(); if ('*' != $next && !$next->isType('Symbol')) { throw new ParseException(sprintf("Expected symbol, got '%s'", $next)); } if ($stream->peek() == '|') { $namespace = $next; $stream->next(); $element = $stream->next(); if ('*' != $element && !$next->isType('Symbol')) { throw new ParseException(sprintf("Expected symbol, got '%s'", $next)); } } else { $namespace = '*'; $element = $next; } } $result = new Node\ElementNode($namespace, $element); $hasHash = false; while (true) { $peek = $stream->peek(); if ('#' == $peek) { if ($hasHash) { break; } $stream->next(); $result = new Node\HashNode($result, $stream->next()); $hasHash = true; continue; } elseif ('.' == $peek) { $stream->next(); $result = new Node\ClassNode($result, $stream->next()); continue; } elseif ('[' == $peek) { $stream->next(); $result = $this->parseAttrib($result, $stream); $next = $stream->next(); if (']' != $next) { throw new ParseException(sprintf("] expected, got '%s'", $next)); } continue; } elseif (':' == $peek || '::' == $peek) { $type = $stream->next(); $ident = $stream->next(); if (!$ident || !$ident->isType('Symbol')) { throw new ParseException(sprintf("Expected symbol, got '%s'", $ident)); } if ($stream->peek() == '(') { $stream->next(); $peek = $stream->peek(); if ($peek->isType('String')) { $selector = $stream->next(); } elseif ($peek->isType('Symbol') && is_int($peek)) { $selector = intval($stream->next()); } else { $selector = $this->parseSimpleSelector($stream); } $next = $stream->next(); if (')' != $next) { throw new ParseException(sprintf("Expected ')', got '%s' and '%s'", $next, $selector)); } $result = new Node\FunctionNode($result, $type, $ident, $selector); } else { $result = new Node\PseudoNode($result, $type, $ident); } continue; } else { if (' ' == $peek) { $stream->next(); } break; } } return $result; } private function parseAttrib($selector, $stream) { $attrib = $stream->next(); if ($stream->peek() == '|') { $namespace = $attrib; $stream->next(); $attrib = $stream->next(); } else { $namespace = '*'; } if ($stream->peek() == ']') { return new Node\AttribNode($selector, $namespace, $attrib, 'exists', null); } $op = $stream->next(); if (!in_array($op, array('^=', '$=', '*=', '=', '~=', '|=', '!='))) { throw new ParseException(sprintf("Operator expected, got '%s'", $op)); } $value = $stream->next(); if (!$value->isType('Symbol') && !$value->isType('String')) { throw new ParseException(sprintf("Expected string or symbol, got '%s'", $value)); } return new Node\AttribNode($selector, $namespace, $attrib, $op, $value); } } selector = $selector; $this->namespace = $namespace; $this->attrib = $attrib; $this->operator = $operator; $this->value = $value; } public function __toString() { if ($this->operator == 'exists') { return sprintf('%s[%s[%s]]', __CLASS__, $this->selector, $this->formatAttrib()); } return sprintf('%s[%s[%s %s %s]]', __CLASS__, $this->selector, $this->formatAttrib(), $this->operator, $this->value); } public function toXpath() { $path = $this->selector->toXpath(); $attrib = $this->xpathAttrib(); $value = $this->value; if ($this->operator == 'exists') { $path->addCondition($attrib); } elseif ($this->operator == '=') { $path->addCondition(sprintf('%s = %s', $attrib, XPathExpr::xpathLiteral($value))); } elseif ($this->operator == '!=') { if ($value) { $path->addCondition(sprintf('not(%s) or %s != %s', $attrib, $attrib, XPathExpr::xpathLiteral($value))); } else { $path->addCondition(sprintf('%s != %s', $attrib, XPathExpr::xpathLiteral($value))); } } elseif ($this->operator == '~=') { $path->addCondition(sprintf("contains(concat(' ', normalize-space(%s), ' '), %s)", $attrib, XPathExpr::xpathLiteral(' '.$value.' '))); } elseif ($this->operator == '|=') { $path->addCondition(sprintf('%s = %s or starts-with(%s, %s)', $attrib, XPathExpr::xpathLiteral($value), $attrib, XPathExpr::xpathLiteral($value.'-'))); } elseif ($this->operator == '^=') { $path->addCondition(sprintf('starts-with(%s, %s)', $attrib, XPathExpr::xpathLiteral($value))); } elseif ($this->operator == '$=') { $path->addCondition(sprintf('substring(%s, string-length(%s)-%s) = %s', $attrib, $attrib, strlen($value) - 1, XPathExpr::xpathLiteral($value))); } elseif ($this->operator == '*=') { $path->addCondition(sprintf('contains(%s, %s)', $attrib, XPathExpr::xpathLiteral($value))); } else { throw new ParseException(sprintf('Unknown operator: %s', $this->operator)); } return $path; } protected function xpathAttrib() { if ($this->namespace == '*') { return '@'.$this->attrib; } return sprintf('@%s:%s', $this->namespace, $this->attrib); } protected function formatAttrib() { if ($this->namespace == '*') { return $this->attrib; } return sprintf('%s|%s', $this->namespace, $this->attrib); } } selector = $selector; $this->className = $className; } public function __toString() { return sprintf('%s[%s.%s]', __CLASS__, $this->selector, $this->className); } public function toXpath() { $selXpath = $this->selector->toXpath(); $selXpath->addCondition(sprintf("contains(concat(' ', normalize-space(@class), ' '), %s)", XPathExpr::xpathLiteral(' '.$this->className.' '))); return $selXpath; } } 'descendant', '>' => 'child', '+' => 'direct_adjacent', '~' => 'indirect_adjacent', ); protected $selector; protected $combinator; protected $subselector; public function __construct($selector, $combinator, $subselector) { $this->selector = $selector; $this->combinator = $combinator; $this->subselector = $subselector; } public function __toString() { $comb = $this->combinator == ' ' ? '' : $this->combinator; return sprintf('%s[%s %s %s]', __CLASS__, $this->selector, $comb, $this->subselector); } public function toXpath() { if (!isset(self::$methodMapping[$this->combinator])) { throw new ParseException(sprintf('Unknown combinator: %s', $this->combinator)); } $method = '_xpath_'.self::$methodMapping[$this->combinator]; $path = $this->selector->toXpath(); return $this->$method($path, $this->subselector); } protected function _xpath_descendant($xpath, $sub) { $xpath->join('/descendant::', $sub->toXpath()); return $xpath; } protected function _xpath_child($xpath, $sub) { $xpath->join('/', $sub->toXpath()); return $xpath; } protected function _xpath_direct_adjacent($xpath, $sub) { $xpath->join('/following-sibling::', $sub->toXpath()); $xpath->addNameTest(); $xpath->addCondition('position() = 1'); return $xpath; } protected function _xpath_indirect_adjacent($xpath, $sub) { $xpath->join('/following-sibling::', $sub->toXpath()); return $xpath; } } namespace = $namespace; $this->element = $element; } public function __toString() { return sprintf('%s[%s]', __CLASS__, $this->formatElement()); } public function formatElement() { if ($this->namespace == '*') { return $this->element; } return sprintf('%s|%s', $this->namespace, $this->element); } public function toXpath() { if ($this->namespace == '*') { $el = strtolower($this->element); } else { $el = sprintf('%s:%s', $this->namespace, $this->element); } return new XPathExpr(null, null, $el); } } selector = $selector; $this->type = $type; $this->name = $name; $this->expr = $expr; } public function __toString() { return sprintf('%s[%s%s%s(%s)]', __CLASS__, $this->selector, $this->type, $this->name, $this->expr); } public function toXpath() { $selPath = $this->selector->toXpath(); if (in_array($this->name, self::$unsupported)) { throw new ParseException(sprintf('The pseudo-class %s is not supported', $this->name)); } $method = '_xpath_'.str_replace('-', '_', $this->name); if (!method_exists($this, $method)) { throw new ParseException(sprintf('The pseudo-class %s is unknown', $this->name)); } return $this->$method($selPath, $this->expr); } protected function _xpath_nth_child($xpath, $expr, $last = false, $addNameTest = true) { list($a, $b) = $this->parseSeries($expr); if (!$a && !$b && !$last) { $xpath->addCondition('false() and position() = 0'); return $xpath; } if ($addNameTest) { $xpath->addNameTest(); } $xpath->addStarPrefix(); if ($a == 0) { if ($last) { $b = sprintf('last() - %s', $b); } $xpath->addCondition(sprintf('position() = %s', $b)); return $xpath; } if ($last) { $a = -$a; $b = -$b; } if ($b > 0) { $bNeg = -$b; } else { $bNeg = sprintf('+%s', -$b); } if ($a != 1) { $expr = array(sprintf('(position() %s) mod %s = 0', $bNeg, $a)); } else { $expr = array(); } if ($b >= 0) { $expr[] = sprintf('position() >= %s', $b); } elseif ($b < 0 && $last) { $expr[] = sprintf('position() < (last() %s)', $b); } $expr = implode($expr, ' and '); if ($expr) { $xpath->addCondition($expr); } return $xpath; } protected function _xpath_nth_last_child($xpath, $expr) { return $this->_xpath_nth_child($xpath, $expr, true); } protected function _xpath_nth_of_type($xpath, $expr) { if ($xpath->getElement() == '*') { throw new ParseException('*:nth-of-type() is not implemented'); } return $this->_xpath_nth_child($xpath, $expr, false, false); } protected function _xpath_nth_last_of_type($xpath, $expr) { return $this->_xpath_nth_child($xpath, $expr, true, false); } protected function _xpath_contains($xpath, $expr) { if ($expr instanceof ElementNode) { $expr = $expr->formatElement(); } $xpath->addCondition(sprintf('contains(string(.), %s)', XPathExpr::xpathLiteral($expr))); return $xpath; } protected function _xpath_not($xpath, $expr) { $expr = $expr->toXpath(); $cond = $expr->getCondition(); $xpath->addCondition(sprintf('not(%s)', $cond)); return $xpath; } protected function parseSeries($s) { if ($s instanceof ElementNode) { $s = $s->formatElement(); } if (!$s || '*' == $s) { return array(0, 0); } if (is_string($s)) { return array(0, $s); } if ('odd' == $s) { return array(2, 1); } if ('even' == $s) { return array(2, 0); } if ('n' == $s) { return array(1, 0); } if (false === strpos($s, 'n')) { return array(0, intval((string) $s)); } list($a, $b) = explode('n', $s); if (!$a) { $a = 1; } elseif ('-' == $a || '+' == $a) { $a = intval($a.'1'); } else { $a = intval($a); } if (!$b) { $b = 0; } elseif ('-' == $b || '+' == $b) { $b = intval($b.'1'); } else { $b = intval($b); } return array($a, $b); } } selector = $selector; $this->id = $id; } public function __toString() { return sprintf('%s[%s#%s]', __CLASS__, $this->selector, $this->id); } public function toXpath() { $path = $this->selector->toXpath(); $path->addCondition(sprintf('@id = %s', XPathExpr::xpathLiteral($this->id))); return $path; } } items = $items; } public function __toString() { return sprintf('%s(%s)', __CLASS__, $this->items); } public function toXpath() { $paths = array(); foreach ($this->items as $item) { $paths[] = $item->toXpath(); } return new XPathExprOr($paths); } } element = $element; if (!in_array($type, array(':', '::'))) { throw new ParseException(sprintf('The PseudoNode type can only be : or :: (%s given).', $type)); } $this->type = $type; $this->ident = $ident; } public function __toString() { return sprintf('%s[%s%s%s]', __CLASS__, $this->element, $this->type, $this->ident); } public function toXpath() { $elXpath = $this->element->toXpath(); if (in_array($this->ident, self::$unsupported)) { throw new ParseException(sprintf('The pseudo-class %s is unsupported', $this->ident)); } $method = 'xpath_'.str_replace('-', '_', $this->ident); if (!method_exists($this, $method)) { throw new ParseException(sprintf('The pseudo-class %s is unknown', $this->ident)); } return $this->$method($elXpath); } protected function xpath_checked($xpath) { $xpath->addCondition("(@selected or @checked) and (name(.) = 'input' or name(.) = 'option')"); return $xpath; } protected function xpath_root($xpath) { throw new ParseException(); } protected function xpath_first_child($xpath) { $xpath->addStarPrefix(); $xpath->addNameTest(); $xpath->addCondition('position() = 1'); return $xpath; } protected function xpath_last_child($xpath) { $xpath->addStarPrefix(); $xpath->addNameTest(); $xpath->addCondition('position() = last()'); return $xpath; } protected function xpath_first_of_type($xpath) { if ($xpath->getElement() == '*') { throw new ParseException('*:first-of-type is not implemented'); } $xpath->addStarPrefix(); $xpath->addCondition('position() = 1'); return $xpath; } protected function xpath_last_of_type($xpath) { if ($xpath->getElement() == '*') { throw new ParseException('*:last-of-type is not implemented'); } $xpath->addStarPrefix(); $xpath->addCondition('position() = last()'); return $xpath; } protected function xpath_only_child($xpath) { $xpath->addNameTest(); $xpath->addStarPrefix(); $xpath->addCondition('last() = 1'); return $xpath; } protected function xpath_only_of_type($xpath) { if ($xpath->getElement() == '*') { throw new ParseException('*:only-of-type is not implemented'); } $xpath->addCondition('last() = 1'); return $xpath; } protected function xpath_empty($xpath) { $xpath->addCondition('not(*) and not(normalize-space())'); return $xpath; } } type = $type; $this->value = $value; $this->position = $position; } public function __toString() { return (string) $this->value; } public function isType($type) { return $this->type == $type; } public function getPosition() { return $this->position; } } = strlen($s)) { if (isset($mbEncoding)) { mb_internal_encoding($mbEncoding); } return $tokens; } if (preg_match('#[+-]?\d*n(?:[+-]\d+)?#A', $s, $match, 0, $pos) && 'n' !== $match[0]) { $sym = substr($s, $pos, strlen($match[0])); $tokens[] = new Token('Symbol', $sym, $pos); $pos += strlen($match[0]); continue; } $c = $s[$pos]; $c2 = substr($s, $pos, 2); if (in_array($c2, array('~=', '|=', '^=', '$=', '*=', '::', '!='))) { $tokens[] = new Token('Token', $c2, $pos); $pos += 2; continue; } if (in_array($c, array('>', '+', '~', ',', '.', '*', '=', '[', ']', '(', ')', '|', ':', '#'))) { if (in_array($c, array('.', '#', '[')) && $precedingWhitespacePos > 0) { $tokens[] = new Token('Token', ' ', $precedingWhitespacePos); } $tokens[] = new Token('Token', $c, $pos); ++$pos; continue; } if ('"' === $c || "'" === $c) { $oldPos = $pos; list($sym, $pos) = $this->tokenizeEscapedString($s, $pos); $tokens[] = new Token('String', $sym, $oldPos); continue; } $oldPos = $pos; list($sym, $pos) = $this->tokenizeSymbol($s, $pos); $tokens[] = new Token('Symbol', $sym, $oldPos); continue; } } private function tokenizeEscapedString($s, $pos) { $quote = $s[$pos]; $pos = $pos + 1; $start = $pos; while (true) { $next = strpos($s, $quote, $pos); if (false === $next) { throw new ParseException(sprintf('Expected closing %s for string in: %s', $quote, substr($s, $start))); } $result = substr($s, $start, $next - $start); if ('\\' === $result[strlen($result) - 1]) { $pos = $next + 1; continue; } if (false !== strpos($result, '\\')) { $result = $this->unescapeStringLiteral($result); } return array($result, $next + 1); } } private function unescapeStringLiteral($literal) { return preg_replace_callback('#(\\\\(?:[A-Fa-f0-9]{1,6}(?:\r\n|\s)?|[^A-Fa-f0-9]))#', function ($matches) use ($literal) { if ($matches[0][0] == '\\' && strlen($matches[0]) > 1) { $matches[0] = substr($matches[0], 1); if (in_array($matches[0][0], array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'a', 'b', 'c', 'd', 'e', 'f'))) { return chr(trim($matches[0])); } } else { throw new ParseException(sprintf('Invalid escape sequence %s in string %s', $matches[0], $literal)); } }, $literal); } private function tokenizeSymbol($s, $pos) { $start = $pos; if (!preg_match('#[^\w\-]#', $s, $match, PREG_OFFSET_CAPTURE, $pos)) { return array(substr($s, $start), strlen($s)); } $matchStart = $match[0][1]; if ($matchStart == $pos) { throw new ParseException(sprintf('Unexpected symbol: %s at %s', $s[$pos], $pos)); } $result = substr($s, $start, $matchStart - $start); $pos = $matchStart; return array($result, $pos); } } used = array(); $this->tokens = $tokens; $this->source = $source; $this->peeked = null; $this->peeking = false; } public function getUsed() { return $this->used; } public function next() { if ($this->peeking) { $this->peeking = false; $this->used[] = $this->peeked; return $this->peeked; } if (!count($this->tokens)) { return null; } $next = array_shift($this->tokens); $this->used[] = $next; return $next; } public function peek() { if (!$this->peeking) { if (!count($this->tokens)) { return null; } $this->peeked = array_shift($this->tokens); $this->peeking = true; } return $this->peeked; } } prefix = $prefix; $this->path = $path; $this->element = $element; $this->condition = $condition; $this->starPrefix = $starPrefix; } public function getPrefix() { return $this->prefix; } public function getPath() { return $this->path; } public function hasStarPrefix() { return $this->starPrefix; } public function getElement() { return $this->element; } public function getCondition() { return $this->condition; } public function __toString() { $path = ''; if (null !== $this->prefix) { $path .= $this->prefix; } if (null !== $this->path) { $path .= $this->path; } $path .= $this->element; if ($this->condition) { $path .= sprintf('[%s]', $this->condition); } return $path; } public function addCondition($condition) { if ($this->condition) { $this->condition = sprintf('%s and (%s)', $this->condition, $condition); } else { $this->condition = $condition; } } public function addPrefix($prefix) { if ($this->prefix) { $this->prefix = $prefix.$this->prefix; } else { $this->prefix = $prefix; } } public function addNameTest() { if ($this->element == '*') { return; } $this->addCondition(sprintf('name() = %s', XPathExpr::xpathLiteral($this->element))); $this->element = '*'; } public function addStarPrefix() { if ($this->path) { $this->path .= '*/'; } else { $this->path = '*/'; } $this->starPrefix = true; } public function join($combiner, $other) { $prefix = (string) $this; $prefix .= $combiner; $path = $other->getPrefix().$other->getPath(); if ($other->hasStarPrefix() && '*/' == $path) { $path = ''; } $this->prefix = $prefix; $this->path = $path; $this->element = $other->getElement(); $this->condition = $other->GetCondition(); } static public function xpathLiteral($s) { if ($s instanceof Node\ElementNode) { $s = $s->formatElement(); } else { $s = (string) $s; } if (false === strpos($s, "'")) { return sprintf("'%s'", $s); } if (false === strpos($s, '"')) { return sprintf('"%s"', $s); } $string = $s; $parts = array(); while (true) { if (false !== $pos = strpos($string, "'")) { $parts[] = sprintf("'%s'", substr($string, 0, $pos)); $parts[] = "\"'\""; $string = substr($string, $pos + 1); } else { $parts[] = "'$string'"; break; } } return sprintf('concat(%s)', implode($parts, ', ')); } } items = $items; $this->prefix = $prefix; } public function __toString() { $prefix = $this->getPrefix(); $tmp = array(); foreach ($this->items as $i) { $tmp[] = sprintf('%s%s', $prefix, $i); } return implode($tmp, ' | '); } } uri = $uri; $this->add($node); } public function clear() { $this->removeAll($this); } public function add($node) { if ($node instanceof \DOMNodeList) { $this->addNodeList($node); } elseif (is_array($node)) { $this->addNodes($node); } elseif (is_string($node)) { $this->addContent($node); } elseif (is_object($node)) { $this->addNode($node); } } public function addContent($content, $type = null) { if (empty($type)) { $type = 'text/html'; } if (!preg_match('/(x|ht)ml/i', $type, $matches)) { return null; } $charset = 'ISO-8859-1'; if (false !== $pos = strpos($type, 'charset=')) { $charset = substr($type, $pos + 8); if (false !== $pos = strpos($charset, ';')) { $charset = substr($charset, 0, $pos); } } if ('x' === $matches[1]) { $this->addXmlContent($content, $charset); } else { $this->addHtmlContent($content, $charset); } } public function addHtmlContent($content, $charset = 'UTF-8') { $dom = new \DOMDocument('1.0', $charset); $dom->validateOnParse = true; $current = libxml_use_internal_errors(true); @$dom->loadHTML($content); libxml_use_internal_errors($current); $this->addDocument($dom); $base = $this->filterXPath('descendant-or-self::base')->extract(array('href')); if (count($base)) { $this->uri = current($base); } } public function addXmlContent($content, $charset = 'UTF-8') { $dom = new \DOMDocument('1.0', $charset); $dom->validateOnParse = true; $current = libxml_use_internal_errors(true); @$dom->loadXML(str_replace('xmlns', 'ns', $content)); libxml_use_internal_errors($current); $this->addDocument($dom); } public function addDocument(\DOMDocument $dom) { if ($dom->documentElement) { $this->addNode($dom->documentElement); } } public function addNodeList(\DOMNodeList $nodes) { foreach ($nodes as $node) { $this->addNode($node); } } public function addNodes(array $nodes) { foreach ($nodes as $node) { $this->add($node); } } public function addNode(\DOMNode $node) { if ($node instanceof \DOMDocument) { $this->attach($node->documentElement); } else { $this->attach($node); } } public function eq($position) { foreach ($this as $i => $node) { if ($i == $position) { return new static($node, $this->uri); } } return new static(null, $this->uri); } public function each(\Closure $closure) { $data = array(); foreach ($this as $i => $node) { $data[] = $closure($node, $i); } return $data; } public function reduce(\Closure $closure) { $nodes = array(); foreach ($this as $i => $node) { if (false !== $closure($node, $i)) { $nodes[] = $node; } } return new static($nodes, $this->uri); } public function first() { return $this->eq(0); } public function last() { return $this->eq(count($this) - 1); } public function siblings() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return new static($this->sibling($this->getNode(0)->parentNode->firstChild), $this->uri); } public function nextAll() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return new static($this->sibling($this->getNode(0)), $this->uri); } public function previousAll() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return new static($this->sibling($this->getNode(0), 'previousSibling'), $this->uri); } public function parents() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); $nodes = array(); while ($node = $node->parentNode) { if (1 === $node->nodeType && '_root' !== $node->nodeName) { $nodes[] = $node; } } return new static($nodes, $this->uri); } public function children() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return new static($this->sibling($this->getNode(0)->firstChild), $this->uri); } public function attr($attribute) { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->getNode(0)->getAttribute($attribute); } public function text() { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } return $this->getNode(0)->nodeValue; } public function extract($attributes) { $attributes = (array) $attributes; $data = array(); foreach ($this as $node) { $elements = array(); foreach ($attributes as $attribute) { if ('_text' === $attribute) { $elements[] = $node->nodeValue; } else { $elements[] = $node->getAttribute($attribute); } } $data[] = count($attributes) > 1 ? $elements : $elements[0]; } return $data; } public function filterXPath($xpath) { $document = new \DOMDocument('1.0', 'UTF-8'); $root = $document->appendChild($document->createElement('_root')); foreach ($this as $node) { $root->appendChild($document->importNode($node, true)); } $domxpath = new \DOMXPath($document); return new static($domxpath->query($xpath), $this->uri); } public function filter($selector) { if (!class_exists('Symfony\\Component\\CssSelector\\CssSelector')) { throw new \RuntimeException('Unable to filter with a CSS selector as the Symfony CssSelector is not installed (you can use filterXPath instead).'); } return $this->filterXPath(CssSelector::toXPath($selector)); } public function selectLink($value) { $xpath = sprintf('//a[contains(concat(\' \', normalize-space(string(.)), \' \'), %s)] ', static::xpathLiteral(' '.$value.' ')). sprintf('| //a/img[contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)]/ancestor::a', static::xpathLiteral(' '.$value.' ')); return $this->filterXPath($xpath); } public function selectButton($value) { $xpath = sprintf('//input[((@type="submit" or @type="button") and contains(concat(\' \', normalize-space(string(@value)), \' \'), %s)) ', static::xpathLiteral(' '.$value.' ')). sprintf('or (@type="image" and contains(concat(\' \', normalize-space(string(@alt)), \' \'), %s)) or @id="%s" or @name="%s"] ', static::xpathLiteral(' '.$value.' '), $value, $value). sprintf('| //button[contains(concat(\' \', normalize-space(string(.)), \' \'), %s) or @id="%s" or @name="%s"]', static::xpathLiteral(' '.$value.' '), $value, $value); return $this->filterXPath($xpath); } public function link($method = 'get') { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } $node = $this->getNode(0); return new Link($node, $this->uri, $method); } public function links() { $links = array(); foreach ($this as $node) { $links[] = new Link($node, $this->uri, 'get'); } return $links; } public function form(array $values = null, $method = null) { if (!count($this)) { throw new \InvalidArgumentException('The current node list is empty.'); } $form = new Form($this->getNode(0), $this->uri, $method); if (null !== $values) { $form->setValues($values); } return $form; } static public function xpathLiteral($s) { if (false === strpos($s, "'")) { return sprintf("'%s'", $s); } if (false === strpos($s, '"')) { return sprintf('"%s"', $s); } $string = $s; $parts = array(); while (true) { if (false !== $pos = strpos($string, "'")) { $parts[] = sprintf("'%s'", substr($string, 0, $pos)); $parts[] = "\"'\""; $string = substr($string, $pos + 1); } else { $parts[] = "'$string'"; break; } } return sprintf("concat(%s)", implode($parts, ', ')); } private function getNode($position) { foreach ($this as $i => $node) { if ($i == $position) { return $node; } } return null; } private function sibling($node, $siblingDir = 'nextSibling') { $nodes = array(); do { if ($node !== $this->getNode(0) && $node->nodeType === 1) { $nodes[] = $node; } } while ($node = $node->$siblingDir); return $nodes; } } type, array('checkbox', 'radio')) && null === $this->value) { return false; } return true; } public function isDisabled() { foreach ($this->options as $option) { if ($option['value'] == $this->value && $option['disabled']) { return true; } } return false; } public function select($value) { $this->setValue($value); } public function tick() { if ('checkbox' !== $this->type) { throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); } $this->setValue(true); } public function untick() { if ('checkbox' !== $this->type) { throw new \LogicException(sprintf('You cannot tick "%s" as it is not a checkbox (%s).', $this->name, $this->type)); } $this->setValue(false); } public function setValue($value) { if ('checkbox' == $this->type && false === $value) { $this->value = null; } elseif ('checkbox' == $this->type && true === $value) { $this->value = $this->options[0]['value']; } else { if (is_array($value)) { if (!$this->multiple) { throw new \InvalidArgumentException(sprintf('The value for "%s" cannot be an array.', $this->name)); } foreach ($value as $v) { if (!$this->containsOption($v, $this->options)) { throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $v, implode(', ', $this->availableOptionValues()))); } } } elseif (!$this->containsOption($value, $this->options)) { throw new \InvalidArgumentException(sprintf('Input "%s" cannot take "%s" as a value (possible values: %s).', $this->name, $value, implode(', ', $this->availableOptionValues()))); } if ($this->multiple) { $value = (array) $value; } if (is_array($value)) { $this->value = $value; } else { parent::setValue($value); } } } public function addChoice(\DOMNode $node) { if (!$this->multiple && 'radio' != $this->type) { throw new \LogicException(sprintf('Unable to add a choice for "%s" as it is not multiple or is not a radio button.', $this->name)); } $option = $this->buildOptionValue($node); $this->options[] = $option; if ($node->getAttribute('checked')) { $this->value = $option['value']; } } public function getType() { return $this->type; } public function isMultiple() { return $this->multiple; } protected function initialize() { if ('input' != $this->node->nodeName && 'select' != $this->node->nodeName) { throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input or select tag (%s given).', $this->node->nodeName)); } if ('input' == $this->node->nodeName && 'checkbox' != $this->node->getAttribute('type') && 'radio' != $this->node->getAttribute('type')) { throw new \LogicException(sprintf('A ChoiceFormField can only be created from an input tag with a type of checkbox or radio (given type is %s).', $this->node->getAttribute('type'))); } $this->value = null; $this->options = array(); $this->multiple = false; if ('input' == $this->node->nodeName) { $this->type = $this->node->getAttribute('type'); $optionValue = $this->buildOptionValue($this->node); $this->options[] = $optionValue; if ($this->node->getAttribute('checked')) { $this->value = $optionValue['value']; } } else { $this->type = 'select'; if ($this->node->hasAttribute('multiple')) { $this->multiple = true; $this->value = array(); $this->name = str_replace('[]', '', $this->name); } $found = false; foreach ($this->xpath->query('descendant::option', $this->node) as $option) { $this->options[] = $this->buildOptionValue($option); if ($option->getAttribute('selected')) { $found = true; if ($this->multiple) { $this->value[] = $option->getAttribute('value'); } else { $this->value = $option->getAttribute('value'); } } } $option = $this->xpath->query('descendant::option', $this->node)->item(0); if (!$found && !$this->multiple && $option instanceof \DOMElement) { $this->value = $option->getAttribute('value'); } } } private function buildOptionValue($node) { $option = array(); $defaultValue = (isset($node->nodeValue) && !empty($node->nodeValue)) ? $node->nodeValue : '1'; $option['value'] = $node->hasAttribute('value') ? $node->getAttribute('value') : $defaultValue; $option['disabled'] = ($node->hasAttribute('disabled') && $node->getAttribute('disabled') == 'disabled'); return $option; } public function containsOption($optionValue, $options) { foreach ($options as $option) { if ($option['value'] == $optionValue) { return true; } } return false; } public function availableOptionValues() { $values = array(); foreach ($this->options as $option) { $values[] = $option['value']; } return $values; } } value = array('name' => '', 'type' => '', 'tmp_name' => '', 'error' => $error, 'size' => 0); } public function upload($value) { $this->setValue($value); } public function setValue($value) { if (null !== $value && is_readable($value)) { $error = UPLOAD_ERR_OK; $size = filesize($value); $name = basename($value); $tmp = tempnam(sys_get_temp_dir(), 'upload'); unlink($tmp); copy($value, $tmp); $value = $tmp; } else { $error = UPLOAD_ERR_NO_FILE; $size = 0; $name = ''; $value = ''; } $this->value = array('name' => $name, 'type' => '', 'tmp_name' => $value, 'error' => $error, 'size' => $size); } protected function initialize() { if ('input' != $this->node->nodeName) { throw new \LogicException(sprintf('A FileFormField can only be created from an input tag (%s given).', $this->node->nodeName)); } if ('file' != $this->node->getAttribute('type')) { throw new \LogicException(sprintf('A FileFormField can only be created from an input tag with a type of file (given type is %s).', $this->node->getAttribute('type'))); } $this->setValue(null); } } node = $node; $this->name = $node->getAttribute('name'); $this->document = new \DOMDocument('1.0', 'UTF-8'); $this->node = $this->document->importNode($this->node, true); $root = $this->document->appendChild($this->document->createElement('_root')); $root->appendChild($this->node); $this->xpath = new \DOMXPath($this->document); $this->initialize(); } public function getName() { return $this->name; } public function getValue() { return $this->value; } public function setValue($value) { $this->value = (string) $value; } public function hasValue() { return true; } public function isDisabled() { return $this->node->hasAttribute('disabled'); } abstract protected function initialize(); } node->nodeName) { throw new \LogicException(sprintf('An InputFormField can only be created from an input tag (%s given).', $this->node->nodeName)); } if ('checkbox' == $this->node->getAttribute('type')) { throw new \LogicException('Checkboxes should be instances of ChoiceFormField.'); } if ('file' == $this->node->getAttribute('type')) { throw new \LogicException('File inputs should be instances of FileFormField.'); } $this->value = $this->node->getAttribute('value'); } } node->nodeName) { throw new \LogicException(sprintf('A TextareaFormField can only be created from a textarea tag (%s given).', $this->node->nodeName)); } $this->value = null; foreach ($this->node->childNodes as $node) { $this->value .= $this->document->saveXML($node); } } } initialize(); } public function getFormNode() { return $this->node; } public function setValues(array $values) { foreach ($values as $name => $value) { $this->fields->set($name, $value); } return $this; } public function getValues() { $values = array(); foreach ($this->fields->all() as $name => $field) { if ($field->isDisabled()) { continue; } if (!$field instanceof Field\FileFormField && $field->hasValue()) { $values[$name] = $field->getValue(); } } return $values; } public function getFiles() { if (!in_array($this->getMethod(), array('POST', 'PUT', 'DELETE', 'PATCH'))) { return array(); } $files = array(); foreach ($this->fields->all() as $name => $field) { if ($field->isDisabled()) { continue; } if ($field instanceof Field\FileFormField) { $files[$name] = $field->getValue(); } } return $files; } public function getPhpValues() { $qs = http_build_query($this->getValues(), '', '&'); parse_str($qs, $values); return $values; } public function getPhpFiles() { $qs = http_build_query($this->getFiles(), '', '&'); parse_str($qs, $values); return $values; } public function getUri() { $uri = parent::getUri(); if (!in_array($this->getMethod(), array('POST', 'PUT', 'DELETE', 'PATCH')) && $queryString = http_build_query($this->getValues(), null, '&')) { $sep = false === strpos($uri, '?') ? '?' : '&'; $uri .= $sep.$queryString; } return $uri; } protected function getRawUri() { return $this->node->getAttribute('action'); } public function getMethod() { if (null !== $this->method) { return $this->method; } return $this->node->getAttribute('method') ? strtoupper($this->node->getAttribute('method')) : 'GET'; } public function has($name) { return $this->fields->has($name); } public function remove($name) { $this->fields->remove($name); } public function get($name) { return $this->fields->get($name); } public function set(FormField $field) { $this->fields->add($field); } public function all() { return $this->fields->all(); } public function offsetExists($name) { return $this->has($name); } public function offsetGet($name) { return $this->fields->get($name); } public function offsetSet($name, $value) { $this->fields->set($name, $value); } public function offsetUnset($name) { $this->fields->remove($name); } protected function setNode(\DOMNode $node) { $this->button = $node; if ('button' == $node->nodeName || ('input' == $node->nodeName && in_array($node->getAttribute('type'), array('submit', 'button', 'image')))) { do { if (null === $node = $node->parentNode) { throw new \LogicException('The selected node does not have a form ancestor.'); } } while ('form' != $node->nodeName); } elseif('form' != $node->nodeName) { throw new \LogicException(sprintf('Unable to submit on a "%s" tag.', $node->nodeName)); } $this->node = $node; } private function initialize() { $this->fields = new FormFieldRegistry(); $document = new \DOMDocument('1.0', 'UTF-8'); $node = $document->importNode($this->node, true); $button = $document->importNode($this->button, true); $root = $document->appendChild($document->createElement('_root')); $root->appendChild($node); $root->appendChild($button); $xpath = new \DOMXPath($document); foreach ($xpath->query('descendant::input | descendant::textarea | descendant::select', $root) as $node) { if (!$node->hasAttribute('name')) { continue; } $nodeName = $node->nodeName; if ($node === $button) { $this->set(new Field\InputFormField($node)); } elseif ('select' == $nodeName || 'input' == $nodeName && 'checkbox' == $node->getAttribute('type')) { $this->set(new Field\ChoiceFormField($node)); } elseif ('input' == $nodeName && 'radio' == $node->getAttribute('type')) { if ($this->has($node->getAttribute('name'))) { $this->get($node->getAttribute('name'))->addChoice($node); } else { $this->set(new Field\ChoiceFormField($node)); } } elseif ('input' == $nodeName && 'file' == $node->getAttribute('type')) { $this->set(new Field\FileFormField($node)); } elseif ('input' == $nodeName && !in_array($node->getAttribute('type'), array('submit', 'button', 'image'))) { $this->set(new Field\InputFormField($node)); } elseif ('textarea' == $nodeName) { $this->set(new Field\TextareaFormField($node)); } } } } class FormFieldRegistry { private $fields = array(); private $base; public function add(FormField $field) { $segments = $this->getSegments($field->getName()); $target =& $this->fields; while ($segments) { if (!is_array($target)) { $target = array(); } $path = array_shift($segments); if ('' === $path) { $target =& $target[]; } else { $target =& $target[$path]; } } $target = $field; } public function remove($name) { $segments = $this->getSegments($name); $target =& $this->fields; while (count($segments) > 1) { $path = array_shift($segments); if (!array_key_exists($path, $target)) { return; } $target =& $target[$path]; } unset($target[array_shift($segments)]); } public function &get($name) { $segments = $this->getSegments($name); $target =& $this->fields; while ($segments) { $path = array_shift($segments); if (!array_key_exists($path, $target)) { throw new \InvalidArgumentException(sprintf('Unreachable field "%s"', $path)); } $target =& $target[$path]; } return $target; } public function has($name) { try { $this->get($name); return true; } catch (\InvalidArgumentException $e) { return false; } } public function set($name, $value) { $target =& $this->get($name); if (is_array($value)) { $fields = self::create($name, $value); foreach ($fields->all() as $k => $v) { $this->set($k, $v); } } else { $target->setValue($value); } } public function all() { return $this->walk($this->fields, $this->base); } static private function create($base, array $values) { $registry = new static(); $registry->base = $base; $registry->fields = $values; return $registry; } private function walk(array $array, $base = '', array &$output = array()) { foreach ($array as $k => $v) { $path = empty($base) ? $k : sprintf("%s[%s]", $base, $k); if (is_array($v)) { $this->walk($v, $path, $output); } else { $output[$path] = $v; } } return $output; } private function getSegments($name) { if (preg_match('/^(?P[^[]+)(?P(\[.*)|$)/', $name, $m)) { $segments = array($m['base']); while (preg_match('/^\[(?P.*?)\](?P.*)$/', $m['extra'], $m)) { $segments[] = $m['segment']; } return $segments; } throw new \InvalidArgumentException(sprintf('Malformed field path "%s"', $name)); } } setNode($node); $this->method = $method ? strtoupper($method) : null; $this->currentUri = $currentUri; } public function getNode() { return $this->node; } public function getMethod() { return $this->method; } public function getUri() { $uri = trim($this->getRawUri()); if (0 === strpos($uri, 'http')) { return $uri; } if (!$uri) { return $this->currentUri; } if ('#' === $uri[0]) { $baseUri = $this->currentUri; if (false !== $pos = strpos($baseUri, '#')) { $baseUri = substr($baseUri, 0, $pos); } return $baseUri.$uri; } if ('?' === $uri[0]) { $baseUri = $this->currentUri; if (false !== $pos = strpos($baseUri, '?')) { $baseUri = substr($baseUri, 0, $pos); } return $baseUri.$uri; } if ('/' === $uri[0]) { return preg_replace('#^(.*?//[^/]+)(?:\/.*)?$#', '$1', $this->currentUri).$uri; } return substr($this->currentUri, 0, strrpos($this->currentUri, '/') + 1).$uri; } protected function getRawUri() { return $this->node->getAttribute('href'); } protected function setNode(\DOMNode $node) { if ('a' != $node->nodeName) { throw new \LogicException(sprintf('Unable to click on a "%s" tag.', $node->nodeName)); } $this->node = $node; } } Copyright (c) 2010 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. $path) { $loader->add($namespace, $path); } $classMap = require $composerDir . '/autoload_classmap.php'; if ($classMap) { $loader->addClassMap($classMap); } $loader->register(); return $loader; }); prefixes; } public function getFallbackDirs() { return $this->fallbackDirs; } public function getClassMap() { return $this->classMap; } public function addClassMap(array $classMap) { if ($this->classMap) { $this->classMap = array_merge($this->classMap, $classMap); } else { $this->classMap = $classMap; } } public function add($prefix, $paths) { if (!$prefix) { foreach ((array) $paths as $path) { $this->fallbackDirs[] = $path; } return; } if (isset($this->prefixes[$prefix])) { $this->prefixes[$prefix] = array_merge( $this->prefixes[$prefix], (array) $paths ); } else { $this->prefixes[$prefix] = (array) $paths; } } public function setUseIncludePath($useIncludePath) { $this->useIncludePath = $useIncludePath; } public function getUseIncludePath() { return $this->useIncludePath; } public function register($prepend = false) { spl_autoload_register(array($this, 'loadClass'), true, $prepend); } public function unregister() { spl_autoload_unregister(array($this, 'loadClass')); } public function loadClass($class) { if ($file = $this->findFile($class)) { require $file; return true; } } public function findFile($class) { if (isset($this->classMap[$class])) { return $this->classMap[$class]; } if ('\\' == $class[0]) { $class = substr($class, 1); } if (false !== $pos = strrpos($class, '\\')) { $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR; $className = substr($class, $pos + 1); } else { $classPath = null; $className = $class; } $classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php'; foreach ($this->prefixes as $prefix => $dirs) { if (0 === strpos($class, $prefix)) { foreach ($dirs as $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { return $dir . DIRECTORY_SEPARATOR . $classPath; } } } } foreach ($this->fallbackDirs as $dir) { if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) { return $dir . DIRECTORY_SEPARATOR . $classPath; } } if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) { return $file; } } } $baseDir . '/vendor/twig/twig/lib/', 'Symfony\\Component\\Validator' => $baseDir . '/vendor/symfony/validator/', 'Symfony\\Component\\Translation' => $baseDir . '/vendor/symfony/translation/', 'Symfony\\Component\\Routing' => $baseDir . '/vendor/symfony/routing/', 'Symfony\\Component\\Process' => $baseDir . '/vendor/symfony/process/', 'Symfony\\Component\\Locale' => $baseDir . '/vendor/symfony/locale/', 'Symfony\\Component\\HttpKernel' => $baseDir . '/vendor/symfony/http-kernel/', 'Symfony\\Component\\HttpFoundation' => $baseDir . '/vendor/symfony/http-foundation/', 'Symfony\\Component\\Form' => $baseDir . '/vendor/symfony/form/', 'Symfony\\Component\\Finder' => $baseDir . '/vendor/symfony/finder/', 'Symfony\\Component\\EventDispatcher' => $baseDir . '/vendor/symfony/event-dispatcher/', 'Symfony\\Component\\DomCrawler' => $baseDir . '/vendor/symfony/dom-crawler/', 'Symfony\\Component\\CssSelector' => $baseDir . '/vendor/symfony/css-selector/', 'Symfony\\Component\\ClassLoader' => $baseDir . '/vendor/symfony/class-loader/', 'Symfony\\Component\\BrowserKit' => $baseDir . '/vendor/symfony/browser-kit/', 'Symfony\\Bridge\\Twig' => $baseDir . '/vendor/symfony/twig-bridge/', 'Silex' => $baseDir . '/src/', 'SessionHandlerInterface' => $baseDir . '/vendor/symfony/http-foundation/Symfony/Component/HttpFoundation/Resources/stubs', 'Pimple' => $baseDir . '/vendor/pimple/pimple/lib/', 'Monolog' => $baseDir . '/vendor/monolog/monolog/src/', 'Doctrine\\DBAL' => $baseDir . '/vendor/doctrine/dbal/lib/', 'Doctrine\\Common' => $baseDir . '/vendor/doctrine/common/lib/', );
{% include 'menu.twig' %}
{{ file }}
{% for commit, blame in blames %} {% endfor %}
{{ commit }}
{{ blame.line }}

{% include 'footer.twig' %} {% endblock %} views/branch_menu.twig000066400000000000000000000011451516067305400154000ustar00rootroot00000000000000
views/commit.twig000066400000000000000000000042601516067305400144100ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% include 'menu.twig' %}
Browse code

{{ commit.getMessage }}

{{ commit.getAuthor.getName }} authored in {{ commit.getDate | date('d/m/Y \\a\\t H:i:s') }}
Showing {{ commit.getChangedFiles }} changed files
{% for diff in commit.getDiffs %}
{% for line in diff.getLines %} {{ line.getLine }} {% endfor %}
{% endfor %}
{% include 'footer.twig' %}
{% endblock %} views/commits.twig000066400000000000000000000035421516067305400145750ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% include 'branch_menu.twig' %} {% include 'menu.twig' %}
{% for date, commit in commits %} {% for item in commit %} {% endfor %}
{{ date | date("F j, Y") }}
View {{ item.getShortHash }}

{{ item.getMessage }}

{{ item.getAuthor.getName }} authored in {{ item.getDate | date('d/m/Y \\a\\t H:i:s') }}
{% endfor %}
    {% if pager.current != 0 %} {% endif %} {% if pager.current != pager.last %} {% endif %}

{% include 'footer.twig' %}
{% endblock %} views/error.twig000066400000000000000000000004541516067305400142520ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
Oops! {{ message }}

{% include 'footer.twig' %}
{% endblock %} views/file.twig000066400000000000000000000033251516067305400140400ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% include 'branch_menu.twig' %} {% include 'menu.twig' %}
{% if fileType == 'image' %}
{{ file }}
{% else %} {% endif %}

{% include 'footer.twig' %}
{% endblock %} views/footer.twig000066400000000000000000000001501516067305400144100ustar00rootroot00000000000000 views/index.twig000066400000000000000000000013051516067305400142240ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% for repository in repositories %}

{{ repository.description }}

{% endfor %}
{% include 'footer.twig' %}
{% endblock %} views/layout.twig000066400000000000000000000012441516067305400144340ustar00rootroot00000000000000 {% block title %}Welcome!{% endblock %} {% block body %}{% endblock %} views/menu.twig000066400000000000000000000006411516067305400140630ustar00rootroot00000000000000views/navigation.twig000066400000000000000000000015331516067305400152570ustar00rootroot00000000000000 views/rss.twig000066400000000000000000000012741516067305400137310ustar00rootroot00000000000000 Latest commits in {{ repo }}:{{ branch }} RSS provided by Gitlist {{ baseurl }}/ {% for commit in commits %} {{ commit.getMessage }} {{ commit.getAuthor.getName }} authored {{ commit.getShortHash }} in {{ commit.getDate | date('d/m/Y \\a\\t H:i:s') }} {{ baseurl }}/{{ repo }}/commit/{{ commit.getShortHash }} {{ commit.getDate | date('r') }} {% endfor %} views/stats.twig000066400000000000000000000035061516067305400142600ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% include 'branch_menu.twig' %} {% include 'menu.twig' %}
File extensions ({{ stats.extensions|length }}) Authors ({{ authors|length }}) Other
    {% for ext, amount in stats.extensions %}
  • {{ ext }}: {{ amount }} files
  • {% endfor %}
    {% for author in authors %}
  • {{ author.name }}: {{ author.commits }} commits
  • {% endfor %}

Total files: {{ stats.files }}

Total bytes: {{ stats.size }} bytes ({{ ((stats.size / 1024) / 1024) | number_format }} MB)


{% include 'footer.twig' %}
{% endblock %} views/tree.twig000066400000000000000000000037701516067305400140640ustar00rootroot00000000000000{% extends 'layout.twig' %} {% block title %}Gitlist{% endblock %} {% block body %} {% include 'navigation.twig' %}
{% include 'branch_menu.twig' %} {% include 'menu.twig' %}
{% if parent is not empty %} {% endif %} {% for file in files %} {% endfor %}
name mode size
..
{{ file.name }} {{ file.mode }} {% if file.size %}{{ (file.size / 1024) | number_format }} kb{% endif %}

{% include 'footer.twig' %}
{% endblock %} web/000077500000000000000000000000001516067305400116425ustar00rootroot00000000000000web/Makefile000077500000000000000000000001001516067305400132740ustar00rootroot00000000000000bootstrap: lessc --compress less/bootstrap.less > css/style.cssweb/css/000077500000000000000000000000001516067305400124325ustar00rootroot00000000000000web/css/style.css000066400000000000000000002657351516067305400143260ustar00rootroot00000000000000article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} audio:not([controls]){display:none;} html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} a:hover,a:active{outline:0;} sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} sup{top:-0.5em;} sub{bottom:-0.25em;} img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;} button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} button,input{*overflow:visible;line-height:normal;} button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;} input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;} input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} textarea{overflow:auto;vertical-align:top;} .clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";} .clearfix:after{clear:both;} .hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} .input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;padding-top:60px;padding-bottom:40px;} a{color:#4183c4;text-decoration:none;} a:hover{color:#2c5d8d;text-decoration:underline;} .row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} .span12{width:940px;} .span11{width:860px;} .span10{width:780px;} .span9{width:700px;} .span8{width:620px;} .span7{width:540px;} .span6{width:460px;} .span5{width:380px;} .span4{width:300px;} .span3{width:220px;} .span2{width:140px;} .span1{width:60px;} .offset12{margin-left:980px;} .offset11{margin-left:900px;} .offset10{margin-left:820px;} .offset9{margin-left:740px;} .offset8{margin-left:660px;} .offset7{margin-left:580px;} .offset6{margin-left:500px;} .offset5{margin-left:420px;} .offset4{margin-left:340px;} .offset3{margin-left:260px;} .offset2{margin-left:180px;} .offset1{margin-left:100px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574%;*margin-left:2.0744680846382977%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%;} .row-fluid .span11{width:91.489361693%;*width:91.4361702036383%;} .row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%;} .row-fluid .span9{width:74.468085099%;*width:74.4148936096383%;} .row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%;} .row-fluid .span7{width:57.446808505%;*width:57.3936170156383%;} .row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%;} .row-fluid .span5{width:40.425531911%;*width:40.3723404216383%;} .row-fluid .span4{width:31.914893614%;*width:31.8617021246383%;} .row-fluid .span3{width:23.404255317%;*width:23.3510638276383%;} .row-fluid .span2{width:14.89361702%;*width:14.8404255306383%;} .row-fluid .span1{width:6.382978723%;*width:6.329787233638298%;} .container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";} .container:after{clear:both;} .container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";} .container-fluid:after{clear:both;} p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;} .lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;} h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;} h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;} h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;} h3{font-size:18px;line-height:27px;}h3 small{font-size:14px;} h4,h5,h6{line-height:18px;} h4{font-size:14px;}h4 small{font-size:12px;} h5{font-size:12px;} h6{font-size:11px;color:#999999;text-transform:uppercase;} .page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;} .page-header h1{line-height:1;} ul,ol{padding:0;margin:0 0 9px 25px;} ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} ul{list-style:disc;} ol{list-style:decimal;} li{line-height:18px;} ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} dl{margin-bottom:18px;} dt,dd{line-height:18px;} dt{font-weight:bold;line-height:17px;} dd{margin-left:9px;} .dl-horizontal dt{float:left;width:120px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} .dl-horizontal dd{margin-left:130px;} hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} strong{font-weight:bold;} em{font-style:italic;} .muted{color:#999999;} abbr[title]{cursor:help;border-bottom:1px dotted #ddd;} abbr.initialism{font-size:90%;text-transform:uppercase;} blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;} blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} q:before,q:after,blockquote:before,blockquote:after{content:"";} address{display:block;margin-bottom:18px;font-style:normal;line-height:18px;} small{font-size:100%;} cite{font-style:normal;} code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;} pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:18px;} pre code{padding:0;color:inherit;background-color:transparent;border:0;} .pre-scrollable{max-height:340px;overflow-y:scroll;} form{margin:0 0 18px;} fieldset{padding:0;margin:0;border:0;} legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;} label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;} input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} label{display:block;margin-bottom:5px;color:#333333;} input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;background-color:#ffffff;border:1px solid #cccccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .uneditable-textarea{width:auto;height:auto;} label input,label textarea,label select{display:block;} input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;background-color:transparent;border:0 \9;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} input[type="image"]{border:0;} input[type="file"]{width:auto;padding:initial;line-height:initial;background-color:#ffffff;background-color:initial;border:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;} select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;} input[type="file"]{line-height:18px \9;} select{width:220px;background-color:#ffffff;} select[multiple],select[size]{height:auto;} input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} textarea{height:auto;} input[type="hidden"]{display:none;} .radio,.checkbox{min-height:18px;padding-left:18px;} .radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;} .controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} .radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} .radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;} input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);} input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .input-mini{width:60px;} .input-small{width:90px;} .input-medium{width:150px;} .input-large{width:210px;} .input-xlarge{width:270px;} .input-xxlarge{width:530px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;} input,textarea,.uneditable-input{margin-left:0;} input.span12, textarea.span12, .uneditable-input.span12{width:930px;} input.span11, textarea.span11, .uneditable-input.span11{width:850px;} input.span10, textarea.span10, .uneditable-input.span10{width:770px;} input.span9, textarea.span9, .uneditable-input.span9{width:690px;} input.span8, textarea.span8, .uneditable-input.span8{width:610px;} input.span7, textarea.span7, .uneditable-input.span7{width:530px;} input.span6, textarea.span6, .uneditable-input.span6{width:450px;} input.span5, textarea.span5, .uneditable-input.span5{width:370px;} input.span4, textarea.span4, .uneditable-input.span4{width:290px;} input.span3, textarea.span3, .uneditable-input.span3{width:210px;} input.span2, textarea.span2, .uneditable-input.span2{width:130px;} input.span1, textarea.span1, .uneditable-input.span1{width:50px;} input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;border-color:#ddd;} input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;} .control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} .control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;} .control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} .control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} .control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;} .control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} .control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} .control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;} .control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} .form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";} .form-actions:after{clear:both;} .uneditable-input{overflow:hidden;white-space:nowrap;cursor:not-allowed;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);} :-moz-placeholder{color:#999999;} ::-webkit-input-placeholder{color:#999999;} .help-block,.help-inline{color:#555555;} .help-block{display:block;margin-bottom:9px;} .help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} .input-prepend,.input-append{margin-bottom:5px;}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:middle;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{z-index:2;} .input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;} .input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;height:18px;min-width:16px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #ffffff;vertical-align:middle;background-color:#eeeeee;border:1px solid #ccc;} .input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;} .input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} .input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-append .uneditable-input{border-right-color:#ccc;border-left-color:#eee;} .input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;} .form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;} .form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} .form-search label,.form-inline label{display:inline-block;} .form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} .form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} .form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;} .control-group{margin-bottom:9px;} legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;} .form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";} .form-horizontal .control-group:after{clear:both;} .form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;} .form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:160px;} .form-horizontal .help-block{margin-top:9px;margin-bottom:0;} .form-horizontal .form-actions{padding-left:160px;} table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;} .table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} .table th{font-weight:bold;} .table thead th{vertical-align:bottom;} .table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} .table tbody+tbody{border-top:2px solid #dddddd;} .table-condensed th,.table-condensed td{padding:4px 5px;} .table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} .table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} .table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;} .table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;} .table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;} .table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;} .table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;} .table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;} table .span1{float:none;width:44px;margin-left:0;} table .span2{float:none;width:124px;margin-left:0;} table .span3{float:none;width:204px;margin-left:0;} table .span4{float:none;width:284px;margin-left:0;} table .span5{float:none;width:364px;margin-left:0;} table .span6{float:none;width:444px;margin-left:0;} table .span7{float:none;width:524px;margin-left:0;} table .span8{float:none;width:604px;margin-left:0;} table .span9{float:none;width:684px;margin-left:0;} table .span10{float:none;width:764px;margin-left:0;} table .span11{float:none;width:844px;margin-left:0;} table .span12{float:none;width:924px;margin-left:0;} table .span13{float:none;width:1004px;margin-left:0;} table .span14{float:none;width:1084px;margin-left:0;} table .span15{float:none;width:1164px;margin-left:0;} table .span16{float:none;width:1244px;margin-left:0;} table .span17{float:none;width:1324px;margin-left:0;} table .span18{float:none;width:1404px;margin-left:0;} table .span19{float:none;width:1484px;margin-left:0;} table .span20{float:none;width:1564px;margin-left:0;} table .span21{float:none;width:1644px;margin-left:0;} table .span22{float:none;width:1724px;margin-left:0;} table .span23{float:none;width:1804px;margin-left:0;} table .span24{float:none;width:1884px;margin-left:0;} .tree{width:100%;margin-bottom:18px;border:1px solid #cacaca;}.tree thead th{padding:8px;line-height:18px;text-align:left;vertical-align:bottom;background-color:#f4f4f4;background-image:-moz-linear-gradient(top, #fafafa, #eaeaea);background-image:-ms-linear-gradient(top, #fafafa, #eaeaea);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#eaeaea));background-image:-webkit-linear-gradient(top, #fafafa, #eaeaea);background-image:-o-linear-gradient(top, #fafafa, #eaeaea);background-image:linear-gradient(top, #fafafa, #eaeaea);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafa', endColorstr='#eaeaea', GradientType=0);border-bottom:1px solid #d7d7d7;font-weight:bold;color:#555555;text-shadow:1px 1px 1px #ffffff;} .tree tbody td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-bottom:1px solid #EEE;background-color:#F8F8F8;} .tree caption+thead tr:first-child th,.tree caption+thead tr:first-child td,.tree colgroup+thead tr:first-child th,.tree colgroup+thead tr:first-child td,.tree thead:first-child tr:first-child th,.tree thead:first-child tr:first-child td{border-top:0;} .tree tbody tr:last-child td{border-bottom:0;} .source-view{width:100%;margin-bottom:18px;border:1px solid #cacaca;}.source-view .source-header{padding:8px;line-height:18px;text-align:left;vertical-align:bottom;background-color:#f4f4f4;background-image:-moz-linear-gradient(top, #fafafa, #eaeaea);background-image:-ms-linear-gradient(top, #fafafa, #eaeaea);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#eaeaea));background-image:-webkit-linear-gradient(top, #fafafa, #eaeaea);background-image:-o-linear-gradient(top, #fafafa, #eaeaea);background-image:linear-gradient(top, #fafafa, #eaeaea);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafa', endColorstr='#eaeaea', GradientType=0);border-bottom:1px solid #d7d7d7;font-weight:bold;color:#555555;text-shadow:1px 1px 1px #ffffff;height:28px;}.source-view .source-header .meta{float:left;padding:4px 0;font-size:14px;} .source-view pre{margin:0;padding:12px;border:none;} .source-view #sourcecode{margin:0;padding:0;border:none;width:100%;height:600px;} .source-view .source-diff{background-color:#f5f5f5;padding:12px;}.source-view .source-diff pre{margin:0;padding:0;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .source-view .source-diff .new{background-color:#DFD;} .source-view .source-diff .old{background-color:#FDD;} .source-view .source-diff .chunk{background-color:#e8e8e8;color:#999999;} .source-view .image-blob{padding:10px;max-width:600px;} .blame-view{width:100%;background-color:#f5f5f5;}.blame-view td{vertical-align:top;padding:8px;} .blame-view tr{border-bottom:1px solid #cccccc;} .blame-view tr:last-child{border-bottom:0;} .blame-view .line{font-weight:700;border-right:1px solid #cccccc;} .blame-view .commit{font-weight:700;border-right:1px solid #cccccc;} .blame-view pre{margin:0;padding:0;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .commit-view{width:100%;margin-bottom:18px;border:1px solid #cacaca;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.commit-view .commit-header{padding:8px;line-height:18px;text-align:left;vertical-align:bottom;background-color:#f4f4f4;background-image:-moz-linear-gradient(top, #fafafa, #eaeaea);background-image:-ms-linear-gradient(top, #fafafa, #eaeaea);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#eaeaea));background-image:-webkit-linear-gradient(top, #fafafa, #eaeaea);background-image:-o-linear-gradient(top, #fafafa, #eaeaea);background-image:linear-gradient(top, #fafafa, #eaeaea);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafa', endColorstr='#eaeaea', GradientType=0);border-bottom:1px solid #d7d7d7;font-weight:bold;text-shadow:1px 1px 1px #ffffff;height:28px;}.commit-view .commit-header h4{padding:4px 0;} .commit-view .commit-body{padding:8px;} .commit-list{list-style-type:none;}.commit-list li{padding:8px 5px 8px 5px;font-size:14px;font-weight:700;border-bottom:1px solid #d7d7d7;}.commit-list li .meta{font-weight:normal;font-size:14px;color:#999999;} .commit-list li:last-child{border-bottom:0;margin-bottom:25px;} .repository{margin-bottom:18px;border:1px solid #d7d7d7;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.repository .repository-header{border-bottom:1px solid #d7d7d7;text-shadow:1px 1px 1px #ffffff;padding:8px;font-weight:700;font-size:14px;} .repository .repository-body{padding:8px;background-color:#f7f7f7;}.repository .repository-body p{margin:0;} .rss{display:inline-block;width:16px;height:16px;*margin-right:.3em;line-height:16px;vertical-align:text-top;background-image:url("../img/feed.png");background-position:0 0;background-repeat:no-repeat;}.rss:last-child{*margin-left:0;} [class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;} .icon-white{background-image:url("../img/glyphicons-halflings-white.png");} .icon-spaced{padding:0 3px 0 3px;} .icon-glass{background-position:0 0;} .icon-music{background-position:-24px 0;} .icon-search{background-position:-48px 0;} .icon-envelope{background-position:-72px 0;} .icon-heart{background-position:-96px 0;} .icon-star{background-position:-120px 0;} .icon-star-empty{background-position:-144px 0;} .icon-user{background-position:-168px 0;} .icon-film{background-position:-192px 0;} .icon-th-large{background-position:-216px 0;} .icon-th{background-position:-240px 0;} .icon-th-list{background-position:-264px 0;} .icon-ok{background-position:-288px 0;} .icon-remove{background-position:-312px 0;} .icon-zoom-in{background-position:-336px 0;} .icon-zoom-out{background-position:-360px 0;} .icon-off{background-position:-384px 0;} .icon-signal{background-position:-408px 0;} .icon-cog{background-position:-432px 0;} .icon-trash{background-position:-456px 0;} .icon-home{background-position:0 -24px;} .icon-file{background-position:-24px -24px;} .icon-time{background-position:-48px -24px;} .icon-road{background-position:-72px -24px;} .icon-download-alt{background-position:-96px -24px;} .icon-download{background-position:-120px -24px;} .icon-upload{background-position:-144px -24px;} .icon-inbox{background-position:-168px -24px;} .icon-play-circle{background-position:-192px -24px;} .icon-repeat{background-position:-216px -24px;} .icon-refresh{background-position:-240px -24px;} .icon-list-alt{background-position:-264px -24px;} .icon-lock{background-position:-287px -24px;} .icon-flag{background-position:-312px -24px;} .icon-headphones{background-position:-336px -24px;} .icon-volume-off{background-position:-360px -24px;} .icon-volume-down{background-position:-384px -24px;} .icon-volume-up{background-position:-408px -24px;} .icon-qrcode{background-position:-432px -24px;} .icon-barcode{background-position:-456px -24px;} .icon-tag{background-position:0 -48px;} .icon-tags{background-position:-25px -48px;} .icon-book{background-position:-48px -48px;} .icon-bookmark{background-position:-72px -48px;} .icon-print{background-position:-96px -48px;} .icon-camera{background-position:-120px -48px;} .icon-font{background-position:-144px -48px;} .icon-bold{background-position:-167px -48px;} .icon-italic{background-position:-192px -48px;} .icon-text-height{background-position:-216px -48px;} .icon-text-width{background-position:-240px -48px;} .icon-align-left{background-position:-264px -48px;} .icon-align-center{background-position:-288px -48px;} .icon-align-right{background-position:-312px -48px;} .icon-align-justify{background-position:-336px -48px;} .icon-list{background-position:-360px -48px;} .icon-indent-left{background-position:-384px -48px;} .icon-indent-right{background-position:-408px -48px;} .icon-facetime-video{background-position:-432px -48px;} .icon-picture{background-position:-456px -48px;} .icon-pencil{background-position:0 -72px;} .icon-map-marker{background-position:-24px -72px;} .icon-adjust{background-position:-48px -72px;} .icon-tint{background-position:-72px -72px;} .icon-edit{background-position:-96px -72px;} .icon-share{background-position:-120px -72px;} .icon-check{background-position:-144px -72px;} .icon-move{background-position:-168px -72px;} .icon-step-backward{background-position:-192px -72px;} .icon-fast-backward{background-position:-216px -72px;} .icon-backward{background-position:-240px -72px;} .icon-play{background-position:-264px -72px;} .icon-pause{background-position:-288px -72px;} .icon-stop{background-position:-312px -72px;} .icon-forward{background-position:-336px -72px;} .icon-fast-forward{background-position:-360px -72px;} .icon-step-forward{background-position:-384px -72px;} .icon-eject{background-position:-408px -72px;} .icon-chevron-left{background-position:-432px -72px;} .icon-chevron-right{background-position:-456px -72px;} .icon-plus-sign{background-position:0 -96px;} .icon-minus-sign{background-position:-24px -96px;} .icon-remove-sign{background-position:-48px -96px;} .icon-ok-sign{background-position:-72px -96px;} .icon-question-sign{background-position:-96px -96px;} .icon-info-sign{background-position:-120px -96px;} .icon-screenshot{background-position:-144px -96px;} .icon-remove-circle{background-position:-168px -96px;} .icon-ok-circle{background-position:-192px -96px;} .icon-ban-circle{background-position:-216px -96px;} .icon-arrow-left{background-position:-240px -96px;} .icon-arrow-right{background-position:-264px -96px;} .icon-arrow-up{background-position:-289px -96px;} .icon-arrow-down{background-position:-312px -96px;} .icon-share-alt{background-position:-336px -96px;} .icon-resize-full{background-position:-360px -96px;} .icon-resize-small{background-position:-384px -96px;} .icon-plus{background-position:-408px -96px;} .icon-minus{background-position:-433px -96px;} .icon-asterisk{background-position:-456px -96px;} .icon-exclamation-sign{background-position:0 -120px;} .icon-gift{background-position:-24px -120px;} .icon-leaf{background-position:-48px -120px;} .icon-fire{background-position:-72px -120px;} .icon-eye-open{background-position:-96px -120px;} .icon-eye-close{background-position:-120px -120px;} .icon-warning-sign{background-position:-144px -120px;} .icon-plane{background-position:-168px -120px;} .icon-calendar{background-position:-192px -120px;} .icon-random{background-position:-216px -120px;} .icon-comment{background-position:-240px -120px;} .icon-magnet{background-position:-264px -120px;} .icon-chevron-up{background-position:-288px -120px;} .icon-chevron-down{background-position:-313px -119px;} .icon-retweet{background-position:-336px -120px;} .icon-shopping-cart{background-position:-360px -120px;} .icon-folder-close{background-position:-384px -120px;} .icon-folder-open{background-position:-408px -120px;} .icon-resize-vertical{background-position:-432px -119px;} .icon-resize-horizontal{background-position:-456px -118px;} .icon-hdd{background-position:0 -144px;} .icon-bullhorn{background-position:-24px -144px;} .icon-bell{background-position:-48px -144px;} .icon-certificate{background-position:-72px -144px;} .icon-thumbs-up{background-position:-96px -144px;} .icon-thumbs-down{background-position:-120px -144px;} .icon-hand-right{background-position:-144px -144px;} .icon-hand-left{background-position:-168px -144px;} .icon-hand-up{background-position:-192px -144px;} .icon-hand-down{background-position:-216px -144px;} .icon-circle-arrow-right{background-position:-240px -144px;} .icon-circle-arrow-left{background-position:-264px -144px;} .icon-circle-arrow-up{background-position:-288px -144px;} .icon-circle-arrow-down{background-position:-312px -144px;} .icon-globe{background-position:-336px -144px;} .icon-wrench{background-position:-360px -144px;} .icon-tasks{background-position:-384px -144px;} .icon-filter{background-position:-408px -144px;} .icon-briefcase{background-position:-432px -144px;} .icon-fullscreen{background-position:-456px -144px;} .dropup,.dropdown{position:relative;} .dropdown-toggle{*margin-bottom:-3px;} .dropdown-toggle:active,.open .dropdown-toggle{outline:0;} .caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";opacity:0.3;filter:alpha(opacity=30);} .dropdown .caret{margin-top:8px;margin-left:2px;} .dropdown:hover .caret,.open .caret{opacity:1;filter:alpha(opacity=100);} .dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:4px 0;margin:1px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;} .dropdown-menu .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} .dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333333;white-space:nowrap;} .dropdown-menu .dropdown-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} .dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#4183c4;} .open{*z-index:1000;}.open .dropdown-menu{display:block;} .pull-right .dropdown-menu{right:0;left:auto;} .dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"\2191";} .dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} .typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} .well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} .well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .fade{opacity:0;filter:alpha(opacity=0);-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;filter:alpha(opacity=100);} .collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;} .close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);} button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;} .btn{display:inline-block;*display:inline;*zoom:1;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;*line-height:20px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;*background-color:#d9d9d9;} .btn:active,.btn.active{background-color:#cccccc \9;} .btn:first-child{*margin-left:0;} .btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} .btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} .btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} .btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} .btn-large [class^="icon-"]{margin-top:1px;} .btn-small{padding:5px 9px;font-size:11px;line-height:16px;} .btn-small [class^="icon-"]{margin-top:-1px;} .btn-mini{padding:2px 6px;font-size:11px;line-height:14px;} .btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);} .btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} .btn{border-color:#ccc;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);} .btn-primary{background-color:#417ac4;background-image:-moz-linear-gradient(top, #4183c4, #416dc4);background-image:-ms-linear-gradient(top, #4183c4, #416dc4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#4183c4), to(#416dc4));background-image:-webkit-linear-gradient(top, #4183c4, #416dc4);background-image:-o-linear-gradient(top, #4183c4, #416dc4);background-image:linear-gradient(top, #4183c4, #416dc4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#4183c4', endColorstr='#416dc4', GradientType=0);border-color:#416dc4 #416dc4 #2c4c8d;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#416dc4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#416dc4;*background-color:#3862b4;} .btn-primary:active,.btn-primary.active{background-color:#3257a0 \9;} .btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;*background-color:#df8505;} .btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} .btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;*background-color:#a9302a;} .btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} .btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;*background-color:#499249;} .btn-success:active,.btn-success.active{background-color:#408140 \9;} .btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;*background-color:#2a85a0;} .btn-info:active,.btn-info.active{background-color:#24748c \9;} .btn-inverse{background-color:#414141;background-image:-moz-linear-gradient(top, #555555, #222222);background-image:-ms-linear-gradient(top, #555555, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#222222));background-image:-webkit-linear-gradient(top, #555555, #222222);background-image:-o-linear-gradient(top, #555555, #222222);background-image:linear-gradient(top, #555555, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#555555', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222222;*background-color:#151515;} .btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} .btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";} .btn-group:after{clear:both;} .btn-group:first-child{*margin-left:0;} .btn-group+.btn-group{margin-left:5px;} .btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;} .btn-group>.btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} .btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} .btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} .btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} .btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;} .btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} .btn-group>.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:4px;*padding-bottom:4px;} .btn-group>.btn-mini.dropdown-toggle{padding-left:5px;padding-right:5px;} .btn-group>.btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px;} .btn-group>.btn-large.dropdown-toggle{padding-left:12px;padding-right:12px;} .btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} .btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;} .btn-group.open .btn-primary.dropdown-toggle{background-color:#416dc4;} .btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;} .btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;} .btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;} .btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;} .btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;} .btn .caret{margin-top:7px;margin-left:0;} .btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);} .btn-mini .caret{margin-top:5px;} .btn-small .caret{margin-top:6px;} .btn-large .caret{margin-top:6px;border-left-width:5px;border-right-width:5px;border-top-width:5px;} .dropup .btn-large .caret{border-bottom:5px solid #000000;border-top:0;} .btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);} .alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;} .alert-heading{color:inherit;} .alert .close{position:relative;top:-2px;right:-21px;line-height:18px;} .alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} .alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} .alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} .alert-block{padding-top:14px;padding-bottom:14px;} .alert-block>p,.alert-block>ul{margin-bottom:0;} .alert-block p+p{margin-top:5px;} .nav{margin-left:0;margin-bottom:18px;list-style:none;} .nav>li>a{display:block;} .nav>li>a:hover{text-decoration:none;background-color:#eeeeee;} .nav>.pull-right{float:right;} .nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} .nav li+.nav-header{margin-top:9px;} .nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} .nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} .nav-list>li>a{padding:3px 15px;} .nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#4183c4;} .nav-list [class^="icon-"]{margin-right:2px;} .nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} .nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";} .nav-tabs:after,.nav-pills:after{clear:both;} .nav-tabs>li,.nav-pills>li{float:left;} .nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} .nav-tabs{border-bottom:1px solid #ddd;} .nav-tabs>li{margin-bottom:-1px;} .nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;} .nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} .nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} .nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#4183c4;} .nav-stacked>li{float:none;} .nav-stacked>li>a{margin-right:0;} .nav-tabs.nav-stacked{border-bottom:0;} .nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} .nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} .nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;} .nav-pills.nav-stacked>li>a{margin-bottom:3px;} .nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} .nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;} .nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#4183c4;border-bottom-color:#4183c4;margin-top:6px;} .nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#2c5d8d;border-bottom-color:#2c5d8d;} .nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;border-bottom-color:#333333;} .nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;} .nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;} .nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} .tabs-stacked .open>a:hover{border-color:#999999;} .tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";} .tabbable:after{clear:both;} .tab-content{overflow:auto;} .tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;} .tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} .tab-content>.active,.pill-content>.active{display:block;} .tabs-below>.nav-tabs{border-top:1px solid #ddd;} .tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;} .tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;} .tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;} .tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;} .tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} .tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} .tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} .tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} .tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} .tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} .tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} .tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} .tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} .navbar{*position:relative;*z-index:2;overflow:visible;margin-bottom:18px;} .navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;border-bottom:1px solid #cacaca;background-color:#f4f4f4;background-image:-moz-linear-gradient(top, #fafafa, #eaeaea);background-image:-ms-linear-gradient(top, #fafafa, #eaeaea);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#eaeaea));background-image:-webkit-linear-gradient(top, #fafafa, #eaeaea);background-image:-o-linear-gradient(top, #fafafa, #eaeaea);background-image:linear-gradient(top, #fafafa, #eaeaea);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafa', endColorstr='#eaeaea', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 0 rgba(255,255,255,0.4), 0 0 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 0 rgba(255,255,255,0.4), 0 0 10px rgba(0,0,0,0.1);box-shadow:0 1px 0 rgba(255,255,255,0.4), 0 0 10px rgba(0,0,0,0.1);} .navbar .container{width:auto;} .nav-collapse.collapse{height:auto;} .navbar{color:#333333;}.navbar .brand:hover{text-decoration:none;} .navbar .brand{float:left;display:block;padding:10px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#7b7b7b;text-shadow:1px 1px 1px #ffffff;font-weight:700;letter-spacing:1px;} .navbar .navbar-text{margin-bottom:0;line-height:40px;} .navbar .navbar-link{color:#222222;}.navbar .navbar-link:hover{color:#4183c4;} .navbar .btn,.navbar .btn-group{margin-top:5px;} .navbar .btn-group .btn{margin:0;} .navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";} .navbar-form:after{clear:both;} .navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} .navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0;} .navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} .navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} .navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;background-color:#ffffff;border:1px solid #b3b3b3;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0px rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0px rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0px rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query:-moz-placeholder{color:#cccccc;} .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} .navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} .navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} .navbar-fixed-top{top:0;} .navbar-fixed-bottom{bottom:0;} .navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} .navbar .nav.pull-right{float:right;} .navbar .nav>li{display:block;float:left;} .navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#222222;text-decoration:none;font-weight:700;} .navbar .btn{display:inline-block;padding:4px 10px 4px;margin:5px 5px 6px;line-height:18px;} .navbar .btn-group{margin:0;padding:5px 5px 6px;} .navbar .nav>li>a:hover{color:#4183c4;text-decoration:none;background:transparent;} .navbar .nav .active>a,.navbar .nav .active>a:hover{color:#4183c4;text-decoration:none;} .navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#eaeaea;border-right:1px solid #fafafa;} .navbar .nav.pull-right{margin-left:10px;margin-right:0;} .navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#f4f4f4;background-image:-moz-linear-gradient(top, #fafafa, #eaeaea);background-image:-ms-linear-gradient(top, #fafafa, #eaeaea);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fafafa), to(#eaeaea));background-image:-webkit-linear-gradient(top, #fafafa, #eaeaea);background-image:-o-linear-gradient(top, #fafafa, #eaeaea);background-image:linear-gradient(top, #fafafa, #eaeaea);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fafafa', endColorstr='#eaeaea', GradientType=0);border-color:#eaeaea #eaeaea #c4c4c4;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#eaeaea;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{background-color:#eaeaea;*background-color:#dddddd;} .navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#d1d1d1 \9;} .navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} .btn-navbar .icon-bar+.icon-bar{margin-top:3px;} .navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} .navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} .navbar-fixed-bottom .dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} .navbar-fixed-bottom .dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} .navbar .nav li.dropdown .dropdown-toggle .caret,.navbar .nav li.dropdown.open .caret{border-top-color:#555555;border-bottom-color:#999999;} .navbar .nav li.dropdown.active .caret{opacity:1;filter:alpha(opacity=100);} .navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:transparent;} .navbar .nav li.dropdown.active>.dropdown-toggle:hover{color:#ffffff;} .navbar .pull-right .dropdown-menu,.navbar .dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right .dropdown-menu:before,.navbar .dropdown-menu.pull-right:before{left:auto;right:12px;} .navbar .pull-right .dropdown-menu:after,.navbar .dropdown-menu.pull-right:after{left:auto;right:13px;} .breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;font-weight:700;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;} .breadcrumb .divider{padding:0 5px;color:#999999;} .breadcrumb .active a{color:#333333;} .pagination{height:36px;margin:18px 0;} .pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} .pagination li{display:inline;} .pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;} .pagination a:hover,.pagination .active a{background-color:#f5f5f5;} .pagination .active a{color:#999999;cursor:default;} .pagination .disabled span,.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;} .pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;} .pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;} .pagination-centered{text-align:center;} .pagination-right{text-align:right;} .pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";} .pager:after{clear:both;} .pager li{display:inline;} .pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} .pager a:hover{text-decoration:none;background-color:#f5f5f5;} .pager .next a{float:right;} .pager .previous a{float:left;} .pager .disabled a,.pager .disabled a:hover{color:#999999;background-color:#fff;cursor:default;} .modal-open .dropdown-menu{z-index:2050;} .modal-open .dropdown.open{*z-index:2050;} .modal-open .popover{z-index:2060;} .modal-open .tooltip{z-index:2070;} .modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} .modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} .modal{position:fixed;top:50%;left:50%;z-index:1050;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} .modal.fade.in{top:50%;} .modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} .modal-body{overflow-y:auto;max-height:400px;padding:15px;} .modal-form{margin-bottom:0;} .modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";} .modal-footer:after{clear:both;} .modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} .modal-footer .btn-group .btn+.btn{margin-left:-1px;} .tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} .tooltip.top{margin-top:-2px;} .tooltip.right{margin-left:2px;} .tooltip.bottom{margin-top:2px;} .tooltip.left{margin-left:-2px;} .tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} .tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} .tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} .tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} .tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .tooltip-arrow{position:absolute;width:0;height:0;} .popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;} .popover.right{margin-left:5px;} .popover.bottom{margin-top:5px;} .popover.left{margin-left:-5px;} .popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;} .popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;} .popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;} .popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;} .popover .arrow{position:absolute;width:0;height:0;} .popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);} .popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;} .popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;} .thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";} .thumbnails:after{clear:both;} .row-fluid .thumbnails{margin-left:0;} .thumbnails>li{float:left;margin-bottom:18px;margin-left:20px;} .thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);} a.thumbnail:hover{border-color:#4183c4;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} .thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} .thumbnail .caption{padding:9px;} .label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;} .label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} a.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;} .label-important,.badge-important{background-color:#b94a48;} .label-important[href],.badge-important[href]{background-color:#953b39;} .label-warning,.badge-warning{background-color:#f89406;} .label-warning[href],.badge-warning[href]{background-color:#c67605;} .label-success,.badge-success{background-color:#468847;} .label-success[href],.badge-success[href]{background-color:#356635;} .label-info,.badge-info{background-color:#3a87ad;} .label-info[href],.badge-info[href]{background-color:#2d6987;} .label-inverse,.badge-inverse{background-color:#333333;} .label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;} @-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} .progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} .progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} .progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);} .progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);} .progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);} .progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);} .progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} .accordion{margin-bottom:18px;} .accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .accordion-heading{border-bottom:0;} .accordion-heading .accordion-toggle{display:block;padding:8px 15px;} .accordion-toggle{cursor:pointer;} .accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} .carousel{position:relative;margin-bottom:18px;line-height:1;} .carousel-inner{overflow:hidden;width:100%;position:relative;} .carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;} .carousel .item>img{display:block;line-height:1;} .carousel .active,.carousel .next,.carousel .prev{display:block;} .carousel .active{left:0;} .carousel .next,.carousel .prev{position:absolute;top:0;width:100%;} .carousel .next{left:100%;} .carousel .prev{left:-100%;} .carousel .next.left,.carousel .prev.right{left:0;} .carousel .active.left{left:-100%;} .carousel .active.right{left:100%;} .carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} .carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} .carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);} .carousel-caption h4,.carousel-caption p{color:#ffffff;} .hero-unit{padding:60px;margin-bottom:30px;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} .hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit;} .pull-right{float:right;} .pull-left{float:left;} .hide{display:none;} .show{display:block;} .invisible{visibility:hidden;} .space-right{padding:0 8px 0 0;} .space-left{padding:0 0 0 8px;} .CodeMirror{line-height:1em;font-family:monospace;} .CodeMirror-scroll{overflow:auto;height:500px;position:relative;outline:none;} .CodeMirror-gutter{position:absolute;left:0;top:0;z-index:10;background-color:#f7f7f7;border-right:1px solid #eee;min-width:2em;height:100%;} .CodeMirror-gutter-text{color:#aaa;text-align:right;padding:.4em .2em .4em .4em;white-space:pre !important;} .CodeMirror-lines{padding:.4em;white-space:pre;} .CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;-o-border-radius:0;border-radius:0;border-width:0;margin:0;padding:0;background:transparent;font-family:inherit;font-size:inherit;padding:0;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;} .CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal;} .CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden;} .CodeMirror textarea{outline:none !important;} .CodeMirror pre.CodeMirror-cursor{z-index:10;position:absolute;visibility:hidden;border-left:1px solid black;border-right:none;width:0;} .cm-keymap-fat-cursor pre.CodeMirror-cursor{width:auto;border:0;background:transparent;background:rgba(0, 200, 0, 0.4);} .cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id){filter:progid:dximagetransform.microsoft.gradient(enabled=false);} .CodeMirror-focused pre.CodeMirror-cursor{visibility:visible;} div.CodeMirror-selected{background:#d9d9d9;} .CodeMirror-focused div.CodeMirror-selected{background:#d7d4f0;} .CodeMirror-searching{background:#ffa;background:rgba(255, 255, 0, 0.4);} .cm-s-default span.cm-keyword{color:#708;} .cm-s-default span.cm-atom{color:#219;} .cm-s-default span.cm-number{color:#164;} .cm-s-default span.cm-def{color:#00f;} .cm-s-default span.cm-variable{color:black;} .cm-s-default span.cm-variable-2{color:#05a;} .cm-s-default span.cm-variable-3{color:#085;} .cm-s-default span.cm-property{color:black;} .cm-s-default span.cm-operator{color:black;} .cm-s-default span.cm-comment{color:#a50;} .cm-s-default span.cm-string{color:#a11;} .cm-s-default span.cm-string-2{color:#f50;} .cm-s-default span.cm-meta{color:#555;} .cm-s-default span.cm-error{color:#f00;} .cm-s-default span.cm-qualifier{color:#555;} .cm-s-default span.cm-builtin{color:#30a;} .cm-s-default span.cm-bracket{color:#cc7;} .cm-s-default span.cm-tag{color:#170;} .cm-s-default span.cm-attribute{color:#00c;} .cm-s-default span.cm-header{color:blue;} .cm-s-default span.cm-quote{color:#090;} .cm-s-default span.cm-hr{color:#999;} .cm-s-default span.cm-link{color:#00c;} span.cm-header,span.cm-strong{font-weight:bold;} span.cm-em{font-style:italic;} span.cm-emstrong{font-style:italic;font-weight:bold;} span.cm-link{text-decoration:underline;} div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0;} div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22;} web/img/000077500000000000000000000000001516067305400124165ustar00rootroot00000000000000web/img/feed.png000066400000000000000000000013371516067305400140330ustar00rootroot00000000000000‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<IDATxÚ¤RMHTQ>÷^'Ó Igü™RcMA-.ªMD+-ŠE’ Q-‚ Û¸hSeAP´m•`-7©é’?MšæØó/±Ô§ã{ïÞ¾;Ž ôà{çÞs¾óÝsÏ=L)Eÿó±ÅÏ3X0 ô¯`bÝ„ý¯ï]§ªŠh~–äÌ8ɯ_HÍ̽#)!Þ¡ÈŸ8`Ù­Ñdæñ‘«ü¹Nœ-å{²Iðóº·üoÂfû€R˜åû“â ‘üaüð†äØä]ÄjQÜ$°±‰81¦Š%&Öðý%;¹;‡ä`'9}¡FR²zcotõ°ÙÀ[  „–˜PÌCQ[Á|¹¤ÆCäô>FüÊæ&;S$a”:Lʘ ÂÄ—1¡û"ߥ¦“"9®Dìùú&Fœž6bŽE®ƒä:Z^ÂÓÜÍH¼­ ×8ý¡&5;AÌJ´5¡±äõÕrÌ8nwwßYyÕ`ÈÉQ…e$üÙµúôï²ói4Œ÷"ž™êÕûß6 8‚î‰@ö9–’±ZrØ8*ê«äÞž’BvhhŽÌ¥üSQ˜ ÇxLè‰ðïºÄ¶%‘=ðyš–—òàž'!zEVz@Y Ž s ÐÃâ· `ýˆùª3òí£2‘ãIvcd‹§™l‡˜Ð7§#k=¸á*.ÎÅ{·sû"öeÑñµìê炾¥æŒÝ²E.˜¤ÌE½.\$W@sˆVÛ±Ö”V5oF¸CÊy• îÍ3(b9¯G„²ôO—{Ë öf¦/€®˜À”Z4û¬öŽÝX/ë•ßaÃV{ר9Mú%À´’ ̵wIEND®B`‚web/img/glyphicons-halflings-white.png000077500000000000000000000211111516067305400203650ustar00rootroot00000000000000‰PNG  IHDRÕŸ˜Ó³{ÙPLTEÿÿÿùùùÿÿÿÿÿÿýýýmmmÿÿÿÿÿÿÿÿÿÿÿÿðððþþþöööüüüÿÿÿÿÿÿÚÚÚÂÂÂôôôÿÿÿÿÿÿôôô÷÷÷ÿÿÿ³³³ýýýâââ°°°ÿÿÿÿÿÿûûûçççþþþÿÿÿíííÏÏÏýýýöööíííûûûçççúúúááá’’’þþþþþþÁÁÁ˜˜˜tttáááÐÐÐóóó»»»¡¡¡€€€ýýýÔÔÔbbbÿÿÿÕÕÕøøøÜÜÜúúúûûûéééûûûýýýýýýÑÑÑòòòüüüøøøëëëüüü¶¶¶ÆÆÆåååîîîõõõýýýeeegggððð¶¶¶ààà÷÷÷úúúéééåååúúúøøøËËËÿÿÿ„„„ñññxxx÷÷÷ÝÝÝùùùÈÈÈÒÒÒìììúúúÞÞÞâââæææóóó›››¨¨¨¥¥¥ÜÜÜîîîÿÿÿñññÉÉÉðððÿÿÿÿÿÿÞÞÞÆÆÆ¼¼¼ëëëÖÖÖÐÐÐâââùùùôôôâââìììõõõ´´´ÿÿÿýýýûûûüüüúúúæææäääüüü÷÷÷°°°™™™ýýýìììüüüÁÁÁéééÿÿÿÚÚÚððððððõõõñññþþþøøøþþþŽŽŽâââûûûùùùÜÜÜÿÿÿòòòúúúŸŸŸííí÷÷÷öööèèèóóóúúúõõõõõõ¦¦¦ËËËúúúøøøÓÓÓëëëúúúëë몪ªóóóííí¢¢¢ÏÏÏÚÚÚÖÖÖ¢¢¢ëëëâââùùùUUUÍÍÍÿÿÿÖÖÖãããáááêêêüüüÿÿÿöööûûûóóóôôôÌÌÌÿÿÿÿÿÿùùùõõõÿÿÿòòòýýýÙÙÙüüüûûûüüüééé¿¿¿ûûûêêêéééþþþÿÿÿørOæòtRNSÔÏñ#ïŸ_ /©ðÆâ¿oS·ß?†ÅCá kD¯ÂÀOS_ ¥š²ŒÓ6Ðà>4!~a §@1Ñ_'oÄn¢Ò‹‘€M†¡“3±BQj™¶p&%!lµÃ"Xqr;€— A[‚<`‰am}4…3/0Iˆ¨PCM!6(*gK&YQ¦GDP,å`’{VP¤-êxÁ)hÝ7‡e1]ôˆßW¿³$—‡1ƒbÄzSÜ•cOÙÍ]ÀŠ–U;Zié»'yÜ"€âÐÐ‘ÝØ†‰K 64ÖYœ*.vè@²¸îŽc.};‡ïŸtN%¨DIª˜ÊÐ !Z¶Ð5LñH£2Ú6 ŒƒÉ¯ŽÖ"Š Ô-b±E,,)ÊÀ BŒ·¦>m¹ªÃãúnøö6pmŸRöO wm@°ÝÌVÝ#?É'C…È‘Z#©Žqž‡ìÀbÒÓ|$½:Ü)‰Â/E¾%÷ânR¹q—CàhnµÉ%õiÓÌ“­º¶¶ß}lƒm ?iÿdâdÃ"€,Ø­Ç`¬Hñ"r.z¡¼‹ŽÁ~ýìü(bðQÜU&ê½—)–5õêX#•§ òé™EMªæÜR<Í*p[€[%.©OÉÌ£˜¥k7“lIo°ý¨ý“¶ßJ°F  ¥lV!̡ăuH‚`Ƽ™€—›ç‚&¢,Çz´ÉRk$¤ò¨|$ölŠ»¼Xbü¢âéÇjߪÈdU±û?Σ$Hµî¸©W±¾$Uû'…ÆÅHÜE3*Õ­º€µµU\}ê­ý†(Ò ¤zhVk}gÇu«Rk$¤ò%¨|‰T¨|Úêck¦ç³"ãžä±Dç”ý«ƒ_W+‹®”Ê.QòÒÅ)Õ@«ý“ƽ€H¢À›Íbµs¸ÔlžŽT´©·Dÿô­RÄ2Xm£#a Ýêº3lYÃÎzÌj¹ŽÔã’š#!Þ 4þJ´Ä8Ñ(Œòcµv™‰¾t]­a·˜T™Çàø Ò÷D Î…à¼áQ?^-‹Õ_^$:\ÿìÞV  $«•N|ì=(vˆZ'q6¹Zð׆‡×üB5VìÌî!y†´¼3äßKœÿ㱿bàv4Œñxðëê£âR]al—í!ÔþIÛo‡P‰@Åt¥äVy”ºîàLïÿÙªmlµÚ¿I¨Ub|[*°¶lke'*¾WdîÀÝdà³ðïD·Ó}\W›ƒ_Wß´ù¶¤rÐNÚ?™øÛvÞ«ÁÛ²X%§Ž0u‡öoui*„üJV·€Æ¦‡b%†}ôãˆi5I¥YlNŸE-wÐÏ‚ûf_W3mþIåà…Äý“…—-ŒmƒÊ¬²Q)“S µÖk´«TC7êím¤<"ÄôÜŒ‡b‹T|ìÆ'¦Õ$µÒ˜Ÿ£óóÖR&>¥êO pœõºš¾ù…ê6ݬÒöçú½t±¨î¥S­ŽN\©×¯LŒîmÕø\ÈÎÑÊÄr@¦3žuT b7úÓt.5.q©ôÈ3²r0ü=™8T¿ªi­J©\ëÈ6uF ”²R¸32^÷íñ'ŪŠóÀí±xˆâI« ïÒF„8O{%8­žkJšÓMSÈ´dâBEdæÑè ïW‚CYÃ÷O:/OŒN/—I‹ê_=½€xFE”Ñ! Í=¥æi:oÁ~’¡· yþ?¶š'·š'·š[Í“[Í“[Í“[Í“[Í­–è».¹U>±$÷P–ƦŠc%†] Û\c©´:é| ý,e¯SœZ,‘oš¿XríäÎËXº!ëRæ”ÇÆò@áZøv‚ ‡0Ôç>?Á*ç® Ô<ðþÕ|ø«¼N6þ0ú¹;{¯ažd³ê2Ôév+Däó^tààúÑ[q!òÛžV}Èøf«œÛ¨ÏŽÎ×Yÿêeॗ€Ë)Vyl|" f÷UDzqˆ@ëˆÇ¼˜4Y-˜³YýÍ-!¶6a“žŠB:o%ñJ¤ÛI±´—UQ|£UÆK¨O `¢®=\ ý´­ò:ë0¾°Àx …±Paó‰Ìuˆ@œ»!ç»K†âPÏdÕxhw1>×$jγ“vöZdàè™xñ«ÕSšUAÅ&[URßd•ý7ðøÂz·ký«/˜œðr¢U^¬Žä £ó—w:I.àVÇ®ëôÿc>qí.!·zSÛr&«³Õ2…)Wgù ¾…R -ÎiãQ 8¿çØûPa\О×U%•iÝ¡¦þUï_=àÃpÊø ›Lu ê(îžN¹?†Ÿ 0?Æ:]½Î¬ä†ÔÏt¬B%“U|™úù²¡NsorNÿ¹f¶ú ø,»P !­v" Y¬6¼hLï_­@@…bé·s¯c¶¬£qg˜v4|Â|0lÏŸÐëÔ$SŒõ9ŽîòbʱšÑj#ŽŸ£~žƒÁÒÏ?o²÷}‘‘ƒð}7sAPm:IV¹=n•÷¯ !ôþÕ{±›{ÍÝh¼ÎEࢪ£8¤sèu€ÍoL®ëÈTð$ñ„õ;VÝú¹­sõöcqìD¦3ðø¸ñ üÛ༂3.D«Bˆ«éý«³B4Ì&ìV'ØÜ TÅ `õà½Dï6ÿ™žšÏ·óqýyùjû8V‰Õæ*ëÖíX%ý³›@s«\ÞjrNµ$à|ö=5þΆ 'ìmU«iý«Kýi€%C™ÉIð:ssaÆ…`*`óµ=úl½÷)>ÈuÕ˜MeuSš›·¨Iò_ÎO÷ˆLü£_©}o&©íÀjzÿêÝpèºþ{¨¤ÖáÜlu:OñÁ®«ÆÌ)«s¤%Q@ãÍ$Þ<]f› € xO%…÷PCbhr2£ÕôþÕ¼ŸèýPK·Êëpžf5½Në3^o«ù©ú¼]êe²JÊêÁ¤iÐB˜œ464†€^tï‡uÙ²þUÖŒ:G4'¿ò22YêpÎëˆÌu¦G'/PyÙ4?¡þè.ÕæSB„P_>‘ÑëšI 1t3Γ÷BäÉ­æÉ­æÉ­æÉ­æVóäVóäVóäVóäVs«æÃ]î³!×67(ªÇg ¯¤¥‹Šyƒ°@†” 4>QÚò ßÕV«F­}^XׇìÚ¼ˆ’Õjµ¦e÷26 Lž³Ð%žòY´Gâh û³šl‰C­}­)Óâ< ˆ!ÚE ôðÇE½PçZWZ™½ŒV+þ@†ÏR 5{@ou—Ɇ4²‚²&…„˜´H…Ѭ6÷eµy V‹ˆÝ€˜VÅ¥ÖÁ¬¾ácqZ„Þ’©rìÓJÆçyBêæyžÓˆFzÑõFN¢$¢HbÈÈÕ³*+jÕqòÑÎÀ Ú«˜kÝ¿UàX„¯lºe·ìÄö¾Ä1“ÕÊÚdà0d^õ-‘B%‰ƒ}ê œø¸{Yõ¡™%rÇ*Òj5Ak5¦u«³"Ì,·:~éÒ¸áY¾Ü~ h™÷ûÄSA~¿­6ì ¼fuÁlÕ‡fµŠ{ȵQtATHÐZˆkÀªŠÆ­/_°¸ÕSŸî¼náû¹ ±u']bù]|m`«B…ñÄÁÏÀ¡J,O$íÁdu]·Zs® ÀFLß:©Äùúú›aõø‹À‹Ç™ÕÂÌT4Ïoà~by?wpÇj滥ÖAœ…Ø(€xù]„†¦ú…ªfÕí¶~anÖ§/ž©¸¿^ÈdÕÚ²öcØÚú˜Õ‡,!ÄÐ1©øi&–xi_VK@ip«Íƒ9¯ÐÞVi%a; Õ¯L?‰0J“*¹’šÅª5ܶ¸UÑ·Š“'Á¬ºx^î²6âV[¥^ à{öeU™ÈÒ|—:0ø=0‡»ÈdÛ«o‡¨ç*J“q%•[­ÆõYÃN¸˜.sQ„L‹udš[2×ð9þIýó:WÁn—ÔÈÿÐÙŽÊm™Xl¥Úƒ¾6×!lNl‡ÙVÙÕ§KU¼¤¤jVã\J%©UߊßB°ŽLcKfáb×ö>a“=Òb›~¹R]aG%[ú÷×js@«/9ðMطݘU×>yɲXÇ@}³ ” ëëF¢´tÜg^‚ÛvO\°žÓ¸wv‚p•ϯz3›K5i¤!$P>”ÄÅ€¹'Ò”VÆ›¬”¢Lž2r´ú@¤UMÃÉKÃúZ¯õ‰¹å6Ö×ÀtwŒë§ŸÂ¦bä„mß1âh|ô|É]}~¹0øÀMjA¢À´Ò(JâŠÝÁ­JP68ÌC&yrÈÌ׉e}­jŽ_cËJ½?êI0¬¯kêÛ>š«W™‹áø Æû‹™¯é|¡B¾Þá."TEXd Ô8”Ä!cwµ*E(ÎJ)ÊåÉ!Î[W"­j_ÔÃáТeX_×ÐXB;¤÷¯o°†O0~?¬:P½Cã (.²í¶±[·Ž‘‘ò!Wq£%ßÔ*leÃÀY)E™<^ˆKåZ¹T•60Ö.ðõ#«µøA\ý¤Á5;RmÆtkdÂ/8§)5~‚¿ ¬^0Ú #åCkg–¦¶eÍÌy)²—±Í¶¿‘ÔºÒ°6Ä¥ª<€(?Æ×&ÉõõuîA„áVŸ’õm0^h.—tÌxR*ô×aô©'ö:,¥H§|èÅ–ªÏ l5z„;8+e¦#b'#|û}2Æw(|Kc–J½ Èl6 뀶¾®wù‹^‚ÕŒo×—iúœ3HÓ êR –ŽÌ”9Š,Y“gP«Ö°:N œ[5SÃöû‰R‡!¢§ä[)•ç]€úœi}`úúºm¬’¸N±4Ð¥¹²ãvÑ`|;f¬(®´Fïlt©„¢LÔ8”Ä÷Z#½Aï–¤O%ÕÀY)N¹U®5YêÑeœ¼d–JÎE3dZذ’þÇ<Èx·ÇñØÉñä¶e •@ùPÚ§ÏþÎFúTR œ•2S¡Â·ßüΦ/uˆZ°~ðšCæ3ÇÔXÊz¼ÍÓU¨žâxõ\2s«ñä¶e •DùD.çÉåfBO&enÝ'iÈåR%™?Fy¸VsS~$uˆ®mœw()Á´r”ºo³0*Dí˜Õi!3½:On[Bµ!sʇBäp>Ý£HTÙ1òè ;ö8M×jnʤ‘Ó¤ï¼äqpÞ 1hò^ˆ<¹Õ<¹Õ<¹ÕÜjžÜjžÜjžÜjžÜjnÕÜßû–qÕ(qpõOkª’Ô}¸ßøI?TY8H«®mhyK¸Ìu5ÍÏÂÎIœt÷eÕnQBÞ—`µRÄÂ`¯·EÀPË ­Ú¦ö˜½¹xû™«ž½>¹>€â‘¡yt¾{?|œ×'j)”ÉÆ€µ}YUÛÏäUùÛÜ{ç@Vå‡/€J1ìF+€¬¿7䀉[OW«O[æù ø¹‘‰y³ÇUY«ª•ˆõ!?BôÈD%D™Wj¼>-Ai6x£z)»ÕÎU R½ùª±’7 dõÙŠ@µg‡ˆëï•\†soØ)œaÏ4ßzfŒ[«W+•±>¹¸« œÿPô>ä |•ÛqLãÑG8vâ¸âêÈ£„˜l´j©µ2ZíÆtÜß+åŒV¥ÔA¬6g<„/ŽæQ ‚H­çSrΣ“ÑçÖd}ØùYqàÔg]€sY]ç;]FëCª@5¼YÓÕ–5ÎC©3å8oÙ)kš1'ûüd6«>T *Ëʆ’§Uz(¥m)ûâ®CD `‡ÖHe/¾.ñ:ç—zN¥È9pgo &NC¦×ƒŒÞ‡¼>¶WÓøÕ°_’ñHj ñ)¤Xe6F„ 7p’m¾-è`'Öc†»Ü.Õ«‹ÂAZ=³þ^Ée8÷ÂF×;<ËûÄJ1{óãŠ+8'€Éª'„Ö‡\Aµ*¿Òø[² ‹ñR$UãY)V¹ óAyɃŒw)ŽEc#<ÕT‡ƒ”»\vW•{R­®«ÉëÉýºtÛn(–ÏzÏ!S×7o ×ï€×Ie®Žî™wõ3]ÔçbÜ—üäÇ8¹5|Æi·Ï æêRÛÚJkʱZ‘RO+ê8£U&µ:]•Z‰ieR‰’¬¢‰(üóJËMŠÞ—7—³«ÒZ@Œ²5Ýa^äº\G˜z™¯sª¾éÏU‚Ò*¥rMÏe³zT¬^Ê:ɬ‚õͦX=>Ü$ bi>³U&X¬Qoybb¹GÄøkøÍ8¯ – ÅÒ˜óýÿn).Õ¤òœÙðoã ¥À^Mmád³ZƒÊóië$s«ªo–oÞê*{»4ììÑeLb¤LÙ³""mx: `:mÉkž[ØgeTˆÑ‡Þ¬)Á„'0*T˜›Bá€{!úîIÞ ‘'·š'·š'·š'·š[Í“[Í“[Í“[Í“[]˜ZˆƒÜj QŠ.e '/¸®y÷vQ¤71ø(Z&†óÒX‘õ?(_œšZ”œÇº”){tÄÚ€m˜ZíÿÀWÑÏ)­«-C“ŠÓò´¶ jqání,Ì‹Ÿ"áIv‹¦½ULØ!h¢™Ù꛿îñ©¯Ýsçk’óAcrN‚ôþ佚ф€…VE4ö0úy˜XÜÒ~å4zʸVã³°%·ñ,é¹ßû)føÃÀqtÃp˜u¦~ã  Þø©ŽÑ*ý“©^æÖ0:åýÏéܲö3ÿ3…ÃÏJÎâOô(¦·ö£›ZB?K™^ Àv]’un ŸlçúÿôWþÀ‚¶i0´p6­ˆ[ì°©àC_5Xý#ú[¿öwX3ábñÎ廫ÄR½{ùÎâ¢NKðAîÏÿŒée S«èÓeª|Ýã¹wñ¢ÇxâºÊÞsôño>ÖP\å„”Ô•6Ò;nVÛm¯fëI$àø‰ÇûVÍ“J-ÛJ%ÖŒ¼Ž0¯óUwûYÐŽÉSõóó×n‘uÿÒmÿè—®Æù«xzµÒË—VŸÆ«ÚIµvnôWÿÚ_ÿqLZØÇòé"_—X®z‡Ã÷Æ 8Ç]Ap—‰ƒˆÍ?†¶CÍ‹Ž‘ž5È4ˆ·3ñŽzw(Ü{7e²*Ȳ`Û°¬!AÔQ“:ñKUnõ•¿Âÿzë]ú1y†V„ø›Ga°úCÿêm0îPY ÙšUx6TT&·hVï9V§ þîßÓ¬žzÑ  1[÷X®z‡ZœËÕî„Ð9ªe¢r›qóJ¸³¸NDß/ù¬¹g·þX¦ë*9o—ðíN6«DÃÃ` Ë{à÷ªIï%ËM´z9—ãTûQŽŸà–ˆþþ7fö\"jþÃ_3ÙþÖç~xBá'€ŸùÜ·ˆˆY›]*KÐŒãî“«%"úÔç5«"ðÈqxq~ü’Æ•=·‘¨j¼´ºSá>j¤Vç·&~]2 xzÀF¸ÕíŸ1X•§_yÞùDÀÎ<#N’ÕîïRB÷Ô}KôÏÿÅ/ói‰Šy†ù¿õË !V^¢ñË¿e²JŸ‰‡}/FkïñAßú7Ÿû· âëS©È×+.–(ec—ˆJ:˜zðƒªóW“ZšŠ°ëª–wïÒÙQ™þáðÅž~aÛÒê„ØÍ„öpç6,e5í¯,¬+¢–”Á,ýûÿð­óñ÷ÿt±võ%O^OøüO}ãן -Oüú7>e²ÚkC¦6£waô_þëC ¢‹|½â›9‘‘×*•šÎ‡ØWÆñ¸Aª)×U¶Jgê8<ýZ€´šx^?„ÿ¾2²u¶­Yýí³õè*^?ûÛÚ‡KC­Z¤[‚ÿ©ÿù0.’–àCµ¯@m¾çÓçß$-ßÄ/~ž|Y¥å[eþwƒeQýŸÙ×¶&cëÊOž4s|‰œc’§JåûŸwsïûXÍ8/ñš¼Î6Ï/ Ú¼;ç'F¯LN^8]ÛeadëZ 1'®Ü°ž÷^†Úü™û¼‡L³‘sBdü%Ó+M¢·`ÝãSKö8פ²÷«ìº*ƒª)gl#Ž3"Ä’gÑŠ˜S Ç㋎©qtcxxƒš|H>–¬Æø=ðŒ:³ÅçýÎmÊjÕå¬ßÿìÕUßòÁóv£qìys©Ü’žLglþC6+[FÍSWg…ö“9õ˜ƒwV3¼1µA ë N”ßD¾<Íû«ËÂ$5eÿ(s„ú¡ ÿ[Ð Û¨bú—³‡žaF.”¨]±K¡îÇIEND®B`‚web/img/glyphicons-halflings.png000077500000000000000000000330021516067305400172510ustar00rootroot00000000000000‰PNG  IHDRÕŸ‹ÂtEXtSoftwareAdobe ImageReadyqÉe<÷iTXtXML:com.adobe.xmp glyphicons_small_dark 5kÒ1¡IDATxÚí}ol\E¶§W²´^ÉzŽD$|_w'þCwìþG;ã4¶ÁäÏ<ã1ËÆÉœu˜Ä³Œ6C‚È"À ÆÒæEʼ0 "=ñ€÷,á· ïûÀ’f3oÒ 0 `àýôì¸õ¾ì—Úsnuõ½Ý¾·êT§;1K«ÄmûwëÖ­{~U§ÎuýªªÊ˜1cKά:kÎbö1çü0“ûQá‘!8dM` \¯5e]‹OY½KªA¦*…‡–9c·ã«Î8Þ ?'MÿÑ÷7kþ1ôcü¤]?¦b€ŠÑ½à¶c}x$œ’/ôõÌ$YáÑ3s¡OqY›¢+Ø*bQ8CÞ AÖÆâ,ÿ™•V”¬ÙuXx Ð÷Xðù ÝMYRÇÚ˜5¤ñ@4ð ïEì–Œ°†÷ÔÙë àjt(üJÆ®àÑM¥åü>ÀÍ(=BËJÀCšàþ’¶71Q7º% àWY}¶ù¥dlíP"o÷¤Óþ¬º˜¬HTV-/NPά¬¢Vo öŽcqhOg6¬pw½®Ãªk¼ÚˆÔÇºÒ _“ð€ç)MÒú+À¾I :øH¾î¦z̬/Éž{Æ9øOdnÁVã|–»‘ƒ_©xÊŠŸHÃÅ0k¸èÿ¬t|ˆ²°”Nºþ£‹‡nêÐ3#×3ƒu+/Ua9³%Xàq¾N²özùºg†Š§;yÒî9ïyÈ9øOÔ%~–ã¥áu©ÊÉ—*ú=±ªªÄçIÑp‘cáy}®öY(þ£ëoÖ(•u±$«^¬jŸ¾ î®»ïe\õ‰iXíñœ¬Ùã;X-¥r‡ö×ã¬ѲŠ&¾>º>¥eز’쬜¨aŸsº»?ºû?1aÛ¤^‘›¼û=7þÈ65^Ÿª8†R•6ªÒ¨*úäâ¯4|Q¯N$*>µskUqS”E Ó-î?–D²ªüGàù¡Æ¯ù ÏÕM¸#Û  ŸÖ™¥ÊŸ€U±ïòôÖÓ[û3HVUwŸd#¿)üç~@@V¼ ¨¶ƒ-s'A…Ç]—åΛdn² ¢ú3ð„7UžðuÅúS›‹C잸ïz¾{vì(8l-ëÛ;Þ™•á¹¹£”[;ªV~® é’)t>7QeS¨Â)—jºÅýǹO¥ÿhâc Yîó¢CbµÙÄ7:ã©ì X½ ïáï'Y «9ŸÂÏ ïY1y©=G ÿ6`­=G©¥VÑÿ»B[\¯×y¬QÖ=«ºùuoóÇÉ㺷ý›‚Õc?U|ôgdD‚&ëžtÐÓ¬Cv߈z«ÅЬ¡&öÿAŽ·ÏIåg”)ʨºÊuÈGU÷8Gó*=Wµbù6œyhDåùM$?º.Ü&ÃrÿÁÁvQûÀóCïšíXÔ™vd“ÙrQõÔ]ÄßolåwŽŸïúc÷¦ *-µ˜œ˜‚–7ö3pÄyNV+¼ÔxU^òà4 YiYqDµÒ,48í…ó©Åcäù”ªþÏÜïà~T}¿ˆÿ›Ö™{·Óðî~2ª¦•d£ªn¸ÒsÕ¦S ;˜]ɨDuF_1g•„ÂlâüG×ßzþ”`…cœK瓪²Z>’ß·Óhö{>åŽIoUR—Ε–N'0iž±2üq†®Ë†NÔ°cè‹ùA$+-œ¢å¯y6f´³ø?%«‹xï¾Y­ïõ®ˆúÀû½ÞÊÌUiàJÏU?ìÒm}gôsVYÆU×tñ£Ï&Ùê³îŸ¬†qyôYñTñªù uÃ,°óU«Ê. Uáê§×æc,´w'÷ŠŒ¤aÀóþÇ‰Š¥"MùW$«¬)²ÒˆÊ³¿#iÖ5v³À:ø„}çD¹óÒà6þãÆw}®ªßúëO ¬8sý©òù¶¿Õ÷ÌDðJ,#ž‰`F¸^gë°w¼?Ó‘íšÝtþx¢C~úTåWyfçá-´ê̶B‰Î?WÔªó-×_5T•l¬öÔfúc%—Z}h µî«Ã£ª-ÞûoMüÛ´t<-|sÞ«B›„ÊýDËå?<ŒÃ0ÚµË_Â9/uÿ¯spÆ”­M‘&—xÓ¤=_ª¸hî9ñã`e†¨ù8¦¾kŠ»iâ±ü_^—˜é ó¥gaYÝ«-(x®³ ‹j³Ù£è¬®þ1–Þ;Ñ;_Wÿ˜Ò$t]=Ýúè⣿.^•"_Œ^j}PV¤ ñsaF-ñ+X”Ñž/meU×굪q™½ø;â˜ð>EýÏ4d,ŠsÚ÷»ÄdÐåªÓÉœô¶Xã|燠bÕNÁÊg(…¬îÇGÁãªÿþ Š²Ô‰ýµÎjèS,}ËØ–1{µç§å¥ªn}tñ¸ ݽ.t¾®\}p5¦ü¾‹ñªv*¬½Êµ„^”º»4‰БžoR7¢FÆ+VÔ?ËúOoÅzœÞ:’Žtza‘xF‹p6ž&öîÆ[•R)Òdnd´…KûÜß•@ÕÂÅÜjò®˜TáQg$*⬫ËÉâ茲›³\Ѓ¯ÝDAJR©ê®ˆO*ëãÂOX| n @;Ö3gþ*NùøN}ð»–ת1Ï…·êÔxǹÜÁš|i¹Ðc˨TMä×ñF»3X£ ÖùGX#Ü;U†ÙÖÁF;vàž£ö_Ɉ[mäðó‘áÁéÖ¯äw‹Kä’Ì!l‰T]¬º "Ÿ›ªêeߨ³zx‹¨Úá-rÕ;öñÒíá½t’ݱ¯|Tuׇãåõx«7„ þ½*<Ö¾P€JÚžT×ß½>9š„T«IÝx{U©rõ©p'÷ZU‰,Ûœ[” ÷iNU>=¼_•ˆ‚5¤¬~p:|M>7ä!9ñ¬Ñ•’ÎÞGU“Öw(sOßöZèw/< 늖„µÒ>Tõ’GQ‘ÕÁQRŽÎª¨žJg5t—þ@êœDg蚢ù2–S#EØã®¯‘¼>;Ž|iÏ›¿´êøÿ™d?ú¥û'?ú%ˆ`}¨®Oƒªú$¿xš9åSMoTMxøO‚•ªqöØöâŸ=¶=NPÉ@Ù™½ãM0»…Q¹†‚¯ªzô¡È5¦Dü·¶1”åõ u¦¶¯Ù“ YgéKUìe7µ|¤ÔI9¸uV“yZËtV­˜<`°V„Ir‰ãB!.yS‹úX¶0'¶¬>ãQ—]§.\¤,Ãã:#›Ý?Ù,Û¹ÆÝ>ðÈ_SÕ“C#Ûßð4µXCU„Ê5ªê&¡¼¨*SêM²‰ÆâŸM4ÒêSUuÏcøõžÇ¨Ô»o #«CÕûøÝÜ7àÛþ}îŒ.ïödÛt®ª×кxGgU¯ø+Ù5t„¸D}p»¾‚¼>NýÅÊñ¶æ+Ö+ÑöZ¶øª9åwÏÂæ"ͪòû.xéÖö¿¯“@‘ëÜꪥPÕªëÏØzëý\FïØvi’«ÚíÚv†¡šV+€#*ެþpa­×[V‡ªkŽm:gÅ0”ÌÜ—ÝyàäPUdúÊMU]UÌŸòžëÕzaTúZ>wXÁø¦F+”!¹¨«Iƒ\h­ª>NýÅÊñùm„Æí»Wµ‘S>H­-S—ïÝžïW¾ÙKÓÚÿfŒª£ÄÙrH-WËèËŒ9ì7Šá1’æ0äëY=ü_CÁõ®ïÛ!÷þB|ä뱟µ¼¾ZKyY#Ú¶¤¸8!S~ªêé¬ZC"üíùsò!ð­6<E© wAµî« oo¬ Â;ïôƒT}Ý)¿š¢C«¯[Ë•š_x€Ž¯ô¨ª3sI{QuDñ–‚OìÄ<¼È«®"ð§6Ëuï‹ñS<‘h_xô´—5b|!ñ£ªžÎjÛ›¢Ì»þˆßóý>dFP\— Bí__÷Uïíº²U¶>X#|÷ªƒ¯ü\•n¨¾¼˜ªøSÅyµ¸£Æul^W×÷êÓ…ªíÝÚo×ѹÕÐ%Ny SòòµÉàº>u¯×%CäBÝæep•˜è¦Ê˜1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f¬À\”ÖÇ[i‚m ªÐueõ4hsç¤óè+k)T»iµ³&È¥æÎȨîÔ»dʲ¥´¨±%g¸Rap:©¥ìàYhÝÛª³.ÆPz’*V©»rÍY‘gtH= _S©Qpãâm‡öØß3"KX³ú±£I¶éœ|é–5¶é¯³vGSÕ·J—Ò€,gÉÐíœ cKïµøÌ ÅõO¢ôd¨?CW.Ä«ÉeöjIF«Ô§*J¸DÜvé5± ‡’°ÜkÍuél‰MXA±ütIí¦>¤ÎW“L©AÐ %7£`)ˆ»ô‰õ¨À[(hê6lqëÓ»{ݳXMé _\6ea'uy]1*Ét©§*ßk]S’S5"*ÀÅxY½š­¼Tm{Ò– —r1L« tK)‡‰úÝÀéž™£lÄ êŒbÖñ*Uð’üòr*pô¾‚1¯º¸Ì4ÖÁ/#F}7~µl ^¡¦R¡ÕZ‡ªÞÞìϾgEñ†"9ª"ùôT€‹ñr²V–ªH4ôtŽœ—õ]ÎøÛ3ÃuG~£’ÃÄp­½ðÀ¶¿UunªZ±Æ“  |–JUlU•ˆ[qËé,´&JškîX£ Jh+'5Ò*F•BU”ô•ÕÄÞ”æZ.ÏcKóØWáóNº °7^FÖÊRÕÖý¦ Xø†PퟜÜ;žÌË/ËìŽ}(uõKm#Ì…ùXÝȰÉU!­ÄãÔ‚B¸ÊRUWÃB7@õ NomÌçþÅZ„”úäI>¡Ó>\{[ö|‘cï"QqÀ¼UgãYH¬~x²Vžªñ‚þ3Nxô=3:V²•ì@‡PV„¿×6½cõÆ×#ºùEŠ»ãþ*˜(jú˜¶Rü¿&Ù½ÿãÖSUWÃB_õB? ­\Œþ©¿´£$¨S{ÞªV:$‰{óº·Uâ¢öA$jÔ@o¸˜Ã{‘oÝÛ’Êúà×½í}V婪ßKw]ÞØŠ_7¶v]&Ù½qèŽP`-šMÔ¤‰¬†áÉ( ¼@"Òñ$ÛpôÖSµ¤Wešg訕 €‘pÓ,ä€i÷êJ… _z{âÛü‘†âuðb0Ðô`4w†kWŸbòp–t/¼•^÷¶÷Y¥QµgæôVʈWU£'>½õôÖð®(¡;ý=ÈqöñÈì1¼—JŠ!áûˆB¤Øg¸÷]å¨jÚÁ×(…кù\Ý3tÔÊÀ˜QwÀ´{-›õÚùã·b W[!â»ãyÖßM>Q½ðþD-ª¶N~ØàBl§¶Õ¾‰..5‘ö ³]Ï 'ÛtöÐù{RZ)`¶\O²»O¡võVŽªM¹»Ö€+‘^*pq˜.¨›îuI~pþøãsS¸ˆ_W#ÈG!j1^FToªNËnNlh!6¸ ÐbÎì’$1Ì(‹’ä01{ ÿzcàï칹䯖¬=<­´ˆ‘ &–ø9Ïþµ›C;I ÚHÉñn“¥AJ 8—þ†3ÀÔú¨©ê¨8í£”´^ÑU|T¢ºñÖ¨Œ¨~!€?Þ½ó '«ª)ŠÿB[ S"‡iÄ|]ã¼P³çùâÀ¼Z 6N‚??Pêµ[~NÃUe›7C‹7댔"éá>BLçÕZùÔ¥•T-¥>¥¨—ªvæ)¤S,ǃÆl¨œ!UáQ(P­¬GmAùõålºœq*¿U±Ré¶ .]”àrhJ›ûcÞxžôp˜H)gÀ¹Ôðú>·øZ}JQ5.%¿D•€Õ`L«=›Õ?1f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3fìÖ¬– ,‰zL™ga̘„¨ ŧKq£Öè¾LQdÁlôë ¬9CÃãrnF*¹³Z-™¦)+3V’“¯m꺜®ánØ*Cø×¤Ô8DÉî&\}—MÀÿ€ÏP$Lš>i”¯(Hk:æ^cg³J²üÛ…?ƒ«JµÊŸÃN Öèש‰&*+»µe±­ô±ê³ôðp¿½KÆ#óÞBó›Åx¾$ŽvëjÏ4MŒÇiuzç eËîðB°|CÁésk£ØDõX§ÂÊæn¸Ø–SìOæ¿¶)f[âb”,Ãå`)g¹‹vç9E1N«G²ÊR•»,^xª¸ ënOJô‰*!«Q«ªÖŸåÛa@zÅÞCvÍvd=QV6NãX`¹FŸ»q¢Êˆ!ðk'Oo…09Þ™Ý;ájµÿÌýkZR’ð}ý)/¹ yÀ,$©TºÜD}VãI=|1•ÂJ!™ÊSµðžýc o<]‡‚-$ª:û"ÚDß55Vºg‹îW—¨UUûvpEµÖœªÚñ{ý±=JäEÜ›ë» ¯7íp°qF¡jàñh®þò¤I~ç–«Á¯§6³zõrZPµÇw`,Á‰*S3⽡{;'uoÊÛžNUK9ëÜZ=|1•§?¾ïÖSÕ}þ17žNU 6/¯ã>:Ôígz/ï¬t¼ð~ùë¢âEÓN3CÒ¥Æ;ú,Ì7Ï?¢ÑgeáuûŸ¯s”“$ªvÞ;ÎëU>ú‚{©ÁOjY¹&Q“¢FBåUœ©{)„T)Nå`)g ÝGúU’®}}@Æ-¤òŠÊS}3IN¼ðTªÒ°º»ú8íf:/kÂÅ÷xœ¿ž¡íÝ„xäÝ J·¾gÆ–cî¾K&U¶þl”­úmß–ïä‚Af*aRUϪQ—C 5>ŸEB$КÕås²â^^¹¹jZöØão5Eõ¸K;K/WáuVEÆ­ÒTå¾IN¼ðÔX…ŽÕSDÔ'«Qafø©x=£#?ƪlÃq¯{ö|J…ÅjFp‡Õ9§ï’áOnè̆ó‚ÅY‘?ö ÆŸÄ ¢Dß¶ÂÞ,jß“·_˜ %rA6Aõx1–v–¯±éL –ÂËá®´¸Ï O¡[Š¢ CV—5÷kp†·íoU¯g<.a÷ì±íêóPtïx¦#Û=»é$q:äç°šS›ñÏ ¸«ƒÃÔJÑËìçÓo¡¼{`?[~ëðn²R3~ù [©zì…¥œ%Pök~%ÞV/n—Mk¼œ×ùJÃÓ]¸«UG‹û”óIM?liÆ[]çeMÑýî¾Ý΃6”"è a—œFî0fÕ)À·STzac¦PNZ;¤v¶Êu+ï.¿µx§¹©?ÇYÕªÇ^XŠV2Gñç¬ÂÓÔ‹o޹ëLñRåú¤õ4°7BV—5E4@M•1cÆnF·S]9´1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ•Ùtuz¿oxû²ìäÒ¬Å}(5Šé´¦ÅnB­ÒºW²bÖÄR¥iN§7Îh:½ß7¼8‹ËˆÑÛ3™íÈêÔ§Rø›eK ay‰Zꂹ‚;ÏèïûðÂzW²byÐÉœ¸•] ßß"'Øpµh±VŒJ§·4<_Ô†ÿW¦üd^Ô¬Üåsqæ6vÅœZ·ßÑ=f©;û3”ú”Šß;NÓU¶yFÛe4¨aMD•ºG7JÕ( žj훀ģ_ F`À'ÀKŸ¹¿õ§•ïoa ±Æù¼ êôòË = ¹N¯ƒw;» ß3óÉF\¿ùÉF\`K/_A©ñ°ŠDÍNì¤×Ÿv¿h'ÛIöÈË v*×0Îéo¸ ¿Ûp‹#ùäõ:ÉöÂB ¼k¹N©? 7ÎGµ‹N k(”M£…亮nõZ{P¿r£‡§‚x'vNSða@@< ³ß:ª®mŠ/àþX>Ö?¾°¶Éþêô:—Uëô:x÷!Çwfqí®ßÄ5{8²ÒÊï™ùø>N$`–[{¬«åkí)å P•.±Uf»_bõ6½y¹åº¬¡¹î1ô†(Ê™†ÿc‡·¨ê#t.øÖ T¼pDl!¹®²5± \Pß±¨Ô°«ç§Ör2ë¸:(cÎAZ=/ãNí[%ˆG_â¢~;(«°+GUVƒ’{‰œ´®]¾P5¶ F–iüuz¼8Ôø„+,j<™ ”ò[ý$øX?R[…‡q……®uo²ê¢ŒRqj]biIâŒÚsh“ÎR¸î1«œÆ=k`Õ?|††ÿFއë챸µBãI">GTxõ2<¾!W礒írc¨Ô\J¸ºm.•ÓÕqã‘DQ×x•äôÍÓ4â¹ëÔòºzŽjµ(e^KMCt£ë~(uÄñ]³ÅM&×é- ï(ÊpÕ~r-ƒ ¯š;¤Ÿ´زƓ*a· ¢¼ã P£ej5 ¡{Ìï“ßwGVVÄ[{ZØJÍ IðQkåøÆ«Q-Ù./¬Š\nÓÕv(fÀ…®.ßêª7¼¨>=3ǶӲ¸¬™BT‘%Î >!5uDÐô´¤¼¯`ÿ¢çO¢Éÿå:½ÞÝ¿ÈñYG¹õÜZ%UåìLbž¨J<ª±°RgØÁ»›ÅÏú>°gÂ}–=²¢ê“LÔƒë[1QqdÅÏ i}?ÆÀ«éð£n¢ÊñǶ;Џ¥RUM qrrÐ-Û™”±ï`Æbxc¡K ­T[Ž,n)YâÊS•õØé´P÷,$¹·¡Nïb×õ×éuðîCŽOØbþ8wÃìV‚P¾-ÿß+ˆJ«; UãEÀ¯Ö%fÕƒÓ˜LBÜÚŸ¶/ì~IÖÐ\÷˜ÕBÃÜþ¯]}VUÀÃÞvAéPã› ’r<«Å’ÝA¿\x¬xjC¡†UYÍSO;žóÔÓrÉ 6Ô™î‚ÑÑŽiT{!èeqKɶ Q¯PKßÐ ðúóŽ,ްðéêô§Yd:½ÞÝëªðQxÍs·sQbù¸[JB«>zõwÇr]bŒN7åR&˜`’>–œî±ÈãV!ªú >t'º ŒÁ<Öêa¨*¼­ŸÚ;Ž^?­¤¦F)³O¶\H¾ƒºBTˆÌG383/_·”,qåÓJ»oO}õç)®Îlê‹Ý·ç~å(®ÓtzKËŒV¥Ê¯ž;;†ÁIöÉFµâ¢£{lÍ5²©>ºx;ÑEÄs‚ß¡ ]l¨Qšó²fð³f%2è¾sêKz2I7K|2Àa¡¤®=jמÚìR.:½TÞï^œÅÕé)H¡{Ü¥UŸJá@X×ihoiÎ{d[÷¬|–êuçåÉâÞH–¸òT:¢9m嚢»ÖÓéýþáÅŒƒŒ]Šõ¯Öw-tŸV ¡Št„m)YÜb²êU÷n3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3fÌX –Íí1­`ÌX!-4teAé%v¡<ç?|ㇶÔ&i_¾q†zë Ïð”É] e²R_Ä× ©|& c*kÖ€4fÔñÈ,J «U—øÜ_Äh“ø\1A¤„îîèù•¿éõÅ÷ºeL·ý-‰L\÷¬^çê~ÔP¹hrÃÉ*tqa0¯ƒfTêâ:ßMUùÅÛpÔ>µyd³u¥UÙÏYCÖA>†Ž€ákþ).,ù°+ɦ@Úb÷ÚjE)øÔW°â¾ÙÏ …ÆFÒ+Aþs$¢e¢6\äµQ9oI}4Èx<÷“U.ÕB?¢–BÕÂß«ë#ˆš$‘åHxì.x%,•Ìa!®RThwgd5zðÉÅ÷úDB·ýeŠŽþ².L7@¥*ïž AsduttWëâVUaà‹RU|–I xG¶߇$T®üÃëüñ-Ÿ¬Äë™#_œùIF÷NÀŒö_XufÕo÷ÙÂQ°IDͺI²Þ ?|×eŽ¿ÿå$Û|ê ¥îÙi{œŸŽtÏFÔÛNĸÜwÞs²qqñ?ÕíîäDß½m}o—/`Ó£ªCT±i ¬ñj÷·HÁ}ù2¾Þo^ÕŸÁñ|ªãí’ϧpä„+ýðP§ã;昭´?^$”^ü)«ÞtnÓ9VýâOí­êdDÅÀTŒñ›ÎÙóʘÿäYߪ® #jÓÇvÙþàÊRÕ!*Œë]|6©ÞîÊ!«œ¨~.«îMPx§ýïëG5þåØÚ÷9G6Q©Êçä…¯¹˜IWG·ªjãRT|–^|Yß…&—´gö|JuKØwÿž-w”íýÐçS=3­,ðœ‚7<Þ ßÿ ˆ‡È{oü…-³†¥xL(Eáúïx?Þ ’O¶ßY`¾# ßí¹š·Øß‘ Ì—kTÅHÈgŽEp#¢Fi¸ØqÅ3ð¿ßO2®½_NóîÆŸtëOåˆrR?Þ ./²ªˆºØÁ1œ‡õIEæ”ËÑ;³WNªÂ˜úŽ÷Ð5嘫b+º¿ÏOntutuçªøÖ6RôNéÃãѾ|ã:ßéêâêQµáb×åÓ[Aò–˜«T @ŸÜ€ÄÑÌe-¯óú8Ûhx?tÖ›Q½ŸøCâýïÚS˜‚ðÄCºâ>Hêo=´±ð’5}Œ ·•ùn ¿®´#„¦}ËoÇÞU(¶ãx ‘íåUÕò›<¦ ‚$Ÿk¨G/÷¸ÁÇU×t¥^ñ""ä÷ê9¨ë䮉óÚFv·ð+OîF8k¢±œTm:ê‡ám™*¬¥v0²&ÓÒÅÕ£j×ep’šœ[‘DYÍÇ÷¹ëqÖ3CÓ¹…mÚ!ŽÃÿËH×X¶ºŸm-“õÉQæ÷(£Š—6]ö^#'vvͪ\Q®ºØ¤®[§CT>Iž1 Oʧ+•¶¢—"!uwÏ´ÏÙéõѼ™JÕ5×½ñ»žW‡µ7HTÑ“ÒueóÍvÊ·JzN’ïUW}çL´ º%uÿ¢p&ì:Ô¼ •¨m´ïàƒ6f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘1cÆŒ3f̘±ÿ WY¦ŒÉœ$P,;AUžÓºJ]v†ë‚€ŒŽóÚúÄsßÕ§ ™¯ÚÅ¢{%kååð¨ówÆn£ƒeõd--¬üY™¡•¾øjö7‘ábáɦµˆ¾É®@„ –-/É7p]·ábÃų¯@ÑÁ« ];š`1“k†ƒÁÙµæôÖ€Ôà?*šªÃäè<'ˆ:ÏKßúUß? ¿ºïÉû~«Æ;Ö𮔆eŽAIéÚ:É¥-¯ˆÚk}¢±ÙÂòÄ !^ȯ-ðú5ÑÙ¡o\ÉÂ_í¾]å0Á/¹n xIUîÚ&XšÁef¸Íʬdk›Ôµ ¼Ð‘ýeW’$‘m½‚j®ëO±¾çžžl%e ‰påÎ~êé&RgÐÄžzúΆQ —NUÐÕùÖ^ O¨ÍÈoœCé°š:Ï¥â{f„4mùËÁœPì£è¯#_Sa„¢DÐÐ[¸ÌÑŸÜ ænK<².dúЉ=¤î ’¬@œ}Næ|üµ£Ê Qs~û¬˜ª±ÏŽ›^±Ðúeâÿtýkœ±j•¦]ܽÎSÑ'²šž™¨ ‹v•cke¼ŒñeñM’ýà<ÿÜü"E§:סåä¾¹ä̱í囫âsß-Êß]^• ´ }(¢µ#Jü,œkÜ« È¸w!=3B5¾ð²òK¯ùÔ^ó©Ýj…3FҬﳽãr¹S7QÕ3ÚRæª<¶'J9"¡”]|È_ìˆÐ—‡Á%ÇêØ/Þÿ# TÇé­cGqn"£ê[­cGQ Ñ™†÷gÆŽ¾Õ*iêVÔ!jTú2%ТÈtuhcä•(;²MÙе¼|Çõ' RƸçHge-ƒ«S»ÚÙ1å ˜c½í,µ+¸šjª¢ ©†ýç25{¾²©zu͵¯cx'-¹ÞiË6‚γƒosw–-Ãëµ´¹ªã4”–ΰgØž^'“1 KËð½¶ø\d@ãf#iÿÞ0 †øÙÀ¡=‡ö@Ò%ß5Èz£Ý·ƒûuˆ÷tØ!ì¾]âŠØ±·M|þ×ð![@QDL§ÂÙ;ö7U ßѾ€3ÔÕŠM<Äë¦þÌj[=GH¬ú%¹ûuí-,¼$ë‚SY]ç›…²¨fù­_Á‹—ÌŸËðzD]ü^•6WåÏ€òâNww|²v`ªikMÚ¾cûiqQ–Þ–¾WÂùX°85¢Vͯš§èriÑáI †'ívVG.x R«ÞöZ aN"Fá| 'áã…ÒÚz½/é=bÝó:ÏѨu•—&~Ó¹îÙÎoC¿Ûõ¼ᱎÞnñ{Uê\U®½\z€ôüÃBûY—«ë\I£TÔŸE=ÚªŠ™=ÚÝR9êE£7ùÏÔ†'®b7F.ëd.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(){return clearInterval(this.interval),this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this;return this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),!a.support.transition&&this.$element.hasClass("slide")?(this.$element.trigger("slide"),d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")):(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.trigger("slide"),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})),f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=typeof c=="object"&&c;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():e.cycle()})},a.fn.carousel.defaults={interval:5e3},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find(".in"),e;d&&d.length&&(e=d.data("collapse"),d.collapse("hide"),e||d.data("collapse",null)),this.$element[b](0),this.transition("addClass","show","shown"),this.$element[b](this.$element[0][c])},hide:function(){var a=this.dimension();this.reset(this.$element[a]()),this.transition("removeClass","hide","hidden"),this.$element[a](0)},reset:function(a){var b=this.dimension();this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element.addClass("collapse")},transition:function(b,c,d){var e=this,f=function(){c=="show"&&e.reset(),e.$element.trigger(d)};this.$element.trigger(c)[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e=c.attr("data-target"),f,g;return e||(e=c.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,"")),f=a(e),f.length||(f=c.parent()),g=f.hasClass("open"),d(),!g&&f.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('