├── .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 |
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 |Unfortunately, the page you were looking for does not exist here.
21 | 22 |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 (
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 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 Clay28 | */ 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, '_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 | ?> --------------------------------------------------------------------------------