ringleader 0.0.2 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. data/README.md +61 -22
  2. data/assets/app.js +106 -0
  3. data/assets/backbone-min.js +38 -0
  4. data/assets/bootstrap/css/bootstrap-responsive.css +815 -0
  5. data/assets/bootstrap/css/bootstrap-responsive.min.css +9 -0
  6. data/assets/bootstrap/css/bootstrap.css +4983 -0
  7. data/assets/bootstrap/css/bootstrap.min.css +9 -0
  8. data/assets/bootstrap/img/glyphicons-halflings-white.png +0 -0
  9. data/assets/bootstrap/img/glyphicons-halflings.png +0 -0
  10. data/assets/bootstrap/js/bootstrap.js +1825 -0
  11. data/assets/bootstrap/js/bootstrap.min.js +6 -0
  12. data/assets/favicon.ico +0 -0
  13. data/assets/index.html +129 -0
  14. data/assets/jquery-1.7.2.min.js +4 -0
  15. data/assets/jquery.mustache.js +636 -0
  16. data/assets/top_hat.png +0 -0
  17. data/assets/underscore-min.js +32 -0
  18. data/dev_scripts/Procfile +3 -2
  19. data/dev_scripts/stubborn.rb +4 -0
  20. data/dev_scripts/test.yml +4 -2
  21. data/dev_scripts/wait_fork_tree.rb +15 -0
  22. data/dev_scripts/wait_test.rb +25 -0
  23. data/dev_scripts/webserver.rb +4 -0
  24. data/lib/ringleader.rb +7 -1
  25. data/lib/ringleader/app.rb +88 -121
  26. data/lib/ringleader/app_serializer.rb +15 -0
  27. data/lib/ringleader/cli.rb +43 -56
  28. data/lib/ringleader/config.rb +58 -15
  29. data/lib/ringleader/controller.rb +30 -0
  30. data/lib/ringleader/process.rb +145 -0
  31. data/lib/ringleader/server.rb +116 -0
  32. data/lib/ringleader/version.rb +1 -1
  33. data/lib/ringleader/wait_for_exit.rb +1 -1
  34. data/ringleader.gemspec +1 -0
  35. data/screenshot.png +0 -0
  36. data/spec/fixtures/config.yml +1 -1
  37. data/spec/fixtures/no_app_port.yml +5 -0
  38. data/spec/fixtures/no_server_port.yml +6 -0
  39. data/spec/fixtures/rvm.yml +6 -0
  40. data/spec/ringleader/config_spec.rb +25 -2
  41. metadata +48 -3
  42. data/lib/ringleader/app_proxy.rb +0 -61
data/README.md CHANGED
@@ -16,10 +16,26 @@ Ringleader is an application proxy for socket applications.
16
16
  ## What's it for?
17
17
 
18
18
  I designed this for a large suite of apps running behind nginx with a somewhat
