diff --git a/.gitignore b/.gitignore index 7bac31d5a..d4f687c7b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,5 @@ .DS_Store +export/* public/* -source/* -!public/listeners/* -!public/styleguide/* -!public/patterns/**/* -!public/data/*.js -config.ini -latest-change.txt -*-ck.js +source/styleguide/* +vendor/* diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 0c3e5b8a7..000000000 --- a/CHANGELOG +++ /dev/null @@ -1,170 +0,0 @@ -THIS CHANGELOG IS AN ATTEMPT TO DOCUMENT CHANGES TO THIS PROJECT. - -PL-v0.7.8 - - ADD: can show annotations on view-all pages by default - - FIX: can target pattern divs and apply annotations - -PL-v0.7.7 - - ADD: can hide all of the patterns for a given pattern type from being shown on the styleguide. good for nested pages/templates - - FIX: the MQ menu is hidden on smaller viewports - -PL-v0.7.6 - - FIX: pattern search now searches the entire name of a pattern - - FIX: the MQ menu lines up with the navigation item - -PL-v0.7.5 - - ADD: a quick pattern search using typeahead - - ADD: keyboard shortcuts for a bunch of features using jwerty - - ADD: using cmd+a/ctrl+a when in code view selects the contents of the currently active tab - - ADD: code and annotation views can be opened automatically on load via query string params - - ADD: can use the config to remove items from pattern nav - - ADD: check for json support now that certain flavors of PHP 5.5.3 don't come with it - - ADD: can use boolean vars to enable/disable sections via pattern parameters - - ADD: pattern states for tracking progress on individual patterns - - FIX: updated icomoon icons - - FIX: code view has tabs - - FIX: code view shows mustache versions of a pattern - - FIX: patterns are properly sorted in style guide and view all views - - FIX: pattern lab-specific JS & CSS is only loaded when in the iframe - - FIX: classlist polyfill for better IE9 support - - FIX: stringified the postmessage messages for better IE9 support - - FIX: make sure history is only used by browsers that support it (e.g. IE9 doesn't) - - FIX: using watcher-launched auto-reload server now works on Windows - - FIX: various bugs with lineage - - FIX: vendored third-party JS and CSS - - FIX: infinite refresh bug squashed - - THX: thanks to @joshrcook for some styling fixes and hitting on the cause of the start-up issues on ubuntu - - THX: thanks to @tylersticka for lots of ideas: pattern states, cmd+a, boolean pattern parameters and the feedback on the watcher - - THX: thanks to @nikvm for the fix for properly sorting the styleguide view - - THX: thanks to @aarongustafson for the idea to only load the JS when it's in the iframe - -PL-v0.7.2 - - FIX: proper support for Windows with the changes that happened in v0.7.0 - - THX: thanks to @chriskevin and @MattKohnen for reporting the issue - -PL-v0.7.1 - - FIX: annotation event should only fire when overlay is active - - FIX: styleguide should properly sort patterns - - THX: thanks to @jplhomer for the heads up on the annotations issue - - THX: thanks to @tylersticka for the heads up on the styleguide issue - -PL-v0.7.0 - - ADD: auto-reload server can be started directly from the watcher - - ADD: pattern parameter support - - ADD: styleModifier support - - ADD: pseudo-pattern support - - ADD: RAM usage now outputted when generating the site - - ADD: an easter egg - - ADD: configuration flag for cleanPublic - - ADD: dedicated pattern header and footer files - - ADD: QR code generator to make mobile testing easier - - ADD: reverse lineages to see where a pattern is used - - ADD: if _data.json contains a reserved keyword an error is thrown - - ADD: closer to being PSR-0 and PSR-1 compatible - - ADD: migrator class to handle file moves/updates between versions - - ADD: configurer class to handle managing the configuration file - - FIX: ran JS hint against project JavaScript - - FIX: attempted to add better cache busting - - FIX: reorganized the project for better upgradeability by moving lots to core/ - - FIX: malformed JSON throws error and gives file name - - FIX: code view styles - - FIX: annotation styles and functionality are now more robust - - FIX: mobile styles are more robust including scrolling on iOS7 - - FIX: drop down interaction - - FIX: refactored how patterns and view all pages are gathered and generated - - FIX: lineage list now hidden if pattern doesn't have a lineage - - FIX: listitems.json and data.json default attributes match - - FIX: an existing config.ini file is automatically updated with new version - - FIX: pull bar now works in Firefox - - FIX: history now works in Firefox - - FIX: renamed the websocket servers - - THX: thanks to @faustgertz for some fixes with the new watcher class - - THX: thanks to @coding-stuff for the original idea and original code for pattern parameters - - THX: thanks to @mattwellss for inspiring the PSR compliant changes as well as changes to the configuration - -PL-v0.6.4 - - FIX: using # for a link won't cause a jump - - THX: thanks to @tylersticka for the heads up - -PL-v0.6.3 - - FIX: making sure code view is properly encoded - - THX: thanks to @tylersticka for the heads up - -PL-v0.6.2 - - FIX: a few small sass and styling tweaks - - THX: thanks to @griffinartworks for the sass and styling fixes - -PL-v0.6.1 - - FIX: fixed the height of the HTML pre element on the pattern detail view - - ADD: added in support for viewing the generated CSS on the pattern detail view - -PL-v0.6.0 - - ADD: a UI list of the current media query widths from the CSS - - ADD: a pattern's "lineage" now displays in the UI under code view - - ADD: annotations can be added to DOM elements of patterns - - ADD: separate annotation views on the list view and pattern details views - - ADD: generate() now "cleans" public/ before generating the site by deleting most everything - - ADD: added support for the css rule saver library - - ADD: can use a flag to generate the specific CSS that is used in a pattern. shows on code view when available. - - ADD: mark-up for a pattern is now included in the UI under code view - - FIX: can open the "raw" version of a pattern in a new window - - FIX: frame resizing bar properly supports decimals - - FIX: the checkboxes for the websocket-based features, page follow & auto-reload, now work - - FIX: postmessage calls now centralized and refactored - - FIX: units appear in the toolbar when using Hay! mode - - FIX: patterns shouldn't be cached - - THX: thanks to @benedfit for the MQ idea which he originally named "phases" - - THX: thanks to @alienlebarge for the "clean public/" idea - -PL-v0.3.6 - - FIX: added a delay to the watcher so the CPU doesn't get maxed - - THX: thanks to martin berglund for the heads up - -PL-v0.3.5 - - ADD: an explicit MIT license - - FIX: updated .gitignore so that it's more flexible - - THX: thanks to @alienlebarge for the .gitignore fix - -PL-v0.3.4 - - FIX: Generator class renamed because it's a reserved name in PHP 5.5 - - THX: thanks to @faustgertz for the heads up - -PL-v0.3.3 - - FIX: links created with {{ link.pattern }} now have the correct path - - FIX: links within a pattern now properly update the history - - FIX: simplified the history updates from a pattern - - THX: thanks to @kevin-heil for the fix for {{ link.pattern }} - -PL-v0.3.2 - - ADD: added .svn to the ignore dirs listing when checking the source dir - - FIX: top-level ignored dirs are now found properly - - THX: thanks to @alienlebarge for the heads up regarding .svn dirs - -PL-v0.3.1 - - FIX: made sure the command scripts work in directories that contain spaces - - THX: thanks to @mattsims for the heads up - -PL-v0.3.0 - - ADD: added "all" link to the nav that takes the user back to the style guide - - ADD: title tag updates when switching patterns - - FIX: if a pattern type or pattern sub-type doesn't have any patterns it's removed from the nav - - FIX: added styleguide.css to the pattern header - - FIX: commented out the video & audio patterns to address an issue w/ Chrome 29, frames, & History API - - FIX: reduced the number of comments called in the comment-thread pattern - - FIX: patterns won't try to auto-reload if viewed directly - - THX: thanks to @bmuenzenmeyer for the "all link" suggestion - -PL-v0.2.0 - - ADD: better styling in the overall navigation (via @geibi) - - FIX: better windows support for the generator and watcher - - FIX: more comprehensive "apache-less" support - - FIX: debian linux path issue when loading mustache - - FIX: pattern fix which mis-used an ID - - FIX: widths in 'ish are now properly updated onload - - THX: thanks to @benedfit & @bmuenzenmeyer for the help w/ windows - - THX: thanks to @geibi for the pull request with the improved nav style - - THX: thanks to @juanmi007 for alerting me to issues on debian - - THX: thanks to @lewisnyman for the pattern fix - -PL-v0.1.0 - - ADD: re-launch of the PHP version of Pattern Lab \ No newline at end of file diff --git a/LICENSE b/LICENSE index 465444edd..bd36c1262 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-14 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com +Copyright (c) 2013-2016 Brad Frost, http://bradfrostweb.com & Dave Olsen, http://dmolsen.com 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 diff --git a/README.md b/README.md index 319eb847f..04543132c 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,101 @@ -## About the PHP Version of Pattern Lab +![license](https://img.shields.io/github/license/pattern-lab/patternlab-php.svg) +[![Packagist](https://img.shields.io/packagist/v/pattern-lab/edition-mustache-standard.svg)](https://packagist.org/packages/pattern-lab/edition-mustache-standard) [![Gitter](https://img.shields.io/gitter/room/pattern-lab/php.svg)](https://gitter.im/pattern-lab/php) -The PHP version of Pattern Lab is, at its core, a static site generator. It combines platform-agnostic assets, like the [Mustache](http://mustache.github.io/)-based patterns and the JavaScript-based viewer, with a PHP-based "builder" that transforms and dynamically builds the Pattern Lab site. By making it a static site generator, the PHP version of Pattern Lab strongly separates patterns, data, and presentation from build logic. The PHP version should be seen as a reference for other developers to improve upon as they build their own Pattern Lab Builders in their language of choice. +# Pattern Lab Standard Edition for Mustache + +The Pattern Lab Standard Edition for Mustache is the evolution of Pattern Lab 1. Pattern Lab is still, at its core, a prototyping tool focused on encouraging communication between content creators, designers, devs, and clients. It combines platform-agnostic assets, like the [Mustache](http://mustache.github.io/)-based patterns, with a PHP-based "builder." Pattern Lab 2 introduces [the beginnings of an ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html) that will allow teams to mix, match and extend Pattern Lab to meet their specific needs. It will also make it easier for the Pattern Lab team to push out new features. Pattern Lab Standard Edition for Mustache is just [one of the four PHP-based Editions currently available](http://patternlab.io/docs/installation.html). ## Demo -You can play with a demo of the front-end of the PHP version of Pattern Lab at [demo.pattern-lab.info](http://demo.pattern-lab.info). +You can play with a demo of the front-end of Pattern Lab at [demo.patternlab.io](http://demo.patternlab.io). + +## Requirements + +To use the basic features of Pattern Lab to compile patterns, you must have **PHP 5.4+** installed. On Mac OS X Pattern Lab should work "out of the box." If you're on Windows you can [download PHP from PHP.net](http://windows.php.net/download/). Pattern Lab comes with its own built-in web server. + +Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. It's required if you want to install Pattern Lab using Composer's `create-project` command or if you want to upgrade Pattern Lab in the future. + +## Installing + +There are two methods for downloading and installing the Standard Edition for Mustache: + +* Download a pre-built project +* Create a project based on this Edition with Composer + +### Download a pre-built project + +The fastest way to get started with Pattern Lab's Standard Edition for Mustache is to download the latest pre-built version from the [releases page](https://github.com/pattern-lab/patternlab-php/releases/latest). + +### Use Composer to create a project + +Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. + +#### 1. Install Composer + +Please follow the directions for [installing Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) on the Composer website. We recommend you [install it globally](https://getcomposer.org/doc/00-intro.md#globally). + +#### 2. Install the Standard Edition for Mustache + +Use Composer's [`create-project` command](https://getcomposer.org/doc/03-cli.md#create-project) to install the Standard Edition for Mustache into a location of your choosing. To create a project do the following: + +1. In a terminal window navigate to where you want to install Pattern Lab +2. Type `composer create-project pattern-lab/edition-mustache-standard patternlab2-example && cd $_` +3. When prompted, type `1` to install the demo StarterKit + +This will install the Standard Edition for Mustache along with the demo StarterKit into a directory called `patternlab2-example`. You will be automatically dropped into `patternlab2-example/` when the install is finished. + +**Note:** If you clone or download this repository and use `composer install` to install the project dependencies you'll need to type the following to install the demo StarterKit: + + composer install-demo + +Otherwise you'll have a very bare set-up of Pattern Lab. + +## Get Up and Running + +After installing do the following to start and view Pattern Lab: + +1. In a terminal window navigate to the root of your project if you aren't there already +2. Type `php core/console --server --with-watch` + +You should now be able to open [http://localhost:8080](http://localhost:8080) to see your generated site. Any changes you make in `./source/` will automatically rebuild your site and reload your browser. + +As you get more comfortable with Pattern Lab you can [integrate it with a Gulp or Grunt workflow](http://patternlab.io/docs/advanced-integration-with-grunt.html) and drop some of the native Pattern Lab features like automatic browser reload. You can also check out [the list of plugins](http://patternlab.io/download.html). + +## More Documentation + +Obviously Pattern Lab is deeper than the install process. [Check out the documentation](https://patternlab.io/docs/) to learn about how to use patterns, how to modify the data used to populate those patterns, and about some advanced features. + +## Migrating from Pattern Lab 1 to Pattern Lab 2 + +Pattern Lab 2 was a complete rewrite and reorganization of Pattern Lab 1. [Learn about the changes](http://patternlab.io/docs/changes-1-to-2.html). After installing the Standard Edition for Mustache do the following to migrate from Pattern Lab 1 to Pattern Lab 2: -## Getting Started +1. Copy `./source` from your old project to your new install +2. Copy `./source/_patterns/00-atoms/00-meta/_00-head.mustache` to `./source/_meta/_00-head.mustache` +3. Copy `./source/_patterns/00-atoms/00-meta/_01-foot.mustache` to `./source/_meta/_00-foot.mustache` +4. Copy `./source/_data/annotations.js` to `./source/_annotations/annotations.js` -The PHP version of Pattern Lab should be relatively easy for anyone to get up and running. +Everything else should work without changes. -* [Requirements](http://pattern-lab.info/docs/requirements.html) -* [Installing the PHP Version of Pattern Lab](http://pattern-lab.info/docs/installation.html) -* [Upgrading the PHP Version of Pattern Lab](http://pattern-lab.info/docs/upgrading.html) -* [Generating the Pattern Lab Website for the First Time](http://pattern-lab.info/docs/first-run.html) -* [Editing the Pattern Lab Website Source Files](http://pattern-lab.info/docs/editing-source-files.html) -* [Using the Command-line Options](http://pattern-lab.info/docs/command-line.html) -* [Command Prompt on Windows](http://pattern-lab.info/docs/command-prompt-windows.html) +## Need Pattern Lab 1? -## Working with Patterns +The [source code for Pattern Lab 1](https://github.com/pattern-lab/patternlab-php/releases/tag/v1.1.0) is still available for download. -Patterns are the core element of Pattern Lab. Understanding how they work is the key to getting the most out of the system. Patterns use [Mustache](http://mustache.github.io/) so please read [Mustache's docs](http://mustache.github.io/mustache.5.html) as well. +## Packaged Components -* [How Patterns Are Organized](http://pattern-lab.info/docs/pattern-organization.html) -* [Adding New Patterns](http://pattern-lab.info/docs/pattern-add-new.html) -* [Reorganizing Patterns](http://pattern-lab.info/docs/pattern-reorganizing.html) -* [Including One Pattern Within Another via Partials](http://pattern-lab.info/docs/pattern-including.html) -* [Managing Assets for a Pattern: JavaScript, images, CSS, etc.](http://pattern-lab.info/docs/pattern-managing-assets.html) -* [Modifying the Pattern Header and Footer](http://pattern-lab.info/docs/pattern-header-footer.html) -* [Using Pseudo-Patterns](http://pattern-lab.info/docs/pattern-pseudo-patterns.html) -* [Using Pattern Parameters](http://pattern-lab.info/docs/pattern-parameters.html) -* [Using Pattern State](http://pattern-lab.info/docs/pattern-states.html) -* ["Hiding" Patterns in the Navigation](http://pattern-lab.info/docs/pattern-hiding.html) -* [Adding Annotations](http://pattern-lab.info/docs/pattern-adding-annotations.html) -* [Viewing Patterns on a Mobile Device](http://pattern-lab.info/docs/pattern-mobile-view.html) +The Standard Edition for Mustache installs the following components: -## Creating & Working With Dynamic Data for a Pattern +* `pattern-lab/core`: [GitHub](https://github.com/pattern-lab/patternlab-php-core), [Packagist](https://packagist.org/packages/pattern-lab/core) +* `pattern-lab/patternengine-mustache`: [documentation](https://github.com/pattern-lab/patternengine-php-mustache#mustache-patternengine-for-pattern-lab-php), [GitHub](https://github.com/pattern-lab/patternengine-php-mustache), [Packagist](https://packagist.org/packages/pattern-lab/patternengine-mustache) +* `pattern-lab/plugin-reload`: [GitHub](https://github.com/pattern-lab/plugin-php-reload), [Packagist](https://packagist.org/packages/pattern-lab/plugin-reload) +* `pattern-lab/styleguidekit-assets-default`: [GitHub](https://github.com/pattern-lab/styleguidekit-assets-default), [Packagist](https://packagist.org/packages/pattern-lab/styleguidekit-assets-default) +* `pattern-lab/styleguidekit-mustache-default`: [GitHub](https://github.com/pattern-lab/styleguidekit-mustache-default), [Packagist](https://packagist.org/packages/pattern-lab/styleguidekit-mustache-default) -The PHP version of Pattern Lab utilizes Mustache as the template language for patterns. In addition to allowing for the [inclusion of one pattern within another](https://github.com/pattern-lab/patternlab-php/wiki/Including-One-Pattern-Within-Another) it also gives pattern developers the ability to include variables. This means that attributes like image sources can be centralized in one file for easy modification across one or more patterns. The PHP version of Pattern Lab uses a JSON file, `source/_data/data.json`, to centralize many of these attributes. +## List All of the Available Commands and Their Options -* [Introduction to JSON & Mustache Variables](http://pattern-lab.info/docs/data-json-mustache.html) -* [Overriding the Central `data.json` Values with Pattern-specific Values](http://pattern-lab.info/docs/data-pattern-specific.html) -* [Linking to Patterns with Pattern Lab's Default `link` Variable](http://pattern-lab.info/docs/data-link-variable.html) -* [Creating Lists with Pattern Lab's Default `listItems` Variable](http://pattern-lab.info/docs/data-listitems.html) +To list all available commands type: -## Using Pattern Lab's Advanced Features + php core/console --help -By default, the Pattern Lab assets can be manually generated and the Pattern Lab site manually refreshed but who wants to waste time doing that? Here are some ways that the PHP version of Pattern Lab can make your development workflow a little smoother: +To list the options for a particular command type: -* [Watching for Changes and Auto-Regenerating Patterns](http://pattern-lab.info/docs/advanced-auto-regenerate.html) -* [Auto-Reloading the Browser Window When Changes Are Made](http://pattern-lab.info/docs/advanced-reload-browser.html) -* [Multi-browser & Multi-device Testing with Page Follow](http://pattern-lab.info/docs/advanced-page-follow.html) -* [Keyboard Shortcuts](http://pattern-lab.info/docs/advanced-keyboard-shortcuts.html) -* [Special Pattern Lab-specific Query String Variables ](http://pattern-lab.info/docs/pattern-linking.html) -* [Preventing the Cleaning of public/](http://pattern-lab.info/docs/advanced-clean-public.html) -* [Generating CSS](http://pattern-lab.info/docs/advanced-generating-css.html) -* [Modifying the Pattern Lab Nav](http://pattern-lab.info/docs/advanced-pattern-lab-nav.html) -* [Integration with Compass](http://pattern-lab.info/docs/advanced-integration-with-compass.html) \ No newline at end of file + php core/console --help --[command] diff --git a/composer.json b/composer.json new file mode 100644 index 000000000..f5106e938 --- /dev/null +++ b/composer.json @@ -0,0 +1,68 @@ +{ + "name": "pattern-lab/edition-mustache-standard", + "description": "The Standard Edition of Pattern Lab for Mustache. Installs all Mustache-related dependencies.", + "keywords": ["pattern lab", "mustache"], + "homepage": "http://patternlab.io", + "license": "MIT", + "type": "project", + "authors": [ + { + "name": "Dave Olsen", + "email": "dmolsen@gmail.com", + "homepage": "http://dmolsen.com", + "role": "Lead Developer" + } + ], + "support": { + "issues": "https://github.com/pattern-lab/patternlab-php/issues", + "wiki": "http://patternlab.io/docs/", + "source": "https://github.com/pattern-lab/patternlab-php/releases" + }, + "autoload": { + "psr-0": { + "PatternLab": "core/src/" + } + }, + "require": { + "php": ">=5.4", + "pattern-lab/core": "^2.0.0", + "pattern-lab/patternengine-mustache": "^2.0.0", + "pattern-lab/styleguidekit-mustache-default": "^3.0.0", + "pattern-lab/plugin-reload": "^2.0.0" + }, + "scripts": { + "server": "php core/console --server", + "generate": "php core/console --generate", + "watch": "php core/console --watch", + "start": "php core/console --server --with-watch", + "install-demo": "php core/console --starterkit --install pattern-lab/starterkit-mustache-demo", + "post-install-cmd": [ + "PatternLab\\Installer::postInstallCmd" + ], + "post-update-cmd": [ + "PatternLab\\Installer::postUpdateCmd" + ], + "post-root-package-install": [ + "PatternLab\\Installer::setProjectInstall", + "PatternLab\\Installer::getSuggestedStarterKits", + "PatternLab\\Installer::getConfigOverrides" + ], + "post-package-install": [ + "PatternLab\\Installer::postPackageInstall" + ], + "post-package-update": [ + "PatternLab\\Installer::postPackageUpdate" + ], + "pre-package-uninstall": [ + "PatternLab\\Installer::prePackageUninstall" + ] + }, + "extra": { + "patternlab": { + "starterKitSuggestions": [ + "pattern-lab/starterkit-mustache-demo", + "pattern-lab/starterkit-mustache-base" + ] + } + } +} diff --git a/config/README b/config/.gitkeep similarity index 100% rename from config/README rename to config/.gitkeep diff --git a/core/autoReloadServer.php b/core/autoReloadServer.php deleted file mode 100755 index 9c3ede53b..000000000 --- a/core/autoReloadServer.php +++ /dev/null @@ -1,45 +0,0 @@ -register(); - -// parse the main config for the content sync port -if (!($config = @parse_ini_file(__DIR__."/../config/config.ini"))) { - print "Missing the configuration file. Please build it using the Pattern Lab builder.\n"; - exit; -} - -// give it a default port -$port = ($config) ? trim($config['autoReloadPort']) : '8001'; -$args = getopt("s"); -$newlines = (isset($args["s"])) ? true : false; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application -$server->registerApplication('autoreload', new \Wrench\Application\AutoReloadApplication($newlines)); - -if (!isset($args["s"])) { - print "\n"; - print "Auto-reload Server Started...\n"; - print "Use CTRL+C to stop this service...\n"; -} - -// run it -$server->run(); diff --git a/core/builder.php b/core/builder.php deleted file mode 100644 index 55cbe4228..000000000 --- a/core/builder.php +++ /dev/null @@ -1,117 +0,0 @@ -register(); - -$loader = new SplClassLoader('Mustache', __DIR__.'/lib'); -$loader->setNamespaceSeparator("_"); -$loader->register(); - -// make sure this script is being accessed from the command line -if (php_sapi_name() != 'cli') { - print "The builder script can only be run from the command line.\n"; - exit; -} - -// grab the arguments from the command line -$args = getopt("gwcrv"); - -// load Pattern Lab's config, if first time set-up move files appropriately too -$co = new PatternLab\Configurer; -$config = $co->getConfig(); - -// show the version of Pattern Lab -if (isset($args["v"])) { - print "You're running v".$config["v"]." of the PHP version of Pattern Lab.\n"; - exit; -} - -// generate the pattern lab site if appropriate -if (isset($args["g"]) || isset($args["w"])) { - - $g = new PatternLab\Generator($config); - $c = false; - - // check to see if CSS for patterns should be parsed & outputted - if (isset($args["c"]) && !isset($args["w"])) { - $c = true; - } - - $g->generate($c); - - // have some fun - if (!isset($args["w"])) { - $g->printSaying(); - } - -} - -// watch the source directory and regenerate any changed files -if (isset($args["w"])) { - - $w = new PatternLab\Watcher($config); - $a = false; - - if (isset($args["r"])) { - $a = true; - } - - $w->watch($a); - -} - -// when in doubt write out the usage -if (!isset($args["g"]) && !isset($args["w"]) && !isset($args["v"])) { - - print "\n"; - print "Usage:\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -g\n"; - print " Iterates over the 'source' directories & files and generates the entire site a single time.\n"; - print " It also cleans the 'public' directory.\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -gc\n"; - print " In addition to the -g flag features it will also generate CSS for each pattern. Resource instensive.\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -w\n"; - print " Generates the site like the -g flag and then watches for changes in the 'source' directories &\n"; - print " files. Will re-generate files if they've changed.\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -wr\n"; - print " In addition to the -w flag features it will also automatically start the auto-reload server.\n\n"; - print " php ".$_SERVER["PHP_SELF"]." -v\n"; - print " Prints out the current version of Pattern Lab.\n\n"; - -} diff --git a/core/config/config.ini.default b/core/config/config.ini.default deleted file mode 100644 index 70f9495aa..000000000 --- a/core/config/config.ini.default +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Configuration Options for Pattern Lab - * If config.ini doesn't exist Pattern Lab will try to create a new version - */ - -v = "0.7.8" - -// file extensions to ignore when building or watching the source dir, separate with a comma -ie = "scss,DS_Store,less" - -// directories and files to ignore when building or watching the source dir, separate with a comma -id = "scss,.svn" - -// choose which ports the websocket services should run on -autoReloadPort = "8002" -pageFollowPort = "8003" - -// whether the public directory should be cleaned when generating your site -cleanPublic = "true" - -// pattern lab's xip host if you have it configured -xipHostname = "http://patternlab.*.xip.io" - -// which, if any, controls to hide in the nav -ishControlsHide = "" - -// the order of pattern states -patternStates = "inprogress,inreview,complete" - -// the pattern types that shouldn't be included in the style guide -styleGuideExcludes = "" \ No newline at end of file diff --git a/core/console b/core/console new file mode 100644 index 000000000..51e4c0d14 --- /dev/null +++ b/core/console @@ -0,0 +1,46 @@ +dispatch("config.configLoadEnd"); + +// run the console +Console::run(); diff --git a/core/lib/CSSRuleSaver/CSSRuleSaver.php b/core/lib/CSSRuleSaver/CSSRuleSaver.php deleted file mode 100644 index 412e17f4c..000000000 --- a/core/lib/CSSRuleSaver/CSSRuleSaver.php +++ /dev/null @@ -1,266 +0,0 @@ -ruleSets and $this->atRules arrays - * @param {String} the filename of the CSS file - */ - public function loadCSS($file) { - - if (!file_exists($file)) { - $this->error("The CSS file you supplied doesn't seem to exist. Check the path."); - } - - $commentOpen = false; - $atRuleOpen = false; - $declarationBlockOpen = false; - $fontFaceRuleOpen = false; - - $atRule = ""; - $declarationBlock = ""; - $selectors = ""; - - // iterate over the given file and parse it into at-rules, selectors and their given declaration blocks - $fp = fopen($file, "r"); - while(!feof($fp)) { - $current_line = fgets($fp); - if (!feof($fp)) { - - if ((strpos($current_line, "/*") !== false) && (strpos($current_line, "*/") === false)) { - - // matched a comment that *didn't* close on the same line - $commentOpen = true; - - } else if (strpos($current_line, "*/") !== false) { - - // comment closed - $commentOpen = false; - - } else if ($commentOpen) { - - // skip this line of the CSS file because we're inside a comment - - } else if (strpos($current_line, "@") !== false) { - - // matched an at-rule like a media query - $atRuleOpen = true; - $atRule = trim(str_replace("{","",$current_line)); - - // handle the weird case of the @font-face at-rule - if (strpos($current_line, "@font-face") !== false) { - $declarationBlock = ""; - $declarationBlockOpen = true; - $fontFaceRuleOpen = true; - } - - } else if (strpos($current_line, "{") !== false) { - - // matched the opening of a declaration block - $declarationBlock = ""; - $declarationBlockOpen = true; - $selectors = trim(str_replace("{","",$current_line)); - - } else if (strpos($current_line, "}") !== false) { - - // matched the closing of a declaration block or at-rule - if ($atRuleOpen && !$declarationBlockOpen) { - - // it was an at-rule. close it up - $atRuleOpen = false; - - } else { - - // it was a declaration block. close it up. - $declarationBlockOpen = false; - $declarationBlock .= "\t".trim(str_replace("}","",$current_line)); - - // if we're within an at-rule assign all the styles to it (e.g. styles under a media query) - if ($atRuleOpen) { - if (!array_key_exists($atRule,$this->atRules)) { - $this->atRules[$atRule] = array(); - } - $this->atRules[$atRule][$selectors] = !array_key_exists($selectors,$this->atRules[$atRule]) ? "\t".trim($declarationBlock) : $this->atRules[$atRule][$selectors]."\n\t".trim($declarationBlock); - } else { - $this->ruleSets[$selectors] = !array_key_exists($selectors,$this->ruleSets) ? "\t".trim($declarationBlock) : $this->ruleSets[$selectors]."\n\t".trim($declarationBlock); - } - - // wait, a font-face rule was open. close it all up - if ($fontFaceRuleOpen) { - $fontFaceRuleOpen = false; - $atRuleOpen = false; - } else if (substr_count($current_line, "}") > 1) { - - // oops, someone closed the at-rule on the same line as the declaration block - // *shakes fist at sass* - $atRuleOpen = false; - } - } - } else if ($declarationBlockOpen) { - - // declaration block is open so keep reading it in - $declarationBlock .= "\t".ltrim($current_line); - - } - } - } - fclose($fp); - - } - - /** - * Load the HTML data - * @param {String} the filename of the HTML file - */ - public function loadHTML($file,$load = true) { - if ($load) { - if (file_exists($file)) { - $this->htmlData = file_get_contents($file); - } else { - $this->error("The HTML file you supplied doesn't seem to exist. Check the path."); - } - } else { - $this->htmlData = $file; - } - } - - /** - * Save the CSS rules that match between the given CSS file and the HTML file - * - * @return {String} the rules that match between the given CSS file and HTML file - */ - public function saveRules() { - - // make sure data exists to compare - if (($this->htmlData == "") || (count($this->ruleSets) == 0)) { - $this->error("This would work better if there was CSS or HTML data."); - } - - // set-up the selector DOM to compare - $this->dom = new SelectorDOM($this->htmlData); - - // iterate over the default rule sets and test them against the given mark-up - $statements = ""; - foreach ($this->ruleSets as $selector => $declarationBlock) { - $statements .= $this->buildRuleSet($selector,$declarationBlock); - } - - // iterate over the at-rules - foreach ($this->atRules as $atRule => $ruleSets) { - - // iterate over the rule sets in the at-rules and test them against the given mark-up - $atRuleSets = ""; - foreach ($ruleSets as $selector => $declarationBlock) { - $atRuleSets .= $this->buildRuleSet($selector,$declarationBlock,"\t"); - } - - if ($atRuleSets != "") { - - // only write-out the at-rule if it contains at least one rule set - $statements .= $atRule." {\n"; - $statements .= $atRuleSets."\n"; - $statements .= "}\n\n"; - - } else if ($atRule == "@font-face") { - - // if the at-rule is a @font-face write it out no matter what - foreach ($ruleSets as $selector => $ruleSet) { - $statements .= $atRule." {\n"; - $statements .= $ruleSet."\n"; - $statements .= "}\n\n"; - } - - } - } - - unset($this->dom); - - return $statements; - - } - - /** - * Compare the given selector(s) against the DOM. Return the rule set if it matches - * @param {String} the selector(s) to test against the xPath - * @param {String} the declaration block that goes with the selector - * @param {String} any indent characters that might need to be added to the final output - * - * @return {String} if the selector(s) matched return the entire rule set with matches - */ - protected function buildRuleSet($selector,$declarationBlock,$indent = "") { - - // trap the selectors that are found - $foundSelectors = array(); - - // a given selector may have multiple parts (e.g. h1, h2, h3 ) break it up so each can be tested. - $selectors = explode(",",$selector); - - // iterate over each selector - foreach ($selectors as $selector) { - - $selector = trim($selector); - - // save the original selector and strip off bad pseudo-classes for matching purposes - $selectorOrig = $selector; - $badPseudoClasses = array(":first-child",":last-child",":after",":before",":nth-of",":visited",":hover",":focus","::"); - foreach ($badPseudoClasses as $badPseudoClass) { - $pos = strpos($selector,$badPseudoClass); - if ($pos !== false) { - $selector = substr($selector,0,$pos-strlen($selector)); - break; - } - } - - // match the selector against the DOM. if result is found save the original selector format - if (count($this->dom->select($selector)) > 0) { - $foundSelectors[] = $selectorOrig; - } - } - - // if the given selectors matched against the DOM build the rule set - if (count($foundSelectors) > 0) { - - // combine selectors that share a rule set - $i = 0; - $selectorList = ""; - foreach ($foundSelectors as $selector) { - $selectorList .= ($i > 0) ? ", ".$selector : $selector; - $i++; - } - - // write out the rule set & return it - $text = $indent.$selectorList." { \n"; - $text .= str_replace($indent,$indent.$indent,$declarationBlock)."\n"; - $text .= $indent."}\n\n"; - return $text; - - } - - } - - /** - * Print the error message. Yes, I should be using exception handling but I'm being lazy for now - * @param {String} the message to spit out - */ - protected function error($msg) { - print $msg."\n"; - exit; - } - -} diff --git a/core/lib/CSSRuleSaver/LICENSE b/core/lib/CSSRuleSaver/LICENSE deleted file mode 100644 index 2e13f8ef8..000000000 --- a/core/lib/CSSRuleSaver/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Dave Olsen, http://dmolsen.com - -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. diff --git a/core/lib/CSSRuleSaver/LICENSE.SelectorDOM b/core/lib/CSSRuleSaver/LICENSE.SelectorDOM deleted file mode 100644 index 55c4aabe3..000000000 --- a/core/lib/CSSRuleSaver/LICENSE.SelectorDOM +++ /dev/null @@ -1,22 +0,0 @@ -(The MIT License) - -Copyright (c) 2008 - 2009 TJ Holowaychuk - -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. \ No newline at end of file diff --git a/core/lib/CSSRuleSaver/SelectorDOM.php b/core/lib/CSSRuleSaver/SelectorDOM.php deleted file mode 100755 index 342148559..000000000 --- a/core/lib/CSSRuleSaver/SelectorDOM.php +++ /dev/null @@ -1,178 +0,0 @@ - MIT Licensed - * - * Persitant object for selecting elements. - * - * $dom = new SelectorDOM($html); - * $links = $dom->select('a'); - * $list_links = $dom->select('ul li a'); - * - */ -class SelectorDOM { - - const VERSION = '1.1.3'; - - /** - * @var DOMXPath - */ - protected $xpath; - - /** - * Map of regexes to convert CSS selector to XPath - * - * @var array - */ - public static $regexMap = array( - '/\s*,\s*/' => '|descendant-or-self::', - '/:(button|submit|file|checkbox|radio|image|reset|text|password)/' => 'input[@type="\1"]', - '/\[(\w+)\]/' => '*[@\1]', # [id] - '/\[(\w+)=[\'"]?(.*?)[\'"]?\]/' => '[@\1="\2"]', # foo[id=foo] - '/^\[/' => '*[', # [id=foo] - '/([\w\-]+)\#([\w\-]+)/' => '\1[@id="\2"]', # div#foo - '/\#([\w\-]+)/' => '*[@id="\1"]', # #foo - '/([\w\-]+)\.([\w\-]+)/' => '\1[contains(concat(" ",@class," ")," \2 ")]', # div.foo - '/\.([\w\-]+)/' => '*[contains(concat(" ",@class," ")," \1 ")]', # .foo - '/([\w\-]+):first-child/' => '*/\1[position()=1]', - '/([\w\-]+):last-child/' => '*/\1[position()=last()]', - '/:first-child/' => '*/*[position()=1]', - '/:last-child/' => '*/*[position()=last()]', - '/([\w\-]+):nth-child\((\d+)\)/' => '*/\1[position()=\2]', - '/:nth-child\((\d+)\)/' => '*/*[position()=\1]', - '/([\w\-]+):contains\((.*?)\)/' => '\1[contains(string(.),"\2")]', - '/\s*>\s*/' => '/', # > - '/\s*~\s*/' => '/following-sibling::', # ~ - '/\s*\+\s*([\w\-]+)/' => '/following-sibling::\1[position()=1]', # + - '/\]\*/' => ']', - '/\]\/\*/' => ']', - ); - - /** - * Load $data into the object - * - * @param string|DOMDocument $data - * @param array $errors A by-ref capture for libxml error messages. - */ - public function __construct($data, &$errors = null) { - # Wrap this with libxml errors off - # this both sets the new value, and returns the previous. - $lib_xml_errors = libxml_use_internal_errors(true); - - if (is_a($data, 'DOMDocument')) { - $this->xpath = new \DOMXpath($data); - } else { - $dom = new \DOMDocument(); - $dom->loadHTML($data); - $this->xpath = new \DOMXpath($dom); - } - - # Clear any errors and restore the original value - $errors = libxml_get_errors(); - libxml_clear_errors(); - libxml_use_internal_errors($lib_xml_errors); - } - - /** - * Select elements from the loaded HTML using the css $selector. - * When $as_array is true elements and their children will - * be converted to array's containing the following keys (defaults to true): - * - * - name : element name - * - text : element text - * - children : array of children elements - * - attributes : attributes array - * - * Otherwise regular DOMElement's will be returned. - * - * @param string $selector CSS Selector - * @param boolean $as_array Whether to return an array or DOMElement - */ - public function select($selector, $as_array = true) { - $elements = $this->xpath->evaluate(self::selectorToXpath($selector)); - return $as_array ? self::elementsToArray($elements) : $elements; - } - - /** - * This allows a static access to the class, in the same way as the - * `select_elements` function did. - * - * @see $this->select() - * @param string $html - * @param string $selector CSS Selector - */ - public static function selectElements($selector, $html, $as_array = true) { - $dom = new SelectorDOM($html); - return $dom->select($selector, $as_array); - } - - /** - * Convert $elements to an array. - * - * @param DOMNodeList $elements - */ - public function elementsToArray($elements) { - $array = array(); - for ($i = 0, $length = $elements->length; $i < $length; ++$i) { - if ($elements->item($i)->nodeType == XML_ELEMENT_NODE) { - array_push($array, self::elementToArray($elements->item($i))); - } - } - return $array; - } - - /** - * Convert $element to an array. - */ - public function elementToArray($element) { - $array = array( - 'name' => $element->nodeName, - 'attributes' => array(), - 'text' => $element->textContent, - 'children' => self::elementsToArray($element->childNodes), - ); - if ($element->attributes->length) { - foreach($element->attributes as $key => $attr) { - $array['attributes'][$key] = $attr->value; - } - } - return $array; - } - - /** - * Convert $selector into an XPath string. - */ - public static function selectorToXpath($selector) { - // remove spaces around operators - $selector = preg_replace('/\s*(>|~|\+|,)\s*/', '$1', $selector); - $selectors = preg_split("/\s+/", $selector); - // Process all regular expressions to convert selector to XPath - foreach ($selectors as &$selector) { - foreach (self::$regexMap as $regex => $replacement) { - $selector = preg_replace($regex, $replacement, $selector); - } - } - $selector = implode('/descendant::', $selectors); - $selector = 'descendant-or-self::' . $selector; - return $selector; - } - -} - -# -# Procedural components -# - -define('SELECTOR_VERSION', SelectorDOM::VERSION); - -/** - * Provides a procedural function to select use SelectorDOM::select() - * on some HTML. - */ -function select_elements($selector, $html, $as_array = true) { - return SelectorDOM::selectElements($selector, $html, $as_array); -} - diff --git a/core/lib/Mustache/Autoloader.php b/core/lib/Mustache/Autoloader.php deleted file mode 100644 index df48536d0..000000000 --- a/core/lib/Mustache/Autoloader.php +++ /dev/null @@ -1,69 +0,0 @@ -baseDir = dirname(__FILE__).'/..'; - } else { - $this->baseDir = rtrim($baseDir, '/'); - } - } - - /** - * Register a new instance as an SPL autoloader. - * - * @param string $baseDir Mustache library base directory (default: dirname(__FILE__).'/..') - * - * @return Mustache_Autoloader Registered Autoloader instance - */ - public static function register($baseDir = null) - { - $loader = new self($baseDir); - spl_autoload_register(array($loader, 'autoload')); - - return $loader; - } - - /** - * Autoload Mustache classes. - * - * @param string $class - */ - public function autoload($class) - { - if ($class[0] === '\\') { - $class = substr($class, 1); - } - - if (strpos($class, 'Mustache') !== 0) { - return; - } - - $file = sprintf('%s/%s.php', $this->baseDir, str_replace('_', '/', $class)); - if (is_file($file)) { - require $file; - } - } -} diff --git a/core/lib/Mustache/Compiler.php b/core/lib/Mustache/Compiler.php deleted file mode 100644 index a95c9194b..000000000 --- a/core/lib/Mustache/Compiler.php +++ /dev/null @@ -1,475 +0,0 @@ -pragmas = array(); - $this->sections = array(); - $this->source = $source; - $this->indentNextLine = true; - $this->customEscape = $customEscape; - $this->charset = $charset; - $this->strictCallables = $strictCallables; - - return $this->writeCode($tree, $name); - } - - /** - * Helper function for walking the Mustache token parse tree. - * - * @throws Mustache_Exception_SyntaxException upon encountering unknown token types. - * - * @param array $tree Parse tree of Mustache tokens - * @param int $level (default: 0) - * - * @return string Generated PHP source code - */ - private function walk(array $tree, $level = 0) - { - $code = ''; - $level++; - foreach ($tree as $node) { - switch ($node[Mustache_Tokenizer::TYPE]) { - case Mustache_Tokenizer::T_PRAGMA: - $this->pragmas[$node[Mustache_Tokenizer::NAME]] = true; - break; - - case Mustache_Tokenizer::T_SECTION: - $code .= $this->section( - $node[Mustache_Tokenizer::NODES], - $node[Mustache_Tokenizer::NAME], - $node[Mustache_Tokenizer::INDEX], - $node[Mustache_Tokenizer::END], - $node[Mustache_Tokenizer::OTAG], - $node[Mustache_Tokenizer::CTAG], - $level - ); - break; - - case Mustache_Tokenizer::T_INVERTED: - $code .= $this->invertedSection( - $node[Mustache_Tokenizer::NODES], - $node[Mustache_Tokenizer::NAME], - $level - ); - break; - - case Mustache_Tokenizer::T_PARTIAL: - case Mustache_Tokenizer::T_PARTIAL_2: - $code .= $this->partial( - $node[Mustache_Tokenizer::NAME], - isset($node[Mustache_Tokenizer::INDENT]) ? $node[Mustache_Tokenizer::INDENT] : '', - $level - ); - break; - - case Mustache_Tokenizer::T_UNESCAPED: - case Mustache_Tokenizer::T_UNESCAPED_2: - $code .= $this->variable($node[Mustache_Tokenizer::NAME], false, $level); - break; - - case Mustache_Tokenizer::T_COMMENT: - break; - - case Mustache_Tokenizer::T_ESCAPED: - $code .= $this->variable($node[Mustache_Tokenizer::NAME], true, $level); - break; - - case Mustache_Tokenizer::T_TEXT: - $code .= $this->text($node[Mustache_Tokenizer::VALUE], $level); - break; - - default: - throw new Mustache_Exception_SyntaxException(sprintf('Unknown token type: %s', $node[Mustache_Tokenizer::TYPE]), $node); - } - } - - return $code; - } - - const KLASS = 'lambdaHelper = new Mustache_LambdaHelper($this->mustache, $context); - $buffer = \'\'; - %s - - return $buffer; - } - %s - }'; - - const KLASS_NO_LAMBDAS = 'walk($tree); - $sections = implode("\n", $this->sections); - $klass = empty($this->sections) ? self::KLASS_NO_LAMBDAS : self::KLASS; - $callable = $this->strictCallables ? $this->prepare(self::STRICT_CALLABLE) : ''; - - return sprintf($this->prepare($klass, 0, false, true), $name, $callable, $code, $sections); - } - - const SECTION_CALL = ' - // %s section - $buffer .= $this->section%s($context, $indent, $context->%s(%s)); - '; - - const SECTION = ' - private function section%s(Mustache_Context $context, $indent, $value) - { - $buffer = \'\'; - if (%s) { - $source = %s; - $buffer .= $this->mustache - ->loadLambda((string) call_user_func($value, $source, $this->lambdaHelper)%s) - ->renderInternal($context, $indent); - } elseif (!empty($value)) { - $values = $this->isIterable($value) ? $value : array($value); - foreach ($values as $value) { - $context->push($value);%s - $context->pop(); - } - } - - return $buffer; - }'; - - /** - * Generate Mustache Template section PHP source. - * - * @param array $nodes Array of child tokens - * @param string $id Section name - * @param int $start Section start offset - * @param int $end Section end offset - * @param string $otag Current Mustache opening tag - * @param string $ctag Current Mustache closing tag - * @param int $level - * - * @return string Generated section PHP source code - */ - private function section($nodes, $id, $start, $end, $otag, $ctag, $level) - { - $method = $this->getFindMethod($id); - $id = var_export($id, true); - $source = var_export(substr($this->source, $start, $end - $start), true); - $callable = $this->getCallable(); - - if ($otag !== '{{' || $ctag !== '}}') { - $delims = ', '.var_export(sprintf('{{= %s %s =}}', $otag, $ctag), true); - } else { - $delims = ''; - } - - $key = ucfirst(md5($delims."\n".$source)); - - if (!isset($this->sections[$key])) { - $this->sections[$key] = sprintf($this->prepare(self::SECTION), $key, $callable, $source, $delims, $this->walk($nodes, 2)); - } - - return sprintf($this->prepare(self::SECTION_CALL, $level), $id, $key, $method, $id); - } - - const INVERTED_SECTION = ' - // %s inverted section - $value = $context->%s(%s); - if (empty($value)) { - %s - }'; - - /** - * Generate Mustache Template inverted section PHP source. - * - * @param array $nodes Array of child tokens - * @param string $id Section name - * @param int $level - * - * @return string Generated inverted section PHP source code - */ - private function invertedSection($nodes, $id, $level) - { - $method = $this->getFindMethod($id); - $id = var_export($id, true); - - return sprintf($this->prepare(self::INVERTED_SECTION, $level), $id, $method, $id, $this->walk($nodes, $level)); - } - - const PARTIAL = ' - if ($partial = $this->mustache->loadPartial(%s)) { - $buffer .= $partial->renderInternal($context, %s); - } - '; - - /** - * Generate Mustache Template partial call PHP source. - * - * @param string $id Partial name - * @param string $indent Whitespace indent to apply to partial - * @param int $level - * - * @return string Generated partial call PHP source code - */ - private function partial($id, $indent, $level) - { - return sprintf( - $this->prepare(self::PARTIAL, $level), - var_export($id, true), - var_export($indent, true) - ); - } - - const VARIABLE = ' - $value = $this->resolveValue($context->%s(%s), $context, $indent);%s - $buffer .= %s%s; - '; - - /** - * Generate Mustache Template variable interpolation PHP source. - * - * @param string $id Variable name - * @param boolean $escape Escape the variable value for output? - * @param int $level - * - * @return string Generated variable interpolation PHP source - */ - private function variable($id, $escape, $level) - { - $filters = ''; - - if (isset($this->pragmas[Mustache_Engine::PRAGMA_FILTERS])) { - list($id, $filters) = $this->getFilters($id, $level); - } - - $method = $this->getFindMethod($id); - $id = ($method !== 'last') ? var_export($id, true) : ''; - $value = $escape ? $this->getEscape() : '$value'; - - return sprintf($this->prepare(self::VARIABLE, $level), $method, $id, $filters, $this->flushIndent(), $value); - } - - /** - * Generate Mustache Template variable filtering PHP source. - * - * @param string $id Variable name - * @param int $level - * - * @return string Generated variable filtering PHP source - */ - private function getFilters($id, $level) - { - $filters = array_map('trim', explode('|', $id)); - $id = array_shift($filters); - - return array($id, $this->getFilter($filters, $level)); - } - - const FILTER = ' - $filter = $context->%s(%s); - if (!(%s)) { - throw new Mustache_Exception_UnknownFilterException(%s); - } - $value = call_user_func($filter, $value);%s - '; - - /** - * Generate PHP source for a single filter. - * - * @param array $filters - * @param int $level - * - * @return string Generated filter PHP source - */ - private function getFilter(array $filters, $level) - { - if (empty($filters)) { - return ''; - } - - $name = array_shift($filters); - $method = $this->getFindMethod($name); - $filter = ($method !== 'last') ? var_export($name, true) : ''; - $callable = $this->getCallable('$filter'); - $msg = var_export($name, true); - - return sprintf($this->prepare(self::FILTER, $level), $method, $filter, $callable, $msg, $this->getFilter($filters, $level)); - } - - const LINE = '$buffer .= "\n";'; - const TEXT = '$buffer .= %s%s;'; - - /** - * Generate Mustache Template output Buffer call PHP source. - * - * @param string $text - * @param int $level - * - * @return string Generated output Buffer call PHP source - */ - private function text($text, $level) - { - if ($text === "\n") { - $this->indentNextLine = true; - - return $this->prepare(self::LINE, $level); - } else { - return sprintf($this->prepare(self::TEXT, $level), $this->flushIndent(), var_export($text, true)); - } - } - - /** - * Prepare PHP source code snippet for output. - * - * @param string $text - * @param int $bonus Additional indent level (default: 0) - * @param boolean $prependNewline Prepend a newline to the snippet? (default: true) - * @param boolean $appendNewline Append a newline to the snippet? (default: false) - * - * @return string PHP source code snippet - */ - private function prepare($text, $bonus = 0, $prependNewline = true, $appendNewline = false) - { - $text = ($prependNewline ? "\n" : '').trim($text); - if ($prependNewline) { - $bonus++; - } - if ($appendNewline) { - $text .= "\n"; - } - - return preg_replace("/\n( {8})?/", "\n".str_repeat(" ", $bonus * 4), $text); - } - - const DEFAULT_ESCAPE = 'htmlspecialchars(%s, ENT_COMPAT, %s)'; - const CUSTOM_ESCAPE = 'call_user_func($this->mustache->getEscape(), %s)'; - - /** - * Get the current escaper. - * - * @param string $value (default: '$value') - * - * @return string Either a custom callback, or an inline call to `htmlspecialchars` - */ - private function getEscape($value = '$value') - { - if ($this->customEscape) { - return sprintf(self::CUSTOM_ESCAPE, $value); - } else { - return sprintf(self::DEFAULT_ESCAPE, $value, var_export($this->charset, true)); - } - } - - /** - * Select the appropriate Context `find` method for a given $id. - * - * The return value will be one of `find`, `findDot` or `last`. - * - * @see Mustache_Context::find - * @see Mustache_Context::findDot - * @see Mustache_Context::last - * - * @param string $id Variable name - * - * @return string `find` method name - */ - private function getFindMethod($id) - { - if ($id === '.') { - return 'last'; - } elseif (strpos($id, '.') === false) { - return 'find'; - } else { - return 'findDot'; - } - } - - const IS_CALLABLE = '!is_string(%s) && is_callable(%s)'; - const STRICT_IS_CALLABLE = 'is_object(%s) && is_callable(%s)'; - - private function getCallable($variable = '$value') - { - $tpl = $this->strictCallables ? self::STRICT_IS_CALLABLE : self::IS_CALLABLE; - - return sprintf($tpl, $variable, $variable); - } - - const LINE_INDENT = '$indent . '; - - /** - * Get the current $indent prefix to write to the buffer. - * - * @return string "$indent . " or "" - */ - private function flushIndent() - { - if ($this->indentNextLine) { - $this->indentNextLine = false; - - return self::LINE_INDENT; - } else { - return ''; - } - } -} diff --git a/core/lib/Mustache/Context.php b/core/lib/Mustache/Context.php deleted file mode 100644 index e7783b43c..000000000 --- a/core/lib/Mustache/Context.php +++ /dev/null @@ -1,149 +0,0 @@ -stack = array($context); - } - } - - /** - * Push a new Context frame onto the stack. - * - * @param mixed $value Object or array to use for context - */ - public function push($value) - { - array_push($this->stack, $value); - } - - /** - * Pop the last Context frame from the stack. - * - * @return mixed Last Context frame (object or array) - */ - public function pop() - { - return array_pop($this->stack); - } - - /** - * Get the last Context frame. - * - * @return mixed Last Context frame (object or array) - */ - public function last() - { - return end($this->stack); - } - - /** - * Find a variable in the Context stack. - * - * Starting with the last Context frame (the context of the innermost section), and working back to the top-level - * rendering context, look for a variable with the given name: - * - * * If the Context frame is an associative array which contains the key $id, returns the value of that element. - * * If the Context frame is an object, this will check first for a public method, then a public property named - * $id. Failing both of these, it will try `__isset` and `__get` magic methods. - * * If a value named $id is not found in any Context frame, returns an empty string. - * - * @param string $id Variable name - * - * @return mixed Variable value, or '' if not found - */ - public function find($id) - { - return $this->findVariableInStack($id, $this->stack); - } - - /** - * Find a 'dot notation' variable in the Context stack. - * - * Note that dot notation traversal bubbles through scope differently than the regular find method. After finding - * the initial chunk of the dotted name, each subsequent chunk is searched for only within the value of the previous - * result. For example, given the following context stack: - * - * $data = array( - * 'name' => 'Fred', - * 'child' => array( - * 'name' => 'Bob' - * ), - * ); - * - * ... and the Mustache following template: - * - * {{ child.name }} - * - * ... the `name` value is only searched for within the `child` value of the global Context, not within parent - * Context frames. - * - * @param string $id Dotted variable selector - * - * @return mixed Variable value, or '' if not found - */ - public function findDot($id) - { - $chunks = explode('.', $id); - $first = array_shift($chunks); - $value = $this->findVariableInStack($first, $this->stack); - - foreach ($chunks as $chunk) { - if ($value === '') { - return $value; - } - - $value = $this->findVariableInStack($chunk, array($value)); - } - - return $value; - } - - /** - * Helper function to find a variable in the Context stack. - * - * @see Mustache_Context::find - * - * @param string $id Variable name - * @param array $stack Context stack - * - * @return mixed Variable value, or '' if not found - */ - private function findVariableInStack($id, array $stack) - { - for ($i = count($stack) - 1; $i >= 0; $i--) { - if (is_object($stack[$i]) && !$stack[$i] instanceof Closure) { - if (method_exists($stack[$i], $id)) { - return $stack[$i]->$id(); - } elseif (isset($stack[$i]->$id)) { - return $stack[$i]->$id; - } - } elseif (is_array($stack[$i]) && array_key_exists($id, $stack[$i])) { - return $stack[$i][$id]; - } - } - - return ''; - } -} diff --git a/core/lib/Mustache/Engine.php b/core/lib/Mustache/Engine.php deleted file mode 100644 index 5f92d1948..000000000 --- a/core/lib/Mustache/Engine.php +++ /dev/null @@ -1,729 +0,0 @@ - '__MyTemplates_', - * - * // A cache directory for compiled templates. Mustache will not cache templates unless this is set - * 'cache' => dirname(__FILE__).'/tmp/cache/mustache', - * - * // Override default permissions for cache files. Defaults to using the system-defined umask. It is - * // *strongly* recommended that you configure your umask properly rather than overriding permissions here. - * 'cache_file_mode' => 0666, - * - * // A Mustache template loader instance. Uses a StringLoader if not specified. - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * - * // A Mustache loader instance for partials. - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * - * // An array of Mustache partials. Useful for quick-and-dirty string template loading, but not as - * // efficient or lazy as a Filesystem (or database) loader. - * 'partials' => array('foo' => file_get_contents(dirname(__FILE__).'/views/partials/foo.mustache')), - * - * // An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order - * // sections), or any other valid Mustache context value. They will be prepended to the context stack, - * // so they will be available in any template loaded by this Mustache instance. - * 'helpers' => array('i18n' => function($text) { - * // do something translatey here... - * }), - * - * // An 'escape' callback, responsible for escaping double-mustache variables. - * 'escape' => function($value) { - * return htmlspecialchars($buffer, ENT_COMPAT, 'UTF-8'); - * }, - * - * // Character set for `htmlspecialchars`. Defaults to 'UTF-8'. Use 'UTF-8'. - * 'charset' => 'ISO-8859-1', - * - * // A Mustache Logger instance. No logging will occur unless this is set. Using a PSR-3 compatible - * // logging library -- such as Monolog -- is highly recommended. A simple stream logger implementation is - * // available as well: - * 'logger' => new Mustache_Logger_StreamLogger('php://stderr'), - * - * // Only treat Closure instances and invokable classes as callable. If true, values like - * // `array('ClassName', 'methodName')` and `array($classInstance, 'methodName')`, which are traditionally - * // "callable" in PHP, are not called to resolve variables for interpolation or section contexts. This - * // helps protect against arbitrary code execution when user input is passed directly into the template. - * // This currently defaults to false, but will default to true in v3.0. - * 'strict_callables' => true, - * ); - * - * @throws Mustache_Exception_InvalidArgumentException If `escape` option is not callable. - * - * @param array $options (default: array()) - */ - public function __construct(array $options = array()) - { - if (isset($options['template_class_prefix'])) { - $this->templateClassPrefix = $options['template_class_prefix']; - } - - if (isset($options['cache'])) { - $this->cache = $options['cache']; - } - - if (isset($options['cache_file_mode'])) { - $this->cacheFileMode = $options['cache_file_mode']; - } - - if (isset($options['loader'])) { - $this->setLoader($options['loader']); - } - - if (isset($options['partials_loader'])) { - $this->setPartialsLoader($options['partials_loader']); - } - - if (isset($options['partials'])) { - $this->setPartials($options['partials']); - } - - if (isset($options['helpers'])) { - $this->setHelpers($options['helpers']); - } - - if (isset($options['escape'])) { - if (!is_callable($options['escape'])) { - throw new Mustache_Exception_InvalidArgumentException('Mustache Constructor "escape" option must be callable'); - } - - $this->escape = $options['escape']; - } - - if (isset($options['charset'])) { - $this->charset = $options['charset']; - } - - if (isset($options['logger'])) { - $this->setLogger($options['logger']); - } - - if (isset($options['strict_callables'])) { - $this->strictCallables = $options['strict_callables']; - } - } - - /** - * Shortcut 'render' invocation. - * - * Equivalent to calling `$mustache->loadTemplate($template)->render($context);` - * - * @see Mustache_Engine::loadTemplate - * @see Mustache_Template::render - * - * @param string $template - * @param mixed $context (default: array()) - * - * @return string Rendered template - */ - public function render($template, $context = array()) - { - return $this->loadTemplate($template)->render($context); - } - - /** - * Get the current Mustache escape callback. - * - * @return mixed Callable or null - */ - public function getEscape() - { - return $this->escape; - } - - /** - * Get the current Mustache character set. - * - * @return string - */ - public function getCharset() - { - return $this->charset; - } - - /** - * Set the Mustache template Loader instance. - * - * @param Mustache_Loader $loader - */ - public function setLoader(Mustache_Loader $loader) - { - $this->loader = $loader; - } - - /** - * Get the current Mustache template Loader instance. - * - * If no Loader instance has been explicitly specified, this method will instantiate and return - * a StringLoader instance. - * - * @return Mustache_Loader - */ - public function getLoader() - { - if (!isset($this->loader)) { - $this->loader = new Mustache_Loader_StringLoader; - } - - return $this->loader; - } - - /** - * Set the Mustache partials Loader instance. - * - * @param Mustache_Loader $partialsLoader - */ - public function setPartialsLoader(Mustache_Loader $partialsLoader) - { - $this->partialsLoader = $partialsLoader; - } - - /** - * Get the current Mustache partials Loader instance. - * - * If no Loader instance has been explicitly specified, this method will instantiate and return - * an ArrayLoader instance. - * - * @return Mustache_Loader - */ - public function getPartialsLoader() - { - if (!isset($this->partialsLoader)) { - $this->partialsLoader = new Mustache_Loader_ArrayLoader; - } - - return $this->partialsLoader; - } - - /** - * Set partials for the current partials Loader instance. - * - * @throws Mustache_Exception_RuntimeException If the current Loader instance is immutable - * - * @param array $partials (default: array()) - */ - public function setPartials(array $partials = array()) - { - if (!isset($this->partialsLoader)) { - $this->partialsLoader = new Mustache_Loader_ArrayLoader; - } - - if (!$this->partialsLoader instanceof Mustache_Loader_MutableLoader) { - throw new Mustache_Exception_RuntimeException('Unable to set partials on an immutable Mustache Loader instance'); - } - - $this->partialsLoader->setTemplates($partials); - } - - /** - * Set an array of Mustache helpers. - * - * An array of 'helpers'. Helpers can be global variables or objects, closures (e.g. for higher order sections), or - * any other valid Mustache context value. They will be prepended to the context stack, so they will be available in - * any template loaded by this Mustache instance. - * - * @throws Mustache_Exception_InvalidArgumentException if $helpers is not an array or Traversable - * - * @param array|Traversable $helpers - */ - public function setHelpers($helpers) - { - if (!is_array($helpers) && !$helpers instanceof Traversable) { - throw new Mustache_Exception_InvalidArgumentException('setHelpers expects an array of helpers'); - } - - $this->getHelpers()->clear(); - - foreach ($helpers as $name => $helper) { - $this->addHelper($name, $helper); - } - } - - /** - * Get the current set of Mustache helpers. - * - * @see Mustache_Engine::setHelpers - * - * @return Mustache_HelperCollection - */ - public function getHelpers() - { - if (!isset($this->helpers)) { - $this->helpers = new Mustache_HelperCollection; - } - - return $this->helpers; - } - - /** - * Add a new Mustache helper. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * @param mixed $helper - */ - public function addHelper($name, $helper) - { - $this->getHelpers()->add($name, $helper); - } - - /** - * Get a Mustache helper by name. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * - * @return mixed Helper - */ - public function getHelper($name) - { - return $this->getHelpers()->get($name); - } - - /** - * Check whether this Mustache instance has a helper. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - * - * @return boolean True if the helper is present - */ - public function hasHelper($name) - { - return $this->getHelpers()->has($name); - } - - /** - * Remove a helper by name. - * - * @see Mustache_Engine::setHelpers - * - * @param string $name - */ - public function removeHelper($name) - { - $this->getHelpers()->remove($name); - } - - /** - * Set the Mustache Logger instance. - * - * @throws Mustache_Exception_InvalidArgumentException If logger is not an instance of Mustache_Logger or Psr\Log\LoggerInterface. - * - * @param Mustache_Logger|Psr\Log\LoggerInterface $logger - */ - public function setLogger($logger = null) - { - if ($logger !== null && !($logger instanceof Mustache_Logger || is_a($logger, 'Psr\\Log\\LoggerInterface'))) { - throw new Mustache_Exception_InvalidArgumentException('Expected an instance of Mustache_Logger or Psr\\Log\\LoggerInterface.'); - } - - $this->logger = $logger; - } - - /** - * Get the current Mustache Logger instance. - * - * @return Mustache_Logger|Psr\Log\LoggerInterface - */ - public function getLogger() - { - return $this->logger; - } - - /** - * Set the Mustache Tokenizer instance. - * - * @param Mustache_Tokenizer $tokenizer - */ - public function setTokenizer(Mustache_Tokenizer $tokenizer) - { - $this->tokenizer = $tokenizer; - } - - /** - * Get the current Mustache Tokenizer instance. - * - * If no Tokenizer instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Tokenizer - */ - public function getTokenizer() - { - if (!isset($this->tokenizer)) { - $this->tokenizer = new Mustache_Tokenizer; - } - - return $this->tokenizer; - } - - /** - * Set the Mustache Parser instance. - * - * @param Mustache_Parser $parser - */ - public function setParser(Mustache_Parser $parser) - { - $this->parser = $parser; - } - - /** - * Get the current Mustache Parser instance. - * - * If no Parser instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Parser - */ - public function getParser() - { - if (!isset($this->parser)) { - $this->parser = new Mustache_Parser; - } - - return $this->parser; - } - - /** - * Set the Mustache Compiler instance. - * - * @param Mustache_Compiler $compiler - */ - public function setCompiler(Mustache_Compiler $compiler) - { - $this->compiler = $compiler; - } - - /** - * Get the current Mustache Compiler instance. - * - * If no Compiler instance has been explicitly specified, this method will instantiate and return a new one. - * - * @return Mustache_Compiler - */ - public function getCompiler() - { - if (!isset($this->compiler)) { - $this->compiler = new Mustache_Compiler; - } - - return $this->compiler; - } - - /** - * Helper method to generate a Mustache template class. - * - * @param string $source - * - * @return string Mustache Template class name - */ - public function getTemplateClassName($source) - { - return $this->templateClassPrefix . md5(sprintf( - 'version:%s,escape:%s,charset:%s,strict_callables:%s,source:%s', - self::VERSION, - isset($this->escape) ? 'custom' : 'default', - $this->charset, - $this->strictCallables ? 'true' : 'false', - $source - )); - } - - /** - * Load a Mustache Template by name. - * - * @param string $name - * - * @return Mustache_Template - */ - public function loadTemplate($name) - { - return $this->loadSource($this->getLoader()->load($name)); - } - - /** - * Load a Mustache partial Template by name. - * - * This is a helper method used internally by Template instances for loading partial templates. You can most likely - * ignore it completely. - * - * @param string $name - * - * @return Mustache_Template - */ - public function loadPartial($name) - { - try { - if (isset($this->partialsLoader)) { - $loader = $this->partialsLoader; - } elseif (isset($this->loader) && !$this->loader instanceof Mustache_Loader_StringLoader) { - $loader = $this->loader; - } else { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->loadSource($loader->load($name)); - } catch (Mustache_Exception_UnknownTemplateException $e) { - // If the named partial cannot be found, log then return null. - $this->log( - Mustache_Logger::WARNING, - 'Partial not found: "{name}"', - array('name' => $e->getTemplateName()) - ); - } - } - - /** - * Load a Mustache lambda Template by source. - * - * This is a helper method used by Template instances to generate subtemplates for Lambda sections. You can most - * likely ignore it completely. - * - * @param string $source - * @param string $delims (default: null) - * - * @return Mustache_Template - */ - public function loadLambda($source, $delims = null) - { - if ($delims !== null) { - $source = $delims . "\n" . $source; - } - - return $this->loadSource($source); - } - - /** - * Instantiate and return a Mustache Template instance by source. - * - * @see Mustache_Engine::loadTemplate - * @see Mustache_Engine::loadPartial - * @see Mustache_Engine::loadLambda - * - * @param string $source - * - * @return Mustache_Template - */ - private function loadSource($source) - { - $className = $this->getTemplateClassName($source); - - if (!isset($this->templates[$className])) { - if (!class_exists($className, false)) { - if ($fileName = $this->getCacheFilename($source)) { - if (!is_file($fileName)) { - $this->log( - Mustache_Logger::DEBUG, - 'Writing "{className}" class to template cache: "{fileName}"', - array('className' => $className, 'fileName' => $fileName) - ); - - $this->writeCacheFile($fileName, $this->compile($source)); - } - - require_once $fileName; - } else { - $this->log( - Mustache_Logger::WARNING, - 'Template cache disabled, evaluating "{className}" class at runtime', - array('className' => $className) - ); - - eval('?>'.$this->compile($source)); - } - } - - $this->log( - Mustache_Logger::DEBUG, - 'Instantiating template: "{className}"', - array('className' => $className) - ); - - $this->templates[$className] = new $className($this); - } - - return $this->templates[$className]; - } - - /** - * Helper method to tokenize a Mustache template. - * - * @see Mustache_Tokenizer::scan - * - * @param string $source - * - * @return array Tokens - */ - private function tokenize($source) - { - return $this->getTokenizer()->scan($source); - } - - /** - * Helper method to parse a Mustache template. - * - * @see Mustache_Parser::parse - * - * @param string $source - * - * @return array Token tree - */ - private function parse($source) - { - return $this->getParser()->parse($this->tokenize($source)); - } - - /** - * Helper method to compile a Mustache template. - * - * @see Mustache_Compiler::compile - * - * @param string $source - * - * @return string generated Mustache template class code - */ - private function compile($source) - { - $tree = $this->parse($source); - $name = $this->getTemplateClassName($source); - - $this->log( - Mustache_Logger::INFO, - 'Compiling template to "{className}" class', - array('className' => $name) - ); - - return $this->getCompiler()->compile($source, $tree, $name, isset($this->escape), $this->charset, $this->strictCallables); - } - - /** - * Helper method to generate a Mustache Template class cache filename. - * - * @param string $source - * - * @return string Mustache Template class cache filename - */ - private function getCacheFilename($source) - { - if ($this->cache) { - return sprintf('%s/%s.php', $this->cache, $this->getTemplateClassName($source)); - } - } - - /** - * Helper method to dump a generated Mustache Template subclass to the file cache. - * - * @throws Mustache_Exception_RuntimeException if unable to create the cache directory or write to $fileName. - * - * @param string $fileName - * @param string $source - * - * @codeCoverageIgnore - */ - private function writeCacheFile($fileName, $source) - { - $dirName = dirname($fileName); - if (!is_dir($dirName)) { - $this->log( - Mustache_Logger::INFO, - 'Creating Mustache template cache directory: "{dirName}"', - array('dirName' => $dirName) - ); - - @mkdir($dirName, 0777, true); - if (!is_dir($dirName)) { - throw new Mustache_Exception_RuntimeException(sprintf('Failed to create cache directory "%s".', $dirName)); - } - - } - - $this->log( - Mustache_Logger::DEBUG, - 'Caching compiled template to "{fileName}"', - array('fileName' => $fileName) - ); - - $tempFile = tempnam($dirName, basename($fileName)); - if (false !== @file_put_contents($tempFile, $source)) { - if (@rename($tempFile, $fileName)) { - $mode = isset($this->cacheFileMode) ? $this->cacheFileMode : (0666 & ~umask()); - @chmod($fileName, $mode); - - return; - } - - $this->log( - Mustache_Logger::ERROR, - 'Unable to rename Mustache temp cache file: "{tempName}" -> "{fileName}"', - array('tempName' => $tempFile, 'fileName' => $fileName) - ); - } - - throw new Mustache_Exception_RuntimeException(sprintf('Failed to write cache file "%s".', $fileName)); - } - - /** - * Add a log record if logging is enabled. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - private function log($level, $message, array $context = array()) - { - if (isset($this->logger)) { - $this->logger->log($level, $message, $context); - } - } -} diff --git a/core/lib/Mustache/Exception.php b/core/lib/Mustache/Exception.php deleted file mode 100644 index b4f830046..000000000 --- a/core/lib/Mustache/Exception.php +++ /dev/null @@ -1,18 +0,0 @@ -token = $token; - parent::__construct($msg); - } - - public function getToken() - { - return $this->token; - } -} diff --git a/core/lib/Mustache/Exception/UnknownFilterException.php b/core/lib/Mustache/Exception/UnknownFilterException.php deleted file mode 100644 index f5c0884d4..000000000 --- a/core/lib/Mustache/Exception/UnknownFilterException.php +++ /dev/null @@ -1,29 +0,0 @@ -filterName = $filterName; - parent::__construct(sprintf('Unknown filter: %s', $filterName)); - } - - public function getFilterName() - { - return $this->filterName; - } -} diff --git a/core/lib/Mustache/Exception/UnknownHelperException.php b/core/lib/Mustache/Exception/UnknownHelperException.php deleted file mode 100644 index 98af13ebe..000000000 --- a/core/lib/Mustache/Exception/UnknownHelperException.php +++ /dev/null @@ -1,29 +0,0 @@ -helperName = $helperName; - parent::__construct(sprintf('Unknown helper: %s', $helperName)); - } - - public function getHelperName() - { - return $this->helperName; - } -} diff --git a/core/lib/Mustache/Exception/UnknownTemplateException.php b/core/lib/Mustache/Exception/UnknownTemplateException.php deleted file mode 100644 index 141d372bd..000000000 --- a/core/lib/Mustache/Exception/UnknownTemplateException.php +++ /dev/null @@ -1,29 +0,0 @@ -templateName = $templateName; - parent::__construct(sprintf('Unknown template: %s', $templateName)); - } - - public function getTemplateName() - { - return $this->templateName; - } -} diff --git a/core/lib/Mustache/HelperCollection.php b/core/lib/Mustache/HelperCollection.php deleted file mode 100644 index e9911378a..000000000 --- a/core/lib/Mustache/HelperCollection.php +++ /dev/null @@ -1,170 +0,0 @@ - $helper` pairs. - * - * @throws Mustache_Exception_InvalidArgumentException if the $helpers argument isn't an array or Traversable - * - * @param array|Traversable $helpers (default: null) - */ - public function __construct($helpers = null) - { - if ($helpers !== null) { - if (!is_array($helpers) && !$helpers instanceof Traversable) { - throw new Mustache_Exception_InvalidArgumentException('HelperCollection constructor expects an array of helpers'); - } - - foreach ($helpers as $name => $helper) { - $this->add($name, $helper); - } - } - } - - /** - * Magic mutator. - * - * @see Mustache_HelperCollection::add - * - * @param string $name - * @param mixed $helper - */ - public function __set($name, $helper) - { - $this->add($name, $helper); - } - - /** - * Add a helper to this collection. - * - * @param string $name - * @param mixed $helper - */ - public function add($name, $helper) - { - $this->helpers[$name] = $helper; - } - - /** - * Magic accessor. - * - * @see Mustache_HelperCollection::get - * - * @param string $name - * - * @return mixed Helper - */ - public function __get($name) - { - return $this->get($name); - } - - /** - * Get a helper by name. - * - * @throws Mustache_Exception_UnknownHelperException If helper does not exist. - * - * @param string $name - * - * @return mixed Helper - */ - public function get($name) - { - if (!$this->has($name)) { - throw new Mustache_Exception_UnknownHelperException($name); - } - - return $this->helpers[$name]; - } - - /** - * Magic isset(). - * - * @see Mustache_HelperCollection::has - * - * @param string $name - * - * @return boolean True if helper is present - */ - public function __isset($name) - { - return $this->has($name); - } - - /** - * Check whether a given helper is present in the collection. - * - * @param string $name - * - * @return boolean True if helper is present - */ - public function has($name) - { - return array_key_exists($name, $this->helpers); - } - - /** - * Magic unset(). - * - * @see Mustache_HelperCollection::remove - * - * @param string $name - */ - public function __unset($name) - { - $this->remove($name); - } - - /** - * Check whether a given helper is present in the collection. - * - * @throws Mustache_Exception_UnknownHelperException if the requested helper is not present. - * - * @param string $name - */ - public function remove($name) - { - if (!$this->has($name)) { - throw new Mustache_Exception_UnknownHelperException($name); - } - - unset($this->helpers[$name]); - } - - /** - * Clear the helper collection. - * - * Removes all helpers from this collection - */ - public function clear() - { - $this->helpers = array(); - } - - /** - * Check whether the helper collection is empty. - * - * @return boolean True if the collection is empty - */ - public function isEmpty() - { - return empty($this->helpers); - } -} diff --git a/core/lib/Mustache/LICENSE b/core/lib/Mustache/LICENSE deleted file mode 100644 index 6db530008..000000000 --- a/core/lib/Mustache/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2010 Justin Hileman - -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. diff --git a/core/lib/Mustache/LambdaHelper.php b/core/lib/Mustache/LambdaHelper.php deleted file mode 100644 index dfd4659c4..000000000 --- a/core/lib/Mustache/LambdaHelper.php +++ /dev/null @@ -1,49 +0,0 @@ -mustache = $mustache; - $this->context = $context; - } - - /** - * Render a string as a Mustache template with the current rendering context. - * - * @param string $string - * - * @return Rendered template. - */ - public function render($string) - { - return $this->mustache - ->loadLambda((string) $string) - ->renderInternal($this->context); - } -} diff --git a/core/lib/Mustache/Loader.php b/core/lib/Mustache/Loader.php deleted file mode 100644 index f659a1d3a..000000000 --- a/core/lib/Mustache/Loader.php +++ /dev/null @@ -1,28 +0,0 @@ - '{{ bar }}', - * 'baz' => 'Hey {{ qux }}!' - * ); - * - * $tpl = $loader->load('foo'); // '{{ bar }}' - * - * The ArrayLoader is used internally as a partials loader by Mustache_Engine instance when an array of partials - * is set. It can also be used as a quick-and-dirty Template loader. - */ -class Mustache_Loader_ArrayLoader implements Mustache_Loader, Mustache_Loader_MutableLoader -{ - - /** - * ArrayLoader constructor. - * - * @param array $templates Associative array of Template source (default: array()) - */ - public function __construct(array $templates = array()) - { - $this->templates = $templates; - } - - /** - * Load a Template. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->templates[$name]; - } - - /** - * Set an associative array of Template sources for this loader. - * - * @param array $templates - */ - public function setTemplates(array $templates) - { - $this->templates = $templates; - } - - /** - * Set a Template source by name. - * - * @param string $name - * @param string $template Mustache Template source - */ - public function setTemplate($name, $template) - { - $this->templates[$name] = $template; - } -} diff --git a/core/lib/Mustache/Loader/CascadingLoader.php b/core/lib/Mustache/Loader/CascadingLoader.php deleted file mode 100644 index 192edb97f..000000000 --- a/core/lib/Mustache/Loader/CascadingLoader.php +++ /dev/null @@ -1,69 +0,0 @@ -loaders = array(); - foreach ($loaders as $loader) { - $this->addLoader($loader); - } - } - - /** - * Add a Loader instance. - * - * @param Mustache_Loader $loader A Mustache Loader instance - */ - public function addLoader(Mustache_Loader $loader) - { - $this->loaders[] = $loader; - } - - /** - * Load a Template by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - foreach ($this->loaders as $loader) { - try { - return $loader->load($name); - } catch (Mustache_Exception_UnknownTemplateException $e) { - // do nothing, check the next loader. - } - } - - throw new Mustache_Exception_UnknownTemplateException($name); - } -} diff --git a/core/lib/Mustache/Loader/FilesystemLoader.php b/core/lib/Mustache/Loader/FilesystemLoader.php deleted file mode 100644 index 71d7f1c8e..000000000 --- a/core/lib/Mustache/Loader/FilesystemLoader.php +++ /dev/null @@ -1,120 +0,0 @@ -load('foo'); // equivalent to `file_get_contents(dirname(__FILE__).'/views/foo.mustache'); - * - * This is probably the most useful Mustache Loader implementation. It can be used for partials and normal Templates: - * - * $m = new Mustache(array( - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * )); - */ -class Mustache_Loader_FilesystemLoader implements Mustache_Loader -{ - private $baseDir; - private $extension = '.mustache'; - private $templates = array(); - - /** - * Mustache filesystem Loader constructor. - * - * Passing an $options array allows overriding certain Loader options during instantiation: - * - * $options = array( - * // The filename extension used for Mustache templates. Defaults to '.mustache' - * 'extension' => '.ms', - * ); - * - * @throws Mustache_Exception_RuntimeException if $baseDir does not exist. - * - * @param string $baseDir Base directory containing Mustache template files. - * @param array $options Array of Loader options (default: array()) - */ - public function __construct($baseDir, array $options = array()) - { - $this->baseDir = rtrim(realpath($baseDir), '/'); - - if (!is_dir($this->baseDir)) { - throw new Mustache_Exception_RuntimeException(sprintf('FilesystemLoader baseDir must be a directory: %s', $baseDir)); - } - - if (array_key_exists('extension', $options)) { - if (empty($options['extension'])) { - $this->extension = ''; - } else { - $this->extension = '.' . ltrim($options['extension'], '.'); - } - } - } - - /** - * Load a Template by name. - * - * $loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'); - * $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache"; - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - $this->templates[$name] = $this->loadFile($name); - } - - return $this->templates[$name]; - } - - /** - * Helper function for loading a Mustache file by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - protected function loadFile($name) - { - $fileName = $this->getFileName($name); - - if (!file_exists($fileName)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return file_get_contents($fileName); - } - - /** - * Helper function for getting a Mustache template file name. - * - * @param string $name - * - * @return string Template file name - */ - protected function getFileName($name) - { - $fileName = $this->baseDir . '/' . $name; - if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { - $fileName .= $this->extension; - } - - return $fileName; - } -} diff --git a/core/lib/Mustache/Loader/InlineLoader.php b/core/lib/Mustache/Loader/InlineLoader.php deleted file mode 100644 index 1463bf8b5..000000000 --- a/core/lib/Mustache/Loader/InlineLoader.php +++ /dev/null @@ -1,121 +0,0 @@ -load('hello'); - * $goodbye = $loader->load('goodbye'); - * - * __halt_compiler(); - * - * @@ hello - * Hello, {{ planet }}! - * - * @@ goodbye - * Goodbye, cruel {{ planet }} - * - * Templates are deliniated by lines containing only `@@ name`. - * - * The InlineLoader is well-suited to micro-frameworks such as Silex: - * - * $app->register(new MustacheServiceProvider, array( - * 'mustache.loader' => new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__) - * )); - * - * $app->get('/{name}', function() use ($app) { - * return $app['mustache']->render('hello', compact('name')); - * }) - * ->value('name', 'world'); - * - * __halt_compiler(); - * - * @@ hello - * Hello, {{ name }}! - * - */ -class Mustache_Loader_InlineLoader implements Mustache_Loader -{ - protected $fileName; - protected $offset; - protected $templates; - - /** - * The InlineLoader requires a filename and offset to process templates. - * The magic constants `__FILE__` and `__COMPILER_HALT_OFFSET__` are usually - * perfectly suited to the job: - * - * $loader = new Mustache_Loader_InlineLoader(__FILE__, __COMPILER_HALT_OFFSET__); - * - * Note that this only works if the loader is instantiated inside the same - * file as the inline templates. If the templates are located in another - * file, it would be necessary to manually specify the filename and offset. - * - * @param string $fileName The file to parse for inline templates - * @param int $offset A string offset for the start of the templates. - * This usually coincides with the `__halt_compiler` - * call, and the `__COMPILER_HALT_OFFSET__`. - */ - public function __construct($fileName, $offset) - { - if (!is_file($fileName)) { - throw new Mustache_Exception_InvalidArgumentException('InlineLoader expects a valid filename.'); - } - - if (!is_int($offset) || $offset < 0) { - throw new Mustache_Exception_InvalidArgumentException('InlineLoader expects a valid file offset.'); - } - - $this->fileName = $fileName; - $this->offset = $offset; - } - - /** - * Load a Template by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - $this->loadTemplates(); - - if (!array_key_exists($name, $this->templates)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - return $this->templates[$name]; - } - - /** - * Parse and load templates from the end of a source file. - */ - protected function loadTemplates() - { - if ($this->templates === null) { - $this->templates = array(); - $data = file_get_contents($this->fileName, false, null, $this->offset); - foreach (preg_split("/^@@(?= [\w\d\.]+$)/m", $data, -1) as $chunk) { - if (trim($chunk)) { - list($name, $content) = explode("\n", $chunk, 2); - $this->templates[trim($name)] = trim($content); - } - } - } - } -} diff --git a/core/lib/Mustache/Loader/MutableLoader.php b/core/lib/Mustache/Loader/MutableLoader.php deleted file mode 100644 index 02bb207a9..000000000 --- a/core/lib/Mustache/Loader/MutableLoader.php +++ /dev/null @@ -1,32 +0,0 @@ -load('foo'); // equivalent to `file_get_contents(dirname(__FILE__).'/views/foo.mustache'); - * - * This is probably the most useful Mustache Loader implementation. It can be used for partials and normal Templates: - * - * $m = new Mustache(array( - * 'loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'), - * 'partials_loader' => new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views/partials'), - * )); - */ -class Mustache_Loader_PatternLoader implements Mustache_Loader -{ - private $baseDir; - private $extension = '.mustache'; - private $templates = array(); - private $patternPaths = array(); - - /** - * Mustache filesystem Loader constructor. - * - * Passing an $options array allows overriding certain Loader options during instantiation: - * - * $options = array( - * // The filename extension used for Mustache templates. Defaults to '.mustache' - * 'extension' => '.ms', - * ); - * - * @throws Mustache_Exception_RuntimeException if $baseDir does not exist. - * - * @param string $baseDir Base directory containing Mustache template files. - * @param array $options Array of Loader options (default: array()) - */ - public function __construct($baseDir, array $options = array()) - { - $this->baseDir = rtrim(realpath($baseDir), '/'); - - if (!is_dir($this->baseDir)) { - throw new Mustache_Exception_RuntimeException(sprintf('FilesystemLoader baseDir must be a directory: %s', $baseDir)); - } - - if (array_key_exists('extension', $options)) { - if (empty($options['extension'])) { - $this->extension = ''; - } else { - $this->extension = '.' . ltrim($options['extension'], '.'); - } - } - - if (array_key_exists('patternPaths', $options)) { - $this->patternPaths = $options['patternPaths']; - } - - } - - /** - * Load a Template by name. - * - * $loader = new Mustache_Loader_FilesystemLoader(dirname(__FILE__).'/views'); - * $loader->load('admin/dashboard'); // loads "./views/admin/dashboard.mustache"; - * - * @param string $name - * - * @return string Mustache Template source - */ - public function load($name) - { - if (!isset($this->templates[$name])) { - try { - $this->templates[$name] = $this->loadFile($name); - } catch (Exception $e) { - print "The partial, ".$name.", wasn't found so a pattern failed to build.\n"; - } - } - - return (isset($this->templates[$name])) ? $this->templates[$name] : false; - - } - - /** - * Helper function for loading a Mustache file by name. - * - * @throws Mustache_Exception_UnknownTemplateException If a template file is not found. - * - * @param string $name - * - * @return string Mustache Template source - */ - protected function loadFile($name) - { - - // get pattern data - list($partialName,$styleModifier,$parameters) = $this->getPartialInfo($name); - - // get the real file path for the pattern - $fileName = $this->getFileName($partialName); - //print $fileName."\n"; - // throw error if path is not found - if (!file_exists($fileName)) { - throw new Mustache_Exception_UnknownTemplateException($name); - } - - // get the file data - $fileData = file_get_contents($fileName); - - // if the pattern name had a style modifier find & replace it - if (count($styleModifier) > 0) { - $fileData = $this->findReplaceParameters($fileData, $styleModifier); - } - - // if the pattern name had parameters find & replace them - if (count($parameters) > 0) { - $fileData = $this->findReplaceParameters($fileData, $parameters); - } - - return $fileData; - - } - - /** - * Helper function for getting a Mustache template file name. - * @param {String} the pattern type for the pattern - * @param {String} the pattern sub-type - * - * @return {Array} an array of rendered partials that match the given path - */ - protected function getFileName($name) - { - - $fileName = ""; - $dirSep = DIRECTORY_SEPARATOR; - - // test to see what kind of path was supplied - $posDash = strpos($name,"-"); - $posSlash = strpos($name,$dirSep); - if (($posSlash === false) && ($posDash !== false)) { - - list($patternType,$pattern) = $this->getPatternInfo($name); - - // see if the pattern is an exact match for patternPaths. if not iterate over patternPaths to find a likely match - if (isset($this->patternPaths[$patternType][$pattern])) { - $fileName = $this->baseDir.$dirSep.$this->patternPaths[$patternType][$pattern]["patternSrcPath"]; - } else if (isset($this->patternPaths[$patternType])) { - foreach($this->patternPaths[$patternType] as $patternMatchKey=>$patternMatchValue) { - $pos = strpos($patternMatchKey,$pattern); - if ($pos !== false) { - $fileName = $this->baseDir.$dirSep.$patternMatchValue["patternSrcPath"]; - break; - } - } - } - - } else { - $fileName = $this->baseDir.$dirSep.$name; - } - - if (substr($fileName, 0 - strlen($this->extension)) !== $this->extension) { - $fileName .= $this->extension; - } - - return $fileName; - - } - - /** - * Helper function to return the parts of a partial name - * @param {String} the name of the partial - * - * @return {Array} the pattern type and the name of the pattern - */ - private function getPatternInfo($name) - { - - $patternBits = explode("-",$name); - - $i = 1; - $k = 2; - $c = count($patternBits); - $patternType = $patternBits[0]; - while (!isset($this->patternPaths[$patternType]) && ($i < $c)) { - $patternType .= "-".$patternBits[$i]; - $i++; - $k++; - } - - $patternBits = explode("-",$name,$k); - $pattern = $patternBits[count($patternBits)-1]; - - return array($patternType, $pattern); - - } - - /** - * Helper function for finding if a partial name has style modifier or parameters - * @param {String} the pattern name - * - * @return {Array} an array containing just the partial name, a style modifier, and any parameters - */ - protected function getPartialInfo($partial) - { - - $styleModifier = array(); - $parameters = array(); - - if (strpos($partial, "(") !== false) { - $partialBits = explode("(",$partial,2); - $partial = trim($partialBits[0]); - $parametersString = substr($partialBits[1],0,(strlen($partialBits[1]) - strlen(strrchr($partialBits[1],")")))); - $parameters = $this->parseParameters($parametersString); - } - - if (strpos($partial, ":") !== false) { - $partialBits = explode(":",$partial,2); - $partial = $partialBits[0]; - $styleModifier = array("styleModifier" => $partialBits[1]); - } - - return array($partial,$styleModifier,$parameters); - - } - - /** - * Helper function to find and replace the given parameters in a particular partial before handing it back to Mustache - * @param {String} the file contents - * @param {Array} an array of paramters to match - * - * @return {String} the modified file contents - */ - private function findReplaceParameters($fileData, $parameters) - { - foreach ($parameters as $k => $v) { - if ($v == "true") { - $fileData = preg_replace('/{{\#([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}} - $fileData = preg_replace('/{{\^([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}} - } else if ($v == "false") { - $fileData = preg_replace('/{{\^([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','$2',$fileData); // {{# asdf }}STUFF{{/ asdf}} - $fileData = preg_replace('/{{\#([\s]*'.$k .'[\s]*)}}(.*?){{\/([\s]*'.$k .'[\s]*)}}/s','',$fileData); // {{^ asdf }}STUFF{{/ asdf}} - } else { - $fileData = preg_replace('/{{([\s]*'.$k .'[\s]*)}}/', $v, $fileData); // {{ asdf }} - } - } - return $fileData; - } - - /** - * Helper function to parse the parameters and return them as an array - * @param {String} tbe parameter string - * - * @return {Array} the keys and values for the parameters - */ - private function parseParameters($string) - { - - $parameters = array(); - $betweenSQuotes = false; - $betweenDQuotes = false; - $inKey = true; - $inValue = false; - $char = ""; - $buffer = ""; - $keyBuffer = ""; - $strLength = strlen($string); - - for ($i = 0; $i < $strLength; $i++) { - - $previousChar = $char; - $char = $string[$i]; - - if ($inKey && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) { - // if inKey, a quote, and betweenQuotes is false ignore quote, set betweenQuotes to true and empty buffer to kill spaces - ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true); - } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) { - // if inKey, a quote, betweenQuotes is true, and previous character is \ add to buffer - $buffer .= $char; - } else if ($inKey && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) { - // if inKey, a quote, betweenQuotes is true set betweenQuotes to false, save as key buffer, empty buffer set inKey false - $keyBuffer = $buffer; - $buffer = ""; - $inKey = false; - $betweenSQuotes = false; - $betweenDQuotes = false; - } else if ($inKey && !$betweenDQuotes && !$betweenSQuotes && ($char == ":")) { - // if inKey, a colon, betweenQuotes is false, save as key buffer, empty buffer, set inKey false set inValue true - $keyBuffer = $buffer; - $buffer = ""; - $inKey = false; - $inValue = true; - } else if ($inKey) { - // if inKey add to buffer - $buffer .= $char; - } else if (!$inKey && !$inValue && ($char == ":")) { - // if inKey is false, inValue false, and a colon set inValue true - $inValue = true; - } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && (($char == "\"") || ($char == "'"))) { - // if inValue, a quote, and betweenQuote is false set betweenQuotes to true and empty buffer to kill spaces - ($char == "\"") ? ($betweenDQuotes = true) : ($betweenSQuotes = true); - } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'"))) && ($previousChar == "\\")) { - // if inValue, a quote, betweenQuotes is true, and previous character is \ add to buffer - $buffer .= $char; - } else if ($inValue && (($betweenDQuotes && ($char == "\"")) || ($betweenSQuotes && ($char == "'")))) { - // if inValue, a quote, betweenQuotes is true set betweenQuotes to false, save to parameters array, empty buffer, set inValue false - $buffer = str_replace("\\\"","\"",$buffer); - $buffer = str_replace('\\\'','\'',$buffer); - $parameters[trim($keyBuffer)] = trim($buffer); - $buffer = ""; - $inValue = false; - $betweenSQuotes = false; - $betweenDQuotes = false; - } else if ($inValue && !$betweenDQuotes && !$betweenSQuotes && ($char == ",")) { - // if inValue, a comman, betweenQuotes is false, save to parameters array, empty buffer, set inValue false, set inKey true - $parameters[trim($keyBuffer)] = trim($buffer); - $buffer = ""; - $inValue = false; - $inKey = true; - } else if ($inValue && (($i + 1) == $strLength)) { - // if inValue and end of the string add to buffer, save to parameters array - $buffer .= $char; - $parameters[trim($keyBuffer)] = trim($buffer); - } else if ($inValue) { - // if inValue add to buffer - $buffer .= $char; - } else if (!$inValue && !$inKey && ($char == ",")) { - // if inValue is false, inKey false, and a comma set inKey true - $inKey = true; - } - } - - return $parameters; - - } - -} diff --git a/core/lib/Mustache/Loader/StringLoader.php b/core/lib/Mustache/Loader/StringLoader.php deleted file mode 100644 index e73b3cdec..000000000 --- a/core/lib/Mustache/Loader/StringLoader.php +++ /dev/null @@ -1,40 +0,0 @@ -load('{{ foo }}'); // '{{ foo }}' - * - * This is the default Template Loader instance used by Mustache: - * - * $m = new Mustache; - * $tpl = $m->loadTemplate('{{ foo }}'); - * echo $tpl->render(array('foo' => 'bar')); // "bar" - */ -class Mustache_Loader_StringLoader implements Mustache_Loader -{ - - /** - * Load a Template by source. - * - * @param string $name Mustache Template source - * - * @return string Mustache Template source - */ - public function load($name) - { - return $name; - } -} diff --git a/core/lib/Mustache/Logger.php b/core/lib/Mustache/Logger.php deleted file mode 100644 index e08359a91..000000000 --- a/core/lib/Mustache/Logger.php +++ /dev/null @@ -1,135 +0,0 @@ -log(Mustache_Logger::EMERGENCY, $message, $context); - } - - /** - * Action must be taken immediately. - * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. - * - * @param string $message - * @param array $context - */ - public function alert($message, array $context = array()) - { - $this->log(Mustache_Logger::ALERT, $message, $context); - } - - /** - * Critical conditions. - * - * Example: Application component unavailable, unexpected exception. - * - * @param string $message - * @param array $context - */ - public function critical($message, array $context = array()) - { - $this->log(Mustache_Logger::CRITICAL, $message, $context); - } - - /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. - * - * @param string $message - * @param array $context - */ - public function error($message, array $context = array()) - { - $this->log(Mustache_Logger::ERROR, $message, $context); - } - - /** - * Exceptional occurrences that are not errors. - * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. - * - * @param string $message - * @param array $context - */ - public function warning($message, array $context = array()) - { - $this->log(Mustache_Logger::WARNING, $message, $context); - } - - /** - * Normal but significant events. - * - * @param string $message - * @param array $context - */ - public function notice($message, array $context = array()) - { - $this->log(Mustache_Logger::NOTICE, $message, $context); - } - - /** - * Interesting events. - * - * Example: User logs in, SQL logs. - * - * @param string $message - * @param array $context - */ - public function info($message, array $context = array()) - { - $this->log(Mustache_Logger::INFO, $message, $context); - } - - /** - * Detailed debug information. - * - * @param string $message - * @param array $context - */ - public function debug($message, array $context = array()) - { - $this->log(Mustache_Logger::DEBUG, $message, $context); - } -} diff --git a/core/lib/Mustache/Logger/StreamLogger.php b/core/lib/Mustache/Logger/StreamLogger.php deleted file mode 100644 index da771f90e..000000000 --- a/core/lib/Mustache/Logger/StreamLogger.php +++ /dev/null @@ -1,193 +0,0 @@ - 100, - self::INFO => 200, - self::NOTICE => 250, - self::WARNING => 300, - self::ERROR => 400, - self::CRITICAL => 500, - self::ALERT => 550, - self::EMERGENCY => 600, - ); - - protected $stream = null; - protected $url = null; - - /** - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param string $stream Resource instance or URL - * @param integer $level The minimum logging level at which this handler will be triggered - */ - public function __construct($stream, $level = Mustache_Logger::ERROR) - { - $this->setLevel($level); - - if (is_resource($stream)) { - $this->stream = $stream; - } else { - $this->url = $stream; - } - } - - /** - * Close stream resources. - */ - public function __destruct() - { - if (is_resource($this->stream)) { - fclose($this->stream); - } - } - - /** - * Set the minimum logging level. - * - * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown. - * - * @param integer $level The minimum logging level which will be written - */ - public function setLevel($level) - { - if (!array_key_exists($level, self::$levels)) { - throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level)); - } - - $this->level = $level; - } - - /** - * Get the current minimum logging level. - * - * @return integer - */ - public function getLevel() - { - return $this->level; - } - - /** - * Logs with an arbitrary level. - * - * @throws Mustache_Exception_InvalidArgumentException if the logging level is unknown. - * - * @param mixed $level - * @param string $message - * @param array $context - */ - public function log($level, $message, array $context = array()) - { - if (!array_key_exists($level, self::$levels)) { - throw new Mustache_Exception_InvalidArgumentException(sprintf('Unexpected logging level: %s', $level)); - } - - if (self::$levels[$level] >= self::$levels[$this->level]) { - $this->writeLog($level, $message, $context); - } - } - - /** - * Write a record to the log. - * - * @throws Mustache_Exception_LogicException If neither a stream resource nor url is present. - * @throws Mustache_Exception_RuntimeException If the stream url cannot be opened. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - */ - protected function writeLog($level, $message, array $context = array()) - { - if (!is_resource($this->stream)) { - if (!isset($this->url)) { - throw new Mustache_Exception_LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); - } - - $this->stream = fopen($this->url, 'a'); - if (!is_resource($this->stream)) { - // @codeCoverageIgnoreStart - throw new Mustache_Exception_RuntimeException(sprintf('The stream or file "%s" could not be opened.', $this->url)); - // @codeCoverageIgnoreEnd - } - } - - fwrite($this->stream, self::formatLine($level, $message, $context)); - } - - /** - * Gets the name of the logging level. - * - * @throws InvalidArgumentException if the logging level is unknown. - * - * @param integer $level - * - * @return string - */ - protected static function getLevelName($level) - { - return strtoupper($level); - } - - /** - * Format a log line for output. - * - * @param integer $level The logging level - * @param string $message The log message - * @param array $context The log context - * - * @return string - */ - protected static function formatLine($level, $message, array $context = array()) - { - return sprintf( - "%s: %s\n", - self::getLevelName($level), - self::interpolateMessage($message, $context) - ); - } - - /** - * Interpolate context values into the message placeholders. - * - * @param string $message - * @param array $context - * - * @return string - */ - protected static function interpolateMessage($message, array $context = array()) - { - if (strpos($message, '{') === false) { - return $message; - } - - // build a replacement array with braces around the context keys - $replace = array(); - foreach ($context as $key => $val) { - $replace['{' . $key . '}'] = $val; - } - - // interpolate replacement values into the the message and return - return strtr($message, $replace); - } -} diff --git a/core/lib/Mustache/Parser.php b/core/lib/Mustache/Parser.php deleted file mode 100644 index ab7db8463..000000000 --- a/core/lib/Mustache/Parser.php +++ /dev/null @@ -1,91 +0,0 @@ -buildTree(new ArrayIterator($tokens)); - } - - /** - * Helper method for recursively building a parse tree. - * - * @throws Mustache_Exception_SyntaxException when nesting errors or mismatched section tags are encountered. - * - * @param ArrayIterator $tokens Stream of Mustache tokens - * @param array $parent Parent token (default: null) - * - * @return array Mustache Token parse tree - */ - private function buildTree(ArrayIterator $tokens, array $parent = null) - { - $nodes = array(); - - do { - $token = $tokens->current(); - $tokens->next(); - - if ($token === null) { - continue; - } else { - switch ($token[Mustache_Tokenizer::TYPE]) { - case Mustache_Tokenizer::T_SECTION: - case Mustache_Tokenizer::T_INVERTED: - $nodes[] = $this->buildTree($tokens, $token); - break; - - case Mustache_Tokenizer::T_END_SECTION: - if (!isset($parent)) { - $msg = sprintf('Unexpected closing tag: /%s', $token[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $token); - } - - if ($token[Mustache_Tokenizer::NAME] !== $parent[Mustache_Tokenizer::NAME]) { - $msg = sprintf('Nesting error: %s vs. %s', $parent[Mustache_Tokenizer::NAME], $token[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $token); - } - - $parent[Mustache_Tokenizer::END] = $token[Mustache_Tokenizer::INDEX]; - $parent[Mustache_Tokenizer::NODES] = $nodes; - - return $parent; - break; - - default: - $nodes[] = $token; - break; - } - } - - } while ($tokens->valid()); - - if (isset($parent)) { - $msg = sprintf('Missing closing tag: %s', $parent[Mustache_Tokenizer::NAME]); - throw new Mustache_Exception_SyntaxException($msg, $parent); - } - - return $nodes; - } -} diff --git a/core/lib/Mustache/Template.php b/core/lib/Mustache/Template.php deleted file mode 100644 index aeee42d49..000000000 --- a/core/lib/Mustache/Template.php +++ /dev/null @@ -1,177 +0,0 @@ -mustache = $mustache; - } - - /** - * Mustache Template instances can be treated as a function and rendered by simply calling them: - * - * $m = new Mustache_Engine; - * $tpl = $m->loadTemplate('Hello, {{ name }}!'); - * echo $tpl(array('name' => 'World')); // "Hello, World!" - * - * @see Mustache_Template::render - * - * @param mixed $context Array or object rendering context (default: array()) - * - * @return string Rendered template - */ - public function __invoke($context = array()) - { - return $this->render($context); - } - - /** - * Render this template given the rendering context. - * - * @param mixed $context Array or object rendering context (default: array()) - * - * @return string Rendered template - */ - public function render($context = array()) - { - return $this->renderInternal($this->prepareContextStack($context)); - } - - /** - * Internal rendering method implemented by Mustache Template concrete subclasses. - * - * This is where the magic happens :) - * - * NOTE: This method is not part of the Mustache.php public API. - * - * @param Mustache_Context $context - * @param string $indent (default: '') - * - * @return string Rendered template - */ - abstract public function renderInternal(Mustache_Context $context, $indent = ''); - - /** - * Tests whether a value should be iterated over (e.g. in a section context). - * - * In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists - * should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript, - * Java, Python, etc. - * - * PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish - * between between a list of things (numeric, normalized array) and a set of variables to be used as section context - * (associative array). In other words, this will be iterated over: - * - * $items = array( - * array('name' => 'foo'), - * array('name' => 'bar'), - * array('name' => 'baz'), - * ); - * - * ... but this will be used as a section context block: - * - * $items = array( - * 1 => array('name' => 'foo'), - * 'banana' => array('name' => 'bar'), - * 42 => array('name' => 'baz'), - * ); - * - * @param mixed $value - * - * @return boolean True if the value is 'iterable' - */ - protected function isIterable($value) - { - if (is_object($value)) { - return $value instanceof Traversable; - } elseif (is_array($value)) { - $i = 0; - foreach ($value as $k => $v) { - if ($k !== $i++) { - return false; - } - } - - return true; - } else { - return false; - } - } - - /** - * Helper method to prepare the Context stack. - * - * Adds the Mustache HelperCollection to the stack's top context frame if helpers are present. - * - * @param mixed $context Optional first context frame (default: null) - * - * @return Mustache_Context - */ - protected function prepareContextStack($context = null) - { - $stack = new Mustache_Context; - - $helpers = $this->mustache->getHelpers(); - if (!$helpers->isEmpty()) { - $stack->push($helpers); - } - - if (!empty($context)) { - $stack->push($context); - } - - return $stack; - } - - /** - * Resolve a context value. - * - * Invoke the value if it is callable, otherwise return the value. - * - * @param mixed $value - * @param Mustache_Context $context - * @param string $indent - * - * @return string - */ - protected function resolveValue($value, Mustache_Context $context, $indent = '') - { - if (($this->strictCallables ? is_object($value) : !is_string($value)) && is_callable($value)) { - return $this->mustache - ->loadLambda((string) call_user_func($value)) - ->renderInternal($context, $indent); - } - - return $value; - } -} diff --git a/core/lib/Mustache/Tokenizer.php b/core/lib/Mustache/Tokenizer.php deleted file mode 100644 index 56e8ba6b7..000000000 --- a/core/lib/Mustache/Tokenizer.php +++ /dev/null @@ -1,315 +0,0 @@ -'; - const T_PARTIAL_2 = '<'; - const T_DELIM_CHANGE = '='; - const T_ESCAPED = '_v'; - const T_UNESCAPED = '{'; - const T_UNESCAPED_2 = '&'; - const T_TEXT = '_t'; - const T_PRAGMA = '%'; - - // Valid token types - private static $tagTypes = array( - self::T_SECTION => true, - self::T_INVERTED => true, - self::T_END_SECTION => true, - self::T_COMMENT => true, - self::T_PARTIAL => true, - self::T_PARTIAL_2 => true, - self::T_DELIM_CHANGE => true, - self::T_ESCAPED => true, - self::T_UNESCAPED => true, - self::T_UNESCAPED_2 => true, - self::T_PRAGMA => true, - ); - - // Interpolated tags - private static $interpolatedTags = array( - self::T_ESCAPED => true, - self::T_UNESCAPED => true, - self::T_UNESCAPED_2 => true, - ); - - // Token properties - const TYPE = 'type'; - const NAME = 'name'; - const OTAG = 'otag'; - const CTAG = 'ctag'; - const INDEX = 'index'; - const END = 'end'; - const INDENT = 'indent'; - const NODES = 'nodes'; - const VALUE = 'value'; - - private $pragmas; - private $state; - private $tagType; - private $tag; - private $buffer; - private $tokens; - private $seenTag; - private $lineStart; - private $otag; - private $ctag; - - /** - * Scan and tokenize template source. - * - * @param string $text Mustache template source to tokenize - * @param string $delimiters Optionally, pass initial opening and closing delimiters (default: null) - * - * @return array Set of Mustache tokens - */ - public function scan($text, $delimiters = null) - { - $this->reset(); - - if ($delimiters = trim($delimiters)) { - list($otag, $ctag) = explode(' ', $delimiters); - $this->otag = $otag; - $this->ctag = $ctag; - } - - $len = strlen($text); - for ($i = 0; $i < $len; $i++) { - switch ($this->state) { - case self::IN_TEXT: - if ($this->tagChange($this->otag, $text, $i)) { - $i--; - $this->flushBuffer(); - $this->state = self::IN_TAG_TYPE; - } else { - $char = substr($text, $i, 1); - if ($char == "\n") { - $this->filterLine(); - } else { - $this->buffer .= $char; - } - } - break; - - case self::IN_TAG_TYPE: - - $i += strlen($this->otag) - 1; - $char = substr($text, $i + 1, 1); - if (isset(self::$tagTypes[$char])) { - $tag = $char; - $this->tagType = $tag; - } else { - $tag = null; - $this->tagType = self::T_ESCAPED; - } - - if ($this->tagType === self::T_DELIM_CHANGE) { - $i = $this->changeDelimiters($text, $i); - $this->state = self::IN_TEXT; - } elseif ($this->tagType === self::T_PRAGMA) { - $i = $this->addPragma($text, $i); - $this->state = self::IN_TEXT; - } else { - if ($tag !== null) { - $i++; - } - $this->state = self::IN_TAG; - } - $this->seenTag = $i; - break; - - default: - if ($this->tagChange($this->ctag, $text, $i)) { - $this->tokens[] = array( - self::TYPE => $this->tagType, - self::NAME => trim($this->buffer), - self::OTAG => $this->otag, - self::CTAG => $this->ctag, - self::INDEX => ($this->tagType == self::T_END_SECTION) ? $this->seenTag - strlen($this->otag) : $i + strlen($this->ctag) - ); - - $this->buffer = ''; - $i += strlen($this->ctag) - 1; - $this->state = self::IN_TEXT; - if ($this->tagType == self::T_UNESCAPED) { - if ($this->ctag == '}}') { - $i++; - } else { - // Clean up `{{{ tripleStache }}}` style tokens. - $lastName = $this->tokens[count($this->tokens) - 1][self::NAME]; - if (substr($lastName, -1) === '}') { - $this->tokens[count($this->tokens) - 1][self::NAME] = trim(substr($lastName, 0, -1)); - } - } - } - } else { - $this->buffer .= substr($text, $i, 1); - } - break; - } - } - - $this->filterLine(true); - - foreach ($this->pragmas as $pragma) { - array_unshift($this->tokens, array( - self::TYPE => self::T_PRAGMA, - self::NAME => $pragma, - )); - } - - return $this->tokens; - } - - /** - * Helper function to reset tokenizer internal state. - */ - private function reset() - { - $this->state = self::IN_TEXT; - $this->tagType = null; - $this->tag = null; - $this->buffer = ''; - $this->tokens = array(); - $this->seenTag = false; - $this->lineStart = 0; - $this->otag = '{{'; - $this->ctag = '}}'; - $this->pragmas = array(); - } - - /** - * Flush the current buffer to a token. - */ - private function flushBuffer() - { - if (!empty($this->buffer)) { - $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => $this->buffer); - $this->buffer = ''; - } - } - - /** - * Test whether the current line is entirely made up of whitespace. - * - * @return boolean True if the current line is all whitespace - */ - private function lineIsWhitespace() - { - $tokensCount = count($this->tokens); - for ($j = $this->lineStart; $j < $tokensCount; $j++) { - $token = $this->tokens[$j]; - if (isset(self::$tagTypes[$token[self::TYPE]])) { - if (isset(self::$interpolatedTags[$token[self::TYPE]])) { - return false; - } - } elseif ($token[self::TYPE] == self::T_TEXT) { - if (preg_match('/\S/', $token[self::VALUE])) { - return false; - } - } - } - - return true; - } - - /** - * Filter out whitespace-only lines and store indent levels for partials. - * - * @param bool $noNewLine Suppress the newline? (default: false) - */ - private function filterLine($noNewLine = false) - { - $this->flushBuffer(); - if ($this->seenTag && $this->lineIsWhitespace()) { - $tokensCount = count($this->tokens); - for ($j = $this->lineStart; $j < $tokensCount; $j++) { - if ($this->tokens[$j][self::TYPE] == self::T_TEXT) { - if (isset($this->tokens[$j+1]) && $this->tokens[$j+1][self::TYPE] == self::T_PARTIAL) { - $this->tokens[$j+1][self::INDENT] = $this->tokens[$j][self::VALUE]; - } - - $this->tokens[$j] = null; - } - } - } elseif (!$noNewLine) { - $this->tokens[] = array(self::TYPE => self::T_TEXT, self::VALUE => "\n"); - } - - $this->seenTag = false; - $this->lineStart = count($this->tokens); - } - - /** - * Change the current Mustache delimiters. Set new `otag` and `ctag` values. - * - * @param string $text Mustache template source - * @param int $index Current tokenizer index - * - * @return int New index value - */ - private function changeDelimiters($text, $index) - { - $startIndex = strpos($text, '=', $index) + 1; - $close = '='.$this->ctag; - $closeIndex = strpos($text, $close, $index); - - list($otag, $ctag) = explode(' ', trim(substr($text, $startIndex, $closeIndex - $startIndex))); - $this->otag = $otag; - $this->ctag = $ctag; - - return $closeIndex + strlen($close) - 1; - } - - private function addPragma($text, $index) - { - $end = strpos($text, $this->ctag, $index); - $this->pragmas[] = trim(substr($text, $index + 2, $end - $index - 2)); - - return $end + strlen($this->ctag) - 1; - } - - /** - * Test whether it's time to change tags. - * - * @param string $tag Current tag name - * @param string $text Mustache template source - * @param int $index Current tokenizer index - * - * @return boolean True if this is a closing section tag - */ - private function tagChange($tag, $text, $index) - { - return substr($text, $index, strlen($tag)) === $tag; - } - - public function returnTokens() - { - return $this->tokens; - } -} diff --git a/core/lib/PatternLab/Builder.php b/core/lib/PatternLab/Builder.php deleted file mode 100644 index 3913a23d8..000000000 --- a/core/lib/PatternLab/Builder.php +++ /dev/null @@ -1,1371 +0,0 @@ - $value) { - - // if the variables are array-like make sure the properties are validated/trimmed/lowercased before saving - $arrayKeys = array("ie","id","patternStates","styleGuideExcludes"); - if (in_array($key,$arrayKeys)) { - $values = explode(",",$value); - array_walk($values,'PatternLab\Builder::trim'); - $this->$key = $values; - } else if ($key == "ishControlsHide") { - $this->$key = new \stdClass(); - if ($value != "") { - $values = explode(",",$value); - foreach($values as $value2) { - $value2 = trim($value2); - $this->$key->$value2 = true; - } - } - } else { - $this->$key = $value; - } - - } - - // set-up the source & public dirs - $this->sp = "/../../../source/_patterns".DIRECTORY_SEPARATOR; - $this->pp = "/../../../public/patterns".DIRECTORY_SEPARATOR; - $this->sd = __DIR__."/../../../source"; - $this->pd = __DIR__."/../../../public"; - - // provide the default for enable CSS. performance hog so it should be run infrequently - $this->enableCSS = false; - $this->patternCSS = array(); - - } - - /** - * Load a new Mustache instance that uses the Pattern Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustachePatternLoaderInstance() { - $this->mpl = new Engine(array( - "loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)), - "partials_loader" => new PatternLoader(__DIR__.$this->sp,array("patternPaths" => $this->patternPaths)) - )); - } - - /** - * Load a new Mustache instance that uses the File System Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustacheFileSystemLoaderInstance() { - $this->mfs = new Engine(array( - "loader" => new FilesystemLoader(__DIR__."/../../templates/"), - "partials_loader" => new FilesystemLoader(__DIR__."/../../templates/partials/") - )); - } - - /** - * Load a new Mustache instance that uses the File System Loader - * - * @return {Object} an instance of the Mustache engine - */ - protected function loadMustacheVanillaInstance() { - $this->mv = new Engine; - } - - /** - * Renders a given pattern file using Mustache and incorporating the provided data - * @param {String} the filename of the file to be rendered - * @param {String} the pattern partial - * - * @return {String} the mark-up as rendered by Mustache - */ - protected function renderPattern($f,$p) { - - // if there is pattern-specific data make sure to override the default in $this->d - $d = $this->d; - - if (isset($d["patternSpecific"]) && array_key_exists($p,$d["patternSpecific"])) { - - if (!empty($d["patternSpecific"][$p]["data"])) { - $d = array_replace_recursive($d, $d["patternSpecific"][$p]["data"]); - } - - if (!empty($d["patternSpecific"][$p]["listItems"])) { - - $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"); - - $k = 0; - $c = count($d["patternSpecific"][$p]["listItems"]); - - while ($k < $c) { - $section = $numbers[$k]; - $d["listItems"][$section] = array_replace_recursive( $d["listItems"][$section], $d["patternSpecific"][$p]["listItems"][$section]); - $k++; - } - - } - - } - - $pattern = $this->mpl->render($f,$d); - $escaped = htmlentities($pattern); - - if ($this->addPatternHF) { - $patternHead = $this->mv->render($this->patternHead,$d); - $patternFoot = $this->mv->render($this->patternFoot,$d); - $pattern = $patternHead.$pattern.$patternFoot; - } - - return array($pattern,$escaped); - - } - - /** - * Generates the index page and style guide - */ - protected function generateMainPages() { - - // make sure $this->mfs & $this->mv are refreshed - $this->loadMustacheFileSystemLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // get the source pattern paths - $patternPathDests = array(); - foreach($this->patternPaths as $patternType => $patterns) { - $patternPathDests[$patternType] = array(); - foreach ($patterns as $pattern => $patternInfo) { - if ($patternInfo["render"]) { - $patternPathDests[$patternType][$pattern] = $patternInfo["patternDestPath"]; - } - } - } - - // render out the main pages and move them to public - $this->navItems['autoreloadport'] = $this->autoReloadPort; - $this->navItems['pagefollowport'] = $this->pageFollowPort; - $this->navItems['patternpaths'] = json_encode($patternPathDests); - $this->navItems['viewallpaths'] = json_encode($this->viewAllPaths); - $this->navItems['mqs'] = $this->gatherMQs(); - $this->navItems['ipaddress'] = getHostByName(getHostName()); - $this->navItems['xiphostname'] = $this->xipHostname; - $this->navItems['ishControlsHide'] = $this->ishControlsHide; - - // grab the partials into a data object for the style guide - $sd = array("partials" => array()); - foreach ($this->patternPartials as $patternSubtypes) { - foreach ($patternSubtypes as $patterns) { - $sd["partials"][] = $patterns; - } - } - - // render the "view all" pages - $this->generateViewAllPages(); - - // add cacheBuster info - $this->navItems['cacheBuster'] = $this->cacheBuster; - $sd['cacheBuster'] = $this->cacheBuster; - - // render the index page - $r = $this->mfs->render('index',$this->navItems); - file_put_contents($this->pd."/index.html",$r); - - // render the style guide - $sd = array_replace_recursive($this->d,$sd); - $styleGuideHead = $this->mv->render($this->mainPageHead,$sd); - $styleGuideFoot = $this->mv->render($this->mainPageFoot,$sd); - $styleGuidePage = $styleGuideHead.$this->mfs->render('viewall',$sd).$styleGuideFoot; - file_put_contents($this->pd."/styleguide/html/styleguide.html",$styleGuidePage); - - } - - /** - * Generates all of the patterns and puts them in the public directory - */ - protected function generatePatterns() { - - // make sure the pattern header & footer are added - $this->addPatternHF = true; - - // make sure $this->mpl & $this->mv are refreshed - $this->loadMustachePatternLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // loop over the pattern paths to generate patterns for each - foreach($this->patternPaths as $patternType) { - - foreach($patternType as $pattern => $pathInfo) { - - // make sure this pattern should be rendered - if ($pathInfo["render"]) { - - // get the rendered, escaped, and mustache pattern - $this->generatePatternFile($pathInfo["patternSrcPath"].".mustache",$pathInfo["patternPartial"],$pathInfo["patternDestPath"],$pathInfo["patternState"]); - - } - - } - - } - - } - - /** - * Generates a pattern with a header & footer, the escaped version of a pattern, the msutache template, and the css if appropriate - * @param {String} the filename of the file to be rendered - * @param {String} the pattern partial - * @param {String} path where the files need to be written too - * @param {String} pattern state - */ - private function generatePatternFile($f,$p,$path,$state) { - - // render the pattern and return it as well as the encoded version - list($rf,$e) = $this->renderPattern($f,$p); - - // the core footer isn't rendered as mustache but we have some variables there any way. find & replace. - $rf = str_replace("{% patternPartial %}",$p,$rf); - $rf = str_replace("{% lineage %}",json_encode($this->patternLineages[$p]),$rf); - $rf = str_replace("{% lineageR %}",json_encode($this->patternLineagesR[$p]),$rf); - $rf = str_replace("{% patternState %}",$state,$rf); - - // figure out what to put in the css section - $c = $this->enableCSS && isset($this->patternCSS[$p]) ? "true" : "false"; - $rf = str_replace("{% cssEnabled %}",$c,$rf); - - // get the original mustache template - $m = htmlentities(file_get_contents(__DIR__.$this->sp.$f)); - - // if the pattern directory doesn't exist create it - if (!is_dir(__DIR__.$this->pp.$path)) { - mkdir(__DIR__.$this->pp.$path); - } - - // write out the various pattern files - file_put_contents(__DIR__.$this->pp.$path."/".$path.".html",$rf); - file_put_contents(__DIR__.$this->pp.$path."/".$path.".escaped.html",$e); - file_put_contents(__DIR__.$this->pp.$path."/".$path.".mustache",$m); - if ($this->enableCSS && isset($this->patternCSS[$p])) { - file_put_contents(__DIR__.$this->pp.$path."/".$path.".css",htmlentities($this->patternCSS[$p])); - } - - } - - /** - * Generates the view all pages - */ - protected function generateViewAllPages() { - - // make sure $this->mfs & $this->mv are refreshed on each generation of view all - $this->loadMustacheFileSystemLoaderInstance(); - $this->loadMustacheVanillaInstance(); - - // add view all to each list - $i = 0; $k = 0; - foreach ($this->navItems['patternTypes'] as $bucket) { - - // make sure that the navItems index exists. catches issues with pages & templates - if (isset($bucket["patternTypeItems"])) { - - foreach ($bucket["patternTypeItems"] as $navItem) { - - // make sure the navSubItems index exists. catches issues with empty folders - if (isset($navItem["patternSubtypeItems"])) { - - foreach ($navItem["patternSubtypeItems"] as $subItem) { - - if ($subItem["patternName"] == "View All") { - - // get the pattern parts - $patternType = $subItem["patternType"]; - $patternSubType = $subItem["patternSubtype"]; - - // get all the rendered partials that match - $sid = array("partials" => $this->patternPartials[$this->getPatternName($patternType,false)."-".$this->getPatternName($patternSubType,false)]); - $sid["patternPartial"] = $subItem["patternPartial"]; - $sid["cacheBuster"] = $this->cacheBuster; - $sid = array_replace_recursive($this->d,$sid); - - // render the viewall template - $viewAllHead = $this->mv->render($this->mainPageHead,$sid); - $viewAllFoot = $this->mv->render($this->mainPageFoot,$sid); - $viewAllPage = $viewAllHead.$this->mfs->render('viewall',$sid).$viewAllFoot; - - // if the pattern directory doesn't exist create it - $patternPath = $patternType."-".$patternSubType; - if (!is_dir(__DIR__.$this->pp.$patternPath)) { - mkdir(__DIR__.$this->pp.$patternPath); - file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage); - } else { - file_put_contents(__DIR__.$this->pp.$patternPath."/index.html",$viewAllPage); - } - - } - - } - - } - - } - - } - - $i++; - $k = 0; - - } - - } - - /** - * Gather data from source/_data/_data.json, source/_data/_listitems.json, and pattern-specific json files - * - * Reserved attributes: - * - $this->d["listItems"] : listItems from listitems.json, duplicated into separate arrays for $this->d->listItems->one, $this->d->listItems->two, $this->d->listItems->three... etc. - * - $this->d["link"] : the links to each pattern - * - $this->d["cacheBuster"] : the cache buster value to be appended to URLs - * - $this->d["patternSpecific"] : holds attributes from the pattern-specific data files - * - * @return {Array} populates $this->d - */ - protected function gatherData() { - - // set the cacheBuster - $this->cacheBuster = time(); - - // gather the data from the main source data.json - if (file_exists($this->sd."/_data/_data.json")) { - $this->d = json_decode(file_get_contents($this->sd."/_data/_data.json"),true); - $this->jsonLastErrorMsg("_data/_data.json"); - } else { - print "Missing a required file, source/_data/_data.json. Aborting.\n"; - exit; - } - - $reservedKeys = array("listItems","cacheBuster","link","patternSpecific"); - foreach ($reservedKeys as $reservedKey) { - if (array_key_exists($reservedKey,$this->d)) { - print "\"".$reservedKey."\" is a reserved key in Pattern Lab. The data using that key in _data.json will be overwritten. Please choose a new key.\n"; - } - } - - - $this->d["listItems"] = $this->getListItems($this->sd."/_data/_listitems.json"); - $this->d["cacheBuster"] = $this->cacheBuster; - $this->d["link"] = array(); - $this->d["patternSpecific"] = array(); - - } - - /** - * Finds the regular and reverse lineages for the patterns - * - * @return {Array} an array of patterns with their lineages - */ - protected function gatherLineages() { - - $this->patternLineages = array(); - $this->patternLineagesR = array(); - $foundLineages = array(); - - // check for the regular lineages - foreach($this->patternPaths as $patternType => $patterns) { - - foreach ($patterns as $pattern => $patternInfo) { - - $patternLineage = array(); - $filename = $patternInfo["patternSrcPath"]; - - // if a file doesn't exist it assumes it's a pseudo-pattern and will use the last lineage found - if (file_exists(__DIR__.$this->sp.$filename.".mustache")) { - $foundLineages = array_unique($this->getLineage($filename)); - } - - if (count($foundLineages) > 0) { - foreach ($foundLineages as $lineage) { - $patternBits = $this->getPatternInfo($lineage); - if ((count($patternBits) == 2) && isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) { - $path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"]; - $patternLineage[] = array("lineagePattern" => $lineage, - "lineagePath" => "../../patterns/".$path."/".$path.".html"); - } else { - if (strpos($lineage, '/') === false) { - print "You may have a typo in ".$patternInfo["patternSrcPath"].". {{> ".$lineage." }} is not a valid pattern.\n"; - } - } - } - } - - $this->patternLineages[$patternType."-".$pattern] = $patternLineage; - - } - - } - - // check for the reverse lineages - foreach ($this->patternLineages as $needlePartial => $needleLineages) { - - $patternLineageR = array(); - - foreach ($this->patternLineages as $haystackPartial => $haystackLineages) { - - foreach ($haystackLineages as $haystackLineage) { - - if ($haystackLineage["lineagePattern"] == $needlePartial) { - - $foundAlready = false; - foreach ($patternLineageR as $patternCheck) { - if ($patternCheck["lineagePattern"] == $haystackPartial) { - $foundAlready = true; - break; - } - } - - if (!$foundAlready) { - $patternBits = $this->getPatternInfo($haystackPartial); - if (isset($this->patternPaths[$patternBits[0]][$patternBits[1]])) { - $path = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternDestPath"]; - $patternLineageR[] = array("lineagePattern" => $haystackPartial, - "lineagePath" => "../../patterns/".$path."/".$path.".html"); - } - } - - } - - } - - } - - $this->patternLineagesR[$needlePartial] = $patternLineageR; - - } - - } - - /** - * Finds Media Queries in CSS files in the source/css/ dir - * - * @return {Array} an array of the appropriate MQs - */ - protected function gatherMQs() { - - $mqs = array(); - - foreach(glob($this->sd."/css/*.css") as $filename) { - $data = file_get_contents($filename); - preg_match_all("/(min|max)-width:([ ]+)?(([0-9]{1,5})(\.[0-9]{1,20}|)(px|em))/",$data,$matches); - foreach ($matches[3] as $match) { - if (!in_array($match,$mqs)) { - $mqs[] = $match; - } - } - } - - sort($mqs); - return $mqs; - - } - - /** - * Refactoring the pattern path stuff - */ - protected function gatherPatternInfo() { - - // make sure the pattern header & footer aren't added - $this->addPatternHF = false; - - // set-up the defaults - $patternType = ""; - $patternSubtype = ""; - $patternSubtypeSet = false; - $dirSep = DIRECTORY_SEPARATOR; - - // initialize various arrays - $this->navItems = array(); - $this->navItems["patternTypes"] = array(); - $this->patternPaths = array(); - $this->patternTypes = array(); - $this->patternLineages = array(); - $this->patternPartials = array(); - $this->viewAllPaths = array(); - - // iterate over the patterns & related data and regenerate the entire site if they've changed - $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__.$this->sp), \RecursiveIteratorIterator::SELF_FIRST); - $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); - - $patternObjects = iterator_to_array($patternObjects); - ksort($patternObjects); - - foreach($patternObjects as $name => $object) { - - $name = str_replace(__DIR__.$this->sp,"",$name); - $depth = substr_count($name,$dirSep); - - // track old types and subtypes for increment purposes - - if ($object->isDir() && ($depth == 0)) { - - /************************************* - * This section is for: - * The pattern type directory - *************************************/ - - // is this the first bucket to be set? - $bi = (count($this->navItems["patternTypes"]) == 0) ? 0 : $bi + 1; - - // set-up the names - $patternType = $name; // 00-atoms - $patternTypeDash = $this->getPatternName($name,false); // atoms - $patternTypeClean = str_replace("-"," ",$patternTypeDash); // atoms (dashes replaced with spaces) - - // add to pattern types & pattern paths - $this->patternTypes[] = $patternType; - $this->patternPaths[$patternTypeDash] = array(); - - // add a new patternType to the nav - $this->navItems["patternTypes"][$bi] = array("patternTypeLC" => strtolower($patternTypeClean), - "patternTypeUC" => ucwords($patternTypeClean), - "patternType" => $patternType, - "patternTypeDash" => $patternTypeDash); - - // starting a new set of pattern types. it might not have any pattern subtypes - $patternSubtypeSet = false; - - } else if ($object->isDir() && ($depth == 1)) { - - /************************************* - * This section is for: - * The pattern sub-type directory - *************************************/ - - // is this the first bucket to be set? - $ni = (!$patternSubtypeSet) ? 0 : $ni + 1; - - // set-up the names - $patternSubtype = $object->getFilename(); // 02-blocks - $patternSubtypeDash = $this->getPatternName($object->getFilename(),false); // blocks - $patternSubtypeClean = str_replace("-"," ",$patternSubtypeDash); // blocks (dashes replaced with spaces) - - // add to patternPartials - $this->patternPartials[$patternTypeDash."-".$patternSubtypeDash] = array(); - - // add a new patternSubtype to the nav - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni] = array("patternSubtypeLC" => strtolower($patternSubtypeClean), - "patternSubtypeUC" => ucwords($patternSubtypeClean), - "patternSubtype" => $patternSubtype, - "patternSubtypeDash" => $patternSubtypeDash); - - // starting a new set of pattern types. it might not have any pattern subtypes - $patternSubtypeSet = true; - - } else if ($object->isFile() && ($object->getExtension() == "mustache")) { - - /************************************* - * This section is for: - * Mustache patterns - *************************************/ - - $patternFull = $object->getFilename(); // 00-colors.mustache - $pattern = str_replace(".mustache","",$patternFull); // 00-colors - - // check for pattern state - $patternState = ""; - if (strpos($pattern,"@") !== false) { - $patternBits = explode("@",$pattern,2); - $pattern = $patternBits[0]; - $patternState = $patternBits[1]; - } - - if ($patternSubtypeSet) { - $patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path) - } else { - $patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path) - } - - // track to see if this pattern should get rendered - $render = false; - - // make sure the pattern isn't hidden - if ($patternFull[0] != "_") { - - // set-up the names - $patternDash = $this->getPatternName($pattern,false); // colors - $patternClean = str_replace("-"," ",$patternDash); // colors (dashes replaced with spaces) - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - // set-up the info for the nav - $patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html", - "patternSrcPath" => str_replace(__DIR__.$this->sp,"",$object->getPathname()), - "patternName" => ucwords($patternClean), - "patternState" => $patternState, - "patternPartial" => $patternPartial); - - // add to the nav - if ($depth == 1) { - $this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo; - } else { - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo; - } - - // add to the link var for inclusion in patterns - $this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html"; - - // yup, this pattern should get rendered - $render = true; - - } else { - - // replace the underscore to generate a good file pattern name - $patternDash = $this->getPatternName(str_replace("_","",$pattern),false); // colors - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - } - - // add all patterns to patternPaths - $patternSrcPath = str_replace(__DIR__.$this->sp,"",str_replace(".mustache","",$object->getPathname())); - $patternDestPath = $patternPathDash; - $this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath, - "patternDestPath" => $patternDestPath, - "patternPartial" => $patternPartial, - "patternState" => $patternState, - "patternType" => $patternTypeDash, - "render" => $render); - - } else if ($object->isFile() && ($object->getExtension() == "json") && (strpos($object->getFilename(),"~") !== false)) { - - /************************************* - * This section is for: - * JSON psuedo-patterns - *************************************/ - - $patternSubtypeInclude = ($patternSubtypeSet) ? $patternSubtype."-" : ""; - $patternFull = $object->getFilename(); - - if ($patternFull[0] != "_") { - - // check for a pattern state - $patternState = ""; - $patternBits = explode("@",$patternFull,2); - if (isset($patternBits[1])) { - $patternState = str_replace(".json","",$patternBits[1]); - $patternFull = preg_replace("/@(.*?)\./",".",$patternFull); - } - - // set-up the names - // $patternFull is defined above 00-colors.mustache - $patternBits = explode("~",$patternFull); - $patternBase = $patternBits[0].".mustache"; // 00-homepage.mustache - $patternBaseDash = $this->getPatternName($patternBits[0],false); // homepage - $patternBaseJSON = $patternBits[0].".json"; // 00-homepage.json - $stripJSON = str_replace(".json","",$patternBits[1]); - $patternBitClean = preg_replace("/@(.*?)/","",$patternBits[0]); - $pattern = $patternBitClean."-".$stripJSON; // 00-homepage-00-emergency - $patternInt = $patternBitClean."-".$this->getPatternName($stripJSON, false); // 00-homepage-emergency - $patternDash = $this->getPatternName($patternInt,false); // homepage-emergency - $patternClean = str_replace("-"," ",$patternDash); // homepage emergency - $patternPartial = $patternTypeDash."-".$patternDash; // pages-homepage-emergency - - // add to patternPaths - if ($patternSubtypeSet) { - $patternPath = $patternType.$dirSep.$patternSubtype.$dirSep.$pattern; // 00-atoms/01-global/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-01-global-00-colors (file path) - } else { - $patternPath = $patternType.$dirSep.$pattern; // 00-atoms/00-colors - $patternPathDash = str_replace($dirSep,"-",$patternPath); // 00-atoms-00-colors (file path) - } - - // add all patterns to patternPaths - $patternSrcPath = $this->patternPaths[$patternTypeDash][$patternBaseDash]["patternSrcPath"]; - $patternDestPath = $patternPathDash; - $this->patternPaths[$patternTypeDash][$patternDash] = array("patternSrcPath" => $patternSrcPath, - "patternDestPath" => $patternDestPath, - "patternPartial" => $patternPartial, - "patternState" => $patternState, - "patternType" => $patternTypeDash, - "render" => true); - - // set-up the info for the nav - $patternInfo = array("patternPath" => $patternPathDash."/".$patternPathDash.".html", - "patternSrcPath" => str_replace(__DIR__.$this->sp,"",preg_replace("/\~(.*)\.json/",".mustache",$object->getPathname())), - "patternName" => ucwords($patternClean), - "patternState" => $patternState, - "patternPartial" => $patternPartial); - - // add to the nav - if ($depth == 1) { - $this->navItems["patternTypes"][$bi]["patternItems"][] = $patternInfo; - } else { - $this->navItems["patternTypes"][$bi]["patternTypeItems"][$ni]["patternSubtypeItems"][] = $patternInfo; - } - - // add to the link var for inclusion in patterns - $this->d["link"][$patternPartial] = "../../patterns/".$patternPathDash."/".$patternPathDash.".html"; - - // get the base data - $patternDataBase = array(); - if (file_exists($object->getPath()."/".$patternBaseJSON)) { - $patternDataBase = json_decode(file_get_contents($object->getPath()."/".$patternBaseJSON),true); - $this->jsonLastErrorMsg($patternBaseJSON); - } - - // get the special pattern data - $patternData = (array) json_decode(file_get_contents($object->getPathname())); - $this->jsonLastErrorMsg($object->getFilename()); - - // merge them for the file - if (!isset($this->d["patternSpecific"][$patternPartial])) { - $this->d["patternSpecific"][$patternPartial] = array(); - $this->d["patternSpecific"][$patternPartial]["data"] = array(); - $this->d["patternSpecific"][$patternPartial]["listItems"] = array(); - } - - if (is_array($patternDataBase) && is_array($patternData)) { - $this->d["patternSpecific"][$patternPartial]["data"] = array_merge($patternDataBase, $patternData); - } - - } - - } else if ($object->isFile() && ($object->getExtension() == "json")) { - - /************************************* - * This section is for: - * JSON data - *************************************/ - $patternFull = $object->getFilename(); // 00-colors.mustache - $pattern = str_replace(".listitems","",str_replace(".json","",$patternFull)); // 00-colors - $patternDash = $this->getPatternName($pattern,false); // colors - $patternPartial = $patternTypeDash."-".$patternDash; // atoms-colors - - if ($patternFull[0] != "_") { - - if (!isset($this->d["patternSpecific"][$patternPartial])) { - $this->d["patternSpecific"][$patternPartial] = array(); - $this->d["patternSpecific"][$patternPartial]["data"] = array(); - $this->d["patternSpecific"][$patternPartial]["listItems"] = array(); - } - - if (strpos($object->getFilename(),".listitems.json") !== false) { - $patternData = $this->getListItems($object->getPathname()); - $this->d["patternSpecific"][$patternPartial]["listItems"] = $patternData; - } else { - $patternData = json_decode(file_get_contents($object->getPathname()),true); - $this->jsonLastErrorMsg($patternFull); - $this->d["patternSpecific"][$patternPartial]["data"] = $patternData; - } - - } - - } - - } - - // get all of the lineages - $this->gatherLineages(); - - // check on the states of the patterns - $patternStateLast = count($this->patternStates) - 1; - foreach($this->patternPaths as $patternType => $patterns) { - - foreach ($patterns as $pattern => $patternInfo) { - - $patternState = $this->patternPaths[$patternType][$pattern]["patternState"]; - - // make sure the pattern has a given state - if ($patternState != "") { - - $patternStateDigit = array_search($patternState, $this->patternStates); - if ($patternStateDigit !== false) { - // iterate over each of the reverse lineages for a given pattern to update their state - foreach ($this->patternLineagesR[$patternType."-".$pattern] as $patternCheckInfo) { - $patternBits = $this->getPatternInfo($patternCheckInfo["lineagePattern"]); - if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] == "") && ($patternStateDigit != $patternStateLast)) { - $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState; - } else { - $patternStateCheck = array_search($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"], $this->patternStates); - if ($patternStateDigit < $patternStateCheck) { - $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] = $patternState; - } - } - } - - } - - } - - } - - } - - // make sure we update the lineages with the pattern state if appropriate - foreach($this->patternLineages as $pattern => $patternLineages) { - foreach($patternLineages as $key => $patternLineageInfo) { - $patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]); - $patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - if (($patternState != "") && ($patternState != null)) { - $this->patternLineages[$pattern][$key]["lineageState"] = $patternState; - } - } - } - - foreach($this->patternLineagesR as $pattern => $patternLineages) { - foreach($patternLineages as $key => $patternLineageInfo) { - $patternBits = $this->getPatternInfo($patternLineageInfo["lineagePattern"]); - $patternState = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - if (($patternState != "") && ($patternState != null)) { - $this->patternLineagesR[$pattern][$key]["lineageState"] = $patternState; - } - } - } - - // make sure $this->mpl is refreshed - $this->loadMustachePatternLoaderInstance(); - - // run through the nav items and generate pattern partials and the view all pages - foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) { - - $patternType = $patternTypeValues["patternType"]; - $patternTypeDash = $patternTypeValues["patternTypeDash"]; - - // if this has a second level of patterns check them out (means we don't process pages & templates) - if (isset($patternTypeValues["patternTypeItems"]) && (!in_array($patternType,$this->styleGuideExcludes))) { - - $arrayReset = false; - - foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) { - - // if there are no sub-items in a section remove it, else do a bunch of other stuff - if (!isset($patternSubtypeValues["patternSubtypeItems"])) { - - unset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]); - $arrayReset = true; - - } else { - - $patternSubtype = $patternSubtypeValues["patternSubtype"]; - $patternSubtypeDash = $patternSubtypeValues["patternSubtypeDash"]; - $subItemsCount = count($patternSubtypeValues["patternSubtypeItems"]); - - // add a view all link - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$subItemsCount] = array( - "patternPath" => $patternType."-".$patternSubtype."/index.html", - "patternName" => "View All", - "patternType" => $patternType, - "patternSubtype" => $patternSubtype, - "patternPartial" => "viewall-".$patternTypeDash."-".$patternSubtypeDash); - - // add to the view all paths - $this->viewAllPaths[$patternTypeDash][$patternSubtypeDash] = $patternType."-".$patternSubtype; - - // add patterns to $this->patternPartials - foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) { - - $patternCode = $this->renderPattern($patternSubtypeItem["patternSrcPath"],$patternSubtypeItem["patternPartial"]); - $patternCodeRaw = $patternCode[0]; - $patternCodeEncoded = $patternCode[1]; - $patternLineageExists = (count($this->patternLineages[$patternSubtypeItem["patternPartial"]]) > 0) ? true : false; - $patternLineages = $this->patternLineages[$patternSubtypeItem["patternPartial"]]; - - // set-up the mark-up for CSS Rule Saver so it can figure out which rules to save - $patternCSSExists = $this->enableCSS; - $patternCSS = ""; - if ($this->enableCSS) { - $this->cssRuleSaver->loadHTML($patternCodeRaw,false); - $patternCSS = $this->cssRuleSaver->saveRules(); - $this->patternCSS[$patternSubtypeItem["patternPartial"]] = $patternCSS; - } - - $this->patternPartials[$patternTypeDash."-".$patternSubtypeDash][] = array("patternName" => $patternSubtypeItem["patternName"], - "patternLink" => $patternSubtypeItem["patternPath"], - "patternPartial" => $patternSubtypeItem["patternPartial"], - "patternPartialCode" => $patternCodeRaw, - "patternPartialCodeE" => $patternCodeEncoded, - "patternCSSExists" => $patternCSSExists, - "patternCSS" => $patternCSS, - "patternLineageExists" => $patternLineageExists, - "patternLineages" => $patternLineages - ); - - // set the pattern state - $patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]); - if (($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") && (isset($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"]))) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - } - - } - - } - - } - - // reset the items to take into account removed items affecting the index - if ($arrayReset) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"] = array_values($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"]); - $arrayReset = false; - } - - } else { - - foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) { - // set the pattern state - $patternBits = $this->getPatternInfo($patternSubtypeItem["patternPartial"]); - if ($this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"] != "") { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $this->patternPaths[$patternBits[0]][$patternBits[1]]["patternState"]; - } - } - } - - } - - // load pattern-lab's resources - $htmlHead = file_get_contents(__DIR__."/../../templates/pattern-header-footer/header.html"); - $htmlFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer.html"); - $extraFoot = file_get_contents(__DIR__."/../../templates/pattern-header-footer/footer-pattern.html"); - - // gather the user-defined header and footer information - $patternHeadPath = __DIR__.$this->sp."00-atoms/00-meta/_00-head.mustache"; - $patternFootPath = __DIR__.$this->sp."00-atoms/00-meta/_01-foot.mustache"; - $patternHead = (file_exists($patternHeadPath)) ? file_get_contents($patternHeadPath) : ""; - $patternFoot = (file_exists($patternFootPath)) ? file_get_contents($patternFootPath) : ""; - - // add pattern lab's resource to the user-defined files - $this->patternHead = str_replace("{% pattern-lab-head %}",$htmlHead,$patternHead); - $this->patternFoot = str_replace("{% pattern-lab-foot %}",$extraFoot.$htmlFoot,$patternFoot); - $this->mainPageHead = $this->patternHead; - $this->mainPageFoot = str_replace("{% pattern-lab-foot %}",$htmlFoot,$patternFoot); - - } - - /** - * Get the lineage for a given pattern by parsing it and matching mustache partials - * @param {String} the filename for the pattern to be parsed - * - * @return {Array} a list of patterns - */ - protected function getLineage($filename) { - $data = file_get_contents(__DIR__.$this->sp.$filename.".mustache"); - //$data = file_get_contents($filename); - if (preg_match_all('/{{>([ ]+)?([A-Za-z0-9-]+)(?:\:[A-Za-z0-9-]+)?(?:(| )\(.*)?([ ]+)}}/',$data,$matches)) { - return $matches[2]; - } - return array(); - } - - /** - * Get the lineage for a given pattern by parsing it and matching mustache partials - * @param {String} the filename for the pattern to be parsed - * - * @return {Array} the final set of list items - */ - protected function getListItems($filepath) { - - $listItems = array(); - - // add list item data, makes 'listItems' a reserved word - if (file_exists($filepath)) { - - $listItemsJSON = json_decode(file_get_contents($filepath), true); - $this->jsonLastErrorMsg(str_replace($this->sd."/","",$filepath)); - - $numbers = array("one","two","three","four","five","six","seven","eight","nine","ten","eleven","twelve"); - - $i = 0; - $k = 1; - $c = count($listItemsJSON)+1; - - while ($k < $c) { - - shuffle($listItemsJSON); - $itemsArray = array(); - //$listItems[$numbers[$k-1]] = array(); - - while ($i < $k) { - $itemsArray[] = $listItemsJSON[$i]; - $i++; - } - - $listItems[$numbers[$k-1]] = $itemsArray; - - $i = 0; - $k++; - - } - - } - - return $listItems; - - } - - /** - * Get the directory path for a given pattern or json file by parsing the file path - * @param {String} the filepath for a directory that contained the match - * @param {String} the type of match for the pattern matching, defaults to mustache - * - * @return {String} the directory for the pattern - */ - protected function getPath($filepath,$type = "m") { - $file = ($type == 'm') ? '\.mustache' : '\.json'; - if (preg_match('/\/('.$this->patternTypesRegex.'\/(([A-z0-9-]{1,})\/|)([A-z0-9-]{1,}))'.$file.'$/',$filepath,$matches)) { - return $matches[1]; - } - } - - /** - * Helper function to return the parts of a partial name - * @param {String} the name of the partial - * - * @return {Array} the pattern type and the name of the pattern - */ - private function getPatternInfo($name) { - - $patternBits = explode("-",$name); - - $i = 1; - $k = 2; - $c = count($patternBits); - $patternType = $patternBits[0]; - while (!isset($this->patternPaths[$patternType]) && ($i < $c)) { - $patternType .= "-".$patternBits[$i]; - $i++; - $k++; - } - - $patternBits = explode("-",$name,$k); - $pattern = $patternBits[count($patternBits)-1]; - - return array($patternType, $pattern); - - } - - /** - * Get the name for a given pattern sans any possible digits used for reordering - * @param {String} the pattern based on the filesystem name - * @param {Boolean} whether or not to strip slashes from the pattern name - * - * @return {String} a lower-cased version of the pattern name - */ - protected function getPatternName($pattern, $clean = true) { - $patternBits = explode("-",$pattern,2); - $patternName = (((int)$patternBits[0] != 0) || ($patternBits[0] == '00')) ? $patternBits[1] : $pattern; - return ($clean) ? (str_replace("-"," ",$patternName)) : $patternName; - } - - protected function setPatternState($patternState, $patternPartial) { - - // set-up some defaults - $patternState = array_search($patternState, $this->patternStates); - - // iterate over each of the reverse lineages for a given pattern to update their state - foreach ($this->patternLineagesR[$patternPartial] as $patternCheckInfo) { - - // run through all of the navitems to find what pattern states match. this feels, and is, overkill - foreach ($this->navItems["patternTypes"] as $patternTypeKey => $patternTypeValues) { - - if (isset($patternTypeValues["patternTypeItems"])) { - - foreach ($patternTypeValues["patternTypeItems"] as $patternSubtypeKey => $patternSubtypeValues) { - - // add patterns to $this->patternPartials - foreach ($patternSubtypeValues["patternSubtypeItems"] as $patternSubtypeItemKey => $patternSubtypeItem) { - - if ($patternSubtypeItem["patternPartial"] == $patternPartial) { - - if ($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] == "") { - $f = $patternState; - } else { - $patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"], $this->patternStates); - if ($patternState < $patternCheckState) { - $this->navItems["patternTypes"][$patternTypeKey]["patternTypeItems"][$patternSubtypeKey]["patternSubtypeItems"][$patternSubtypeItemKey]["patternState"] = $patternState; - } - } - - } - - } - - } - - } else { - - foreach ($patternTypeValues["patternItems"] as $patternSubtypeKey => $patternSubtypeItem) { - - if ($patternSubtypeItem["patternPartial"] == $patternPartial) { - - if ($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] == "") { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState; - } else { - $patternCheckState = array_search($this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"], $this->patternStates); - if ($patternState < $patternCheckState) { - $this->navItems["patternTypes"][$patternTypeKey]["patternItems"][$patternSubtypeKey]["patternState"] = $patternState; - } - } - - } - - } - - } - - } - - } - - } - - /** - * Write out the time tracking file so the content sync service will work. A holdover - * from how I put together the original AJAX polling set-up. - */ - protected function updateChangeTime() { - - if (is_dir($this->pd."/")) { - file_put_contents($this->pd."/latest-change.txt",time()); - } else { - print "Either the public directory for Pattern Lab doesn't exist or the builder is in the wrong location. Please fix."; - exit; - } - - } - - /** - * Delete patterns and user-created directories and files in public/ - */ - protected function cleanPublic() { - - // find all of the patterns in public/. sort by the children first - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->pd."/patterns/"), \RecursiveIteratorIterator::CHILD_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - // for each file figure out what to do with it - foreach($objects as $name => $object) { - - if ($object->isDir()) { - // if this is a directory remove it - rmdir($name); - } else if ($object->isFile() && ($object->getFilename() != "README")) { - // if this is a file remove it - unlink($name); - } - - } - - // scan source/ & public/ to figure out what directories might need to be cleaned up - $sourceDirs = glob($this->sd."/*",GLOB_ONLYDIR); - $publicDirs = glob($this->pd."/*",GLOB_ONLYDIR); - - // make sure some directories aren't deleted - $ignoreDirs = array("styleguide"); - foreach ($ignoreDirs as $ignoreDir) { - $key = array_search($this->pd."/".$ignoreDir,$publicDirs); - if ($key !== false){ - unset($publicDirs[$key]); - } - } - - // compare source dirs against public. remove those dirs w/ an underscore in source/ from the public/ list - foreach ($sourceDirs as $sourceDir) { - $cleanDir = str_replace($this->sd."/","",$sourceDir); - if ($cleanDir[0] == "_") { - $key = array_search($this->pd."/".str_replace("_","",$cleanDir),$publicDirs); - if ($key !== false){ - unset($publicDirs[$key]); - } - } - } - - // for the remaining dirs in public delete them and their files - foreach ($publicDirs as $dir) { - - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), \RecursiveIteratorIterator::CHILD_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - if ($object->isDir()) { - rmdir($name); - } else if ($object->isFile()) { - unlink($name); - } - - } - - rmdir($dir); - - } - - } - - /** - * Copies a file from the given source path to the given public path. - * THIS IS NOT FOR PATTERNS - * @param {String} the source file - * @param {String} the public file - */ - protected function moveFile($s,$p) { - if (file_exists($this->sd."/".$s)) { - copy($this->sd."/".$s,$this->pd."/".$p); - } - } - - /** - * Moves static files that aren't directly related to Pattern Lab - * @param {String} file name to be moved - * @param {String} copy for the message to be printed out - * @param {String} part of the file name to be found for replacement - * @param {String} the replacement - */ - protected function moveStaticFile($fileName,$copy = "", $find = "", $replace = "") { - $this->moveFile($fileName,str_replace($find, $replace, $fileName)); - $this->updateChangeTime(); - if ($copy != "") { - print $fileName." ".$copy."...\n"; - } - } - - /** - * Check to see if a given filename is in a directory that should be ignored - * @param {String} file name to be checked - * - * @return {Boolean} whether the directory should be ignored - */ - protected function ignoreDir($fileName) { - foreach($this->id as $dir) { - $pos = strpos(DIRECTORY_SEPARATOR.$fileName,DIRECTORY_SEPARATOR.$dir.DIRECTORY_SEPARATOR); - if ($pos !== false) { - return true; - } - } - return false; - } - - /** - * Loads the CSS from source/css/ into CSS Rule Saver to be used for code view - */ - protected function initializeCSSRuleSaver() { - - $loader = new \SplClassLoader('CSSRuleSaver', __DIR__.'/../../lib'); - $loader->register(); - - $this->cssRuleSaver = new \CSSRuleSaver\CSSRuleSaver; - - foreach(glob($this->sd."/css/*.css") as $filename) { - $this->cssRuleSaver->loadCSS($filename); - } - - } - - /** - * Returns the last error message when building a JSON file. Mimics json_last_error_msg() from PHP 5.5 - * @param {String} the file that generated the error - */ - protected function jsonLastErrorMsg($file) { - $errors = array( - JSON_ERROR_NONE => null, - JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', - JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', - JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', - JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', - JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' - ); - $error = json_last_error(); - $errorMessage = array_key_exists($error, $errors) ? $errors[$error] : "Unknown error ({$error})"; - if ($errorMessage != null) { - print "The JSON file, ".$file.", wasn't loaded. The error: ".$errorMessage."\n"; - } - } - - /** - * Print out the data var. For debugging purposes - * - * @return {String} the formatted version of the d object - */ - public function printData() { - print_r($this->d); - } - - /** - * Trim a given string. Used in the array_walk() function in __construct as a sanity check - * @param {String} an entry from one of the list-based config entries - * - * @return {String} trimmed version of the given $v var - */ - public function trim(&$v) { - $v = trim($v); - } - - /** - * Lowercase the given string. Used in the array_walk() function in __construct as a sanity check - * @param {String} an entry from one of the list-based config entries - * - * @return {String} lowercased version of the given $v var - */ - public function strtolower(&$v) { - $v = strtolower($v); - } - -} diff --git a/core/lib/PatternLab/Configurer.php b/core/lib/PatternLab/Configurer.php deleted file mode 100644 index f0e72551f..000000000 --- a/core/lib/PatternLab/Configurer.php +++ /dev/null @@ -1,113 +0,0 @@ -userConfigPath = __DIR__."/../../../config/config.ini"; - $this->plConfigPath = __DIR__."/../../config/config.ini.default"; - - } - - /** - * Returns the appropriate config. If it's an old version it updates the config and runs migrations - * @param {String} the version number for Pattern Lab from builder.php - * - * @return {Array} the configuration - */ - public function getConfig() { - - // make sure migrate doesn't happen by default - $migrate = false; - $diffVersion = false; - - // double-check the default config file exists - if (!file_exists($this->plConfigPath)) { - print "Please make sure config.ini.default exists before trying to have Pattern Lab build the config.ini file automagically.\n"; - exit; - } - - // set the default config using the pattern lab config - $config = parse_ini_file($this->plConfigPath); - $defaultConfig = $config; - - // check to see if the user config exists, if not create it - print "configuring pattern lab...\n"; - if (!file_exists($this->userConfigPath)) { - $migrate = true; - } else { - $config = parse_ini_file($this->userConfigPath); - } - - // compare version numbers - $diffVersion = ($config["v"] != $defaultConfig["v"]) ? true : false; - - // run an upgrade and migrations if necessary - if ($migrate || $diffVersion) { - print "upgrading your version of pattern lab...\n"; - print "checking for migrations...\n"; - $m = new Migrator; - $m->migrate(true); - if ($migrate) { - if (!@copy($this->plConfigPath, $this->userConfigPath)) { - print "Please make sure that Pattern Lab can write a new config to config/.\n"; - exit; - } - } else { - $config = $this->writeNewConfig($config,$defaultConfig); - } - } - - return $config; - - } - - /** - * Use the default config as a base and update it with old config options. Write out a new user config. - * @param {Array} the old configuration file options - * @param {Array} the default configuration file options - * - * @return {Array} the new configuration - */ - protected function writeNewConfig($oldConfig,$defaultConfig) { - - // iterate over the old config and replace values in the new config - foreach ($oldConfig as $key => $value) { - if ($key != "v") { - $defaultConfig[$key] = $value; - } - } - - // create the output data - $configOutput = ""; - foreach ($defaultConfig as $key => $value) { - $configOutput .= $key." = \"".$value."\"\n"; - } - - // write out the new config file - file_put_contents($this->userConfigPath,$configOutput); - - return $defaultConfig; - - } - -} diff --git a/core/lib/PatternLab/Generator.php b/core/lib/PatternLab/Generator.php deleted file mode 100644 index 08e91ee74..000000000 --- a/core/lib/PatternLab/Generator.php +++ /dev/null @@ -1,161 +0,0 @@ -enableCSS = true; - - // initialize CSS rule saver - $this->initializeCSSRuleSaver(); - print "CSS generation enabled. This could take a few seconds...\n"; - - } - - // gather up all of the data to be used in patterns - $this->gatherData(); - - // gather all of the various pattern info - $this->gatherPatternInfo(); - - // clean the public directory to remove old files - if ($this->cleanPublic == "true") { - $this->cleanPublic(); - } - - // render out the patterns and move them to public/patterns - $this->generatePatterns(); - - // render out the index and style guide - $this->generateMainPages(); - - // iterate over the data files and regenerate the entire site if they've changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_data/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace($this->sd."/_data".DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - - } - - // iterate over all of the other files in the source directory - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd.DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && (!in_array($object->getExtension(),$this->ie)) && (!in_array($object->getFilename(),$this->id))) { - - // catch directories that have the ignored dir in their path - $ignoreDir = $this->ignoreDir($fileName); - - // check to see if it's a new directory - if (!$ignoreDir && $object->isDir() && !is_dir($this->pd."/".$fileName)) { - mkdir($this->pd."/".$fileName); - } - - // check to see if it's a new file or a file that has changed - if (!$ignoreDir && $object->isFile() && (!file_exists($this->pd."/".$fileName))) { - $this->moveStaticFile($fileName); - } - - } - - } - - // update the change time so the auto-reload will fire (doesn't work for the index and style guide) - $this->updateChangeTime(); - - print "your site has been generated...\n"; - - // print out how long it took to generate the site - if ($timePL) { - $mtime = microtime(); - $mtime = explode(" ",$mtime); - $mtime = $mtime[1] + $mtime[0]; - $endtime = $mtime; - $totaltime = ($endtime - $starttime); - $mem = round((memory_get_peak_usage(true)/1024)/1024,2); - print "site generation took ".$totaltime." seconds and used ".$mem."MB of memory...\n"; - } - - } - - /** - * Randomly prints a saying after the generate is complete - */ - public function printSaying() { - - $randomNumber = rand(0,60); - $sayings = array( - "have fun storming the castle", - "be well, do good work, and keep in touch", - "may the sun shine, all day long", - "smile", - "namaste", - "walk as if you are kissing the earth with your feet", - "to be beautiful means to be yourself", - "i was thinking of the immortal words of socrates, who said \"...i drank what?\"", - "let me take this moment to compliment you on your fashion sense, particularly your slippers", - "42", - "he who controls the spice controls the universe", - "the greatest thing you'll ever learn is just to love and be loved in return", - "nice wand", - "i don't have time for a grudge match with every poseur in a parka" - ); - if (isset($sayings[$randomNumber])) { - print $sayings[$randomNumber]."...\n"; - } - - } - -} \ No newline at end of file diff --git a/core/lib/PatternLab/Migrator.php b/core/lib/PatternLab/Migrator.php deleted file mode 100644 index 0437b5eba..000000000 --- a/core/lib/PatternLab/Migrator.php +++ /dev/null @@ -1,136 +0,0 @@ -getFilename(); - - if (!$migration->isDot() && $migration->isFile() && ($filename[0] != "_")) { - - $basePath = __DIR__."/../../../"; - $migrationData = json_decode(file_get_contents($migration->getPathname())); - $checkType = $migrationData->checkType; - $sourcePath = ($checkType == "fileExists") ? $basePath.$migrationData->sourcePath : $basePath.$migrationData->sourcePath.DIRECTORY_SEPARATOR; - $destinationPath = ($checkType == "fileExists") ? $basePath.$migrationData->destinationPath : $basePath.$migrationData->destinationPath.DIRECTORY_SEPARATOR; - - if ($checkType == "dirEmpty") { - - $emptyDir = true; - $objects = new \DirectoryIterator($destinationPath); - foreach ($objects as $object) { - if (!$object->isDot() && ($object->getFilename() != "README") && ($object->getFilename() != ".DS_Store")) { - $emptyDir = false; - } - } - - if ($emptyDir) { - $this->runMigration($filename, $sourcePath, $destinationPath, false); - } - - } else if ($checkType == "dirExists") { - - if (!is_dir($destinationPath)) { - mkdir($destinationPath); - $this->runMigration($filename, $sourcePath, $destinationPath, false); - } - - } else if ($checkType == "fileExists") { - - if (!file_exists($destinationPath)) { - $this->runMigration($filename, $sourcePath, $destinationPath, true); - } - - } else if (($checkType == "versionDiffDir") && $diffVersion) { - - $this->runMigration($filename, $sourcePath, $destinationPath, false); - - } else if (($checkType == "versionDiffFile") && $diffVersion) { - - $this->runMigration($filename, $sourcePath, $destinationPath, true); - - } else { - - print "Pattern Lab doesn't recognize a checkType of ".$checkType.". The migrator class is pretty thin at the moment.\n"; - exit; - - } - - } - - } - - } - - /** - * Run any migrations found in core/migrations that match the approved types - * @param {String} the filename of the migration - * @param {String} the path of the source directory - * @param {String} the path to the destination - * @param {Boolean} moving a single file or a directory - */ - protected function runMigration($filename, $sourcePath, $destinationPath, $singleFile) { - - $filename = str_replace(".json","",$filename); - print " Starting the ".$filename." migration...\n"; - - if ($singleFile) { - - copy($sourcePath.$fileName,$destinationPath.$fileName); - - } else { - - // iterate over all of the other files in the source directory and move them if their modified time has changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($sourcePath), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach ($objects as $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($sourcePath,"",$object->getPathname()); - - // check to see if it's a new directory - if ($object->isDir() && !is_dir($destinationPath.$fileName)) { - mkdir($destinationPath.$fileName); - } else if ($object->isFile()) { - copy($sourcePath.$fileName,$destinationPath.$fileName); - } - - } - - } - - print " Completed the ".$filename." migration...\n"; - - } - -} diff --git a/core/lib/PatternLab/Watcher.php b/core/lib/PatternLab/Watcher.php deleted file mode 100644 index df3ba0cfe..000000000 --- a/core/lib/PatternLab/Watcher.php +++ /dev/null @@ -1,258 +0,0 @@ -patterns = new \stdClass(); - - print "watching your site for changes...\n"; - - // run forever - while (true) { - - // clone the patterns so they can be checked in case something gets deleted - $cp = clone $o->patterns; - - // iterate over the patterns & related data and regenerate the entire site if they've changed - $patternObjects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_patterns/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $patternObjects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($patternObjects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd."/_patterns".DIRECTORY_SEPARATOR,"",$name); - $fileNameClean = str_replace(DIRECTORY_SEPARATOR."_",DIRECTORY_SEPARATOR,$fileName); - - if ($object->isFile() && (($object->getExtension() == "mustache") || ($object->getExtension() == "json"))) { - - // make sure this isn't a hidden pattern - $patternParts = explode(DIRECTORY_SEPARATOR,$fileName); - $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; - - - // make sure the pattern still exists in source just in case it's been deleted during the iteration - if (file_exists($name)) { - - $mt = $object->getMTime(); - if (isset($o->patterns->$fileName) && ($o->patterns->$fileName != $mt)) { - $o->patterns->$fileName = $mt; - $this->updateSite($fileName,"changed"); - } else if (!isset($o->patterns->$fileName) && $c) { - $o->patterns->$fileName = $mt; - $this->updateSite($fileName,"added"); - if ($object->getExtension() == "mustache") { - $patternSrcPath = str_replace(".mustache","",$fileName); - $patternDestPath = str_replace("/","-",$patternSrcPath); - $render = ($pattern[0] != "_") ? true : false; - $this->patternPaths[$patternParts[0]][$pattern] = array("patternSrcPath" => $patternSrcPath, "patternDestPath" => $patternDestPath, "render" => $render); - } - } else if (!isset($o->patterns->$fileName)) { - $o->patterns->$fileName = $mt; - } - - if ($c && isset($o->patterns->$fileName)) { - unset($cp->$fileName); - } - - } else { - - // the file was removed during the iteration so remove references to the item - unset($o->patterns->$fileName); - unset($cp->$fileName); - unset($this->patternPaths[$patternParts[0]][$pattern]); - $this->updateSite($fileName,"removed"); - - } - - } - - } - - // make sure old entries are deleted - // will throw "pattern not found" errors if an entire directory is removed at once but that shouldn't be a big deal - if ($c) { - - foreach($cp as $fileName => $mt) { - - unset($o->patterns->$fileName); - $patternParts = explode(DIRECTORY_SEPARATOR,$fileName); - $pattern = isset($patternParts[2]) ? $patternParts[2] : $patternParts[1]; - - unset($this->patternPaths[$patternParts[0]][$pattern]); - $this->updateSite($fileName,"removed"); - - } - - } - - // iterate over the data files and regenerate the entire site if they've changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/_data/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - $fileName = str_replace($this->sd."/_data".DIRECTORY_SEPARATOR,"",$name); - $mt = $object->getMTime(); - - if (!isset($o->$fileName)) { - $o->$fileName = $mt; - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - } else if ($o->$fileName != $mt) { - $o->$fileName = $mt; - $this->updateSite($fileName,"changed"); - if (($fileName[0] != "_") && $object->isFile()) { - $this->moveStaticFile("_data/".$fileName,"","_data","data"); - } - } - - } - - // iterate over all of the other files in the source directory and move them if their modified time has changed - $objects = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->sd."/"), \RecursiveIteratorIterator::SELF_FIRST); - - // make sure dots are skipped - $objects->setFlags(\FilesystemIterator::SKIP_DOTS); - - foreach($objects as $name => $object) { - - // clean-up the file name and make sure it's not one of the pattern lab files or to be ignored - $fileName = str_replace($this->sd.DIRECTORY_SEPARATOR,"",$name); - if (($fileName[0] != "_") && (!in_array($object->getExtension(),$this->ie)) && (!in_array($object->getFilename(),$this->id))) { - - // catch directories that have the ignored dir in their path - $ignoreDir = $this->ignoreDir($fileName); - - // check to see if it's a new directory - if (!$ignoreDir && $object->isDir() && !isset($o->$fileName) && !is_dir($this->pd."/".$fileName)) { - mkdir($this->pd."/".$fileName); - $o->$fileName = "dir created"; // placeholder - print $fileName."/ directory was created...\n"; - } - - // check to see if it's a new file or a file that has changed - if (file_exists($name)) { - - $mt = $object->getMTime(); - if (!$ignoreDir && $object->isFile() && !isset($o->$fileName) && !file_exists($this->pd."/".$fileName)) { - $o->$fileName = $mt; - $this->moveStaticFile($fileName,"added"); - if ($object->getExtension() == "css") { - $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons - } - } else if (!$ignoreDir && $object->isFile() && isset($o->$fileName) && ($o->$fileName != $mt)) { - $o->$fileName = $mt; - $this->moveStaticFile($fileName,"changed"); - if ($object->getExtension() == "css") { - $this->updateSite($fileName,"changed",0); // make sure the site is updated for MQ reasons - } - } else if (!isset($o->fileName)) { - $o->$fileName = $mt; - } - - } else { - unset($o->$fileName); - } - - } - - } - - $c = true; - - // taking out the garbage. basically killing mustache after each run. - unset($this->mpl); - unset($this->msf); - unset($this->mv); - if (gc_enabled()) gc_collect_cycles(); - - // output anything the reload server might send our way - if ($reload) { - $output = fgets($fp, 100); - if ($output != "\n") print $output; - } - - // pause for .05 seconds to give the CPU a rest - usleep(50000); - - } - - // close the auto-reload process, this shouldn't do anything - fclose($fp); - - } - - /** - * Updates the Pattern Lab Website and prints the appropriate message - * @param {String} file name to included in the message - * @param {String} a switch for decided which message isn't printed - * - * @return {String} the final message - */ - private function updateSite($fileName,$message,$verbose = true) { - $this->gatherData(); - $this->gatherPatternInfo(); - $this->generatePatterns(); - $this->generateViewAllPages(); - $this->updateChangeTime(); - $this->generateMainPages(); - if ($verbose) { - if ($message == "added") { - print $fileName." was added to Pattern Lab. Reload the website to see this change in the navigation...\n"; - } elseif ($message == "removed") { - print $fileName." was removed from Pattern Lab. Reload the website to see this change reflected in the navigation...\n"; - } elseif ($message == "hidden") { - print $fileName." was hidden from Pattern Lab. Reload the website to see this change reflected in the navigation...\n"; - } else { - print $fileName." changed...\n"; - } - } - } - -} diff --git a/core/lib/SplClassLoader.php b/core/lib/SplClassLoader.php deleted file mode 100644 index 2bc31f04b..000000000 --- a/core/lib/SplClassLoader.php +++ /dev/null @@ -1,136 +0,0 @@ -register(); - * - * @author Jonathan H. Wage - * @author Roman S. Borschel - * @author Matthew Weier O'Phinney - * @author Kris Wallsmith - * @author Fabien Potencier - */ -class SplClassLoader -{ - private $_fileExtension = '.php'; - private $_namespace; - private $_includePath; - private $_namespaceSeparator = '\\'; - - /** - * Creates a new SplClassLoader that loads classes of the - * specified namespace. - * - * @param string $ns The namespace to use. - */ - public function __construct($ns = null, $includePath = null) - { - $this->_namespace = $ns; - $this->_includePath = $includePath; - } - - /** - * Sets the namespace separator used by classes in the namespace of this class loader. - * - * @param string $sep The separator to use. - */ - public function setNamespaceSeparator($sep) - { - $this->_namespaceSeparator = $sep; - } - - /** - * Gets the namespace seperator used by classes in the namespace of this class loader. - * - * @return void - */ - public function getNamespaceSeparator() - { - return $this->_namespaceSeparator; - } - - /** - * Sets the base include path for all class files in the namespace of this class loader. - * - * @param string $includePath - */ - public function setIncludePath($includePath) - { - $this->_includePath = $includePath; - } - - /** - * Gets the base include path for all class files in the namespace of this class loader. - * - * @return string $includePath - */ - public function getIncludePath() - { - return $this->_includePath; - } - - /** - * Sets the file extension of class files in the namespace of this class loader. - * - * @param string $fileExtension - */ - public function setFileExtension($fileExtension) - { - $this->_fileExtension = $fileExtension; - } - - /** - * Gets the file extension of class files in the namespace of this class loader. - * - * @return string $fileExtension - */ - public function getFileExtension() - { - return $this->_fileExtension; - } - - /** - * Installs this class loader on the SPL autoload stack. - */ - public function register() - { - spl_autoload_register(array($this, 'loadClass')); - } - - /** - * Uninstalls this class loader from the SPL autoloader stack. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $className The name of the class to load. - * @return void - */ - public function loadClass($className) - { - if (null === $this->_namespace || $this->_namespace.$this->_namespaceSeparator === substr($className, 0, strlen($this->_namespace.$this->_namespaceSeparator))) { - $fileName = ''; - $namespace = ''; - if (false !== ($lastNsPos = strripos($className, $this->_namespaceSeparator))) { - $namespace = substr($className, 0, $lastNsPos); - $className = substr($className, $lastNsPos + 1); - $fileName = str_replace($this->_namespaceSeparator, DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR; - } - $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . $this->_fileExtension; - - require ($this->_includePath !== null ? $this->_includePath . DIRECTORY_SEPARATOR : '') . $fileName; - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Application/Application.php b/core/lib/Wrench/Application/Application.php deleted file mode 100755 index 2132a8907..000000000 --- a/core/lib/Wrench/Application/Application.php +++ /dev/null @@ -1,34 +0,0 @@ -newlines = $newlines; - - if (file_exists(__DIR__."/../../../../public/latest-change.txt")) { - $this->savedTimestamp = file_get_contents(__DIR__."/../../../../public/latest-change.txt"); - } else { - $this->savedTimestamp = time(); - } - - } - - /** - * When a client connects add it to the list of connected clients - */ - public function onConnect($client) { - $id = $client->getId(); - $this->clients[$id] = $client; - } - - /** - * When a client disconnects remove it from the list of connected clients - */ - public function onDisconnect($client) { - $id = $client->getId(); - unset($this->clients[$id]); - } - - /** - * Dead function in this instance - */ - public function onData($data, $client) { - // function not in use - } - - /** - * Sends out a message once a second to all connected clients containing the contents of latest-change.txt - */ - public function onUpdate() { - - if (file_exists(__DIR__."/../../../../public/latest-change.txt")) { - $readTimestamp = file_get_contents(__DIR__."/../../../../public/latest-change.txt"); - if ($readTimestamp != $this->savedTimestamp) { - print "pattern lab updated. alerting connected browsers...\n"; - foreach ($this->clients as $sendto) { - $sendto->send($readTimestamp); - } - $this->savedTimestamp = $readTimestamp; - } else { - if ($this->newlines) print "\n"; - } - } - - } - -} diff --git a/core/lib/Wrench/Application/PageFollowApplication.php b/core/lib/Wrench/Application/PageFollowApplication.php deleted file mode 100644 index 9306b64e7..000000000 --- a/core/lib/Wrench/Application/PageFollowApplication.php +++ /dev/null @@ -1,71 +0,0 @@ -getId(); - $this->clients[$id] = $client; - if ($this->data != null) { - $client->send(json_encode($this->data)); - } - } - - /** - * When a client disconnects remove it from the list of connected clients - */ - public function onDisconnect($client) { - $id = $client->getId(); - unset($this->clients[$id]); - } - - /** - * When receiving a message from a client, strip it to avoid cross-domain issues and send it to all clients except the one who sent it - * Also store the address as the current address for any new clients that attach - */ - public function onData($data, $client) { - - $dataDecoded = json_decode($data); - - $dataDecoded->url = "/".$dataDecoded->url; - $dataEncoded = json_encode($dataDecoded); - $testId = $client->getId(); - foreach ($this->clients as $sendto) { - if ($testId != $sendto->getId()) { - $sendto->send($dataEncoded); - } - } - - $this->data = $dataDecoded; - - } - - /** - * Dead function in this instance - */ - public function onUpdate() { - // not using for this application - } - -} diff --git a/core/lib/Wrench/BasicServer.php b/core/lib/Wrench/BasicServer.php deleted file mode 100755 index 88578a055..000000000 --- a/core/lib/Wrench/BasicServer.php +++ /dev/null @@ -1,70 +0,0 @@ -configureRateLimiter(); - $this->configureOriginPolicy(); - } - - /** - * @see Wrench.Server::configure() - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'check_origin' => true, - 'allowed_origins' => array(), - 'origin_policy_class' => 'Wrench\Listener\OriginPolicy', - 'rate_limiter_class' => 'Wrench\Listener\RateLimiter' - ), $options); - - parent::configure($options); - } - - protected function configureRateLimiter() - { - $class = $this->options['rate_limiter_class']; - $this->rateLimiter = new $class(); - $this->rateLimiter->listen($this); - } - - /** - * Configures the origin policy - */ - protected function configureOriginPolicy() - { - $class = $this->options['origin_policy_class']; - $this->originPolicy = new $class($this->options['allowed_origins']); - - if ($this->options['check_origin']) { - $this->originPolicy->listen($this); - } - } - - /** - * Adds an allowed origin - * - * @param array $origin - */ - public function addAllowedOrigin($origin) - { - $this->originPolicy->addAllowedOrigin($origin); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Client.php b/core/lib/Wrench/Client.php deleted file mode 100755 index 87e8f11ba..000000000 --- a/core/lib/Wrench/Client.php +++ /dev/null @@ -1,265 +0,0 @@ - - */ - protected $received = array(); - - /** - * Constructor - * - * @param string $uri - * @param string $origin The origin to include in the handshake (required - * in later versions of the protocol) - * @param array $options (optional) Array of options - * - socket => Socket instance (otherwise created) - * - protocol => Protocol - */ - public function __construct($uri, $origin, array $options = array()) - { - parent::__construct($options); - - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('No URI specified'); - } - $this->uri = $uri; - - $origin = (string)$origin; - if (!$origin) { - throw new InvalidArgumentException('No origin specified'); - } - $this->origin = $origin; - - $this->protocol->validateUri($this->uri); - $this->protocol->validateOriginUri($this->origin); - - $this->configureSocket(); - $this->configurePayloadHandler(); - } - - /** - * Configure options - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'socket_class' => 'Wrench\\Socket\\ClientSocket', - 'on_data_callback' => null - ), $options); - - parent::configure($options); - } - - /** - * Configures the client socket - */ - protected function configureSocket() - { - $class = $this->options['socket_class']; - $this->socket = new $class($this->uri); - } - - /** - * Configures the payload handler - */ - protected function configurePayloadHandler() - { - $this->payloadHandler = new PayloadHandler(array($this, 'onData'), $this->options); - } - - /** - * Payload receiver - * - * Public because called from our PayloadHandler. Don't call us, we'll call - * you (via the on_data_callback option). - * - * @param Payload $payload - */ - public function onData(Payload $payload) - { - $this->received[] = $payload; - if (($callback = $this->options['on_data_callback'])) { - call_user_func($callback, $payload); - } - } - - /** - * Adds a request header to be included in the initial handshake - * - * For example, to include a Cookie header - * - * @param string $name - * @param string $value - * @return void - */ - public function addRequestHeader($name, $value) - { - $this->headers[$name] = $value; - } - - /** - * Sends data to the socket - * - * @param string $data - * @param string $type Payload type - * @param boolean $masked - * @return boolean Success - */ - public function sendData($data, $type = Protocol::TYPE_TEXT, $masked = true) - { - if (is_string($type) && isset(Protocol::$frameTypes[$type])) { - $type = Protocol::$frameTypes[$type]; - } - - $payload = $this->protocol->getPayload(); - - $payload->encode( - $data, - $type, - $masked - ); - - return $payload->sendToSocket($this->socket); - } - - /** - * Receives data sent by the server - * - * @param callable $callback - * @return array Payload received since the last call to receive() - */ - public function receive() - { - if (!$this->isConnected()) { - return false; - } - - $data = $this->socket->receive(); - - if (!$data) { - return $data; - } - - $old = $this->received; - $this->payloadHandler->handle($data); - return array_diff($this->received, $old); - } - - /** - * Connect to the Wrench server - * - * @return boolean Whether a new connection was made - */ - public function connect() - { - if ($this->isConnected()) { - return false; - } - - $this->socket->connect(); - - $key = $this->protocol->generateKey(); - $handshake = $this->protocol->getRequestHandshake( - $this->uri, - $key, - $this->origin, - $this->headers - ); - - $this->socket->send($handshake); - $response = $this->socket->receive(self::MAX_HANDSHAKE_RESPONSE); - return ($this->connected = - $this->protocol->validateResponseHandshake($response, $key)); - } - - /** - * Whether the client is currently connected - * - * @return boolean - */ - public function isConnected() - { - return $this->connected; - } - - /** - * @todo Bug: what if connect has been called twice. The first socket never - * gets closed. - */ - public function disconnect() - { - if ($this->socket) { - $this->socket->disconnect(); - } - $this->connected = false; - } - - -} diff --git a/core/lib/Wrench/Connection.php b/core/lib/Wrench/Connection.php deleted file mode 100755 index 2538fc739..000000000 --- a/core/lib/Wrench/Connection.php +++ /dev/null @@ -1,538 +0,0 @@ - 'value' - * - * @var array - */ - protected $queryParams = null; - - /** - * Connection ID - * - * @var string|null - */ - protected $id = null; - - /** - * @var PayloadHandler - */ - protected $payloadHandler; - - /** - * Constructor - * - * @param Server $server - * @param ServerClientSocket $socket - * @param array $options - * @throws InvalidArgumentException - */ - public function __construct( - ConnectionManager $manager, - ServerClientSocket $socket, - array $options = array() - ) { - $this->manager = $manager; - $this->socket = $socket; - - - parent::__construct($options); - - $this->configureClientInformation(); - $this->configurePayloadHandler(); - - $this->log('Connected'); - } - - /** - * Gets the connection manager of this connection - * - * @return \Wrench\ConnectionManager - */ - public function getConnectionManager() - { - return $this->manager; - } - - /** - * @see Wrench\Util.Configurable::configure() - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connection_id_secret' => 'asu5gj656h64Da(0crt8pud%^WAYWW$u76dwb', - 'connection_id_algo' => 'sha512', - ), $options); - - parent::configure($options); - } - - protected function configurePayloadHandler() - { - $this->payloadHandler = new PayloadHandler( - array($this, 'handlePayload'), - $this->options - ); - } - - /** - * @throws RuntimeException - */ - protected function configureClientInformation() - { - $this->ip = $this->socket->getIp(); - $this->port = $this->socket->getPort(); - $this->configureClientId(); - } - - /** - * Configures the client ID - * - * We hash the client ID to prevent leakage of information if another client - * happens to get a hold of an ID. The secret *must* be lengthy, and must - * be kept secret for this to work: otherwise it's trivial to search the space - * of possible IP addresses/ports (well, if not trivial, at least very fast). - */ - protected function configureClientId() - { - $message = sprintf( - '%s:uri=%s&ip=%s&port=%s', - $this->options['connection_id_secret'], - rawurlencode($this->manager->getUri()), - rawurlencode($this->ip), - rawurlencode($this->port) - ); - - $algo = $this->options['connection_id_algo']; - - if (extension_loaded('gmp')) { - $hash = hash($algo, $message); - $hash = gmp_strval(gmp_init('0x' . $hash, 16), 62); - } else { - // @codeCoverageIgnoreStart - $hash = hash($algo, $message); - // @codeCoverageIgnoreEnd - } - - $this->id = $hash; - } - - /** - * Data receiver - * - * Called by the connection manager when the connection has received data - * - * @param string $data - */ - public function onData($data) - { - if (!$this->handshaked) { - return $this->handshake($data); - } - return $this->handle($data); - } - - /** - * Performs a websocket handshake - * - * @param string $data - * @throws BadRequestException - * @throws HandshakeException - * @throws WrenchException - */ - public function handshake($data) - { - try { - list($path, $origin, $key, $extensions, $protocol, $headers, $params) - = $this->protocol->validateRequestHandshake($data); - - $this->headers = $headers; - $this->queryParams = $params; - - $this->application = $this->manager->getApplicationForPath($path); - if (!$this->application) { - throw new BadRequestException('Invalid application'); - } - - $this->manager->getServer()->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($this, $path, $origin, $key, $extensions) - ); - - $response = $this->protocol->getResponseHandshake($key); - - if (!$this->socket->isConnected()) { - throw new HandshakeException('Socket is not connected'); - } - - if ($this->socket->send($response) === false) { - throw new HandshakeException('Could not send handshake response'); - } - - $this->handshaked = true; - - $this->log(sprintf( - 'Handshake successful: %s:%d (%s) connected to %s', - $this->getIp(), - $this->getPort(), - $this->getId(), - $path - ), 'info'); - - $this->manager->getServer()->notify( - Server::EVENT_HANDSHAKE_SUCCESSFUL, - array($this) - ); - - if (method_exists($this->application, 'onConnect')) { - $this->application->onConnect($this); - } - } catch (WrenchException $e) { - $this->log('Handshake failed: ' . $e, 'err'); - $this->close($e); - } - } - - /** - * Returns a string export of the given binary data - * - * @param string $data - * @return string - */ - protected function export($data) - { - $export = ''; - foreach (str_split($data) as $chr) { - $export .= '\\x' . ord($chr); - } - } - - /** - * Handle data received from the client - * - * The data passed in may belong to several different frames across one or - * more protocols. It may not even contain a single complete frame. This method - * manages slotting the data into separate payload objects. - * - * @todo An endpoint MUST be capable of handling control frames in the - * middle of a fragmented message. - * @param string $data - * @return void - */ - public function handle($data) - { - $this->payloadHandler->handle($data); - } - - /** - * Handle a complete payload received from the client - * - * Public because called from our PayloadHandler - * - * @param string $payload - */ - public function handlePayload(Payload $payload) - { - $app = $this->getClientApplication(); - - $this->log('Handling payload: ' . $payload->getPayload(), 'debug'); - - switch ($type = $payload->getType()) { - case Protocol::TYPE_TEXT: - if (method_exists($app, 'onData')) { - $app->onData($payload, $this); - } - return; - - case Protocol::TYPE_BINARY: - if(method_exists($app, 'onBinaryData')) { - $app->onBinaryData($payload, $this); - } else { - $this->close(1003); - } - break; - - case Protocol::TYPE_PING: - $this->log('Ping received', 'notice'); - $this->send($payload->getPayload(), Protocol::TYPE_PONG); - $this->log('Pong!', 'debug'); - break; - - /** - * A Pong frame MAY be sent unsolicited. This serves as a - * unidirectional heartbeat. A response to an unsolicited Pong - * frame is not expected. - */ - case Protocol::TYPE_PONG: - $this->log('Received unsolicited pong', 'info'); - break; - - case Protocol::TYPE_CLOSE: - $this->log('Close frame received', 'notice'); - $this->close(); - $this->log('Disconnected', 'info'); - break; - - default: - throw new ConnectionException('Unhandled payload type'); - } - } - - /** - * Sends the payload to the connection - * - * @param string $payload - * @param string $type - * @throws HandshakeException - * @throws ConnectionException - * @return boolean - */ - public function send($data, $type = Protocol::TYPE_TEXT) - { - if (!$this->handshaked) { - throw new HandshakeException('Connection is not handshaked'); - } - - $payload = $this->protocol->getPayload(); - - // Servers don't send masked payloads - $payload->encode($data, $type, false); - - if (!$payload->sendToSocket($this->socket)) { - $this->log('Could not send payload to client', 'warn'); - throw new ConnectionException('Could not send data to connection: ' . $this->socket->getLastError()); - } - - return true; - } - - /** - * Processes data on the socket - * - * @throws CloseException - */ - public function process() - { - $data = $this->socket->receive(); - $bytes = strlen($data); - - if ($bytes === 0 || $data === false) { - throw new CloseException('Error reading data from socket: ' . $this->socket->getLastError()); - } - - $this->onData($data); - } - - /** - * Closes the connection according to the WebSocket protocol - * - * If an endpoint receives a Close frame and that endpoint did not - * previously send a Close frame, the endpoint MUST send a Close frame - * in response. It SHOULD do so as soon as is practical. An endpoint - * MAY delay sending a close frame until its current message is sent - * (for instance, if the majority of a fragmented message is already - * sent, an endpoint MAY send the remaining fragments before sending a - * Close frame). However, there is no guarantee that the endpoint which - * has already sent a Close frame will continue to process data. - - * After both sending and receiving a close message, an endpoint - * considers the WebSocket connection closed, and MUST close the - * underlying TCP connection. The server MUST close the underlying TCP - * connection immediately; the client SHOULD wait for the server to - * close the connection but MAY close the connection at any time after - * sending and receiving a close message, e.g. if it has not received a - * TCP close from the server in a reasonable time period. - * - * @param int|Exception $statusCode - * @return boolean - */ - public function close($code = Protocol::CLOSE_NORMAL) - { - try { - if (!$this->handshaked) { - $response = $this->protocol->getResponseError($code); - $this->socket->send($response); - } else { - $response = $this->protocol->getCloseFrame($code); - $this->socket->send($response); - } - } catch (Exception $e) { - $this->log('Unable to send close message', 'warning'); - } - - if ($this->application && method_exists($this->application, 'onDisconnect')) { - $this->application->onDisconnect($this); - } - - $this->socket->disconnect(); - $this->manager->removeConnection($this); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->manager->log(sprintf( - '%s: %s:%d (%s): %s', - __CLASS__, - $this->getIp(), - $this->getPort(), - $this->getId(), - $message - ), $priority); - } - - /** - * Gets the IP address of the connection - * - * @return string Usually dotted quad notation - */ - public function getIp() - { - return $this->ip; - } - - /** - * Gets the port of the connection - * - * @return int - */ - public function getPort() - { - return $this->port; - } - - /** - * Gets the non-web-sockets headers included with the original request - * - * @return array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * Gets the query parameters included with the original request - * - * @return array - */ - public function getQueryParams() - { - return $this->queryParams; - } - - /** - * Gets the connection ID - * - * @return string - */ - public function getId() - { - return $this->id; - } - - /** - * Gets the socket object - * - * @return Socket\ServerClientSocket - */ - public function getSocket() - { - return $this->socket; - } - - /** - * Gets the client application - * - * @return Application - */ - public function getClientApplication() - { - return (isset($this->application)) ? $this->application : false; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/ConnectionManager.php b/core/lib/Wrench/ConnectionManager.php deleted file mode 100755 index 8a503de03..000000000 --- a/core/lib/Wrench/ConnectionManager.php +++ /dev/null @@ -1,332 +0,0 @@ - Connection> - */ - protected $connections = array(); - - /** - * An array of raw socket resources, corresponding to connections, roughly - * - * @var array resource> - */ - protected $resources = array(); - - /** - * Constructor - * - * @param Server $server - * @param array $options - */ - public function __construct(Server $server, array $options = array()) - { - $this->server = $server; - - parent::__construct($options); - } - - /** - * @see Countable::count() - */ - public function count() - { - return count($this->connections); - } - - /** - * @see Wrench\Socket.Socket::configure() - * Options include: - * - timeout_select => int, seconds, default 0 - * - timeout_select_microsec => int, microseconds (NB: not milli), default: 200000 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'socket_master_class' => 'Wrench\Socket\ServerSocket', - 'socket_master_options' => array(), - 'socket_client_class' => 'Wrench\Socket\ServerClientSocket', - 'socket_client_options' => array(), - 'connection_class' => 'Wrench\Connection', - 'connection_options' => array(), - 'timeout_select' => self::TIMEOUT_SELECT, - 'timeout_select_microsec' => self::TIMEOUT_SELECT_MICROSEC - ), $options); - - parent::configure($options); - - $this->configureMasterSocket(); - } - - /** - * Gets the application associated with the given path - * - * @param string $path - */ - public function getApplicationForPath($path) - { - $path = ltrim($path, '/'); - return $this->server->getApplication($path); - } - - /** - * Configures the main server socket - * - * @param string $uri - */ - protected function configureMasterSocket() - { - $class = $this->options['socket_master_class']; - $options = $this->options['socket_master_options']; - $this->socket = new $class($this->server->getUri(), $options); - } - - /** - * Listens on the main socket - * - * @return void - */ - public function listen() - { - $this->socket->listen(); - $this->resources[$this->socket->getResourceId()] = $this->socket->getResource(); - } - - /** - * Gets all resources - * - * @return array resource) - */ - protected function getAllResources() - { - return array_merge($this->resources, array( - $this->socket->getResourceId() => $this->socket->getResource() - )); - } - - /** - * Returns the Connection associated with the specified socket resource - * - * @param resource $socket - * @return Connection - */ - protected function getConnectionForClientSocket($socket) - { - if (!isset($this->connections[$this->resourceId($socket)])) { - return false; - } - return $this->connections[$this->resourceId($socket)]; - } - - /** - * Select and process an array of resources - * - * @param array $resources - */ - public function selectAndProcess() - { - $read = $this->resources; - $unused_write = null; - $unsued_exception = null; - - stream_select( - $read, - $unused_write, - $unused_exception, - $this->options['timeout_select'], - $this->options['timeout_select_microsec'] - ); - - foreach ($read as $socket) { - if ($socket == $this->socket->getResource()) { - $this->processMasterSocket(); - } else { - $this->processClientSocket($socket); - } - } - } - - /** - * Process events on the master socket ($this->socket) - * - * @return void - */ - protected function processMasterSocket() - { - $new = null; - - try { - $new = $this->socket->accept(); - } catch (Exception $e) { - $this->server->log('Socket error: ' . $e, 'err'); - return; - } - - $connection = $this->createConnection($new); - $this->server->notify(Server::EVENT_SOCKET_CONNECT, array($new, $connection)); - } - - /** - * Creates a connection from a socket resource - * - * The create connection object is based on the options passed into the - * constructor ('connection_class', 'connection_options'). This connection - * instance and its associated socket resource are then stored in the - * manager. - * - * @param resource $resource A socket resource - * @return Connection - */ - protected function createConnection($resource) - { - if (!$resource || !is_resource($resource)) { - throw new InvalidArgumentException('Invalid connection resource'); - } - - $socket_class = $this->options['socket_client_class']; - $socket_options = $this->options['socket_client_options']; - - $connection_class = $this->options['connection_class']; - $connection_options = $this->options['connection_options']; - - $socket = new $socket_class($resource, $socket_options); - $connection = new $connection_class($this, $socket, $connection_options); - - $id = $this->resourceId($resource); - $this->resources[$id] = $resource; - $this->connections[$id] = $connection; - - return $connection; - } - - /** - * Process events on a client socket - * - * @param resource $socket - */ - protected function processClientSocket($socket) - { - $connection = $this->getConnectionForClientSocket($socket); - - if (!$connection) { - $this->log('No connection for client socket', 'warning'); - return; - } - - try { - $connection->process(); - } catch (CloseException $e) { - $this->log('Client connection closed: ' . $e, 'notice'); - $connection->close($e); - } catch (WrenchException $e) { - $this->log('Error on client socket: ' . $e, 'warning'); - $connection->close($e); - } - } - - /** - * This server makes an explicit assumption: PHP resource types may be cast - * to a integer. Furthermore, we assume this is bijective. Both seem to be - * true in most circumstances, but may not be guaranteed. - * - * This method (and $this->getResourceId()) exist to make this assumption - * explicit. - * - * This is needed on the connection manager as well as on resources - * - * @param resource $resource - */ - protected function resourceId($resource) - { - return (int)$resource; - } - - /** - * Gets the connection manager's listening URI - * - * @return string - */ - public function getUri() - { - return $this->server->getUri(); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->server->log(sprintf( - '%s: %s', - __CLASS__, - $message - ), $priority); - } - - /** - * @return \Wrench\Server - */ - public function getServer() - { - return $this->server; - } - - /** - * Removes a connection - * - * @param Connection $connection - */ - public function removeConnection(Connection $connection) - { - $socket = $connection->getSocket(); - - if ($socket->getResource()) { - $index = $socket->getResourceId(); - } else { - $index = array_search($connection, $this->connections); - } - - if (!$index) { - $this->log('Could not remove connection: not found', 'warning'); - } - - unset($this->connections[$index]); - unset($this->resources[$index]); - - $this->server->notify( - Server::EVENT_SOCKET_DISCONNECT, - array($connection->getSocket(), $connection) - ); - } -} diff --git a/core/lib/Wrench/Exception/BadRequestException.php b/core/lib/Wrench/Exception/BadRequestException.php deleted file mode 100755 index 8b8a1591f..000000000 --- a/core/lib/Wrench/Exception/BadRequestException.php +++ /dev/null @@ -1,22 +0,0 @@ -buffer) { - return false; - } - - try { - return $this->getBufferLength() >= $this->getExpectedBufferLength(); - } catch (FrameException $e) { - return false; - } - } - - /** - * Receieves data into the frame - * - * @param string $buffer - */ - public function receiveData($data) - { - $this->buffer .= $data; - } - - /** - * Gets the remaining number of bytes before this frame will be complete - * - * @return number - */ - public function getRemainingData() - { - try { - return $this->getExpectedBufferLength() - $this->getBufferLength(); - } catch (FrameException $e) { - return null; - } - } - - /** - * Whether this frame is waiting for more data - * - * @return boolean - */ - public function isWaitingForData() - { - return $this->getRemainingData() > 0; - } - - /** - * Gets the contents of the frame payload - * - * The frame must be complete to call this method. - * - * @return string - */ - public function getFramePayload() - { - if (!$this->isComplete()) { - throw new FrameException('Cannot get payload: frame is not complete'); - } - - if (!$this->payload && $this->buffer) { - $this->decodeFramePayloadFromBuffer(); - } - - return $this->payload; - } - - /** - * Gets the contents of the frame buffer - * - * This is the encoded value, receieved into the frame with receiveData(). - * - * @throws FrameException - * @return string binary - */ - public function getFrameBuffer() - { - if (!$this->buffer && $this->payload) { - throw new FrameException('Cannot get frame buffer'); - } - return $this->buffer; - } - - /** - * Gets the expected length of the frame payload - * - * @return int - */ - protected function getBufferLength() - { - return strlen($this->buffer); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Frame/HybiFrame.php b/core/lib/Wrench/Frame/HybiFrame.php deleted file mode 100755 index da6377d7e..000000000 --- a/core/lib/Wrench/Frame/HybiFrame.php +++ /dev/null @@ -1,376 +0,0 @@ -= 0 - */ - public function encode($payload, $type = Protocol::TYPE_TEXT, $masked = false) - { - if (!is_int($type) || !in_array($type, Protocol::$frameTypes)) { - throw new InvalidArgumentException('Invalid frame type'); - } - - $this->type = $type; - $this->masked = $masked; - $this->payload = $payload; - $this->length = strlen($this->payload); - $this->offset_mask = null; - $this->offset_payload = null; - - $this->buffer = "\x00\x00"; - - $this->buffer[self::BYTE_HEADER] = chr( - (self::BITFIELD_TYPE & $this->type) - | (self::BITFIELD_FINAL & PHP_INT_MAX) - ); - - $masked_bit = (self::BITFIELD_MASKED & ($this->masked ? PHP_INT_MAX : 0)); - - if ($this->length <= 125) { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & $this->length) | $masked_bit - ); - } elseif ($this->length <= 65536) { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & 126) | $masked_bit - ); - $this->buffer .= pack('n', $this->length); - } else { - $this->buffer[self::BYTE_INITIAL_LENGTH] = chr( - (self::BITFIELD_INITIAL_LENGTH & 127) | $masked_bit - ); - - if (PHP_INT_MAX > 2147483647) { - $this->buffer .= pack('NN', $this->length >> 32, $this->length); - // $this->buffer .= pack('I', $this->length); - } else { - $this->buffer .= pack('NN', 0, $this->length); - } - } - - if ($this->masked) { - $this->mask = $this->generateMask(); - $this->buffer .= $this->mask; - $this->buffer .= $this->mask($this->payload); - } else { - $this->buffer .= $this->payload; - } - - $this->offset_mask = $this->getMaskOffset(); - $this->offset_payload = $this->getPayloadOffset(); - - return $this; - } - - /** - * Masks/Unmasks the frame - * - * @param string $payload - * @return string - */ - protected function mask($payload) - { - $length = strlen($payload); - $mask = $this->getMask(); - - $unmasked = ''; - for ($i = 0; $i < $length; $i++) { - $unmasked .= $payload[$i] ^ $mask[$i % 4]; - } - - return $unmasked; - } - - /** - * Masks a payload - * - * @param string $payload - * @return string - */ - protected function unmask($payload) - { - return $this->mask($payload); - } - - public function receiveData($data) - { - if ($this->getBufferLength() <= self::BYTE_INITIAL_LENGTH) { - $this->length = null; - $this->offset_payload = null; - } - parent::receiveData($data); - } - - /** - * Gets the mask - * - * @throws FrameException - * @return string - */ - protected function getMask() - { - if (!isset($this->mask)) { - if (!$this->isMasked()) { - throw new FrameException('Cannot get mask: frame is not masked'); - } - $this->mask = substr($this->buffer, $this->getMaskOffset(), $this->getMaskSize()); - } - return $this->mask; - } - - /** - * Generates a suitable masking key - * - * @return string - */ - protected function generateMask() - { - if (extension_loaded('openssl')) { - return openssl_random_pseudo_bytes(4); - } else { - // SHA1 is 128 bit (= 16 bytes) - // So we pack it into 32 bits - return pack('N', sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true)); - } - } - - /** - * Whether the frame is masked - * - * @return boolean - */ - public function isMasked() - { - if (!isset($this->masked)) { - if (!isset($this->buffer[1])) { - throw new FrameException('Cannot tell if frame is masked: not enough frame data received'); - } - $this->masked = (boolean)(ord($this->buffer[1]) & self::BITFIELD_MASKED); - } - return $this->masked; - } - - /** - * @see Wrench\Frame.Frame::getExpectedDataLength() - */ - protected function getExpectedBufferLength() - { - return $this->getLength() + $this->getPayloadOffset(); - } - - /** - * Gets the offset of the payload in the frame - * - * @return int - */ - protected function getPayloadOffset() - { - if (!isset($this->offset_payload)) { - $offset = $this->getMaskOffset(); - $offset += $this->getMaskSize(); - - $this->offset_payload = $offset; - } - return $this->offset_payload; - } - - /** - * Gets the offset in the frame to the masking bytes - * - * @return int - */ - protected function getMaskOffset() - { - if (!isset($this->offset_mask)) { - $offset = self::BYTE_INITIAL_LENGTH + 1; - $offset += $this->getLengthSize(); - - $this->offset_mask = $offset; - } - return $this->offset_mask; - } - - /** - * @see Wrench\Frame.Frame::getLength() - */ - public function getLength() - { - if (!$this->length) { - $initial = $this->getInitialLength(); - - if ($initial < 126) { - $this->length = $initial; - } elseif ($initial >= 126) { - // Extended payload length: 2 or 8 bytes - $start = self::BYTE_INITIAL_LENGTH + 1; - $end = self::BYTE_INITIAL_LENGTH + $this->getLengthSize(); - - if ($end > $this->getBufferLength()) { - throw new FrameException('Cannot get extended length: need more data'); - } - - $length = 0; - for ($i = $start; $i <= $end; $i++) { - $length <<= 8; - $length += ord($this->buffer[$i]); - } - - $this->length = $length; - } - } - return $this->length; - } - - /** - * Gets the inital length value, stored in the first length byte - * - * This determines how the rest of the length value is parsed out of the - * frame. - * - * @return int - */ - protected function getInitialLength() - { - if (!isset($this->buffer[self::BYTE_INITIAL_LENGTH])) { - throw new FrameException('Cannot yet tell expected length'); - } - $a = (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH); - - return (int)(ord($this->buffer[self::BYTE_INITIAL_LENGTH]) & self::BITFIELD_INITIAL_LENGTH); - } - - /** - * Returns the byte size of the length part of the frame - * - * Not including the initial 7 bit part - * - * @return int - */ - protected function getLengthSize() - { - $initial = $this->getInitialLength(); - - if ($initial < 126) { - return 0; - } elseif ($initial === 126) { - return 2; - } elseif ($initial === 127) { - return 8; - } - } - - /** - * Returns the byte size of the mask part of the frame - * - * @return int - */ - protected function getMaskSize() - { - if ($this->isMasked()) { - return 4; - } - return 0; - } - - /** - * @see Wrench\Frame.Frame::decodeFramePayloadFromBuffer() - */ - protected function decodeFramePayloadFromBuffer() - { - $payload = substr($this->buffer, $this->getPayloadOffset()); - - if ($this->isMasked()) { - $payload = $this->unmask($payload); - } - - $this->payload = $payload; - } - - /** - * @see Wrench\Frame.Frame::isFinal() - */ - public function isFinal() - { - if (!isset($this->buffer[self::BYTE_HEADER])) { - throw new FrameException('Cannot yet tell if frame is final'); - } - return (boolean)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_FINAL); - } - - /** - * @throws FrameException - * @see Wrench\Frame.Frame::getType() - */ - public function getType() - { - if (!isset($this->buffer[self::BYTE_HEADER])) { - throw new FrameException('Cannot yet tell type of frame'); - } - - $type = (int)(ord($this->buffer[self::BYTE_HEADER]) & self::BITFIELD_TYPE); - - if (!in_array($type, Protocol::$frameTypes)) { - throw new FrameException('Invalid payload type'); - } - - return $type; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Listener/HandshakeRequestListener.php b/core/lib/Wrench/Listener/HandshakeRequestListener.php deleted file mode 100755 index 9b5b841ee..000000000 --- a/core/lib/Wrench/Listener/HandshakeRequestListener.php +++ /dev/null @@ -1,19 +0,0 @@ -allowed = $allowed; - } - - /** - * Handshake request listener - * - * Closes the connection on handshake from an origin that isn't allowed - * - * @param Connection $connection - * @param string $path - * @param string $origin - * @param string $key - * @param array $extensions - */ - public function onHandshakeRequest(Connection $connection, $path, $origin, $key, $extensions) - { - if (!$this->isAllowed($origin)) { - $connection->close(new InvalidOriginException('Origin not allowed')); - } - } - - /** - * Whether the specified origin is allowed under this policy - * - * @param string $origin - * @return boolean - */ - public function isAllowed($origin) - { - $scheme = parse_url($origin, PHP_URL_SCHEME); - $host = parse_url($origin, PHP_URL_HOST) ?: $origin; - - foreach ($this->allowed as $allowed) { - $allowed_scheme = parse_url($allowed, PHP_URL_SCHEME); - - if ($allowed_scheme && $scheme != $allowed_scheme) { - continue; - } - - $allowed_host = parse_url($allowed, PHP_URL_HOST) ?: $allowed; - - if ($host != $allowed_host) { - continue; - } - - return true; - } - - return false; - } - - /** - * @param Server $server - */ - public function listen(Server $server) - { - $server->addListener( - Server::EVENT_HANDSHAKE_REQUEST, - array($this, 'onHandshakeRequest') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Listener/RateLimiter.php b/core/lib/Wrench/Listener/RateLimiter.php deleted file mode 100755 index 6ca0fe86e..000000000 --- a/core/lib/Wrench/Listener/RateLimiter.php +++ /dev/null @@ -1,230 +0,0 @@ - - */ - protected $ips = array(); - - /** - * Request tokens per IP address - * - * @var array> - */ - protected $requests = array(); - - /** - * Constructor - * - * @param array $options - */ - public function __construct(array $options = array()) - { - parent::__construct($options); - } - - /** - * @param array $options - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connections' => 200, // Total - 'connections_per_ip' => 5, // At once - 'requests_per_minute' => 200 // Per connection - ), $options); - - parent::configure($options); - } - - /** - * @see Wrench\Listener.Listener::listen() - */ - public function listen(Server $server) - { - $this->server = $server; - - $server->addListener( - Server::EVENT_SOCKET_CONNECT, - array($this, 'onSocketConnect') - ); - - $server->addListener( - Server::EVENT_SOCKET_DISCONNECT, - array($this, 'onSocketDisconnect') - ); - - $server->addListener( - Server::EVENT_CLIENT_DATA, - array($this, 'onClientData') - ); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onSocketConnect($socket, $connection) - { - $this->checkConnections($connection); - $this->checkConnectionsPerIp($connection); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onSocketDisconnect($socket, $connection) - { - $this->releaseConnection($connection); - } - - /** - * Event listener - * - * @param resource $socket - * @param Connection $connection - */ - public function onClientData($socket, $connection) - { - $this->checkRequestsPerMinute($connection); - } - - /** - * Idempotent - * - * @param Connection $connection - */ - protected function checkConnections($connection) - { - $connections = $connection->getConnectionManager()->count(); - - if ($connections > $this->options['connections']) { - $this->limit($connection, 'Max connections'); - } - } - - /** - * NOT idempotent, call once per connection - * - * @param Connection $connection - */ - protected function checkConnectionsPerIp($connection) - { - $ip = $connection->getIp(); - - if (!$ip) { - $this->log('Cannot check connections per IP', 'warning'); - return; - } - - if (!isset($this->ips[$ip])) { - $this->ips[$ip] = 1; - } else { - $this->ips[$ip] = min( - $this->options['connections_per_ip'], - $this->ips[$ip] + 1 - ); - } - - if ($this->ips[$ip] > $this->options['connections_per_ip']) { - $this->limit($connection, 'Connections per IP'); - } - } - - /** - * NOT idempotent, call once per disconnection - * - * @param Connection $connection - */ - protected function releaseConnection($connection) - { - $ip = $connection->getIp(); - - if (!$ip) { - $this->log('Cannot release connection', 'warning'); - return; - } - - if (!isset($this->ips[$ip])) { - $this->ips[$ip] = 0; - } else { - $this->ips[$ip] = max(0, $this->ips[$ip] - 1); - } - - unset($this->requests[$connection->getId()]); - } - - /** - * NOT idempotent, call once per data - * - * @param Connection $connection - */ - protected function checkRequestsPerMinute($connection) - { - $id = $connection->getId(); - - if (!isset($this->requests[$id])) { - $this->requests[$id] = array(); - } - - // Add current token - $this->requests[$id][] = time(); - - // Expire old tokens - while (reset($this->requests[$id]) < time() - 60) { - array_shift($this->requests[$id]); - } - - if (count($this->requests[$id]) > $this->options['requests_per_minute']) { - $this->limit($connection, 'Requests per minute'); - } - } - - /** - * Limits the given connection - * - * @param Connection $connection - * @param string $limit Reason - */ - protected function limit($connection, $limit) - { - $this->log(sprintf( - 'Limiting connection %s: %s', - $connection->getIp(), - $limit - ), 'notice'); - - $connection->close(new RateLimiterException($limit)); - } - - /** - * Logger - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - $this->server->log('RateLimiter: ' . $message, $priority); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Payload/HybiPayload.php b/core/lib/Wrench/Payload/HybiPayload.php deleted file mode 100755 index 92d4821ab..000000000 --- a/core/lib/Wrench/Payload/HybiPayload.php +++ /dev/null @@ -1,22 +0,0 @@ - - */ - protected $frames = array(); - - /** - * Gets the current frame for the payload - * - * @return mixed - */ - protected function getCurrentFrame() - { - if (empty($this->frames)) { - array_push($this->frames, $this->getFrame()); - } - return end($this->frames); - } - - /** - * Gets the frame into which data should be receieved - * - * @throws PayloadException - * @return Frame - */ - protected function getReceivingFrame() - { - $current = $this->getCurrentFrame(); - - if ($current->isComplete()) { - if ($current->isFinal()) { - throw new PayloadException('Payload cannot receieve data: it is already complete'); - } else { - $current = array_push($this->frames, $this->getFrame()); - } - } - - return $current; - } - - /** - * Get a frame object - * - * @return Frame - */ - abstract protected function getFrame(); - - /** - * Whether the payload is complete - * - * @return boolean - */ - public function isComplete() - { - return $this->getCurrentFrame()->isComplete() && $this->getCurrentFrame()->isFinal(); - } - - /** - * Encodes a payload - * - * @param string $data - * @param int $type - * @param boolean $masked - * @return Payload - * @todo No splitting into multiple frames just yet - */ - public function encode($data, $type = Protocol::TYPE_TEXT, $masked = false) - { - $this->frames = array(); - - $frame = $this->getFrame(); - array_push($this->frames, $frame); - - $frame->encode($data, $type, $masked); - - return $this; - } - - /** - * Gets the number of remaining bytes before this payload will be - * complete - * - * May return 0 (no more bytes required) or null (unknown number of bytes - * required). - * - * @return number|NULL - */ - public function getRemainingData() - { - if ($this->isComplete()) { - return 0; - } - - try { - if ($this->getCurrentFrame()->isFinal()) { - return $this->getCurrentFrame()->getRemainingData(); - } - } catch (FrameException $e) { - return null; - } - - return null; - } - - /** - * Whether this payload is waiting for more data - * - * @return boolean - */ - public function isWaitingForData() - { - return $this->getRemainingData() > 0; - } - - /** - * @param Socket $socket - * @return boolean - */ - public function sendToSocket(Socket $socket) - { - $success = true; - foreach ($this->frames as $frame) { - $success = $success && ($socket->send($frame->getFrameBuffer()) !== false); - } - return $success; - } - - /** - * Receive raw data into the payload - * - * @param string $data - * @return void - */ - public function receiveData($data) - { - while ($data) { - $frame = $this->getReceivingFrame(); - - $size = strlen($data); - $remaining = $frame->getRemainingData(); - - if ($remaining === null) { - $chunk_size = 2; - } elseif ($remaining > 0) { - $chunk_size = $remaining; - } - - $chunk_size = min(strlen($data), $chunk_size); - $chunk = substr($data, 0, $chunk_size); - $data = substr($data, $chunk_size); - - $frame->receiveData($chunk); - } - } - - /** - * @return string - */ - public function getPayload() - { - $this->buffer = ''; - - foreach ($this->frames as $frame) { - $this->buffer .= $frame->getFramePayload(); - } - - return $this->buffer; - } - - /** - * @return string - */ - public function __toString() - { - try { - return $this->getPayload(); - } catch (\Exception $e) { - // __toString must not throw an exception - return ''; - } - } - - /** - * Gets the type of the payload - * - * The type of a payload is taken from its first frame - * - * @throws PayloadException - * @return int - */ - public function getType() - { - if (!isset($this->frames[0])) { - throw new PayloadException('Cannot tell payload type yet'); - } - return $this->frames[0]->getType(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Payload/PayloadHandler.php b/core/lib/Wrench/Payload/PayloadHandler.php deleted file mode 100755 index 2be036ff1..000000000 --- a/core/lib/Wrench/Payload/PayloadHandler.php +++ /dev/null @@ -1,110 +0,0 @@ -callback = $callback; - } - - /** - * Handles the raw socket data given - * - * @param string $data - */ - public function handle($data) - { - if (!$this->payload) { - $this->payload = $this->protocol->getPayload(); - } - - while ($data) { // Each iteration pulls off a single payload chunk - $size = strlen($data); - $remaining = $this->payload->getRemainingData(); - - // If we don't yet know how much data is remaining, read data into - // the payload in two byte chunks (the size of a WebSocket frame - // header to get the initial length) - // - // Then re-loop. For extended lengths, this will happen once or four - // times extra, as the extended length is read in. - if ($remaining === null) { - $chunk_size = 2; - } elseif ($remaining > 0) { - $chunk_size = $remaining; - } elseif ($remaining === 0) { - $chunk_size = 0; - } - - $chunk_size = min(strlen($data), $chunk_size); - $chunk = substr($data, 0, $chunk_size); - $data = substr($data, $chunk_size); - - $this->payload->receiveData($chunk); - - if ($remaining !== 0 && !$this->payload->isComplete()) { - continue; - } - - if ($this->payload->isComplete()) { - $this->emit($this->payload); - $this->payload = $this->protocol->getPayload(); - } else { - throw new PayloadException('Payload will not complete'); - } - } - } - - /** - * Get the current payload - * - * @return Payload - */ - public function getCurrent() - { - return $this->getPayloadHandler->getCurrent(); - } - - /** - * Emits a complete payload to the callback - * - * @param Payload $payload - */ - protected function emit(Payload $payload) - { - call_user_func($this->callback, $payload); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/Hybi10Protocol.php b/core/lib/Wrench/Protocol/Hybi10Protocol.php deleted file mode 100755 index 33cfe15e3..000000000 --- a/core/lib/Wrench/Protocol/Hybi10Protocol.php +++ /dev/null @@ -1,35 +0,0 @@ -= 10) { - return true; - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/HybiProtocol.php b/core/lib/Wrench/Protocol/HybiProtocol.php deleted file mode 100755 index 1d73c2fab..000000000 --- a/core/lib/Wrench/Protocol/HybiProtocol.php +++ /dev/null @@ -1,24 +0,0 @@ - - */ - protected static $schemes = array( - self::SCHEME_WEBSOCKET, - self::SCHEME_WEBSOCKET_SECURE, - self::SCHEME_UNDERLYING, - self::SCHEME_UNDERLYING_SECURE - ); - - /** - * Close status codes - * - * @var array string> - */ - public static $closeReasons = array( - self::CLOSE_NORMAL => 'normal close', - self::CLOSE_GOING_AWAY => 'going away', - self::CLOSE_PROTOCOL_ERROR => 'protocol error', - self::CLOSE_DATA_INVALID => 'data invalid', - self::CLOSE_DATA_INCONSISTENT => 'data inconsistent', - self::CLOSE_POLICY_VIOLATION => 'policy violation', - self::CLOSE_MESSAGE_TOO_BIG => 'message too big', - self::CLOSE_EXTENSION_NEEDED => 'extension needed', - self::CLOSE_UNEXPECTED => 'unexpected error', - self::CLOSE_RESERVED => null, // Don't use these! - self::CLOSE_RESERVED_NONE => null, - self::CLOSE_RESERVED_ABNORM => null, - self::CLOSE_RESERVED_TLS => null - ); - - /** - * Frame types - * - * @todo flip values and keys? - * @var array int> - */ - public static $frameTypes = array( - 'continuation' => self::TYPE_CONTINUATION, - 'text' => self::TYPE_TEXT, - 'binary' => self::TYPE_BINARY, - 'close' => self::TYPE_CLOSE, - 'ping' => self::TYPE_PING, - 'pong' => self::TYPE_PONG - ); - - /** - * HTTP errors - * - * @var array string> - */ - public static $httpResponses = array( - self::HTTP_SWITCHING_PROTOCOLS => 'Switching Protocols', - self::HTTP_BAD_REQUEST => 'Bad Request', - self::HTTP_UNAUTHORIZED => 'Unauthorized', - self::HTTP_FORBIDDEN => 'Forbidden', - self::HTTP_NOT_FOUND => 'Not Found', - self::HTTP_NOT_IMPLEMENTED => 'Not Implemented', - self::HTTP_RATE_LIMITED => 'Enhance Your Calm' - ); - - /** - * Gets a version number - * - * @return - */ - abstract public function getVersion(); - - /** - * Subclasses should implement this method and return a boolean to the given - * version string, as to whether they would like to accept requests from - * user agents that specify that version. - * - * @return boolean - */ - abstract public function acceptsVersion($version); - - /** - * Gets a payload instance, suitable for use in decoding/encoding protocol - * frames - * - * @return Payload - */ - abstract public function getPayload(); - - /** - * Generates a key suitable for use in the protocol - * - * This base implementation returns a 16-byte (128 bit) random key as a - * binary string. - * - * @return string - */ - public function generateKey() - { - if (extension_loaded('openssl')) { - $key = openssl_random_pseudo_bytes(16); - } else { - // SHA1 is 128 bit (= 16 bytes) - $key = sha1(spl_object_hash($this) . mt_rand(0, PHP_INT_MAX) . uniqid('', true), true); - } - - return base64_encode($key); - } - - /** - * Gets request handshake string - * - * The leading line from the client follows the Request-Line format. - * The leading line from the server follows the Status-Line format. The - * Request-Line and Status-Line productions are defined in [RFC2616]. - * - * An unordered set of header fields comes after the leading line in - * both cases. The meaning of these header fields is specified in - * Section 4 of this document. Additional header fields may also be - * present, such as cookies [RFC6265]. The format and parsing of - * headers is as defined in [RFC2616]. - * - * @param string $uri WebSocket URI, e.g. ws://example.org:8000/chat - * @param string $key 16 byte binary string key - * @param string $origin Origin of the request - * @return string - */ - public function getRequestHandshake( - $uri, - $key, - $origin, - array $headers = array() - ) { - if (!$uri || !$key || !$origin) { - throw new InvalidArgumentException('You must supply a URI, key and origin'); - } - - list($scheme, $host, $port, $path) = self::validateUri($uri); - - $handshake = array( - sprintf(self::REQUEST_LINE_FORMAT, $path) - ); - - $headers = array_merge( - $this->getDefaultRequestHeaders( - $host . ':' . $port, $key, $origin - ), - $headers - ); - - foreach ($headers as $name => $value) { - $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value); - } - return implode($handshake, "\r\n") . "\r\n\r\n"; - } - - /** - * Gets a handshake response body - * - * @param string $key - * @param array $headers - */ - public function getResponseHandshake($key, array $headers = array()) - { - $headers = array_merge( - $this->getSuccessResponseHeaders( - $key - ), - $headers - ); - - return $this->getHttpResponse(self::HTTP_SWITCHING_PROTOCOLS, $headers); - } - - /** - * Gets a response to an error in the handshake - * - * @param int|Exception $e Exception or HTTP error - * @param array $headers - */ - public function getResponseError($e, array $headers = array()) - { - $code = false; - - if ($e instanceof Exception) { - $code = $e->getCode(); - } elseif (is_numeric($e)) { - $code = (int)$e; - } - - if (!$code || $code < 400 || $code > 599) { - $code = self::HTTP_SERVER_ERROR; - } - - return $this->getHttpResponse($code, $headers); - } - - /** - * Gets an HTTP response - * - * @param int $status - * @param array $headers - */ - protected function getHttpResponse($status, array $headers = array()) - { - if (array_key_exists($status, self::$httpResponses)) { - $response = self::$httpResponses[$status]; - } else { - $response = self::$httpResponses[self::HTTP_NOT_IMPLEMENTED]; - } - - $handshake = array( - sprintf(self::RESPONSE_LINE_FORMAT, $status, $response) - ); - - foreach ($headers as $name => $value) { - $handshake[] = sprintf(self::HEADER_LINE_FORMAT, $name, $value); - } - - return implode($handshake, "\r\n") . "\r\n\r\n"; - } - - /** - * @todo better header handling - * @todo throw exception - * @param unknown_type $response - * @param unknown_type $key - * @return boolean - */ - public function validateResponseHandshake($response, $key) - { - if (!$response) { - return false; - } - - $headers = $this->getHeaders($response); - - if (!isset($headers[self::HEADER_ACCEPT])) { - throw new HandshakeException('No accept header receieved on handshake response'); - } - - $accept = $headers[self::HEADER_ACCEPT]; - - if (!$accept) { - throw new HandshakeException('Invalid accept header'); - } - - $expected = $this->getAcceptValue($key); - - preg_match('#Sec-WebSocket-Accept:\s(.*)$#mU', $response, $matches); - $keyAccept = trim($matches[1]); - - return ($keyAccept === $this->getEncodedHash($key)) ? true : false; - } - - /** - * Gets an encoded hash for a key - * - * @param string $key - * @return string - */ - public function getEncodedHash($key) - { - return base64_encode(pack('H*', sha1($key . self::MAGIC_GUID))); - } - - /** - * Validates a request handshake - * - * @param string $request - * @throws BadRequestException - */ - public function validateRequestHandshake( - $request - ) { - if (!$request) { - return false; - } - - list($request, $headers) = $this->getRequestHeaders($request); - // make a copy of the headers array to store all extra headers - $extraHeaders = $headers; - - // parse the resulting url to separate query parameters from the path - $url = parse_url($this->validateRequestLine($request)); - $path = isset($url['path']) ? $url['path'] : null; - $urlParams = array(); - if (isset($url['query'])) { - parse_str($url['query'], $urlParams); - } - - if (empty($headers[self::HEADER_ORIGIN])) { - throw new BadRequestException('No origin header'); - } else { - unset($extraHeaders[self::HEADER_ORIGIN]); - } - - $origin = $headers[self::HEADER_ORIGIN]; - - if (!isset($headers[self::HEADER_UPGRADE]) - || strtolower($headers[self::HEADER_UPGRADE]) != self::UPGRADE_VALUE - ) { - throw new BadRequestException('Invalid upgrade header'); - } else { - unset($extraHeaders[self::HEADER_UPGRADE]); - } - - if (!isset($headers[self::HEADER_CONNECTION]) - || stripos($headers[self::HEADER_CONNECTION], self::CONNECTION_VALUE) === false - ) { - throw new BadRequestException('Invalid connection header'); - } else { - unset($extraHeaders[self::HEADER_CONNECTION]); - } - - if (!isset($headers[self::HEADER_HOST])) { - // @todo Validate host == listening socket? Or would that break - // TCP proxies? - throw new BadRequestException('No host header'); - } else { - unset($extraHeaders[self::HEADER_HOST]); - } - - if (!isset($headers[self::HEADER_VERSION])) { - throw new BadRequestException('No version header received on handshake request'); - } - - if (!$this->acceptsVersion($headers[self::HEADER_VERSION])) { - throw new BadRequestException('Unsupported version: ' . $version); - } else { - unset($extraHeaders[self::HEADER_VERSION]); - } - - if (!isset($headers[self::HEADER_KEY])) { - throw new BadRequestException('No key header received'); - } - - $key = trim($headers[self::HEADER_KEY]); - - if (!$key) { - throw new BadRequestException('Invalid key'); - } else { - unset($extraHeaders[self::HEADER_KEY]); - } - - // Optional - $protocol = null; - if (isset($headers[self::HEADER_PROTOCOL])) { - $protocol = $headers[self::HEADER_PROTOCOL]; - unset($extraHeaders[self::HEADER_PROTOCOL]); - } - - $extensions = array(); - if (!empty($headers[self::HEADER_EXTENSIONS])) { - $extensions = $headers[self::HEADER_EXTENSIONS]; - if (is_scalar($extensions)) { - $extensions = array($extensions); - } - } - unset($extraHeaders[self::HEADER_EXTENSIONS]); - - return array($path, $origin, $key, $extensions, $protocol, $extraHeaders, $urlParams); - } - - /** - * Gets a suitable WebSocket close frame - * - * @param Exception|int $e - */ - public function getCloseFrame($e) - { - $code = false; - - if ($e instanceof Exception) { - $code = $e->getCode(); - } elseif (is_numeric($e)) { - $code = (int)$e; - } - - if (!$code || !key_exists($code, self::$closeReasons)) { - $code = self::CLOSE_UNEXPECTED; - } - - $body = pack('n', $code) . self::$closeReasons[$code]; - - $payload = $this->getPayload(); - return $payload->encode($body, self::TYPE_CLOSE); - } - - /** - * Validates a WebSocket URI - * - * @param string $uri - * @return array(string $scheme, string $host, int $port, string $path) - */ - public function validateUri($uri) - { - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($uri, PHP_URL_SCHEME); - $this->validateScheme($scheme); - - $host = parse_url($uri, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - $port = parse_url($uri, PHP_URL_PORT); - if (!$port) { - $port = $this->getPort($scheme); - } - - $path = parse_url($uri, PHP_URL_PATH); - if (!$path) { - throw new InvalidArgumentException('Invalid path'); - } - - return array($scheme, $host, $port, $path); - } - - /** - * Validates a socket URI - * - * @param string $uri - * @throws InvalidArgumentException - * @return array(string $scheme, string $host, string $port) - */ - public function validateSocketUri($uri) - { - $uri = (string)$uri; - if (!$uri) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($uri, PHP_URL_SCHEME); - $scheme = $this->validateScheme($scheme); - - $host = parse_url($uri, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - $port = parse_url($uri, PHP_URL_PORT); - if (!$port) { - $port = $this->getPort($scheme); - } - - return array($scheme, $host, $port); - } - - /** - * Validates an origin URI - * - * @param string $origin - * @throws InvalidArgumentException - * @return string - */ - public function validateOriginUri($origin) - { - $origin = (string)$origin; - if (!$origin) { - throw new InvalidArgumentException('Invalid URI'); - } - - $scheme = parse_url($origin, PHP_URL_SCHEME); - if (!$scheme) { - throw new InvalidArgumentException('Invalid scheme'); - } - - $host = parse_url($origin, PHP_URL_HOST); - if (!$host) { - throw new InvalidArgumentException("Invalid host"); - } - - return $origin; - } - - /** - * Validates a request line - * - * @param string $line - * @throws BadRequestException - */ - protected function validateRequestLine($line) - { - $matches = array(0 => null, 1 => null); - - if (!preg_match(self::REQUEST_LINE_REGEX, $line, $matches) || !$matches[1]) { - throw new BadRequestException('Invalid request line', 400); - } - - return $matches[1]; - } - - /** - * Gets the expected accept value for a handshake response - * - * Note that the protocol calls for the base64 encoded value to be hashed, - * not the original 16 byte random key. - * - * @see http://tools.ietf.org/html/rfc6455#section-4.2.2 - * @param string $key - */ - protected function getAcceptValue($encoded_key) - { - return base64_encode(sha1($encoded_key . self::MAGIC_GUID, true)); - } - - /** - * Gets the headers from a full response - * - * @param string $response - * @return array() - * @throws InvalidArgumentException - */ - protected function getHeaders($response, &$request_line = null) - { - $parts = explode("\r\n\r\n", $response, 2); - - if (count($parts) != 2) { - $parts = array($parts, ''); - } - - list($headers, $body) = $parts; - - $return = array(); - foreach (explode("\r\n", $headers) as $header) { - $parts = explode(': ', $header, 2); - if (count($parts) == 2) { - list($name, $value) = $parts; - if (!isset($return[$name])) { - $return[$name] = $value; - } else { - if (is_array($return[$name])) { - $return[$name][] = $value; - } else { - $return[$name] = array($return[$name], $value); - } - } - } - } - - return $return; - } - - /** - * Gets request headers - * - * @param string $response - * @return array> The request line, and an array of - * headers - * @throws InvalidArgumentException - */ - protected function getRequestHeaders($response) - { - $eol = stripos($response, "\r\n"); - - if ($eol === false) { - throw new InvalidArgumentException('Invalid request line'); - } - - $request = substr($response, 0, $eol); - $headers = $this->getHeaders(substr($response, $eol + 2)); - - return array($request, $headers); - } - - /** - * Validates a scheme - * - * @param string $scheme - * @return string Underlying scheme - * @throws InvalidArgumentException - */ - protected function validateScheme($scheme) - { - if (!$scheme) { - throw new InvalidArgumentException('No scheme specified'); - } - if (!in_array($scheme, self::$schemes)) { - throw new InvalidArgumentException( - 'Unknown socket scheme: ' . $scheme - ); - } - - if ($scheme == self::SCHEME_WEBSOCKET_SECURE) { - return self::SCHEME_UNDERLYING_SECURE; - } - return self::SCHEME_UNDERLYING; - } - - /** - * Gets the default request headers - * - * @param string $host - * @param string $key - * @param string $origin - * @param int $version - * @return multitype:unknown string NULL - */ - protected function getDefaultRequestHeaders($host, $key, $origin) - { - return array( - self::HEADER_HOST => $host, - self::HEADER_UPGRADE => self::UPGRADE_VALUE, - self::HEADER_CONNECTION => self::CONNECTION_VALUE, - self::HEADER_KEY => $key, - self::HEADER_ORIGIN => $origin, - self::HEADER_VERSION => $this->getVersion() - ); - } - - /** - * Gets the default response headers - * - * @param string $key - */ - protected function getSuccessResponseHeaders($key) - { - return array( - self::HEADER_UPGRADE => self::UPGRADE_VALUE, - self::HEADER_CONNECTION => self::CONNECTION_VALUE, - self::HEADER_ACCEPT => $this->getAcceptValue($key) - ); - } - - /** - * Gets the default port for a scheme - * - * By default, the WebSocket Protocol uses port 80 for regular WebSocket - * connections and port 443 for WebSocket connections tunneled over - * Transport Layer Security - * - * @param string $uri - * @return int - */ - protected function getPort($scheme) - { - if ($scheme == self::SCHEME_WEBSOCKET) { - return 80; - } elseif ($scheme == self::SCHEME_WEBSOCKET_SECURE) { - return 443; - } elseif ($scheme == self::SCHEME_UNDERLYING) { - return 80; - } elseif ($scheme == self::SCHEME_UNDERLYING_SECURE) { - return 443; - } else { - throw new InvalidArgumentException('Unknown websocket scheme'); - } - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Protocol/Rfc6455Protocol.php b/core/lib/Wrench/Protocol/Rfc6455Protocol.php deleted file mode 100755 index b0f5c5289..000000000 --- a/core/lib/Wrench/Protocol/Rfc6455Protocol.php +++ /dev/null @@ -1,36 +0,0 @@ - - * @author Simon Samtleben - * @author Dominic Scheirlinck - */ -class Server extends Configurable -{ - /**#@+ - * Events - * - * @var string - */ - const EVENT_SOCKET_CONNECT = 'socket_connect'; - const EVENT_SOCKET_DISCONNECT = 'socket_disconnect'; - const EVENT_HANDSHAKE_REQUEST = 'handshake_request'; - const EVENT_HANDSHAKE_SUCCESSFUL = 'handshake_successful'; - const EVENT_CLIENT_DATA = 'client_data'; - /**#@-*/ - - /** - * The URI of the server - * - * @var string - */ - protected $uri; - - /** - * Options - * - * @var array - */ - protected $options = array(); - - /** - * A logging callback - * - * The default callback simply prints to stdout. You can pass your own logger - * in the options array. It should take a string message and string priority - * as parameters. - * - * @var Closure - */ - protected $logger; - - /** - * Event listeners - * - * Add listeners using the addListener() method. - * - * @var array array> - */ - protected $listeners = array(); - - /** - * Connection manager - * - * @var ConnectionManager - */ - protected $connectionManager; - - /** - * Applications - * - * @var array Application> - */ - protected $applications = array(); - - /** - * Constructor - * - * @param string $uri Websocket URI, e.g. ws://localhost:8000/, path will - * be ignored - * @param array $options (optional) See configure - */ - public function __construct($uri, array $options = array()) - { - $this->uri = $uri; - - parent::__construct($options); - - $this->log('Server initialized', 'info'); - } - - /** - * Configure options - * - * Options include - * - socket_class => The socket class to use, defaults to ServerSocket - * - socket_options => An array of socket options - * - logger => Closure($message, $priority = 'info'), used - * for logging - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'connection_manager_class' => 'Wrench\ConnectionManager', - 'connection_manager_options' => array() - ), $options); - - parent::configure($options); - - $this->configureConnectionManager(); - $this->configureLogger(); - } - - /** - * Configures the logger - * - * @return void - */ - protected function configureLogger() - { - // Default logger - if (!isset($this->options['logger'])) { - $this->options['logger'] = function ($message, $priority = 'info') { - printf("%s: %s%s", $priority, $message, PHP_EOL); - }; - } - $this->setLogger($this->options['logger']); - } - - /** - * Configures the connection manager - * - * @return void - */ - protected function configureConnectionManager() - { - $class = $this->options['connection_manager_class']; - $options = $this->options['connection_manager_options']; - $this->connectionManager = new $class($this, $options); - } - - /** - * Gets the connection manager - * - * @return \Wrench\ConnectionManager - */ - public function getConnectionManager() - { - return $this->connectionManager; - } - - /** - * @return string - */ - public function getUri() - { - return $this->uri; - } - - /** - * Sets a logger - * - * @param Closure $logger - * @return void - */ - public function setLogger($logger) - { - if (!is_callable($logger)) { - throw new \InvalidArgumentException('Logger must be callable'); - } - $this->logger = $logger; - } - - /** - * Main server loop - * - * @return void This method does not return! - */ - public function run() - { - $this->connectionManager->listen(); - - while (true) { - /* - * If there's nothing changed on any of the sockets, the server - * will sleep and other processes will have a change to run. Control - * this behaviour with the timeout options. - */ - $this->connectionManager->selectAndProcess(); - - /* - * If the application wants to perform periodic operations or queries and push updates to clients based on the result then that logic can be implemented in the 'onUpdate' method. - */ - foreach($this->applications as $application) { - if(method_exists($application, 'onUpdate')) { - $application->onUpdate(); - } - } - } - } - - /** - * Logs a message to the server log - * - * The default logger simply prints the message to stdout. You can provide - * a logging closure. This is useful, for instance, if you've daemonized - * and closed STDOUT. - * - * @param string $message Message to display. - * @param string $type Type of message. - * @return void - */ - public function log($message, $priority = 'info') - { - call_user_func($this->logger, $message, $priority); - } - - /** - * Notifies listeners of an event - * - * @param string $event - * @param array $arguments Event arguments - * @return void - */ - public function notify($event, array $arguments = array()) - { - if (!isset($this->listeners[$event])) { - return; - } - - foreach ($this->listeners[$event] as $listener) { - call_user_func_array($listener, $arguments); - } - } - - /** - * Adds a listener - * - * Provide an event (see the Server::EVENT_* constants) and a callback - * closure. Some arguments may be provided to your callback, such as the - * connection the caused the event. - * - * @param string $event - * @param Closure $callback - * @return void - * @throws InvalidArgumentException - */ - public function addListener($event, $callback) - { - if (!isset($this->listeners[$event])) { - $this->listeners[$event] = array(); - } - - if (!is_callable($callback)) { - throw new InvalidArgumentException('Invalid listener'); - } - - $this->listeners[$event][] = $callback; - } - - /** - * Returns a server application. - * - * @param string $key Name of application. - * @return Application The application object. - */ - public function getApplication($key) - { - if (empty($key)) { - return false; - } - - if (array_key_exists($key, $this->applications)) { - return $this->applications[$key]; - } - - return false; - } - - /** - * Adds a new application object to the application storage. - * - * @param string $key Name of application. - * @param object $application The application object - * @return void - */ - public function registerApplication($key, $application) - { - $this->applications[$key] = $application; - } -} diff --git a/core/lib/Wrench/Socket/ClientSocket.php b/core/lib/Wrench/Socket/ClientSocket.php deleted file mode 100755 index 9f5fbe293..000000000 --- a/core/lib/Wrench/Socket/ClientSocket.php +++ /dev/null @@ -1,105 +0,0 @@ - int, seconds, default 2 - */ -class ClientSocket extends UriSocket -{ - /** - * Default connection timeout - * - * @var int seconds - */ - const TIMEOUT_CONNECT = 2; - - /** - * @see Wrench\Socket.Socket::configure() - * Options include: - * - ssl_verify_peer => boolean, whether to perform peer verification - * of SSL certificate used - * - ssl_allow_self_signed => boolean, whether ssl_verify_peer allows - * self-signed certs - * - timeout_connect => int, seconds, default 2 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'timeout_connect' => self::TIMEOUT_CONNECT, - 'ssl_verify_peer' => false, - 'ssl_allow_self_signed' => true - ), $options); - - parent::configure($options); - } - - /** - * Connects to the given socket - */ - public function connect() - { - if ($this->isConnected()) { - return true; - } - - $errno = null; - $errstr = null; - - $this->socket = stream_socket_client( - $this->getUri(), - $errno, - $errstr, - $this->options['timeout_connect'], - STREAM_CLIENT_CONNECT, - $this->getStreamContext() - ); - - if (!$this->socket) { - throw new \Wrench\Exception\ConnectionException(sprintf( - 'Could not connect to socket: %s (%d)', - $errstr, - $errno - )); - } - - stream_set_timeout($this->socket, $this->options['timeout_socket']); - - return ($this->connected = true); - } - - public function reconnect() - { - $this->disconnect(); - $this->connect(); - } - - /** - * @see Wrench\Socket.UriSocket::getSocketStreamContextOptions() - */ - protected function getSocketStreamContextOptions() - { - $options = array(); - return $options; - } - - /** - * @see Wrench\Socket.UriSocket::getSslStreamContextOptions() - */ - protected function getSslStreamContextOptions() - { - $options = array(); - - if ($this->options['ssl_verify_peer']) { - $options['verify_peer'] = true; - } - - if ($this->options['ssl_allow_self_signed']) { - $options['allow_self_signed'] = true; - } - - return $options; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/ServerClientSocket.php b/core/lib/Wrench/Socket/ServerClientSocket.php deleted file mode 100755 index 61583f6cc..000000000 --- a/core/lib/Wrench/Socket/ServerClientSocket.php +++ /dev/null @@ -1,25 +0,0 @@ -connect() or whatnot. - * - * @param resource $accepted_socket - * @param array $options - */ - public function __construct($accepted_socket, array $options = array()) - { - parent::__construct($options); - - $this->socket = $accepted_socket; - $this->connected = (boolean)$accepted_socket; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/ServerSocket.php b/core/lib/Wrench/Socket/ServerSocket.php deleted file mode 100755 index facb89f86..000000000 --- a/core/lib/Wrench/Socket/ServerSocket.php +++ /dev/null @@ -1,126 +0,0 @@ - int, used to limit the number of outstanding - * connections in the socket's listen queue - * - ssl_cert_file => string, server SSL certificate - * file location. File should contain - * certificate and private key - * - ssl_passphrase => string, passphrase for the key - * - timeout_accept => int, seconds, default 5 - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'backlog' => 50, - 'ssl_cert_file' => null, - 'ssl_passphrase' => null, - 'ssl_allow_self_signed' => false, - 'timeout_accept' => self::TIMEOUT_ACCEPT - ), $options); - - parent::configure($options); - } - - /** - * Listens - * - * @throws ConnectionException - */ - public function listen() - { - $this->socket = stream_socket_server( - $this->getUri(), - $errno, - $errstr, - STREAM_SERVER_BIND|STREAM_SERVER_LISTEN. - $this->getStreamContext() - ); - - if (!$this->socket) { - throw new ConnectionException(sprintf( - 'Could not listen on socket: %s (%d)', - $errstr, - $errno - )); - } - - $this->listening = true; - } - - /** - * Accepts a new connection on the socket - * - * @throws ConnectionException - * @return resource - */ - public function accept() - { - $new = stream_socket_accept( - $this->socket, - $this->options['timeout_accept'] - ); - - if (!$new) { - throw new ConnectionException(socket_strerror(socket_last_error($new))); - } - - return $new; - } - - /** - * @see Wrench\Socket.UriSocket::getSocketStreamContextOptions() - */ - protected function getSocketStreamContextOptions() - { - $options = array(); - - if ($this->options['backlog']) { - $options['backlog'] = $this->options['backlog']; - } - - return $options; - } - - /** - * @see Wrench\Socket.UriSocket::getSslStreamContextOptions() - */ - protected function getSslStreamContextOptions() - { - $options = array(); - - if ($this->options['server_ssl_cert_file']) { - $options['local_cert'] = $this->options['server_ssl_cert_file']; - if ($this->options['server_ssl_passphrase']) { - $options['passphrase'] = $this->options['server_ssl_passphrase']; - } - } - - return $options; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/Socket.php b/core/lib/Wrench/Socket/Socket.php deleted file mode 100755 index 97f6b28cc..000000000 --- a/core/lib/Wrench/Socket/Socket.php +++ /dev/null @@ -1,322 +0,0 @@ - int, seconds, default 2 - * - timeout_socket => int, seconds, default 5 - * - * @param array $options - * @return void - */ - protected function configure(array $options) - { - $options = array_merge(array( - 'timeout_socket' => self::TIMEOUT_SOCKET, - ), $options); - - parent::configure($options); - } - - /** - * Gets the name of the socket - */ - protected function getName() - { - if (!isset($this->name) || !$this->name) { - $this->name = @stream_socket_get_name($this->socket, true); - } - return $this->name; - } - - /** - * Gets part of the name of the socket - * - * PHP seems to return IPV6 address/port combos like this: - * ::1:1234, where ::1 is the address and 1234 the port - * So, the part number here is either the last : delimited section (the port) - * or all the other sections (the whole initial part, the address). - * - * @param string $name (from $this->getName() usually) - * @param int<0, 1> $part - * @return string - * @throws SocketException - */ - public static function getNamePart($name, $part) - { - if (!$name) { - throw new InvalidArgumentException('Invalid name'); - } - - $parts = explode(':', $name); - - if (count($parts) < 2) { - throw new SocketException('Could not parse name parts: ' . $name); - } - - if ($part == self::NAME_PART_PORT) { - return end($parts); - } elseif ($part == self::NAME_PART_IP) { - return implode(':', array_slice($parts, 0, -1)); - } else { - throw new InvalidArgumentException('Invalid name part'); - } - - return null; - } - - /** - * Gets the IP address of the socket - * - * @return string - */ - public function getIp() - { - $name = $this->getName(); - - if ($name) { - return self::getNamePart($name, self::NAME_PART_IP); - } else { - throw new SocketException('Cannot get socket IP address'); - } - } - - /** - * Gets the port of the socket - * - * @return int - */ - public function getPort() - { - $name = $this->getName(); - - if ($name) { - return self::getNamePart($name, self::NAME_PART_PORT); - } else { - throw new SocketException('Cannot get socket IP address'); - } - } - - /** - * Get the last error that occurred on the socket - * - * @return int|string - */ - public function getLastError() - { - if ($this->isConnected() && $this->socket) { - $err = @socket_last_error($this->socket); - if ($err) { - $err = socket_strerror($err); - } - if (!$err) { - $err = 'Unknown error'; - } - return $err; - } else { - return 'Not connected'; - } - } - - /** - * Whether the socket is currently connected - * - * @return boolean - */ - public function isConnected() - { - return $this->connected; - } - - /** - * Disconnect the socket - * - * @return void - */ - public function disconnect() - { - if ($this->socket) { - stream_socket_shutdown($this->socket, STREAM_SHUT_RDWR); - } - $this->socket = null; - $this->connected = false; - } - - /** - * @see Wrench.Resource::getResource() - */ - public function getResource() - { - return $this->socket; - } - - /** - * @see Wrench.Resource::getResourceId() - */ - public function getResourceId() - { - return (int)$this->socket; - } - - /** - * @param unknown_type $data - * @throws SocketException - * @return boolean|int The number of bytes sent or false on error - */ - public function send($data) - { - if (!$this->isConnected()) { - throw new SocketException('Socket is not connected'); - } - - $length = strlen($data); - - if ($length == 0) { - return 0; - } - - for ($i = $length; $i > 0; $i -= $written) { - $written = @fwrite($this->socket, substr($data, -1 * $i)); - - if ($written === false) { - return false; - } elseif ($written === 0) { - return false; - } - } - - return $length; - } - - /** - * Receive data from the socket - * - * @param int $length - * @return string - */ - public function receive($length = self::DEFAULT_RECEIVE_LENGTH) - { - $remaining = $length; - - $buffer = ''; - $metadata['unread_bytes'] = 0; - - do { - if (feof($this->socket)) { - return $buffer; - } - - $result = fread($this->socket, $length); - - if ($result === false) { - return $buffer; - } - - $buffer .= $result; - - if (feof($this->socket)) { - return $buffer; - } - - $continue = false; - - if ($this->firstRead == true && strlen($result) == 1) { - // Workaround Chrome behavior (still needed?) - $continue = true; - } - $this->firstRead = false; - - if (strlen($result) == $length) { - $continue = true; - } - - // Continue if more data to be read - $metadata = stream_get_meta_data($this->socket); - if ($metadata && isset($metadata['unread_bytes']) && $metadata['unread_bytes']) { - $continue = true; - $length = $metadata['unread_bytes']; - } - } while ($continue); - - return $buffer; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Socket/UriSocket.php b/core/lib/Wrench/Socket/UriSocket.php deleted file mode 100755 index 8e1cbc047..000000000 --- a/core/lib/Wrench/Socket/UriSocket.php +++ /dev/null @@ -1,118 +0,0 @@ - Wrench\Protocol object, latest protocol - * version used if not specified - * - timeout_socket => int, seconds, default 5 - * - server_ssl_cert_file => string, server SSL certificate - * file location. File should contain - * certificate and private key - * - server_ssl_passphrase => string, passphrase for the key - * - server_ssl_allow_self_signed => boolean, whether to allows self- - * signed certs - */ - public function __construct($uri, array $options = array()) - { - parent::__construct($options); - - list($this->scheme, $this->host, $this->port) - = $this->protocol->validateSocketUri($uri); - } - - /** - * Gets the canonical/normalized URI for this socket - * - * @return string - */ - protected function getUri() - { - return sprintf( - '%s://%s:%d', - $this->scheme, - $this->host, - $this->port - ); - } - - /** - * @todo DNS lookup? Override getIp()? - * @see Wrench\Socket.Socket::getName() - */ - protected function getName() - { - return sprintf('%s:%s', $this->host, $this->port); - } - - /** - * Gets the host name - */ - public function getHost() - { - return $this->host; - } - - /** - * @see Wrench\Socket.Socket::getPort() - */ - public function getPort() - { - return $this->port; - } - - /** - * Gets a stream context - */ - protected function getStreamContext($listen = false) - { - $options = array(); - - if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE - || $this->scheme == Protocol::SCHEME_UNDERLYING) { - $options['socket'] = $this->getSocketStreamContextOptions(); - } - - if ($this->scheme == Protocol::SCHEME_UNDERLYING_SECURE) { - $options['ssl'] = $this->getSslStreamContextOptions(); - } - - return stream_context_create( - $options, - array() - ); - } - - /** - * Returns an array of socket stream context options - * - * See http://php.net/manual/en/context.socket.php - * - * @return array - */ - abstract protected function getSocketStreamContextOptions(); - - /** - * Returns an array of ssl stream context options - * - * See http://php.net/manual/en/context.ssl.php - * - * @return array - */ - abstract protected function getSslStreamContextOptions(); -} diff --git a/core/lib/Wrench/Tests/Application/EchoApplicationTest.php b/core/lib/Wrench/Tests/Application/EchoApplicationTest.php deleted file mode 100755 index bd32aeb33..000000000 --- a/core/lib/Wrench/Tests/Application/EchoApplicationTest.php +++ /dev/null @@ -1,57 +0,0 @@ -assertInstanceOfClass($this->getInstance()); - } - - /** - * @param unknown_type $payload - * @dataProvider getValidPayloads - */ - public function testOnData($payload) - { - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->once()) - ->method('send') - ->with($this->equalTo($payload), $this->equalTo(Protocol::TYPE_TEXT)) - ->will($this->returnValue(true)); - - $this->getInstance()->onData($payload, $connection); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidPayloads() - { - return array( - array('asdkllakdaowidoaw noaoinosdna nwodinado ndsnd aklndiownd'), - array(' ') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/BasicServerTest.php b/core/lib/Wrench/Tests/BasicServerTest.php deleted file mode 100755 index 20d004419..000000000 --- a/core/lib/Wrench/Tests/BasicServerTest.php +++ /dev/null @@ -1,119 +0,0 @@ -getInstance('ws://localhost:8000', array( - 'allowed_origins' => $allowed, - 'logger' => array($this, 'log') - )); - - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->never()) - ->method('close') - ->will($this->returnValue(true)); - - $server->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($connection, '', $origin, '', array()) - ); - } - - /** - * @param array $allowed - * @param string $origin - * @dataProvider getInvalidOrigins - */ - public function testInvalidOriginPolicy(array $allowed, $origin) - { - $server = $this->getInstance('ws://localhost:8000', array( - 'allowed_origins' => $allowed, - 'logger' => array($this, 'log') - )); - - $connection = $this->getMockBuilder('Wrench\Connection') - ->disableOriginalConstructor() - ->getMock(); - - $connection - ->expects($this->once()) - ->method('close') - ->will($this->returnValue(true)); - - $server->notify( - Server::EVENT_HANDSHAKE_REQUEST, - array($connection, '', $origin, '', array()) - ); - } - - /** - * @see Wrench\Tests.ServerTest::getValidConstructorArguments() - */ - public function getValidConstructorArguments() - { - return array_merge(parent::getValidConstructorArguments(), array( - array( - 'ws://localhost:8000', - array('logger' => function () {}) - ) - )); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidOrigins() - { - return array( - array(array('localhost'), 'localhost'), - array(array('somewhere.com'), 'somewhere.com'), - ); - } - - /** - * Data provider - * - * @return array> - */ - public function getInvalidOrigins() - { - return array( - array(array('localhost'), 'blah'), - array(array('somewhere.com'), 'somewhereelse.com'), - array(array('somewhere.com'), 'subdomain.somewhere.com') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ClientTest.php b/core/lib/Wrench/Tests/ClientTest.php deleted file mode 100755 index 824774eef..000000000 --- a/core/lib/Wrench/Tests/ClientTest.php +++ /dev/null @@ -1,173 +0,0 @@ -assertInstanceOfClass( - $client = new Client( - 'ws://localhost/test', 'http://example.org/' - ), - 'ws:// scheme, default socket' - ); - - $this->assertInstanceOfClass( - $client = new Client( - 'ws://localhost/test', 'http://example.org/', - array('socket' => $this->getMockSocket()) - ), - 'ws:// scheme, socket specified' - ); - } - - /** - * Gets a mock socket - * - * @return Socket - */ - protected function getMockSocket() - { - return $this->getMock('Wrench\Socket\ClientSocket', array(), array('wss://localhost:8000')); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorSocketUnspecified() - { - $w = new Client(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriInvalid() - { - $w = new Client('invalid uri', 'http://www.example.com/'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriEmpty() - { - $w = new Client(null, 'http://www.example.com/'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriPathUnspecified() - { - $w = new Client('ws://localhost', 'http://www.example.com/'); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorOriginUnspecified() - { - $w = new Client('ws://localhost'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorOriginEmpty() - { - $w = new Client('wss://localhost', null); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorOriginInvalid() - { - $w = new Client('ws://localhost:8000', 'NOTAVALIDURI'); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSendInvalidType() - { - $client = new Client('ws://localhost/test', 'http://example.org/'); - $client->sendData('blah', 9999); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testSendInvalidTypeString() - { - $client = new Client('ws://localhost/test', 'http://example.org/'); - $client->sendData('blah', 'fooey'); - } - - public function testSend() - { - try { - $helper = new ServerTestHelper(); - $helper->setUp(); - - /* @var $instance Wrench\Client */ - $instance = $this->getInstance($helper->getEchoConnectionString(), 'http://www.example.com/send'); - $instance->addRequestHeader('X-Test', 'Custom Request Header'); - - $this->assertFalse($instance->receive(), 'Receive before connect'); - - $success = $instance->connect(); - $this->assertTrue($success, 'Client can connect to test server'); - $this->assertTrue($instance->isConnected()); - - $this->assertFalse($instance->connect(), 'Double connect'); - - $this->assertFalse((boolean)$instance->receive(), 'No data'); - - $bytes = $instance->sendData('foobar', 'text'); - $this->assertTrue($bytes >= 6, 'sent text frame'); - sleep(1); - - $bytes = $instance->sendData('baz', Protocol::TYPE_TEXT); - $this->assertTrue($bytes >= 3, 'sent text frame'); - sleep(1); - - $responses = $instance->receive(); - $this->assertTrue(is_array($responses)); - $this->assertCount(2, $responses); - $this->assertInstanceOf('Wrench\\Payload\\Payload', $responses[0]); - $this->assertInstanceOf('Wrench\\Payload\\Payload', $responses[1]); - - $instance->disconnect(); - - $this->assertFalse($instance->isConnected()); - } catch (\Exception $e) { - $helper->tearDown(); - throw $e; - } - - $helper->tearDown(); - } -} diff --git a/core/lib/Wrench/Tests/ConnectionManagerTest.php b/core/lib/Wrench/Tests/ConnectionManagerTest.php deleted file mode 100755 index ed3de0b03..000000000 --- a/core/lib/Wrench/Tests/ConnectionManagerTest.php +++ /dev/null @@ -1,101 +0,0 @@ -assertInstanceOfClass( - $instance = $this->getInstance( - $server, - $options - ), - 'Valid constructor arguments' - ); - } - - /** - * Tests the constructor - */ - public function testConstructor() - { - $this->assertInstanceOfClass( - $instance = $this->getInstance( - $this->getMockServer(), - array() - ), - 'Constructor' - ); - return $instance; - } - - /** - * @depends testConstructor - * @param ConnectionManager $instance - */ - public function testCount($instance) - { - $this->assertTrue(is_numeric($instance->count())); - } - - /** - * Data provider - */ - public function getValidConstructorArguments() - { - return array( - array($this->getMockServer(), array()) - ); - } - - /** - * Gets a mock server - */ - protected function getMockServer() - { - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - - $server->registerApplication('/echo', $this->getMockApplication()); - - $server->expects($this->any()) - ->method('getUri') - ->will($this->returnValue('ws://localhost:8000/')); - - return $server; - } - - /** - * Gets a mock application - * - * @return EchoApplication - */ - protected function getMockApplication() - { - return new EchoApplication(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ConnectionTest.php b/core/lib/Wrench/Tests/ConnectionTest.php deleted file mode 100755 index 25d57ffbc..000000000 --- a/core/lib/Wrench/Tests/ConnectionTest.php +++ /dev/null @@ -1,386 +0,0 @@ -assertInstanceOfClass( - $instance = $this->getInstance( - $manager, - $socket, - $options - ), - 'Valid constructor arguments' - ); - - return $instance; - } - - /** - * @dataProvider getValidCloseCodes - */ - public function testClose($code) - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $socket->expects($this->any()) - ->method('getPort') - ->will($this->returnValue(mt_rand(1025, 50000))); - - $manager = $this->getMockConnectionManager(); - - $connection = $this->getInstance($manager, $socket); - $connection->close($code); - } - - /** - * @dataProvider getValidHandshakeData - */ - public function testHandshake($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - $connection->onData('somedata'); - $this->assertTrue($connection->send('someotherdata')); - return $connection; - } - - /** - * @dataProvider getValidHandshakeData - * @expectedException Wrench\Exception\HandshakeException - */ - public function testHandshakeBadSocket($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getNotConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - } - - /** - * Because expectation is that only $path application is available - * - * @dataProvider getWrongPathHandshakeData - * @expectedException PHPUnit_Framework_ExpectationFailedException - */ - public function testWrongPathHandshake($path, $request) - { - $connection = $this->getConnectionForHandshake( - $this->getConnectedSocket(), - $path, - $request - ); - $connection->handshake($request); - } - - /** - * @dataProvider getValidHandleData - */ - public function testHandle($path, $request_handshake, array $requests, array $counts) - { - $connection = $this->getConnectionForHandle( - $this->getConnectedSocket(), - $path, - $request_handshake, - $counts - ); - - $connection->handshake($request_handshake); - - foreach ($requests as $request) { - $connection->handle($request); - } - - return $connection; - } - - /** - * @return Socket - */ - protected function getConnectedSocket() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('isConnected') - ->will($this->returnValue(true)); - - return $socket; - } - - /** - * @return Socket - */ - protected function getNotConnectedSocket() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('isConnected') - ->will($this->returnValue(false)); - - return $socket; - } - - protected function getConnectionForHandshake($socket, $path, $request) - { - $manager = $this->getMockConnectionManager(); - - $application = $this->getMockApplication(); - - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - $server->registerApplication($path, $application); - - $manager->expects($this->any()) - ->method('getApplicationForPath') - ->with($path) - ->will($this->returnValue($application)); - - $manager->expects($this->any()) - ->method('getServer') - ->will($this->returnValue($server)); - - $connection = $this->getInstance($manager, $socket); - - return $connection; - } - - protected function getConnectionForHandle($socket, $path, $handshake, array $counts) - { - $connection = $this->getConnectionForHandshake($socket, $path, $handshake); - - $manager = $this->getMockConnectionManager(); - - $application = $this->getMockApplication(); - - $application->expects($this->exactly(isset($counts['onData']) ? $counts['onData'] : 0)) - ->method('onData') - ->will($this->returnValue(true)); - - $server = $this->getMock('Wrench\Server', array(), array(), '', false); - $server->registerApplication($path, $application); - - $manager->expects($this->any()) - ->method('getApplicationForPath') - ->with($path) - ->will($this->returnValue($application)); - - $manager->expects($this->exactly(isset($counts['removeConnection']) ? $counts['removeConnection'] : 0)) - ->method('removeConnection'); - - $manager->expects($this->any()) - ->method('getServer') - ->will($this->returnValue($server)); - - $connection = $this->getInstance($manager, $socket); - - return $connection; - } - - /** - * @return ConnectionManager - */ - protected function getMockConnectionManager() - { - return $this->getMock('Wrench\ConnectionManager', array(), array(), '', false); - } - - /** - * Gets a mock socket - * - * @return Socket - */ - protected function getMockSocket() - { - return $this->getMock('Wrench\Socket\ServerClientSocket', array(), array(), '', false); - } - - /** - * Gets a mock application - * - * @return EchoApplication - */ - protected function getMockApplication() - { - return $this->getMock('Wrench\Application\EchoApplication'); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidCloseCodes() - { - $arguments = array(); - foreach (Protocol::$closeReasons as $code => $reason) { - $arguments[] = array($code); - } - return $arguments; - } - - /** - * Data provider - * - * @return array> - */ - public function getValidConstructorArguments() - { - $socket = $this->getMockSocket(); - - $socket->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $socket->expects($this->any()) - ->method('getPort') - ->will($this->returnValue(mt_rand(1025, 50000))); - - $manager = $this->getMockConnectionManager(); - - return array( - array( - $manager, - $socket, - array('logger' => function() {}) - ), - array( - $manager, - $socket, - array('logger' => function () {}, - 'connection_id_algo' => 'sha512') - ) - ); - } - - /** - * Data provider - * - * Uses this awkward valid request array so that splitting of payloads - * across multiple calls to handle can be tested - * - * testHandle($path, $request_handshake, array $requests, array $counts) - */ - public function getValidHandleData() - { - $valid_requests = array( - array( - 'data' => array( - "\x81\xad\x2e\xab\x82\xac\x6f\xfe\xd6\xe4\x14\x8b\xf9\x8c\x0c" - ."\xde\xf1\xc9\x5c\xc5\xe3\xc1\x4b\x89\xb8\x8c\x0c\xcd\xed\xc3" - ."\x0c\x87\xa2\x8e\x5e\xca\xf1\xdf\x59\xc4\xf0\xc8\x0c\x91\xa2" - ."\x8e\x4c\xca\xf0\x8e\x53\x81\xad\xd4\xfd\x81\xfe\x95\xa8\xd5" - ."\xb6\xee\xdd\xfa\xde\xf6\x88\xf2\x9b\xa6\x93\xe0\x93\xb1\xdf" - ."\xbb\xde\xf6\x9b\xee\x91\xf6\xd1\xa1\xdc\xa4\x9c\xf2\x8d\xa3" - ."\x92\xf3\x9a\xf6\xc7\xa1\xdc\xb6\x9c\xf3\xdc\xa9\x81\x80\x8e" - ."\x12\xcd\x8e\x81\x8c\xf6\x8a\xf0\xee\x9a\xeb\x83\x9a\xd6\xe7" - ."\x95\x9d\x85\xeb\x97\x8b" // Four text frames - ), - 'counts' => array( - 'onData' => 4 - ) - ), - array( - 'data' => array( - "\x88\x80\xdc\x8e\xa2\xc5" // Close frame - ), - 'counts' => array( - 'removeConnection' => 1 - ) - ) - ); - - $data = array(); - - $handshakes = $this->getValidHandshakeData(); - - foreach ($handshakes as $handshake) { - foreach ($valid_requests as $handle_args) { - $arguments = $handshake; - $arguments[] = $handle_args['data']; - $arguments[] = $handle_args['counts']; - - $data[] = $arguments; - } - } - - return $data; - } - - /** - * Data provider - */ - public function getValidHandshakeData() - { - return array( - array( - '/chat', -"GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Version: 13\r\n\r\n" - ) - ); - } - - /** - * Data provider - */ - public function getWrongPathHandshakeData() - { - return array( - array( - '/foobar', -"GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Version: 13\r\n\r\n" - ), - ); - } -} diff --git a/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php b/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php deleted file mode 100755 index bcced6695..000000000 --- a/core/lib/Wrench/Tests/Frame/BaseSubclassFrameTest.php +++ /dev/null @@ -1,29 +0,0 @@ -getFrameBuffer(); - } - - protected function getClass() - { - return 'Wrench\Tests\Frame\BadSubclassFrame'; - } -} diff --git a/core/lib/Wrench/Tests/Frame/FrameTest.php b/core/lib/Wrench/Tests/Frame/FrameTest.php deleted file mode 100755 index 848c7103e..000000000 --- a/core/lib/Wrench/Tests/Frame/FrameTest.php +++ /dev/null @@ -1,168 +0,0 @@ -frame = $this->getNewFrame(); - } - - protected function getNewFrame() - { - $class = $this->getClass(); - return new $class(); - } - - /** - * @see PHPUnit_Framework_TestCase::tearDown() - */ - protected function tearDown() - { - parent::tearDown(); - unset($this->frame); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testBijection($type, $payload, $masked) - { - // Encode the payload - $this->frame->encode($payload, $type, $masked); - - // Get the resulting buffer - $buffer = $this->frame->getFrameBuffer(); - $this->assertTrue((boolean)$buffer, 'Got raw frame buffer'); - - // And feed it back into a new frame - $frame = $this->getNewFrame(); - $frame->receiveData($buffer); - - // Check the properties of the new frame against the old, all match - $this->assertEquals( - $this->frame->getType(), - $frame->getType(), - 'Types match after encode -> receiveData' - ); - - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData' - ); - - // Masking key should not be different, because we read the buffer in directly - $this->assertEquals( - $this->frame->getFrameBuffer(), - $frame->getFrameBuffer(), - 'Raw buffers match too' - ); - - // This time, we create a new frame and read the data in with encode - $frame = $this->getNewFrame(); - $frame->encode($this->frame->getFramePayload(), $type, $masked); - - // These still match - $this->assertEquals( - $this->frame->getType(), - $frame->getType(), - 'Types match after encode -> receiveData -> encode' - ); - - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData -> encode' - ); - - // But the masking key should be different, thus, so are the buffers - if ($masked) { - $this->assertNotEquals( - $this->frame->getFrameBuffer(), - $frame->getFrameBuffer(), - 'Raw buffers don\'t match because of masking' - ); - } else { - $this->assertEquals( - $this->frame->getFramePayload(), - $frame->getFramePayload(), - 'Payloads match after encode -> receiveData -> encode' - ); - } - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeTypeReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type); - $this->assertEquals(Protocol::TYPE_TEXT, $this->frame->getType(), 'Encode retains type information'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeLengthReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type); - $this->assertEquals(strlen($payload), $this->frame->getLength(), 'Encode does not alter payload length'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodePayloadReflection($type, $payload, $masked) - { - $this->frame->encode($payload, $type, $masked); - $this->assertEquals($payload, $this->frame->getFramePayload(), 'Encode retains payload information'); - } - - /** - * Data provider - * - * @return array - */ - public function getValidEncodePayloads() - { - return array( - array( - Protocol::TYPE_TEXT, - "123456\x007890!@#$%^&*()qwe\trtyuiopQWERTYUIOPasdfghjklASFGH\n - JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\|'asdad0x11\aasdassasdasasdsd", - true - ), - array( - Protocol::TYPE_TEXT, - pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0), - true - ), - array(Protocol::TYPE_TEXT, ' ', true) - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Frame/HybiFrameTest.php b/core/lib/Wrench/Tests/Frame/HybiFrameTest.php deleted file mode 100755 index 721429513..000000000 --- a/core/lib/Wrench/Tests/Frame/HybiFrameTest.php +++ /dev/null @@ -1,14 +0,0 @@ -getMock('Wrench\Server', array(), array(), '', false); - - $instance->listen($server); - } - - abstract public function testConstructor(); -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php b/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php deleted file mode 100755 index 103af9bfe..000000000 --- a/core/lib/Wrench/Tests/Listener/OriginPolicyTest.php +++ /dev/null @@ -1,110 +0,0 @@ -getInstance(array()); - $this->assertInstanceOfClass($instance, 'No constructor arguments'); - return $instance; - } - - /** - * @dataProvider getValidArguments - * @param array $allowed - * @param string $domain - */ - public function testValidAllowed($allowed, $domain) - { - $instance = $this->getInstance($allowed); - $this->assertTrue($instance->isAllowed($domain)); - } - - /** - * @dataProvider getValidArguments - * @param array $allowed - * @param string $domain - */ - public function testValidHandshake($allowed, $domain) - { - $instance = $this->getInstance($allowed); - - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->never()) - ->method('close'); - - $instance->onHandshakeRequest($connection, '/', $domain, 'abc', array()); - } - - /** - * @dataProvider getInvalidArguments - * @param array $allowed - * @param string $bad_domain - */ - public function testInvalidAllowed($allowed, $bad_domain) - { - $instance = $this->getInstance($allowed); - $this->assertFalse($instance->isAllowed($bad_domain)); - } - - /** - * @dataProvider getInvalidArguments - * @param array $allowed - * @param string $domain - */ - public function testInvalidHandshake($allowed, $bad_domain) - { - $instance = $this->getInstance($allowed); - - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->once()) - ->method('close'); - - $instance->onHandshakeRequest($connection, '/', $bad_domain, 'abc', array()); - } - - /** - * Data provider - */ - public function getValidArguments() - { - return array( - array(array('localhost'), 'http://localhost'), - array(array('foobar.com'), 'https://foobar.com'), - array(array('https://foobar.com'), 'https://foobar.com') - ); - } - - /** - * Data provider - */ - public function getInvalidArguments() - { - return array( - array(array('localhost'), 'localdomain'), - array(array('foobar.com'), 'foobar.org'), - array(array('https://foobar.com'), 'http://foobar.com'), - array(array('http://foobar.com'), 'foobar.com') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Listener/RateLimiterTest.php b/core/lib/Wrench/Tests/Listener/RateLimiterTest.php deleted file mode 100755 index 602442308..000000000 --- a/core/lib/Wrench/Tests/Listener/RateLimiterTest.php +++ /dev/null @@ -1,67 +0,0 @@ -getInstance(); - $this->assertInstanceOfClass($instance, 'No constructor arguments'); - return $instance; - } - - public function testOnSocketConnect() - { - $this->getInstance()->onSocketConnect(null, $this->getConnection()); - } - - public function testOnSocketDisconnect() - { - $this->getInstance()->onSocketDisconnect(null, $this->getConnection()); - } - - public function testOnClientData() - { - $this->getInstance()->onClientData(null, $this->getConnection()); - } - - protected function getConnection() - { - $connection = $this->getMock('Wrench\Connection', array(), array(), '', false); - - $connection - ->expects($this->any()) - ->method('getIp') - ->will($this->returnValue('127.0.0.1')); - - $connection - ->expects($this->any()) - ->method('getId') - ->will($this->returnValue('abcdef01234567890')); - - $manager = $this->getMock('Wrench\ConnectionManager', array(), array(), '', false); - $manager->expects($this->any())->method('count')->will($this->returnValue(5)); - - $connection - ->expects($this->any()) - ->method('getConnectionManager') - ->will($this->returnValue($manager)); - - return $connection; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php b/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php deleted file mode 100755 index 5dd2b2497..000000000 --- a/core/lib/Wrench/Tests/Payload/HybiPayloadTest.php +++ /dev/null @@ -1,14 +0,0 @@ -payload = $this->getInstance(); - } - - /** - * Tests the constructor - */ - public function testConstructor() - { - $this->assertInstanceOfClass($this->getInstance()); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testBijection($type, $payload) - { - // Encode the payload - $this->payload->encode($payload, $type); - - // Create a new payload and read the data in with encode - $payload = $this->getInstance(); - $payload->encode($this->payload->getPayload(), $type); - - // These still match - $this->assertEquals( - $this->payload->getType(), - $payload->getType(), - 'Types match after encode -> receiveData' - ); - - $this->assertEquals( - $this->payload->getPayload(), - $payload->getPayload(), - 'Payloads match after encode -> receiveData' - ); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodeTypeReflection($type, $payload) - { - $this->payload->encode($payload, Protocol::TYPE_TEXT); - $this->assertEquals(Protocol::TYPE_TEXT, $this->payload->getType(), 'Encode retains type information'); - } - - /** - * @param string $payload - * @dataProvider getValidEncodePayloads - */ - public function testEncodePayloadReflection($type, $payload) - { - $this->payload->encode($payload, Protocol::TYPE_TEXT); - $this->assertEquals($payload, $this->payload->getPayload(), 'Encode retains payload information'); - } - - /** - * Tests sending to a socket - * @dataProvider getValidEncodePayloads - */ - public function testSendToSocket($type, $payload) - { - $successfulSocket = $this->getMock('Wrench\Socket\ClientSocket', array(), array('wss://localhost:8000')); - $failedSocket = clone $successfulSocket; - - $successfulSocket->expects($this->any()) - ->method('send') - ->will($this->returnValue(true)); - - $failedSocket->expects($this->any()) - ->method('send') - ->will($this->returnValue(false)); - - $this->payload->encode($payload, $type); - - $this->assertTrue($this->payload->sendToSocket($successfulSocket)); - $this->assertFalse($this->payload->sendToSocket($failedSocket)); - } - - /** - * Tests receiving data - * @dataProvider getValidEncodePayloads - */ - public function testReceieveData($type, $payload) - { - $payload = $this->getInstance(); - $payload->receiveData($payload); - } - - /** - * Data provider - * - * @return array - */ - public function getValidEncodePayloads() - { - return array( - array( - Protocol::TYPE_TEXT, - "123456\x007890!@#$%^&*()qwe\trtyuiopQWERTYUIOPasdfghjklASFGH\n - JKLzxcvbnmZXCVBNM,./<>?;[]{}-=_+\|'asdad0x11\aasdassasdasasdsd" - ), - array( - Protocol::TYPE_TEXT, - pack('CCCCCCC', 0x00, 0x01, 0x02, 0x03, 0x04, 0xff, 0xf0) - ), - array(Protocol::TYPE_TEXT, ' ') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Protocol/ProtocolTest.php b/core/lib/Wrench/Tests/Protocol/ProtocolTest.php deleted file mode 100755 index afba179da..000000000 --- a/core/lib/Wrench/Tests/Protocol/ProtocolTest.php +++ /dev/null @@ -1,180 +0,0 @@ -getInstance()->validateRequestHandshake($request); - - $this->assertEquals('/chat', $path); - $this->assertEquals('http://example.com', $origin); - $this->assertEquals('dGhlIHNhbXBsZSBub25jZQ==', $key); - $this->assertTrue(is_array($extensions), 'Extensions returned as array'); - $this->assertEquals(array('x-test', 'x-test2'), $extensions, 'Extensions match'); - $this->assertEquals('chat, superchat', $protocol); - } catch (Exception $e) { - $this->fail($e); - } - } - - /** - * @dataProvider getValidHandshakeResponses - */ - public function testValidateHandshakeResponseValid($response, $key) - { - try { - $valid = $this->getInstance()->validateResponseHandshake($response, $key); - $this->assertTrue(is_bool($valid), 'Validation return value is boolean'); - $this->assertTrue($valid, 'Handshake response validates'); - } catch (Exception $e) { - $this->fail('Validated valid response handshake as invalid'); - } - } - - /** - * @dataProvider getValidHandshakeResponses - */ - public function testGetResponseHandsake($unused, $key) - { - try { - $response = $this->getInstance()->getResponseHandshake($key); - $this->assertHttpResponse($response); - } catch (Exception $e) { - $this->fail('Unable to get handshake response: ' . $e); - } - } - - /** - * Asserts the string response is an HTTP response - * - * @param string $response - */ - protected function assertHttpResponse($response, $message = '') - { - $this->assertStringStartsWith('HTTP', $response, $message . ' - response starts well'); - $this->assertStringEndsWith("\r\n", $response, $message . ' - response ends well'); - } - - public function testGetVersion() - { - $version = $this->getInstance()->getVersion(); - $this->assertTrue(is_int($version)); - } - - public function testGetResponseError() - { - $response = $this->getInstance()->getResponseError(400); - $this->assertHttpResponse($response, 'Code as int'); - - $response = $this->getInstance()->getResponseError(new Exception('Some message', 500)); - $this->assertHttpResponse($response, 'Code in Exception'); - - $response = $this->getInstance()->getResponseError(888); - $this->assertHttpResponse($response, 'Invalid code produces unimplemented response'); - } - - /** - * @dataProvider getValidOriginUris - */ - public function testValidateOriginUriValid($uri) - { - try { - $this->getInstance()->validateOriginUri($uri); - } catch (\Exception $e) { - $this->fail('Valid URI validated as invalid: ' . $e); - } - } - - /** - * @dataProvider getInvalidOriginUris - * @expectedException InvalidArgumentException - */ - public function testValidateOriginUriInvalid($uri) - { - $this->getInstance()->validateOriginUri($uri); - } - - public function getValidOriginUris() - { - return array( - array('http://www.example.org'), - array('http://www.example.com/some/page'), - array('https://localhost/') - ); - } - - public function getInvalidOriginUris() - { - return array( - array(false), - array(true), - array(''), - array('blah') - ); - } - - public function getValidHandshakeRequests() - { - $cases = array(); - - - $cases[] = array("GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Extensions: x-test\r -Sec-WebSocket-Extensions: x-test2\r -Sec-WebSocket-Protocol: chat, superchat\r -Sec-WebSocket-Version: 13\r -\r\n"); - - $cases[] = array("GET /chat HTTP/1.1\r -Host: server.example.com\r -Upgrade: Websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://example.com\r -Sec-WebSocket-Extensions: x-test\r -Sec-WebSocket-Extensions: x-test2\r -Sec-WebSocket-Protocol: chat, superchat\r -Sec-WebSocket-Version: 13\r -\r\n"); - - return $cases; - } - - public function getValidHandshakeResponses() - { - $cases = array(); - - for ($i = 10; $i > 0; $i--) { - $key = sha1(time() . uniqid('', true)); - $response = "Sec-WebSocket-Accept: " - . base64_encode(sha1($key . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true)) - . "\r\n\r\n"; - - $cases[] = array($response, $key); - } - - return $cases; - } -} diff --git a/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php b/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php deleted file mode 100755 index ee329f31e..000000000 --- a/core/lib/Wrench/Tests/Protocol/Rfc6455ProtocolTest.php +++ /dev/null @@ -1,14 +0,0 @@ -assertInstanceOfClass( - $this->getInstance($url, $options), - 'Valid constructor arguments' - ); - } - - /** - * Tests logging - */ - public function testLogging() - { - $test = $this; - $logged = false; - - $server = $this->getInstance('ws://localhost:8000', array( - 'logger' => function ($message, $priority) use ($test, &$logged) { - $test->assertTrue(is_string($message), 'Log had a string message'); - $test->assertTrue(is_string($priority), 'Log had a string priority'); - $logged = true; - } - )); - - $this->assertTrue($logged, 'The log callback was hit'); - } - - /** - * Data provider - * - * @return array> - */ - public function getValidConstructorArguments() - { - return array( - array( - 'ws://localhost:8000', - array('logger' => array($this, 'log')) - ), - array( - 'ws://localhost', - array('logger' => array($this, 'log')) - ) - ); - } - -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/ServerTestHelper.php b/core/lib/Wrench/Tests/ServerTestHelper.php deleted file mode 100755 index 57dd1ec05..000000000 --- a/core/lib/Wrench/Tests/ServerTestHelper.php +++ /dev/null @@ -1,144 +0,0 @@ -tearDown(); - } - - /** - * @return string - */ - public function getConnectionString() - { - return 'ws://localhost:' . $this->port; - } - - /** - * @return string - */ - public function getEchoConnectionString() - { - return $this->getConnectionString() . '/echo'; - } - - /** - * Sets up the server process and sleeps for a few seconds while - * it wakes up - */ - public function setUp() - { - $this->port = self::getNextPort(); - - $this->process = proc_open( - $this->getCommand(), - array( - 0 => array('file', '/dev/null', 'r'), - 1 => array('file', __DIR__ . '/../../../build/server.log', 'a+'), - 2 => array('file', __DIR__ . '/../../../build/server.err.log', 'a+') - ), - $this->pipes, - __DIR__ . '../' - ); - - sleep(3); - } - - /** - * Tears down the server process - * - * This method *must* be called - */ - public function tearDown() - { - if ($this->process) { - foreach ($this->pipes as &$pipe) { - fclose($pipe); - } - $this->pipes = null; - - // Sigh - $status = proc_get_status($this->process); - - if ($status && isset($status['pid']) && $status['pid']) { - // More sigh, this is the pid of the parent sh process, we want - // to terminate the server directly - $this->log('Command: /bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \' ' . $status['pid'] . "'", 'info'); - exec('/bin/ps -ao pid,ppid | /usr/bin/col | /usr/bin/tail -n +2 | /bin/grep \' ' . $status['pid'] . "'", $processes, $return); - - if ($return === 0) { - foreach ($processes as $process) { - list($pid, $ppid) = explode(' ', str_replace(' ', ' ', $process)); - if ($pid) { - $this->log('Killing ' . $pid, 'info'); - exec('/bin/kill ' . $pid . ' > /dev/null 2>&1'); - } - } - } else { - $this->log('Unable to find child processes', 'warning'); - } - - sleep(1); - - $this->log('Killing ' . $status['pid'], 'info'); - exec('/bin/kill ' . $status['pid'] . ' > /dev/null 2>&1'); - - sleep(1); - } - - proc_close($this->process); - $this->process = null; - } - } - - /** - * Gets the server command - * - * @return string - */ - protected function getCommand() - { - return sprintf('/usr/bin/env php %s/server.php %d', __DIR__, $this->port); - } - - /** - * Logs a message - * - * @param string $message - * @param string $priority - */ - public function log($message, $priority = 'info') - { - //echo $message . "\n"; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ClientSocketTest.php b/core/lib/Wrench/Tests/Socket/ClientSocketTest.php deleted file mode 100755 index d64ea5df2..000000000 --- a/core/lib/Wrench/Tests/Socket/ClientSocketTest.php +++ /dev/null @@ -1,167 +0,0 @@ -assertInstanceOfClass( - new ClientSocket('ws://localhost/'), - 'ws:// scheme, default port' - ); - - $this->assertInstanceOfClass( - new ClientSocket('ws://localhost/some-arbitrary-path'), - 'with path' - ); - - $this->assertInstanceOfClass( - new ClientSocket('wss://localhost/test', array()), - 'empty options' - ); - - $this->assertInstanceOfClass( - new ClientSocket('ws://localhost:8000/foo'), - 'specified port' - ); - - return $instance; - } - - public function testOptions() - { - $socket = null; - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'timeout_connect' => 10 - ) - ), - 'connect timeout' - ); - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'timeout_socket' => 10 - ) - ), - 'socket timeout' - ); - - $this->assertInstanceOfClass( - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'protocol' => new Rfc6455Protocol() - ) - ), - 'protocol' - ); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testProtocolTypeError() - { - $socket = new ClientSocket( - 'ws://localhost:8000/foo', array( - 'protocol' => new stdClass() - ) - ); - } - - /** - * @expectedException PHPUnit_Framework_Error - */ - public function testConstructorUriUnspecified() - { - $w = new ClientSocket(); - } - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriEmpty() - { - $w = new ClientSocket(null); - } - - - /** - * @expectedException InvalidArgumentException - */ - public function testConstructorUriInvalid() - { - $w = new ClientSocket('Bad argument'); - } - - - /** - * @depends testConstructor - * @expectedException Wrench\Exception\SocketException - */ - public function testSendTooEarly($instance) - { - $instance->send('foo'); - } - - /** - * Test the connect, send, receive method - */ - public function testConnect() - { - try { - $helper = new ServerTestHelper(); - $helper->setUp(); - - $instance = $this->getInstance($helper->getConnectionString()); - $success = $instance->connect(); - - $this->assertTrue($success, 'Client socket can connect to test server'); - - $sent = $instance->send("GET /echo HTTP/1.1\r -Host: localhost\r -Upgrade: websocket\r -Connection: Upgrade\r -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r -Origin: http://localhost\r -Sec-WebSocket-Version: 13\r\n\r\n"); - $this->assertNotEquals(false, $sent, 'Client socket can send to test server'); - - $response = $instance->receive(); - $this->assertStringStartsWith('HTTP', $response, 'Response looks like HTTP handshake response'); - - } catch (\Exception $e) { - $helper->tearDown(); - throw $e; - } - - $helper->tearDown(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php b/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php deleted file mode 100755 index ca71983b5..000000000 --- a/core/lib/Wrench/Tests/Socket/ServerClientSocketTest.php +++ /dev/null @@ -1,42 +0,0 @@ -getInstance($resource); - $this->assertInstanceOfClass($instance); - return $instance; - } - - /** - * @expectedException Wrench\Exception\SocketException - * @depends testConstructor - */ - public function testGetIpTooSoon($instance) - { - $instance->getIp(); - } - - /** - * @expectedException Wrench\Exception\SocketException - * @depends testConstructor - */ - public function testGetPortTooSoon($instance) - { - $instance->getPort(); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/ServerSocketTest.php b/core/lib/Wrench/Tests/Socket/ServerSocketTest.php deleted file mode 100755 index a4d4251c5..000000000 --- a/core/lib/Wrench/Tests/Socket/ServerSocketTest.php +++ /dev/null @@ -1,13 +0,0 @@ -isConnected(); - $this->assertTrue(is_bool($connected), 'isConnected returns boolean'); - $this->assertFalse($connected); - } - - /** - * @dataProvider getValidNames - * @param string $name - */ - public function testGetNamePart($name, $ip, $port) - { - $this->assertEquals($ip, Socket::getNamePart($name, Socket::NAME_PART_IP), 'splits ip correctly'); - $this->assertEquals($port, Socket::getNamePart($name, Socket::NAME_PART_PORT), 'splits port correctly'); - } - - /** - * Data provider - */ - public function getValidNames() - { - return array( - array('127.0.0.1:52339', '127.0.0.1', '52339'), - array('255.255.255.255:1025', '255.255.255.255', '1025'), - array('::1:56670', '::1', '56670') - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Socket/UriSocketTest.php b/core/lib/Wrench/Tests/Socket/UriSocketTest.php deleted file mode 100755 index d0b7f8bdc..000000000 --- a/core/lib/Wrench/Tests/Socket/UriSocketTest.php +++ /dev/null @@ -1,56 +0,0 @@ -getInstance('ws://localhost:8000'); - $this->assertInstanceOfClass($instance); - return $instance; - } - - /** - * @dataProvider getInvalidConstructorArguments - * @expectedException InvalidArgumentException - */ - public function testInvalidConstructor($uri) - { - $this->getInstance($uri); - } - - /** - * @depends testConstructor - */ - public function testGetIp($instance) - { - $this->assertStringStartsWith('localhost', $instance->getIp(), 'Correct host'); - } - - /** - * @depends testConstructor - */ - public function testGetPort($instance) - { - $this->assertEquals(8000, $instance->getPort(), 'Correct port'); - } - - /** - * Data provider - */ - public function getInvalidConstructorArguments() - { - return array( - array(false), - array('http://www.google.com/'), - array('ws:///'), - array(':::::'), - ); - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Tests/Test.php b/core/lib/Wrench/Tests/Test.php deleted file mode 100755 index f9b421fd9..000000000 --- a/core/lib/Wrench/Tests/Test.php +++ /dev/null @@ -1,61 +0,0 @@ -assertInstanceOf( - $this->getClass(), - $instance, - $message - ); - } - - /** - * Gets an instance of the class under test - * - * @param mixed Normal constructor arguments - * @magic This method accepts a variable number of arguments - * @return object Of type given by getClass() - */ - public function getInstance(/* ... */) - { - $reflection = new ReflectionClass($this->getClass()); - return $reflection->newInstanceArgs(func_get_args()); - } - - /** - * Logging function - * - * Passed into some classes under test as a callable - * - * @param string $message - * @param string $priority - * @return void - */ - public function log($message, $priority = 'info') - { - // nothing - } -} diff --git a/core/lib/Wrench/Tests/bootstrap.php b/core/lib/Wrench/Tests/bootstrap.php deleted file mode 100755 index 84bd83943..000000000 --- a/core/lib/Wrench/Tests/bootstrap.php +++ /dev/null @@ -1,11 +0,0 @@ -register(); \ No newline at end of file diff --git a/core/lib/Wrench/Tests/server.php b/core/lib/Wrench/Tests/server.php deleted file mode 100755 index 34d680622..000000000 --- a/core/lib/Wrench/Tests/server.php +++ /dev/null @@ -1,16 +0,0 @@ -register(); - -$server = new Wrench\Server('ws://localhost:' . $port); -$server->registerApplication('echo', new Wrench\Application\EchoApplication()); -$server->run(); \ No newline at end of file diff --git a/core/lib/Wrench/Util/Configurable.php b/core/lib/Wrench/Util/Configurable.php deleted file mode 100755 index f1983d5e6..000000000 --- a/core/lib/Wrench/Util/Configurable.php +++ /dev/null @@ -1,67 +0,0 @@ - Wrench\Protocol object, latest protocol - * version used if not specified - */ - public function __construct( - array $options = array() - ) { - $this->configure($options); - $this->configureProtocol(); - } - - /** - * Configures the options - * - * @param array $options - */ - protected function configure(array $options) - { - $this->options = array_merge(array( - 'protocol' => new Rfc6455Protocol() - ), $options); - } - - /** - * Configures the protocol option - * - * @throws InvalidArgumentException - */ - protected function configureProtocol() - { - $protocol = $this->options['protocol']; - - if (!$protocol || !($protocol instanceof Protocol)) { - throw new InvalidArgumentException('Invalid protocol option'); - } - - $this->protocol = $protocol; - } -} \ No newline at end of file diff --git a/core/lib/Wrench/Util/Ssl.php b/core/lib/Wrench/Util/Ssl.php deleted file mode 100755 index e8cc8bd7e..000000000 --- a/core/lib/Wrench/Util/Ssl.php +++ /dev/null @@ -1,51 +0,0 @@ - $country_name, - 'stateOrProvinceName' => $state_or_province_name, - 'localityName' => $locality_name, - 'organizationName' => $organization_name, - 'organizationalUnitName' => $organizational_unit_name, - 'commonName' => $common_name, - 'emailAddress' => $email_address - ); - - $privkey = openssl_pkey_new(); - $cert = openssl_csr_new($dn, $privkey); - $cert = openssl_csr_sign($cert, null, $privkey, 365); - - $pem = array(); - - openssl_x509_export($cert, $pem[0]); - - if ($pem_passphrase !== null) { - openssl_pkey_export($privkey, $pem[1], $pem_passphrase); - } - - $pem = implode($pem); - file_put_contents($pem_file, $pem); - } -} \ No newline at end of file diff --git a/core/migrations/001-move-source.json b/core/migrations/001-move-source.json deleted file mode 100644 index 08bfd4d28..000000000 --- a/core/migrations/001-move-source.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/source", - "destinationPath": "source", - "checkType": "dirEmpty" -} \ No newline at end of file diff --git a/core/migrations/002-move-styleguide.json b/core/migrations/002-move-styleguide.json deleted file mode 100644 index 9f96dd1ee..000000000 --- a/core/migrations/002-move-styleguide.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/styleguide", - "destinationPath": "public/styleguide", - "checkType": "versionDiffDir" -} \ No newline at end of file diff --git a/core/migrations/003-move-pattern-header-footer.json b/core/migrations/003-move-pattern-header-footer.json deleted file mode 100644 index 6823124be..000000000 --- a/core/migrations/003-move-pattern-header-footer.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "sourcePath": "core/source/_patterns/00-atoms/00-meta", - "destinationPath": "source/_patterns/00-atoms/00-meta", - "checkType": "dirExists" -} \ No newline at end of file diff --git a/core/pageFollowServer.php b/core/pageFollowServer.php deleted file mode 100755 index bd579087d..000000000 --- a/core/pageFollowServer.php +++ /dev/null @@ -1,40 +0,0 @@ -register(); - -// parse the main config for the content sync port -if (!($config = @parse_ini_file(__DIR__."/../config/config.ini"))) { - print "Missing the configuration file. Please build it using the Pattern Lab builder.\n"; - exit; -} - -// give it a default port -$port = ($config) ? trim($config['pageFollowPort']) : '8000'; - -// start the content sync server -$server = new \Wrench\Server('ws://0.0.0.0:'.$port.'/', array()); - -// register the application & run it -$server->registerApplication('pagefollow', new \Wrench\Application\PageFollowApplication()); - -print "\n"; -print "Page Follow Server Started...\n"; -print "Use CTRL+C to stop this service...\n"; - -$server->run(); diff --git a/core/scripts/README b/core/scripts/README deleted file mode 100644 index 95dca5ed7..000000000 --- a/core/scripts/README +++ /dev/null @@ -1,6 +0,0 @@ -These are Mac OS X-compatible files to open up select command line scripts. Simply double-click on a file and it should run -the appropriate shell command. If you receive a permissions error you will need to use the command line to fix it. -Simply go to the command line, cd to the scripts/php directory and type chmod +x [filename]. Replace [filename] with the -appropriate filenames. - -That's confusing. \ No newline at end of file diff --git a/core/scripts/generateSite.command b/core/scripts/generateSite.command deleted file mode 100755 index c339b935a..000000000 --- a/core/scripts/generateSite.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -g \ No newline at end of file diff --git a/core/scripts/generateSiteWithCSS.command b/core/scripts/generateSiteWithCSS.command deleted file mode 100755 index b97af439e..000000000 --- a/core/scripts/generateSiteWithCSS.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -gc \ No newline at end of file diff --git a/core/scripts/startAutoReloadServer.command b/core/scripts/startAutoReloadServer.command deleted file mode 100755 index 934877ba6..000000000 --- a/core/scripts/startAutoReloadServer.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../autoReloadServer.php" \ No newline at end of file diff --git a/core/scripts/startPageFollowServer.command b/core/scripts/startPageFollowServer.command deleted file mode 100755 index e3a1e362f..000000000 --- a/core/scripts/startPageFollowServer.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../pageFollowServer.php" \ No newline at end of file diff --git a/core/scripts/startWatcher.command b/core/scripts/startWatcher.command deleted file mode 100755 index 08c37f182..000000000 --- a/core/scripts/startWatcher.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -w \ No newline at end of file diff --git a/core/scripts/startWatcherWithAutoReload.command b/core/scripts/startWatcherWithAutoReload.command deleted file mode 100755 index 14e251966..000000000 --- a/core/scripts/startWatcherWithAutoReload.command +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -DIR="$( cd "$( dirname "$0" )" && pwd )" -php "$DIR/../builder.php" -wr \ No newline at end of file diff --git a/core/server/router.php b/core/server/router.php new file mode 100644 index 000000000..02bc4c232 --- /dev/null +++ b/core/server/router.php @@ -0,0 +1,41 @@ +

Further reading: Optimizing Web Experiences for High Resolution Screens

" - }, - { - "el": "#nav", - "title" : "Navigation", - "comment": "

Navigation for adaptive web experiences can be tricky. Top navigations are typical on desktop sites, but mobile screen sizes don't give us the luxury of space. We're dealing with this situation by creating a simple menu anchor that toggles the main navigation on small screens. This is just one method. Bagcheck and Contents Magazine add an anchor in the header that jumps users to the navigation which is placed in the footer. This solution works well because it doesn't require any Javascript in order to work. Other methods exist too. For example, ESPN's mobile navigation overlays the main content of the page.

The nav is only hidden when a certain level of javascript is supported in order to ensure that users with little/poor javascript support can still access the navigation. Once the screen size is large enough to accommodate the nav, we show the main navigation links and hide the menu anchor.

See also: Responsive Navigation Patterns

" - }, - { - "el": ".search-form", - "title" : "Search", - "comment": "

Search is an incredibly important priority, especially for mobile. It is a great idea to give users the ability to jump directly to what they are looking for without forcing them to wade through your site's navigation. Check out the Burton and Yelp mobile sites for great examples of experiences that prioritize search.

We're also using the HTML5 search input type, which is great for mobile devices that can bring up the appropriate virtual keyboard for many smartphones. And like the main header navigation, we're hiding the search form on small screens to save space. Clicking the search anchor toggles the form.

" - }, - { - "el": ".article-header h1", - "title" : "Article Header", - "comment": "

The article header should be no more than 140 characters.

" - }, - { - "el": ".block-hero", - "title" : "Hero", - "comment": "

The hero area highlights one major story using a large image and a captivating headline.

" - } -] -}; \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/00-meta/_00-head.mustache b/core/source/_patterns/00-atoms/00-meta/_00-head.mustache deleted file mode 100644 index 938c0d2db..000000000 --- a/core/source/_patterns/00-atoms/00-meta/_00-head.mustache +++ /dev/null @@ -1,16 +0,0 @@ - - - - {{ title }} - - - - - - - {% pattern-lab-head %} - - - - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache b/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache deleted file mode 100644 index 5bd39a972..000000000 --- a/core/source/_patterns/00-atoms/00-meta/_01-foot.mustache +++ /dev/null @@ -1,6 +0,0 @@ - - - {% pattern-lab-foot %} - - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/00-colors.mustache b/core/source/_patterns/00-atoms/01-global/00-colors.mustache deleted file mode 100644 index 7f2653f8d..000000000 --- a/core/source/_patterns/00-atoms/01-global/00-colors.mustache +++ /dev/null @@ -1,38 +0,0 @@ -
    -
  • - - #ff0000 -
  • -
  • - - #00ff00 -
  • -
  • - - #0000ff -
  • -
  • - - #ffff00 -
  • -
  • - - #00ffff -
  • -
  • - - #ff00ff -
  • -
  • - - #ffffff -
  • -
  • - - #808080 -
  • -
  • - - #000000 -
  • -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/01-fonts.mustache b/core/source/_patterns/00-atoms/01-global/01-fonts.mustache deleted file mode 100644 index a292ff438..000000000 --- a/core/source/_patterns/00-atoms/01-global/01-fonts.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Primary font: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Primary font italic: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Primary font bold: "HelveticaNeue", "Helvetica", "Arial", sans-serif;

-

Secondary font: Georgia, Times, "Times New Roman", serif;

-

Secondary font italic: Georgia, Times, "Times New Roman", serif;

-

Secondary font bold; Georgia, Times, "Times New Roman", serif;

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/02-animations.mustache b/core/source/_patterns/00-atoms/01-global/02-animations.mustache deleted file mode 100644 index 7d3074575..000000000 --- a/core/source/_patterns/00-atoms/01-global/02-animations.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
Fade: Duration: 0.3s Easing: ease-out (Hover to see effect)
- -
Movement: Duration: 0.8s Easing: ease-in-out; (Hover to see effect)
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/01-global/03-visibility.mustache b/core/source/_patterns/00-atoms/01-global/03-visibility.mustache deleted file mode 100644 index 13e602122..000000000 --- a/core/source/_patterns/00-atoms/01-global/03-visibility.mustache +++ /dev/null @@ -1,11 +0,0 @@ -

This text is hidden on smaller screens

- -

This text is only visible on smaller screens

- -

This text is hidden on medium screens only

- -

This text is only visible on medium screens

- -

This text is hidden on large screens

- -

This text is only visible on large screens

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/00-headings.mustache b/core/source/_patterns/00-atoms/02-text/00-headings.mustache deleted file mode 100644 index 43f648c7f..000000000 --- a/core/source/_patterns/00-atoms/02-text/00-headings.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Heading Level 1

-

Heading Level 2

-

Heading Level 3

-

Heading Level 4

-
Heading Level 5
-
Heading Level 6
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/01-subheadings.mustache b/core/source/_patterns/00-atoms/02-text/01-subheadings.mustache deleted file mode 100644 index 367c09a82..000000000 --- a/core/source/_patterns/00-atoms/02-text/01-subheadings.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Subheading Level 1

-

Subheading Level 2

-

Subheading Level 3

-

Subheading Level 4

-
Subheading Level 5
-
Subheading Level 6
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/02-headings-with-links.mustache b/core/source/_patterns/00-atoms/02-text/02-headings-with-links.mustache deleted file mode 100644 index 9540d4c23..000000000 --- a/core/source/_patterns/00-atoms/02-text/02-headings-with-links.mustache +++ /dev/null @@ -1,6 +0,0 @@ -

Heading 1 with link

-

Heading 2 with link

-

Heading 3 with link

-

Heading 4 with link

-
Heading 5 with link
-
Heading 6 with link
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/03-paragraph.mustache b/core/source/_patterns/00-atoms/02-text/03-paragraph.mustache deleted file mode 100644 index 01534936d..000000000 --- a/core/source/_patterns/00-atoms/02-text/03-paragraph.mustache +++ /dev/null @@ -1 +0,0 @@ -

{{ description }}

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/04-blockquote.mustache b/core/source/_patterns/00-atoms/02-text/04-blockquote.mustache deleted file mode 100644 index 2f11319b3..000000000 --- a/core/source/_patterns/00-atoms/02-text/04-blockquote.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
-

A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.

-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/05-inline-elements.mustache b/core/source/_patterns/00-atoms/02-text/05-inline-elements.mustache deleted file mode 100644 index dd4ff1f39..000000000 --- a/core/source/_patterns/00-atoms/02-text/05-inline-elements.mustache +++ /dev/null @@ -1,41 +0,0 @@ -
-

This is a text link

- -

Strong is used to indicate strong importance

- -

This text has added emphasis

- -

The b element is stylistically different text from normal text, without any special importance

- -

The i element is text that is set off from the normal text

- -

The u element is text with an unarticulated, though explicitly rendered, non-textual annotation

- -

This text is deleted and This text is inserted

- -

This text has a strikethrough

- -

Superscript®

- -

Subscript for things like H2O

- -

This small text is small for for fine print, etc.

- -

Abbreviation: HTML

- -

Keybord input: Cmd

- -

This text is a short inline quotation

- -

This is a citation - -

The dfn element indicates a definition.

- -

The mark element indicates a highlight

- -

This is what inline code looks like.

- -

This is sample output from a computer program

- -

The variarble element, such as x = y

-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/06-time.mustache b/core/source/_patterns/00-atoms/02-text/06-time.mustache deleted file mode 100644 index 26cecc136..000000000 --- a/core/source/_patterns/00-atoms/02-text/06-time.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/07-preformatted-text.mustache b/core/source/_patterns/00-atoms/02-text/07-preformatted-text.mustache deleted file mode 100644 index 70de25e11..000000000 --- a/core/source/_patterns/00-atoms/02-text/07-preformatted-text.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
  	
-P R E F O R M A T T E D T E X T
-! " # $ % & ' ( ) * + , - . /
-0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-@ A B C D E F G H I J K L M N O
-P Q R S T U V W X Y Z [ \ ] ^ _
-` a b c d e f g h i j k l m n o
-p q r s t u v w x y z { | } ~ 
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/08-emphasis-colors.mustache b/core/source/_patterns/00-atoms/02-text/08-emphasis-colors.mustache deleted file mode 100644 index b2fae06d2..000000000 --- a/core/source/_patterns/00-atoms/02-text/08-emphasis-colors.mustache +++ /dev/null @@ -1,4 +0,0 @@ -

This is what error text looks like

-

This is what valid text looks like

-

This is what warning text looks like

-

This is what information text looks like.

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/09-hr.mustache b/core/source/_patterns/00-atoms/02-text/09-hr.mustache deleted file mode 100644 index 1d6667d2e..000000000 --- a/core/source/_patterns/00-atoms/02-text/09-hr.mustache +++ /dev/null @@ -1 +0,0 @@ -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/02-text/10-caption.mustache b/core/source/_patterns/00-atoms/02-text/10-caption.mustache deleted file mode 100644 index 204437d16..000000000 --- a/core/source/_patterns/00-atoms/02-text/10-caption.mustache +++ /dev/null @@ -1 +0,0 @@ -

A caption can be applied to an image, quote, form field, etc.

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache b/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache deleted file mode 100644 index 3f9de349f..000000000 --- a/core/source/_patterns/00-atoms/03-lists/00-unordered.mustache +++ /dev/null @@ -1,14 +0,0 @@ -
-
    -
  • This is a list item in an unordered list
  • -
  • An unordered list is a list in which the sequence of items is not important. Sometimes, an unordered list is a bulleted list. And this is a long list item in an unordered list that can wrap onto a new line.
  • -
  • - Lists can be nested inside of each other -
      -
    • This is a nested list item
    • -
    • This is another nested list item in an unordered list
    • -
    -
  • -
  • This is the last list item
  • -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache b/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache deleted file mode 100644 index e206c7b10..000000000 --- a/core/source/_patterns/00-atoms/03-lists/01-ordered.mustache +++ /dev/null @@ -1,14 +0,0 @@ -
-
    -
  1. This is a list item in an ordered list
  2. -
  3. An ordered list is a list in which the sequence of items is important. An ordered list does not necessarily contain sequence characters.
  4. -
  5. - Lists can be nested inside of each other -
      -
    1. This is a nested list item
    2. -
    3. This is another nested list item in an ordered list
    4. -
    -
  6. -
  7. This is the last list item
  8. -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/03-lists/02-definition.mustache b/core/source/_patterns/00-atoms/03-lists/02-definition.mustache deleted file mode 100644 index 0488e0812..000000000 --- a/core/source/_patterns/00-atoms/03-lists/02-definition.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
Definition List
-
A number of connected items or names written or printed consecutively, typically one below the other.
-
This is a term.
-
This is the definition of that term, which both live in a dl.
-
Here is another term.
-
And it gets a definition too, which is this line.
-
Here is term that shares a definition with the term below.
-
And it gets a definition too, which is this line.
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/00-logo.mustache b/core/source/_patterns/00-atoms/04-images/00-logo.mustache deleted file mode 100644 index c0f431f98..000000000 --- a/core/source/_patterns/00-atoms/04-images/00-logo.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache b/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache deleted file mode 100644 index cf874ee9d..000000000 --- a/core/source/_patterns/00-atoms/04-images/01-landscape-4x3.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-4x3.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache b/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache deleted file mode 100644 index 9efc5eeb3..000000000 --- a/core/source/_patterns/00-atoms/04-images/02-landscape-16x9.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.landscape-16x9.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/03-square.mustache b/core/source/_patterns/00-atoms/04-images/03-square.mustache deleted file mode 100644 index 805cce5f2..000000000 --- a/core/source/_patterns/00-atoms/04-images/03-square.mustache +++ /dev/null @@ -1 +0,0 @@ -{{ img.square.alt }} \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/04-avatar.mustache b/core/source/_patterns/00-atoms/04-images/04-avatar.mustache deleted file mode 100644 index 6b79ad0c5..000000000 --- a/core/source/_patterns/00-atoms/04-images/04-avatar.mustache +++ /dev/null @@ -1 +0,0 @@ -Avatar \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/05-icons.mustache b/core/source/_patterns/00-atoms/04-images/05-icons.mustache deleted file mode 100644 index 4e2512348..000000000 --- a/core/source/_patterns/00-atoms/04-images/05-icons.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
    -
  • -
  • -
  • -
  • -
  • -
  • -
  • -
  • - -
  • -
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache b/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache deleted file mode 100644 index 9a10165ab..000000000 --- a/core/source/_patterns/00-atoms/04-images/06-loading-icon.mustache +++ /dev/null @@ -1 +0,0 @@ -Loading \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/04-images/07-favicon.mustache b/core/source/_patterns/00-atoms/04-images/07-favicon.mustache deleted file mode 100644 index 07e985d37..000000000 --- a/core/source/_patterns/00-atoms/04-images/07-favicon.mustache +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache b/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache deleted file mode 100644 index 90cbb7747..000000000 --- a/core/source/_patterns/00-atoms/05-forms/00-text-fields.mustache +++ /dev/null @@ -1,38 +0,0 @@ -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache b/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache deleted file mode 100644 index 760c9199a..000000000 --- a/core/source/_patterns/00-atoms/05-forms/01-select-menu.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
-
- - -
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache b/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache deleted file mode 100644 index 017a8dc5c..000000000 --- a/core/source/_patterns/00-atoms/05-forms/02-checkbox.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Checkbox * -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache b/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache deleted file mode 100644 index 68c83eaeb..000000000 --- a/core/source/_patterns/00-atoms/05-forms/03-radio-buttons.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
- Radio -
    -
  • -
  • -
  • -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache b/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache deleted file mode 100644 index 99c22cce7..000000000 --- a/core/source/_patterns/00-atoms/05-forms/04-html5-inputs.mustache +++ /dev/null @@ -1,10 +0,0 @@ -
-
-
-
-
-
-
-
-
-
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache b/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache deleted file mode 100644 index bdbeec360..000000000 --- a/core/source/_patterns/00-atoms/06-buttons/00-buttons.mustache +++ /dev/null @@ -1,4 +0,0 @@ -

Button

-

Alternate Button

-

Disabled Button

-

Text Button

\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/07-tables/00-table.mustache b/core/source/_patterns/00-atoms/07-tables/00-table.mustache deleted file mode 100644 index 53153d519..000000000 --- a/core/source/_patterns/00-atoms/07-tables/00-table.mustache +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Table Heading 1Table Heading 2Table Heading 3Table Heading 4Table Heading 5
Table Footer 1Table Footer 2Table Footer 3Table Footer 4Table Footer 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
Table Cell 1Table Cell 2Table Cell 3Table Cell 4Table Cell 5
\ No newline at end of file diff --git a/core/source/_patterns/00-atoms/08-media/_00-video.mustache b/core/source/_patterns/00-atoms/08-media/_00-video.mustache deleted file mode 100644 index f28fcd7fc..000000000 --- a/core/source/_patterns/00-atoms/08-media/_00-video.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/00-atoms/08-media/_01-audio.mustache b/core/source/_patterns/00-atoms/08-media/_01-audio.mustache deleted file mode 100644 index 91c82135e..000000000 --- a/core/source/_patterns/00-atoms/08-media/_01-audio.mustache +++ /dev/null @@ -1,4 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache b/core/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache deleted file mode 100644 index 08366cabe..000000000 --- a/core/source/_patterns/01-molecules/00-text/00-byline-author-only.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache b/core/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache deleted file mode 100644 index 5d61bc716..000000000 --- a/core/source/_patterns/01-molecules/00-text/01-byline-author-time.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/02-address.mustache b/core/source/_patterns/01-molecules/00-text/02-address.mustache deleted file mode 100644 index a13ea79fc..000000000 --- a/core/source/_patterns/01-molecules/00-text/02-address.mustache +++ /dev/null @@ -1,11 +0,0 @@ -
-
Company Name
-
-
1234 Main St.
- Anywhere, - 101010, - CA -
U.S.A
-
-
+1.888.123.4567
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/03-heading-group.mustache b/core/source/_patterns/01-molecules/00-text/03-heading-group.mustache deleted file mode 100644 index bf18f5ac4..000000000 --- a/core/source/_patterns/01-molecules/00-text/03-heading-group.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
-

This is the heading group's main heading

-

This is the heading group's subheading

-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/04-blockquote-with-citation.mustache b/core/source/_patterns/01-molecules/00-text/04-blockquote-with-citation.mustache deleted file mode 100644 index b9b6c98fc..000000000 --- a/core/source/_patterns/01-molecules/00-text/04-blockquote-with-citation.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
-

A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.

- Quote Source -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/05-intro-text.mustache b/core/source/_patterns/01-molecules/00-text/05-intro-text.mustache deleted file mode 100644 index b2b1bdef8..000000000 --- a/core/source/_patterns/01-molecules/00-text/05-intro-text.mustache +++ /dev/null @@ -1 +0,0 @@ -

The intro text may be a lead-in to the passage of text, or it may just be used to create a visual distinction between the rest of the passage of text.

\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/00-text/06-pullquote.mustache b/core/source/_patterns/01-molecules/00-text/06-pullquote.mustache deleted file mode 100644 index dba015d32..000000000 --- a/core/source/_patterns/01-molecules/00-text/06-pullquote.mustache +++ /dev/null @@ -1,3 +0,0 @@ -
-

A pull quote is a quotation or excerpt from an article

-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache b/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache deleted file mode 100644 index eb58a0e24..000000000 --- a/core/source/_patterns/01-molecules/01-layout/00-one-up.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
1/1
-
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache b/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache deleted file mode 100644 index ff1553aee..000000000 --- a/core/source/_patterns/01-molecules/01-layout/01-two-up.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
-
1/2
-
1/2
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache b/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache deleted file mode 100644 index d68fb4854..000000000 --- a/core/source/_patterns/01-molecules/01-layout/02-three-up.mustache +++ /dev/null @@ -1,8 +0,0 @@ -
- -
-
1/3
-
1/3
-
1/3
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache b/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache deleted file mode 100644 index f7351c023..000000000 --- a/core/source/_patterns/01-molecules/01-layout/03-four-up.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
- -
-
1/4
-
1/4
-
1/4
-
1/4
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache b/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache deleted file mode 100644 index 3262d382d..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/00-media-block.mustache +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache b/core/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache deleted file mode 100644 index 914580e31..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/01-headline-byline.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache b/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache deleted file mode 100644 index c685176f8..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/02-block-hero.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache b/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache deleted file mode 100644 index 4fbfa639c..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/03-block-thumb-headline.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache b/core/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache deleted file mode 100644 index 5a32707f3..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/04-headline-only.mustache +++ /dev/null @@ -1,5 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache b/core/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache deleted file mode 100644 index 45817ccf8..000000000 --- a/core/source/_patterns/01-molecules/02-blocks/05-inset-block.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache b/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache deleted file mode 100644 index 98e2b4435..000000000 --- a/core/source/_patterns/01-molecules/03-media/00-figure-with-caption.mustache +++ /dev/null @@ -1,4 +0,0 @@ -
- {{> atoms-landscape-4x3 }} -
This is an example of an image with a caption. Photo captions, also known as cutlines, are a few lines of text used to explain or elaborate on published photographs.
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/03-media/_map.mustache b/core/source/_patterns/01-molecules/03-media/_map.mustache deleted file mode 100644 index 9acb52b23..000000000 --- a/core/source/_patterns/01-molecules/03-media/_map.mustache +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/00-search.mustache b/core/source/_patterns/01-molecules/04-forms/00-search.mustache deleted file mode 100644 index 604b6125f..000000000 --- a/core/source/_patterns/01-molecules/04-forms/00-search.mustache +++ /dev/null @@ -1,11 +0,0 @@ -
-
- Search - - - -
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache b/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache deleted file mode 100644 index e4360727b..000000000 --- a/core/source/_patterns/01-molecules/04-forms/01-comment-form.mustache +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
- - -
-
- - -
-
- - -
-
- - -
-
-
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache b/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache deleted file mode 100644 index 041e2319e..000000000 --- a/core/source/_patterns/01-molecules/04-forms/02-newsletter.mustache +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache b/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache deleted file mode 100644 index 505ffa048..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/00-primary-nav.mustache +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache b/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache deleted file mode 100644 index d46a36b0c..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/01-footer-nav.mustache +++ /dev/null @@ -1,6 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache b/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache deleted file mode 100644 index 3b5c15351..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/02-breadcrumbs.mustache +++ /dev/null @@ -1,7 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache b/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache deleted file mode 100644 index 8b6de64a3..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/03-pagination.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
    -
  1. 1
  2. -
  3. 2
  4. -
  5. 3
  6. -
  7. 4
  8. -
  9. 5
  10. -
  11. 6
  12. -
  13. 7
  14. -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache b/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache deleted file mode 100644 index 8e4ec10e2..000000000 --- a/core/source/_patterns/01-molecules/05-navigation/04-tabs.mustache +++ /dev/null @@ -1,7 +0,0 @@ -
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/00-social-share.mustache b/core/source/_patterns/01-molecules/06-components/00-social-share.mustache deleted file mode 100644 index 120527d78..000000000 --- a/core/source/_patterns/01-molecules/06-components/00-social-share.mustache +++ /dev/null @@ -1,8 +0,0 @@ - \ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/01-accordion.mustache b/core/source/_patterns/01-molecules/06-components/01-accordion.mustache deleted file mode 100644 index 253962dcb..000000000 --- a/core/source/_patterns/01-molecules/06-components/01-accordion.mustache +++ /dev/null @@ -1,19 +0,0 @@ -
- -
\ No newline at end of file diff --git a/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache b/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache deleted file mode 100644 index a7f56279a..000000000 --- a/core/source/_patterns/01-molecules/06-components/02-single-comment.mustache +++ /dev/null @@ -1,9 +0,0 @@ -
  • -
    - {{> atoms-avatar }} -

    {{name.first}} {{name.last}}

    -
    -
    -

    {{description}}

    -
    -
  • \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/00-global/00-header.mustache b/core/source/_patterns/02-organisms/00-global/00-header.mustache deleted file mode 100644 index e4a73fb88..000000000 --- a/core/source/_patterns/02-organisms/00-global/00-header.mustache +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/00-global/01-footer.mustache b/core/source/_patterns/02-organisms/00-global/01-footer.mustache deleted file mode 100644 index 63f6fa5ef..000000000 --- a/core/source/_patterns/02-organisms/00-global/01-footer.mustache +++ /dev/null @@ -1,7 +0,0 @@ - -
    -
    - -
    -
    - \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/01-article/00-article-body.mustache b/core/source/_patterns/02-organisms/01-article/00-article-body.mustache deleted file mode 100644 index 7e95f0494..000000000 --- a/core/source/_patterns/02-organisms/01-article/00-article-body.mustache +++ /dev/null @@ -1,26 +0,0 @@ -

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer fringilla sem a urna porttitor fringilla. Nulla eget justo felis.

    - -

    Aliquam erat volutpat. Mauris vulputate scelerisque feugiat. Cras a erat a diam venenatis aliquam. Sed tempus, purus ac pretium varius, risus orci sagittis purus, quis auctor libero magna nec magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas eros dolor, rutrum eu sollicitudin eu, commodo at leo. Suspendisse potenti. Sed eu nibh sit amet quam auctor feugiat vel et risus. Maecenas eu urna adipiscing neque dictum mollis suscipit in augue. Praesent pulvinar condimentum sagittis. Maecenas laoreet neque non eros consectetur fringilla. Donec vitae risus leo, vitae pharetra ipsum. Sed placerat eros eget elit iaculis semper. Aliquam congue blandit orci ac pretium.

    - -{{> atoms-landscape-16x9 }} - -

    Aliquam ultrices cursus mauris, eget volutpat justo mattis nec. Sed a orci turpis. Aliquam aliquet placerat dui, consectetur tincidunt leo tristique et. Vivamus enim nisi, blandit a venenatis quis, convallis et arcu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris libero sapien, placerat in sodales eu, tempor quis dui. Vivamus egestas faucibus pulvinar. Maecenas eget diam nunc. Phasellus at sem eros, ac suscipit neque. Phasellus sollicitudin libero a odio dignissim scelerisque. Aliquam purus nulla, tempor eget ullamcorper quis, rhoncus non dui. -

    - -{{> atoms-blockquote }} - -

    Cras at fringilla ipsum. Donec nec libero eget est blandit dignissim a eu ante. Morbi augue nulla, luctus eu sagittis vel, malesuada ut felis. Aliquam erat volutpat. Morbi malesuada augue ac massa hendrerit fermentum. Integer scelerisque lacus a dolor convallis lobortis. Curabitur mollis ante in massa ultricies dignissim. -

    - -{{> atoms-unordered }} - -{{> atoms-ordered }} - -

    Donec posuere fringilla nunc, vitae venenatis diam scelerisque vel. Nullam vitae mauris magna. Mauris et diam quis justo volutpat tincidunt congue nec magna. Curabitur vitae orci elit. Ut mollis massa id magna vestibulum consequat. Proin rutrum lectus justo, sit amet tincidunt est. Vivamus vitae lacinia risus. -

    - -{{> molecules-pullquote }} - -

    Donec venenatis imperdiet tortor, vitae blandit odio interdum ut. Integer orci metus, lobortis id lacinia eget, rutrum vitae justo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In pretium fermentum justo nec pharetra. Maecenas eget dapibus justo. Ut quis est risus. Nullam et eros at odio commodo venenatis quis et augue. Sed sed augue at tortor porttitor hendrerit nec ut nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin sollicitudin enim consectetur mi commodo quis cursus ante pretium. Nunc gravida cursus nisi in gravida. Suspendisse eget tortor sed urna consequat tincidunt. Etiam eget convallis lectus. Suspendisse cursus rutrum massa ac faucibus. -

    -

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis, suscipit repellendus nulla accusantium deserunt sed explicabo voluptate sapiente ratione inventore molestiae nihil earum repellat quia odit vitae perspiciatis aliquam amet?

    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache b/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache deleted file mode 100644 index 6e150a137..000000000 --- a/core/source/_patterns/02-organisms/02-comments/00-comment-thread.mustache +++ /dev/null @@ -1,12 +0,0 @@ -
    -
    -

    59 Comments

    - {{> molecules-comment-form }} -
      - {{#listItems.five}} - {{> molecules-single-comment }} - {{/listItems.five}} -
    -
    - {{> molecules-pagination }} -
    \ No newline at end of file diff --git a/core/source/_patterns/02-organisms/03-components/00-carousel.mustache b/core/source/_patterns/02-organisms/03-components/00-carousel.mustache deleted file mode 100644 index 4e8641ec8..000000000 --- a/core/source/_patterns/02-organisms/03-components/00-carousel.mustache +++ /dev/null @@ -1,10 +0,0 @@ -