├── .rvmrc ├── public ├── min │ ├── builder │ │ ├── rewriteTest.js │ │ ├── bm2.js │ │ ├── ocCheck.php │ │ ├── bm.js │ │ └── test.php │ ├── .htaccess │ ├── groupsConfig.php │ ├── lib │ │ ├── Minify │ │ │ ├── Packer.php │ │ │ ├── Logger.php │ │ │ ├── Controller │ │ │ │ ├── Files.php │ │ │ │ ├── Page.php │ │ │ │ ├── Groups.php │ │ │ │ ├── Version1.php │ │ │ │ ├── MinApp.php │ │ │ │ └── Base.php │ │ │ ├── CommentPreserver.php │ │ │ ├── Build.php │ │ │ ├── CSS.php │ │ │ ├── Cache │ │ │ │ ├── APC.php │ │ │ │ ├── Memcache.php │ │ │ │ └── File.php │ │ │ ├── YUICompressor.php │ │ │ ├── Lines.php │ │ │ ├── ImportProcessor.php │ │ │ ├── Source.php │ │ │ ├── HTML │ │ │ │ └── Helper.php │ │ │ └── HTML.php │ │ └── Solar │ │ │ └── Dir.php │ ├── index.php │ ├── utils.php │ ├── README.txt │ └── config.php ├── images │ ├── _.gif │ ├── bg.jpg │ ├── jason.jpg │ ├── logo.png │ ├── icon-rss.png │ ├── loading.gif │ ├── postmark.jpg │ ├── icon-about.png │ ├── icon-play.png │ ├── icon-rdio.png │ ├── icon-work.png │ ├── logo-sass.png │ ├── mail-slot.png │ ├── html5-badge.png │ ├── icon-colophon.png │ ├── icon-contact.png │ ├── icon-dribbble.png │ ├── icon-external.png │ ├── icon-flickr.png │ ├── icon-github.png │ ├── icon-lastfm.png │ ├── icon-lovedsgn.png │ ├── icon-mlkshk.png │ ├── icon-pinboard.png │ ├── icon-shelfari.png │ ├── icon-twitter.png │ ├── logo-lifetree.png │ ├── logo-mootools.png │ ├── logo-pictos.png │ ├── logo-stacey.png │ ├── logo-typekit.png │ ├── ss_nav_next.png │ ├── icon-goodreads.png │ ├── icon-instagram.png │ ├── logo-modernizr.png │ ├── ss_nav_previous.png │ ├── logo-asmallorange.png │ └── texture-envelope.jpg ├── 404.html ├── php │ └── contact.php └── docs │ ├── css │ └── reset.css │ └── js │ ├── modernizr-1.6.min.js │ ├── modernizr-2.0.min.js │ └── Carousel.js ├── sass-watch ├── favicon.ico ├── content ├── 1.index │ └── index.txt ├── 3.play │ ├── play.txt │ ├── 1.domo │ │ ├── 01.png │ │ └── play.txt │ ├── zen-signup │ │ ├── 01.png │ │ └── play.txt │ ├── 4.rdio-concept │ │ ├── 01.png │ │ └── play.txt │ ├── 5.benfords-law │ │ ├── 01.png │ │ └── play.txt │ ├── multi-select │ │ ├── 01.png │ │ └── play.txt │ └── 2.metal-toggle-switches │ │ ├── 01.png │ │ └── play.txt ├── 2.work │ ├── projects.txt │ ├── 13.git │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── thumb.png │ │ └── project.txt │ ├── 6.legalpm │ │ ├── 01.jpg │ │ ├── 02.png │ │ ├── 03.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── 7.cobra │ │ ├── 01.jpg │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.png │ │ ├── 07.jpg │ │ ├── thumb.jpg │ │ └── project.txt │ ├── connect │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── contegix │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── 10.slipware │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── thumb.jpg │ │ └── project.txt │ ├── reviewshine │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── thumb.jpg │ │ └── project.txt │ ├── 11.mindleaders │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── 05.jpg │ │ ├── thumb.jpg │ │ └── project.txt │ ├── 5.run-code-run │ │ ├── 01.jpg │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ ├── 05.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── 8.spring-metrics │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── 9.verizon-veris │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── security-ninjas │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── thumb.png │ │ └── project.txt │ ├── 12.inside-tracker │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── 04.jpg │ │ ├── 05.jpg │ │ ├── thumb.png │ │ └── project.txt │ └── sustainable-harvest │ │ ├── 01.jpg │ │ ├── 02.jpg │ │ ├── 03.jpg │ │ ├── thumb.jpg │ │ └── project.txt └── _shared.txt ├── .gitignore ├── Capfile ├── templates ├── project.json └── projects.json ├── config ├── settings.example.php └── deploy.rb ├── index.php ├── app ├── asset-types │ ├── html.inc.php │ ├── video.inc.php │ ├── asset.inc.php │ ├── image.inc.php │ ├── asset-factory.inc.php │ └── page.inc.php ├── parsers │ └── json-minifier.inc.php ├── cache.inc.php ├── stacey.inc.php └── helpers.inc.php ├── LICENSE ├── .htaccess └── README.md /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm use ruby-1.9.2-p136 2 | -------------------------------------------------------------------------------- /public/min/builder/rewriteTest.js: -------------------------------------------------------------------------------- 1 | 1 -------------------------------------------------------------------------------- /sass-watch: -------------------------------------------------------------------------------- 1 | sass --watch public/docs/css/sass:public/docs/css 2 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/favicon.ico -------------------------------------------------------------------------------- /content/1.index/index.txt: -------------------------------------------------------------------------------- 1 | title: Black Ant Media 2 | 3 | page_description: Porfolio of Jason Long -------------------------------------------------------------------------------- /content/3.play/play.txt: -------------------------------------------------------------------------------- 1 | title: Black Ant Media 2 | 3 | page_description: Porfolio of Jason Long -------------------------------------------------------------------------------- /content/2.work/projects.txt: -------------------------------------------------------------------------------- 1 | title: Black Ant Media 2 | 3 | page_description: Porfolio of Jason Long -------------------------------------------------------------------------------- /content/_shared.txt: -------------------------------------------------------------------------------- 1 | name: Name 2 | 3 | profession: Graphic Designer 4 | 5 | email: hi@yourdomain.com -------------------------------------------------------------------------------- /public/images/_.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/_.gif -------------------------------------------------------------------------------- /public/images/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/bg.jpg -------------------------------------------------------------------------------- /public/images/jason.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/jason.jpg -------------------------------------------------------------------------------- /public/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo.png -------------------------------------------------------------------------------- /public/images/icon-rss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-rss.png -------------------------------------------------------------------------------- /public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/loading.gif -------------------------------------------------------------------------------- /public/images/postmark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/postmark.jpg -------------------------------------------------------------------------------- /content/2.work/13.git/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/01.png -------------------------------------------------------------------------------- /content/2.work/13.git/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/02.png -------------------------------------------------------------------------------- /content/2.work/13.git/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/03.png -------------------------------------------------------------------------------- /content/2.work/13.git/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/04.png -------------------------------------------------------------------------------- /content/2.work/13.git/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/05.png -------------------------------------------------------------------------------- /content/3.play/1.domo/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/1.domo/01.png -------------------------------------------------------------------------------- /public/images/icon-about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-about.png -------------------------------------------------------------------------------- /public/images/icon-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-play.png -------------------------------------------------------------------------------- /public/images/icon-rdio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-rdio.png -------------------------------------------------------------------------------- /public/images/icon-work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-work.png -------------------------------------------------------------------------------- /public/images/logo-sass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-sass.png -------------------------------------------------------------------------------- /public/images/mail-slot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/mail-slot.png -------------------------------------------------------------------------------- /content/2.work/13.git/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/13.git/thumb.png -------------------------------------------------------------------------------- /content/2.work/6.legalpm/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/6.legalpm/01.jpg -------------------------------------------------------------------------------- /content/2.work/6.legalpm/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/6.legalpm/02.png -------------------------------------------------------------------------------- /content/2.work/6.legalpm/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/6.legalpm/03.jpg -------------------------------------------------------------------------------- /content/2.work/7.cobra/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/01.jpg -------------------------------------------------------------------------------- /content/2.work/7.cobra/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/02.png -------------------------------------------------------------------------------- /content/2.work/7.cobra/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/03.png -------------------------------------------------------------------------------- /content/2.work/7.cobra/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/04.png -------------------------------------------------------------------------------- /content/2.work/7.cobra/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/05.png -------------------------------------------------------------------------------- /content/2.work/7.cobra/07.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/07.jpg -------------------------------------------------------------------------------- /content/2.work/connect/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/connect/01.jpg -------------------------------------------------------------------------------- /content/2.work/connect/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/connect/02.jpg -------------------------------------------------------------------------------- /content/2.work/connect/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/connect/03.jpg -------------------------------------------------------------------------------- /content/2.work/connect/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/connect/04.jpg -------------------------------------------------------------------------------- /content/2.work/contegix/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/contegix/01.jpg -------------------------------------------------------------------------------- /content/2.work/contegix/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/contegix/02.jpg -------------------------------------------------------------------------------- /content/2.work/contegix/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/contegix/03.jpg -------------------------------------------------------------------------------- /content/2.work/contegix/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/contegix/04.jpg -------------------------------------------------------------------------------- /public/images/html5-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/html5-badge.png -------------------------------------------------------------------------------- /public/images/icon-colophon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-colophon.png -------------------------------------------------------------------------------- /public/images/icon-contact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-contact.png -------------------------------------------------------------------------------- /public/images/icon-dribbble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-dribbble.png -------------------------------------------------------------------------------- /public/images/icon-external.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-external.png -------------------------------------------------------------------------------- /public/images/icon-flickr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-flickr.png -------------------------------------------------------------------------------- /public/images/icon-github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-github.png -------------------------------------------------------------------------------- /public/images/icon-lastfm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-lastfm.png -------------------------------------------------------------------------------- /public/images/icon-lovedsgn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-lovedsgn.png -------------------------------------------------------------------------------- /public/images/icon-mlkshk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-mlkshk.png -------------------------------------------------------------------------------- /public/images/icon-pinboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-pinboard.png -------------------------------------------------------------------------------- /public/images/icon-shelfari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-shelfari.png -------------------------------------------------------------------------------- /public/images/icon-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-twitter.png -------------------------------------------------------------------------------- /public/images/logo-lifetree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-lifetree.png -------------------------------------------------------------------------------- /public/images/logo-mootools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-mootools.png -------------------------------------------------------------------------------- /public/images/logo-pictos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-pictos.png -------------------------------------------------------------------------------- /public/images/logo-stacey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-stacey.png -------------------------------------------------------------------------------- /public/images/logo-typekit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-typekit.png -------------------------------------------------------------------------------- /public/images/ss_nav_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/ss_nav_next.png -------------------------------------------------------------------------------- /content/2.work/10.slipware/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/10.slipware/01.jpg -------------------------------------------------------------------------------- /content/2.work/10.slipware/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/10.slipware/02.jpg -------------------------------------------------------------------------------- /content/2.work/10.slipware/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/10.slipware/03.jpg -------------------------------------------------------------------------------- /content/2.work/7.cobra/thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/7.cobra/thumb.jpg -------------------------------------------------------------------------------- /content/2.work/connect/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/connect/thumb.png -------------------------------------------------------------------------------- /content/2.work/contegix/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/contegix/thumb.png -------------------------------------------------------------------------------- /content/2.work/reviewshine/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/reviewshine/01.jpg -------------------------------------------------------------------------------- /content/2.work/reviewshine/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/reviewshine/02.jpg -------------------------------------------------------------------------------- /content/2.work/reviewshine/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/reviewshine/03.jpg -------------------------------------------------------------------------------- /content/3.play/zen-signup/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/zen-signup/01.png -------------------------------------------------------------------------------- /public/images/icon-goodreads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-goodreads.png -------------------------------------------------------------------------------- /public/images/icon-instagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/icon-instagram.png -------------------------------------------------------------------------------- /public/images/logo-modernizr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-modernizr.png -------------------------------------------------------------------------------- /public/images/ss_nav_previous.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/ss_nav_previous.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | app/_cache/ 2 | app/cache/ 3 | .DS_Store 4 | config/settings.php 5 | .sass-cache/ 6 | mkmf.log 7 | .ruby-version 8 | 9 | -------------------------------------------------------------------------------- /content/2.work/10.slipware/thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/10.slipware/thumb.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/01.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/02.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/03.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/04.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/05.jpg -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/01.jpg -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/02.png -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/03.png -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/04.png -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/05.jpg -------------------------------------------------------------------------------- /content/2.work/6.legalpm/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/6.legalpm/thumb.png -------------------------------------------------------------------------------- /content/2.work/reviewshine/thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/reviewshine/thumb.jpg -------------------------------------------------------------------------------- /content/3.play/4.rdio-concept/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/4.rdio-concept/01.png -------------------------------------------------------------------------------- /content/3.play/5.benfords-law/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/5.benfords-law/01.png -------------------------------------------------------------------------------- /content/3.play/multi-select/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/multi-select/01.png -------------------------------------------------------------------------------- /public/images/logo-asmallorange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/logo-asmallorange.png -------------------------------------------------------------------------------- /public/images/texture-envelope.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/public/images/texture-envelope.jpg -------------------------------------------------------------------------------- /content/2.work/8.spring-metrics/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/8.spring-metrics/01.jpg -------------------------------------------------------------------------------- /content/2.work/8.spring-metrics/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/8.spring-metrics/02.jpg -------------------------------------------------------------------------------- /content/2.work/8.spring-metrics/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/8.spring-metrics/03.jpg -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/9.verizon-veris/01.jpg -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/9.verizon-veris/02.jpg -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/9.verizon-veris/03.jpg -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/9.verizon-veris/04.jpg -------------------------------------------------------------------------------- /content/2.work/security-ninjas/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/security-ninjas/01.jpg -------------------------------------------------------------------------------- /content/2.work/security-ninjas/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/security-ninjas/02.jpg -------------------------------------------------------------------------------- /content/2.work/security-ninjas/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/security-ninjas/03.jpg -------------------------------------------------------------------------------- /content/2.work/security-ninjas/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/security-ninjas/04.jpg -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/11.mindleaders/thumb.jpg -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/12.inside-tracker/02.jpg -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/12.inside-tracker/03.jpg -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/12.inside-tracker/04.jpg -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/05.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/12.inside-tracker/05.jpg -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/5.run-code-run/thumb.png -------------------------------------------------------------------------------- /content/2.work/8.spring-metrics/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/8.spring-metrics/thumb.png -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/9.verizon-veris/thumb.png -------------------------------------------------------------------------------- /content/2.work/security-ninjas/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/security-ninjas/thumb.png -------------------------------------------------------------------------------- /content/2.work/sustainable-harvest/01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/sustainable-harvest/01.jpg -------------------------------------------------------------------------------- /content/2.work/sustainable-harvest/02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/sustainable-harvest/02.jpg -------------------------------------------------------------------------------- /content/2.work/sustainable-harvest/03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/sustainable-harvest/03.jpg -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/12.inside-tracker/thumb.png -------------------------------------------------------------------------------- /content/2.work/sustainable-harvest/thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/2.work/sustainable-harvest/thumb.jpg -------------------------------------------------------------------------------- /content/3.play/2.metal-toggle-switches/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonlong/blackantmedia/master/content/3.play/2.metal-toggle-switches/01.png -------------------------------------------------------------------------------- /content/3.play/1.domo/play.txt: -------------------------------------------------------------------------------- 1 | title: Pure CSS Domo 2 | - 3 | link: http://concepts.blackantmedia.com/domo/ 4 | - 5 | description: A Domo made entirely out of Unicode characters and CSS. 6 | -------------------------------------------------------------------------------- /content/3.play/zen-signup/play.txt: -------------------------------------------------------------------------------- 1 | title: Zen Signup 2 | - 3 | link: http://lovedsgn.com/post/1698 4 | - 5 | description: A simple sigup form concept playing with glass and transparency. 6 | -------------------------------------------------------------------------------- /content/3.play/4.rdio-concept/play.txt: -------------------------------------------------------------------------------- 1 | title: Rdio Search Concept 2 | - 3 | link: http://dribbble.com/shots/66019-Rdio-Search-Concept 4 | - 5 | description: A Dribbble rebound of Adam Polselli's mockup. 6 | -------------------------------------------------------------------------------- /content/3.play/2.metal-toggle-switches/play.txt: -------------------------------------------------------------------------------- 1 | title: Metal Toggle Switches 2 | - 3 | link: http://dribbble.com/shots/114849-Toggle-Switches 4 | - 5 | description: Sometimes you just need a beefier switch. 6 | -------------------------------------------------------------------------------- /content/3.play/5.benfords-law/play.txt: -------------------------------------------------------------------------------- 1 | title: Testing Benford's Law 2 | - 3 | link: http://testingbenfordslaw.com 4 | - 5 | description: An open source experiment testing this odd law with public datasets. 6 | -------------------------------------------------------------------------------- /content/3.play/multi-select/play.txt: -------------------------------------------------------------------------------- 1 | title: Multi-select Dropdown Lists 2 | - 3 | link: http://sntf.blackantmedia.com/multiselect/ 4 | - 5 | description: A sample of the custom dropdowns used in the Verizon project. 6 | -------------------------------------------------------------------------------- /Capfile: -------------------------------------------------------------------------------- 1 | load 'deploy' if respond_to?(:namespace) # cap2 differentiator 2 | Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } 3 | 4 | load 'config/deploy' # remove this line to skip loading any of the default tasks -------------------------------------------------------------------------------- /templates/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "@title", 3 | "services": "@services", 4 | "description": "@description", 5 | "images": [ 6 | foreach $images do 7 | {"url": "@url", "name": "@name"}, 8 | endforeach 9 | ], 10 | } 11 | -------------------------------------------------------------------------------- /config/settings.example.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /templates/projects.json: -------------------------------------------------------------------------------- 1 | { 2 | if $children do 3 | "projects": [ 4 | foreach $children do 5 | { 6 | "title": "@title", 7 | "thumb": "@thumb", 8 | "title": "@title", 9 | "url": "@url" 10 | } 11 | if !@is_last do 12 | , 13 | endif 14 | endforeach 15 | ] 16 | endif 17 | } 18 | -------------------------------------------------------------------------------- /public/min/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine on 3 | 4 | # You may need RewriteBase on some servers 5 | #RewriteBase /min 6 | 7 | # rewrite URLs like "/min/f=..." to "/min/?f=..." 8 | RewriteRule ^([bfg]=.*) index.php?$1 [L,NE] 9 | 10 | 11 | # In case AddOutputFilterByType has been added 12 | SetEnv no-gzip 13 | 14 | -------------------------------------------------------------------------------- /content/2.work/13.git/project.txt: -------------------------------------------------------------------------------- 1 | title: Git 2 | - 3 | services: Logo Design / UI Design / HTML / CSS / Javascript 4 | - 5 | description: I created an updated identity and web presence for the Git version control system. Working with a small team from GitHub, we created a new site that houses documentation, downloads, screencasts, and the entire Pro Git book. The logo and all of the other graphical assets I created are Creative Commons-licensed. 6 | -------------------------------------------------------------------------------- /content/2.work/6.legalpm/project.txt: -------------------------------------------------------------------------------- 1 | title: LegalPM 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: LegalPM (since renamed Onit) is a project management and collaboration tool for lawyers. Users are able to organize their legal cases, track documents and tasks, and watch budgets. I designed and built the screens for this previous version of the application including a simplified navigation/search bar, overhauled dashboard, and project detail page. -------------------------------------------------------------------------------- /content/2.work/5.run-code-run/project.txt: -------------------------------------------------------------------------------- 1 | title: Run Code Run 2 | - 3 | services: UI Design 4 | - 5 | description: Run Code Run was a hosted continuous integration product Relevance built and operated but decided to shut down recently. Before that decision, they asked me to put together some concepts for a possible redesign. These screens show some of these ideas: the build state (pass/fail) of the user's projects, dashboard overview, and project detail page. -------------------------------------------------------------------------------- /content/2.work/security-ninjas/project.txt: -------------------------------------------------------------------------------- 1 | title: Security Ninjas 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: Security Ninjas is an interesting site that allows people responsible for websites to hire an expert to perform security audits. They maintain relationships with many high-caliber security experts and audits can be basic or in-depth depending on budgets and timeframes. I designed and built the initial templates for the site, including dashboard, project activity, and project creation pages. -------------------------------------------------------------------------------- /content/2.work/11.mindleaders/project.txt: -------------------------------------------------------------------------------- 1 | title: MindLeaders-ThirdForce 2 | - 3 | services: UI Design 4 | - 5 | description: MindLeaders-ThirdForce is an industry leader in e-learning, but their courseware interface was beginning to look dated. I helped establish a refreshed visual style to help ensure that the courseware itself didn't compete for attention next to the numerous UI tools. Contraints have a tendency to bring out the best designs, and I enjoyed the challenge of integrating a large number of features into a fixed window resolution. 6 | -------------------------------------------------------------------------------- /content/2.work/12.inside-tracker/project.txt: -------------------------------------------------------------------------------- 1 | title: InsideTracker 2 | - 3 | services: UI Design 4 | - 5 | description: InsideTracker is a sophisticated personal health assessment tool. Users have their blood drawn at regular intervals and then receive detailed analyses about their body's biomarkers and an optimzed eating plan for making improvements. I worked with the team at Innvolution Studios to come up with ideas for displaying large amounts of complex nutritional information in a friendly and easy to \"digest\" way. 6 | -------------------------------------------------------------------------------- /content/2.work/connect/project.txt: -------------------------------------------------------------------------------- 1 | title: Connect for Healthcare 2 | - 3 | services: UI Design / HTML / CSS / Javascript / Ruby on Rails 4 | - 5 | description: Connect for Healthcare is a service that allows long-term care providers to send updates (email and text messages) to loved-ones. Family members choose which \"wellness metrics\" they wish to be informed about and providers have a simple interface for entering updates. I am a partner in the business and have designed and built the entire application, including the HTML, CSS, jQuery, and Rails back-end. -------------------------------------------------------------------------------- /content/2.work/reviewshine/project.txt: -------------------------------------------------------------------------------- 1 | title: ReviewShine 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: ReviewShine is a popular site for musicians and music reviewers. Musicians can get away from the hassle of sending CDs to reviewers and hoping one of them will publish a review. With ReviewShine, they simply upload digital copies of their works and large pool of reviewers can see all of the submissions at a glance. I gave the site a fresh coat of pixels and markup to bring the visual design up to snuff with the great application under the hood. -------------------------------------------------------------------------------- /content/2.work/8.spring-metrics/project.txt: -------------------------------------------------------------------------------- 1 | title: Spring Metrics 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: Spring Metrics is a new startup with a new spin on web analytics. Their service provides a friendly and easy to use SpringBox widget that is used to tag buttons, links, and pages for later conversion analysis. I was given a logo and used that as the starting point for the app's visual design. I then built clean HTML5 and CSS templates they could take and run with to bring the rest of the site to life. The SpringBox widget is designed to work well on either light or dark sites. -------------------------------------------------------------------------------- /public/min/builder/bm2.js: -------------------------------------------------------------------------------- 1 | javascript:(function(){ 2 | var d = document 3 | ,c = d.cookie 4 | ,m = c.match(/\bminDebug=([^; ]+)/) 5 | ,v = m ? decodeURIComponent(m[1]) : '' 6 | ,p = prompt('Debug Minify URIs on ' + location.hostname + ' which contain:' 7 | + '\n(empty for none, space = OR)', v) 8 | ; 9 | if (p === null) return; 10 | p = p.replace(/^\s+|\s+$/, ''); 11 | v = (p === '') 12 | ? 'minDebug=; expires=Fri, 27 Jul 2001 02:47:11 UTC; path=/' 13 | : 'minDebug=' + encodeURIComponent(p) + '; path=/'; 14 | d.cookie = v; 15 | })(); -------------------------------------------------------------------------------- /content/2.work/contegix/project.txt: -------------------------------------------------------------------------------- 1 | title: Contegix Cloud Panel 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: Contegix is one of the top hosting companies I've ever worked with. I learned about their legendary support during this project and became a paying customer shortly thereafter. They recently unveiled their new cloud service and I designed and built the UI that sits on top of the amazing work Relevance did on the back-end. Customers can create new virtual machines, specifying their preferred Linux distribution and specs, and power them on and off as needed. -------------------------------------------------------------------------------- /content/2.work/7.cobra/project.txt: -------------------------------------------------------------------------------- 1 | title: Project: Cobra 2 | - 3 | services: UI Design / HTML / CSS / Javascript / Ruby on Rails 4 | - 5 | description: I'm not yet allowed to identify this client, but I'm allowed to show a few screenshots. Cobra is a tool used for collecting research data from participants. The researchers can create fully custom \"homework assignments\" with both traditional-style survey questions and some custom ones as well. I've been responsible for the entire design and development of this application, from the initial UI design concepts to the HTML5, CSS (Sass), heavy AJAX/jQuery front-end, and Rails 3 back-end. 6 | -------------------------------------------------------------------------------- /content/2.work/9.verizon-veris/project.txt: -------------------------------------------------------------------------------- 1 | title: Verizon VERIS 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: VERIS is a Verizon Business initiative that allows security experts to anonymously report incidents. This information can then be compared with the community dataset so that better risk management decisions can be made. The multi-step wizard-style interface is implemented entirely in client-side Javascript, including many dynamic elements. I designed and implemented the user interface and jQuery code for VERIS while Relevance handled the heavy-lifting on the backend. 6 | -------------------------------------------------------------------------------- /content/2.work/sustainable-harvest/project.txt: -------------------------------------------------------------------------------- 1 | title: Sustainable Harvest 2 | - 3 | services: UI Design / HTML / CSS / Javascript 4 | - 5 | description: Sustainable Harvest is a very interesting organization that imports speciality coffee and manages the relationships of the entire supply chain, from farmer to end customer. I worked with Relevance again on multiple projects for this client and I was tasked with designing interfaces for the workflow management as well as for cupping sessions. The workflow portion is especially interesting because it is used in the field at washing stations and dry mills in Tanzania and other countries. -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | Stacey requires PHP/5.0 or higher.
You are currently running PHP/'.phpversion().'.

