Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

first commit

  • Loading branch information...
commit c9c021f94986620f66ba42c58dece66d31dacbe3 0 parents
Phil Leggetter leggetter authored
Showing with 14,418 additions and 0 deletions.
  1. +3 −0  README.md
  2. +21 −0 src/example.html
  3. +13 −0 src/frames.html
  4. BIN  src/images/announce.png
  5. BIN  src/images/create.png
  6. BIN  src/images/delete.png
  7. BIN  src/images/read.png
  8. BIN  src/images/update.png
  9. BIN  src/js/.DS_Store
  10. +44 −0 src/js/gritter/README.markdown
  11. +89 −0 src/js/gritter/css/jquery.gritter.css
  12. BIN  src/js/gritter/images/gritter-long.png
  13. BIN  src/js/gritter/images/gritter.png
  14. BIN  src/js/gritter/images/ie-spacer.gif
  15. BIN  src/js/gritter/images/trees.jpg
  16. +224 −0 src/js/gritter/index.html
  17. +405 −0 src/js/gritter/js/jquery.gritter.js
  18. +11 −0 src/js/gritter/js/jquery.gritter.min.js
  19. +59 −0 src/js/pusher-notification-helper.js
  20. BIN  src/lib/.DS_Store
  21. BIN  src/lib/less/.DS_Store
  22. +16 −0 src/lib/less/less-1.1.5.min.js
  23. +55 −0 src/lib/pusher-php/pusher_notification_helper.php
  24. +102 −0 src/lib/pusher-php/squeeks-Pusher-PHP/README.md
  25. +223 −0 src/lib/pusher-php/squeeks-Pusher-PHP/lib/Pusher.php
  26. +44 −0 src/lib/pusher-php/squeeks-Pusher-PHP/test/push.php
  27. +28 −0 src/lib/pusher-php/squeeks-Pusher-PHP/test/socket_auth.php
  28. +4 −0 src/lib/twitter-bootstrap/.gitignore
  29. +176 −0 src/lib/twitter-bootstrap/LICENSE
  30. +47 −0 src/lib/twitter-bootstrap/Makefile
  31. +105 −0 src/lib/twitter-bootstrap/README.md
  32. +2,467 −0 src/lib/twitter-bootstrap/bootstrap.css
  33. +356 −0 src/lib/twitter-bootstrap/bootstrap.min.css
  34. +317 −0 src/lib/twitter-bootstrap/docs/assets/css/docs.css
  35. BIN  src/lib/twitter-bootstrap/docs/assets/ico/bootstrap-apple-114x114.png
  36. BIN  src/lib/twitter-bootstrap/docs/assets/ico/bootstrap-apple-57x57.png
  37. BIN  src/lib/twitter-bootstrap/docs/assets/ico/bootstrap-apple-72x72.png
  38. BIN  src/lib/twitter-bootstrap/docs/assets/ico/favicon.ico
  39. BIN  src/lib/twitter-bootstrap/docs/assets/img/bird.png
  40. BIN  src/lib/twitter-bootstrap/docs/assets/img/browsers.png
  41. BIN  src/lib/twitter-bootstrap/docs/assets/img/example-diagram-01.png
  42. BIN  src/lib/twitter-bootstrap/docs/assets/img/example-diagram-02.png
  43. BIN  src/lib/twitter-bootstrap/docs/assets/img/example-diagram-03.png
  44. BIN  src/lib/twitter-bootstrap/docs/assets/img/grid-18px.png
  45. BIN  src/lib/twitter-bootstrap/docs/assets/img/twitter-logo-no-bird.png
  46. +52 −0 src/lib/twitter-bootstrap/docs/assets/js/application.js
  47. +94 −0 src/lib/twitter-bootstrap/docs/assets/js/google-code-prettify/prettify.css
  48. +28 −0 src/lib/twitter-bootstrap/docs/assets/js/google-code-prettify/prettify.js
  49. +2,037 −0 src/lib/twitter-bootstrap/docs/index.html
  50. +798 −0 src/lib/twitter-bootstrap/docs/javascript.html
  51. +119 −0 src/lib/twitter-bootstrap/examples/container-app.html
  52. +122 −0 src/lib/twitter-bootstrap/examples/fluid.html
  53. +79 −0 src/lib/twitter-bootstrap/examples/hero.html
  54. +124 −0 src/lib/twitter-bootstrap/js/bootstrap-alerts.js
  55. +64 −0 src/lib/twitter-bootstrap/js/bootstrap-buttons.js
  56. +55 −0 src/lib/twitter-bootstrap/js/bootstrap-dropdown.js
  57. +260 −0 src/lib/twitter-bootstrap/js/bootstrap-modal.js
  58. +90 −0 src/lib/twitter-bootstrap/js/bootstrap-popover.js
  59. +107 −0 src/lib/twitter-bootstrap/js/bootstrap-scrollspy.js
  60. +80 −0 src/lib/twitter-bootstrap/js/bootstrap-tabs.js
  61. +321 −0 src/lib/twitter-bootstrap/js/bootstrap-twipsy.js
  62. +40 −0 src/lib/twitter-bootstrap/js/tests/index.html
  63. +41 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-alerts.js
  64. +42 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-buttons.js
  65. +52 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-dropdown.js
  66. +151 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-modal.js
  67. +76 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-popover.js
  68. +31 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-scrollspy.js
  69. +77 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-tabs.js
  70. +81 −0 src/lib/twitter-bootstrap/js/tests/unit/bootstrap-twipsy.js
  71. +232 −0 src/lib/twitter-bootstrap/js/tests/vendor/qunit.css
  72. +1,510 −0 src/lib/twitter-bootstrap/js/tests/vendor/qunit.js
  73. +26 −0 src/lib/twitter-bootstrap/lib/bootstrap.less
  74. +479 −0 src/lib/twitter-bootstrap/lib/forms.less
  75. +222 −0 src/lib/twitter-bootstrap/lib/mixins.less
  76. +1,060 −0 src/lib/twitter-bootstrap/lib/patterns.less
  77. +141 −0 src/lib/twitter-bootstrap/lib/reset.less
  78. +139 −0 src/lib/twitter-bootstrap/lib/scaffolding.less
  79. +224 −0 src/lib/twitter-bootstrap/lib/tables.less
  80. +187 −0 src/lib/twitter-bootstrap/lib/type.less
  81. +60 −0 src/lib/twitter-bootstrap/lib/variables.less
  82. +142 −0 src/no_frames.html
  83. +21 −0 src/php/announce.php
  84. +7 −0 src/php/config.php
  85. +13 −0 src/php/create.php
  86. +13 −0 src/php/delete.php
  87. +9 −0 src/php/nav.inc.php
  88. +1 −0  src/php/nothing.php
  89. +14 −0 src/php/read.php
  90. +14 −0 src/php/update.php
  91. +74 −0 src/styles.css