19
- complex routing configuration in nginx. Additionally, many of the apps required
20
- active [resque](https://github.com/defunkt/resque/) pollers to run properly.
21
- Ultimately this meant having many terminal windows open just to make a few
22
- requests to the apps. Instead, I wanted something to manage all that for me:
19
+ complex routing configuration. Additionally, many of the apps required active
20
+ [resque](https://github.com/defunkt/resque/) pollers to run properly. Ultimately
21
+ this meant having many terminal windows open just to make a few requests to the
22
+ apps. Instead, I wanted something to manage all that for me.
23
+
24
+ Before, each app in a terminal, started manually:
25
+
26
+ +-------+
27
+ +->| app 1 |
28
+ | +-------+
29
+ +-----------+ |
30
+ http | | | +-------+
31
+ requests ---> | nginx +--+->| app 2 |
32
+ | | | +-------+
33
+ +-----------+ |
34
+ | +-------+
35
+ +->| app n |
36
+ +-------+
37
+
38
+ After, apps managed by ringleader, started on demand:
23
39
 
24
40
  +-------+
25
41
  +->| app 1 |
@@ -33,10 +49,21 @@ requests to the apps. Instead, I wanted something to manage all that for me:
33
49
  +->| app n |
34
50
  +-------+
35
51
 
36
- Ringleader is essentially a generalized replacement for [pow](http://pow.cx/),
37
- and allows on-demand startup and proxying for any TCP server programs. It can
38
- start a foreman or ruby or any other process which opens a socket. For example,
39
- I started resque pollers alongside applications using foreman.
52
+ Ringleader gives on-demand startup and proxying for any TCP server program. It
53
+ can be a rails app managed with foreman, a node app, or simply a shell command
54
+ to start netcat.
55
+
56
+ ## Isn't this just like inetd?
57
+
58
+ Pretty much. But with pretty colors in console and a nice web interface.
59
+
60
+ ## Web interface?
61
+
62
+ Yep. Hook it up with [fluid](http://fluidapp.com) and put it in the menu bar. By
63
+ default it runs at [http://localhost:42000](http://localhost:42000).
64
+
65
+
66
+ ![screenshot of ringleader control panel](/aniero/ringleader/raw/master/screenshot.png)
40
67
 
41
68
  ## Installation
42
69
 
@@ -52,24 +79,36 @@ like this:
52
79
  ---
53
80
  # name of app (used in logging)
54
81
  main_app:
55
- # working directory, where to start the app from
56
- dir: "~/apps/main"
57
- # the command to run to start up the app server. Executed under "bash -c".
58
- command: "foreman start"
59
- # the host to listen on, defaults to 127.0.0.1
60
- hostname: 0.0.0.0
61
- # the port ringleader listens on
62
- server_port: 3000
63
- # the port the application listens on
64
- app_port: 4000
65
- # idle timeout in seconds
66
- idle_timeout: 6000
67
- # application startup timeout
68
- startup_timeout: 180
82
+
83
+ # Required settings
84
+ dir: "~/apps/main" # Working directory
85
+ command: "foreman start" # The command to run to start up the app server.
86
+ # Executed under "bash -c".
87
+ server_port: 3000 # The port ringleader listens on
88
+ app_port: 4000 # The port the application listens on
89
+
90
+ # Optional settings
91
+ host: 127.0.0.1 # The host ringleader should listen on
92
+ idle_timeout: 6000 # Idle timeout in seconds
93
+ startup_timeout: 180 # Application startup timeout
94
+ disabled: true # Set the app to be disabled when ringleader starts
95
+
96
+ # If you have an application managed by rvm, this setting automatically adds
97
+ # the rvm-specific shell setup before executing the given command. This
98
+ # supersedes the `command` setting.
99
+ rvm: "foreman start"
100
+
69
101
  other_app:
70
102
  [...]
71
103
  ```
72
104
 
105
+ ## License
106
+
107
+ MIT, see `LICENSE`.
108
+
109
+ Top hat icon by [Luka Taylor](http://lukataylo.deviantart.com/gallery/#/d2g95fp)
110
+ under a Creative Commons Attribution/Non-commercial license.
111
+
73
112
  ## Contributing
74
113
 
75
114
  1. Fork it
@@ -0,0 +1,106 @@
1
+ var App = Backbone.Model.extend({
2
+ idAttribute: 'name',
3
+
4
+ initialize: function() {
5
+ var model = this;
6
+ // unfortunately, there's not a nice way of updating apps collectively
7
+ // without replacing the entire collection each time.
8
+ this.refresh = setInterval(function() { model.fetch(); }, 5000);
9
+ },
10
+
11
+ url: function(extra) {
12
+ if(extra) {
13
+ return '/apps/' + this.get('name') + '/' + extra;
14
+ }
15
+ else {
16
+ return '/apps/' + this.get('name');
17
+ }
18
+ },
19
+
20
+ // for mustache, these must be exclusive
21
+ name: function() { return this.get('name'); },
22
+ 'disabled?': function() { return !this.get('enabled'); },
23
+ 'stopped?': function() { return this.get('enabled') && !this.get('running'); },
24
+ 'running?': function() { return this.get('enabled') && this.get('running'); },
25
+
26
+ // actions
27
+ enable: function() { this.request('enable'); },
28
+ disable: function() { this.request('disable'); },
29
+ stop: function() { this.request('stop'); },
30
+ start: function() { this.request('start'); },
31
+ restart: function() { this.request('restart'); },
32
+
33
+ request: function(action) {
34
+ var model = this;
35
+ this.set({waiting: true});
36
+ console.log(action, this.get('name'), this.url(action));
37
+ $.post(
38
+ this.url(action),
39
+ function(data) { model.set(_.extend({}, data, {waiting: false})); },
40
+ 'json');
41
+ }
42
+ });
43
+
44
+ var Apps = Backbone.Collection.extend({
45
+ url: '/apps',
46
+ model: App
47
+ });
48
+
49
+ var AppControl = Backbone.View.extend({
50
+ className: 'app',
51
+ initialize: function() {
52
+ this.template = $('#app-template');
53
+ this.model.bind('change', this.render, this);
54
+ },
55
+ events: {
56
+ 'click .start' : 'start',
57
+ 'click .stop' : 'stop',
58
+ 'click .restart' : 'restart',
59
+ 'click .enable' : 'enable',
60
+ 'click .disable' : 'disable'
61
+ },
62
+ render: function() {
63
+ $(this.el).html(this.template.mustache(this.model));
64
+ if(this.model.get('waiting')) {
65
+ this.$('.buttons').hide();
66
+ this.$('.loading').show();
67
+ }
68
+ else {
69
+ this.$('.buttons').show();
70
+ this.$('.loading').hide();
71
+ }
72
+ return this;
73
+ },
74
+ start: function() { this.model.start(); return false; },
75
+ stop: function() { this.model.stop(); return false; },
76
+ restart: function() { this.model.restart(); return false; },
77
+ enable: function() { this.model.enable(); return false; },
78
+ disable: function() { this.model.disable(); return false; }
79
+ });
80
+
81
+ var ControlPanel = Backbone.View.extend({
82
+ el: $('#apps'),
83
+ initialize: function(options) {
84
+ this.collection = new Apps();
85
+ this.collection.bind('add', this.addApp, this);
86
+ this.collection.bind('reset', this.addAll, this);
87
+ this.collection.fetch();
88
+
89
+ var self = this;
90
+ },
91
+
92
+ addApp: function(app) {
93
+ var view = new AppControl({model: app});
94
+ this.$el.append(view.render().el);
95
+ },
96
+
97
+ addAll: function(apps) {
98
+ this.$el.html('');
99
+ apps.each(this.addApp, this);
100
+ }
101
+
102
+ });
103
+
104
+ $(function() {
105
+ window.control_panel = new ControlPanel();
106
+ });
@@ -0,0 +1,38 @@
1
+ // Backbone.js 0.9.2
2
+
3
+ // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
4
+ // Backbone may be freely distributed under the MIT license.
5
+ // For all details and documentation:
6
+ // http://backbonejs.org
7
+ (function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks=
8
+ {});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g=
9
+ z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent=
10
+ {};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null==
11
+ b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent:
12
+ b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};
13
+ a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error,
14
+ h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();
15
+ return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending=
16
+ {};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||
17
+ !this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator);
18
+ this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;i=e.id;j[g]||this._byCid[g]||null!=i&&(k[i]||this._byId[i])?
19
+ l.push(c):j[g]=k[i]=e}for(c=l.length;c--;)a.splice(l[c],1);c=0;for(d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=e.id&&(this._byId[e.id]=e);this.length+=d;A.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;c=0;for(d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?
20
+ a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a},
21
+ shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?
22
+ this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,
23
+ e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId=
24
+ {};this._byCid={}},_prepareModel:function(a,b){b||(b={});a instanceof o?a.collection||(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,
25
+ arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/:\w+/g,
26
+ C=/\*\w+/g,D=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,k,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,
27
+ this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(D,"\\$&").replace(B,"([^/]+)").replace(C,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,E=/msie [\w.]+/;m.started=!1;f.extend(m.prototype,k,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]:
28
+ ""},getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");m.started=!0;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=
29
+ !(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=E.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,
30
+ this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},
31
+ stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,
32
+ function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||
33
+ this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");
34
+ f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();
35
+ for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,
36
+ !1);else{var a=n(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=G(this,a,b);c.extend=this.extend;return c};var H={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=H[a];c||(c={});var e={type:d,dataType:"json"};c.url||(e.url=n(b,"url")||t());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",
37
+ e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},G=function(a,
38
+ b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');}}).call(this);
@@ -0,0 +1,815 @@
1
+ /*!
2
+ * Bootstrap Responsive v2.0.4
3
+ *
4
+ * Copyright 2012 Twitter, Inc
5
+ * Licensed under the Apache License v2.0
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
9
+ */
10
+
11
+ .clearfix {
12
+ *zoom: 1;
13
+ }
14
+
15
+ .clearfix:before,
16
+ .clearfix:after {
17
+ display: table;
18
+ content: "";
19
+ }
20
+
21
+ .clearfix:after {
22
+ clear: both;
23
+ }
24
+
25
+ .hide-text {
26
+ font: 0/0 a;
27
+ color: transparent;
28
+ text-shadow: none;
29
+ background-color: transparent;
30
+ border: 0;
31
+ }
32
+
33
+ .input-block-level {
34
+ display: block;
35
+ width: 100%;
36
+ min-height: 28px;
37
+ -webkit-box-sizing: border-box;
38
+ -moz-box-sizing: border-box;
39
+ -ms-box-sizing: border-box;
40
+ box-sizing: border-box;
41
+ }
42
+
43
+ .hidden {
44
+ display: none;
45
+ visibility: hidden;
46
+ }
47
+
48
+ .visible-phone {
49
+ display: none !important;
50
+ }
51
+
52
+ .visible-tablet {
53
+ display: none !important;
54
+ }
55
+
56
+ .hidden-desktop {
57
+ display: none !important;
58
+ }
59
+
60
+ @media (max-width: 767px) {
61
+ .visible-phone {
62
+ display: inherit !important;
63
+ }
64
+ .hidden-phone {
65
+ display: none !important;
66
+ }
67
+ .hidden-desktop {
68
+ display: inherit !important;
69
+ }
70
+ .visible-desktop {
71
+ display: none !important;
72
+ }
73
+ }
74
+
75
+ @media (min-width: 768px) and (max-width: 979px) {
76
+ .visible-tablet {
77
+ display: inherit !important;
78
+ }
79
+ .hidden-tablet {
80
+ display: none !important;
81
+ }
82
+ .hidden-desktop {
83
+ display: inherit !important;
84
+ }
85
+ .visible-desktop {
86
+ display: none !important ;
87
+ }
88
+ }
89
+
90
+ @media (max-width: 480px) {
91
+ .nav-collapse {
92
+ -webkit-transform: translate3d(0, 0, 0);
93
+ }
94
+ .page-header h1 small {
95
+ display: block;
96
+ line-height: 18px;
97
+ }
98
+ input[type="checkbox"],
99
+ input[type="radio"] {
100
+ border: 1px solid #ccc;
101
+ }
102
+ .form-horizontal .control-group > label {
103
+ float: none;
104
+ width: auto;
105
+ padding-top: 0;
106
+ text-align: left;
107
+ }
108
+ .form-horizontal .controls {
109
+ margin-left: 0;
110
+ }
111
+ .form-horizontal .control-list {
112
+ padding-top: 0;
113
+ }
114
+ .form-horizontal .form-actions {
115
+ padding-right: 10px;
116
+ padding-left: 10px;
117
+ }
118
+ .modal {
119
+ position: absolute;
120
+ top: 10px;
121
+ right: 10px;
122
+ left: 10px;
123
+ width: auto;
124
+ margin: 0;
125
+ }
126
+ .modal.fade.in {
127
+ top: auto;
128
+ }
129
+ .modal-header .close {
130
+ padding: 10px;
131
+ margin: -10px;
132
+ }
133
+ .carousel-caption {
134
+ position: static;
135
+ }
136
+ }
137
+
138
+ @media (max-width: 767px) {
139
+ body {
140
+ padding-right: 20px;
141
+ padding-left: 20px;
142
+ }
143
+ .navbar-fixed-top,
144
+ .navbar-fixed-bottom {
145
+ margin-right: -20px;
146
+ margin-left: -20px;
147
+ }
148
+ .container-fluid {
149
+ padding: 0;
150
+ }
151
+ .dl-horizontal dt {
152
+ float: none;
153
+ width: auto;
154
+ clear: none;
155
+ text-align: left;
156
+ }
157
+ .dl-horizontal dd {
158
+ margin-left: 0;
159
+ }
160
+ .container {
161
+ width: auto;
162
+ }
163
+ .row-fluid {
164
+ width: 100%;
165
+ }
166
+ .row,
167
+ .thumbnails {
168
+ margin-left: 0;
169
+ }
170
+ [class*="span"],
171
+ .row-fluid [class*="span"] {
172
+ display: block;
173
+ float: none;
174
+ width: auto;
175
+ margin-left: 0;
176
+ }
177
+ .input-large,
178
+ .input-xlarge,
179
+ .input-xxlarge,
180
+ input[class*="span"],
181
+ select[class*="span"],
182
+ textarea[class*="span"],
183
+ .uneditable-input {
184
+ display: block;
185
+ width: 100%;
186
+ min-height: 28px;
187
+ -webkit-box-sizing: border-box;
188
+ -moz-box-sizing: border-box;
189
+ -ms-box-sizing: border-box;
190
+ box-sizing: border-box;
191
+ }
192
+ .input-prepend input,
193
+ .input-append input,
194
+ .input-prepend input[class*="span"],
195
+ .input-append input[class*="span"] {
196
+ display: inline-block;
197
+ width: auto;
198
+ }
199
+ }
200
+
201
+ @media (min-width: 768px) and (max-width: 979px) {
202
+ .row {
203
+ margin-left: -20px;
204
+ *zoom: 1;
205
+ }
206
+ .row:before,
207
+ .row:after {
208
+ display: table;
209
+ content: "";
210
+ }
211
+ .row:after {
212
+ clear: both;
213
+ }
214
+ [class*="span"] {
215
+ float: left;
216
+ margin-left: 20px;
217
+ }
218
+ .container,
219
+ .navbar-fixed-top .container,
220
+ .navbar-fixed-bottom .container {
221
+ width: 724px;
222
+ }
223
+ .span12 {
224
+ width: 724px;
225
+ }
226
+ .span11 {
227
+ width: 662px;
228
+ }
229
+ .span10 {
230
+ width: 600px;
231
+ }
232
+ .span9 {
233
+ width: 538px;
234
+ }
235
+ .span8 {
236
+ width: 476px;
237
+ }
238
+ .span7 {
239
+ width: 414px;
240
+ }
241
+ .span6 {
242
+ width: 352px;
243
+ }
244
+ .span5 {
245
+ width: 290px;
246
+ }
247
+ .span4 {
248
+ width: 228px;
249
+ }
250
+ .span3 {
251
+ width: 166px;
252
+ }
253
+ .span2 {
254
+ width: 104px;
255
+ }
256
+ .span1 {
257
+ width: 42px;
258
+ }
259
+ .offset12 {
260
+ margin-left: 764px;
261
+ }
262
+ .offset11 {
263
+ margin-left: 702px;
264
+ }
265
+ .offset10 {
266
+ margin-left: 640px;
267
+ }
268
+ .offset9 {
269
+ margin-left: 578px;
270
+ }
271
+ .offset8 {
272
+ margin-left: 516px;
273
+ }
274
+ .offset7 {
275
+ margin-left: 454px;
276
+ }
277
+ .offset6 {
278
+ margin-left: 392px;
279
+ }
280
+ .offset5 {
281
+ margin-left: 330px;
282
+ }
283
+ .offset4 {
284
+ margin-left: 268px;
285
+ }
286
+ .offset3 {
287
+ margin-left: 206px;
288
+ }
289
+ .offset2 {
290
+ margin-left: 144px;
291
+ }
292
+ .offset1 {
293
+ margin-left: 82px;
294
+ }
295
+ .row-fluid {
296
+ width: 100%;
297
+ *zoom: 1;
298
+ }
299
+ .row-fluid:before,
300
+ .row-fluid:after {
301
+ display: table;
302
+ content: "";
303
+ }
304
+ .row-fluid:after {
305
+ clear: both;
306
+ }
307
+ .row-fluid [class*="span"] {
308
+ display: block;
309
+ float: left;
310
+ width: 100%;
311
+ min-height: 28px;
312
+ margin-left: 2.762430939%;
313
+ *margin-left: 2.709239449638298%;
314
+ -webkit-box-sizing: border-box;
315
+ -moz-box-sizing: border-box;
316
+ -ms-box-sizing: border-box;
317
+ box-sizing: border-box;
318
+ }
319
+ .row-fluid [class*="span"]:first-child {
320
+ margin-left: 0;
321
+ }
322
+ .row-fluid .span12 {
323
+ width: 99.999999993%;
324
+ *width: 99.9468085036383%;
325
+ }
326
+ .row-fluid .span11 {
327
+ width: 91.436464082%;
328
+ *width: 91.38327259263829%;
329
+ }
330
+ .row-fluid .span10 {
331
+ width: 82.87292817100001%;
332
+ *width: 82.8197366816383%;
333
+ }
334
+ .row-fluid .span9 {
335
+ width: 74.30939226%;
336
+ *width: 74.25620077063829%;
337
+ }
338
+ .row-fluid .span8 {
339
+ width: 65.74585634900001%;
340
+ *width: 65.6926648596383%;
341
+ }
342
+ .row-fluid .span7 {
343
+ width: 57.182320438000005%;
344
+ *width: 57.129128948638304%;
345
+ }
346
+ .row-fluid .span6 {
347
+ width: 48.618784527%;
348
+ *width: 48.5655930376383%;
349
+ }
350
+ .row-fluid .span5 {
351
+ width: 40.055248616%;
352
+ *width: 40.0020571266383%;
353
+ }
354
+ .row-fluid .span4 {
355
+ width: 31.491712705%;
356
+ *width: 31.4385212156383%;
357
+ }
358
+ .row-fluid .span3 {
359
+ width: 22.928176794%;
360
+ *width: 22.874985304638297%;
361
+ }
362
+ .row-fluid .span2 {
363
+ width: 14.364640883%;
364
+ *width: 14.311449393638298%;
365
+ }
366
+ .row-fluid .span1 {
367
+ width: 5.801104972%;
368
+ *width: 5.747913482638298%;
369
+ }
370
+ input,
371
+ textarea,
372
+ .uneditable-input {
373
+ margin-left: 0;
374
+ }
375
+ input.span12,
376
+ textarea.span12,
377
+ .uneditable-input.span12 {
378
+ width: 714px;
379
+ }
380
+ input.span11,
381
+ textarea.span11,
382
+ .uneditable-input.span11 {
383
+ width: 652px;
384
+ }
385
+ input.span10,
386
+ textarea.span10,
387
+ .uneditable-input.span10 {
388
+ width: 590px;
389
+ }
390
+ input.span9,
391
+ textarea.span9,
392
+ .uneditable-input.span9 {
393
+ width: 528px;
394
+ }
395
+ input.span8,
396
+ textarea.span8,
397
+ .uneditable-input.span8 {
398
+ width: 466px;
399
+ }
400
+ input.span7,
401
+ textarea.span7,
402
+ .uneditable-input.span7 {
403
+ width: 404px;
404
+ }
405
+ input.span6,
406
+ textarea.span6,
407
+ .uneditable-input.span6 {
408
+ width: 342px;
409
+ }
410
+ input.span5,
411
+ textarea.span5,
412
+ .uneditable-input.span5 {
413
+ width: 280px;
414
+ }
415
+ input.span4,
416
+ textarea.span4,
417
+ .uneditable-input.span4 {
418
+ width: 218px;
419
+ }
420
+ input.span3,
421
+ textarea.span3,
422
+ .uneditable-input.span3 {
423
+ width: 156px;
424
+ }
425
+ input.span2,
426
+ textarea.span2,
427
+ .uneditable-input.span2 {
428
+ width: 94px;
429
+ }
430
+ input.span1,
431
+ textarea.span1,
432
+ .uneditable-input.span1 {
433
+ width: 32px;
434
+ }
435
+ }
436
+
437
+ @media (min-width: 1200px) {
438
+ .row {
439
+ margin-left: -30px;
440
+ *zoom: 1;
441
+ }
442
+ .row:before,
443
+ .row:after {
444
+ display: table;
445
+ content: "";
446
+ }
447
+ .row:after {
448
+ clear: both;
449
+ }
450
+ [class*="span"] {
451
+ float: left;
452
+ margin-left: 30px;
453
+ }
454
+ .container,
455
+ .navbar-fixed-top .container,
456
+ .navbar-fixed-bottom .container {
457
+ width: 1170px;
458
+ }
459
+ .span12 {
460
+ width: 1170px;
461
+ }
462
+ .span11 {
463
+ width: 1070px;
464
+ }
465
+ .span10 {
466
+ width: 970px;
467
+ }
468
+ .span9 {
469
+ width: 870px;
470
+ }
471
+ .span8 {
472
+ width: 770px;
473
+ }
474
+ .span7 {
475
+ width: 670px;
476
+ }
477
+ .span6 {
478
+ width: 570px;
479
+ }
480
+ .span5 {
481
+ width: 470px;
482
+ }
483
+ .span4 {
484
+ width: 370px;
485
+ }
486
+ .span3 {
487
+ width: 270px;
488
+ }
489
+ .span2 {
490
+ width: 170px;
491
+ }
492
+ .span1 {
493
+ width: 70px;
494
+ }
495
+ .offset12 {
496
+ margin-left: 1230px;
497
+ }
498
+ .offset11 {
499
+ margin-left: 1130px;
500
+ }
501
+ .offset10 {
502
+ margin-left: 1030px;
503
+ }
504
+ .offset9 {
505
+ margin-left: 930px;
506
+ }
507
+ .offset8 {
508
+ margin-left: 830px;
509
+ }
510
+ .offset7 {
511
+ margin-left: 730px;
512
+ }
513
+ .offset6 {
514
+ margin-left: 630px;
515
+ }
516
+ .offset5 {
517
+ margin-left: 530px;
518
+ }
519
+ .offset4 {
520
+ margin-left: 430px;
521
+ }
522
+ .offset3 {
523
+ margin-left: 330px;
524
+ }
525
+ .offset2 {
526
+ margin-left: 230px;
527
+ }
528
+ .offset1 {
529
+ margin-left: 130px;
530
+ }
531
+ .row-fluid {
532
+ width: 100%;
533
+ *zoom: 1;
534
+ }
535
+ .row-fluid:before,
536
+ .row-fluid:after {
537
+ display: table;
538
+ content: "";
539
+ }
540
+ .row-fluid:after {
541
+ clear: both;
542
+ }
543
+ .row-fluid [class*="span"] {
544
+ display: block;
545
+ float: left;
546
+ width: 100%;
547
+ min-height: 28px;
548
+ margin-left: 2.564102564%;
549
+ *margin-left: 2.510911074638298%;
550
+ -webkit-box-sizing: border-box;
551
+ -moz-box-sizing: border-box;
552
+ -ms-box-sizing: border-box;
553
+ box-sizing: border-box;
554
+ }
555
+ .row-fluid [class*="span"]:first-child {
556
+ margin-left: 0;
557
+ }
558
+ .row-fluid .span12 {
559
+ width: 100%;
560
+ *width: 99.94680851063829%;
561
+ }
562
+ .row-fluid .span11 {
563
+ width: 91.45299145300001%;
564
+ *width: 91.3997999636383%;
565
+ }
566
+ .row-fluid .span10 {
567
+ width: 82.905982906%;
568
+ *width: 82.8527914166383%;
569
+ }
570
+ .row-fluid .span9 {
571
+ width: 74.358974359%;
572
+ *width: 74.30578286963829%;
573
+ }
574
+ .row-fluid .span8 {
575
+ width: 65.81196581200001%;
576
+ *width: 65.7587743226383%;
577
+ }
578
+ .row-fluid .span7 {
579
+ width: 57.264957265%;
580
+ *width: 57.2117657756383%;
581
+ }
582
+ .row-fluid .span6 {
583
+ width: 48.717948718%;
584
+ *width: 48.6647572286383%;
585
+ }
586
+ .row-fluid .span5 {
587
+ width: 40.170940171000005%;
588
+ *width: 40.117748681638304%;
589
+ }
590
+ .row-fluid .span4 {
591
+ width: 31.623931624%;
592
+ *width: 31.5707401346383%;
593
+ }
594
+ .row-fluid .span3 {
595
+ width: 23.076923077%;
596
+ *width: 23.0237315876383%;
597
+ }
598
+ .row-fluid .span2 {
599
+ width: 14.529914530000001%;
600
+ *width: 14.4767230406383%;
601
+ }
602
+ .row-fluid .span1 {
603
+ width: 5.982905983%;
604
+ *width: 5.929714493638298%;
605
+ }
606
+ input,
607
+ textarea,
608
+ .uneditable-input {
609
+ margin-left: 0;
610
+ }
611
+ input.span12,
612
+ textarea.span12,
613
+ .uneditable-input.span12 {
614
+ width: 1160px;
615
+ }
616
+ input.span11,
617
+ textarea.span11,
618
+ .uneditable-input.span11 {
619
+ width: 1060px;
620
+ }
621
+ input.span10,
622
+ textarea.span10,
623
+ .uneditable-input.span10 {
624
+ width: 960px;
625
+ }
626
+ input.span9,
627
+ textarea.span9,
628
+ .uneditable-input.span9 {
629
+ width: 860px;
630
+ }
631
+ input.span8,
632
+ textarea.span8,
633
+ .uneditable-input.span8 {
634
+ width: 760px;
635
+ }
636
+ input.span7,
637
+ textarea.span7,
638
+ .uneditable-input.span7 {
639
+ width: 660px;
640
+ }
641
+ input.span6,
642
+ textarea.span6,
643
+ .uneditable-input.span6 {
644
+ width: 560px;
645
+ }
646
+ input.span5,
647
+ textarea.span5,
648
+ .uneditable-input.span5 {
649
+ width: 460px;
650
+ }
651
+ input.span4,
652
+ textarea.span4,
653
+ .uneditable-input.span4 {
654
+ width: 360px;
655
+ }
656
+ input.span3,
657
+ textarea.span3,
658
+ .uneditable-input.span3 {
659
+ width: 260px;
660
+ }
661
+ input.span2,
662
+ textarea.span2,
663
+ .uneditable-input.span2 {
664
+ width: 160px;
665
+ }
666
+ input.span1,
667
+ textarea.span1,
668
+ .uneditable-input.span1 {
669
+ width: 60px;
670
+ }
671
+ .thumbnails {
672
+ margin-left: -30px;
673
+ }
674
+ .thumbnails > li {
675
+ margin-left: 30px;
676
+ }
677
+ .row-fluid .thumbnails {
678
+ margin-left: 0;
679
+ }
680
+ }
681
+
682
+ @media (max-width: 979px) {
683
+ body {
684
+ padding-top: 0;
685
+ }
686
+ .navbar-fixed-top,
687
+ .navbar-fixed-bottom {
688
+ position: static;
689
+ }
690
+ .navbar-fixed-top {
691
+ margin-bottom: 18px;
692
+ }
693
+ .navbar-fixed-bottom {
694
+ margin-top: 18px;
695
+ }
696
+ .navbar-fixed-top .navbar-inner,
697
+ .navbar-fixed-bottom .navbar-inner {
698
+ padding: 5px;
699
+ }
700
+ .navbar .container {
701
+ width: auto;
702
+ padding: 0;
703
+ }
704
+ .navbar .brand {
705
+ padding-right: 10px;
706
+ padding-left: 10px;
707
+ margin: 0 0 0 -5px;
708
+ }
709
+ .nav-collapse {
710
+ clear: both;
711
+ }
712
+ .nav-collapse .nav {
713
+ float: none;
714
+ margin: 0 0 9px;
715
+ }
716
+ .nav-collapse .nav > li {
717
+ float: none;
718
+ }
719
+ .nav-collapse .nav > li > a {
720
+ margin-bottom: 2px;
721
+ }
722
+ .nav-collapse .nav > .divider-vertical {
723
+ display: none;
724
+ }
725
+ .nav-collapse .nav .nav-header {
726
+ color: #999999;
727
+ text-shadow: none;
728
+ }
729
+ .nav-collapse .nav > li > a,
730
+ .nav-collapse .dropdown-menu a {
731
+ padding: 6px 15px;
732
+ font-weight: bold;
733
+ color: #999999;
734
+ -webkit-border-radius: 3px;
735
+ -moz-border-radius: 3px;
736
+ border-radius: 3px;
737
+ }
738
+ .nav-collapse .btn {
739
+ padding: 4px 10px 4px;
740
+ font-weight: normal;
741
+ -webkit-border-radius: 4px;
742
+ -moz-border-radius: 4px;
743
+ border-radius: 4px;
744
+ }
745
+ .nav-collapse .dropdown-menu li + li a {
746
+ margin-bottom: 2px;
747
+ }
748
+ .nav-collapse .nav > li > a:hover,
749
+ .nav-collapse .dropdown-menu a:hover {
750
+ background-color: #222222;
751
+ }
752
+ .nav-collapse.in .btn-group {
753
+ padding: 0;
754
+ margin-top: 5px;
755
+ }
756
+ .nav-collapse .dropdown-menu {
757
+ position: static;
758
+ top: auto;
759
+ left: auto;
760
+ display: block;
761
+ float: none;
762
+ max-width: none;
763
+ padding: 0;
764
+ margin: 0 15px;
765
+ background-color: transparent;
766
+ border: none;
767
+ -webkit-border-radius: 0;
768
+ -moz-border-radius: 0;
769
+ border-radius: 0;
770
+ -webkit-box-shadow: none;
771
+ -moz-box-shadow: none;
772
+ box-shadow: none;
773
+ }
774
+ .nav-collapse .dropdown-menu:before,
775
+ .nav-collapse .dropdown-menu:after {
776
+ display: none;
777
+ }
778
+ .nav-collapse .dropdown-menu .divider {
779
+ display: none;
780
+ }
781
+ .nav-collapse .navbar-form,
782
+ .nav-collapse .navbar-search {
783
+ float: none;
784
+ padding: 9px 15px;
785
+ margin: 9px 0;
786
+ border-top: 1px solid #222222;
787
+ border-bottom: 1px solid #222222;
788
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
789
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
790
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
791
+ }
792
+ .navbar .nav-collapse .nav.pull-right {
793
+ float: none;
794
+ margin-left: 0;
795
+ }
796
+ .nav-collapse,
797
+ .nav-collapse.collapse {
798
+ height: 0;
799
+ overflow: hidden;
800
+ }
801
+ .navbar .btn-navbar {
802
+ display: block;
803
+ }
804
+ .navbar-static .navbar-inner {
805
+ padding-right: 10px;
806
+ padding-left: 10px;
807
+ }
808
+ }
809
+
810
+ @media (min-width: 980px) {
811
+ .nav-collapse.collapse {
812
+ height: auto !important;
813
+ overflow: visible !important;
814
+ }
815
+ }