You should contact your host to see if they can upgrade your version of PHP.

'); 7 | 8 | } else { 9 | 10 | # require helpers class so we can use rglob 11 | require_once './app/helpers.inc.php'; 12 | # include any php files which sit in the app folder 13 | foreach(Helpers::rglob('./app/**.inc.php') as $include) include_once $include; 14 | 15 | # start the app 16 | new Stacey($_GET); 17 | 18 | } 19 | 20 | ?> -------------------------------------------------------------------------------- /content/2.work/10.slipware/project.txt: -------------------------------------------------------------------------------- 1 | title: AppAnalyzer by Slipware 2 | - 3 | services: UI Design / Visual Design Direction 4 | - 5 | description: AppAnalyzer is an iPad application that allows developers to visualize usage statistics for their software using the Flurry Analytics engine. Slipware approached me and asked if I could help create a sleek UI design to replace their working development interface. I created Photoshop mockups and Slipware did a great job incorporating everything into the app. AppAnalyzer is now available in the App Store. 6 | -------------------------------------------------------------------------------- /public/min/groupsConfig.php: -------------------------------------------------------------------------------- 1 | array( 16 | '//public/docs/js/site.js', 17 | '//public/docs/js/mootools-more.js', 18 | '//public/docs/js/modernizr-2.0.min.js' 19 | ), 20 | 21 | 'css' => array( 22 | '//public/docs/css/reset.css', 23 | '//public/docs/css/screen.css' 24 | ) 25 | ); 26 | -------------------------------------------------------------------------------- /app/asset-types/html.inc.php: -------------------------------------------------------------------------------- 1 | set_extended_data($file_path); 12 | } 13 | 14 | function set_extended_data($file_path) { 15 | if(is_readable($file_path)) { 16 | ob_start(); 17 | include $file_path; 18 | $this->data['@content'] = ob_get_contents(); 19 | ob_end_clean(); 20 | } else { 21 | $this->data['@content'] = ''; 22 | } 23 | } 24 | 25 | } 26 | 27 | ?> -------------------------------------------------------------------------------- /app/asset-types/video.inc.php: -------------------------------------------------------------------------------- 1 | set_extended_data($file_path); 12 | } 13 | 14 | function set_extended_data($file_path) { 15 | if(preg_match('/(\d+?)x(\d+?)\./', $this->file_name, $matches)) $dimensions = array('width' => $matches[1], 'height' => $matches[2]); 16 | else $dimensions = array('width' => '', 'height' => ''); 17 | $this->data['@width'] = $dimensions['width']; 18 | $this->data['@height'] = $dimensions['height']; 19 | } 20 | 21 | } 22 | 23 | ?> -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | Page not found (404) 7 | 8 | 15 | 16 | 17 |
18 |

404

19 |

Page could not be found.

20 |

Unfortunately, the page you were looking for does not exist here.

21 |

← Index

22 |
23 | 24 | -------------------------------------------------------------------------------- /public/min/builder/ocCheck.php: -------------------------------------------------------------------------------- 1 | 'World!' 27 | ,'method' => 'deflate' 28 | )); 29 | $he->encode(); 30 | $he->sendAll(); 31 | 32 | } else { 33 | // echo status "0" or "1" 34 | header('Content-Type: text/plain'); 35 | echo (int)$_oc; 36 | } 37 | -------------------------------------------------------------------------------- /config/deploy.rb: -------------------------------------------------------------------------------- 1 | load 'deploy' if respond_to?(:namespace) # cap2 differentiator 2 | Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) } 3 | 4 | set :use_sudo, false 5 | #set :home_path, "/var/www/mysitename" 6 | set :scm, :git 7 | set :repository, "git@github.com:jasonlong/blackantmedia.git" 8 | set(:current_branch) { `git branch`.match(/\* (\S+)\s/m)[1] || raise("Couldn't determine current branch") } 9 | set :branch, defer { current_branch } 10 | set :repository_cache, "git_cache" 11 | set :deploy_via, :remote_cache 12 | set :deploy_to, "/home/blackant/blackantmedia" 13 | role :web, "blackant" 14 | 15 | 16 | namespace :deploy do 17 | task :restart do 18 | symlink_settings 19 | cleanup 20 | end 21 | end 22 | 23 | task :symlink_settings do 24 | run <<-CMD 25 | rm -rf #{release_path}/config/settings.php && 26 | ln -nfs #{shared_path}/settings.php #{release_path}/config/settings.php 27 | CMD 28 | end 29 | 30 | -------------------------------------------------------------------------------- /app/asset-types/asset.inc.php: -------------------------------------------------------------------------------- 1 | set_default_data($file_path); 13 | } 14 | 15 | function construct_link_path($file_path) { 16 | return preg_replace('/^\.\//', Helpers::relative_root_path(), $file_path); 17 | } 18 | 19 | function set_default_data($file_path) { 20 | # store link path 21 | $this->link_path = $this->construct_link_path($file_path); 22 | 23 | # extract filename from path 24 | $split_path = explode('/', $file_path); 25 | $this->file_name = array_pop($split_path); 26 | 27 | # set @url & @name variables 28 | $this->data['@url'] = $this->link_path; 29 | $this->data['@file_name'] = $this->file_name; 30 | $this->data['@name'] = ucfirst(preg_replace(array('/[-_]/', '/\.[\w\d]+?$/', '/^\d+?\./'), array(' ', '', ''), $this->file_name)); 31 | } 32 | 33 | } 34 | 35 | ?> -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Anthony Kolber 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /public/min/lib/Minify/Packer.php: -------------------------------------------------------------------------------- 1 | pack()); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Logger.php: -------------------------------------------------------------------------------- 1 | 12 | * 13 | * @todo lose this singleton! pass log object in Minify::serve and distribute to others 14 | */ 15 | class Minify_Logger { 16 | 17 | /** 18 | * Set logger object. 19 | * 20 | * The object should have a method "log" that accepts a value as 1st argument and 21 | * an optional string label as the 2nd. 22 | * 23 | * @param mixed $obj or a "falsey" value to disable 24 | * @return null 25 | */ 26 | public static function setLogger($obj = null) { 27 | self::$_logger = $obj 28 | ? $obj 29 | : null; 30 | } 31 | 32 | /** 33 | * Pass a message to the logger (if set) 34 | * 35 | * @param string $msg message to log 36 | * @return null 37 | */ 38 | public static function log($msg, $label = 'Minify') { 39 | if (! self::$_logger) return; 40 | self::$_logger->log($msg, $label); 41 | } 42 | 43 | /** 44 | * @var mixed logger object (like FirePHP) or null (i.e. no logger available) 45 | */ 46 | private static $_logger = null; 47 | } 48 | -------------------------------------------------------------------------------- /public/php/contact.php: -------------------------------------------------------------------------------- 1 | setCommentAuthor($name); 16 | $akismet->setCommentAuthorEmail($email); 17 | $akismet->setCommentContent($message); 18 | $akismet->setUserIP($ip); 19 | 20 | if (send_mail( $name, $email, $ip, $akismet->isCommentSpam(), $message)) { 21 | $status = array('code' => '1'); 22 | } 23 | else { 24 | $status = array('code' => '0'); 25 | } 26 | echo json_encode($status); 27 | } 28 | 29 | function send_mail( $name, $email, $ip, $is_spam, $message) { 30 | $subject = ''; 31 | if( $is_spam == false && empty($name) == false && empty($email) == false ) { 32 | $subject = $GLOBALS['CONTACT_SUBJECT']; 33 | 34 | $smtp = new SMTP($GLOBALS['SMTP_SERVER'], $GLOBALS['SMTP_PORT']); 35 | $smtp->mail_from($email); 36 | return $smtp->send($GLOBALS['CONTACT_RECIPIENT'], $subject, "Name: ".$name."\n\n".stripslashes($message)); 37 | } 38 | else return true; 39 | } 40 | ?> 41 | -------------------------------------------------------------------------------- /.htaccess: -------------------------------------------------------------------------------- 1 | RewriteEngine on 2 | 3 | # Some hosts require a rewritebase rule, if so, uncomment the RewriteBase line below. If you are running from a subdirectory, your rewritebase should match the name of the path to where stacey is stored. 4 | # ie. if in a folder named 'stacey', RewriteBase /stacey 5 | #RewriteBase / 6 | 7 | ErrorDocument 404 /404.html 8 | 9 | # Rewrite any calls to *.html, *.json, *.xml, *.atom, *.rss, *.rdf or *.txt if a folder matching * exists 10 | RewriteCond %{REQUEST_FILENAME} !-f 11 | RewriteCond %{REQUEST_URI} !public/ 12 | RewriteCond %{DOCUMENT_ROOT}/public/$1.$2 !-f 13 | RewriteRule (.+)\.(html|json|xml|atom|rss|rdf|txt)$ $1/ [L] 14 | 15 | # Add a trailing slash to directories 16 | RewriteCond %{REQUEST_FILENAME} !-f 17 | RewriteCond %{REQUEST_FILENAME} !-d 18 | RewriteCond %{REQUEST_URI} !(\.) 19 | RewriteCond %{REQUEST_URI} !(.*)/$ 20 | RewriteRule ([^/]+)$ $1/ [L] 21 | 22 | # Rewrite any calls to /* or /app to the index.php file 23 | RewriteCond %{REQUEST_URI} /app/$ 24 | RewriteRule ^app/ index.php [L] 25 | RewriteCond %{REQUEST_FILENAME} !-f 26 | RewriteCond %{REQUEST_FILENAME} !-d 27 | RewriteRule ^(.*)/$ index.php?$1 [L] 28 | 29 | # Rewrite any file calls to the public directory 30 | RewriteCond %{REQUEST_FILENAME} !-f 31 | RewriteCond %{REQUEST_FILENAME} !-d 32 | RewriteCond %{REQUEST_URI} !public/ 33 | RewriteRule ^(.+)$ public/$1 [L] -------------------------------------------------------------------------------- /public/min/builder/bm.js: -------------------------------------------------------------------------------- 1 | javascript:(function() { 2 | var d = document 3 | ,uris = [] 4 | ,i = 0 5 | ,o 6 | ,home = (location + '').split('/').splice(0, 3).join('/') + '/'; 7 | function add(uri) { 8 | return (0 === uri.indexOf(home)) 9 | && (!/[\?&]/.test(uri)) 10 | && uris.push(escape(uri.substr(home.length))); 11 | }; 12 | function sheet(ss) { 13 | // we must check the domain with add() before accessing ss.cssRules 14 | // otherwise a security exception will be thrown 15 | if (ss.href && add(ss.href) && ss.cssRules) { 16 | var i = 0, r; 17 | while (r = ss.cssRules[i++]) 18 | r.styleSheet && sheet(r.styleSheet); 19 | } 20 | }; 21 | while (o = d.getElementsByTagName('script')[i++]) 22 | o.src && !(o.type && /vbs/i.test(o.type)) && add(o.src); 23 | i = 0; 24 | while (o = d.styleSheets[i++]) 25 | /* http://www.w3.org/TR/DOM-Level-2-Style/stylesheets.html#StyleSheets-DocumentStyle-styleSheets 26 | document.styleSheet is a list property where [0] accesses the 1st element and 27 | [outOfRange] returns null. In IE, styleSheets is a function, and also throws an 28 | exception when you check the out of bounds index. (sigh) */ 29 | sheet(o); 30 | if (uris.length) 31 | window.open('%BUILDER_URL%#' + uris.join(',')); 32 | else 33 | alert('No js/css files found with URLs within "' 34 | + home.split('/')[2] 35 | + '".\n(This tool is limited to URLs with the same domain.)'); 36 | })(); -------------------------------------------------------------------------------- /public/min/builder/test.php: -------------------------------------------------------------------------------- 1 | realpath(DOCUMENT_ROOT) failed. You may need " 29 | . "to set \$min_documentRoot manually (hopefully realpath() is not " 30 | . "broken in your environment).

"; 31 | } 32 | if (0 !== strpos(realpath(__FILE__), realpath($_SERVER['DOCUMENT_ROOT']))) { 33 | echo "

DOCUMENT_ROOT doesn't contain this file. You may " 34 | . " need to set \$min_documentRoot manually

"; 35 | } 36 | if (isset($_SERVER['SUBDOMAIN_DOCUMENT_ROOT'])) { 37 | echo "

\$_SERVER['SUBDOMAIN_DOCUMENT_ROOT'] is set. " 38 | . "You may need to set \$min_documentRoot to this in config.php