3  README.md
@@ -0,0 +1,3 @@
+# HTML5 Push Notifications using Pusher
+
+The first version of this sample shows how to perform Realtime Push Notifications from PHP. Later version will demonstrate how to achieve this using other backend technologies.
21 src/example.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <title>Notification Example</title>
+
+ <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
+
+ <link rel="stylesheet" type="text/css" href="js/gritter/css/jquery.gritter.css" />
+ <script src="js/gritter/js/jquery.gritter.min.js"></script>
+
+ <script src="http://js.pusherapp.com/1.9/pusher.min.js"></script>
+ <script src="js/pusher-notification-helper.js"></script>
+ <script>
+ var pusher = new Pusher('49e26cb8e9dde3dfc009');
+ var helper = new PusherNotificationHelper(pusher);
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
13 src/frames.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <title>PHP HTML5 Push Notifications using Pusher - Frameset</title>
+ </head>
+
+ <frameset cols="50%,50%">
+ <frame src="no_frames.html" />
+ <frame src="no_frames.html" />
+ </frameset>
+
+</html>
BIN  src/images/announce.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/images/create.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/images/delete.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/images/read.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/images/update.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/js/.DS_Store
Binary file not shown
44 src/js/gritter/README.markdown
@@ -0,0 +1,44 @@
+# Gritter for jQuery
+
+A small growl-like notification plugin for jQuery
+- http://boedesign.com/blog/2009/07/11/growl-for-jquery-gritter/
+
+## Change Log
+
+### Changes in 1.7.1 (March 29, 2011)
+
+* Dropped IE6 support
+* Added position option to global options (bottom-left, top-left, top-right, bottom-right)
+
+### Changes in 1.7 (March 25, 2011)
+
+* Fixed 404 issue in the css when fetching '.' as an image
+* Added callback parameter in before_close and after_close callbacks to determine whether it was closed manually by clicking the (X)
+
+### Changes in 1.6 (December1, 2009)
+
+* Commented code using JSDOC
+* Major code cleanup/re-write
+* Made it so when you hit the (X) close button, the notification slides up and vanishes instead of just vanishing
+* Added optional "class_name" option for $.gritter.add() to apply a class to a specific notification
+* Fixed IE7 issue pointed out by stoffel (http://boedesign.com/blog/2009/07/11/growl-for-jquery-gritter/)
+
+### Changes in 1.5 (October 21, 2009)
+
+* Renamed the global option parameters to make more sense
+* Made it so the global options are only being ran once instead of each $.gritter.add() call
+
+### Changes in 1.4 (October 20, 2009)
+
+* Added callbacks (before_open, before_close, after_open, after_close) to the gritter notifications
+* Added callbacks (before_close, after_close) to the removeAll() function
+* Using 1 image for the CSS instead of 5 (Thanks to Ozum Eldogan)
+* Added option to over-ride gritter global options with $.extend
+
+### Changes in 1.3 (August 1, 2009)
+
+* Fixed IE6 positioning bug
+
+### Changes in 1.2 (July 13, 2009)
+
+* Fixed hover bug (pointed out by Beel & tXptr on the comments)
89 src/js/gritter/css/jquery.gritter.css
@@ -0,0 +1,89 @@
+/* the norm */
+#gritter-notice-wrapper {
+ position:fixed;
+ top:20px;
+ right:20px;
+ width:301px;
+ z-index:9999;
+}
+#gritter-notice-wrapper.top-left {
+ left: 20px;
+ right: auto;
+}
+#gritter-notice-wrapper.bottom-right {
+ top: auto;
+ left: auto;
+ bottom: 20px;
+ right: 20px;
+}
+#gritter-notice-wrapper.bottom-left {
+ top: auto;
+ right: auto;
+ bottom: 20px;
+ left: 20px;
+}
+.gritter-item-wrapper {
+ position:relative;
+ margin:0 0 10px 0;
+ background:url('../images/ie-spacer.gif'); /* ie7/8 fix */
+}
+.gritter-top {
+ background:url(../images/gritter.png) no-repeat left -30px;
+ height:10px;
+}
+.hover .gritter-top {
+ background-position:right -30px;
+}
+.gritter-bottom {
+ background:url(../images/gritter.png) no-repeat left bottom;
+ height:8px;
+ margin:0;
+}
+.hover .gritter-bottom {
+ background-position: bottom right;
+}
+.gritter-item {
+ display:block;
+ background:url(../images/gritter.png) no-repeat left -40px;
+ color:#eee;
+ padding:2px 11px 8px 11px;
+ font-size: 11px;
+ font-family:verdana;
+}
+.hover .gritter-item {
+ background-position:right -40px;
+}
+.gritter-item p {
+ padding:0;
+ margin:0;
+}
+.gritter-close {
+ display:none;
+ position:absolute;
+ top:5px;
+ left:3px;
+ background:url(../images/gritter.png) no-repeat left top;
+ cursor:pointer;
+ width:30px;
+ height:30px;
+}
+.gritter-title {
+ font-size:14px;
+ font-weight:bold;
+ padding:0 0 7px 0;
+ display:block;
+ text-shadow:1px 1px #000; /* Not supported by IE :( */
+}
+.gritter-image {
+ width:48px;
+ height:48px;
+ float:left;
+}
+.gritter-with-image,
+.gritter-without-image {
+ padding:0 0 5px 0;
+}
+.gritter-with-image {
+ width:220px;
+ float:right;
+}
BIN  src/js/gritter/images/gritter-long.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/js/gritter/images/gritter.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/js/gritter/images/ie-spacer.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN  src/js/gritter/images/trees.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
224 src/js/gritter/index.html
@@ -0,0 +1,224 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>Gritter demo for jQuery - boedesign.com</title>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="css/jquery.gritter.css" />
+<script type="text/javascript" src="http://www.google.com/jsapi"></script>
+<script type="text/javascript">google.load('jquery', '1.5');</script>
+<script type="text/javascript" src="js/jquery.gritter.min.js"></script>
+<style type="text/css">
+ body {
+ background:#222 url(images/trees.jpg);
+ color:#fff;
+ }
+ a {
+ color:#00ff00;
+ }
+ #container {
+ width:600px;
+ background:#333;
+ padding:10px;
+ }
+</style>
+</head>
+
+
+<body>
+<div id="container">
+ <h1>Gritter Demo</h1>
+ <p>
+ The super awesome background is just to show you that all notifications are transparent!
+ <em>Tested in: FF 3+, Opera 9, IE7, IE8, Safari 4+</em>
+ </p>
+ <ul>
+ <li>
+ <a href="#" id="add-regular">Add regular notification</a>: Fades out after a certain amount of time, can be set for each notification.
+ </li>
+ <li>
+ <a href="#" id="add-sticky">Add sticky notification</a>: Doesn't run on a fade timer. Just sits there until the user manually removes it by clicking on the (X)
+ </li>
+ <li>
+ <a href="#" id="add-without-image">Add notification without image</a>
+ </li>
+ <li>
+ <a href="#" id="add-with-callbacks">Add notification (with callbacks)</a>
+ </li>
+ <li>
+ <a href="#" id="add-sticky-with-callbacks">Add a sticky notification (with callbacks)</a>
+ </li>
+ <li>
+ <a href="#" id="remove-all">Remove all notifications</a>
+ </li>
+ <li>
+ <a href="#" id="remove-all-with-callbacks">Remove all notifications (with callbacks)</a>
+ </li>
+ </ul>
+</div>
+
+<script type="text/javascript">
+
+ $(function(){
+
+ // global setting override
+ /*
+ $.extend($.gritter.options, {
+ position: 'bottom-left', // possibilities: bottom-left, bottom-right, top-left, top-right
+ fade_in_speed: 100, // how fast notifications fade in (string or int)
+ fade_out_speed: 100, // how fast the notices fade out
+ time: 3000 // hang on the screen for...
+ });
+ */
+
+ $('#add-sticky').click(function(){
+
+ var unique_id = $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: 'This is a sticky notice!',
+ // (string | mandatory) the text inside the notification
+ text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus eget tincidunt velit. Cum sociis natoque penatibus et <a href="#" style="color:#ccc">magnis dis parturient</a> montes, nascetur ridiculus mus.',
+ // (string | optional) the image to display on the left
+ image: 'http://s3.amazonaws.com/twitter_production/profile_images/132499022/myface_bigger.jpg',
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: true,
+ // (int | optional) the time you want it to be alive for before fading out
+ time: '',
+ // (string | optional) the class name you want to apply to that specific message
+ class_name: 'my-sticky-class'
+ });
+
+ // You can have it return a unique id, this can be used to manually remove it later using
+ /*
+ setTimeout(function(){
+
+ $.gritter.remove(unique_id, {
+ fade: true,
+ speed: 'slow'
+ });
+
+ }, 6000)
+ */
+
+ return false;
+
+ });
+
+ $('#add-regular').click(function(){
+
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: 'This is a regular notice!',
+ // (string | mandatory) the text inside the notification
+ text: 'This will fade out after a certain amount of time. Vivamus eget tincidunt velit. Cum sociis natoque penatibus et <a href="#" style="color:#ccc">magnis dis parturient</a> montes, nascetur ridiculus mus.',
+ // (string | optional) the image to display on the left
+ image: 'http://a0.twimg.com/profile_images/59268975/jquery_avatar_bigger.png',
+ // (bool | optional) if you want it to fade out on its own or just sit there
+ sticky: false,
+ // (int | optional) the time you want it to be alive for before fading out
+ time: ''
+ });
+
+ return false;
+
+ });
+
+ $('#add-without-image').click(function(){
+
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: 'This is a notice without an image!',
+ // (string | mandatory) the text inside the notification
+ text: 'This will fade out after a certain amount of time. Vivamus eget tincidunt velit. Cum sociis natoque penatibus et <a href="#" style="color:#ccc">magnis dis parturient</a> montes, nascetur ridiculus mus.'
+ });
+
+ return false;
+ });
+
+ $('#add-with-callbacks').click(function(){
+
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: 'This is a notice with callbacks!',
+ // (string | mandatory) the text inside the notification
+ text: 'The callback is...',
+ // (function | optional) function called before it opens
+ before_open: function(){
+ alert('I am called before it opens');
+ },
+ // (function | optional) function called after it opens
+ after_open: function(e){
+ alert("I am called after it opens: \nI am passed the jQuery object for the created Gritter element...\n" + e);
+ },
+ // (function | optional) function called before it closes
+ before_close: function(e, manual_close){
+ var manually = (manual_close) ? 'The "X" was clicked to close me!' : '';
+ alert("I am called before it closes: I am passed the jQuery object for the Gritter element... \n" + manually);
+ },
+ // (function | optional) function called after it closes
+ after_close: function(e, manual_close){
+ var manually = (manual_close) ? 'The "X" was clicked to close me!' : '';
+ alert('I am called after it closes. ' + manually);
+ }
+ });
+
+ return false;
+ });
+
+ $('#add-sticky-with-callbacks').click(function(){
+
+ $.gritter.add({
+ // (string | mandatory) the heading of the notification
+ title: 'This is a sticky notice with callbacks!',
+ // (string | mandatory) the text inside the notification
+ text: 'Sticky sticky notice.. sticky sticky notice...',
+ // Stickeh!
+ sticky: true,
+ // (function | optional) function called before it opens
+ before_open: function(){
+ alert('I am a sticky called before it opens');
+ },
+ // (function | optional) function called after it opens
+ after_open: function(e){
+ alert("I am a sticky called after it opens: \nI am passed the jQuery object for the created Gritter element...\n" + e);
+ },
+ // (function | optional) function called before it closes
+ before_close: function(e){
+ alert("I am a sticky called before it closes: I am passed the jQuery object for the Gritter element... \n" + e);
+ },
+ // (function | optional) function called after it closes
+ after_close: function(){
+ alert('I am a sticky called after it closes');
+ }
+ });
+
+ return false;
+
+ });
+
+ $("#remove-all").click(function(){
+
+ $.gritter.removeAll();
+ return false;
+
+ });
+
+ $("#remove-all-with-callbacks").click(function(){
+
+ $.gritter.removeAll({
+ before_close: function(e){
+ alert("I am called before all notifications are closed. I am passed the jQuery object containing all of Gritter notifications.\n" + e);
+ },
+ after_close: function(){
+ alert('I am called after everything has been closed.');
+ }
+ });
+ return false;
+
+ });
+
+
+ });
+</script>
+
+</body>
+</html>
405 src/js/gritter/js/jquery.gritter.js
@@ -0,0 +1,405 @@
+/*
+ * Gritter for jQuery
+ * http://www.boedesign.com/
+ *
+ * Copyright (c) 2011 Jordan Boesch
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ * Date: March 29, 2011
+ * Version: 1.7.1
+ */
+
+(function($){
+
+ /**
+ * Set it up as an object under the jQuery namespace
+ */
+ $.gritter = {};
+
+ /**
+ * Set up global options that the user can over-ride
+ */
+ $.gritter.options = {
+ position: '',
+ fade_in_speed: 'medium', // how fast notifications fade in
+ fade_out_speed: 1000, // how fast the notices fade out
+ time: 6000 // hang on the screen for...
+ }
+
+ /**
+ * Add a gritter notification to the screen
+ * @see Gritter#add();
+ */
+ $.gritter.add = function(params){
+
+ try {
+ return Gritter.add(params || {});
+ } catch(e) {
+
+ var err = 'Gritter Error: ' + e;
+ (typeof(console) != 'undefined' && console.error) ?
+ console.error(err, params) :
+ alert(err);
+
+ }
+
+ }
+
+ /**
+ * Remove a gritter notification from the screen
+ * @see Gritter#removeSpecific();
+ */
+ $.gritter.remove = function(id, params){
+ Gritter.removeSpecific(id, params || {});
+ }
+
+ /**
+ * Remove all notifications
+ * @see Gritter#stop();
+ */
+ $.gritter.removeAll = function(params){
+ Gritter.stop(params || {});
+ }
+
+ /**
+ * Big fat Gritter object
+ * @constructor (not really since it's object literal)
+ */
+ var Gritter = {
+
+ // Public - options to over-ride with $.gritter.options in "add"
+ position: '',
+ fade_in_speed: '',
+ fade_out_speed: '',
+ time: '',
+
+ // Private - no touchy the private parts
+ _custom_timer: 0,
+ _item_count: 0,
+ _is_setup: 0,
+ _tpl_close: '<div class="gritter-close"></div>',
+ _tpl_item: '<div id="gritter-item-[[number]]" class="gritter-item-wrapper [[item_class]]" style="display:none"><div class="gritter-top"></div><div class="gritter-item">[[close]][[image]]<div class="[[class_name]]"><span class="gritter-title">[[username]]</span><p>[[text]]</p></div><div style="clear:both"></div></div><div class="gritter-bottom"></div></div>',
+ _tpl_wrap: '<div id="gritter-notice-wrapper"></div>',
+
+ /**
+ * Add a gritter notification to the screen
+ * @param {Object} params The object that contains all the options for drawing the notification
+ * @return {Integer} The specific numeric id to that gritter notification
+ */
+ add: function(params){
+
+ // We might have some issues if we don't have a title or text!
+ if(!params.title || !params.text){
+ throw 'You need to fill out the first 2 params: "title" and "text"';
+ }
+
+ // Check the options and set them once
+ if(!this._is_setup){
+ this._runSetup();
+ }
+
+ // Basics
+ var user = params.title,
+ text = params.text,
+ image = params.image || '',
+ sticky = params.sticky || false,
+ item_class = params.class_name || '',
+ position = $.gritter.options.position,
+ time_alive = params.time || '';
+
+ this._verifyWrapper();
+
+ this._item_count++;
+ var number = this._item_count,
+ tmp = this._tpl_item;
+
+ // Assign callbacks
+ $(['before_open', 'after_open', 'before_close', 'after_close']).each(function(i, val){
+ Gritter['_' + val + '_' + number] = ($.isFunction(params[val])) ? params[val] : function(){}
+ });
+
+ // Reset
+ this._custom_timer = 0;
+
+ // A custom fade time set
+ if(time_alive){
+ this._custom_timer = time_alive;
+ }
+
+ var image_str = (image != '') ? '<img src="' + image + '" class="gritter-image" />' : '',
+ class_name = (image != '') ? 'gritter-with-image' : 'gritter-without-image';
+
+ // String replacements on the template
+ tmp = this._str_replace(
+ ['[[username]]', '[[text]]', '[[close]]', '[[image]]', '[[number]]', '[[class_name]]', '[[item_class]]'],
+ [user, text, this._tpl_close, image_str, this._item_count, class_name, item_class], tmp
+ );
+
+ this['_before_open_' + number]();
+ $('#gritter-notice-wrapper').addClass(position).append(tmp);
+
+ var item = $('#gritter-item-' + this._item_count);
+
+ item.fadeIn(this.fade_in_speed, function(){
+ Gritter['_after_open_' + number]($(this));
+ });
+
+ if(!sticky){
+ this._setFadeTimer(item, number);
+ }
+
+ // Bind the hover/unhover states
+ $(item).bind('mouseenter mouseleave', function(event){
+ if(event.type == 'mouseenter'){
+ if(!sticky){
+ Gritter._restoreItemIfFading($(this), number);
+ }
+ }
+ else {
+ if(!sticky){
+ Gritter._setFadeTimer($(this), number);
+ }
+ }
+ Gritter._hoverState($(this), event.type);
+ });
+
+ return number;
+
+ },
+
+ /**
+ * If we don't have any more gritter notifications, get rid of the wrapper using this check
+ * @private
+ * @param {Integer} unique_id The ID of the element that was just deleted, use it for a callback
+ * @param {Object} e The jQuery element that we're going to perform the remove() action on
+ * @param {Boolean} manual_close Did we close the gritter dialog with the (X) button
+ */
+ _countRemoveWrapper: function(unique_id, e, manual_close){
+
+ // Remove it then run the callback function
+ e.remove();
+ this['_after_close_' + unique_id](e, manual_close);
+
+ // Check if the wrapper is empty, if it is.. remove the wrapper
+ if($('.gritter-item-wrapper').length == 0){
+ $('#gritter-notice-wrapper').remove();
+ }
+
+ },
+
+ /**
+ * Fade out an element after it's been on the screen for x amount of time
+ * @private
+ * @param {Object} e The jQuery element to get rid of
+ * @param {Integer} unique_id The id of the element to remove
+ * @param {Object} params An optional list of params to set fade speeds etc.
+ * @param {Boolean} unbind_events Unbind the mouseenter/mouseleave events if they click (X)
+ */
+ _fade: function(e, unique_id, params, unbind_events){
+
+ var params = params || {},
+ fade = (typeof(params.fade) != 'undefined') ? params.fade : true;
+ fade_out_speed = params.speed || this.fade_out_speed,
+ manual_close = unbind_events;
+
+ this['_before_close_' + unique_id](e, manual_close);
+
+ // If this is true, then we are coming from clicking the (X)
+ if(unbind_events){
+ e.unbind('mouseenter mouseleave');
+ }
+
+ // Fade it out or remove it
+ if(fade){
+
+ e.animate({
+ opacity: 0
+ }, fade_out_speed, function(){
+ e.animate({ height: 0 }, 300, function(){
+ Gritter._countRemoveWrapper(unique_id, e, manual_close);
+ })
+ })
+
+ }
+ else {
+
+ this._countRemoveWrapper(unique_id, e);
+
+ }
+
+ },
+
+ /**
+ * Perform actions based on the type of bind (mouseenter, mouseleave)
+ * @private
+ * @param {Object} e The jQuery element
+ * @param {String} type The type of action we're performing: mouseenter or mouseleave
+ */
+ _hoverState: function(e, type){
+
+ // Change the border styles and add the (X) close button when you hover
+ if(type == 'mouseenter'){
+
+ e.addClass('hover');
+
+ // Show close button
+ e.find('.gritter-close').show();
+
+ // Clicking (X) makes the perdy thing close
+ e.find('.gritter-close').click(function(){
+
+ var unique_id = e.attr('id').split('-')[2];
+ Gritter.removeSpecific(unique_id, {}, e, true);
+
+ });
+
+ }
+ // Remove the border styles and hide (X) close button when you mouse out
+ else {
+
+ e.removeClass('hover');
+
+ // Hide close button
+ e.find('.gritter-close').hide();
+
+ }
+
+ },
+
+ /**
+ * Remove a specific notification based on an ID
+ * @param {Integer} unique_id The ID used to delete a specific notification
+ * @param {Object} params A set of options passed in to determine how to get rid of it
+ * @param {Object} e The jQuery element that we're "fading" then removing
+ * @param {Boolean} unbind_events If we clicked on the (X) we set this to true to unbind mouseenter/mouseleave
+ */
+ removeSpecific: function(unique_id, params, e, unbind_events){
+
+ if(!e){
+ var e = $('#gritter-item-' + unique_id);
+ }
+
+ // We set the fourth param to let the _fade function know to
+ // unbind the "mouseleave" event. Once you click (X) there's no going back!
+ this._fade(e, unique_id, params || {}, unbind_events);
+
+ },
+
+ /**
+ * If the item is fading out and we hover over it, restore it!
+ * @private
+ * @param {Object} e The HTML element to remove
+ * @param {Integer} unique_id The ID of the element
+ */
+ _restoreItemIfFading: function(e, unique_id){
+
+ clearTimeout(this['_int_id_' + unique_id]);
+ e.stop().css({ opacity: '', height: '' });
+
+ },
+
+ /**
+ * Setup the global options - only once
+ * @private
+ */
+ _runSetup: function(){
+
+ for(opt in $.gritter.options){
+ this[opt] = $.gritter.options[opt];
+ }
+ this._is_setup = 1;
+
+ },
+
+ /**
+ * Set the notification to fade out after a certain amount of time
+ * @private
+ * @param {Object} item The HTML element we're dealing with
+ * @param {Integer} unique_id The ID of the element
+ */
+ _setFadeTimer: function(e, unique_id){
+
+ var timer_str = (this._custom_timer) ? this._custom_timer : this.time;
+ this['_int_id_' + unique_id] = setTimeout(function(){
+ Gritter._fade(e, unique_id);
+ }, timer_str);
+
+ },
+
+ /**
+ * Bring everything to a halt
+ * @param {Object} params A list of callback functions to pass when all notifications are removed
+ */
+ stop: function(params){
+
+ // callbacks (if passed)
+ var before_close = ($.isFunction(params.before_close)) ? params.before_close : function(){};
+ var after_close = ($.isFunction(params.after_close)) ? params.after_close : function(){};
+
+ var wrap = $('#gritter-notice-wrapper');
+ before_close(wrap);
+ wrap.fadeOut(function(){
+ $(this).remove();
+ after_close();
+ });
+
+ },
+
+ /**
+ * An extremely handy PHP function ported to JS, works well for templating
+ * @private
+ * @param {String/Array} search A list of things to search for
+ * @param {String/Array} replace A list of things to replace the searches with
+ * @return {String} sa The output
+ */
+ _str_replace: function(search, replace, subject, count){
+
+ var i = 0, j = 0, temp = '', repl = '', sl = 0, fl = 0,
+ f = [].concat(search),
+ r = [].concat(replace),
+ s = subject,
+ ra = r instanceof Array, sa = s instanceof Array;
+ s = [].concat(s);
+
+ if(count){
+ this.window[count] = 0;
+ }
+
+ for(i = 0, sl = s.length; i < sl; i++){
+
+ if(s[i] === ''){
+ continue;
+ }
+
+ for (j = 0, fl = f.length; j < fl; j++){
+
+ temp = s[i] + '';
+ repl = ra ? (r[j] !== undefined ? r[j] : '') : r[0];
+ s[i] = (temp).split(f[j]).join(repl);
+
+ if(count && s[i] !== temp){
+ this.window[count] += (temp.length-s[i].length) / f[j].length;
+ }
+
+ }
+ }
+
+ return sa ? s : s[0];
+
+ },
+
+ /**
+ * A check to make sure we have something to wrap our notices with
+ * @private
+ */
+ _verifyWrapper: function(){
+
+ if($('#gritter-notice-wrapper').length == 0){
+ $('body').append(this._tpl_wrap);
+ }
+
+ }
+
+ }
+
+})(jQuery);
11 src/js/gritter/js/jquery.gritter.min.js
@@ -0,0 +1,11 @@
+/*
+ * Gritter for jQuery
+ * http://www.boedesign.com/
+ *
+ * Copyright (c) 2011 Jordan Boesch
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ * Date: July 9, 2011
+ * Version: 1.7.1
+ */
+(function(b){b.gritter={};b.gritter.options={position:"",fade_in_speed:"medium",fade_out_speed:1000,time:6000};b.gritter.add=function(f){try{return a.add(f||{})}catch(d){var c="Gritter Error: "+d;(typeof(console)!="undefined"&&console.error)?console.error(c,f):alert(c)}};b.gritter.remove=function(d,c){a.removeSpecific(d,c||{})};b.gritter.removeAll=function(c){a.stop(c||{})};var a={position:"",fade_in_speed:"",fade_out_speed:"",time:"",_custom_timer:0,_item_count:0,_is_setup:0,_tpl_close:'<div class="gritter-close"></div>',_tpl_item:'<div id="gritter-item-[[number]]" class="gritter-item-wrapper [[item_class]]" style="display:none"><div class="gritter-top"></div><div class="gritter-item">[[close]][[image]]<div class="[[class_name]]"><span class="gritter-title">[[username]]</span><p>[[text]]</p></div><div style="clear:both"></div></div><div class="gritter-bottom"></div></div>',_tpl_wrap:'<div id="gritter-notice-wrapper"></div>',add:function(g){if(!g.title||!g.text){throw'You need to fill out the first 2 params: "title" and "text"'}if(!this._is_setup){this._runSetup()}var i=g.title,n=g.text,e=g.image||"",l=g.sticky||false,m=g.class_name||"",k=b.gritter.options.position,d=g.time||"";this._verifyWrapper();this._item_count++;var f=this._item_count,j=this._tpl_item;b(["before_open","after_open","before_close","after_close"]).each(function(p,q){a["_"+q+"_"+f]=(b.isFunction(g[q]))?g[q]:function(){}});this._custom_timer=0;if(d){this._custom_timer=d}var c=(e!="")?'<img src="'+e+'" class="gritter-image" />':"",h=(e!="")?"gritter-with-image":"gritter-without-image";j=this._str_replace(["[[username]]","[[text]]","[[close]]","[[image]]","[[number]]","[[class_name]]","[[item_class]]"],[i,n,this._tpl_close,c,this._item_count,h,m],j);this["_before_open_"+f]();b("#gritter-notice-wrapper").addClass(k).append(j);var o=b("#gritter-item-"+this._item_count);o.fadeIn(this.fade_in_speed,function(){a["_after_open_"+f](b(this))});if(!l){this._setFadeTimer(o,f)}b(o).bind("mouseenter mouseleave",function(p){if(p.type=="mouseenter"){if(!l){a._restoreItemIfFading(b(this),f)}}else{if(!l){a._setFadeTimer(b(this),f)}}a._hoverState(b(this),p.type)});return f},_countRemoveWrapper:function(c,d,f){d.remove();this["_after_close_"+c](d,f);if(b(".gritter-item-wrapper").length==0){b("#gritter-notice-wrapper").remove()}},_fade:function(f,c,h,d){var h=h||{},g=(typeof(h.fade)!="undefined")?h.fade:true;fade_out_speed=h.speed||this.fade_out_speed,manual_close=d;this["_before_close_"+c](f,manual_close);if(d){f.unbind("mouseenter mouseleave")}if(g){f.animate({opacity:0},fade_out_speed,function(){f.animate({height:0},300,function(){a._countRemoveWrapper(c,f,manual_close)})})}else{this._countRemoveWrapper(c,f)}},_hoverState:function(d,c){if(c=="mouseenter"){d.addClass("hover");d.find(".gritter-close").show();d.find(".gritter-close").click(function(){var e=d.attr("id").split("-")[2];a.removeSpecific(e,{},d,true)})}else{d.removeClass("hover");d.find(".gritter-close").hide()}},removeSpecific:function(c,g,f,d){if(!f){var f=b("#gritter-item-"+c)}this._fade(f,c,g||{},d)},_restoreItemIfFading:function(d,c){clearTimeout(this["_int_id_"+c]);d.stop().css({opacity:"",height:""})},_runSetup:function(){for(opt in b.gritter.options){this[opt]=b.gritter.options[opt]}this._is_setup=1},_setFadeTimer:function(f,d){var c=(this._custom_timer)?this._custom_timer:this.time;this["_int_id_"+d]=setTimeout(function(){a._fade(f,d)},c)},stop:function(e){var c=(b.isFunction(e.before_close))?e.before_close:function(){};var f=(b.isFunction(e.after_close))?e.after_close:function(){};var d=b("#gritter-notice-wrapper");c(d);d.fadeOut(function(){b(this).remove();f()})},_str_replace:function(v,e,o,n){var k=0,h=0,t="",m="",g=0,q=0,l=[].concat(v),c=[].concat(e),u=o,d=c instanceof Array,p=u instanceof Array;u=[].concat(u);if(n){this.window[n]=0}for(k=0,g=u.length;k<g;k++){if(u[k]===""){continue}for(h=0,q=l.length;h<q;h++){t=u[k]+"";m=d?(c[h]!==undefined?c[h]:""):c[0];u[k]=(t).split(l[h]).join(m);if(n&&u[k]!==t){this.window[n]+=(t.length-u[k].length)/l[h].length}}}return p?u:u[0]},_verifyWrapper:function(){if(b("#gritter-notice-wrapper").length==0){b("body").append(this._tpl_wrap)}}}})(jQuery);
59 src/js/pusher-notification-helper.js
@@ -0,0 +1,59 @@
+function PusherNotificationHelper(pusher, options) {
+
+ options = options || {};
+
+ var defaults = {
+ channelName: 'notify',
+ imageDir: 'images'
+ };
+
+ $.extend(options, defaults);
+
+ var channel = pusher.subscribe(options.channelName);
+ channel.bind('created', handleCreated);
+ channel.bind('read', handleRead);
+ channel.bind('updated', handleUpdated);
+ channel.bind('deleted', handleDeleted);
+ channel.bind('announce', handleAnnounce);
+
+ function handleCreated(data){
+ $.gritter.add({
+ title: 'Created',
+ text: data.message,
+ image: options.imageDir + '/create.png'
+ });
+ }
+
+ function handleRead(data){
+ $.gritter.add({
+ title: 'Read',
+ text: data.message,
+ image: options.imageDir + '/read.png'
+ });
+ }
+
+ function handleUpdated(data){
+ $.gritter.add({
+ title: 'Updated',
+ text: data.message,
+ image: options.imageDir + '/update.png'
+ });
+ }
+
+ function handleDeleted(data){
+ $.gritter.add({
+ title: 'Deleted',
+ text: data.message,
+ image: options.imageDir + '/delete.png'
+ });
+ }
+
+ function handleAnnounce(data) {
+ $.gritter.add({
+ title: 'Announcement',
+ text: data.message.replace(/\\/g, ''),
+ image: options.imageDir + '/announce.png'
+ });
+ }
+
+};
BIN  src/lib/.DS_Store
Binary file not shown
BIN  src/lib/less/.DS_Store
Binary file not shown
16 src/lib/less/less-1.1.5.min.js
@@ -0,0 +1,16 @@
+//
+// LESS - Leaner CSS v1.1.5
+// http://lesscss.org
+//
+// Copyright (c) 2009-2011, Alexis Sellier
+// Licensed under the Apache 2.0 License.
+//
+//
+// LESS - Leaner CSS v1.1.5
+// http://lesscss.org
+//
+// Copyright (c) 2009-2011, Alexis Sellier
+// Licensed under the Apache 2.0 License.
+//
+(function(a,b){function c(b){return a.less[b.split("/")[1]]}function l(){var a=document.getElementsByTagName("style");for(var b=0;b<a.length;b++)a[b].type.match(j)&&(new d.Parser).parse(a[b].innerHTML||"",function(c,d){var e=d.toCSS(),f=a[b];try{f.innerHTML=e}catch(g){f.styleSheets.cssText=e}f.type="text/css"})}function m(a,b){for(var c=0;c<d.sheets.length;c++)n(d.sheets[c],a,b,d.sheets.length-(c+1))}function n(b,c,e,f){var h=a.location.href.replace(/[#?].*$/,""),i=b.href.replace(/\?.*$/,""),j=g&&g.getItem(i),k=g&&g.getItem(i+":timestamp"),l={css:j,timestamp:k};/^(https?|file):/.test(i)||(i.charAt(0)=="/"?i=a.location.protocol+"//"+a.location.host+i:i=h.slice(0,h.lastIndexOf("/")+1)+i),q(b.href,b.type,function(a,g){if(!e&&l&&g&&(new Date(g)).valueOf()===(new Date(l.timestamp)).valueOf())p(l.css,b),c(null,b,{local:!0,remaining:f});else try{(new d.Parser({optimization:d.optimization,paths:[i.replace(/[\w\.-]+$/,"")],mime:b.type})).parse(a,function(a,d){if(a)return u(a,i);try{c(d,b,{local:!1,lastModified:g,remaining:f}),s(document.getElementById("less-error-message:"+o(i)))}catch(a){u(a,i)}})}catch(h){u(h,i)}},function(a,b){throw new Error("Couldn't load "+b+" ("+a+")")})}function o(a){return a.replace(/^[a-z]+:\/\/?[^\/]+/,"").replace(/^\//,"").replace(/\?.*$/,"").replace(/\.[^\.\/]+$/,"").replace(/[^\.\w-]+/g,"-").replace(/\./g,":")}function p(a,b,c){var d,e=b.href?b.href.replace(/\?.*$/,""):"",f="less:"+(b.title||o(e));(d=document.getElementById(f))===null&&(d=document.createElement("style"),d.type="text/css",d.media=b.media||"screen",d.id=f,document.getElementsByTagName("head")[0].appendChild(d));if(d.styleSheet)try{d.styleSheet.cssText=a}catch(h){throw new Error("Couldn't reassign styleSheet.cssText.")}else(function(a){d.childNodes.length>0?d.firstChild.nodeValue!==a.nodeValue&&d.replaceChild(a,d.firstChild):d.appendChild(a)})(document.createTextNode(a));c&&g&&(t("saving "+e+" to cache."),g.setItem(e,a),g.setItem(e+":timestamp",c))}function q(a,b,c,e){function i(b,c,d){b.status>=200&&b.status<300?c(b.responseText,b.getResponseHeader("Last-Modified")):typeof d=="function"&&d(b.status,a)}var g=r(),h=f?!1:d.async;typeof g.overrideMimeType=="function"&&g.overrideMimeType("text/css"),g.open("GET",a,h),g.setRequestHeader("Accept",b||"text/x-less, text/css; q=0.9, */*; q=0.5"),g.send(null),f?g.status===0?c(g.responseText):e(g.status,a):h?g.onreadystatechange=function(){g.readyState==4&&i(g,c,e)}:i(g,c,e)}function r(){if(a.XMLHttpRequest)return new XMLHttpRequest;try{return new ActiveXObject("MSXML2.XMLHTTP.3.0")}catch(b){return t("browser doesn't support AJAX."),null}}function s(a){return a&&a.parentNode.removeChild(a)}function t(a){d.env=="development"&&typeof console!="undefined"&&console.log("less: "+a)}function u(a,b){var c="less-error-message:"+o(b),e=["<ul>",'<li><label>[-1]</label><pre class="ctx">{0}</pre></li>',"<li><label>[0]</label><pre>{current}</pre></li>",'<li><label>[1]</label><pre class="ctx">{2}</pre></li>',"</ul>"].join("\n"),f=document.createElement("div"),g,h;f.id=c,f.className="less-error-message",h="<h3>"+(a.message||"There is an error in your .less file")+"</h3>"+'<p><a href="'+b+'">'+b+"</a> ",a.extract&&(h+="on line "+a.line+", column "+(a.column+1)+":</p>"+e.replace(/\[(-?\d)\]/g,function(b,c){return parseInt(a.line)+parseInt(c)||""}).replace(/\{(\d)\}/g,function(b,c){return a.extract[parseInt(c)]||""}).replace(/\{current\}/,a.extract[1].slice(0,a.column)+'<span class="error">'+a.extract[1].slice(a.column)+"</span>")),f.innerHTML=h,p([".less-error-message ul, .less-error-message li {","list-style-type: none;","margin-right: 15px;","padding: 4px 0;","margin: 0;","}",".less-error-message label {","font-size: 12px;","margin-right: 15px;","padding: 4px 0;","color: #cc7777;","}",".less-error-message pre {","color: #ee4444;","padding: 4px 0;","margin: 0;","display: inline-block;","}",".less-error-message pre.ctx {","color: #dd4444;","}",".less-error-message h3 {","font-size: 20px;","font-weight: bold;","padding: 15px 0 5px 0;","margin: 0;","}",".less-error-message a {","color: #10a","}",".less-error-message .error {","color: red;","font-weight: bold;","padding-bottom: 2px;","border-bottom: 1px dashed red;","}"].join("\n"),{title:"error-message"}),f.style.cssText=["font-family: Arial, sans-serif","border: 1px solid #e00","background-color: #eee","border-radius: 5px","-webkit-border-radius: 5px","-moz-border-radius: 5px","color: #e00","padding: 15px","margin-bottom: 15px"].join(";"),d.env=="development"&&(g=setInterval(function(){document.body&&(document.getElementById(c)?document.body.replaceChild(f,document.getElementById(c)):document.body.insertBefore(f,document.body.firstChild),clearInterval(g))},10))}Array.isArray||(Array.isArray=function(a){return Object.prototype.toString.call(a)==="[object Array]"||a instanceof Array}),Array.prototype.forEach||(Array.prototype.forEach=function(a,b){var c=this.length>>>0;for(var d=0;d<c;d++)d in this&&a.call(b,this[d],d,this)}),Array.prototype.map||(Array.prototype.map=function(a){var b=this.length>>>0,c=new Array(b),d=arguments[1];for(var e=0;e<b;e++)e in this&&(c[e]=a.call(d,this[e],e,this));return c}),Array.prototype.filter||(Array.prototype.filter=function(a){var b=[],c=arguments[1];for(var d=0;d<this.length;d++)a.call(c,this[d])&&b.push(this[d]);return b}),Array.prototype.reduce||(Array.prototype.reduce=function(a){var b=this.length>>>0,c=0;if(b===0&&arguments.length===1)throw new TypeError;if(arguments.length>=2)var d=arguments[1];else do{if(c in this){d=this[c++];break}if(++c>=b)throw new TypeError}while(!0);for(;c<b;c++)c in this&&(d=a.call(null,d,this[c],c,this));return d}),Array.prototype.indexOf||(Array.prototype.indexOf=function(a){var b=this.length,c=arguments[1]||0;if(!b)return-1;if(c>=b)return-1;c<0&&(c+=b);for(;c<b;c++){if(!Object.prototype.hasOwnProperty.call(this,c))continue;if(a===this[c])return c}return-1}),Object.keys||(Object.keys=function(a){var b=[];for(var c in a)Object.prototype.hasOwnProperty.call(a,c)&&b.push(c);return b}),String.prototype.trim||(String.prototype.trim=function(){return String(this).replace(/^\s\s*/,"").replace(/\s\s*$/,"")});var d,e;typeof environment=="object"&&{}.toString.call(environment)==="[object Environment]"?(d={},e=d.tree={},d.mode="rhino"):typeof a=="undefined"?(d=exports,e=c("./tree"),d.mode="rhino"):(typeof a.less=="undefined"&&(a.less={}),d=a.less,e=a.less.tree={},d.mode="browser"),d.Parser=function(a){function p(){g=j[f],h=c,k=c}function q(){j[f]=g,c=h,k=c}function r(){c>k&&(j[f]=j[f].slice(c-k),k=c)}function s(a){var d,e,g,h,i,m,n,o;if(a instanceof Function)return a.call(l.parsers);if(typeof a=="string")d=b.charAt(c)===a?a:null,g=1,r();else{r();if(d=a.exec(j[f]))g=d[0].length;else return null}if(d){o=c+=g,m=c+j[f].length-g;while(c<m){h=b.charCodeAt(c);if(h!==32&&h!==10&&h!==9)break;c++}return j[f]=j[f].slice(g+(c-o)),k=c,j[f].length===0&&f<j.length-1&&f++,typeof d=="string"?d:d.length===1?d[0]:d}}function t(a){return typeof a=="string"?b.charAt(c)===a:a.test(j[f])?!0:!1}var b,c,f,g,h,i,j,k,l,m=this,n=function(){},o=this.imports={paths:a&&a.paths||[],queue:[],files:{},mime:a&&a.mime,push:function(b,c){var e=this;this.queue.push(b),d.Parser.importer(b,this.paths,function(a){e.queue.splice(e.queue.indexOf(b),1),e.files[b]=a,c(a),e.queue.length===0&&n()},a)}};return this.env=a=a||{},this.optimization="optimization"in this.env?this.env.optimization:1,this.env.filename=this.env.filename||null,l={imports:o,parse:function(d,g){var h,l,m,o,p,q,r=[],t,u=null;c=f=k=i=0,j=[],b=d.replace(/\r\n/g,"\n"),j=function(c){var d=0,e=/[^"'`\{\}\/\(\)]+/g,f=/\/\*(?:[^*]|\*+[^\/*])*\*+\/|\/\/.*/g,g=0,h,i=c[0],j,k;for(var l=0,m,n;l<b.length;l++){e.lastIndex=l,(h=e.exec(b))&&h.index===l&&(l+=h[0].length,i.push(h[0])),m=b.charAt(l),f.lastIndex=l,!k&&!j&&m==="/"&&(n=b.charAt(l+1),(n==="/"||n==="*")&&(h=f.exec(b))&&h.index===l&&(l+=h[0].length,i.push(h[0]),m=b.charAt(l)));if(m==="{"&&!k&&!j)g++,i.push(m);else if(m==="}"&&!k&&!j)g--,i.push(m),c[++d]=i=[];else if(m==="("&&!k&&!j)i.push(m),j=!0;else if(m===")"&&!k&&j)i.push(m),j=!1;else{if(m==='"'||m==="'"||m==="`")k?k=k===m?!1:k:k=m;i.push(m)}}if(g>0)throw{type:"Syntax",message:"Missing closing `}`",filename:a.filename};return c.map(function(a){return a.join("")})}([[]]),h=new e.Ruleset([],s(this.parsers.primary)),h.root=!0,h.toCSS=function(c){var d,f,g;return function(g,h){function n(a){return a?(b.slice(0,a).match(/\n/g)||"").length:null}var i=[];g=g||{},typeof h=="object"&&!Array.isArray(h)&&(h=Object.keys(h).map(function(a){var b=h[a];return b instanceof e.Value||(b instanceof e.Expression||(b=new e.Expression([b])),b=new e.Value([b])),new e.Rule("@"+a,b,!1,0)}),i=[new e.Ruleset(null,h)]);try{var j=c.call(this,{frames:i}).toCSS([],{compress:g.compress||!1})}catch(k){f=b.split("\n"),d=n(k.index);for(var l=k.index,m=-1;l>=0&&b.charAt(l)!=="\n";l--)m++;throw{type:k.type,message:k.message,filename:a.filename,index:k.index,line:typeof d=="number"?d+1:null,callLine:k.call&&n(k.call)+1,callExtract:f[n(k.call)],stack:k.stack,column:m,extract:[f[d-1],f[d],f[d+1]]}}return g.compress?j.replace(/(\s)+/g,"$1"):j}}(h.eval);if(c<b.length-1){c=i,q=b.split("\n"),p=(b.slice(0,c).match(/\n/g)||"").length+1;for(var v=c,w=-1;v>=0&&b.charAt(v)!=="\n";v--)w++;u={name:"ParseError",message:"Syntax Error on line "+p,index:c,filename:a.filename,line:p,column:w,extract:[q[p-2],q[p-1],q[p]]}}this.imports.queue.length>0?n=function(){g(u,h)}:g(u,h)},parsers:{primary:function(){var a,b=[];while((a=s(this.mixin.definition)||s(this.rule)||s(this.ruleset)||s(this.mixin.call)||s(this.comment)||s(this.directive))||s(/^[\s\n]+/))a&&b.push(a);return b},comment:function(){var a;if(b.charAt(c)!=="/")return;if(b.charAt(c+1)==="/")return new e.Comment(s(/^\/\/.*/),!0);if(a=s(/^\/\*(?:[^*]|\*+[^\/*])*\*+\/\n?/))return new e.Comment(a)},entities:{quoted:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)!=='"'&&b.charAt(d)!=="'")return;f&&s("~");if(a=s(/^"((?:[^"\\\r\n]|\\.)*)"|'((?:[^'\\\r\n]|\\.)*)'/))return new e.Quoted(a[0],a[1]||a[2],f)},keyword:function(){var a;if(a=s(/^[_A-Za-z-][_A-Za-z0-9-]*/))return new e.Keyword(a)},call:function(){var a,b,d=c;if(!(a=/^([\w-]+|%)\(/.exec(j[f])))return;a=a[1].toLowerCase();if(a==="url")return null;c+=a.length;if(a==="alpha")return s(this.alpha);s("("),b=s(this.entities.arguments);if(!s(")"))return;if(a)return new e.Call(a,b,d)},arguments:function(){var a=[],b;while(b=s(this.expression)){a.push(b);if(!s(","))break}return a},literal:function(){return s(this.entities.dimension)||s(this.entities.color)||s(this.entities.quoted)},url:function(){var a;if(b.charAt(c)!=="u"||!s(/^url\(/))return;a=s(this.entities.quoted)||s(this.entities.variable)||s(this.entities.dataURI)||s(/^[-\w%@$\/.&=:;#+?~]+/)||"";if(!s(")"))throw new Error("missing closing ) for url()");return new e.URL(a.value||a.data||a instanceof e.Variable?a:new e.Anonymous(a),o.paths)},dataURI:function(){var a;if(s(/^data:/)){a={},a.mime=s(/^[^\/]+\/[^,;)]+/)||"",a.charset=s(/^;\s*charset=[^,;)]+/)||"",a.base64=s(/^;\s*base64/)||"",a.data=s(/^,\s*[^)]+/);if(a.data)return a}},variable:function(){var a,d=c;if(b.charAt(c)==="@"&&(a=s(/^@@?[\w-]+/)))return new e.Variable(a,d)},color:function(){var a;if(b.charAt(c)==="#"&&(a=s(/^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})/)))return new e.Color(a[1])},dimension:function(){var a,d=b.charCodeAt(c);if(d>57||d<45||d===47)return;if(a=s(/^(-?\d*\.?\d+)(px|%|em|pc|ex|in|deg|s|ms|pt|cm|mm|rad|grad|turn)?/))return new e.Dimension(a[1],a[2])},javascript:function(){var a,d=c,f;b.charAt(d)==="~"&&(d++,f=!0);if(b.charAt(d)!=="`")return;f&&s("~");if(a=s(/^`([^`]*)`/))return new e.JavaScript(a[1],c,f)}},variable:function(){var a;if(b.charAt(c)==="@"&&(a=s(/^(@[\w-]+)\s*:/)))return a[1]},shorthand:function(){var a,b;if(!t(/^[@\w.%-]+\/[@\w.-]+/))return;if((a=s(this.entity))&&s("/")&&(b=s(this.entity)))return new e.Shorthand(a,b)},mixin:{call:function(){var a=[],d,f,g,h=c,i=b.charAt(c);if(i!=="."&&i!=="#")return;while(d=s(/^[#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/))a.push(new e.Element(f,d,c)),f=s(">");s("(")&&(g=s(this.entities.arguments))&&s(")");if(a.length>0&&(s(";")||t("}")))return new e.mixin.Call(a,g,h)},definition:function(){var a,d=[],f,g,h,i;if(b.charAt(c)!=="."&&b.charAt(c)!=="#"||t(/^[^{]*(;|})/))return;if(f=s(/^([#.](?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+)\s*\(/)){a=f[1];while(h=s(this.entities.variable)||s(this.entities.literal)||s(this.entities.keyword)){if(h instanceof e.Variable)if(s(":"))if(i=s(this.expression))d.push({name:h.name,value:i});else throw new Error("Expected value");else d.push({name:h.name});else d.push({value:h});if(!s(","))break}if(!s(")"))throw new Error("Expected )");g=s(this.block);if(g)return new e.mixin.Definition(a,d,g)}}},entity:function(){return s(this.entities.literal)||s(this.entities.variable)||s(this.entities.url)||s(this.entities.call)||s(this.entities.keyword)||s(this.entities.javascript)||s(this.comment)},end:function(){return s(";")||t("}")},alpha:function(){var a;if(!s(/^\(opacity=/i))return;if(a=s(/^\d+/)||s(this.entities.variable)){if(!s(")"))throw new Error("missing closing ) for alpha()");return new e.Alpha(a)}},element:function(){var a,b,d;d=s(this.combinator),a=s(/^(?:\d+\.\d+|\d+)%/)||s(/^(?:[.#]?|:*)(?:[\w-]|\\(?:[a-fA-F0-9]{1,6} ?|[^a-fA-F0-9]))+/)||s("*")||s(this.attribute)||s(/^\([^)@]+\)/);if(a)return new e.Element(d,a,c);if(d.value&&d.value.charAt(0)==="&")return new e.Element(d,null,c)},combinator:function(){var a,d=b.charAt(c);if(d===">"||d==="+"||d==="~"){c++;while(b.charAt(c)===" ")c++;return new e.Combinator(d)}if(d==="&"){a="&",c++,b.charAt(c)===" "&&(a="& ");while(b.charAt(c)===" ")c++;return new e.Combinator(a)}if(d===":"&&b.charAt(c+1)===":"){c+=2;while(b.charAt(c)===" ")c++;return new e.Combinator("::")}return b.charAt(c-1)===" "?new e.Combinator(" "):new e.Combinator(null)},selector:function(){var a,d,f=[],g,h;while(d=s(this.element)){g=b.charAt(c),f.push(d);if(g==="{"||g==="}"||g===";"||g===",")break}if(f.length>0)return new e.Selector(f)},tag:function(){return s(/^[a-zA-Z][a-zA-Z-]*[0-9]?/)||s("*")},attribute:function(){var a="",b,c,d;if(!s("["))return;if(b=s(/^[a-zA-Z-]+/)||s(this.entities.quoted))(d=s(/^[|~*$^]?=/))&&(c=s(this.entities.quoted)||s(/^[\w-]+/))?a=[b,d,c.toCSS?c.toCSS():c].join(""):a=b;if(!s("]"))return;if(a)return"["+a+"]"},block:function(){var a;if(s("{")&&(a=s(this.primary))&&s("}"))return a},ruleset:function(){var a=[],b,d,f;p();while(b=s(this.selector)){a.push(b),s(this.comment);if(!s(","))break;s(this.comment)}if(a.length>0&&(d=s(this.block)))return new e.Ruleset(a,d);i=c,q()},rule:function(){var a,d,g=b.charAt(c),k,l;p();if(g==="."||g==="#"||g==="&")return;if(a=s(this.variable)||s(this.property)){a.charAt(0)!="@"&&(l=/^([^@+\/'"*`(;{}-]*);/.exec(j[f]))?(c+=l[0].length-1,d=new e.Anonymous(l[1])):a==="font"?d=s(this.font):d=s(this.value),k=s(this.important);if(d&&s(this.end))return new e.Rule(a,d,k,h);i=c,q()}},"import":function(){var a;if(s(/^@import\s+/)&&(a=s(this.entities.quoted)||s(this.entities.url))&&s(";"))return new e.Import(a,o)},directive:function(){var a,d,f,g;if(b.charAt(c)!=="@")return;if(d=s(this["import"]))return d;if(a=s(/^@media|@page/)||s(/^@(?:-webkit-|-moz-)?keyframes/)){g=(s(/^[^{]+/)||"").trim();if(f=s(this.block))return new e.Directive(a+" "+g,f)}else if(a=s(/^@[-a-z]+/))if(a==="@font-face"){if(f=s(this.block))return new e.Directive(a,f)}else if((d=s(this.entity))&&s(";"))return new e.Directive(a,d)},font:function(){var a=[],b=[],c,d,f,g;while(g=s(this.shorthand)||s(this.entity))b.push(g);a.push(new e.Expression(b));if(s(","))while(g=s(this.expression)){a.push(g);if(!s(","))break}return new e.Value(a)},value:function(){var a,b=[],c;while(a=s(this.expression)){b.push(a);if(!s(","))break}if(b.length>0)return new e.Value(b)},important:function(){if(b.charAt(c)==="!")return s(/^! *important/)},sub:function(){var a;if(s("(")&&(a=s(this.expression))&&s(")"))return a},multiplication:function(){var a,b,c,d;if(a=s(this.operand)){while((c=s("/")||s("*"))&&(b=s(this.operand)))d=new e.Operation(c,[d||a,b]);return d||a}},addition:function(){var a,d,f,g;if(a=s(this.multiplication)){while((f=s(/^[-+]\s+/)||b.charAt(c-1)!=" "&&(s("+")||s("-")))&&(d=s(this.multiplication)))g=new e.Operation(f,[g||a,d]);return g||a}},operand:function(){var a,d=b.charAt(c+1);b.charAt(c)==="-"&&(d==="@"||d==="(")&&(a=s("-"));var f=s(this.sub)||s(this.entities.dimension)||s(this.entities.color)||s(this.entities.variable)||s(this.entities.call);return a?new e.Operation("*",[new e.Dimension(-1),f]):f},expression:function(){var a,b,c=[],d;while(a=s(this.addition)||s(this.entity))c.push(a);if(c.length>0)return new e.Expression(c)},property:function(){var a;if(a=s(/^(\*?-?[-a-z_0-9]+)\s*:/))return a[1]}}}};if(d.mode==="browser"||d.mode==="rhino")d.Parser.importer=function(a,b,c,d){a.charAt(0)!=="/"&&b.length>0&&(a=b[0]+a),n({href:a,title:a,type:d.mime},c,!0)};(function(a){function b(b){return a.functions.hsla(b.h,b.s,b.l,b.a)}function c(b){if(b instanceof a.Dimension)return parseFloat(b.unit=="%"?b.value/100:b.value);if(typeof b=="number")return b;throw{error:"RuntimeError",message:"color functions take numbers as parameters"}}function d(a){return Math.min(1,Math.max(0,a))}a.functions={rgb:function(a,b,c){return this.rgba(a,b,c,1)},rgba:function(b,d,e,f){var g=[b,d,e].map(function(a){return c(a)}),f=c(f);return new a.Color(g,f)},hsl:function(a,b,c){return this.hsla(a,b,c,1)},hsla:function(a,b,d,e){function h(a){return a=a<0?a+1:a>1?a-1:a,a*6<1?g+(f-g)*a*6:a*2<1?f:a*3<2?g+(f-g)*(2/3-a)*6:g}a=c(a)%360/360,b=c(b),d=c(d),e=c(e);var f=d<=.5?d*(b+1):d+b-d*b,g=d*2-f;return this.rgba(h(a+1/3)*255,h(a)*255,h(a-1/3)*255,e)},hue:function(b){return new a.Dimension(Math.round(b.toHSL().h))},saturation:function(b){return new a.Dimension(Math.round(b.toHSL().s*100),"%")},lightness:function(b){return new a.Dimension(Math.round(b.toHSL().l*100),"%")},alpha:function(b){return new a.Dimension(b.toHSL().a)},saturate:function(a,c){var e=a.toHSL();return e.s+=c.value/100,e.s=d(e.s),b(e)},desaturate:function(a,c){var e=a.toHSL();return e.s-=c.value/100,e.s=d(e.s),b(e)},lighten:function(a,c){var e=a.toHSL();return e.l+=c.value/100,e.l=d(e.l),b(e)},darken:function(a,c){var e=a.toHSL();return e.l-=c.value/100,e.l=d(e.l),b(e)},fadein:function(a,c){var e=a.toHSL();return e.a+=c.value/100,e.a=d(e.a),b(e)},fadeout:function(a,c){var e=a.toHSL();return e.a-=c.value/100,e.a=d(e.a),b(e)},fade:function(a,c){var e=a.toHSL();return e.a=c.value/100,e.a=d(e.a),b(e)},spin:function(a,c){var d=a.toHSL(),e=(d.h+c.value)%360;return d.h=e<0?360+e:e,b(d)},mix:function(b,c,d){var e=d.value/100,f=e*2-1,g=b.toHSL().a-c.toHSL().a,h=((f*g==-1?f:(f+g)/(1+f*g))+1)/2,i=1-h,j=[b.rgb[0]*h+c.rgb[0]*i,b.rgb[1]*h+c.rgb[1]*i,b.rgb[2]*h+c.rgb[2]*i],k=b.alpha*e+c.alpha*(1-e);return new a.Color(j,k)},greyscale:function(b){return this.desaturate(b,new a.Dimension(100))},e:function(b){return new a.Anonymous(b instanceof a.JavaScript?b.evaluated:b)},escape:function(b){return new a.Anonymous(encodeURI(b.value).replace(/=/g,"%3D").replace(/:/g,"%3A").replace(/#/g,"%23").replace(/;/g,"%3B").replace(/\(/g,"%28").replace(/\)/g,"%29"))},"%":function(b){var c=Array.prototype.slice.call(arguments,1),d=b.value;for(var e=0;e<c.length;e++)d=d.replace(/%[sda]/i,function(a){var b=a.match(/s/i)?c[e].value:c[e].toCSS();return a.match(/[A-Z]$/)?encodeURIComponent(b):b});return d=d.replace(/%%/g,"%"),new a.Quoted('"'+d+'"',d)},round:function(b){if(b instanceof a.Dimension)return new a.Dimension(Math.round(c(b)),b.unit);if(typeof b=="number")return Math.round(b);throw{error:"RuntimeError",message:"math functions take numbers as parameters"}},argb:function(b){return new a.Anonymous(b.toARGB())}}})(c("./tree")),function(a){a.Alpha=function(a){this.value=a},a.Alpha.prototype={toCSS:function(){return"alpha(opacity="+(this.value.toCSS?this.value.toCSS():this.value)+")"},eval:function(a){return this.value.eval&&(this.value=this.value.eval(a)),this}}}(c("../tree")),function(a){a.Anonymous=function(a){this.value=a.value||a},a.Anonymous.prototype={toCSS:function(){return this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Call=function(a,b,c){this.name=a,this.args=b,this.index=c},a.Call.prototype={eval:function(b){var c=this.args.map(function(a){return a.eval(b)});if(!(this.name in a.functions))return new a.Anonymous(this.name+"("+c.map(function(a){return a.toCSS()}).join(", ")+")");try{return a.functions[this.name].apply(a.functions,c)}catch(d){throw{message:"error evaluating function `"+this.name+"`",index:this.index}}},toCSS:function(a){return this.eval(a).toCSS()}}}(c("../tree")),function(a){a.Color=function(a,b){Array.isArray(a)?this.rgb=a:a.length==6?this.rgb=a.match(/.{2}/g).map(function(a){return parseInt(a,16)}):this.rgb=a.split("").map(function(a){return parseInt(a+a,16)}),this.alpha=typeof b=="number"?b:1},a.Color.prototype={eval:function(){return this},toCSS:function(){return this.alpha<1?"rgba("+this.rgb.map(function(a){return Math.round(a)}).concat(this.alpha).join(", ")+")":"#"+this.rgb.map(function(a){return a=Math.round(a),a=(a>255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")},operate:function(b,c){var d=[];c instanceof a.Color||(c=c.toColor());for(var e=0;e<3;e++)d[e]=a.operate(b,this.rgb[e],c.rgb[e]);return new a.Color(d,this.alpha+c.alpha)},toHSL:function(){var a=this.rgb[0]/255,b=this.rgb[1]/255,c=this.rgb[2]/255,d=this.alpha,e=Math.max(a,b,c),f=Math.min(a,b,c),g,h,i=(e+f)/2,j=e-f;if(e===f)g=h=0;else{h=i>.5?j/(2-e-f):j/(e+f);switch(e){case a:g=(b-c)/j+(b<c?6:0);break;case b:g=(c-a)/j+2;break;case c:g=(a-b)/j+4}g/=6}return{h:g*360,s:h,l:i,a:d}},toARGB:function(){var a=[Math.round(this.alpha*255)].concat(this.rgb);return"#"+a.map(function(a){return a=Math.round(a),a=(a>255?255:a<0?0:a).toString(16),a.length===1?"0"+a:a}).join("")}}}(c("../tree")),function(a){a.Comment=function(a,b){this.value=a,this.silent=!!b},a.Comment.prototype={toCSS:function(a){return a.compress?"":this.value},eval:function(){return this}}}(c("../tree")),function(a){a.Dimension=function(a,b){this.value=parseFloat(a),this.unit=b||null},a.Dimension.prototype={eval:function(){return this},toColor:function(){return new a.Color([this.value,this.value,this.value])},toCSS:function(){var a=this.value+this.unit;return a},operate:function(b,c){return new a.Dimension(a.operate(b,this.value,c.value),this.unit||c.unit)}}}(c("../tree")),function(a){a.Directive=function(b,c){this.name=b,Array.isArray(c)?this.ruleset=new a.Ruleset([],c):this.value=c},a.Directive.prototype={toCSS:function(a,b){return this.ruleset?(this.ruleset.root=!0,this.name+(b.compress?"{":" {\n ")+this.ruleset.toCSS(a,b).trim().replace(/\n/g,"\n ")+(b.compress?"}":"\n}\n")):this.name+" "+this.value.toCSS()+";\n"},eval:function(a){return a.frames.unshift(this),this.ruleset=this.ruleset&&this.ruleset.eval(a),a.frames.shift(),this},variable:function(b){return a.Ruleset.prototype.variable.call(this.ruleset,b)},find:function(){return a.Ruleset.prototype.find.apply(this.ruleset,arguments)},rulesets:function(){return a.Ruleset.prototype.rulesets.apply(this.ruleset)}}}(c("../tree")),function(a){a.Element=function(b,c,d){this.combinator=b instanceof a.Combinator?b:new a.Combinator(b),this.value=c?c.trim():"",this.index=d},a.Element.prototype.toCSS=function(a){return this.combinator.toCSS(a||{})+this.value},a.Combinator=function(a){a===" "?this.value=" ":a==="& "?this.value="& ":this.value=a?a.trim():""},a.Combinator.prototype.toCSS=function(a){return{"":""," ":" ","&":"","& ":" ",":":" :","::":"::","+":a.compress?"+":" + ","~":a.compress?"~":" ~ ",">":a.compress?">":" > "}[this.value]}}(c("../tree")),function(a){a.Expression=function(a){this.value=a},a.Expression.prototype={eval:function(b){return this.value.length>1?new a.Expression(this.value.map(function(a){return a.eval(b)})):this.value.length===1?this.value[0].eval(b):this},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(" ")}}}(c("../tree")),function(a){a.Import=function(b,c){var d=this;this._path=b,b instanceof a.Quoted?this.path=/\.(le?|c)ss(\?.*)?$/.test(b.value)?b.value:b.value+".less":this.path=b.value.value||b.value,this.css=/css(\?.*)?$/.test(this.path),this.css||c.push(this.path,function(a){if(!a)throw new Error("Error parsing "+d.path);d.root=a})},a.Import.prototype={toCSS:function(){return this.css?"@import "+this._path.toCSS()+";\n":""},eval:function(b){var c;if(this.css)return this;c=new a.Ruleset(null,this.root.rules.slice(0));for(var d=0;d<c.rules.length;d++)c.rules[d]instanceof a.Import&&Array.prototype.splice.apply(c.rules,[d,1].concat(c.rules[d].eval(b)));return c.rules}}}(c("../tree")),function(a){a.JavaScript=function(a,b,c){this.escaped=c,this.expression=a,this.index=b},a.JavaScript.prototype={eval:function(b){var c,d=this,e={},f=this.expression.replace(/@\{([\w-]+)\}/g,function(c,e){return a.jsify((new a.Variable("@"+e,d.index)).eval(b))});try{f=new Function("return ("+f+")")}catch(g){throw{message:"JavaScript evaluation error: `"+f+"`",index:this.index}}for(var h in b.frames[0].variables())e[h.slice(1)]={value:b.frames[0].variables()[h].value,toJS:function(){return this.value.eval(b).toCSS()}};try{c=f.call(e)}catch(g){throw{message:"JavaScript evaluation error: '"+g.name+": "+g.message+"'",index:this.index}}return typeof c=="string"?new a.Quoted('"'+c+'"',c,this.escaped,this.index):Array.isArray(c)?new a.Anonymous(c.join(", ")):new a.Anonymous(c)}}}(c("../tree")),function(a){a.Keyword=function(a){this.value=a},a.Keyword.prototype={eval:function(){return this},toCSS:function(){return this.value}}}(c("../tree")),function(a){a.mixin={},a.mixin.Call=function(b,c,d){this.selector=new a.Selector(b),this.arguments=c,this.index=d},a.mixin.Call.prototype={eval:function(a){var b,c,d=[],e=!1;for(var f=0;f<a.frames.length;f++)if((b=a.frames[f].find(this.selector)).length>0){c=this.arguments&&this.arguments.map(function(b){return b.eval(a)});for(var g=0;g<b.length;g++)if(b[g].match(c,a))try{Array.prototype.push.apply(d,b[g].eval(a,this.arguments).rules),e=!0}catch(h){throw{message:h.message,index:h.index,stack:h.stack,call:this.index}}if(e)return d;throw{message:"No matching definition was found for `"+this.selector.toCSS().trim()+"("+this.arguments.map(function(a){return a.toCSS()}).join(", ")+")`",index:this.index}}throw{message:this.selector.toCSS().trim()+" is undefined",index:this.index}}},a.mixin.Definition=function(b,c,d){this.name=b,this.selectors=[new a.Selector([new a.Element(null,b)])],this.params=c,this.arity=c.length,this.rules=d,this._lookups={},this.required=c.reduce(function(a,b){return!b.name||b.name&&!b.value?a+1:a},0),this.parent=a.Ruleset.prototype,this.frames=[]},a.mixin.Definition.prototype={toCSS:function(){return""},variable:function(a){return this.parent.variable.call(this,a)},variables:function(){return this.parent.variables.call(this)},find:function(){return this.parent.find.apply(this,arguments)},rulesets:function(){return this.parent.rulesets.apply(this)},eval:function(b,c){var d=new a.Ruleset(null,[]),e,f=[];for(var g=0,h;g<this.params.length;g++)if(this.params[g].name)if(h=c&&c[g]||this.params[g].value)d.rules.unshift(new a.Rule(this.params[g].name,h.eval(b)));else throw{message:"wrong number of arguments for "+this.name+" ("+c.length+" for "+this.arity+")"};for(var g=0;g<Math.max(this.params.length,c&&c.length);g++)f.push(c[g]||this.params[g].value);return d.rules.unshift(new a.Rule("@arguments",(new a.Expression(f)).eval(b))),(new a.Ruleset(null,this.rules.slice(0))).eval({frames:[this,d].concat(this.frames,b.frames)})},match:function(a,b){var c=a&&a.length||0,d;if(c<this.required)return!1;if(this.required>0&&c>this.params.length)return!1;d=Math.min(c,this.arity);for(var e=0;e<d;e++)if(!this.params[e].name&&a[e].eval(b).toCSS()!=this.params[e].value.eval(b).toCSS())return!1;return!0}}}(c("../tree")),function(a){a.Operation=function(a,b){this.op=a.trim(),this.operands=b},a.Operation.prototype.eval=function(b){var c=this.operands[0].eval(b),d=this.operands[1].eval(b),e;if(c instanceof a.Dimension&&d instanceof a.Color)if(this.op==="*"||this.op==="+")e=d,d=c,c=e;else throw{name:"OperationError",message:"Can't substract or divide a color from a number"};return c.operate(this.op,d)},a.operate=function(a,b,c){switch(a){case"+":return b+c;case"-":return b-c;case"*":return b*c;case"/":return b/c}}}(c("../tree")),function(a){a.Quoted=function(a,b,c,d){this.escaped=c,this.value=b||"",this.quote=a.charAt(0),this.index=d},a.Quoted.prototype={toCSS:function(){return this.escaped?this.value:this.quote+this.value+this.quote},eval:function(b){var c=this,d=this.value.replace(/`([^`]+)`/g,function(d,e){return(new a.JavaScript(e,c.index,!0)).eval(b).value}).replace(/@\{([\w-]+)\}/g,function(d,e){var f=(new a.Variable("@"+e,c.index)).eval(b);return f.value||f.toCSS()});return new a.Quoted(this.quote+d+this.quote,d,this.escaped,this.index)}}}(c("../tree")),function(a){a.Rule=function(b,c,d,e){this.name=b,this.value=c instanceof a.Value?c:new a.Value([c]),this.important=d?" "+d.trim():"",this.index=e,b.charAt(0)==="@"?this.variable=!0:this.variable=!1},a.Rule.prototype.toCSS=function(a){return this.variable?"":this.name+(a.compress?":":": ")+this.value.toCSS(a)+this.important+";"},a.Rule.prototype.eval=function(b){return new a.Rule(this.name,this.value.eval(b),this.important,this.index)},a.Shorthand=function(a,b){this.a=a,this.b=b},a.Shorthand.prototype={toCSS:function(a){return this.a.toCSS(a)+"/"+this.b.toCSS(a)},eval:function(){return this}}}(c("../tree")),function(a){a.Ruleset=function(a,b){this.selectors=a,this.rules=b,this._lookups={}},a.Ruleset.prototype={eval:function(b){var c=new a.Ruleset(this.selectors,this.rules.slice(0));c.root=this.root,b.frames.unshift(c);if(c.root)for(var d=0;d<c.rules.length;d++)c.rules[d]instanceof a.Import&&Array.prototype.splice.apply(c.rules,[d,1].concat(c.rules[d].eval(b)));for(var d=0;d<c.rules.length;d++)c.rules[d]instanceof a.mixin.Definition&&(c.rules[d].frames=b.frames.slice(0));for(var d=0;d<c.rules.length;d++)c.rules[d]instanceof a.mixin.Call&&Array.prototype.splice.apply(c.rules,[d,1].concat(c.rules[d].eval(b)));for(var d=0,e;d<c.rules.length;d++)e=c.rules[d],e instanceof a.mixin.Definition||(c.rules[d]=e.eval?e.eval(b):e);return b.frames.shift(),c},match:function(a){return!a||a.length===0},variables:function(){return this._variables?this._variables:this._variables=this.rules.reduce(function(b,c){return c instanceof a.Rule&&c.variable===!0&&(b[c.name]=c),b},{})},variable:function(a){return this.variables()[a]},rulesets:function(){return this._rulesets?this._rulesets:this._rulesets=this.rules.filter(function(b){return b instanceof a.Ruleset||b instanceof a.mixin.Definition})},find:function(b,c){c=c||this;var d=[],e,f,g=b.toCSS();return g in this._lookups?this._lookups[g]:(this.rulesets().forEach(function(e){if(e!==c)for(var g=0;g<e.selectors.length;g++)if(f=b.match(e.selectors[g])){b.elements.length>e.selectors[g].elements.length?Array.prototype.push.apply(d,e.find(new a.Selector(b.elements.slice(1)),c)):d.push(e);break}}),this._lookups[g]=d)},toCSS:function(b,c){var d=[],e=[],f=[],g=[],h,i;this.root||(b.length===0?g=this.selectors.map(function(a){return[a]}):this.joinSelectors(g,b,this.selectors));for(var j=0;j<this.rules.length;j++)i=this.rules[j],i.rules||i instanceof a.Directive?f.push(i.toCSS(g,c)):i instanceof a.Comment?i.silent||(this.root?f.push(i.toCSS(c)):e.push(i.toCSS(c))):i.toCSS&&!i.variable?e.push(i.toCSS(c)):i.value&&!i.variable&&e.push(i.value.toString());return f=f.join(""),this.root?d.push(e.join(c.compress?"":"\n")):e.length>0&&(h=g.map(function(a){return a.map(function(a){return a.toCSS(c)}).join("").trim()}).join(c.compress?",":g.length>3?",\n":", "),d.push(h,(c.compress?"{":" {\n ")+e.join(c.compress?"":"\n ")+(c.compress?"}":"\n}\n"))),d.push(f),d.join("")+(c.compress?"\n":"")},joinSelectors:function(a,b,c){for(var d=0;d<c.length;d++)this.joinSelector(a,b,c[d])},joinSelector:function(b,c,d){var e=[],f=[],g=[],h=[],i=!1,j;for(var k=0;k<d.elements.length;k++)j=d.elements[k],j.combinator.value.charAt(0)==="&"&&(i=!0),i?h.push(j):g.push(j);i||(h=g,g=[]),g.length>0&&e.push(new a.Selector(g)),h.length>0&&f.push(new a.Selector(h));for(var l=0;l<c.length;l++)b.push(e.concat(c[l]).concat(f))}}}(c("../tree")),function(a){a.Selector=function(a){this.elements=a,this.elements[0].combinator.value===""&&(this.elements[0].combinator.value=" ")},a.Selector.prototype.match=function(a){var b=this.elements.length,c=a.elements.length,d=Math.min(b,c);if(b<c)return!1;for(var e=0;e<d;e++)if(this.elements[e].value!==a.elements[e].value)return!1
+;return!0},a.Selector.prototype.toCSS=function(a){return this._css?this._css:this._css=this.elements.map(function(b){return typeof b=="string"?" "+b.trim():b.toCSS(a)}).join("")}}(c("../tree")),function(b){b.URL=function(b,c){b.data?this.attrs=b:(!/^(?:https?:\/\/|file:\/\/|data:)?/.test(b.value)&&c.length>0&&typeof a!="undefined"&&(b.value=c[0]+(b.value.charAt(0)==="/"?b.value.slice(1):b.value)),this.value=b,this.paths=c)},b.URL.prototype={toCSS:function(){return"url("+(this.attrs?"data:"+this.attrs.mime+this.attrs.charset+this.attrs.base64+this.attrs.data:this.value.toCSS())+")"},eval:function(a){return this.attrs?this:new b.URL(this.value.eval(a),this.paths)}}}(c("../tree")),function(a){a.Value=function(a){this.value=a,this.is="value"},a.Value.prototype={eval:function(b){return this.value.length===1?this.value[0].eval(b):new a.Value(this.value.map(function(a){return a.eval(b)}))},toCSS:function(a){return this.value.map(function(b){return b.toCSS(a)}).join(a.compress?",":", ")}}}(c("../tree")),function(a){a.Variable=function(a,b){this.name=a,this.index=b},a.Variable.prototype={eval:function(b){var c,d,e=this.name;e.indexOf("@@")==0&&(e="@"+(new a.Variable(e.slice(1))).eval(b).value);if(c=a.find(b.frames,function(a){if(d=a.variable(e))return d.value.eval(b)}))return c;throw{message:"variable "+e+" is undefined",index:this.index}}}}(c("../tree")),c("./tree").find=function(a,b){for(var c=0,d;c<a.length;c++)if(d=b.call(a,a[c]))return d;return null},c("./tree").jsify=function(a){return Array.isArray(a.value)&&a.value.length>1?"["+a.value.map(function(a){return a.toCSS(!1)}).join(", ")+"]":a.toCSS(!1)};var f=location.protocol==="file:"||location.protocol==="chrome:"||location.protocol==="chrome-extension:"||location.protocol==="resource:";d.env=d.env||(location.hostname=="127.0.0.1"||location.hostname=="0.0.0.0"||location.hostname=="localhost"||location.port.length>0||f?"development":"production"),d.async=!1,d.poll=d.poll||(f?1e3:1500),d.watch=function(){return this.watchMode=!0},d.unwatch=function(){return this.watchMode=!1},d.env==="development"?(d.optimization=0,/!watch/.test(location.hash)&&d.watch(),d.watchTimer=setInterval(function(){d.watchMode&&m(function(a,b,c){a&&p(a.toCSS(),b,c.lastModified)})},d.poll)):d.optimization=3;var g;try{g=typeof a.localStorage=="undefined"?null:a.localStorage}catch(h){g=null}var i=document.getElementsByTagName("link"),j=/^text\/(x-)?less$/;d.sheets=[];for(var k=0;k<i.length;k++)(i[k].rel==="stylesheet/less"||i[k].rel.match(/stylesheet/)&&i[k].type.match(j))&&d.sheets.push(i[k]);d.refresh=function(a){var b,c;b=c=new Date,m(function(a,d,e){e.local?t("loading "+d.href+" from cache."):(t("parsed "+d.href+" successfully."),p(a.toCSS(),d,e.lastModified)),t("css for "+d.href+" generated in "+(new Date-c)+"ms"),e.remaining===0&&t("css generated in "+(new Date-b)+"ms"),c=new Date},a),l()},d.refreshStyles=l,d.refresh(d.env==="development")})(window);
55 src/lib/pusher-php/pusher_notification_helper.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * provides a very simple way to send basic Create, Read, Update and Delete (CRUD) event notifications on a 'notify' channel.
+ * All events are triggered on a 'notify' channel by default with the event names of 'created', 'read', 'updated' and
+ * 'deleted'.
+ */
+class PusherNotificationHelper
+{
+ private $pusher = null;
+
+ public $channel_name = null;
+
+ /**
+ * Initializes a new PusherNotificationHelper instance.
+ *
+ * @param Pusher $pusher
+ * @param string $channel_name [optional] defaults to 'notify'
+ */
+ public function __construct( $pusher, $channel_name = null )
+ {
+ $this->pusher = $pusher;
+
+ if( is_null($channel_name) ) {
+ $this->channel_name = 'notify';
+ }
+ }
+
+ public function create_notification($message, $data = array(), $exclude_socket_id = null) {
+ $this->send_notification('created', $message, $data, $exclude_socket_id);
+ }
+
+ public function read_notification($message, $data = array(), $exclude_socket_id = null) {
+ $this->send_notification('read', $message, $data, $exclude_socket_id);
+ }
+
+ public function update_notification($message, $data = array(), $exclude_socket_id = null) {
+ $this->send_notification('updated', $message, $data, $exclude_socket_id);
+ }
+
+ public function delete_notification($message, $data = array(), $exclude_socket_id = null) {
+ $this->send_notification('deleted', $message, $data, $exclude_socket_id);
+ }
+
+ public function announce_notification($message, $data = array(), $exclude_socket_id = null) {
+ $this->send_notification('announce', $message, $data, $exclude_socket_id);
+ }
+
+ private function send_notification($event, $message, $data, $exclude_socket_id) {
+ $data[ 'message' ] = $message;
+ $this->pusher->trigger($this->channel_name, $event, $data, $exclude_socket_id);
+ }
+}
+
+?>
102 src/lib/pusher-php/squeeks-Pusher-PHP/README.md
@@ -0,0 +1,102 @@
+Pusher PHP Library
+==================
+
+This is a very simple PHP library to the Pusher API (http://pusherapp.com).
+Using it is easy as pie:
+
+ require('Pusher.php');
+
+ $pusher = new Pusher($key, $secret, $app_id);
+ $pusher->trigger('my-channel', 'my_event', 'hello world');
+
+
+If you prefer to use the Singleton pattern usage is similiar, but like this:
+
+ require('Pusher.php');
+ $pusher = PusherInstance::get_pusher();
+
+ $pusher->trigger('my-channel', 'my_event', 'hello world');
+
+Note: You need to set your API information in Pusher.php
+
+Arrays
+------
+Objects are automatically converted to JSON format:
+
+ $array['name'] = 'joe';
+ $array['message_count'] = 23;
+
+ $pusher->trigger('my_channel', 'my_event', $array);
+
+The output of this will be:
+
+ "{'name': 'joe', 'message_count': 23}"
+
+Socket id
+---------
+In order to avoid duplicates you can optionally specify the sender's socket id while triggering an event (http://pusherapp.com/docs/duplicates):
+
+ $pusher->trigger('my-channel','event','data','socket_id');
+
+Debugging
+---------
+You can either turn on debugging by setting the fifth argument to true, like so:
+
+ $pusher->trigger('my-channel', 'event', 'data', null, true)
+
+or with all requests:
+
+ $pusher = new Pusher($key, $secret, $app_id, true);
+
+On failed requests, this will return the server's response, instead of false.
+
+JSON format
+-----------
+
+If your data is already encoded in JSON format, you can avoid a second encoding step by setting the sixth argument true, like so:
+
+ $pusher->trigger('my-channel', 'event', 'data', null, false, true)
+
+Private channels
+----------------
+To authorise your users to access private channels on Pusher, you can use the socket_auth function:
+
+ $pusher->socket_auth('my-channel','socket_id');
+
+Presence channels
+-----------------
+Using presence channels is similar to private channels, but you can specify extra data to identify that particular user:
+
+ $pusher->presence_auth('my-channel','socket_id', 'user_id', 'user_info');
+
+Presence example
+----------------
+
+First set this variable in your JS app:
+
+ Pusher.auth_url = '/presence_auth.php';
+
+Next, create the following in presence_auth.php:
+
+ <?php
+ header('Content-Type: application/json');
+ if ($_SESSION['user_id']){
+ $sql = "SELECT * FROM `users` WHERE id='$_SESSION[user_id]'";
+ $result = mysql_query($sql,$mysql);
+ $user = mysql_fetch_assoc($result);
+ } else {
+ die('aaargh, no-one is logged in')
+ }
+
+ $pusher = new Pusher($key, $secret, $app_id);
+ $presence_data = array('name' => $user['name']);
+ echo $pusher->presence_auth($_POST['channel_name'], $_POST['socket_id'], $user['id'], $presence_data);
+ ?>
+
+Note: this assumes that you store your users in a table called `users` and that those users have a `name` column. It also assumes that you have a login mechanism that stores the `user_id` of the logged in user in the session.
+
+
+License
+-------
+Copyright 2010, Squeeks. Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
223 src/lib/pusher-php/squeeks-Pusher-PHP/lib/Pusher.php
@@ -0,0 +1,223 @@
+<?php
+
+/*
+ Pusher PHP Library
+ /////////////////////////////////
+ This was a very simple PHP library to the Pusher API.
+
+ $pusher = new Pusher(APIKEY, SECRET, APP_ID, CHANNEL, [Debug: true/false, HOST, PORT]);
+ $pusher->trigger('my_event', 'test_channel', [socket_id, Debug: true/false]);
+ $pusher->socket_auth('socket_id');
+
+ Copyright 2011, Squeeks. Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
+
+ Contributors:
+ + Paul44 (http://github.com/Paul44)
+ + Ben Pickles (http://github.com/benpickles)
+ + Mastercoding (http://www.mastercoding.nl)
+ + Alias14 (mali0037@gmail.com)
+ + Max Williams (max@pusher.com)
+ + Zack Kitzmiller (delicious@zackisamazing.com)
+ + Andrew Bender (igothelp@gmail.com)
+*/
+
+class PusherInstance {
+
+ private static $instance = null;
+ private static $app_id = '';
+ private static $secret = '';
+ private static $api_key = '';
+
+ private function __construct() { }
+ private function __clone() { }
+
+ public static function get_pusher()
+ {
+ if (self::$instance !== null) return self::$instance;
+
+ self::$instance = new Pusher(
+ self::$api_key,
+ self::$secret,
+ self::$app_id
+ );
+
+ return self::$instance;
+ }
+}
+
+class Pusher
+{
+
+ private $settings = array ();
+
+ /**
+ * PHP5 Constructor.
+ *
+ * Initializes a new Pusher instance with key, secret , app ID and channel.
+ * You can optionally turn on debugging for all requests by setting debug to true.
+ *
+ * @param string $auth_key
+ * @param string $secret
+ * @param int $app_id
+ * @param bool $debug [optional]
+ * @param string $host [optional]
+ * @param int $port [optional]
+ * @param int $timeout [optional]
+ */
+ public function __construct( $auth_key, $secret, $app_id, $debug = false, $host = 'http://api.pusherapp.com', $port = '80', $timeout = 30 )
+ {
+
+ // Check compatibility, disable for speed improvement
+ $this->check_compatibility();
+
+ // Setup defaults
+ $this->settings['server'] = $host;
+ $this->settings['port'] = $port;
+ $this->settings['auth_key'] = $auth_key;
+ $this->settings['secret'] = $secret;
+ $this->settings['app_id'] = $app_id;
+ $this->settings['url'] = '/apps/' . $this->settings['app_id'];
+ $this->settings['debug'] = $debug;
+ $this->settings['timeout'] = $timeout;
+
+ }
+
+ /**
+ * Check if the current PHP setup is sufficient to run this class
+ */
+ private function check_compatibility()
+ {
+
+ // Check for dependent PHP extensions (JSON, cURL)
+ if ( ! extension_loaded( 'curl' ) || ! extension_loaded( 'json' ) )
+ {
+ die( 'There is missing dependant extensions - please ensure both cURL and JSON modules are installed' );
+ }
+
+ # Supports SHA256?
+ if ( ! in_array( 'sha256', hash_algos() ) )
+ {
+ die( 'SHA256 appears to be unsupported - make sure you have support for it, or upgrade your version of PHP.' );
+ }
+
+ }
+
+ /**
+ * Trigger an event by providing event name and payload.
+ * Optionally provide a socket ID to exclude a client (most likely the sender).
+ *
+ * @param string $event
+ * @param mixed $payload
+ * @param int $socket_id [optional]
+ * @param string $channel [optional]
+ * @param bool $debug [optional]
+ * @return bool|string
+ */
+ public function trigger( $channel, $event, $payload, $socket_id = null, $debug = false, $already_encoded = false )
+ {
+
+ # Check if we can initialize a cURL connection
+ $ch = curl_init();
+ if ( $ch === false )
+ {
+ die( 'Could not initialise cURL!' );
+ }
+
+ # Add channel to URL..
+ $s_url = $this->settings['url'] . '/channels/' . $channel . '/events';
+
+ # Build the request
+ $signature = "POST\n" . $s_url . "\n";
+ $payload_encoded = $already_encoded ? $payload : json_encode( $payload );
+ $query = "auth_key=" . $this->settings['auth_key'] . "&auth_timestamp=" . time() . "&auth_version=1.0&body_md5=" . md5( $payload_encoded ) . "&name=" . $event;
+
+ # Socket ID set?
+ if ( $socket_id !== null )
+ {
+ $query .= "&socket_id=" . $socket_id;
+ }
+
+ # Create the signed signature...
+ $auth_signature = hash_hmac( 'sha256', $signature . $query, $this->settings['secret'], false );
+ $signed_query = $query . "&auth_signature=" . $auth_signature;
+ $full_url = $this->settings['server'] . ':' . $this->settings['port'] . $s_url . '?' . $signed_query;
+
+ # Set cURL opts and execute request
+ curl_setopt( $ch, CURLOPT_URL, $full_url );
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, array ( "Content-Type: application/json" ) );
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
+ curl_setopt( $ch, CURLOPT_POST, 1 );
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload_encoded );
+ curl_setopt( $ch, CURLOPT_TIMEOUT, $this->settings['timeout'] );
+
+ $response = curl_exec( $ch );
+
+ curl_close( $ch );
+
+ if ( $response == "202 ACCEPTED\n" && $debug == false )
+ {
+ return true;
+ }
+ elseif ( $debug == true || $this->settings['debug'] == true )
+ {
+ return $response;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+
+ /**
+ * Creates a socket signature
+ *
+ * @param int $socket_id
+ * @param string $custom_data
+ * @return string
+ */
+ public function socket_auth( $channel, $socket_id, $custom_data = false )
+ {
+
+ if($custom_data == true)
+ {
+ $signature = hash_hmac( 'sha256', $socket_id . ':' . $channel . ':' . $custom_data, $this->settings['secret'], false );
+ }
+ else
+ {
+ $signature = hash_hmac( 'sha256', $socket_id . ':' . $channel, $this->settings['secret'], false );
+ }
+
+ $signature = array ( 'auth' => $this->settings['auth_key'] . ':' . $signature );
+ // add the custom data if it has been supplied
+ if($custom_data){
+ $signature['channel_data'] = $custom_data;
+ }
+ return json_encode( $signature );
+
+ }
+
+ /**
+ * Creates a presence signature (an extension of socket signing)
+ *
+ * @param int $socket_id
+ * @param string $user_id
+ * @param mixed $user_info
+ * @return string
+ */
+ public function presence_auth( $channel, $socket_id, $user_id, $user_info = false )
+ {
+
+ $user_data = array( 'user_id' => $user_id );
+ if($user_info == true)
+ {
+ $user_data['user_info'] = $user_info;
+ }
+
+ return $this->socket_auth($channel, $socket_id, json_encode($user_data) );
+ }
+
+
+}
+
+?>
44 src/lib/pusher-php/squeeks-Pusher-PHP/test/push.php
@@ -0,0 +1,44 @@
+<?php
+
+ define('PUSHERAPP_AUTHKEY', getenv('PUSHERAPP_AUTHKEY'));
+ define('PUSHERAPP_SECRET' , getenv('PUSHERAPP_SECRET'));
+ define('PUSHERAPP_APPID' , getenv('PUSHERAPP_APPID'));
+
+ require_once('../lib/Pusher.php');
+
+ class PusherPushTest extends PHPUnit_Framework_TestCase
+ {
+
+ protected function setUp()
+ {
+ if(PUSHERAPP_AUTHKEY == '' || PUSHERAPP_SECRET == '' || PUSHERAPP_APPID == '' )
+ {
+ $this->markTestSkipped('Please set the
+ PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET and
+ PUSHERAPP_APPID keys.');
+ }
+ else
+ {
+ $this->pusher = new Pusher(PUSHERAPP_AUTHKEY, PUSHERAPP_SECRET, PUSHERAPP_APPID, true);
+ }
+ }
+
+ public function testObjectConstruct()
+ {
+ $this->assertNotNull($this->pusher, 'Created new Pusher object');
+ }
+
+ public function testStringPush()
+ {
+ $string_trigger = $this->pusher->trigger('test_channel', 'my_event', 'Test string');
+ $this->assertTrue($string_trigger, 'Trigger with string payload');
+ }
+
+ public function testArrayPush()
+ {
+ $structure_trigger = $this->pusher->trigger('test_channel', 'my_event', array( test => 1 ));
+ $this->assertTrue($structure_trigger, 'Trigger with structured payload');
+ }
+ }
+
+?>
28 src/lib/pusher-php/squeeks-Pusher-PHP/test/socket_auth.php
@@ -0,0 +1,28 @@
+<?php
+
+ require_once('../lib/Pusher.php');
+
+ class PusherPushTest extends PHPUnit_Framework_TestCase
+ {
+
+ protected function setUp()
+ {
+ $this->pusher = new Pusher('thisisaauthkey', 'thisisasecret', 1, true);
+ }
+
+ public function testObjectConstruct()
+ {
+ $this->assertNotNull($this->pusher, 'Created new Pusher object');
+ }
+
+ public function testSocketAuthKey()
+ {
+ $socket_auth = $this->pusher->socket_auth('testing_pusher-php', 'testing_socket_auth');
+ $this->assertEquals($socket_auth,
+ '{"auth":"thisisaauthkey:ee548cf60217ed18281da39a8eb23609105f1bde29372650cb67bd91c284aae1"}',
+ 'Socket auth key valid');
+ }
+
+ }
+
+?>
4 src/lib/twitter-bootstrap/.gitignore
@@ -0,0 +1,4 @@
+*~
+.DS_Store
+thumbs.db
+js/min
176 src/lib/twitter-bootstrap/LICENSE
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
47 src/lib/twitter-bootstrap/Makefile
@@ -0,0 +1,47 @@
+VERSION=1.4.0
+DATE=$(shell DATE)
+BOOTSTRAP = ./bootstrap.css
+BOOTSTRAP_MIN = ./bootstrap.min.css
+BOOTSTRAP_LESS = ./lib/bootstrap.less
+LESS_COMPRESSOR ?= `which lessc`
+UGLIFY_JS ?= `which uglifyjs`
+WATCHR ?= `which watchr`
+
+build:
+ @@if test ! -z ${LESS_COMPRESSOR}; then \
+ sed -e 's/@VERSION/'"v${VERSION}"'/' -e 's/@DATE/'"${DATE}"'/' <${BOOTSTRAP_LESS} >${BOOTSTRAP_LESS}.tmp; \
+ lessc ${BOOTSTRAP_LESS}.tmp > ${BOOTSTRAP}; \
+ lessc ${BOOTSTRAP_LESS}.tmp > ${BOOTSTRAP_MIN} --compress; \
+ rm -f ${BOOTSTRAP_LESS}.tmp; \
+ echo "Bootstrap successfully built! - `date`"; \
+ else \
+ echo "You must have the LESS compiler installed in order to build Bootstrap."; \
+ echo "You can install it by running: npm install less -g"; \
+ fi
+
+js/min:
+ @@if test ! -z ${UGLIFY_JS}; then \
+ mkdir -p js/min; \
+ uglifyjs -o js/min/bootstrap-alerts.min.js js/bootstrap-alerts.js;\
+ uglifyjs -o js/min/bootstrap-buttons.min.js js/bootstrap-buttons.js;\
+ uglifyjs -o js/min/bootstrap-dropdown.min.js js/bootstrap-dropdown.js;\
+ uglifyjs -o js/min/bootstrap-modal.min.js js/bootstrap-modal.js;\
+ uglifyjs -o js/min/bootstrap-popover.min.js js/bootstrap-popover.js;\
+ uglifyjs -o js/min/bootstrap-scrollspy.min.js js/bootstrap-scrollspy.js;\
+ uglifyjs -o js/min/bootstrap-tabs.min.js js/bootstrap-tabs.js;\
+ uglifyjs -o js/min/bootstrap-twipsy.min.js js/bootstrap-twipsy.js;\
+ else \
+ echo "You must have the UGLIFYJS minifier installed in order to minify Bootstrap's js."; \
+ echo "You can install it by running: npm install uglify-js -g"; \
+ fi
+
+watch:
+ @@if test ! -z ${WATCHR}; then \
+ echo "Watching less files..."; \
+ watchr -e "watch('lib/.*\.less') { system 'make' }"; \
+ else \
+ echo "You must have the watchr installed in order to watch Bootstrap less files."; \
+ echo "You can install it by running: gem install watchr"; \
+ fi
+
+.PHONY: build watch
105 src/lib/twitter-bootstrap/README.md
@@ -0,0 +1,105 @@
+TWITTER BOOTSTRAP
+=================
+
+Bootstrap is Twitter's toolkit for kickstarting CSS for websites, apps, and more. It includes base CSS styles for typography, forms, buttons, tables, grids, navigation, alerts, and more.
+
+To get started -- checkout http://twitter.github.com/bootstrap!
+
+
+Usage
+-----
+
+You can use Twitter Bootstrap in one of two ways: just drop the compiled CSS into any new project and start cranking, or run LESS on your site and compile on the fly like a boss.
+
+Here's what the LESS version looks like:
+
+``` html
+<link rel="stylesheet/less" type="text/css" href="lib/bootstrap.less">
+<script src="less.js" type="text/javascript"></script>
+```
+
+Or if you prefer, the standard css way:
+
+``` html
+<link rel="stylesheet" type="text/css" href="bootstrap.css">
+```
+
+For more info, refer to the docs!
+
+
+Versioning
+----------
+
+For transparency and insight into our release cycle, and for striving to maintain backwards compatibility, Bootstrap will be maintained under the Semantic Versioning guidelines as much as possible.
+
+Releases will be numbered with the follow format:
+
+`<major>.<minor>.<patch>`
+
+And constructed with the following guidelines:
+
+* Breaking backwards compatibility bumps the major
+* New additions without breaking backwards compatibility bumps the minor
+* Bug fixes and misc changes bump the patch
+
+For more information on SemVer, please visit http://semver.org/.
+
+
+Bug tracker
+-----------
+
+Have a bug? Please create an issue here on GitHub!
+
+https://github.com/twitter/bootstrap/issues
+
+
+Twitter account
+---------------
+
+Keep up to date on announcements and more by following Bootstrap on Twitter, <a href="http://twitter.com/TwBootstrap">@TwBootstrap</a>.
+
+
+Mailing list
+------------
+
+Have a question? Ask on our mailing list!
+
+twitter-bootstrap@googlegroups.com
+
+http://groups.google.com/group/twitter-bootstrap
+
+
+Developers
+----------
+
+We have included a makefile with convenience methods for working with the bootstrap library.
+
++ **build** - `make build`
+This will run the less compiler on the bootstrap lib and generate a bootstrap.css and bootstrap.min.css file.
+The lessc compiler is required for this command to run.
+
++ **watch** - `make watch`
+This is a convenience method for watching your less files and automatically building them whenever you save.
+Watchr is required for this command to run.
+
+
+Authors
+-------
+
+**Mark Otto**
+
++ http://twitter.com/mdo
++ http://github.com/markdotto
+
+**Jacob Thornton**
+
++ http://twitter.com/fat
++ http://github.com/fat
+
+
+License
+---------------------
+
+Copyright 2011 Twitter, Inc.
+
+Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0
2,467 src/lib/twitter-bootstrap/bootstrap.css
@@ -0,0 +1,2467 @@
+/*!
+ * Bootstrap v1.4.0
+ *
+ * Copyright 2011 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ * Date: Sun Nov 20 21:42:29 PST 2011
+ */
+/* Reset.less
+ * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc).
+ * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
+html, body {
+ margin: 0;
+ padding: 0;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+dd,
+dl,
+dt,
+li,
+ol,
+ul,
+fieldset,
+form,
+label,
+legend,
+button,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-weight: normal;
+ font-style: normal;
+ font-size: 100%;
+ line-height: 1;
+ font-family: inherit;
+}
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+ol, ul {
+ list-style: none;
+}
+q:before,
+q:after,
+blockquote:before,
+blockquote:after {
+ content: "";
+}
+html {
+ overflow-y: scroll;
+ font-size: 100%;
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+}
+a:focus {
+ outline: thin dotted;
+}
+a:hover, a:active {
+ outline: 0;
+}
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+nav,
+section {
+ display: block;
+}
+audio, canvas, video {
+ display: inline-block;
+ *display: inline;
+ *zoom: 1;
+}
+audio:not([controls]) {
+ display: none;
+}
+sub, sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+sup {
+ top: -0.5em;
+}
+sub {
+ bottom: -0.25em;
+}
+img {
+ border: 0;
+ -ms-interpolation-mode: bicubic;
+}
+button,
+input,
+select,
+textarea {
+ font-size: 100%;
+ margin: 0;
+ vertical-align: baseline;
+ *vertical-align: middle;
+}
+button, input {
+ line-height: normal;
+ *overflow: visible;
+}
+button::-moz-focus-inner, input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+button,
+input[type="button"],
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer;
+ -webkit-appearance: button;
+}
+input[type="search"] {
+ -webkit-appearance: textfield;
+ -webkit-box-sizing: content-box;
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+}
+input[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+textarea {
+ overflow: auto;
+ vertical-align: top;
+}
+/* Variables.less
+ * Variables to customize the look and feel of Bootstrap
+ * ----------------------------------------------------- */
+/* Mixins.less
+ * Snippets of reusable CSS to develop faster and keep code readable
+ * ----------------------------------------------------------------- */
+/*
+ * Scaffolding
+ * Basic and global styles for generating a grid system, structural layout, and page templates
+ * ------------------------------------------------------------------------------------------- */
+body {
+ background-color: #ffffff;
+ margin: 0;
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 18px;
+ color: #404040;
+}
+.container {
+ width: 940px;
+ margin-left: auto;
+ margin-right: auto;
+ zoom: 1;
+}
+.container:before, .container:after {
+ display: table;
+ content: "";
+ zoom: 1;
+}
+.container:after {
+ clear: both;
+}
+.container-fluid {
+ position: relative;
+ min-width: 940px;
+ padding-left: 20px;
+ padding-right: 20px;
+ zoom: 1;
+}
+.container-fluid:before, .container-fluid:after {
+ display: table;
+ content: "";
+ zoom: 1;
+}
+.container-fluid:after {
+ clear: both;
+}
+.container-fluid > .sidebar {
+ position: absolute;
+ top: 0;
+ left: 20px;
+ width: 220px;
+}
+.container-fluid > .content {
+ margin-left: 240px;
+}
+a {
+ color: #0069d6;
+ text-decoration: none;
+ line-height: inherit;
+ font-weight: inherit;
+}
+a:hover {
+ color: #00438a;
+ text-decoration: underline;
+}
+.pull-right {
+ float: right;
+}
+.pull-left {
+ float: left;
+}
+.hide {
+ display: none;
+}
+.show {
+ display: block;
+}
+.row {
+ zoom: 1;
+ margin-left: -20px;
+}
+.row:before, .row:after {
+ display: table;
+ content: "";
+ zoom: 1;
+}
+.row:after {
+ clear: both;
+}
+.row > [class*="span"] {
+ display: inline;
+ float: left;
+ margin-left: 20px;
+}
+.span1 {
+ width: 40px;
+}
+.span2 {
+ width: 100px;
+}
+.span3 {
+ width: 160px;
+}
+.span4 {
+ width: 220px;
+}
+.span5 {
+ width: 280px;
+}
+.span6 {
+ width: 340px;
+}
+.span7 {
+ width: 400px;
+}
+.span8 {
+ width: 460px;
+}
+.span9 {
+ width: 520px;
+}
+.span10 {
+ width: 580px;
+}
+.span11 {
+ width: 640px;
+}
+.span12 {
+ width: 700px;
+}
+.span13 {
+ width: 760px;
+}
+.span14 {
+ width: 820px;
+}
+.span15 {
+ width: 880px;
+}
+.span16 {
+ width: 940px;
+}
+.span17 {
+ width: 1000px;
+}
+.span18 {
+ width: 1060px;
+}
+.span19 {
+ width: 1120px;
+}
+.span20 {
+ width: 1180px;
+}
+.span21 {
+ width: 1240px;
+}
+.span22 {
+ width: 1300px;
+}
+.span23 {
+ width: 1360px;
+}
+.span24 {
+ width: 1420px;
+}
+.row > .offset1 {
+ margin-left: 80px;
+}
+.row > .offset2 {
+ margin-left: 140px;
+}
+.row > .offset3 {
+ margin-left: 200px;
+}
+.row > .offset4 {
+ margin-left: 260px;
+}
+.row > .offset5 {
+ margin-left: 320px;
+}
+.row > .offset6 {
+ margin-left: 380px;
+}
+.row > .offset7 {
+ margin-left: 440px;
+}
+.row > .offset8 {
+ margin-left: 500px;
+}
+.row > .offset9 {
+ margin-left: 560px;
+}
+.row > .offset10 {
+ margin-left: 620px;
+}
+.row > .offset11 {
+ margin-left: 680px;
+}
+.row > .offset12 {
+ margin-left: 740px;
+}
+.span-one-third {
+ width: 300px;
+}
+.span-two-thirds {
+ width: 620px;
+}
+.row > .offset-one-third {
+ margin-left: 340px;
+}
+.row > .offset-two-thirds {
+ margin-left: 660px;
+}
+/* Typography.less
+ * Headings, body text, lists, code, and more for a versatile and durable typography system
+ * ---------------------------------------------------------------------------------------- */
+p {
+ font-size: 13px;
+ font-weight: normal;
+ line-height: 18px;
+ margin-bottom: 9px;
+}
+p small {
+ font-size: 11px;
+ color: #bfbfbf;
+}
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-weight: bold;
+ color: #404040;
+}
+h1 small,
+h2 small,
+h3 small,
+h4 small,
+h5 small,
+h6 small {
+ color: #bfbfbf;
+}
+h1 {
+ margin-bottom: 18px;
+ font-size: 30px;
+ line-height: 36px;
+}
+h1 small {
+ font-size: 18px;
+}
+h2 {
+ font-size: 24px;
+ line-height: 36px;
+}
+h2 small {
+ font-size: 14px;
+}
+h3,
+h4,
+h5,
+h6 {
+ line-height: 36px;
+}
+h3 {
+ font-size: 18px;
+}
+h3 small {
+ font-size: 14px;
+}
+h4 {
+ font-size: 16px;
+}
+h4 small {
+ font-size: 12px;
+}
+h5 {
+ font-size: 14px;
+}
+h6 {
+ font-size: 13px;
+ color: #bfbfbf;
+ text-transform: uppercase;
+}
+ul, ol {
+ margin: 0 0 18px 25px;
+}
+ul ul,
+ul ol,
+ol ol,
+ol ul {
+ margin-bottom: 0;
+}
+ul {
+ list-style: disc;
+}
+ol {
+ list-style: decimal;
+}
+li {
+ line-height: 18px;
+ color: #808080;
+}
+ul.unstyled {
+ list-style: none;
+ margin-left: 0;
+}
+dl {
+ margin-bottom: 18px;
+}
+dl dt, dl dd {
+ line-height: 18px;
+}
+dl dt {
+ font-weight: bold;
+}
+dl dd {
+ margin-left: 9px;
+}
+hr {
+ margin: 20px 0 19px;
+ border: 0;
+ border-bottom: 1px solid #eee;
+}
+strong {
+ font-style: inherit;
+ font-weight: bold;
+}
+em {
+ font-style: italic;
+ font-weight: inherit;
+ line-height: inherit;
+}
+.muted {
+ color: #bfbfbf;
+}
+blockquote {
+ margin-bottom: 18px;
+ border-left: 5px solid #eee;
+ padding-left: 15px;
+}
+blockquote p {
+ font-size: 14px;
+ font-weight: 300;
+ line-height: 18px;
+ margin-bottom: 0;
+}
+blockquote small {
+ display: block;
+ font-size: 12px;
+ font-weight: 300;
+ line-height: 18px;
+ color: #bfbfbf;
+}
+blockquote small:before {
+ content: '\2014 \00A0';
+}
+address {
+ display: block;
+ line-height: 18px;
+ margin-bottom: 18px;
+}
+code, pre {
+ padding: 0 3px 2px;
+ font-family: Monaco, Andale Mono, Courier New, monospace;
+ font-size: 12px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+