"; 39 | } 40 | 41 | } 42 | 43 | //*/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | I've made this repo public so that it might help others learn from how it is put together. And better yet, maybe someone will let me know about things that could be improved (though I have a list of improvements to make already). Please feel free to download the code or fork it for your own spelunking, but please don't copy it wholesale as if you built it. 4 | 5 | The site is built on Stacey (). This is a great little CMS that doesn't require a backend database. All of the content and assets are stored in directories. It's a perfect system for lightweight portfolio sites. 6 | 7 | ## Possibly Interesting Features 8 | 9 | A few of the things you may find nifty: 10 | 11 | * Page content fades in once TypeKit fonts load (to avoid "flash of unstyled content"). 12 | * Pseudo-parallax effect for the background while scrolling. 13 | * Animated portfolio section - lots 'o animation and AJAX via MooTools. 14 | * Animated contact form (3D transform for flipping the form in WebKit). 15 | * Modernizr for detecting browser capabilities (ie. supplying fallback effect for 3D transforms). 16 | * Contact form uses inline validation via MooTools. 17 | * Contact form spam detection with Akismet 18 | * -webkit-transitions for subtle hover state transitions 19 | * Sass for generating CSS (I use the sass-watch script). 20 | * hCard microformat for contact info. 21 | * Capistrano used for simple deployment. 22 | 23 | ## To-Dos 24 | 25 | * Add HTML5 History API for portfolio navigation (see ) 26 | * Create mobile version. 27 | * Create larger pool of entries for Play section and pull 4 random ones. 28 | * Refactor giant/fugly JS functions 29 | -------------------------------------------------------------------------------- /app/asset-types/image.inc.php: -------------------------------------------------------------------------------- 1 | set_extended_data($file_path); 12 | } 13 | 14 | function set_extended_data($file_path) { 15 | $small_version_path = preg_replace('/(\.[\w\d]+?)$/', '_sml$1', $this->link_path); 16 | $large_version_path = preg_replace('/(\.[\w\d]+?)$/', '_lge$1', $this->link_path); 17 | 18 | # if a matching _sml version exists, set @small 19 | $small_relative_path = preg_replace('/(\.\.\/)+/', './', $small_version_path); 20 | if(file_exists($small_relative_path) && !is_dir($small_relative_path)) { 21 | $this->data['@small'] = $small_version_path; 22 | } 23 | 24 | # if a matching _lge version exists, set @large 25 | $large_relative_path = preg_replace('/(\.\.\/)+/', './', $large_version_path); 26 | if(file_exists($large_relative_path) && !is_dir($large_relative_path)) { 27 | $this->data['@large'] = $large_version_path; 28 | } 29 | 30 | # set @width & @height variables 31 | $img_data = getimagesize($file_path, $info); 32 | preg_match_all('/\d+/', $img_data[3], $dimensions); 33 | $this->data['@width'] = $dimensions[0][0]; 34 | $this->data['@height'] = $dimensions[0][1]; 35 | 36 | # set iptc variables 37 | if(isset($info["APP13"])) { 38 | $iptc = iptcparse($info["APP13"]); 39 | # @title 40 | if(isset($iptc["2#005"][0])) 41 | $this->data['@title'] = $iptc["2#005"][0]; 42 | # @description 43 | if(isset($iptc["2#120"][0])) 44 | $this->data['@description'] = $iptc["2#120"][0]; 45 | # @keywords 46 | if(isset($iptc["2#025"][0])) 47 | $this->data['@keywords'] = $iptc["2#025"][0]; 48 | } 49 | 50 | } 51 | 52 | } 53 | 54 | ?> -------------------------------------------------------------------------------- /app/asset-types/asset-factory.inc.php: -------------------------------------------------------------------------------- 1 | $identifiers) { 26 | # if a match is found, set $asset to be the name of the matching class 27 | if(in_array(strtolower($split_path[1]), $identifiers)) $asset = $asset_type; 28 | } 29 | 30 | # create a new asset and return its data 31 | $asset = new $asset($file_path); 32 | return $asset->data; 33 | 34 | } else { 35 | # new page 36 | $page = new Page(Helpers::file_path_to_url($file_path)); 37 | return $page->data; 38 | } 39 | } 40 | 41 | static function &get($key) { 42 | # if object doesn't exist, create it 43 | if(!isset(self::$store[$key])) self::$store[$key] =& self::create($key); 44 | return self::$store[$key]; 45 | } 46 | 47 | static function get_asset_subclasses() { 48 | # if asset_subclasses hasn't been filled yet 49 | if(empty(self::$asset_subclasses)) { 50 | # loop through each declared class 51 | foreach(get_declared_classes() as $class) { 52 | # if the class extends 'Asset', then push it into our asset_subclasses hash 53 | if(strtolower(get_parent_class($class)) == 'asset') self::$asset_subclasses[$class] = eval('return '.$class.'::$identifiers;'); 54 | } 55 | } 56 | } 57 | 58 | } 59 | 60 | ?> -------------------------------------------------------------------------------- /app/parsers/json-minifier.inc.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/docs/css/reset.css: -------------------------------------------------------------------------------- 1 | /* 2 | html5doctor.com Reset Stylesheet 3 | v1.6.1 4 | Last Updated: 2010-09-17 5 | Author: Richard Clark - http://richclarkdesign.com 6 | Twitter: @rich_clark 7 | */ 8 | 9 | html, body, div, span, object, iframe, 10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 11 | abbr, address, cite, code, 12 | del, dfn, em, img, ins, kbd, q, samp, 13 | small, strong, sub, sup, var, 14 | b, i, 15 | dl, dt, dd, ol, ul, li, 16 | fieldset, form, label, legend, 17 | table, caption, tbody, tfoot, thead, tr, th, td, 18 | article, aside, canvas, details, figcaption, figure, 19 | footer, header, hgroup, menu, nav, section, summary, 20 | time, mark, audio, video { 21 | margin:0; 22 | padding:0; 23 | border:0; 24 | outline:0; 25 | font-size:100%; 26 | vertical-align:baseline; 27 | background:transparent; 28 | } 29 | 30 | body { 31 | line-height:1; 32 | } 33 | 34 | article,aside,details,figcaption,figure, 35 | footer,header,hgroup,menu,nav,section { 36 | display:block; 37 | } 38 | 39 | nav ul { 40 | list-style:none; 41 | } 42 | 43 | blockquote, q { 44 | quotes:none; 45 | } 46 | 47 | blockquote:before, blockquote:after, 48 | q:before, q:after { 49 | content:''; 50 | content:none; 51 | } 52 | 53 | a { 54 | margin:0; 55 | padding:0; 56 | font-size:100%; 57 | vertical-align:baseline; 58 | background:transparent; 59 | } 60 | 61 | /* change colours to suit your needs */ 62 | ins { 63 | background-color:#ff9; 64 | color:#000; 65 | text-decoration:none; 66 | } 67 | 68 | /* change colours to suit your needs */ 69 | mark { 70 | background-color:#ff9; 71 | color:#000; 72 | font-style:italic; 73 | font-weight:bold; 74 | } 75 | 76 | del { 77 | text-decoration: line-through; 78 | } 79 | 80 | abbr[title], dfn[title] { 81 | border-bottom:1px dotted; 82 | cursor:help; 83 | } 84 | 85 | table { 86 | border-collapse:collapse; 87 | border-spacing:0; 88 | } 89 | 90 | /* change border colour to suit your needs */ 91 | hr { 92 | display:block; 93 | height:1px; 94 | border:0; 95 | border-top:1px solid #cccccc; 96 | margin:1em 0; 97 | padding:0; 98 | } 99 | 100 | input, select { 101 | vertical-align:middle; 102 | } -------------------------------------------------------------------------------- /app/asset-types/page.inc.php: -------------------------------------------------------------------------------- 1 | file_path = Helpers::url_to_file_path($url); 16 | $this->url_path = $url; 17 | 18 | $this->template_name = self::template_name($this->file_path); 19 | $this->template_file = self::template_file($this->template_name); 20 | $this->template_type = self::template_type($this->template_file); 21 | 22 | # create/set all content variables 23 | PageData::create($this); 24 | # sort data array by key length 25 | # 26 | # this ensures that something like '@title' doesn't turn '@page_title' 27 | # into '@page_Contents of @title variable' in the final rendered template 28 | # 29 | uksort($this->data, array('Helpers', 'sort_by_length')); 30 | 31 | } 32 | 33 | function parse_template() { 34 | $data = TemplateParser::parse($this->data, file_get_contents($this->template_file)); 35 | 36 | # post-parse JSON 37 | if (strtolower($this->template_type) == 'json') { 38 | # minfy it 39 | $data = json_minify($data); 40 | # strip any trailing commas 41 | # (run it twice to get partial matches) 42 | $data = preg_replace('/([}\]"]),([}\]])/', '$1$2', $data); 43 | $data = preg_replace('/([}\]"]),([}\]])/', '$1$2', $data); 44 | } 45 | 46 | return $data; 47 | } 48 | 49 | # magic variable assignment 50 | function __set($name, $value) { 51 | $prefix = is_array($value) ? '$' : '@'; 52 | $this->data[$prefix.strtolower($name)] = $value; 53 | } 54 | 55 | static function template_type($template_file) { 56 | preg_match('/\.([\w\d]+?)$/', $template_file, $ext); 57 | return isset($ext[1]) ? $ext[1] : false; 58 | } 59 | 60 | static function template_name($file_path) { 61 | $txts = array_keys(Helpers::list_files($file_path, '/\.txt$/')); 62 | # return first matched .txt file 63 | return (!empty($txts)) ? preg_replace('/([^.]*\.)?([^.]*)\.txt$/', '\\2', $txts[0]) : false; 64 | } 65 | 66 | static function template_file($template_name) { 67 | $template_file = glob('./templates/'.$template_name.'.*'); 68 | # return template if one exists 69 | return isset($template_file[0]) ? $template_file[0] : false; 70 | } 71 | 72 | } 73 | 74 | ?> -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/Files.php: -------------------------------------------------------------------------------- 1 | 14 | * Minify::serve('Files', array( 15 | * 'files' => array( 16 | * '//js/jquery.js' 17 | * ,'//js/plugins.js' 18 | * ,'/home/username/file.js' 19 | * ) 20 | * )); 21 | * 22 | * 23 | * As a shortcut, the controller will replace "//" at the beginning 24 | * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. 25 | * 26 | * @package Minify 27 | * @author Stephen Clay 28 | */ 29 | class Minify_Controller_Files extends Minify_Controller_Base { 30 | 31 | /** 32 | * Set up file sources 33 | * 34 | * @param array $options controller and Minify options 35 | * @return array Minify options 36 | * 37 | * Controller options: 38 | * 39 | * 'files': (required) array of complete file paths, or a single path 40 | */ 41 | public function setupSources($options) { 42 | // strip controller options 43 | 44 | $files = $options['files']; 45 | // if $files is a single object, casting will break it 46 | if (is_object($files)) { 47 | $files = array($files); 48 | } elseif (! is_array($files)) { 49 | $files = (array)$files; 50 | } 51 | unset($options['files']); 52 | 53 | $sources = array(); 54 | foreach ($files as $file) { 55 | if ($file instanceof Minify_Source) { 56 | $sources[] = $file; 57 | continue; 58 | } 59 | if (0 === strpos($file, '//')) { 60 | $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); 61 | } 62 | $realPath = realpath($file); 63 | if (is_file($realPath)) { 64 | $sources[] = new Minify_Source(array( 65 | 'filepath' => $realPath 66 | )); 67 | } else { 68 | $this->log("The path \"{$file}\" could not be found (or was not a file)"); 69 | return $options; 70 | } 71 | } 72 | if ($sources) { 73 | $this->sources = $sources; 74 | } 75 | return $options; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /public/min/index.php: -------------------------------------------------------------------------------- 1 | $target) { 35 | $min_serveOptions['minApp']['allowDirs'][] = $target; 36 | } 37 | 38 | if ($min_allowDebugFlag) { 39 | if (! empty($_COOKIE['minDebug'])) { 40 | foreach (preg_split('/\\s+/', $_COOKIE['minDebug']) as $debugUri) { 41 | if (false !== strpos($_SERVER['REQUEST_URI'], $debugUri)) { 42 | $min_serveOptions['debug'] = true; 43 | break; 44 | } 45 | } 46 | } 47 | // allow GET to override 48 | if (isset($_GET['debug'])) { 49 | $min_serveOptions['debug'] = true; 50 | } 51 | } 52 | 53 | if ($min_errorLogger) { 54 | require_once 'Minify/Logger.php'; 55 | if (true === $min_errorLogger) { 56 | require_once 'FirePHP.php'; 57 | Minify_Logger::setLogger(FirePHP::getInstance(true)); 58 | } else { 59 | Minify_Logger::setLogger($min_errorLogger); 60 | } 61 | } 62 | 63 | // check for URI versioning 64 | if (preg_match('/&\\d/', $_SERVER['QUERY_STRING'])) { 65 | $min_serveOptions['maxAge'] = 31536000; 66 | } 67 | if (isset($_GET['g'])) { 68 | // well need groups config 69 | $min_serveOptions['minApp']['groups'] = (require MINIFY_MIN_DIR . '/groupsConfig.php'); 70 | } 71 | if (isset($_GET['f']) || isset($_GET['g'])) { 72 | // serve! 73 | Minify::serve('MinApp', $min_serveOptions); 74 | 75 | } elseif ($min_enableBuilder) { 76 | header('Location: builder/'); 77 | exit(); 78 | } else { 79 | header("Location: /"); 80 | exit(); 81 | } -------------------------------------------------------------------------------- /public/min/utils.php: -------------------------------------------------------------------------------- 1 | 16 | * 17 | * 18 | * 22 | * 23 | * 24 | * @param mixed $keyOrFiles a group key or array of file paths/URIs 25 | * @param array $opts options: 26 | * 'farExpires' : (default true) append a modified timestamp for cache revving 27 | * 'debug' : (default false) append debug flag 28 | * 'charset' : (default 'UTF-8') for htmlspecialchars 29 | * 'minAppUri' : (default '/min') URI of min directory 30 | * 'rewriteWorks' : (default true) does mod_rewrite work in min app? 31 | * 'groupsConfigFile' : specify if different 32 | * @return string 33 | */ 34 | function Minify_getUri($keyOrFiles, $opts = array()) 35 | { 36 | return Minify_HTML_Helper::getUri($keyOrFiles, $opts); 37 | } 38 | 39 | 40 | /** 41 | * Get the last modification time of several source js/css files. If you're 42 | * caching the output of Minify_getUri(), you might want to know if one of the 43 | * dependent source files has changed so you can update the HTML. 44 | * 45 | * Since this makes a bunch of stat() calls, you might not want to check this 46 | * on every request. 47 | * 48 | * @param array $keysAndFiles group keys and/or file paths/URIs. 49 | * @return int latest modification time of all given keys/files 50 | */ 51 | function Minify_mtime($keysAndFiles, $groupsConfigFile = null) 52 | { 53 | $gc = null; 54 | if (! $groupsConfigFile) { 55 | $groupsConfigFile = dirname(__FILE__) . '/groupsConfig.php'; 56 | } 57 | $sources = array(); 58 | foreach ($keysAndFiles as $keyOrFile) { 59 | if (is_object($keyOrFile) 60 | || 0 === strpos($keyOrFile, '/') 61 | || 1 === strpos($keyOrFile, ':\\')) { 62 | // a file/source obj 63 | $sources[] = $keyOrFile; 64 | } else { 65 | if (! $gc) { 66 | $gc = (require $groupsConfigFile); 67 | } 68 | foreach ($gc[$keyOrFile] as $source) { 69 | $sources[] = $source; 70 | } 71 | } 72 | } 73 | return Minify_HTML_Helper::getLastModified($sources); 74 | } 75 | -------------------------------------------------------------------------------- /public/docs/js/modernizr-1.6.min.js: -------------------------------------------------------------------------------- 1 | window.Modernizr=function(g,e,j){function m(a,b){for(var c in a)if(q[a[c]]!==j&&(!b||b(a[c],n)))return true}var d={},i=e.documentElement,r=e.head||e.getElementsByTagName("head")[0],n=e.createElement("modernizr"),q=n.style;e.createElement("input");var v=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),w="Webkit Moz O ms Khtml".split(" ");g={};var s=[],l;(function(){var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return function(b,c){c=c||e.createElement(a[b]|| 2 | "div");b="on"+b;var k=b in c;if(!k){c.setAttribute||(c=e.createElement("div"));if(c.setAttribute&&c.removeAttribute){c.setAttribute(b,"");k=typeof c[b]==="function";typeof c[b]===j||(c[b]=j);c.removeAttribute(b)}}return k}})();var o={}.hasOwnProperty,t;t=typeof o!==j&&typeof o.call!==j?function(a,b){return o.call(a,b)}:function(a,b){return b in a&&typeof a.constructor.prototype[b]===j};g.csstransforms=function(){return!!m(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])}; 3 | g.csstransforms3d=function(){var a=!!m(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);if(a&&"webkitPerspective"in i.style){var b="@media ("+v.join("transform-3d),(")+"modernizr)";a=e.createElement("style");var c=e.createElement("div");a.textContent=b+"{#modernizr{height:3px}}";r.appendChild(a);c.id="modernizr";i.appendChild(c);b=c.offsetHeight===3;a.parentNode.removeChild(a);c.parentNode.removeChild(c);a=!!b}return a};g.csstransitions=function(){var a= 4 | "transitionProperty".charAt(0).toUpperCase()+"transitionProperty".substr(1);a=("transitionProperty "+w.join(a+" ")+a).split(" ");return!!m(a,void 0)};g.fontface=function(){var a,b=r||i,c=e.createElement("style"),k=e.implementation||{hasFeature:function(){return false}};c.type="text/css";b.insertBefore(c,b.firstChild);a=c.sheet||c.styleSheet;b=k.hasFeature("CSS2","")?function(h){if(!(a&&h))return false;var u=false;try{a.insertRule(h,0);u=!/unknown/i.test(a.cssRules[0].cssText);a.deleteRule(a.cssRules.length- 5 | 1)}catch(x){}return u}:function(h){if(!(a&&h))return false;a.cssText=h;return a.cssText.length!==0&&!/unknown/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(h.split(" ")[0])===0};d._fontfaceready=function(h){h(d.fontface)};return b('@font-face { font-family: "font"; src: "font.ttf"; }')};for(var p in g)if(t(g,p)){l=p.toLowerCase();d[l]=g[p]();s.push((d[l]?"":"no-")+l)}d.crosswindowmessaging=d.postmessage;d.historymanagement=d.history;d.addTest=function(a,b){a=a.toLowerCase();if(!d[a]){b= 6 | !!b();i.className+=" "+(b?"":"no-")+a;d[a]=b;return d}};q.cssText="";n=f=null;d._enableHTML5=true;d._version="1.6";i.className=i.className.replace(/\bno-js\b/,"")+" js";i.className+=" "+s.join(" ");return d}(this,this.document); 7 | -------------------------------------------------------------------------------- /public/min/lib/Minify/CommentPreserver.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class Minify_CommentPreserver { 14 | 15 | /** 16 | * String to be prepended to each preserved comment 17 | * 18 | * @var string 19 | */ 20 | public static $prepend = "\n"; 21 | 22 | /** 23 | * String to be appended to each preserved comment 24 | * 25 | * @var string 26 | */ 27 | public static $append = "\n"; 28 | 29 | /** 30 | * Process a string outside of C-style comments that begin with "/*!" 31 | * 32 | * On each non-empty string outside these comments, the given processor 33 | * function will be called. The comments will be surrounded by 34 | * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append. 35 | * 36 | * @param string $content 37 | * @param callback $processor function 38 | * @param array $args array of extra arguments to pass to the processor 39 | * function (default = array()) 40 | * @return string 41 | */ 42 | public static function process($content, $processor, $args = array()) 43 | { 44 | $ret = ''; 45 | while (true) { 46 | list($beforeComment, $comment, $afterComment) = self::_nextComment($content); 47 | if ('' !== $beforeComment) { 48 | $callArgs = $args; 49 | array_unshift($callArgs, $beforeComment); 50 | $ret .= call_user_func_array($processor, $callArgs); 51 | } 52 | if (false === $comment) { 53 | break; 54 | } 55 | $ret .= $comment; 56 | $content = $afterComment; 57 | } 58 | return $ret; 59 | } 60 | 61 | /** 62 | * Extract comments that YUI Compressor preserves. 63 | * 64 | * @param string $in input 65 | * 66 | * @return array 3 elements are returned. If a YUI comment is found, the 67 | * 2nd element is the comment and the 1st and 3rd are the surrounding 68 | * strings. If no comment is found, the entire string is returned as the 69 | * 1st element and the other two are false. 70 | */ 71 | private static function _nextComment($in) 72 | { 73 | if ( 74 | false === ($start = strpos($in, '/*!')) 75 | || false === ($end = strpos($in, '*/', $start + 3)) 76 | ) { 77 | return array($in, false, false); 78 | } 79 | $ret = array( 80 | substr($in, 0, $start) 81 | ,self::$prepend . '/*!' . substr($in, $start + 3, $end - $start - 1) . self::$append 82 | ); 83 | $endChars = (strlen($in) - $end - 2); 84 | $ret[] = (0 === $endChars) 85 | ? '' 86 | : substr($in, -$endChars); 87 | return $ret; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/Page.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class Minify_Controller_Page extends Minify_Controller_Base { 17 | 18 | /** 19 | * Set up source of HTML content 20 | * 21 | * @param array $options controller and Minify options 22 | * @return array Minify options 23 | * 24 | * Controller options: 25 | * 26 | * 'content': (required) HTML markup 27 | * 28 | * 'id': (required) id of page (string for use in server-side caching) 29 | * 30 | * 'lastModifiedTime': timestamp of when this content changed. This 31 | * is recommended to allow both server and client-side caching. 32 | * 33 | * 'minifyAll': should all CSS and Javascript blocks be individually 34 | * minified? (default false) 35 | * 36 | * @todo Add 'file' option to read HTML file. 37 | */ 38 | public function setupSources($options) { 39 | if (isset($options['file'])) { 40 | $sourceSpec = array( 41 | 'filepath' => $options['file'] 42 | ); 43 | $f = $options['file']; 44 | } else { 45 | // strip controller options 46 | $sourceSpec = array( 47 | 'content' => $options['content'] 48 | ,'id' => $options['id'] 49 | ); 50 | $f = $options['id']; 51 | unset($options['content'], $options['id']); 52 | } 53 | // something like "builder,index.php" or "directory,file.html" 54 | $this->selectionId = strtr(substr($f, 1 + strlen(dirname(dirname($f)))), '/\\', ',,'); 55 | 56 | if (isset($options['minifyAll'])) { 57 | // this will be the 2nd argument passed to Minify_HTML::minify() 58 | $sourceSpec['minifyOptions'] = array( 59 | 'cssMinifier' => array('Minify_CSS', 'minify') 60 | ,'jsMinifier' => array('JSMin', 'minify') 61 | ); 62 | $this->_loadCssJsMinifiers = true; 63 | unset($options['minifyAll']); 64 | } 65 | $this->sources[] = new Minify_Source($sourceSpec); 66 | 67 | $options['contentType'] = Minify::TYPE_HTML; 68 | return $options; 69 | } 70 | 71 | protected $_loadCssJsMinifiers = false; 72 | 73 | /** 74 | * @see Minify_Controller_Base::loadMinifier() 75 | */ 76 | public function loadMinifier($minifierCallback) 77 | { 78 | if ($this->_loadCssJsMinifiers) { 79 | // Minify will not call for these so we must manually load 80 | // them when Minify/HTML.php is called for. 81 | require_once 'Minify/CSS.php'; 82 | require_once 'JSMin.php'; 83 | } 84 | parent::loadMinifier($minifierCallback); // load Minify/HTML.php 85 | } 86 | } 87 | 88 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/Groups.php: -------------------------------------------------------------------------------- 1 | 14 | * Minify::serve('Groups', array( 15 | * 'groups' => array( 16 | * 'css' => array('//css/type.css', '//css/layout.css') 17 | * ,'js' => array('//js/jquery.js', '//js/site.js') 18 | * ) 19 | * )); 20 | * 21 | * 22 | * If the above code were placed in /serve.php, it would enable the URLs 23 | * /serve.php/js and /serve.php/css 24 | * 25 | * As a shortcut, the controller will replace "//" at the beginning 26 | * of a filename with $_SERVER['DOCUMENT_ROOT'] . '/'. 27 | * 28 | * @package Minify 29 | * @author Stephen Clay 30 | */ 31 | class Minify_Controller_Groups extends Minify_Controller_Base { 32 | 33 | /** 34 | * Set up groups of files as sources 35 | * 36 | * @param array $options controller and Minify options 37 | * @return array Minify options 38 | * 39 | * Controller options: 40 | * 41 | * 'groups': (required) array mapping PATH_INFO strings to arrays 42 | * of complete file paths. @see Minify_Controller_Groups 43 | */ 44 | public function setupSources($options) { 45 | // strip controller options 46 | $groups = $options['groups']; 47 | unset($options['groups']); 48 | 49 | // mod_fcgid places PATH_INFO in ORIG_PATH_INFO 50 | $pi = isset($_SERVER['ORIG_PATH_INFO']) 51 | ? substr($_SERVER['ORIG_PATH_INFO'], 1) 52 | : (isset($_SERVER['PATH_INFO']) 53 | ? substr($_SERVER['PATH_INFO'], 1) 54 | : false 55 | ); 56 | if (false === $pi || ! isset($groups[$pi])) { 57 | // no PATH_INFO or not a valid group 58 | $this->log("Missing PATH_INFO or no group set for \"$pi\""); 59 | return $options; 60 | } 61 | $sources = array(); 62 | 63 | $files = $groups[$pi]; 64 | // if $files is a single object, casting will break it 65 | if (is_object($files)) { 66 | $files = array($files); 67 | } elseif (! is_array($files)) { 68 | $files = (array)$files; 69 | } 70 | foreach ($files as $file) { 71 | if ($file instanceof Minify_Source) { 72 | $sources[] = $file; 73 | continue; 74 | } 75 | if (0 === strpos($file, '//')) { 76 | $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); 77 | } 78 | $realPath = realpath($file); 79 | if (is_file($realPath)) { 80 | $sources[] = new Minify_Source(array( 81 | 'filepath' => $realPath 82 | )); 83 | } else { 84 | $this->log("The path \"{$file}\" could not be found (or was not a file)"); 85 | return $options; 86 | } 87 | } 88 | if ($sources) { 89 | $this->sources = $sources; 90 | } 91 | return $options; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Build.php: -------------------------------------------------------------------------------- 1 | 14 | * // in config file 15 | * $groupSources = array( 16 | * 'js' => array('file1.js', 'file2.js') 17 | * ,'css' => array('file1.css', 'file2.css', 'file3.css') 18 | * ) 19 | * 20 | * // during HTML generation 21 | * $jsBuild = new Minify_Build($groupSources['js']); 22 | * $cssBuild = new Minify_Build($groupSources['css']); 23 | * 24 | * $script = ""; 26 | * $link = ""; 28 | * 29 | * // in min.php 30 | * Minify::serve('Groups', array( 31 | * 'groups' => $groupSources 32 | * ,'setExpires' => (time() + 86400 * 365) 33 | * )); 34 | * 35 | * 36 | * @package Minify 37 | * @author Stephen Clay 38 | */ 39 | class Minify_Build { 40 | 41 | /** 42 | * Last modification time of all files in the build 43 | * 44 | * @var int 45 | */ 46 | public $lastModified = 0; 47 | 48 | /** 49 | * String to use as ampersand in uri(). Set this to '&' if 50 | * you are not HTML-escaping URIs. 51 | * 52 | * @var string 53 | */ 54 | public static $ampersand = '&'; 55 | 56 | /** 57 | * Get a time-stamped URI 58 | * 59 | * 60 | * echo $b->uri('/site.js'); 61 | * // outputs "/site.js?1678242" 62 | * 63 | * echo $b->uri('/scriptaculous.js?load=effects'); 64 | * // outputs "/scriptaculous.js?load=effects&1678242" 65 | * 66 | * 67 | * @param string $uri 68 | * @param boolean $forceAmpersand (default = false) Force the use of ampersand to 69 | * append the timestamp to the URI. 70 | * @return string 71 | */ 72 | public function uri($uri, $forceAmpersand = false) { 73 | $sep = ($forceAmpersand || strpos($uri, '?') !== false) 74 | ? self::$ampersand 75 | : '?'; 76 | return "{$uri}{$sep}{$this->lastModified}"; 77 | } 78 | 79 | /** 80 | * Create a build object 81 | * 82 | * @param array $sources array of Minify_Source objects and/or file paths 83 | * 84 | * @return null 85 | */ 86 | public function __construct($sources) 87 | { 88 | $max = 0; 89 | foreach ((array)$sources as $source) { 90 | if ($source instanceof Minify_Source) { 91 | $max = max($max, $source->lastModified); 92 | } elseif (is_string($source)) { 93 | if (0 === strpos($source, '//')) { 94 | $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); 95 | } 96 | if (is_file($source)) { 97 | $max = max($max, filemtime($source)); 98 | } 99 | } 100 | } 101 | $this->lastModified = $max; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /public/min/lib/Minify/CSS.php: -------------------------------------------------------------------------------- 1 | 15 | * @author http://code.google.com/u/1stvamp/ (Issue 64 patch) 16 | */ 17 | class Minify_CSS { 18 | 19 | /** 20 | * Minify a CSS string 21 | * 22 | * @param string $css 23 | * 24 | * @param array $options available options: 25 | * 26 | * 'preserveComments': (default true) multi-line comments that begin 27 | * with "/*!" will be preserved with newlines before and after to 28 | * enhance readability. 29 | * 30 | * 'prependRelativePath': (default null) if given, this string will be 31 | * prepended to all relative URIs in import/url declarations 32 | * 33 | * 'currentDir': (default null) if given, this is assumed to be the 34 | * directory of the current CSS file. Using this, minify will rewrite 35 | * all relative URIs in import/url declarations to correctly point to 36 | * the desired files. For this to work, the files *must* exist and be 37 | * visible by the PHP process. 38 | * 39 | * 'symlinks': (default = array()) If the CSS file is stored in 40 | * a symlink-ed directory, provide an array of link paths to 41 | * target paths, where the link paths are within the document root. Because 42 | * paths need to be normalized for this to work, use "//" to substitute 43 | * the doc root in the link paths (the array keys). E.g.: 44 | * 45 | * array('//symlink' => '/real/target/path') // unix 46 | * array('//static' => 'D:\\staticStorage') // Windows 47 | * 48 | * 49 | * @return string 50 | */ 51 | public static function minify($css, $options = array()) 52 | { 53 | require_once 'Minify/CSS/Compressor.php'; 54 | if (isset($options['preserveComments']) 55 | && !$options['preserveComments']) { 56 | $css = Minify_CSS_Compressor::process($css, $options); 57 | } else { 58 | require_once 'Minify/CommentPreserver.php'; 59 | $css = Minify_CommentPreserver::process( 60 | $css 61 | ,array('Minify_CSS_Compressor', 'process') 62 | ,array($options) 63 | ); 64 | } 65 | if (! isset($options['currentDir']) && ! isset($options['prependRelativePath'])) { 66 | return $css; 67 | } 68 | require_once 'Minify/CSS/UriRewriter.php'; 69 | if (isset($options['currentDir'])) { 70 | return Minify_CSS_UriRewriter::rewrite( 71 | $css 72 | ,$options['currentDir'] 73 | ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'] 74 | ,isset($options['symlinks']) ? $options['symlinks'] : array() 75 | ); 76 | } else { 77 | return Minify_CSS_UriRewriter::prepend( 78 | $css 79 | ,$options['prependRelativePath'] 80 | ); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Cache/APC.php: -------------------------------------------------------------------------------- 1 | 11 | * Minify::setCache(new Minify_Cache_APC()); 12 | * 13 | * 14 | * @package Minify 15 | * @author Chris Edwards 16 | **/ 17 | class Minify_Cache_APC { 18 | 19 | /** 20 | * Create a Minify_Cache_APC object, to be passed to 21 | * Minify::setCache(). 22 | * 23 | * 24 | * @param int $expire seconds until expiration (default = 0 25 | * meaning the item will not get an expiration date) 26 | * 27 | * @return null 28 | */ 29 | public function __construct($expire = 0) 30 | { 31 | $this->_exp = $expire; 32 | } 33 | 34 | /** 35 | * Write data to cache. 36 | * 37 | * @param string $id cache id 38 | * 39 | * @param string $data 40 | * 41 | * @return bool success 42 | */ 43 | public function store($id, $data) 44 | { 45 | return apc_store($id, "{$_SERVER['REQUEST_TIME']}|{$data}", $this->_exp); 46 | } 47 | 48 | /** 49 | * Get the size of a cache entry 50 | * 51 | * @param string $id cache id 52 | * 53 | * @return int size in bytes 54 | */ 55 | public function getSize($id) 56 | { 57 | if (! $this->_fetch($id)) { 58 | return false; 59 | } 60 | return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) 61 | ? mb_strlen($this->_data, '8bit') 62 | : strlen($this->_data); 63 | } 64 | 65 | /** 66 | * Does a valid cache entry exist? 67 | * 68 | * @param string $id cache id 69 | * 70 | * @param int $srcMtime mtime of the original source file(s) 71 | * 72 | * @return bool exists 73 | */ 74 | public function isValid($id, $srcMtime) 75 | { 76 | return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); 77 | } 78 | 79 | /** 80 | * Send the cached content to output 81 | * 82 | * @param string $id cache id 83 | */ 84 | public function display($id) 85 | { 86 | echo $this->_fetch($id) 87 | ? $this->_data 88 | : ''; 89 | } 90 | 91 | /** 92 | * Fetch the cached content 93 | * 94 | * @param string $id cache id 95 | * 96 | * @return string 97 | */ 98 | public function fetch($id) 99 | { 100 | return $this->_fetch($id) 101 | ? $this->_data 102 | : ''; 103 | } 104 | 105 | private $_exp = null; 106 | 107 | // cache of most recently fetched id 108 | private $_lm = null; 109 | private $_data = null; 110 | private $_id = null; 111 | 112 | /** 113 | * Fetch data and timestamp from apc, store in instance 114 | * 115 | * @param string $id 116 | * 117 | * @return bool success 118 | */ 119 | private function _fetch($id) 120 | { 121 | if ($this->_id === $id) { 122 | return true; 123 | } 124 | $ret = apc_fetch($id); 125 | if (false === $ret) { 126 | $this->_id = null; 127 | return false; 128 | } 129 | list($this->_lm, $this->_data) = explode('|', $ret, 2); 130 | $this->_id = $id; 131 | return true; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /app/cache.inc.php: -------------------------------------------------------------------------------- 1 | array("begin" => ""), 13 | "js" => array("begin" => "/*", "end" => "*/"), 14 | "css" => array("begin" => "/*", "end" => "*/"), 15 | "txt" => array("begin" => "#", "end" => "") # robots.txt files need # comments in order to not break 16 | ); 17 | 18 | function __construct($file_path, $template_file) { 19 | # turn a base64 of the current route into the name of the cache file 20 | $this->cachefile = './app/_cache/'.$this->base64_url($file_path); 21 | # collect an md5 of all files 22 | $this->hash = $this->create_hash(); 23 | # determine our file type so we know how (and if) to comment 24 | $this->filetype = $this->set_filetype($template_file); 25 | $this->comment_tags = $this->set_comment_tags(); 26 | } 27 | 28 | function base64_url($input) { 29 | return strtr(base64_encode($input), '+/=', '-_,'); 30 | } 31 | 32 | function render() { 33 | return file_get_contents($this->cachefile)."\n".$this->comment_tags['begin'].' Cached. '.$this->comment_tags['end']; 34 | } 35 | 36 | function create($route) { 37 | $page = new Page($route); 38 | # start output buffer 39 | ob_start(); 40 | echo $page->parse_template(); 41 | # if cache folder is writable, write to it 42 | if(is_writable('./app/_cache') && !$page->data['@bypass_cache']) $this->write_cache(); 43 | else if ($this->is_commentable()) echo "\n".$this->comment_tags['begin'].' Stacey('.Stacey::$version.'). '.$this->comment_tags['end']; 44 | # end buffer 45 | ob_end_flush(); 46 | return ''; 47 | } 48 | 49 | function expired() { 50 | # if cachefile doesn't exist, we need to create one 51 | if(!file_exists($this->cachefile)) return true; 52 | # compare new m5d to existing cached md5 53 | elseif($this->hash !== $this->get_current_hash()) return true; 54 | else return false; 55 | } 56 | 57 | function get_current_hash() { 58 | preg_match('/Stacey.*: (.+?)\s/', file_get_contents($this->cachefile), $matches); 59 | return isset($matches[1]) ? $matches[1] : false; 60 | } 61 | 62 | function write_cache() { 63 | if ($this->is_commentable()) echo "\n".$this->comment_tags['begin'].' Stacey('.Stacey::$version.'): '.$this->hash.' '.$this->comment_tags['end']; 64 | $fp = fopen($this->cachefile, 'w'); 65 | fwrite($fp, ob_get_contents()); 66 | fclose($fp); 67 | } 68 | 69 | function create_hash() { 70 | # .htaccess file 71 | $htaccess = file_exists('./.htaccess') ? '.htaccess:'.filemtime('./.htaccess') : ''; 72 | # serialize the file cache 73 | $file_cache = serialize(Helpers::file_cache()); 74 | # create an md5 of the two collections 75 | return md5($htaccess.$file_cache); 76 | } 77 | 78 | function set_filetype($template_file) { 79 | preg_match('/\.([\w\d]+?)$/', $template_file, $split_path); 80 | return $split_path[1]; 81 | } 82 | 83 | function set_comment_tags() { 84 | if (in_array($this->filetype, $this->filetype_comment_tags)) { 85 | return $this->filetype_comment_tags[$this->filetype]; 86 | } 87 | else return $this->filetype_comment_tags['default']; 88 | } 89 | 90 | function is_commentable() { 91 | return !(in_array($this->filetype, $this->no_comment_types)); 92 | } 93 | 94 | } 95 | ?> 96 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Cache/Memcache.php: -------------------------------------------------------------------------------- 1 | 11 | * // fall back to disk caching if memcache can't connect 12 | * $memcache = new Memcache; 13 | * if ($memcache->connect('localhost', 11211)) { 14 | * Minify::setCache(new Minify_Cache_Memcache($memcache)); 15 | * } else { 16 | * Minify::setCache(); 17 | * } 18 | * 19 | **/ 20 | class Minify_Cache_Memcache { 21 | 22 | /** 23 | * Create a Minify_Cache_Memcache object, to be passed to 24 | * Minify::setCache(). 25 | * 26 | * @param Memcache $memcache already-connected instance 27 | * 28 | * @param int $expire seconds until expiration (default = 0 29 | * meaning the item will not get an expiration date) 30 | * 31 | * @return null 32 | */ 33 | public function __construct($memcache, $expire = 0) 34 | { 35 | $this->_mc = $memcache; 36 | $this->_exp = $expire; 37 | } 38 | 39 | /** 40 | * Write data to cache. 41 | * 42 | * @param string $id cache id 43 | * 44 | * @param string $data 45 | * 46 | * @return bool success 47 | */ 48 | public function store($id, $data) 49 | { 50 | return $this->_mc->set($id, "{$_SERVER['REQUEST_TIME']}|{$data}", 0, $this->_exp); 51 | } 52 | 53 | 54 | /** 55 | * Get the size of a cache entry 56 | * 57 | * @param string $id cache id 58 | * 59 | * @return int size in bytes 60 | */ 61 | public function getSize($id) 62 | { 63 | if (! $this->_fetch($id)) { 64 | return false; 65 | } 66 | return (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) 67 | ? mb_strlen($this->_data, '8bit') 68 | : strlen($this->_data); 69 | } 70 | 71 | /** 72 | * Does a valid cache entry exist? 73 | * 74 | * @param string $id cache id 75 | * 76 | * @param int $srcMtime mtime of the original source file(s) 77 | * 78 | * @return bool exists 79 | */ 80 | public function isValid($id, $srcMtime) 81 | { 82 | return ($this->_fetch($id) && ($this->_lm >= $srcMtime)); 83 | } 84 | 85 | /** 86 | * Send the cached content to output 87 | * 88 | * @param string $id cache id 89 | */ 90 | public function display($id) 91 | { 92 | echo $this->_fetch($id) 93 | ? $this->_data 94 | : ''; 95 | } 96 | 97 | /** 98 | * Fetch the cached content 99 | * 100 | * @param string $id cache id 101 | * 102 | * @return string 103 | */ 104 | public function fetch($id) 105 | { 106 | return $this->_fetch($id) 107 | ? $this->_data 108 | : ''; 109 | } 110 | 111 | private $_mc = null; 112 | private $_exp = null; 113 | 114 | // cache of most recently fetched id 115 | private $_lm = null; 116 | private $_data = null; 117 | private $_id = null; 118 | 119 | /** 120 | * Fetch data and timestamp from memcache, store in instance 121 | * 122 | * @param string $id 123 | * 124 | * @return bool success 125 | */ 126 | private function _fetch($id) 127 | { 128 | if ($this->_id === $id) { 129 | return true; 130 | } 131 | $ret = $this->_mc->get($id); 132 | if (false === $ret) { 133 | $this->_id = null; 134 | return false; 135 | } 136 | list($this->_lm, $this->_data) = explode('|', $ret, 2); 137 | $this->_id = $id; 138 | return true; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Cache/File.php: -------------------------------------------------------------------------------- 1 | _locking = $fileLocking; 16 | $this->_path = $path; 17 | } 18 | 19 | /** 20 | * Write data to cache. 21 | * 22 | * @param string $id cache id (e.g. a filename) 23 | * 24 | * @param string $data 25 | * 26 | * @return bool success 27 | */ 28 | public function store($id, $data) 29 | { 30 | $flag = $this->_locking 31 | ? LOCK_EX 32 | : null; 33 | $file = $this->_path . '/' . $id; 34 | if (is_file($file)) { 35 | @unlink($file); 36 | } 37 | if (! @file_put_contents($file, $data, $flag)) { 38 | $this->_log("Minify_Cache_File: Write failed to '$file'"); 39 | return false; 40 | } 41 | // write control 42 | if ($data !== $this->fetch($id)) { 43 | @unlink($file); 44 | $this->_log("Minify_Cache_File: Post-write read failed for '$file'"); 45 | return false; 46 | } 47 | return true; 48 | } 49 | 50 | /** 51 | * Get the size of a cache entry 52 | * 53 | * @param string $id cache id (e.g. a filename) 54 | * 55 | * @return int size in bytes 56 | */ 57 | public function getSize($id) 58 | { 59 | return filesize($this->_path . '/' . $id); 60 | } 61 | 62 | /** 63 | * Does a valid cache entry exist? 64 | * 65 | * @param string $id cache id (e.g. a filename) 66 | * 67 | * @param int $srcMtime mtime of the original source file(s) 68 | * 69 | * @return bool exists 70 | */ 71 | public function isValid($id, $srcMtime) 72 | { 73 | $file = $this->_path . '/' . $id; 74 | return (is_file($file) && (filemtime($file) >= $srcMtime)); 75 | } 76 | 77 | /** 78 | * Send the cached content to output 79 | * 80 | * @param string $id cache id (e.g. a filename) 81 | */ 82 | public function display($id) 83 | { 84 | if ($this->_locking) { 85 | $fp = fopen($this->_path . '/' . $id, 'rb'); 86 | flock($fp, LOCK_SH); 87 | fpassthru($fp); 88 | flock($fp, LOCK_UN); 89 | fclose($fp); 90 | } else { 91 | readfile($this->_path . '/' . $id); 92 | } 93 | } 94 | 95 | /** 96 | * Fetch the cached content 97 | * 98 | * @param string $id cache id (e.g. a filename) 99 | * 100 | * @return string 101 | */ 102 | public function fetch($id) 103 | { 104 | if ($this->_locking) { 105 | $fp = fopen($this->_path . '/' . $id, 'rb'); 106 | flock($fp, LOCK_SH); 107 | $ret = stream_get_contents($fp); 108 | flock($fp, LOCK_UN); 109 | fclose($fp); 110 | return $ret; 111 | } else { 112 | return file_get_contents($this->_path . '/' . $id); 113 | } 114 | } 115 | 116 | /** 117 | * Fetch the cache path used 118 | * 119 | * @return string 120 | */ 121 | public function getPath() 122 | { 123 | return $this->_path; 124 | } 125 | 126 | /** 127 | * Send message to the Minify logger 128 | * @param string $msg 129 | * @return null 130 | */ 131 | protected function _log($msg) 132 | { 133 | require_once 'Minify/Logger.php'; 134 | Minify_Logger::log($msg); 135 | } 136 | 137 | private $_path = null; 138 | private $_locking = null; 139 | } 140 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/Version1.php: -------------------------------------------------------------------------------- 1 | 13 | * Minify::serve('Version1'); 14 | * 15 | * 16 | * @package Minify 17 | * @author Stephen Clay 18 | */ 19 | class Minify_Controller_Version1 extends Minify_Controller_Base { 20 | 21 | /** 22 | * Set up groups of files as sources 23 | * 24 | * @param array $options controller and Minify options 25 | * @return array Minify options 26 | * 27 | */ 28 | public function setupSources($options) { 29 | self::_setupDefines(); 30 | if (MINIFY_USE_CACHE) { 31 | $cacheDir = defined('MINIFY_CACHE_DIR') 32 | ? MINIFY_CACHE_DIR 33 | : ''; 34 | Minify::setCache($cacheDir); 35 | } 36 | $options['badRequestHeader'] = 'HTTP/1.0 404 Not Found'; 37 | $options['contentTypeCharset'] = MINIFY_ENCODING; 38 | 39 | // The following restrictions are to limit the URLs that minify will 40 | // respond to. Ideally there should be only one way to reference a file. 41 | if (! isset($_GET['files']) 42 | // verify at least one file, files are single comma separated, 43 | // and are all same extension 44 | || ! preg_match('/^[^,]+\\.(css|js)(,[^,]+\\.\\1)*$/', $_GET['files'], $m) 45 | // no "//" (makes URL rewriting easier) 46 | || strpos($_GET['files'], '//') !== false 47 | // no "\" 48 | || strpos($_GET['files'], '\\') !== false 49 | // no "./" 50 | || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['files']) 51 | ) { 52 | return $options; 53 | } 54 | $extension = $m[1]; 55 | 56 | $files = explode(',', $_GET['files']); 57 | if (count($files) > MINIFY_MAX_FILES) { 58 | return $options; 59 | } 60 | 61 | // strings for prepending to relative/absolute paths 62 | $prependRelPaths = dirname($_SERVER['SCRIPT_FILENAME']) 63 | . DIRECTORY_SEPARATOR; 64 | $prependAbsPaths = $_SERVER['DOCUMENT_ROOT']; 65 | 66 | $sources = array(); 67 | $goodFiles = array(); 68 | $hasBadSource = false; 69 | 70 | $allowDirs = isset($options['allowDirs']) 71 | ? $options['allowDirs'] 72 | : MINIFY_BASE_DIR; 73 | 74 | foreach ($files as $file) { 75 | // prepend appropriate string for abs/rel paths 76 | $file = ($file[0] === '/' ? $prependAbsPaths : $prependRelPaths) . $file; 77 | // make sure a real file! 78 | $file = realpath($file); 79 | // don't allow unsafe or duplicate files 80 | if (parent::_fileIsSafe($file, $allowDirs) 81 | && !in_array($file, $goodFiles)) 82 | { 83 | $goodFiles[] = $file; 84 | $srcOptions = array( 85 | 'filepath' => $file 86 | ); 87 | $this->sources[] = new Minify_Source($srcOptions); 88 | } else { 89 | $hasBadSource = true; 90 | break; 91 | } 92 | } 93 | if ($hasBadSource) { 94 | $this->sources = array(); 95 | } 96 | if (! MINIFY_REWRITE_CSS_URLS) { 97 | $options['rewriteCssUris'] = false; 98 | } 99 | return $options; 100 | } 101 | 102 | private static function _setupDefines() 103 | { 104 | $defaults = array( 105 | 'MINIFY_BASE_DIR' => realpath($_SERVER['DOCUMENT_ROOT']) 106 | ,'MINIFY_ENCODING' => 'utf-8' 107 | ,'MINIFY_MAX_FILES' => 16 108 | ,'MINIFY_REWRITE_CSS_URLS' => true 109 | ,'MINIFY_USE_CACHE' => true 110 | ); 111 | foreach ($defaults as $const => $val) { 112 | if (! defined($const)) { 113 | define($const, $val); 114 | } 115 | } 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /public/docs/js/modernizr-2.0.min.js: -------------------------------------------------------------------------------- 1 | window.Modernizr=function(A,e,o){function w(a,b){for(var c in a)if(B[a[c]]!==o&&(!b||b(a[c],x)))return true}var d={},l=e.documentElement,C=e.head||e.getElementsByTagName("head")[0],x=e.createElement("modernizr"),B=x.style;e.createElement("input");var J=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),K="Webkit Moz O ms Khtml".split(" "),m={},D=[],s;(function(){var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return function(b,c){c=c||e.createElement(a[b]|| 2 | "div");b="on"+b;var j=b in c;if(!j){c.setAttribute||(c=e.createElement("div"));if(c.setAttribute&&c.removeAttribute){c.setAttribute(b,"");j=typeof c[b]==="function";typeof c[b]===o||(c[b]=o);c.removeAttribute(b)}}return j}})();var y={}.hasOwnProperty,E;E=typeof y!==o&&typeof y.call!==o?function(a,b){return y.call(a,b)}:function(a,b){return b in a&&typeof a.constructor.prototype[b]===o};m.csstransforms=function(){return!!w(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])}; 3 | m.csstransforms3d=function(){var a=!!w(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);if(a&&"webkitPerspective"in l.style){var b="@media ("+J.join("transform-3d),(")+"modernizr)";a=e.createElement("style");var c=e.createElement("div");a.textContent=b+"{#modernizr{height:3px}}";C.appendChild(a);c.id="modernizr";l.appendChild(c);b=c.offsetHeight===3;a.parentNode.removeChild(a);c.parentNode.removeChild(c);a=!!b}return a};m.csstransitions=function(){var a= 4 | "transitionProperty".charAt(0).toUpperCase()+"transitionProperty".substr(1);a=("transitionProperty "+K.join(a+" ")+a).split(" ");return!!w(a,void 0)};m.fontface=function(){var a,b=C||l,c=e.createElement("style"),j=e.implementation||{hasFeature:function(){return false}};c.type="text/css";b.insertBefore(c,b.firstChild);a=c.sheet||c.styleSheet;b=j.hasFeature("CSS2","")?function(g){if(!(a&&g))return false;var q=false;try{a.insertRule(g,0);q=!/unknown/i.test(a.cssRules[0].cssText);a.deleteRule(a.cssRules.length- 5 | 1)}catch(F){}return q}:function(g){if(!(a&&g))return false;a.cssText=g;return a.cssText.length!==0&&!/unknown/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,"").indexOf(g.split(" ")[0])===0};d._fontfaceready=function(g){g(d.fontface)};return b('@font-face { font-family: "font"; src: "font.ttf"; }')};for(var z in m)if(E(m,z)){s=z.toLowerCase();d[s]=m[z]();D.push((d[s]?"":"no-")+s)}d.crosswindowmessaging=d.postmessage;d.historymanagement=d.history;d.addTest=function(a,b){a=a.toLowerCase();if(!d[a]){b= 6 | !!b();l.className+=" "+(b?"":"no-")+a;d[a]=b;return d}};B.cssText="";x=f=null;A.attachEvent&&function(){var a=e.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function c(k){for(var h=-1;++h 16 | * Minify_YUICompressor::$jarFile = '/path/to/yuicompressor-2.3.5.jar'; 17 | * Minify_YUICompressor::$tempDir = '/tmp'; 18 | * $code = Minify_YUICompressor::minifyJs( 19 | * $code 20 | * ,array('nomunge' => true, 'line-break' => 1000) 21 | * ); 22 | * 23 | * 24 | * @todo unit tests, $options docs 25 | * 26 | * @package Minify 27 | * @author Stephen Clay 28 | */ 29 | class Minify_YUICompressor { 30 | 31 | /** 32 | * Filepath of the YUI Compressor jar file. This must be set before 33 | * calling minifyJs() or minifyCss(). 34 | * 35 | * @var string 36 | */ 37 | public static $jarFile = null; 38 | 39 | /** 40 | * Writable temp directory. This must be set before calling minifyJs() 41 | * or minifyCss(). 42 | * 43 | * @var string 44 | */ 45 | public static $tempDir = null; 46 | 47 | /** 48 | * Filepath of "java" executable (may be needed if not in shell's PATH) 49 | * 50 | * @var string 51 | */ 52 | public static $javaExecutable = 'java'; 53 | 54 | /** 55 | * Minify a Javascript string 56 | * 57 | * @param string $js 58 | * 59 | * @param array $options (verbose is ignored) 60 | * 61 | * @see http://www.julienlecomte.net/yuicompressor/README 62 | * 63 | * @return string 64 | */ 65 | public static function minifyJs($js, $options = array()) 66 | { 67 | return self::_minify('js', $js, $options); 68 | } 69 | 70 | /** 71 | * Minify a CSS string 72 | * 73 | * @param string $css 74 | * 75 | * @param array $options (verbose is ignored) 76 | * 77 | * @see http://www.julienlecomte.net/yuicompressor/README 78 | * 79 | * @return string 80 | */ 81 | public static function minifyCss($css, $options = array()) 82 | { 83 | return self::_minify('css', $css, $options); 84 | } 85 | 86 | private static function _minify($type, $content, $options) 87 | { 88 | self::_prepare(); 89 | if (! ($tmpFile = tempnam(self::$tempDir, 'yuic_'))) { 90 | throw new Exception('Minify_YUICompressor : could not create temp file.'); 91 | } 92 | file_put_contents($tmpFile, $content); 93 | exec(self::_getCmd($options, $type, $tmpFile), $output); 94 | unlink($tmpFile); 95 | return implode("\n", $output); 96 | } 97 | 98 | private static function _getCmd($userOptions, $type, $tmpFile) 99 | { 100 | $o = array_merge( 101 | array( 102 | 'charset' => '' 103 | ,'line-break' => 5000 104 | ,'type' => $type 105 | ,'nomunge' => false 106 | ,'preserve-semi' => false 107 | ,'disable-optimizations' => false 108 | ) 109 | ,$userOptions 110 | ); 111 | $cmd = self::$javaExecutable . ' -jar ' . escapeshellarg(self::$jarFile) 112 | . " --type {$type}" 113 | . (preg_match('/^[a-zA-Z0-9\\-]+$/', $o['charset']) 114 | ? " --charset {$o['charset']}" 115 | : '') 116 | . (is_numeric($o['line-break']) && $o['line-break'] >= 0 117 | ? ' --line-break ' . (int)$o['line-break'] 118 | : ''); 119 | if ($type === 'js') { 120 | foreach (array('nomunge', 'preserve-semi', 'disable-optimizations') as $opt) { 121 | $cmd .= $o[$opt] 122 | ? " --{$opt}" 123 | : ''; 124 | } 125 | } 126 | return $cmd . ' ' . escapeshellarg($tmpFile); 127 | } 128 | 129 | private static function _prepare() 130 | { 131 | if (! is_file(self::$jarFile)) { 132 | throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.'); 133 | } 134 | if (! is_dir(self::$tempDir)) { 135 | throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.'); 136 | } 137 | if (! is_writable(self::$tempDir)) { 138 | throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.'); 139 | } 140 | } 141 | } 142 | 143 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Lines.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Adam Pedersen (Issue 55 fix) 13 | */ 14 | class Minify_Lines { 15 | 16 | /** 17 | * Add line numbers in C-style comments 18 | * 19 | * This uses a very basic parser easily fooled by comment tokens inside 20 | * strings or regexes, but, otherwise, generally clean code will not be 21 | * mangled. URI rewriting can also be performed. 22 | * 23 | * @param string $content 24 | * 25 | * @param array $options available options: 26 | * 27 | * 'id': (optional) string to identify file. E.g. file name/path 28 | * 29 | * 'currentDir': (default null) if given, this is assumed to be the 30 | * directory of the current CSS file. Using this, minify will rewrite 31 | * all relative URIs in import/url declarations to correctly point to 32 | * the desired files, and prepend a comment with debugging information about 33 | * this process. 34 | * 35 | * @return string 36 | */ 37 | public static function minify($content, $options = array()) 38 | { 39 | $id = (isset($options['id']) && $options['id']) 40 | ? $options['id'] 41 | : ''; 42 | $content = str_replace("\r\n", "\n", $content); 43 | 44 | // Hackily rewrite strings with XPath expressions that are 45 | // likely to throw off our dumb parser (for Prototype 1.6.1). 46 | $content = str_replace('"/*"', '"/"+"*"', $content); 47 | $content = preg_replace('@([\'"])(\\.?//?)\\*@', '$1$2$1+$1*', $content); 48 | 49 | $lines = explode("\n", $content); 50 | $numLines = count($lines); 51 | // determine left padding 52 | $padTo = strlen((string) $numLines); // e.g. 103 lines = 3 digits 53 | $inComment = false; 54 | $i = 0; 55 | $newLines = array(); 56 | while (null !== ($line = array_shift($lines))) { 57 | if (('' !== $id) && (0 == $i % 50)) { 58 | array_push($newLines, '', "/* {$id} */", ''); 59 | } 60 | ++$i; 61 | $newLines[] = self::_addNote($line, $i, $inComment, $padTo); 62 | $inComment = self::_eolInComment($line, $inComment); 63 | } 64 | $content = implode("\n", $newLines) . "\n"; 65 | 66 | // check for desired URI rewriting 67 | if (isset($options['currentDir'])) { 68 | require_once 'Minify/CSS/UriRewriter.php'; 69 | Minify_CSS_UriRewriter::$debugText = ''; 70 | $content = Minify_CSS_UriRewriter::rewrite( 71 | $content 72 | ,$options['currentDir'] 73 | ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT'] 74 | ,isset($options['symlinks']) ? $options['symlinks'] : array() 75 | ); 76 | $content = "/* Minify_CSS_UriRewriter::\$debugText\n\n" 77 | . Minify_CSS_UriRewriter::$debugText . "*/\n" 78 | . $content; 79 | } 80 | 81 | return $content; 82 | } 83 | 84 | /** 85 | * Is the parser within a C-style comment at the end of this line? 86 | * 87 | * @param string $line current line of code 88 | * 89 | * @param bool $inComment was the parser in a comment at the 90 | * beginning of the line? 91 | * 92 | * @return bool 93 | */ 94 | private static function _eolInComment($line, $inComment) 95 | { 96 | while (strlen($line)) { 97 | $search = $inComment 98 | ? '*/' 99 | : '/*'; 100 | $pos = strpos($line, $search); 101 | if (false === $pos) { 102 | return $inComment; 103 | } else { 104 | if ($pos == 0 105 | || ($inComment 106 | ? substr($line, $pos, 3) 107 | : substr($line, $pos-1, 3)) != '*/*') 108 | { 109 | $inComment = ! $inComment; 110 | } 111 | $line = substr($line, $pos + 2); 112 | } 113 | } 114 | return $inComment; 115 | } 116 | 117 | /** 118 | * Prepend a comment (or note) to the given line 119 | * 120 | * @param string $line current line of code 121 | * 122 | * @param string $note content of note/comment 123 | * 124 | * @param bool $inComment was the parser in a comment at the 125 | * beginning of the line? 126 | * 127 | * @param int $padTo minimum width of comment 128 | * 129 | * @return string 130 | */ 131 | private static function _addNote($line, $note, $inComment, $padTo) 132 | { 133 | return $inComment 134 | ? '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' *| ' . $line 135 | : '/* ' . str_pad($note, $padTo, ' ', STR_PAD_RIGHT) . ' */ ' . $line; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /public/min/README.txt: -------------------------------------------------------------------------------- 1 | The files in this directory represent the default Minify setup designed to ease 2 | integration with your site. This app will combine and minify your Javascript or 3 | CSS files and serve them with HTTP compression and cache headers. 4 | 5 | 6 | RECOMMENDED 7 | 8 | It's recommended to edit config.php to set $min_cachePath to a writeable 9 | (by PHP) directory on your system. This will improve performance. 10 | 11 | 12 | GETTING STARTED 13 | 14 | The quickest way to get started is to use the Minify URI Builder application 15 | on your website: http://example.com/min/builder/ 16 | 17 | 18 | MINIFYING A SINGLE FILE 19 | 20 | Let's say you want to serve this file: 21 | http://example.com/wp-content/themes/default/default.css 22 | 23 | Here's the "Minify URL" for this file: 24 | http://example.com/min/?f=wp-content/themes/default/default.css 25 | 26 | In other words, the "f" argument is set to the file path from root without the 27 | initial "/". As CSS files may contain relative URIs, Minify will automatically 28 | "fix" these by rewriting them as root relative. 29 | 30 | 31 | COMBINING MULTIPLE FILES IN ONE DOWNLOAD 32 | 33 | Separate the paths given to "f" with commas. 34 | 35 | Let's say you have CSS files at these URLs: 36 | http://example.com/scripts/jquery-1.2.6.js 37 | http://example.com/scripts/site.js 38 | 39 | You can combine these files through Minify by requesting this URL: 40 | http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js 41 | 42 | 43 | SIMPLIFYING URLS WITH A BASE PATH 44 | 45 | If you're combining files that share the same ancestor directory, you can use 46 | the "b" argument to set the base directory for the "f" argument. Do not include 47 | the leading or trailing "/" characters. 48 | 49 | E.g., the following URLs will serve the exact same content: 50 | http://example.com/min/?f=scripts/jquery-1.2.6.js,scripts/site.js,scripts/home.js 51 | http://example.com/min/?b=scripts&f=jquery-1.2.6.js,site.js,home.js 52 | 53 | 54 | MINIFY URLS IN HTML 55 | 56 | In (X)HTML files, don't forget to replace any "&" characters with "&". 57 | 58 | 59 | SPECIFYING ALLOWED DIRECTORIES 60 | 61 | By default, Minify will serve any *.css/*.js files within the DOCUMENT_ROOT. If 62 | you'd prefer to limit Minify's access to certain directories, set the 63 | $min_serveOptions['minApp']['allowDirs'] array in config.php. E.g. to limit 64 | to the /js and /themes/default directories, use: 65 | 66 | $min_serveOptions['minApp']['allowDirs'] = array('//js', '//themes/default'); 67 | 68 | 69 | GROUPS: NICER URLS 70 | 71 | For nicer URLs, edit groupsConfig.php to pre-specify groups of files 72 | to be combined under preset keys. E.g., here's an example configuration in 73 | groupsConfig.php: 74 | 75 | return array( 76 | 'js' => array('//js/Class.js', '//js/email.js') 77 | ); 78 | 79 | This pre-selects the following files to be combined under the key "js": 80 | http://example.com/js/Class.js 81 | http://example.com/js/email.js 82 | 83 | You can now serve these files with this simple URL: 84 | http://example.com/min/?g=js 85 | 86 | 87 | GROUPS: SPECIFYING FILES OUTSIDE THE DOC_ROOT 88 | 89 | In the groupsConfig.php array, the "//" in the file paths is a shortcut for 90 | the DOCUMENT_ROOT, but you can also specify paths from the root of the filesystem 91 | or relative to the DOC_ROOT: 92 | 93 | return array( 94 | 'js' => array( 95 | '//js/file.js' // file within DOC_ROOT 96 | ,'//../file.js' // file in parent directory of DOC_ROOT 97 | ,'C:/Users/Steve/file.js' // file anywhere on filesystem 98 | ) 99 | ); 100 | 101 | 102 | COMBINE MULTIPLE GROUPS AND FILES IN ONE URL 103 | 104 | E.g.: http://example.com/min/?g=js&f=more/scripts.js 105 | 106 | Separate group keys with commas: 107 | http://example.com/min/?g=baseCss,css1&f=moreStyles.css 108 | 109 | 110 | FAR-FUTURE EXPIRES HEADERS 111 | 112 | Minify can send far-future (one year) Expires headers. To enable this you must 113 | add a number to the querystring (e.g. /min/?g=js&1234 or /min/f=file.js&1234) 114 | and alter it whenever a source file is changed. If you have a build process you 115 | can use a build/source control revision number. 116 | 117 | You can alternately use the utility function Minify_getUri() to get a "versioned" 118 | Minify URI for use in your HTML. E.g.: 119 | 120 | "; 125 | 126 | $cssUri = Minify_getUri(array( 127 | '//css/styles1.css' 128 | ,'//css/styles2.css' 129 | )); // a list of files 130 | echo ""; 131 | 132 | 133 | DEBUG MODE 134 | 135 | In debug mode, instead of compressing files, Minify sends combined files with 136 | comments prepended to each line to show the line number in the original source 137 | file. To enable this, set $min_allowDebugFlag to true in config.php and append 138 | "&debug=1" to your URIs. E.g. /min/?f=script1.js,script2.js&debug=1 139 | 140 | Known issue: files with comment-like strings/regexps can cause problems in this mode. 141 | 142 | 143 | QUESTIONS? 144 | 145 | http://groups.google.com/group/minify -------------------------------------------------------------------------------- /app/stacey.inc.php: -------------------------------------------------------------------------------- 1 | hash.'"'); 71 | if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) == '"'.$cache->hash.'"') { 72 | # local cache is still fresh, so return 304 73 | header("HTTP/1.0 304 Not Modified"); 74 | header('Content-Length: 0'); 75 | return false; 76 | } else { 77 | return true; 78 | } 79 | } 80 | 81 | function render($file_path, $template_file) { 82 | $cache = new Cache($file_path, $template_file); 83 | # set any custom headers 84 | $this->set_content_type($template_file); 85 | # if etag is still fresh, return 304 and don't render anything 86 | if(!$this->etag_expired($cache)) return; 87 | # if cache has expired 88 | if($cache->expired()) { 89 | # render page & create new cache 90 | echo $cache->create($this->route); 91 | } else { 92 | # render the existing cache 93 | echo $cache->render(); 94 | } 95 | } 96 | 97 | function create_page($file_path) { 98 | # return a 404 if a matching folder doesn't exist 99 | if(!file_exists($file_path)) throw new Exception('404'); 100 | 101 | # register global for the path to the page which is currently being viewed 102 | global $current_page_file_path; 103 | $current_page_file_path = $file_path; 104 | 105 | # register global for the template for the page which is currently being viewed 106 | global $current_page_template_file; 107 | $template_name = Page::template_name($file_path); 108 | $current_page_template_file = Page::template_file($template_name); 109 | 110 | # error out if template file doesn't exist (or glob returns an error) 111 | if(empty($template_name)) throw new Exception('404'); 112 | 113 | if(!$current_page_template_file) { 114 | throw new Exception('A template named \''.$template_name.'\' could not be found in the \'/templates\' folder'); 115 | } 116 | # render page 117 | $this->render($file_path, $current_page_template_file); 118 | } 119 | 120 | function __construct($get) { 121 | # sometimes when PHP release a new version, they do silly things - this function is here to fix them 122 | $this->php_fixes(); 123 | # it's easier to handle some redirection through php rather than relying on a more complex .htaccess file to do all the work 124 | if($this->handle_redirects()) return; 125 | 126 | # strip any leading or trailing slashes from the passed url 127 | $key = preg_replace(array('/\/$/', '/^\//'), '', key($get)); 128 | # store file path for this current page 129 | $this->route = isset($key) ? $key : 'index'; 130 | $file_path = Helpers::url_to_file_path($this->route); 131 | 132 | try { 133 | # create and render the current page 134 | $this->create_page($file_path); 135 | } catch(Exception $e) { 136 | if($e->getMessage() == "404") { 137 | # return 404 headers 138 | header('HTTP/1.0 404 Not Found'); 139 | if(file_exists('./content/404')) { 140 | $this->create_page('./content/404', '404'); 141 | } 142 | else if(file_exists('./public/404.html')) { 143 | echo file_get_contents('./public/404.html'); 144 | } 145 | else { 146 | echo '

404

Page could not be found.

Unfortunately, the page you were looking for does not exist here.

'; 147 | } 148 | 149 | } else { 150 | echo '

'.$e->getMessage().'

'; 151 | } 152 | } 153 | } 154 | 155 | } 156 | 157 | ?> -------------------------------------------------------------------------------- /public/min/lib/Minify/ImportProcessor.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class Minify_ImportProcessor { 21 | 22 | public static $filesIncluded = array(); 23 | 24 | public static function process($file) 25 | { 26 | self::$filesIncluded = array(); 27 | self::$_isCss = (strtolower(substr($file, -4)) === '.css'); 28 | $obj = new Minify_ImportProcessor(dirname($file)); 29 | return $obj->_getContent($file); 30 | } 31 | 32 | // allows callback funcs to know the current directory 33 | private $_currentDir = null; 34 | 35 | // allows _importCB to write the fetched content back to the obj 36 | private $_importedContent = ''; 37 | 38 | private static $_isCss = null; 39 | 40 | private function __construct($currentDir) 41 | { 42 | $this->_currentDir = $currentDir; 43 | } 44 | 45 | private function _getContent($file) 46 | { 47 | $file = realpath($file); 48 | if (! $file 49 | || in_array($file, self::$filesIncluded) 50 | || false === ($content = @file_get_contents($file)) 51 | ) { 52 | // file missing, already included, or failed read 53 | return ''; 54 | } 55 | self::$filesIncluded[] = realpath($file); 56 | $this->_currentDir = dirname($file); 57 | 58 | // remove UTF-8 BOM if present 59 | if (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) { 60 | $content = substr($content, 3); 61 | } 62 | // ensure uniform EOLs 63 | $content = str_replace("\r\n", "\n", $content); 64 | 65 | // process @imports 66 | $content = preg_replace_callback( 67 | '/ 68 | @import\\s+ 69 | (?:url\\(\\s*)? # maybe url( 70 | [\'"]? # maybe quote 71 | (.*?) # 1 = URI 72 | [\'"]? # maybe end quote 73 | (?:\\s*\\))? # maybe ) 74 | ([a-zA-Z,\\s]*)? # 2 = media list 75 | ; # end token 76 | /x' 77 | ,array($this, '_importCB') 78 | ,$content 79 | ); 80 | 81 | if (self::$_isCss) { 82 | // rewrite remaining relative URIs 83 | $content = preg_replace_callback( 84 | '/url\\(\\s*([^\\)\\s]+)\\s*\\)/' 85 | ,array($this, '_urlCB') 86 | ,$content 87 | ); 88 | } 89 | 90 | return $this->_importedContent . $content; 91 | } 92 | 93 | private function _importCB($m) 94 | { 95 | $url = $m[1]; 96 | $mediaList = preg_replace('/\\s+/', '', $m[2]); 97 | 98 | if (strpos($url, '://') > 0) { 99 | // protocol, leave in place for CSS, comment for JS 100 | return self::$_isCss 101 | ? $m[0] 102 | : "/* Minify_ImportProcessor will not include remote content */"; 103 | } 104 | if ('/' === $url[0]) { 105 | // protocol-relative or root path 106 | $url = ltrim($url, '/'); 107 | $file = realpath($_SERVER['DOCUMENT_ROOT']) . DIRECTORY_SEPARATOR 108 | . strtr($url, '/', DIRECTORY_SEPARATOR); 109 | } else { 110 | // relative to current path 111 | $file = $this->_currentDir . DIRECTORY_SEPARATOR 112 | . strtr($url, '/', DIRECTORY_SEPARATOR); 113 | } 114 | $obj = new Minify_ImportProcessor(dirname($file)); 115 | $content = $obj->_getContent($file); 116 | if ('' === $content) { 117 | // failed. leave in place for CSS, comment for JS 118 | return self::$_isCss 119 | ? $m[0] 120 | : "/* Minify_ImportProcessor could not fetch '{$file}' */";; 121 | } 122 | return (!self::$_isCss || preg_match('@(?:^$|\\ball\\b)@', $mediaList)) 123 | ? $content 124 | : "@media {$mediaList} {\n{$content}\n}\n"; 125 | } 126 | 127 | private function _urlCB($m) 128 | { 129 | // $m[1] is either quoted or not 130 | $quote = ($m[1][0] === "'" || $m[1][0] === '"') 131 | ? $m[1][0] 132 | : ''; 133 | $url = ($quote === '') 134 | ? $m[1] 135 | : substr($m[1], 1, strlen($m[1]) - 2); 136 | if ('/' !== $url[0]) { 137 | if (strpos($url, '//') > 0) { 138 | // probably starts with protocol, do not alter 139 | } else { 140 | // prepend path with current dir separator (OS-independent) 141 | $path = $this->_currentDir 142 | . DIRECTORY_SEPARATOR . strtr($url, '/', DIRECTORY_SEPARATOR); 143 | // strip doc root 144 | $path = substr($path, strlen(realpath($_SERVER['DOCUMENT_ROOT']))); 145 | // fix to absolute URL 146 | $url = strtr($path, '/\\', '//'); 147 | // remove /./ and /../ where possible 148 | $url = str_replace('/./', '/', $url); 149 | // inspired by patch from Oleg Cherniy 150 | do { 151 | $url = preg_replace('@/[^/]+/\\.\\./@', '/', $url, 1, $changed); 152 | } while ($changed); 153 | } 154 | } 155 | return "url({$quote}{$url}{$quote})"; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Source.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | class Minify_Source { 17 | 18 | /** 19 | * @var int time of last modification 20 | */ 21 | public $lastModified = null; 22 | 23 | /** 24 | * @var callback minifier function specifically for this source. 25 | */ 26 | public $minifier = null; 27 | 28 | /** 29 | * @var array minification options specific to this source. 30 | */ 31 | public $minifyOptions = null; 32 | 33 | /** 34 | * @var string full path of file 35 | */ 36 | public $filepath = null; 37 | 38 | /** 39 | * @var string HTTP Content Type (Minify requires one of the constants Minify::TYPE_*) 40 | */ 41 | public $contentType = null; 42 | 43 | /** 44 | * Create a Minify_Source 45 | * 46 | * In the $spec array(), you can either provide a 'filepath' to an existing 47 | * file (existence will not be checked!) or give 'id' (unique string for 48 | * the content), 'content' (the string content) and 'lastModified' 49 | * (unixtime of last update). 50 | * 51 | * As a shortcut, the controller will replace "//" at the beginning 52 | * of a filepath with $_SERVER['DOCUMENT_ROOT'] . '/'. 53 | * 54 | * @param array $spec options 55 | */ 56 | public function __construct($spec) 57 | { 58 | if (isset($spec['filepath'])) { 59 | if (0 === strpos($spec['filepath'], '//')) { 60 | $spec['filepath'] = $_SERVER['DOCUMENT_ROOT'] . substr($spec['filepath'], 1); 61 | } 62 | $segments = explode('.', $spec['filepath']); 63 | $ext = strtolower(array_pop($segments)); 64 | switch ($ext) { 65 | case 'js' : $this->contentType = 'application/x-javascript'; 66 | break; 67 | case 'css' : $this->contentType = 'text/css'; 68 | break; 69 | case 'htm' : // fallthrough 70 | case 'html' : $this->contentType = 'text/html'; 71 | break; 72 | } 73 | $this->filepath = $spec['filepath']; 74 | $this->_id = $spec['filepath']; 75 | $this->lastModified = filemtime($spec['filepath']) 76 | // offset for Windows uploaders with out of sync clocks 77 | + round(Minify::$uploaderHoursBehind * 3600); 78 | } elseif (isset($spec['id'])) { 79 | $this->_id = 'id::' . $spec['id']; 80 | if (isset($spec['content'])) { 81 | $this->_content = $spec['content']; 82 | } else { 83 | $this->_getContentFunc = $spec['getContentFunc']; 84 | } 85 | $this->lastModified = isset($spec['lastModified']) 86 | ? $spec['lastModified'] 87 | : time(); 88 | } 89 | if (isset($spec['contentType'])) { 90 | $this->contentType = $spec['contentType']; 91 | } 92 | if (isset($spec['minifier'])) { 93 | $this->minifier = $spec['minifier']; 94 | } 95 | if (isset($spec['minifyOptions'])) { 96 | $this->minifyOptions = $spec['minifyOptions']; 97 | } 98 | } 99 | 100 | /** 101 | * Get content 102 | * 103 | * @return string 104 | */ 105 | public function getContent() 106 | { 107 | $content = (null !== $this->filepath) 108 | ? file_get_contents($this->filepath) 109 | : ((null !== $this->_content) 110 | ? $this->_content 111 | : call_user_func($this->_getContentFunc, $this->_id) 112 | ); 113 | // remove UTF-8 BOM if present 114 | return (pack("CCC",0xef,0xbb,0xbf) === substr($content, 0, 3)) 115 | ? substr($content, 3) 116 | : $content; 117 | } 118 | 119 | /** 120 | * Get id 121 | * 122 | * @return string 123 | */ 124 | public function getId() 125 | { 126 | return $this->_id; 127 | } 128 | 129 | /** 130 | * Verifies a single minification call can handle all sources 131 | * 132 | * @param array $sources Minify_Source instances 133 | * 134 | * @return bool true iff there no sources with specific minifier preferences. 135 | */ 136 | public static function haveNoMinifyPrefs($sources) 137 | { 138 | foreach ($sources as $source) { 139 | if (null !== $source->minifier 140 | || null !== $source->minifyOptions) { 141 | return false; 142 | } 143 | } 144 | return true; 145 | } 146 | 147 | /** 148 | * Get unique string for a set of sources 149 | * 150 | * @param array $sources Minify_Source instances 151 | * 152 | * @return string 153 | */ 154 | public static function getDigest($sources) 155 | { 156 | foreach ($sources as $source) { 157 | $info[] = array( 158 | $source->_id, $source->minifier, $source->minifyOptions 159 | ); 160 | } 161 | return md5(serialize($info)); 162 | } 163 | 164 | /** 165 | * Get content type from a group of sources 166 | * 167 | * This is called if the user doesn't pass in a 'contentType' options 168 | * 169 | * @param array $sources Minify_Source instances 170 | * 171 | * @return string content type. e.g. 'text/css' 172 | */ 173 | public static function getContentType($sources) 174 | { 175 | foreach ($sources as $source) { 176 | if ($source->contentType !== null) { 177 | return $source->contentType; 178 | } 179 | } 180 | return 'text/plain'; 181 | } 182 | 183 | protected $_content = null; 184 | protected $_getContentFunc = null; 185 | protected $_id = null; 186 | } 187 | 188 | -------------------------------------------------------------------------------- /public/min/lib/Solar/Dir.php: -------------------------------------------------------------------------------- 1 | 11 | * 12 | * @license http://opensource.org/licenses/bsd-license.php BSD 13 | * 14 | * @version $Id: Dir.php 2926 2007-11-09 16:25:44Z pmjones $ 15 | * 16 | */ 17 | class Solar_Dir { 18 | 19 | /** 20 | * 21 | * The OS-specific temporary directory location. 22 | * 23 | * @var string 24 | * 25 | */ 26 | protected static $_tmp; 27 | 28 | /** 29 | * 30 | * Hack for [[php::is_dir() | ]] that checks the include_path. 31 | * 32 | * Use this to see if a directory exists anywhere in the include_path. 33 | * 34 | * {{code: php 35 | * $dir = Solar_Dir::exists('path/to/dir') 36 | * if ($dir) { 37 | * $files = scandir($dir); 38 | * } else { 39 | * echo "Not found in the include-path."; 40 | * } 41 | * }} 42 | * 43 | * @param string $dir Check for this directory in the include_path. 44 | * 45 | * @return mixed If the directory exists in the include_path, returns the 46 | * absolute path; if not, returns boolean false. 47 | * 48 | */ 49 | public static function exists($dir) 50 | { 51 | // no file requested? 52 | $dir = trim($dir); 53 | if (! $dir) { 54 | return false; 55 | } 56 | 57 | // using an absolute path for the file? 58 | // dual check for Unix '/' and Windows '\', 59 | // or Windows drive letter and a ':'. 60 | $abs = ($dir[0] == '/' || $dir[0] == '\\' || $dir[1] == ':'); 61 | if ($abs && is_dir($dir)) { 62 | return $dir; 63 | } 64 | 65 | // using a relative path on the file 66 | $path = explode(PATH_SEPARATOR, ini_get('include_path')); 67 | foreach ($path as $base) { 68 | // strip Unix '/' and Windows '\' 69 | $target = rtrim($base, '\\/') . DIRECTORY_SEPARATOR . $dir; 70 | if (is_dir($target)) { 71 | return $target; 72 | } 73 | } 74 | 75 | // never found it 76 | return false; 77 | } 78 | 79 | /** 80 | * 81 | * "Fixes" a directory string for the operating system. 82 | * 83 | * Use slashes anywhere you need a directory separator. Then run the 84 | * string through fixdir() and the slashes will be converted to the 85 | * proper separator (for example '\' on Windows). 86 | * 87 | * Always adds a final trailing separator. 88 | * 89 | * @param string $dir The directory string to 'fix'. 90 | * 91 | * @return string The "fixed" directory string. 92 | * 93 | */ 94 | public static function fix($dir) 95 | { 96 | $dir = str_replace('/', DIRECTORY_SEPARATOR, $dir); 97 | return rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 98 | } 99 | 100 | /** 101 | * 102 | * Convenience method for dirname() and higher-level directories. 103 | * 104 | * @param string $file Get the dirname() of this file. 105 | * 106 | * @param int $up Move up in the directory structure this many 107 | * times, default 0. 108 | * 109 | * @return string The dirname() of the file. 110 | * 111 | */ 112 | public static function name($file, $up = 0) 113 | { 114 | $dir = dirname($file); 115 | while ($up --) { 116 | $dir = dirname($dir); 117 | } 118 | return $dir; 119 | } 120 | 121 | /** 122 | * 123 | * Returns the OS-specific directory for temporary files. 124 | * 125 | * @param string $sub Add this subdirectory to the returned temporary 126 | * directory name. 127 | * 128 | * @return string The temporary directory path. 129 | * 130 | */ 131 | public static function tmp($sub = '') 132 | { 133 | // find the tmp dir if needed 134 | if (! Solar_Dir::$_tmp) { 135 | 136 | // use the system if we can 137 | if (function_exists('sys_get_temp_dir')) { 138 | $tmp = sys_get_temp_dir(); 139 | } else { 140 | $tmp = Solar_Dir::_tmp(); 141 | } 142 | 143 | // remove trailing separator and save 144 | Solar_Dir::$_tmp = rtrim($tmp, DIRECTORY_SEPARATOR); 145 | } 146 | 147 | // do we have a subdirectory request? 148 | $sub = trim($sub); 149 | if ($sub) { 150 | // remove leading and trailing separators, and force exactly 151 | // one trailing separator 152 | $sub = trim($sub, DIRECTORY_SEPARATOR) 153 | . DIRECTORY_SEPARATOR; 154 | } 155 | 156 | return Solar_Dir::$_tmp . DIRECTORY_SEPARATOR . $sub; 157 | } 158 | 159 | /** 160 | * 161 | * Returns the OS-specific temporary directory location. 162 | * 163 | * @return string The temp directory path. 164 | * 165 | */ 166 | protected static function _tmp() 167 | { 168 | // non-Windows system? 169 | if (strtolower(substr(PHP_OS, 0, 3)) != 'win') { 170 | $tmp = empty($_ENV['TMPDIR']) ? getenv('TMPDIR') : $_ENV['TMPDIR']; 171 | if ($tmp) { 172 | return $tmp; 173 | } else { 174 | return '/tmp'; 175 | } 176 | } 177 | 178 | // Windows 'TEMP' 179 | $tmp = empty($_ENV['TEMP']) ? getenv('TEMP') : $_ENV['TEMP']; 180 | if ($tmp) { 181 | return $tmp; 182 | } 183 | 184 | // Windows 'TMP' 185 | $tmp = empty($_ENV['TMP']) ? getenv('TMP') : $_ENV['TMP']; 186 | if ($tmp) { 187 | return $tmp; 188 | } 189 | 190 | // Windows 'windir' 191 | $tmp = empty($_ENV['windir']) ? getenv('windir') : $_ENV['windir']; 192 | if ($tmp) { 193 | return $tmp; 194 | } 195 | 196 | // final fallback for Windows 197 | return getenv('SystemRoot') . '\\temp'; 198 | } 199 | } -------------------------------------------------------------------------------- /public/min/config.php: -------------------------------------------------------------------------------- 1 | 134 | * array('//symlink' => '/real/target/path') // unix 135 | * array('//static' => 'D:\\staticStorage') // Windows 136 | * 137 | */ 138 | $min_symlinks = array(); 139 | 140 | 141 | /** 142 | * If you upload files from Windows to a non-Windows server, Windows may report 143 | * incorrect mtimes for the files. This may cause Minify to keep serving stale 144 | * cache files when source file changes are made too frequently (e.g. more than 145 | * once an hour). 146 | * 147 | * Immediately after modifying and uploading a file, use the touch command to 148 | * update the mtime on the server. If the mtime jumps ahead by a number of hours, 149 | * set this variable to that number. If the mtime moves back, this should not be 150 | * needed. 151 | * 152 | * In the Windows SFTP client WinSCP, there's an option that may fix this 153 | * issue without changing the variable below. Under login > environment, 154 | * select the option "Adjust remote timestamp with DST". 155 | * @link http://winscp.net/eng/docs/ui_login_environment#daylight_saving_time 156 | */ 157 | $min_uploaderHoursBehind = 0; 158 | 159 | 160 | /** 161 | * Path to Minify's lib folder. If you happen to move it, change 162 | * this accordingly. 163 | */ 164 | $min_libPath = dirname(__FILE__) . '/lib'; 165 | 166 | 167 | // try to disable output_compression (may not have an effect) 168 | ini_set('zlib.output_compression', '0'); 169 | -------------------------------------------------------------------------------- /public/min/lib/Minify/HTML/Helper.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class Minify_HTML_Helper { 14 | public $rewriteWorks = true; 15 | public $minAppUri = '/min'; 16 | public $groupsConfigFile = ''; 17 | 18 | /* 19 | * Get an HTML-escaped Minify URI for a group or set of files 20 | * 21 | * @param mixed $keyOrFiles a group key or array of filepaths/URIs 22 | * @param array $opts options: 23 | * 'farExpires' : (default true) append a modified timestamp for cache revving 24 | * 'debug' : (default false) append debug flag 25 | * 'charset' : (default 'UTF-8') for htmlspecialchars 26 | * 'minAppUri' : (default '/min') URI of min directory 27 | * 'rewriteWorks' : (default true) does mod_rewrite work in min app? 28 | * 'groupsConfigFile' : specify if different 29 | * @return string 30 | */ 31 | public static function getUri($keyOrFiles, $opts = array()) 32 | { 33 | $opts = array_merge(array( // default options 34 | 'farExpires' => true 35 | ,'debug' => false 36 | ,'charset' => 'UTF-8' 37 | ,'minAppUri' => '/min' 38 | ,'rewriteWorks' => true 39 | ,'groupsConfigFile' => '' 40 | ), $opts); 41 | $h = new self; 42 | $h->minAppUri = $opts['minAppUri']; 43 | $h->rewriteWorks = $opts['rewriteWorks']; 44 | $h->groupsConfigFile = $opts['groupsConfigFile']; 45 | if (is_array($keyOrFiles)) { 46 | $h->setFiles($keyOrFiles, $opts['farExpires']); 47 | } else { 48 | $h->setGroup($keyOrFiles, $opts['farExpires']); 49 | } 50 | $uri = $h->getRawUri($opts['farExpires'], $opts['debug']); 51 | return htmlspecialchars($uri, ENT_QUOTES, $opts['charset']); 52 | } 53 | 54 | /* 55 | * Get non-HTML-escaped URI to minify the specified files 56 | */ 57 | public function getRawUri($farExpires = true, $debug = false) 58 | { 59 | $path = rtrim($this->minAppUri, '/') . '/'; 60 | if (! $this->rewriteWorks) { 61 | $path .= '?'; 62 | } 63 | if (null === $this->_groupKey) { 64 | // @todo: implement shortest uri 65 | $path = self::_getShortestUri($this->_filePaths, $path); 66 | } else { 67 | $path .= "g=" . $this->_groupKey; 68 | } 69 | if ($debug) { 70 | $path .= "&debug"; 71 | } elseif ($farExpires && $this->_lastModified) { 72 | $path .= "&" . $this->_lastModified; 73 | } 74 | return $path; 75 | } 76 | 77 | public function setFiles($files, $checkLastModified = true) 78 | { 79 | $this->_groupKey = null; 80 | if ($checkLastModified) { 81 | $this->_lastModified = self::getLastModified($files); 82 | } 83 | // normalize paths like in /min/f= 84 | foreach ($files as $k => $file) { 85 | if (0 === strpos($file, '//')) { 86 | $file = substr($file, 2); 87 | } elseif (0 === strpos($file, '/') 88 | || 1 === strpos($file, ':\\')) { 89 | $file = substr($file, strlen($_SERVER['DOCUMENT_ROOT']) + 1); 90 | } 91 | $file = strtr($file, '\\', '/'); 92 | $files[$k] = $file; 93 | } 94 | $this->_filePaths = $files; 95 | } 96 | 97 | public function setGroup($key, $checkLastModified = true) 98 | { 99 | $this->_groupKey = $key; 100 | if ($checkLastModified) { 101 | if (! $this->groupsConfigFile) { 102 | $this->groupsConfigFile = dirname(dirname(dirname(dirname(__FILE__)))) . '/groupsConfig.php'; 103 | } 104 | if (is_file($this->groupsConfigFile)) { 105 | $gc = (require $this->groupsConfigFile); 106 | if (isset($gc[$key])) { 107 | $this->_lastModified = self::getLastModified($gc[$key]); 108 | } 109 | } 110 | } 111 | } 112 | 113 | public static function getLastModified($sources, $lastModified = 0) 114 | { 115 | $max = $lastModified; 116 | foreach ((array)$sources as $source) { 117 | if (is_object($source) && isset($source->lastModified)) { 118 | $max = max($max, $source->lastModified); 119 | } elseif (is_string($source)) { 120 | if (0 === strpos($source, '//')) { 121 | $source = $_SERVER['DOCUMENT_ROOT'] . substr($source, 1); 122 | } 123 | if (is_file($source)) { 124 | $max = max($max, filemtime($source)); 125 | } 126 | } 127 | } 128 | return $max; 129 | } 130 | 131 | protected $_groupKey = null; // if present, URI will be like g=... 132 | protected $_filePaths = array(); 133 | protected $_lastModified = null; 134 | 135 | 136 | /** 137 | * In a given array of strings, find the character they all have at 138 | * a particular index 139 | * 140 | * @param array $arr array of strings 141 | * @param int $pos index to check 142 | * @return mixed a common char or '' if any do not match 143 | */ 144 | protected static function _getCommonCharAtPos($arr, $pos) { 145 | $l = count($arr); 146 | $c = $arr[0][$pos]; 147 | if ($c === '' || $l === 1) 148 | return $c; 149 | for ($i = 1; $i < $l; ++$i) 150 | if ($arr[$i][$pos] !== $c) 151 | return ''; 152 | return $c; 153 | } 154 | 155 | /** 156 | * Get the shortest URI to minify the set of source files 157 | * 158 | * @param array $paths root-relative URIs of files 159 | * @param string $minRoot root-relative URI of the "min" application 160 | */ 161 | protected static function _getShortestUri($paths, $minRoot = '/min/') { 162 | $pos = 0; 163 | $base = ''; 164 | $c; 165 | while (true) { 166 | $c = self::_getCommonCharAtPos($paths, $pos); 167 | if ($c === '') { 168 | break; 169 | } else { 170 | $base .= $c; 171 | } 172 | ++$pos; 173 | } 174 | $base = preg_replace('@[^/]+$@', '', $base); 175 | $uri = $minRoot . 'f=' . implode(',', $paths); 176 | 177 | if (substr($base, -1) === '/') { 178 | // we have a base dir! 179 | $basedPaths = $paths; 180 | $l = count($paths); 181 | for ($i = 0; $i < $l; ++$i) { 182 | $basedPaths[$i] = substr($paths[$i], strlen($base)); 183 | } 184 | $base = substr($base, 0, strlen($base) - 1); 185 | $bUri = $minRoot . 'b=' . $base . '&f=' . implode(',', $basedPaths); 186 | 187 | $uri = strlen($uri) < strlen($bUri) 188 | ? $uri 189 | : $bUri; 190 | } 191 | return $uri; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /public/docs/js/Carousel.js: -------------------------------------------------------------------------------- 1 | /* 2 | --- 3 | script: Carousel.js 4 | license: MIT-style license. 5 | description: Tab - Minimalistic but extensible tab swapper. 6 | copyright: Copyright (c) 2010 Thierry Bela 7 | authors: [Thierry Bela] 8 | 9 | requires: 10 | core:1.2.3: 11 | - Class.Extras 12 | - Element.Event 13 | - Element.Style 14 | - Element.Dimensions 15 | - Array 16 | provides: [Carousel] 17 | ... 18 | */ 19 | 20 | (function () { 21 | 22 | function style(el, style) { 23 | 24 | var mrg = el.getStyle(style); 25 | 26 | return mrg == 'auto' ? 0 : mrg.toInt() 27 | } 28 | 29 | var Carousel = this.Carousel = new Class({ 30 | 31 | Implements: [Options, Events], 32 | options: { 33 | 34 | /* 35 | circular: false, 36 | onChange: function (index) { 37 | 38 | }, 39 | previous: element1, 40 | next: element2, 41 | container: null, 42 | selector: '', 43 | */ 44 | link: 'cancel', 45 | mode: 'horizontal', 46 | animation: 'Move', 47 | scroll: 4, 48 | distance: 1, 49 | fx: { 50 | 51 | link: 'cancel', 52 | transition: 'sine:out', 53 | duration: 500 54 | } 55 | }, 56 | plugins: {}, 57 | initialize: function (options) { 58 | 59 | this.addEvent('change', function (current) { 60 | 61 | this.current = current 62 | 63 | }.bind(this)).setOptions(options); 64 | 65 | ['previous', 'next'].each(function (val) { 66 | 67 | if($(this.options[val])) $(this.options[val]).addEvent('click', function (e) { 68 | 69 | e.stop(); 70 | this[val]() 71 | 72 | }.bind(this)) 73 | 74 | }, this); 75 | 76 | this.elements = $(options.container).getChildren(options.selector); 77 | 78 | this.current = 0; 79 | this.anim = new this.plugins[this.options.animation](this); 80 | 81 | this.move(this.options.current || 0); 82 | }, 83 | 84 | isVisible: function (index) { 85 | 86 | if($type($(index)) == 'element') index = this.elements.indexOf($(index)); 87 | 88 | var length = this.elements.length, 89 | current = this.current, 90 | scroll = this.options.scroll; 91 | 92 | if(current <= index && index < current + scroll) return true; 93 | 94 | if(this.options.circular) for(var i = 1; i < scroll; i++) { 95 | 96 | if((i + current) % length == index) return true; 97 | } 98 | 99 | return false 100 | }, 101 | 102 | first: function () { 103 | 104 | return this.current 105 | }, 106 | 107 | previous: function (direction) { 108 | 109 | return this.move(this.current - this.options.distance, direction) 110 | }, 111 | 112 | next: function (direction) { 113 | 114 | return this.move(this.current + this.options.distance, direction) 115 | }, 116 | 117 | move: function (index, direction) { 118 | 119 | var elements = this.elements, 120 | current = this.current, 121 | length = elements.length, 122 | scroll = this.options.scroll; 123 | 124 | if($type($(index)) == 'element') index = elements.indexOf($(index)); 125 | 126 | if(!this.options.circular) { 127 | 128 | if(index > length - scroll) index = length - scroll 129 | } 130 | 131 | else { 132 | 133 | if(index < 0) index += length; 134 | index %= Math.max(length, 1) 135 | } 136 | 137 | if(index < 0 || length <= scroll || index >= length) return this; 138 | 139 | if(direction == undefined) { 140 | 141 | //detect direction. inspired by moostack 142 | var forward = current < index ? index - current : elements.length - current + index, 143 | backward = current > index ? current - index : current + elements.length - index; 144 | 145 | direction = Math.abs(forward) <= Math.abs(backward) ? 1 : -1 146 | } 147 | 148 | this.anim.move(this, index, direction); 149 | 150 | return this 151 | } 152 | }); 153 | 154 | Carousel.prototype.plugins.Move = new Class({ 155 | 156 | initialize: function (carousel) { 157 | 158 | var up = this.up = carousel.options.mode == 'vertical', 159 | options = this.options = carousel.options, 160 | elements = this.elements = carousel.elements, 161 | parent = elements[0].getParent(); 162 | 163 | parent.setStyles({height: elements[0].setStyle('display', 'block').getStyle('height'), position: 'relative', overflow: 'hidden'}).getStyle('padding' + (this.up ? 'Top' : 'Left')); 164 | elements.each(function (el) { 165 | 166 | el.setStyles({display: 'block', position: 'absolute'}) 167 | 168 | }); 169 | 170 | this.property = 'offset' + (up ? 'Top' : 'Left'); 171 | this.margin = up ? ['marginTop', 'marginBottom'] : ['marginLeft', 'marginRight']; 172 | this.padding = style(parent, up ? 'paddingTop' : 'paddingLeft'); 173 | this.pad = style(parent, 'paddingLeft'); 174 | 175 | this.reorder(0, 1).fx = new Fx.Elements(elements, options.fx).addEvents({onStart: function () { carousel.active = true }, onComplete: function () { carousel.active = false }}) 176 | }, 177 | 178 | reorder: function (offset, direction) { 179 | 180 | var options = this.options, 181 | panels = this.elements, 182 | panel, 183 | prev, 184 | ini = pos = this.padding, 185 | pad = this.pad, 186 | i, 187 | index, 188 | length = panels.length, 189 | horizontal = options.mode == 'horizontal', 190 | side = horizontal ? 'offsetWidth' : 'offsetHeight'; 191 | 192 | //rtl 193 | if(direction == -1) { 194 | 195 | for(i = length; i > options.scroll - 1; i--) { 196 | 197 | index = (i + offset + length) % length; 198 | prev = panel; 199 | panel = panels[index]; 200 | 201 | if(prev) pos -= style(prev, this.margin[0]); 202 | 203 | if(horizontal) panel.setStyle('left', pos); 204 | else panel.setStyles({left: pad, top: pos}); 205 | pos -= (panel[side] + style(panel, this.margin[1])); 206 | } 207 | 208 | pos = ini + panel[side] + style(panel, this.margin[0]); 209 | 210 | for(i = 1; i < options.scroll; i++) { 211 | 212 | index = (i + offset + length) % length; 213 | 214 | prev = panel; 215 | panel = panels[index]; 216 | 217 | if(prev) pos += style(prev, this.margin[1]); 218 | if(horizontal) panel.setStyle('left', pos); 219 | else panel.setStyles({left: pad, top: pos}); 220 | pos += panel[side] + style(panel, this.margin[0]); 221 | } 222 | 223 | //ltr 224 | } else if(direction == 1) for(i = 0; i < length; i++) { 225 | 226 | index = (i + offset + length) % length; 227 | prev = panel; 228 | panel = panels[index]; 229 | 230 | if(horizontal) panel.setStyle('left', pos); 231 | else panel.setStyles({left: pad, top: pos}); 232 | pos += panel[side] + style(panel, this.margin[0]); 233 | if(prev) pos += style(prev, this.margin[1]); 234 | } 235 | 236 | return this 237 | }, 238 | 239 | move: function (carousel, current, direction) { 240 | 241 | var obj = {}, 242 | up = this.up, 243 | property = this.property, 244 | offset; 245 | 246 | if(this.options.circular) this.reorder(carousel.current, direction); 247 | 248 | offset = carousel.elements[current][property] - this.padding; 249 | 250 | carousel.elements.each(function (el, index) { 251 | 252 | obj[index] = up ? {top: el[property] - offset} : {left: el[property] - offset} 253 | }); 254 | 255 | this.fx.cancel().start(obj).chain(function () { carousel.fireEvent('change', current) }) 256 | } 257 | }) 258 | })(); 259 | 260 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/MinApp.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class Minify_Controller_MinApp extends Minify_Controller_Base { 16 | 17 | /** 18 | * Set up groups of files as sources 19 | * 20 | * @param array $options controller and Minify options 21 | * @return array Minify options 22 | * 23 | */ 24 | public function setupSources($options) { 25 | // filter controller options 26 | $cOptions = array_merge( 27 | array( 28 | 'allowDirs' => '//' 29 | ,'groupsOnly' => false 30 | ,'groups' => array() 31 | ,'noMinPattern' => '@[-\\.]min\\.(?:js|css)$@i' // matched against basename 32 | ) 33 | ,(isset($options['minApp']) ? $options['minApp'] : array()) 34 | ); 35 | unset($options['minApp']); 36 | $sources = array(); 37 | $this->selectionId = ''; 38 | $missingUri = ''; 39 | 40 | if (isset($_GET['g'])) { 41 | // add group(s) 42 | $this->selectionId .= 'g=' . $_GET['g']; 43 | $keys = explode(',', $_GET['g']); 44 | if ($keys != array_unique($keys)) { 45 | $this->log("Duplicate group key found."); 46 | return $options; 47 | } 48 | foreach (explode(',', $_GET['g']) as $key) { 49 | if (! isset($cOptions['groups'][$key])) { 50 | $this->log("A group configuration for \"{$key}\" was not found"); 51 | return $options; 52 | } 53 | $files = $cOptions['groups'][$key]; 54 | // if $files is a single object, casting will break it 55 | if (is_object($files)) { 56 | $files = array($files); 57 | } elseif (! is_array($files)) { 58 | $files = (array)$files; 59 | } 60 | foreach ($files as $file) { 61 | if ($file instanceof Minify_Source) { 62 | $sources[] = $file; 63 | continue; 64 | } 65 | if (0 === strpos($file, '//')) { 66 | $file = $_SERVER['DOCUMENT_ROOT'] . substr($file, 1); 67 | } 68 | $file = realpath($file); 69 | if ($file && is_file($file)) { 70 | $sources[] = $this->_getFileSource($file, $cOptions); 71 | } else { 72 | $this->log("The path \"{$file}\" could not be found (or was not a file)"); 73 | return $options; 74 | } 75 | } 76 | if ($sources) { 77 | try { 78 | $this->checkType($sources[0]); 79 | } catch (Exception $e) { 80 | $this->log($e->getMessage()); 81 | return $options; 82 | } 83 | } 84 | } 85 | } 86 | if (! $cOptions['groupsOnly'] && isset($_GET['f'])) { 87 | // try user files 88 | // The following restrictions are to limit the URLs that minify will 89 | // respond to. Ideally there should be only one way to reference a file. 90 | if (// verify at least one file, files are single comma separated, 91 | // and are all same extension 92 | ! preg_match('/^[^,]+\\.(css|js)(?:,[^,]+\\.\\1)*$/', $_GET['f'], $m) 93 | // no "//" 94 | || strpos($_GET['f'], '//') !== false 95 | // no "\" 96 | || strpos($_GET['f'], '\\') !== false 97 | // no "./" 98 | || preg_match('/(?:^|[^\\.])\\.\\//', $_GET['f']) 99 | ) { 100 | $this->log("GET param 'f' invalid (see MinApp.php line 63)"); 101 | return $options; 102 | } 103 | $ext = ".{$m[1]}"; 104 | try { 105 | $this->checkType($m[1]); 106 | } catch (Exception $e) { 107 | $this->log($e->getMessage()); 108 | return $options; 109 | } 110 | $files = explode(',', $_GET['f']); 111 | if ($files != array_unique($files)) { 112 | $this->log("Duplicate files specified"); 113 | return $options; 114 | } 115 | if (isset($_GET['b'])) { 116 | // check for validity 117 | if (preg_match('@^[^/]+(?:/[^/]+)*$@', $_GET['b']) 118 | && false === strpos($_GET['b'], '..') 119 | && $_GET['b'] !== '.') { 120 | // valid base 121 | $base = "/{$_GET['b']}/"; 122 | } else { 123 | $this->log("GET param 'b' invalid (see MinApp.php line 84)"); 124 | return $options; 125 | } 126 | } else { 127 | $base = '/'; 128 | } 129 | $allowDirs = array(); 130 | foreach ((array)$cOptions['allowDirs'] as $allowDir) { 131 | $allowDirs[] = realpath(str_replace('//', $_SERVER['DOCUMENT_ROOT'] . '/', $allowDir)); 132 | } 133 | $basenames = array(); // just for cache id 134 | foreach ($files as $file) { 135 | $uri = $base . $file; 136 | $path = $_SERVER['DOCUMENT_ROOT'] . $uri; 137 | $file = realpath($path); 138 | if (false === $file || ! is_file($file)) { 139 | if (! $missingUri) { 140 | $missingUri = $uri; 141 | continue; 142 | } else { 143 | $this->log("At least two files missing: '$missingUri', '$uri'"); 144 | return $options; 145 | } 146 | } 147 | try { 148 | parent::checkNotHidden($file); 149 | parent::checkAllowDirs($file, $allowDirs, $uri); 150 | } catch (Exception $e) { 151 | $this->log($e->getMessage()); 152 | return $options; 153 | } 154 | $sources[] = $this->_getFileSource($file, $cOptions); 155 | $basenames[] = basename($file, $ext); 156 | } 157 | if ($this->selectionId) { 158 | $this->selectionId .= '_f='; 159 | } 160 | $this->selectionId .= implode(',', $basenames) . $ext; 161 | } 162 | if ($sources) { 163 | if ($missingUri) { 164 | array_unshift($sources, new Minify_Source(array( 165 | 'id' => 'missingFile' 166 | ,'lastModified' => 0 167 | ,'content' => "/* Minify: missing file '" . ltrim($missingUri, '/') . "' */\n" 168 | ,'minifier' => '' 169 | ))); 170 | } 171 | $this->sources = $sources; 172 | } else { 173 | $this->log("No sources to serve"); 174 | } 175 | return $options; 176 | } 177 | 178 | protected function _getFileSource($file, $cOptions) 179 | { 180 | $spec['filepath'] = $file; 181 | if ($cOptions['noMinPattern'] 182 | && preg_match($cOptions['noMinPattern'], basename($file))) { 183 | $spec['minifier'] = ''; 184 | } 185 | return new Minify_Source($spec); 186 | } 187 | 188 | protected $_type = null; 189 | 190 | /* 191 | * Make sure that only source files of a single type are registered 192 | */ 193 | public function checkType($sourceOrExt) 194 | { 195 | if ($sourceOrExt === 'js') { 196 | $type = Minify::TYPE_JS; 197 | } elseif ($sourceOrExt === 'css') { 198 | $type = Minify::TYPE_CSS; 199 | } elseif ($sourceOrExt->contentType !== null) { 200 | $type = $sourceOrExt->contentType; 201 | } else { 202 | return; 203 | } 204 | if ($this->_type === null) { 205 | $this->_type = $type; 206 | } elseif ($this->_type !== $type) { 207 | throw new Exception('Content-Type mismatch'); 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /public/min/lib/Minify/HTML.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class Minify_HTML { 20 | 21 | /** 22 | * "Minify" an HTML page 23 | * 24 | * @param string $html 25 | * 26 | * @param array $options 27 | * 28 | * 'cssMinifier' : (optional) callback function to process content of STYLE 29 | * elements. 30 | * 31 | * 'jsMinifier' : (optional) callback function to process content of SCRIPT 32 | * elements. Note: the type attribute is ignored. 33 | * 34 | * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If 35 | * unset, minify will sniff for an XHTML doctype. 36 | * 37 | * @return string 38 | */ 39 | public static function minify($html, $options = array()) { 40 | $min = new Minify_HTML($html, $options); 41 | return $min->process(); 42 | } 43 | 44 | 45 | /** 46 | * Create a minifier object 47 | * 48 | * @param string $html 49 | * 50 | * @param array $options 51 | * 52 | * 'cssMinifier' : (optional) callback function to process content of STYLE 53 | * elements. 54 | * 55 | * 'jsMinifier' : (optional) callback function to process content of SCRIPT 56 | * elements. Note: the type attribute is ignored. 57 | * 58 | * 'xhtml' : (optional boolean) should content be treated as XHTML1.0? If 59 | * unset, minify will sniff for an XHTML doctype. 60 | * 61 | * @return null 62 | */ 63 | public function __construct($html, $options = array()) 64 | { 65 | $this->_html = str_replace("\r\n", "\n", trim($html)); 66 | if (isset($options['xhtml'])) { 67 | $this->_isXhtml = (bool)$options['xhtml']; 68 | } 69 | if (isset($options['cssMinifier'])) { 70 | $this->_cssMinifier = $options['cssMinifier']; 71 | } 72 | if (isset($options['jsMinifier'])) { 73 | $this->_jsMinifier = $options['jsMinifier']; 74 | } 75 | } 76 | 77 | 78 | /** 79 | * Minify the markeup given in the constructor 80 | * 81 | * @return string 82 | */ 83 | public function process() 84 | { 85 | if ($this->_isXhtml === null) { 86 | $this->_isXhtml = (false !== strpos($this->_html, '_replacementHash = 'MINIFYHTML' . md5($_SERVER['REQUEST_TIME']); 90 | $this->_placeholders = array(); 91 | 92 | // replace SCRIPTs (and minify) with placeholders 93 | $this->_html = preg_replace_callback( 94 | '/(\\s*)(]*?>)([\\s\\S]*?)<\\/script>(\\s*)/i' 95 | ,array($this, '_removeScriptCB') 96 | ,$this->_html); 97 | 98 | // replace STYLEs (and minify) with placeholders 99 | $this->_html = preg_replace_callback( 100 | '/\\s*(]*?>)([\\s\\S]*?)<\\/style>\\s*/i' 101 | ,array($this, '_removeStyleCB') 102 | ,$this->_html); 103 | 104 | // remove HTML comments (not containing IE conditional comments). 105 | $this->_html = preg_replace_callback( 106 | '//' 107 | ,array($this, '_commentCB') 108 | ,$this->_html); 109 | 110 | // replace PREs with placeholders 111 | $this->_html = preg_replace_callback('/\\s*(]*?>[\\s\\S]*?<\\/pre>)\\s*/i' 112 | ,array($this, '_removePreCB') 113 | ,$this->_html); 114 | 115 | // replace TEXTAREAs with placeholders 116 | $this->_html = preg_replace_callback( 117 | '/\\s*(]*?>[\\s\\S]*?<\\/textarea>)\\s*/i' 118 | ,array($this, '_removeTextareaCB') 119 | ,$this->_html); 120 | 121 | // trim each line. 122 | // @todo take into account attribute values that span multiple lines. 123 | $this->_html = preg_replace('/^\\s+|\\s+$/m', '', $this->_html); 124 | 125 | // remove ws around block/undisplayed elements 126 | $this->_html = preg_replace('/\\s+(<\\/?(?:area|base(?:font)?|blockquote|body' 127 | .'|caption|center|cite|col(?:group)?|dd|dir|div|dl|dt|fieldset|form' 128 | .'|frame(?:set)?|h[1-6]|head|hr|html|legend|li|link|map|menu|meta' 129 | .'|ol|opt(?:group|ion)|p|param|t(?:able|body|head|d|h||r|foot|itle)' 130 | .'|ul)\\b[^>]*>)/i', '$1', $this->_html); 131 | 132 | // remove ws outside of all elements 133 | $this->_html = preg_replace_callback( 134 | '/>([^<]+)_html); 137 | 138 | // use newlines before 1st attribute in open tags (to limit line lengths) 139 | $this->_html = preg_replace('/(<[a-z\\-]+)\\s+([^>]+>)/i', "$1\n$2", $this->_html); 140 | 141 | // fill placeholders 142 | $this->_html = str_replace( 143 | array_keys($this->_placeholders) 144 | ,array_values($this->_placeholders) 145 | ,$this->_html 146 | ); 147 | return $this->_html; 148 | } 149 | 150 | protected function _commentCB($m) 151 | { 152 | return (0 === strpos($m[1], '[') || false !== strpos($m[1], '_replacementHash . count($this->_placeholders) . '%'; 160 | $this->_placeholders[$placeholder] = $content; 161 | return $placeholder; 162 | } 163 | 164 | protected $_isXhtml = null; 165 | protected $_replacementHash = null; 166 | protected $_placeholders = array(); 167 | protected $_cssMinifier = null; 168 | protected $_jsMinifier = null; 169 | 170 | protected function _outsideTagCB($m) 171 | { 172 | return '>' . preg_replace('/^\\s+|\\s+$/', ' ', $m[1]) . '<'; 173 | } 174 | 175 | protected function _removePreCB($m) 176 | { 177 | return $this->_reservePlace($m[1]); 178 | } 179 | 180 | protected function _removeTextareaCB($m) 181 | { 182 | return $this->_reservePlace($m[1]); 183 | } 184 | 185 | protected function _removeStyleCB($m) 186 | { 187 | $openStyle = $m[1]; 188 | $css = $m[2]; 189 | // remove HTML comments 190 | $css = preg_replace('/(?:^\\s*\\s*$)/', '', $css); 191 | 192 | // remove CDATA section markers 193 | $css = $this->_removeCdata($css); 194 | 195 | // minify 196 | $minifier = $this->_cssMinifier 197 | ? $this->_cssMinifier 198 | : 'trim'; 199 | $css = call_user_func($minifier, $css); 200 | 201 | return $this->_reservePlace($this->_needsCdata($css) 202 | ? "{$openStyle}/**/" 203 | : "{$openStyle}{$css}" 204 | ); 205 | } 206 | 207 | protected function _removeScriptCB($m) 208 | { 209 | $openScript = $m[2]; 210 | $js = $m[3]; 211 | 212 | // whitespace surrounding? preserve at least one space 213 | $ws1 = ($m[1] === '') ? '' : ' '; 214 | $ws2 = ($m[4] === '') ? '' : ' '; 215 | 216 | // remove HTML comments (and ending "//" if present) 217 | $js = preg_replace('/(?:^\\s*\\s*$)/', '', $js); 218 | 219 | // remove CDATA section markers 220 | $js = $this->_removeCdata($js); 221 | 222 | // minify 223 | $minifier = $this->_jsMinifier 224 | ? $this->_jsMinifier 225 | : 'trim'; 226 | $js = call_user_func($minifier, $js); 227 | 228 | return $this->_reservePlace($this->_needsCdata($js) 229 | ? "{$ws1}{$openScript}/**/{$ws2}" 230 | : "{$ws1}{$openScript}{$js}{$ws2}" 231 | ); 232 | } 233 | 234 | protected function _removeCdata($str) 235 | { 236 | return (false !== strpos($str, ''), '', $str) 238 | : $str; 239 | } 240 | 241 | protected function _needsCdata($str) 242 | { 243 | return ($this->_isXhtml && preg_match('/(?:[<&]|\\-\\-|\\]\\]>)/', $str)); 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /public/min/lib/Minify/Controller/Base.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | abstract class Minify_Controller_Base { 18 | 19 | /** 20 | * Setup controller sources and set an needed options for Minify::source 21 | * 22 | * You must override this method in your subclass controller to set 23 | * $this->sources. If the request is NOT valid, make sure $this->sources 24 | * is left an empty array. Then strip any controller-specific options from 25 | * $options and return it. To serve files, $this->sources must be an array of 26 | * Minify_Source objects. 27 | * 28 | * @param array $options controller and Minify options 29 | * 30 | * return array $options Minify::serve options 31 | */ 32 | abstract public function setupSources($options); 33 | 34 | /** 35 | * Get default Minify options for this controller. 36 | * 37 | * Override in subclass to change defaults 38 | * 39 | * @return array options for Minify 40 | */ 41 | public function getDefaultMinifyOptions() { 42 | return array( 43 | 'isPublic' => true 44 | ,'encodeOutput' => function_exists('gzdeflate') 45 | ,'encodeMethod' => null // determine later 46 | ,'encodeLevel' => 9 47 | ,'minifierOptions' => array() // no minifier options 48 | ,'contentTypeCharset' => 'utf-8' 49 | ,'maxAge' => 1800 // 30 minutes 50 | ,'rewriteCssUris' => true 51 | ,'bubbleCssImports' => false 52 | ,'quiet' => false // serve() will send headers and output 53 | ,'debug' => false 54 | 55 | // if you override these, the response codes MUST be directly after 56 | // the first space. 57 | ,'badRequestHeader' => 'HTTP/1.0 400 Bad Request' 58 | ,'errorHeader' => 'HTTP/1.0 500 Internal Server Error' 59 | 60 | // callback function to see/modify content of all sources 61 | ,'postprocessor' => null 62 | // file to require to load preprocessor 63 | ,'postprocessorRequire' => null 64 | ); 65 | } 66 | 67 | /** 68 | * Get default minifiers for this controller. 69 | * 70 | * Override in subclass to change defaults 71 | * 72 | * @return array minifier callbacks for common types 73 | */ 74 | public function getDefaultMinifers() { 75 | $ret[Minify::TYPE_JS] = array('JSMin', 'minify'); 76 | $ret[Minify::TYPE_CSS] = array('Minify_CSS', 'minify'); 77 | $ret[Minify::TYPE_HTML] = array('Minify_HTML', 'minify'); 78 | return $ret; 79 | } 80 | 81 | /** 82 | * Load any code necessary to execute the given minifier callback. 83 | * 84 | * The controller is responsible for loading minification code on demand 85 | * via this method. This built-in function will only load classes for 86 | * static method callbacks where the class isn't already defined. It uses 87 | * the PEAR convention, so, given array('Jimmy_Minifier', 'minCss'), this 88 | * function will include 'Jimmy/Minifier.php'. 89 | * 90 | * If you need code loaded on demand and this doesn't suit you, you'll need 91 | * to override this function in your subclass. 92 | * @see Minify_Controller_Page::loadMinifier() 93 | * 94 | * @param callback $minifierCallback callback of minifier function 95 | * 96 | * @return null 97 | */ 98 | public function loadMinifier($minifierCallback) 99 | { 100 | if (is_array($minifierCallback) 101 | && is_string($minifierCallback[0]) 102 | && !class_exists($minifierCallback[0], false)) { 103 | 104 | require str_replace('_', '/', $minifierCallback[0]) . '.php'; 105 | } 106 | } 107 | 108 | /** 109 | * Is a user-given file within an allowable directory, existing, 110 | * and having an extension js/css/html/txt ? 111 | * 112 | * This is a convenience function for controllers that have to accept 113 | * user-given paths 114 | * 115 | * @param string $file full file path (already processed by realpath()) 116 | * 117 | * @param array $safeDirs directories where files are safe to serve. Files can also 118 | * be in subdirectories of these directories. 119 | * 120 | * @return bool file is safe 121 | * 122 | * @deprecated use checkAllowDirs, checkNotHidden instead 123 | */ 124 | public static function _fileIsSafe($file, $safeDirs) 125 | { 126 | $pathOk = false; 127 | foreach ((array)$safeDirs as $safeDir) { 128 | if (strpos($file, $safeDir) === 0) { 129 | $pathOk = true; 130 | break; 131 | } 132 | } 133 | $base = basename($file); 134 | if (! $pathOk || ! is_file($file) || $base[0] === '.') { 135 | return false; 136 | } 137 | list($revExt) = explode('.', strrev($base)); 138 | return in_array(strrev($revExt), array('js', 'css', 'html', 'txt')); 139 | } 140 | 141 | 142 | public static function checkAllowDirs($file, $allowDirs, $uri) 143 | { 144 | foreach ((array)$allowDirs as $allowDir) { 145 | if (strpos($file, $allowDir) === 0) { 146 | return true; 147 | } 148 | } 149 | throw new Exception("File '$file' is outside \$allowDirs. If the path is" 150 | . " resolved via an alias/symlink, look into the \$min_symlinks option." 151 | . " E.g. \$min_symlinks['/" . dirname($uri) . "'] = '" . dirname($file) . "';"); 152 | } 153 | 154 | public static function checkNotHidden($file) 155 | { 156 | $b = basename($file); 157 | if (0 === strpos($b, '.')) { 158 | throw new Exception("Filename '$b' starts with period (may be hidden)"); 159 | } 160 | } 161 | 162 | /** 163 | * @var array instances of Minify_Source, which provide content and 164 | * any individual minification needs. 165 | * 166 | * @see Minify_Source 167 | */ 168 | public $sources = array(); 169 | 170 | /** 171 | * The setupSources() method may choose to set this, making it easier to 172 | * recognize a particular set of sources/settings in the cache folder. It 173 | * will be filtered and truncated to make the final cache id <= 250 bytes. 174 | * 175 | * @var string short name to place inside cache id 176 | */ 177 | public $selectionId = ''; 178 | 179 | /** 180 | * Mix in default controller options with user-given options 181 | * 182 | * @param array $options user options 183 | * 184 | * @return array mixed options 185 | */ 186 | public final function mixInDefaultOptions($options) 187 | { 188 | $ret = array_merge( 189 | $this->getDefaultMinifyOptions(), $options 190 | ); 191 | if (! isset($options['minifiers'])) { 192 | $options['minifiers'] = array(); 193 | } 194 | $ret['minifiers'] = array_merge( 195 | $this->getDefaultMinifers(), $options['minifiers'] 196 | ); 197 | return $ret; 198 | } 199 | 200 | /** 201 | * Analyze sources (if there are any) and set $options 'contentType' 202 | * and 'lastModifiedTime' if they already aren't. 203 | * 204 | * @param array $options options for Minify 205 | * 206 | * @return array options for Minify 207 | */ 208 | public final function analyzeSources($options = array()) 209 | { 210 | if ($this->sources) { 211 | if (! isset($options['contentType'])) { 212 | $options['contentType'] = Minify_Source::getContentType($this->sources); 213 | } 214 | // last modified is needed for caching, even if setExpires is set 215 | if (! isset($options['lastModifiedTime'])) { 216 | $max = 0; 217 | foreach ($this->sources as $source) { 218 | $max = max($source->lastModified, $max); 219 | } 220 | $options['lastModifiedTime'] = $max; 221 | } 222 | } 223 | return $options; 224 | } 225 | 226 | /** 227 | * Send message to the Minify logger 228 | * @param string $msg 229 | * @return null 230 | */ 231 | public function log($msg) { 232 | require_once 'Minify/Logger.php'; 233 | Minify_Logger::log($msg); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /app/helpers.inc.php: -------------------------------------------------------------------------------- 1 | strlen($b) ? -1 : 1); 23 | } 24 | 25 | static function file_path_to_url($file_path) { 26 | $url = preg_replace(array('/\d+?\./', '/\.\/content(\/)?/'), '', $file_path); 27 | return $url ? $url : 'index'; 28 | } 29 | 30 | static function url_to_file_path($url) { 31 | # if the url is empty, we're looking for the index page 32 | $url = empty($url) ? 'index': $url; 33 | 34 | $file_path = './content'; 35 | # Split the url and recursively unclean the parts into folder names 36 | $url_parts = explode('/', $url); 37 | foreach($url_parts as $u) { 38 | # Look for a folder at the current path that doesn't start with an underscore 39 | if(!preg_match('/^_/', $u)) $matches = array_keys(Helpers::list_files($file_path, '/^(\d+?\.)?'.$u.'$/', true)); 40 | # No matches means a bad url 41 | if(empty($matches)) return false; 42 | else $file_path .= '/'.$matches[0]; 43 | } 44 | return $file_path; 45 | } 46 | 47 | static function has_children($dir) { 48 | # check if this folder contains inner folders - if it does, then it is a category 49 | $inner_folders = Helpers::list_files($dir, '/.*/', true); 50 | return !empty($inner_folders); 51 | } 52 | 53 | static function file_cache($dir = false) { 54 | if(!self::$file_cache) { 55 | # build file cache 56 | self::build_file_cache('./content'); 57 | self::build_file_cache('./templates'); 58 | } 59 | if($dir && !self::$file_cache[$dir]) return array(); 60 | return $dir ? self::$file_cache[$dir] : self::$file_cache; 61 | } 62 | 63 | static function build_file_cache($dir = '.') { 64 | # build file cache 65 | $files = glob($dir.'/*'); 66 | $files = is_array($files) ? $files : array(); 67 | foreach($files as $path) { 68 | $file = basename($path); 69 | if(substr($file, 0, 1) == "." || $file == "_cache") continue; 70 | if(is_dir($path)) self::build_file_cache($path); 71 | if(is_readable($path)) { 72 | self::$file_cache[$dir][] = array( 73 | 'path' => $path, 74 | 'file_name' => $file, 75 | 'is_folder' => (is_dir($path) ? 1 : 0), 76 | 'mtime' => filemtime($path) 77 | ); 78 | } 79 | } 80 | } 81 | 82 | static function list_files($dir, $regex, $folders_only = false) { 83 | $files = array(); 84 | foreach(self::file_cache($dir) as $file) { 85 | # if file matches regex, continue 86 | if(preg_match($regex, $file['file_name'])) { 87 | # if $folders_only is true and the file is not a folder, skip it 88 | if($folders_only && !$file['is_folder']) continue; 89 | # otherwise, add file to results list 90 | $files[$file['file_name']] = $file['path']; 91 | } 92 | } 93 | 94 | # sort list in reverse-numeric order 95 | krsort($files, SORT_NUMERIC); 96 | return $files; 97 | } 98 | 99 | static function modrewrite_parse($url) { 100 | # if the .htaccess file is missing or mod_rewrite is disabled, overwrite the clean urls 101 | if(!file_exists('.htaccess') && preg_match('/\/$/', $url)) { 102 | $url = '?/'.$url; 103 | } 104 | return $url; 105 | } 106 | 107 | static function relative_root_path($url = '') { 108 | global $current_page_file_path; 109 | $link_path = ''; 110 | if(!preg_match('/index/', $current_page_file_path) && !preg_match('/\/\?\//', $_SERVER['REQUEST_URI'])) { 111 | # split file path by slashes 112 | $split_path = explode('/', $current_page_file_path); 113 | # if the request uri is pointing at a document, drop another folder from the file path 114 | if(preg_match('/\./', $_SERVER['REQUEST_URI'])) array_pop($split_path); 115 | # add a ../ for each parent folder 116 | for($i = 2; $i < count($split_path); $i++) $link_path .= '../'; 117 | } 118 | 119 | $link_path = empty($link_path) ? './' : $link_path; 120 | 121 | return $link_path .= self::modrewrite_parse($url); 122 | } 123 | 124 | static function last_modified($dir) { 125 | $last_modified = 0; 126 | if(is_dir($dir)) { 127 | foreach(Helpers::list_files($dir, '/.*/', false) as $file) { 128 | if(!is_dir($file)) $last_modified = (filemtime($file) > $last_modified) ? filemtime($file) : $last_modified; 129 | } 130 | } 131 | return $last_modified; 132 | } 133 | 134 | static function site_last_modified($dir = './content') { 135 | $last_updated = 0; 136 | foreach(Helpers::list_files($dir, '/.*/', false) as $file) { 137 | if(filemtime($file) > $last_updated) $last_updated = filemtime($file); 138 | if(is_dir($file)) { 139 | $child_updated = self::site_last_modified($file); 140 | if($child_updated > $last_updated) $last_updated = $child_updated; 141 | } 142 | } 143 | return $last_updated; 144 | } 145 | 146 | static function translate_named_entities($string) { 147 | $mapping = array('&'=>'&','''=>''', '−'=>'-', 'ˆ'=>'^', '˜'=>'~', 'Š'=>'Š', '‹'=>'‹', 'Œ'=>'Œ', '‘'=>'‘', '’'=>'’', '“'=>'“', '”'=>'”', '•'=>'•', '–'=>'–', '—'=>'—', '˜'=>'˜', '™'=>'™', 'š'=>'š', '›'=>'›', 'œ'=>'œ', 'Ÿ'=>'Ÿ', 'ÿ'=>'ÿ', 'Œ'=>'Œ', 'œ'=>'œ', 'Š'=>'Š', 'š'=>'š', 'Ÿ'=>'Ÿ', 'ƒ'=>'ƒ', 'ˆ'=>'ˆ', '˜'=>'˜', 'Α'=>'Α', 'Β'=>'Β', 'Γ'=>'Γ', 'Δ'=>'Δ', 'Ε'=>'Ε', 'Ζ'=>'Ζ', 'Η'=>'Η', 'Θ'=>'Θ', 'Ι'=>'Ι', 'Κ'=>'Κ', 'Λ'=>'Λ', 'Μ'=>'Μ', 'Ν'=>'Ν', 'Ξ'=>'Ξ', 'Ο'=>'Ο', 'Π'=>'Π', 'Ρ'=>'Ρ', 'Σ'=>'Σ', 'Τ'=>'Τ', 'Υ'=>'Υ', 'Φ'=>'Φ', 'Χ'=>'Χ', 'Ψ'=>'Ψ', 'Ω'=>'Ω', 'α'=>'α', 'β'=>'β', 'γ'=>'γ', 'δ'=>'δ', 'ε'=>'ε', 'ζ'=>'ζ', 'η'=>'η', 'θ'=>'θ', 'ι'=>'ι', 'κ'=>'κ', 'λ'=>'λ', 'μ'=>'μ', 'ν'=>'ν', 'ξ'=>'ξ', 'ο'=>'ο', 'π'=>'π', 'ρ'=>'ρ', 'ς'=>'ς', 'σ'=>'σ', 'τ'=>'τ', 'υ'=>'υ', 'φ'=>'φ', 'χ'=>'χ', 'ψ'=>'ψ', 'ω'=>'ω', 'ϑ'=>'ϑ', 'ϒ'=>'ϒ', 'ϖ'=>'ϖ', ' '=>' ', ' '=>' ', ' '=>' ', '‌'=>'‌', '‍'=>'‍', '‎'=>'‎', '‏'=>'‏', '–'=>'–', '—'=>'—', '‘'=>'‘', '’'=>'’', '‚'=>'‚', '“'=>'“', '”'=>'”', '„'=>'„', '†'=>'†', '‡'=>'‡', '•'=>'•', '…'=>'…', '‰'=>'‰', '′'=>'′', '″'=>'″', '‹'=>'‹', '›'=>'›', '‾'=>'‾', '⁄'=>'⁄', '€'=>'€', 'ℑ'=>'ℑ', '℘'=>'℘', 'ℜ'=>'ℜ', '™'=>'™', 'ℵ'=>'ℵ', '←'=>'←', '↑'=>'↑', '→'=>'→', '↓'=>'↓', '↔'=>'↔', '↵'=>'↵', '⇐'=>'⇐', '⇑'=>'⇑', '⇒'=>'⇒', '⇓'=>'⇓', '⇔'=>'⇔', '∀'=>'∀', '∂'=>'∂', '∃'=>'∃', '∅'=>'∅', '∇'=>'∇', '∈'=>'∈', '∉'=>'∉', '∋'=>'∋', '∏'=>'∏', '∑'=>'∑', '−'=>'−', '∗'=>'∗', '√'=>'√', '∝'=>'∝', '∞'=>'∞', '∠'=>'∠', '∧'=>'∧', '∨'=>'∨', '∩'=>'∩', '∪'=>'∪', '∫'=>'∫', '∴'=>'∴', '∼'=>'∼', '≅'=>'≅', '≈'=>'≈', '≠'=>'≠', '≡'=>'≡', '≤'=>'≤', '≥'=>'≥', '⊂'=>'⊂', '⊃'=>'⊃', '⊄'=>'⊄', '⊆'=>'⊆', '⊇'=>'⊇', '⊕'=>'⊕', '⊗'=>'⊗', '⊥'=>'⊥', '⋅'=>'⋅', '⌈'=>'⌈', '⌉'=>'⌉', '⌊'=>'⌊', '⌋'=>'⌋', '⟨'=>'〈', '⟩'=>'〉', '◊'=>'◊', '♠'=>'♠', '♣'=>'♣', '♥'=>'♥', '♦'=>'♦'); 148 | foreach (get_html_translation_table(HTML_ENTITIES, ENT_QUOTES) as $char => $entity){ 149 | $mapping[$entity] = '&#' . ord($char) . ';'; 150 | } 151 | return str_replace(array_keys($mapping), $mapping, $string); 152 | } 153 | 154 | } 155 | 156 | ?> --------------------------------------------------------------------------------