├── test ├── mocha.opts ├── unit │ └── page │ │ └── model.js ├── integration │ └── process_rest_test.js └── helpers │ └── test_server.js ├── .travis.yml ├── .npmignore ├── .gitignore ├── ui ├── index.js └── views │ └── root.jsx ├── bin └── bugger-daemon.js ├── .jshintrc ├── Makefile ├── public ├── index.html ├── bugger.min.css ├── pure.min.css └── bugger.css ├── LICENSE ├── package.json ├── lib ├── page │ ├── controller.js │ ├── url.js │ ├── model.js │ └── index.js ├── api.js ├── agents-socket-transport.js └── bugger-daemon.js └── README.md /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --recursive 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.11" 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | /build 3 | /ui 4 | .jshintrc 5 | .travis.yml 6 | Makefile 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /build 3 | npm-debug.log 4 | public/bugger.js 5 | public/vendor.js 6 | -------------------------------------------------------------------------------- /ui/index.js: -------------------------------------------------------------------------------- 1 | /* jshint browser:true */ 2 | 'use strict'; 3 | 4 | var React = require('react'); 5 | var Root = require('./views/root.jsx'); 6 | 7 | React.renderComponent( 8 | new Root(), document.getElementById('root')); 9 | -------------------------------------------------------------------------------- /bin/bugger-daemon.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 'use strict'; 3 | 4 | var createBuggerServer = require('../lib/bugger-daemon.js'); 5 | createBuggerServer().httpServer 6 | .listen(8058, '127.0.0.1', function() { 7 | var address = this.address(); 8 | console.log('bugger-daemon listening:', address); 9 | console.log('Press Ctrl+C to quit.'); 10 | }); 11 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "undef": true, 3 | "unused": true, 4 | 5 | "freeze": true, 6 | "forin": true, 7 | "eqeqeq": true, 8 | "strict": true, 9 | 10 | "newcap": true, 11 | "latedef": "nofunc", 12 | "immed": true, 13 | 14 | "camelcase": true, 15 | "maxlen": 80, 16 | "indent": 2, 17 | "trailing": true, 18 | "nonbsp": true, 19 | 20 | "node": true, 21 | "esnext": true 22 | } 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default clean build 2 | default: build 3 | 4 | build: public/vendor.js public/bugger.js 5 | 6 | clean: 7 | rm -f public/vendor.js public/bugger.js 8 | 9 | public/vendor.js: 10 | ./node_modules/.bin/browserify \ 11 | --require react \ 12 | --require lodash \ 13 | --outfile $@ 14 | 15 | BUNDLE_OPTS := \ 16 | --external react \ 17 | --external lodash \ 18 | --outfile public/bugger.js 19 | 20 | public/bugger.js: 21 | ./node_modules/.bin/browserify . $(BUNDLE_OPTS) 22 | 23 | watch: 24 | ./node_modules/.bin/watchify . $(BUNDLE_OPTS) 25 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bugger 6 | 7 | 8 | 9 | 10 | 18 |
19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/unit/page/model.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assertive'); 4 | 5 | var PageModel = require('../../../lib/page/model'); 6 | 7 | describe('page/model', function() { 8 | beforeEach(function() { 9 | this.pages = PageModel(); 10 | }); 11 | 12 | describe('fromUrlSpec', function() { 13 | describe('valid url with cwd and script', function() { 14 | var pageUrl = 'bugger:///tmp/my-module:example/ok.js'; 15 | 16 | beforeEach(function() { 17 | this.page = this.pages.fromUrlSpec(pageUrl); 18 | }); 19 | 20 | it('assigns an id', function() { 21 | assert.hasType(String, this.page.id); 22 | }); 23 | 24 | it('parses cwd', function() { 25 | assert.equal('/tmp/my-module', this.page.cwd); 26 | }); 27 | 28 | it('parses script', function() { 29 | assert.equal('example/ok.js', this.page.script); 30 | }); 31 | 32 | it('can re-generate the url', function() { 33 | assert.equal(pageUrl, this.page.url); 34 | }); 35 | }); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Jan Krems 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bugger-daemon", 3 | "version": "0.0.1", 4 | "description": "buggerd sources", 5 | "main": "lib/bugger-daemon.js", 6 | "browser": "ui/index.js", 7 | "scripts": { 8 | "test": "make test", 9 | "start": "node bin/bugger-daemon.js", 10 | "prepublish": "make clean build" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/buggerjs/bugger-daemon.git" 15 | }, 16 | "keywords": [ 17 | "bugger", 18 | "devtools", 19 | "debugger", 20 | "chrome" 21 | ], 22 | "author": "Jan Krems ", 23 | "license": "MIT", 24 | "devDependencies": { 25 | "assertive": "^1.4.0", 26 | "browserify": "^5.12.1", 27 | "mocha": "~1.12.0", 28 | "react": "^0.11.2", 29 | "reactify": "^0.14.0", 30 | "watchify": "^1.0.6" 31 | }, 32 | "dependencies": { 33 | "bluebird": "^2.3.4", 34 | "concat-stream": "~1.0.0", 35 | "debug": "^2.0.0", 36 | "lodash": "^2.4.1", 37 | "node-uuid": "^1.4.1", 38 | "quinn": "^2.3.0", 39 | "quinn-respond": "^2.0.1", 40 | "send": "^0.9.3", 41 | "websocket": "~1.0.8" 42 | }, 43 | "browserify": { 44 | "transform": [ 45 | [ 46 | "reactify", 47 | { 48 | "es6": true 49 | } 50 | ] 51 | ] 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/page/controller.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var respond = require('quinn-respond'); 23 | 24 | function PageController(pages) { 25 | this.pages = pages; 26 | } 27 | 28 | PageController.prototype.index = function(req) { 29 | return respond.json(this.pages.all()); 30 | }; 31 | 32 | PageController.prototype.create = function(req, params) { 33 | if (!params.url) { 34 | return respond 35 | .json({ message: 'Can not create page without url' }) 36 | .status(400); 37 | } 38 | return this.pages.createFromUrl(params.url) 39 | .then(function(page) { 40 | return respond.json(page).status(201); 41 | }); 42 | }; 43 | 44 | module.exports = PageController; 45 | -------------------------------------------------------------------------------- /lib/page/url.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var querystring = require('querystring'); 23 | 24 | exports.pageFromUrl = function pageFromUrl(urlSpec) { 25 | // {pwd}:{script} 26 | var match = urlSpec.match( 27 | /^bugger:\/\/([^:?#]+):([^:?#]+)(\?[^:?#]+)?(#[^:?#]+)?$/ 28 | ); 29 | if (match) { 30 | var cwd = match[1]; 31 | var script = match[2]; 32 | var qs = match[3] ? match[3].substr(1) : ''; 33 | var pid = match[4] ? parseInt(match[4].substr(1), 10) : null; 34 | return { 35 | cwd: cwd, 36 | script: script, 37 | pid: pid, 38 | args: [] 39 | }; 40 | } else { 41 | throw new Error('Invalid bugger:// url:' + urlSpec); 42 | } 43 | }; 44 | 45 | exports.pageToUrl = function pageToUrl(page) { 46 | var urlSpec = 'bugger://' + page.cwd + ':' + page.script; 47 | var query = {}; 48 | if (page.args.length) { 49 | query.args = JSON.stringify(page.args); 50 | } 51 | var qs = querystring.stringify(query); 52 | if (qs) urlSpec += '?' + qs; 53 | if (page.pid) urlSpec += '#' + page.pid; 54 | 55 | return urlSpec; 56 | }; 57 | -------------------------------------------------------------------------------- /lib/api.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var url = require('url'); 23 | 24 | var respond = require('quinn-respond'); 25 | var PROTOCOL_VERSION = require('bugger-agents/package.json').protocolVersion; 26 | 27 | var PageController = require('./page/controller'); 28 | 29 | module.exports = function(buggerd) { 30 | var page = new PageController(buggerd.Pages); 31 | 32 | return function handleApiRequest(req) { 33 | var parsed = url.parse(req.url, true); 34 | var pathname = parsed.pathname.replace(/\/$/, ''); 35 | 36 | // Simple string paths first 37 | switch (pathname) { 38 | case '/json': 39 | case '/json/list': 40 | return page.index(req); 41 | 42 | case '/json/new': 43 | return page.create(req, { 44 | url: parsed.search.substr(1) || null 45 | }); 46 | 47 | case '/json/version': 48 | return respond.json({ 49 | 'Browser': 'node/' + process.version.substr(1), 50 | 'Protocol-Version': PROTOCOL_VERSION 51 | }); 52 | } 53 | 54 | return respond.text('Not implemented').status(501); 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /test/integration/process_rest_test.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | var expect = require('expect.js'); 22 | 23 | var getTestServer = require('../helpers/test_server'); 24 | 25 | describe('/processes resource', function() { 26 | var testServer = getTestServer(); 27 | 28 | it('starts of with an empty process list', function(done) { 29 | testServer.request('/processes', function(err, json, res, body) { 30 | if (err != null) return done(err); 31 | expect(json).to.eql([]); 32 | done(); 33 | }, done); 34 | }); 35 | 36 | it('supports registering a process', function(done) { 37 | testServer.request({ 38 | path: '/processes/42', 39 | method: 'PUT', 40 | data: { 41 | pid: 54, 42 | pwd: '/usr/local/my_app', 43 | script: 'app.js', 44 | params: [ '--port=8080' ] 45 | } 46 | }, function(err, json, res) { 47 | if (err != null) return done(err); 48 | expect(json).to.eql({ success: true }); 49 | 50 | testServer.request('/processes', function(err, json, res, body) { 51 | if (err != null) return done(err); 52 | expect(json).to.be.an('object'); 53 | expect(json.length).to.be(1); 54 | expect(json[0].pid).to.be(42); 55 | expect(json[0].pwd).to.be('/usr/local/my_app'); 56 | expect(json[0].title).to.be('app.js --port=8080'); 57 | expect(json[0].websocket).to.be('/processes/42'); 58 | done(); 59 | }, done); 60 | }, done); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /ui/views/root.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 'use strict'; 3 | 4 | var React = require('react'); 5 | 6 | var Launcher = React.createClass({ 7 | handleSubmit(e) { 8 | if (e) e.preventDefault(); 9 | var cwd = this.refs.cwd.state.value; 10 | var script = this.refs.script.state.value; 11 | var buggerUrl = 'bugger://' + cwd + ':' + script; 12 | 13 | var xhr = new XMLHttpRequest(), self = this; 14 | xhr.addEventListener('load', function() { 15 | if (self.props.onLaunched) { 16 | self.props.onLaunched(); 17 | } 18 | }); 19 | xhr.addEventListener('error', function() { 20 | console.log('error!'); 21 | }); 22 | xhr.open('post', '/json/new?' + buggerUrl, true); 23 | xhr.send(); 24 | }, 25 | 26 | render() { 27 | return
28 | 29 | 30 | 31 |
; 32 | } 33 | }); 34 | 35 | var ProcessList = React.createClass({ 36 | renderProcess(proc) { 37 | var cwd = proc.url.replace('bugger://', '').split(':')[0]; 38 | var pid = proc.url.split('#')[1] || '?'; 39 | return
  • 40 |
    {proc.title}{' - '}{pid}
    41 |
    {'Open in DevTools'}
    42 |
    
    43 |         {'$ cd ' + cwd + ' && \\\n  node --debug-brk=' + (proc.port || 5858) + ' ' + proc.title}
    44 |       
    45 |
  • ; 46 | }, 47 | 48 | render() { 49 | return ; 50 | } 51 | }); 52 | 53 | var Root = React.createClass({ 54 | getInitialState() { 55 | return { processes: [] }; 56 | }, 57 | 58 | updateProcessList() { 59 | var xhr = new XMLHttpRequest(), self = this; 60 | xhr.addEventListener('load', function() { 61 | if (xhr.statusText !== 'OK') { 62 | console.error(xhr.statusText); 63 | return; 64 | } 65 | self.setState({ 66 | processes: JSON.parse(xhr.responseText) 67 | }); 68 | }); 69 | xhr.addEventListener('error', function() { 70 | console.log('error!'); 71 | }); 72 | xhr.open('get', '/json/list', true); 73 | xhr.send(); 74 | }, 75 | 76 | componentWillMount() { 77 | this.updateProcessList(); 78 | }, 79 | 80 | render() { 81 | var processes = this.state.processes; 82 | 83 | return
    84 |

    Running processes

    85 | 86 | 87 |
    ; 88 | } 89 | }); 90 | 91 | module.exports = Root; 92 | -------------------------------------------------------------------------------- /test/helpers/test_server.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 21 | var ConcatStream = require('concat-stream'); 22 | var http = require('http'); 23 | var buggerd = require('../../lib/bugger-daemon'); 24 | 25 | module.exports = function getTestServer() { 26 | function makeRequest(opts, cb, errCb) { 27 | if ('string' === typeof opts) { 28 | if (opts.indexOf('/') === 0) { 29 | opts = 'http://127.0.0.1:8050' + opts; 30 | } 31 | } else if (opts != null && 'object' === typeof opts) { 32 | if (opts.port == null) { 33 | opts.port = 8050; 34 | } 35 | } 36 | 37 | var req = http.request(opts, function(res) { 38 | res.pipe(new ConcatStream(function(body) { 39 | var json; 40 | try { 41 | json = JSON.parse(body); 42 | } catch (err) { 43 | // ignore 44 | } 45 | try { 46 | cb(null, json, res, body); 47 | } catch (err) { 48 | if (errCb) { errCb(err); } 49 | } 50 | })).on('error', function(err) { cb(err); }); 51 | }).on('error', cb); 52 | 53 | if ('object' === typeof opts) { 54 | if (opts['data'] != null) { 55 | req.write(JSON.stringify(opts['data'])); 56 | } 57 | } 58 | req.end(); 59 | 60 | return req; 61 | }; 62 | 63 | var server; 64 | beforeEach(function(done) { 65 | server = buggerd().httpServer 66 | .listen(8050, '127.0.0.1', function() { 67 | return done(); 68 | }); 69 | }); 70 | 71 | afterEach(function(done) { 72 | server.on('close', done); 73 | server.close(); 74 | }); 75 | 76 | return { 77 | request: makeRequest 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /lib/page/model.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var uuid = require('node-uuid'); 23 | var _ = require('lodash'); 24 | 25 | var pageToUrl = require('./url').pageToUrl; 26 | 27 | function generateId() { 28 | return uuid.v1().toUpperCase(); 29 | } 30 | 31 | function PageModel(props) { 32 | props = props || {}; 33 | 34 | this.id = props.id || generateId(); 35 | this.pid = props.pid || null; 36 | this.port = props.port || null; 37 | 38 | this.cwd = props.cwd; 39 | this.script = props.script; 40 | this.args = Array.isArray(props.args) ? props.args : []; 41 | 42 | this.description = props.description || ''; 43 | this.faviconUrl = props.faviconUrl || ''; 44 | 45 | this.joinedAt = props.joinedAt || Date.now(); 46 | this.lastUpdate = props.lastUpdate || Date.now(); 47 | 48 | this.buggerPort = props.buggerPort; 49 | }; 50 | 51 | Object.defineProperties(PageModel.prototype, { 52 | title: { 53 | get: function() { 54 | return [this.script].concat(this.args.map(function(el) { 55 | if (el.indexOf(' ') !== -1) 56 | return JSON.stringify(el); 57 | return el; 58 | })).join(' '); 59 | } 60 | }, 61 | 62 | url: { 63 | get: function() { 64 | var urlSpec = pageToUrl(this); 65 | return urlSpec; 66 | } 67 | }, 68 | 69 | devtoolsFrontendUrl: { 70 | get: function() { 71 | return '/devtools/devtools.html?' + 72 | this.webSocketDebuggerUrl.replace(/^ws:\/\//, 'ws=') + 73 | '&toolbarColor=rgba(230,230,230,1)&textColor=rgba(0,0,0,1)'; 74 | } 75 | }, 76 | 77 | webSocketDebuggerUrl: { 78 | get: function() { 79 | return 'ws://127.0.0.1:' + this.buggerPort + '/devtools/page/' + this.id; 80 | } 81 | } 82 | }); 83 | 84 | PageModel.prototype.validate = function() { 85 | return true; 86 | }; 87 | 88 | PageModel.prototype.toJSON = function() { 89 | return _.pick(this, 90 | 'description', 'devtoolsFrontendUrl', 91 | 'faviconUrl', 'id', 'title', 'type', 92 | 'url', 'webSocketDebuggerUrl'); 93 | }; 94 | 95 | PageModel.buggerPort = 8058; 96 | 97 | module.exports = PageModel; 98 | -------------------------------------------------------------------------------- /lib/agents-socket-transport.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var Promise = require('bluebird'); 23 | var _ = require('lodash'); 24 | 25 | // client: A websocket client 26 | // page: A page model 27 | // page.agents: bugger-agents for the page 28 | function connectClientToPage(Pages, client, page) { 29 | var agents = page.agents; 30 | 31 | function setup() { 32 | client.on('message', handleMessage); 33 | client.on('close', handleClose); 34 | client.on('error', handleFatalError); 35 | agents.on('debugEvent', handleEvent); 36 | } 37 | 38 | var cleanupDone = false; 39 | function cleanup() { 40 | if (cleanupDone) return; 41 | client.removeListener('message', handleMessage); 42 | client.removeListener('close', handleClose); 43 | client.removeListener('error', handleFatalError); 44 | agents.removeListener('debugEvent', handleEvent); 45 | cleanupDone = true; 46 | } 47 | 48 | function handleFatalError(err) { 49 | if (err) console.error(err.stack); 50 | cleanup(); 51 | } 52 | 53 | function handleClose() { 54 | cleanup(); 55 | } 56 | 57 | function handleMessage(data) { 58 | try { 59 | handleRequest(JSON.parse(data.utf8Data)); 60 | } catch (err) { 61 | console.error('Could not process message: ' + 62 | data.utf8Data + '\n' + err.stack); 63 | } 64 | } 65 | 66 | function handleRequest(req) { 67 | var method = req.method, params = req.params, id = req.id; 68 | params = params || {}; 69 | 70 | agents.callMethod(method, params).then( 71 | _.partial(sendResponse, id, null), 72 | _.partial(sendResponse, id)); 73 | } 74 | 75 | function sendResponse(id, error, result) { 76 | if (error) { 77 | writeJSON({ id: id, result: null, 78 | error: typeof error === 'string' ? error : 79 | error.stack || error.message 80 | }); 81 | } else { 82 | writeJSON({ id: id, result: result, error: null }); 83 | } 84 | } 85 | 86 | function handleEvent(e) { 87 | writeJSON(e); 88 | } 89 | 90 | function writeJSON(obj) { 91 | if (client && client.connected) { 92 | client.send(JSON.stringify(obj)); 93 | } else { 94 | console.error('Cannot write, disconnected'); 95 | cleanup(); 96 | } 97 | } 98 | 99 | setup(); 100 | } 101 | 102 | module.exports = connectClientToPage; 103 | -------------------------------------------------------------------------------- /lib/bugger-daemon.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var url = require('url'); 23 | var path = require('path'); 24 | var EventEmitter = require('events').EventEmitter; 25 | 26 | var quinn = require('quinn'); 27 | var respond = require('quinn-respond'); 28 | var send = require('send'); 29 | var devtools = require('bugger-devtools')(); 30 | 31 | var API = require('./api'); 32 | var connectClientToPage = require('./agents-socket-transport'); 33 | 34 | function prefix(parsed, pre) { 35 | if (parsed.pathname === pre) return true; 36 | if (parsed.pathname.indexOf(pre + '/') === 0) return true; 37 | return false; 38 | } 39 | 40 | /** 41 | * Bugger daemon - bringing buggers together since 2013 42 | */ 43 | var createHttpHandler = function(buggerd) { 44 | var publicFolder = path.join(__dirname, '..', 'public'); 45 | var apiApp = quinn(API(buggerd)); 46 | 47 | return function(req, res) { 48 | var parsed = url.parse(req.url, true); 49 | if (prefix(parsed, '/json')) return apiApp(req, res); 50 | if (prefix(parsed, '/devtools')) return devtools(req, res); 51 | send(req, parsed.pathname, { 52 | root: publicFolder, 53 | index: [ 'index.html' ] 54 | }).pipe(res); 55 | }; 56 | }; 57 | 58 | var createWebsocketHandler = function(buggerd, httpServer) { 59 | var WebSocketServer = require('websocket').server; 60 | 61 | var webSocket = new WebSocketServer({ 62 | httpServer: buggerd.httpServer, 63 | autoAcceptConnections: false 64 | }); 65 | 66 | webSocket.on('request', function(wsRequest) { 67 | var parsed = url.parse(wsRequest.httpRequest.url); 68 | 69 | // /devtools/page/{pageId} 70 | var match = parsed.pathname.match(/^\/devtools\/page\/([^/]+)$/); 71 | if (match === null) { 72 | return wsRequest.reject(404, "No handler is configured to accept the connection."); 73 | } else { 74 | var pageId = match[1], page; 75 | try { 76 | page = buggerd.Pages.get(pageId); 77 | } catch (err) { 78 | return wsRequest.reject(404, err.message); 79 | } 80 | wsRequest.socket.page = page; 81 | wsRequest.accept(wsRequest.requestedProtocols[0], wsRequest.origin); 82 | } 83 | }); 84 | 85 | webSocket.on('connect', function(client) { 86 | var page = client.page = client.socket.page; 87 | connectClientToPage(buggerd.Pages, client, page); 88 | }); 89 | 90 | return webSocket; 91 | }; 92 | 93 | /** 94 | * Create an http server that just runs buggerd 95 | */ 96 | module.exports = function createBuggerServer() { 97 | var buggerd = new EventEmitter(); 98 | 99 | var Pages = buggerd.Pages = require('./page')(); 100 | 101 | buggerd.httpServer = require('http').createServer( 102 | createHttpHandler(buggerd) 103 | ); 104 | 105 | buggerd.webSocket = createWebsocketHandler(buggerd); 106 | 107 | buggerd.httpServer.on('listening', function() { 108 | buggerd.Pages.buggerPort = this.address().port; 109 | }); 110 | 111 | return buggerd; 112 | }; 113 | -------------------------------------------------------------------------------- /lib/page/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2013 Jan Krems 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | // this software and associated documentation files (the "Software"), to deal in 5 | // the Software without restriction, including without limitation the rights to 6 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | // of the Software, and to permit persons to whom the Software is furnished to do 8 | // so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | // SOFTWARE. 20 | 'use strict'; 21 | 22 | var execFile = require('child_process').execFile; 23 | 24 | var Promise = require('bluebird'); 25 | var _ = require('lodash'); 26 | var attachToPort = require('bugger-agents').attachToPort; 27 | var debug = require('debug')('bugger-daemon:page'); 28 | 29 | var PageModel = require('./model'); 30 | var pageFromUrl = require('./url').pageFromUrl; 31 | 32 | function verifyPortOpen(port) { 33 | return Promise.reject(new Error('Not implemented')); 34 | } 35 | 36 | function findOpenPort() { 37 | var net = require('net'); 38 | return new Promise(function(resolve, reject) { 39 | var server = net.createServer(); 40 | server.on('error', reject); 41 | server.listen(0, function() { 42 | var port = this.address().port; 43 | server.on('close', resolve.bind(null, port)); 44 | server.close(); 45 | }); 46 | }); 47 | } 48 | 49 | module.exports = function() { 50 | var store = {}; 51 | var procByPid = {}; 52 | var Pages = {}; 53 | 54 | Pages.get = function(id) { 55 | if (!store[id]) { 56 | var err = new Error('Process not found'); 57 | err.code = 404; 58 | throw err; 59 | } 60 | return store[id]; 61 | }; 62 | 63 | Pages.all = function all(skip, limit) { 64 | var acc = _.values(store); 65 | 66 | if (skip == null || isNaN(skip)) { skip = 0; } 67 | if (limit == null || isNaN(limit)) { limit = acc.length; } 68 | 69 | return acc.slice(skip, skip + limit); 70 | }; 71 | 72 | Pages.remove = function(id) { 73 | delete store[id]; 74 | }; 75 | 76 | Pages.save = function(page) { 77 | if (!(page instanceof PageModel)) { 78 | page = new PageModel(page); 79 | } 80 | page.validate(); 81 | if (store[page.id] != null) { 82 | page.joinedAt = store[page.id].joinedAt; 83 | } 84 | return store[page.id] = page; 85 | }; 86 | 87 | Pages.launchAndConnect = function(page) { 88 | // 1. get available debug port 89 | function getAvailablePort() { 90 | debug('getAvailablePort', page.port); 91 | if (page.port !== null) { 92 | return verifyPortOpen(page.port); 93 | } 94 | return findOpenPort(); 95 | } 96 | 97 | // 2. launch process 98 | function launchProcess(port) { 99 | debug('Found available port', port); 100 | page.port = port; 101 | 102 | var nodePath = process.execPath; 103 | var nodeArgs = [ 104 | '--debug-brk=' + page.port, page.script 105 | ].concat(page.args); 106 | var childOptions = { cwd: page.cwd, env: process.env }; 107 | 108 | return new Promise(function(resolve, reject) { 109 | var child = 110 | execFile(nodePath, nodeArgs, childOptions); 111 | if (process.env.BUGGER_PIPE_CHILD) { 112 | child.stdout.pipe(process.stdout); 113 | child.stderr.pipe(process.stderr); 114 | } 115 | var pid = child.pid; 116 | child.on('exit', function(exitCode) { 117 | if (page.pid === pid) page.pid = null; 118 | reject(new Error('Child exited with code ' + exitCode)); 119 | }); 120 | 121 | process.on('exit', function() { 122 | try { child.kill(); } catch (err) {} 123 | }); 124 | 125 | process.on('uncaughtException', function() { 126 | try { child.kill(); } catch (err) {} 127 | }); 128 | 129 | page.pid = child.pid; 130 | procByPid[page.pid] = child.pid; 131 | debug('Attaching debug client', page.port); 132 | attachToPort(page.port).then(function(agents) { 133 | debug('Attached'); 134 | page.agents = agents 135 | resolve(page); 136 | }); 137 | }); 138 | } 139 | 140 | return getAvailablePort().then(launchProcess); 141 | }; 142 | 143 | Pages.createFromUrl = function(urlSpec) { 144 | var page = new PageModel(_.defaults({ 145 | buggerPort: Pages.buggerPort 146 | }, pageFromUrl(urlSpec))); 147 | return Pages.launchAndConnect(page).then(Pages.save); 148 | }; 149 | 150 | Pages.buggerPort = 8058; 151 | 152 | return Pages; 153 | }; 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bugger-daemon 2 | 3 | [![Build Status](https://travis-ci.org/buggerjs/bugger-daemon.png)](https://travis-ci.org/buggerjs/bugger-daemon) 4 | 5 | Main point of communication/integration between the many moving parts of 6 | bugger. 7 | 8 | * Any process being bugger'd will register with buggerd 9 | * Instrumentation code will communicate with buggerd 10 | * The Chrome extension will ask buggerd for information about running procs 11 | * All DevTools will communicate via websocket with buggerd 12 | 13 | ## ASCII art time 14 | 15 | ``` 16 | 17 | --------------------------- Chrome --------------------------- 18 | | | | | 19 | | DevTools A | DevTools B | bugger.crx | 20 | | | | | | | | 21 | ---------|--------------------|--------------------|---------- 22 | | | | 23 | | (I) | (I) | (II) 24 | | | | 25 | ---------|---------------- buggerd ----------------|---------- 26 | | V | V | V | 27 | | Domain Agents A | Domain Agents B | Meta HTTP API | 28 | | | | \ | Δ | 29 | --------|----------------------------\-------------|---------- 30 | | \ | 31 | | (III) | (III) | 32 | | _________________|__________/| (II)* 33 | V / V | 34 | ------- A.js ---/--- ------- B.js -|------ 35 | | / | | | | 36 | | Instrumentation | | Instrumentation | 37 | | | | | 38 | -------------------- --------------------- 39 | 40 | (I) Chrome Remote Debugging Protocol // websocket 41 | https://developers.google.com/chrome-developer-tools/docs/protocol/1.0/ 42 | 43 | (II) REST API for basic meta data about debugged processes (see below) 44 | 45 | (II)* The instrumentation code may also communicate directly with the domain 46 | agents if necessary. 47 | 48 | (III) v8 debugger protocol 49 | https://code.google.com/p/v8/wiki/DebuggerProtocol 50 | ``` 51 | 52 | ## API 53 | 54 | This is meant to be (roughly) compatible with the API Chrome exposes. 55 | 56 | 57 | ### GET /json/version 58 | 59 | *Note: This endpoint works using any HTTP method to be compatible with Chrome.* 60 | 61 | ```json 62 | { 63 | Browser: "Chrome/37.0.2062.124", 64 | Protocol-Version: "1.1", 65 | User-Agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36", 66 | WebKit-Version: "537.36 (@181352)" 67 | } 68 | ``` 69 | 70 | 71 | ### GET /json, GET /json/list 72 | 73 | *Note: This endpoint works using any HTTP method to be compatible with Chrome.* 74 | 75 | ```json 76 | [ { 77 | description: "", 78 | devtoolsFrontendUrl: "/devtools/devtools.html?ws=localhost:9222/devtools/page/961C1EB7-A0DA-2F42-F6D4-76B453E70DB5", 79 | faviconUrl: "https://s.yimg.com/rz/l/favicon.ico", 80 | id: "961C1EB7-A0DA-2F42-F6D4-76B453E70DB5", 81 | title: "Yahoo", 82 | type: "page", 83 | url: "https://www.yahoo.com/", 84 | webSocketDebuggerUrl: "ws://localhost:9222/devtools/page/961C1EB7-A0DA-2F42-F6D4-76B453E70DB5" 85 | } ] 86 | ``` 87 | 88 | 89 | ### POST /json/new?{url} 90 | 91 | *Note: This endpoint works using any HTTP method to be compatible with Chrome.* 92 | 93 | It responds with a description of the newly spawned process. 94 | The format is the same as one element in the array returned by `/json`. 95 | 96 | The url is a "bugger url". 97 | Which obviously isn't *really* a thing but it's relatively straight-forward: 98 | 99 | bugger://{cwd}:{script} 100 | 101 | The working directory may be an absolute path (`/tmp/foo`) 102 | or anything that can be resolved globally (`~/Projects/xyz`). 103 | The script will be resolved relative to the working directory. 104 | 105 | In the future it might be good to also support arguments, 106 | either via query or via POST body. 107 | 108 | 109 | ### POST /json/activate/{pageId} 110 | 111 | *Note: This endpoint works using any HTTP method to be compatible with Chrome.* 112 | 113 | In Chrome this would bring a page into the foreground (activate a tab). 114 | Since this doesn't make a lot of sense for UI-less node processes, 115 | it's a noop. 116 | 117 | If the target is invalid, responds with 404 and a string like this: 118 | 119 | ```json 120 | "No such target id: {pageId}" 121 | ``` 122 | 123 | For valid targets the response is 200, `"Target activated"`. 124 | 125 | 126 | ### POST /json/close/{pageId} 127 | 128 | *Note: This endpoint works using any HTTP method to be compatible with Chrome.* 129 | 130 | Removes the script identifed by `pageId`. 131 | If the process is running currently, it will be killed. 132 | 133 | If the target is invalid, responds with 404 and a string like this: 134 | 135 | ```json 136 | "No such target id: {pageId}" 137 | ``` 138 | 139 | For valid targets the response is 200, `"Target is closing"`. 140 | 141 | 142 | ### Websocket /devtools/page/{pageId} 143 | 144 | This is where the devtools are connecting to. 145 | 146 | 147 | ### GET /devtools/* 148 | 149 | A copy of the devtools that ship with Chrome. 150 | -------------------------------------------------------------------------------- /public/bugger.min.css: -------------------------------------------------------------------------------- 1 | body{background-color:#fff;font-family:"Helvetica Neue", Helvetica, Arial, sans-serif} 2 | .content{margin:0 auto;max-width:800px;margin-bottom:50px} 3 | nav{background:#ededed} 4 | nav>.pure-menu{max-width:800px;margin:0 auto} 5 | dt{font-weight: bold} dd{margin: 0 0 10px 0} 6 | a{color:#b9410e} 7 | .pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none} 8 | .pure-button::-moz-focus-inner{padding:0;border:0} 9 | .pure-button{font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1.5em .5em;color:#0f0f0f;border:1px solid #b6b4b4;border:none rgba(0,0,0,0);background-color:#c0bfbf;border-radius:2px;text-decoration:none;-webkit-font-smoothing:antialiased;-webkit-transition:.1s linear -webkit-box-shadow;-moz-transition:.1s linear -moz-box-shadow;-ms-transition:.1s linear box-shadow;-o-transition:.1s linear box-shadow;transition:.1s linear box-shadow} 10 | .pure-button-hover,.pure-button:hover{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#00000000',GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,0.05)),to(rgba(0,0,0,0.05)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,0.05) 40%,rgba(0,0,0,0.15));background-image:-moz-linear-gradient(top,rgba(0,0,0,0.05) 0,rgba(0,0,0,0.05));background-image:-ms-linear-gradient(transparent,rgba(0,0,0,0.05) 40%,rgba(0,0,0,0.15));background-image:-o-linear-gradient(transparent,rgba(0,0,0,0.05) 40%,rgba(0,0,0,0.05));background-image:linear-gradient(transparent,rgba(0,0,0,0.05) 40%,rgba(0,0,0,0.05))} 11 | .pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,0.15) inset,0 0 6px rgba(0,0,0,0.20) inset} 12 | .pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);filter:alpha(opacity=40);-khtml-opacity:.40;-moz-opacity:.40;opacity:.40;cursor:not-allowed;box-shadow:none} 13 | .pure-button-hidden{display:none} 14 | .pure-button::-moz-focus-inner{padding:0;border:0} 15 | .pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#b9410e;color:#fffcfa} 16 | .pure-button:-moz-focusring{outline-color:rgba(0,0,0,0.85)} 17 | /*! Copyright 2013 Yahoo! Inc. http://yuilibrary.com/license/ *//*! Copyright (c) Nicolas Gallagher and Jonathan Neal *//*! normalize.css v1.1.0 | MIT License | git.io/normalize */.pure-skin-bugger .pure-form{margin:0} 18 | .pure-skin-bugger .pure-form fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} 19 | .pure-skin-bugger .pure-form legend{border:0;padding:0;white-space:normal;*margin-left:-7px} 20 | .pure-skin-bugger .pure-form button,.pure-skin-bugger .pure-form input,.pure-skin-bugger .pure-form select,.pure-skin-bugger .pure-form textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle} 21 | .pure-skin-bugger .pure-form button,.pure-skin-bugger .pure-form input{line-height:normal} 22 | .pure-skin-bugger .pure-form button,.pure-skin-bugger .pure-form input[type="button"],.pure-skin-bugger .pure-form input[type="reset"],.pure-skin-bugger .pure-form input[type="submit"]{-webkit-appearance:button;cursor:pointer;*overflow:visible} 23 | .pure-skin-bugger .pure-form button[disabled],.pure-skin-bugger .pure-form input[disabled]{cursor:default} 24 | .pure-skin-bugger .pure-form input[type="checkbox"],.pure-skin-bugger .pure-form input[type="radio"]{box-sizing:border-box;padding:0;*height:13px;*width:13px} 25 | .pure-skin-bugger .pure-form input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} 26 | .pure-skin-bugger .pure-form input[type="search"]::-webkit-search-cancel-button,.pure-skin-bugger .pure-form input[type="search"]::-webkit-search-decoration{-webkit-appearance:none} 27 | .pure-skin-bugger .pure-form button::-moz-focus-inner,.pure-skin-bugger .pure-form input::-moz-focus-inner{border:0;padding:0} 28 | .pure-skin-bugger .pure-form textarea{overflow:auto;vertical-align:top} 29 | @media only screen and (max-width :480px){.pure-skin-bugger .pure-form button[type="submit"]{margin:.7em 0 0} 30 | .pure-skin-bugger .pure-form input[type="text"],.pure-skin-bugger .pure-form input[type="password"],.pure-skin-bugger .pure-form input[type="email"],.pure-skin-bugger .pure-form input[type="url"],.pure-skin-bugger .pure-form input[type="date"],.pure-skin-bugger .pure-form input[type="month"],.pure-skin-bugger .pure-form input[type="time"],.pure-skin-bugger .pure-form input[type="datetime"],.pure-skin-bugger .pure-form input[type="datetime-local"],.pure-skin-bugger .pure-form input[type="week"],.pure-skin-bugger .pure-form input[type="number"],.pure-skin-bugger .pure-form input[type="search"],.pure-skin-bugger .pure-form input[type="tel"],.pure-skin-bugger .pure-form input[type="color"],.pure-skin-bugger .pure-form label{margin-bottom:.3em;display:block} 31 | .pure-skin-bugger .pure-group input[type="text"],.pure-skin-bugger .pure-group input[type="password"],.pure-skin-bugger .pure-group input[type="email"],.pure-skin-bugger .pure-group input[type="url"],.pure-skin-bugger .pure-group input[type="date"],.pure-skin-bugger .pure-group input[type="month"],.pure-skin-bugger .pure-group input[type="time"],.pure-skin-bugger .pure-group input[type="datetime"],.pure-skin-bugger .pure-group input[type="datetime-local"],.pure-skin-bugger .pure-group input[type="week"],.pure-skin-bugger .pure-group input[type="number"],.pure-skin-bugger .pure-group input[type="search"],.pure-skin-bugger .pure-group input[type="tel"],.pure-skin-bugger .pure-group input[type="color"]{margin-bottom:0} 32 | .pure-skin-bugger .pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%} 33 | .pure-skin-bugger .pure-form-aligned .pure-controls{margin:1.5em 0 0 0} 34 | .pure-skin-bugger .pure-form .pure-help-inline,.pure-skin-bugger .pure-form-message-inline,.pure-skin-bugger .pure-form-message{display:block;font-size:80%;padding:.2em 0 .8em} 35 | } 36 | .pure-skin-bugger .pure-form input[type="text"],.pure-skin-bugger .pure-form input[type="password"],.pure-skin-bugger .pure-form input[type="email"],.pure-skin-bugger .pure-form input[type="url"],.pure-skin-bugger .pure-form input[type="date"],.pure-skin-bugger .pure-form input[type="month"],.pure-skin-bugger .pure-form input[type="time"],.pure-skin-bugger .pure-form input[type="datetime"],.pure-skin-bugger .pure-form input[type="datetime-local"],.pure-skin-bugger .pure-form input[type="week"],.pure-skin-bugger .pure-form input[type="number"],.pure-skin-bugger .pure-form input[type="search"],.pure-skin-bugger .pure-form input[type="tel"],.pure-skin-bugger .pure-form input[type="color"],.pure-skin-bugger .pure-form select,.pure-skin-bugger .pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #e6e6e6;font-size:.8em;box-shadow:inset 0 1px 3px #e6e6e6;border-radius:4px;-webkit-transition:.3s linear border;-moz-transition:.3s linear border;-ms-transition:.3s linear border;-o-transition:.3s linear border;transition:.3s linear border;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased} 37 | .pure-skin-bugger .pure-form input[type="text"]:focus,.pure-skin-bugger .pure-form input[type="password"]:focus,.pure-skin-bugger .pure-form input[type="email"]:focus,.pure-skin-bugger .pure-form input[type="url"]:focus,.pure-skin-bugger .pure-form input[type="date"]:focus,.pure-skin-bugger .pure-form input[type="month"]:focus,.pure-skin-bugger .pure-form input[type="time"]:focus,.pure-skin-bugger .pure-form input[type="datetime"]:focus,.pure-skin-bugger .pure-form input[type="datetime-local"]:focus,.pure-skin-bugger .pure-form input[type="week"]:focus,.pure-skin-bugger .pure-form input[type="number"]:focus,.pure-skin-bugger .pure-form input[type="search"]:focus,.pure-skin-bugger .pure-form input[type="tel"]:focus,.pure-skin-bugger .pure-form input[type="color"]:focus,.pure-skin-bugger .pure-form select:focus,.pure-skin-bugger .pure-form textarea:focus{outline:0;outline:thin dotted \9;border-color:#129fea} 38 | .pure-skin-bugger .pure-form input[type="file"]:focus,.pure-skin-bugger .pure-form input[type="radio"]:focus,.pure-skin-bugger .pure-form input[type="checkbox"]:focus{outline:thin dotted #333;outline:1px auto #129fea} 39 | .pure-skin-bugger .pure-form .pure-checkbox,.pure-skin-bugger .pure-form .pure-radio{margin:.5em 0;display:block} 40 | .pure-skin-bugger .pure-form input[type="text"][disabled],.pure-skin-bugger .pure-form input[type="password"][disabled],.pure-skin-bugger .pure-form input[type="email"][disabled],.pure-skin-bugger .pure-form input[type="url"][disabled],.pure-skin-bugger .pure-form input[type="date"][disabled],.pure-skin-bugger .pure-form input[type="month"][disabled],.pure-skin-bugger .pure-form input[type="time"][disabled],.pure-skin-bugger .pure-form input[type="datetime"][disabled],.pure-skin-bugger .pure-form input[type="datetime-local"][disabled],.pure-skin-bugger .pure-form input[type="week"][disabled],.pure-skin-bugger .pure-form input[type="number"][disabled],.pure-skin-bugger .pure-form input[type="search"][disabled],.pure-skin-bugger .pure-form input[type="tel"][disabled],.pure-skin-bugger .pure-form input[type="color"][disabled],.pure-skin-bugger .pure-form select[disabled],.pure-skin-bugger .pure-form textarea[disabled],.pure-skin-bugger .pure-form input[readonly],.pure-skin-bugger .pure-form select[readonly],.pure-skin-bugger .pure-form textarea[readonly]{cursor:not-allowed;box-shadow:inset 0 1px 10px #ededed;background-color:#fff;color:#adadad;border-color:#e6e6e6} 41 | .pure-skin-bugger .pure-form input:focus:invalid,.pure-skin-bugger .pure-form textarea:focus:invalid,.pure-skin-bugger .pure-form select:focus:invalid{color:#b94a48;border:1px solid #ee5f5b} 42 | .pure-skin-bugger .pure-form input:focus:invalid:focus,.pure-skin-bugger .pure-form textarea:focus:invalid:focus,.pure-skin-bugger .pure-form select:focus:invalid:focus{border-color:#e9322d} 43 | .pure-skin-bugger .pure-form input[type="file"]:focus:invalid:focus,.pure-skin-bugger .pure-form input[type="radio"]:focus:invalid:focus,.pure-skin-bugger .pure-form input[type="checkbox"]:focus:invalid:focus{outline-color:#e9322d} 44 | .pure-skin-bugger .pure-form select{border:1px solid #e6e6e6;background-color:white} 45 | .pure-skin-bugger .pure-form select[multiple]{height:auto} 46 | .pure-skin-bugger .pure-form label{margin:.5em 0 .2em;color:#4f4f4f;font-size:90%} 47 | .pure-skin-bugger .pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0} 48 | .pure-skin-bugger .pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;font-size:125%;color:#262626;border-bottom:1px solid #ededed} 49 | .pure-skin-bugger .pure-form-stacked label{display:block} 50 | .pure-skin-bugger .pure-form-aligned input,.pure-skin-bugger .pure-form-aligned textarea,.pure-skin-bugger .pure-form-aligned select,.pure-skin-bugger .pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle} 51 | .pure-skin-bugger .pure-form-aligned .pure-control-group{margin-bottom:.5em} 52 | .pure-skin-bugger .pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0} 53 | .pure-skin-bugger .pure-form-aligned .pure-controls{margin:1.5em 0 0 10em} 54 | .pure-skin-bugger .pure-form .pure-input-rounded{border-radius:30px;padding-left:1em} 55 | .pure-skin-bugger .pure-form .pure-group fieldset{margin-bottom:10px} 56 | .pure-skin-bugger .pure-form .pure-group input{display:block;padding:.5em .6em;margin:0;border-radius:0;position:relative;top:-1px} 57 | .pure-skin-bugger .pure-form .pure-group input:focus{z-index:2} 58 | .pure-skin-bugger .pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0} 59 | .pure-skin-bugger .pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px} 60 | .pure-skin-bugger .pure-form .pure-group button{margin:.35em 0} 61 | .pure-skin-bugger .pure-form .pure-input-1{width:100%} 62 | .pure-skin-bugger .pure-form .pure-input-2-3{width:66%} 63 | .pure-skin-bugger .pure-form .pure-input-1-2{width:50%} 64 | .pure-skin-bugger .pure-form .pure-input-1-3{width:33%} 65 | .pure-skin-bugger .pure-form .pure-input-1-4{width:25%} 66 | .pure-skin-bugger .pure-form .pure-help-inline,.pure-skin-bugger .pure-form-message-inline{display:inline-block;padding-left:.3em;color:#adadad;font-size:90%;vertical-align:middle} 67 | .pure-skin-bugger .pure-form-message{display:block;margin:.5em 0 .2em;color:#adadad;font-size:90%} 68 | .pure-skin-bugger .pure-table{border-collapse:separate;border-spacing:0;empty-cells:show;border:1px solid #dedede} 69 | .pure-skin-bugger .pure-table caption{color:#adadad;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center} 70 | .pure-skin-bugger .pure-table td,.pure-skin-bugger .pure-table th{border-left:1px solid #dedede;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.3em .6em} 71 | .pure-skin-bugger .pure-table td:first-child,.pure-skin-bugger .pure-table th:first-child{border-left-width:0} 72 | .pure-skin-bugger .pure-table thead{background-color:#d7d6d6;color:#272626;text-align:left;vertical-align:bottom;white-space:nowrap} 73 | .pure-skin-bugger .pure-table td{background-color:#ededed;color:#404040} 74 | .pure-skin-bugger .pure-table-odd td{background-color:#dedede;color:#262626} 75 | .pure-skin-bugger .pure-table-bordered td{border-bottom:1px solid #dedede} 76 | .pure-skin-bugger .pure-table-bordered tbody>tr:last-child td,.pure-skin-bugger .pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} 77 | .pure-skin-bugger .pure-table-horizontal td,.pure-skin-bugger .pure-table-horizontal th{border-width:0 0 1px 0;border-bottom:1px solid #dedede} 78 | .pure-skin-bugger .pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} 79 | .pure-skin-bugger .pure-menu ul{position:absolute;visibility:hidden} 80 | .pure-skin-bugger .pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%} 81 | .pure-skin-bugger .pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1} 82 | .pure-skin-bugger .pure-menu>ul{position:relative} 83 | .pure-skin-bugger .pure-menu-open>ul{left:0;top:0;visibility:visible} 84 | .pure-skin-bugger .pure-menu-open>ul:focus{outline:0} 85 | .pure-skin-bugger .pure-menu li{position:relative} 86 | .pure-skin-bugger .pure-menu a,.pure-skin-bugger .pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:.35em 1.4em;text-decoration:none;white-space:nowrap} 87 | .pure-skin-bugger .pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle} 88 | .pure-skin-bugger .pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle;height:2.4em} 89 | .pure-skin-bugger .pure-menu li a{padding:.35em 1.4em} 90 | .pure-skin-bugger .pure-menu-can-have-children>.pure-menu-label:after{content:'\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px} 91 | .pure-skin-bugger .pure-menu-can-have-children>.pure-menu-label{padding-right:30px} 92 | .pure-skin-bugger .pure-menu-separator{background-color:#dedede;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden} 93 | .pure-skin-bugger .pure-menu-hidden{display:none} 94 | .pure-skin-bugger .pure-menu-fixed{position:fixed;top:0;left:0;width:100%} 95 | .pure-skin-bugger .pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle} 96 | .pure-skin-bugger .pure-menu-horizontal li li{display:block} 97 | .pure-skin-bugger .pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:"\25BE"} 98 | .pure-skin-bugger .pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px} 99 | .pure-skin-bugger .pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px} 100 | .pure-skin-bugger .pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px} 101 | .pure-skin-bugger .pure-paginator{list-style:none;margin:0;padding:0} 102 | .pure-skin-bugger .pure-paginator li{display:inline-block;*display:inline;zoom:1;margin:0 -0.35em 0 0} 103 | .pure-skin-bugger .pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em} 104 | .pure-skin-bugger .pure-paginator .pure-button:focus{outline-style:none} 105 | .pure-skin-bugger .pure-paginator .prev{border-radius:4px 0 0 4px} 106 | .pure-skin-bugger .pure-paginator .next{border-radius:0 4px 4px 0} 107 | .pure-skin-bugger .pure-menu.pure-menu-open,.pure-skin-bugger .pure-menu.pure-menu-horizontal li .pure-menu-children{background:#ededed;border:1px solid #dedede} 108 | .pure-skin-bugger .pure-menu.pure-menu-horizontal,.pure-skin-bugger .pure-menu.pure-menu-horizontal .pure-menu-heading{border:0} 109 | .pure-skin-bugger .pure-menu a{border:1px solid transparent;border-left:0;border-right:0} 110 | .pure-skin-bugger .pure-menu a,.pure-skin-bugger .pure-menu .pure-menu-can-have-children>li:after{color:#404040} 111 | .pure-skin-bugger .pure-menu .pure-menu-can-have-children>li:hover:after{color:#262626} 112 | .pure-skin-bugger .pure-menu .pure-menu-open{background:#d6d6d6} 113 | .pure-skin-bugger .pure-menu li a:hover{background:#d6d6d6} 114 | .pure-skin-bugger .pure-menu li.pure-menu-disabled a:hover{background:#ededed;color:#9e9e9e} 115 | .pure-skin-bugger .pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default} 116 | .pure-skin-bugger .pure-menu .pure-menu-disabled>a,.pure-skin-bugger .pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#9e9e9e} 117 | .pure-skin-bugger .pure-menu .pure-menu-heading{color:#171717;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom:solid 1px #dedede} 118 | .pure-skin-bugger .pure-menu li.pure-menu-selected a{background-color:#b9410e;color:#fffcfa} 119 | .pure-skin-bugger .pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #dedede} 120 | @media(max-width:480px){.pure-skin-bugger .pure-menu-horizontal{width:100%} 121 | .pure-skin-bugger .pure-menu-children li{display:block;border-bottom:1px solid #dedede} 122 | } 123 | -------------------------------------------------------------------------------- /public/pure.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.2.1 3 | Copyright 2013 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yui/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v1.1.2 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v1.1.2 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none;height:0}[hidden]{display:none}html{font-size:100%;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}html,button,input,select,textarea{font-family:sans-serif}body{margin:0}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{font-size:2em;margin:.67em 0}h2{font-size:1.5em;margin:.83em 0}h3{font-size:1.17em;margin:1em 0}h4{font-size:1em;margin:1.33em 0}h5{font-size:.83em;margin:1.67em 0}h6{font-size:.67em;margin:2.33em 0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}blockquote{margin:1em 40px}dfn{font-style:italic}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}mark{background:#ff0;color:#000}p,pre{margin:1em 0}code,kbd,pre,samp{font-family:monospace,serif;_font-family:'courier new',monospace;font-size:1em}pre{white-space:pre;white-space:pre-wrap;word-wrap:break-word}q{quotes:none}q:before,q:after{content:'';content:none}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}dl,menu,ol,ul{margin:1em 0}dd{margin:0 0 0 40px}menu,ol,ul{padding:0 0 0 40px}nav ul,nav ol{list-style:none;list-style-image:none}img{border:0;-ms-interpolation-mode:bicubic}svg:not(:root){overflow:hidden}figure{margin:0}form{margin:0}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0;white-space:normal;*margin-left:-7px}button,input,select,textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}button,input{line-height:normal}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}button[disabled],html input[disabled]{cursor:default}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0} 12 | .pure-button{display:inline-block;*display:inline;zoom:1;line-height:normal;white-space:nowrap;vertical-align:baseline;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-size:100%;*font-size:90%;*overflow:visible;padding:.5em 1.5em;color:#444;color:rgba(0,0,0,.8);*color:#444;border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px;-webkit-font-smoothing:antialiased;-webkit-transition:.1s linear -webkit-box-shadow;-moz-transition:.1s linear -moz-box-shadow;-ms-transition:.1s linear box-shadow;-o-transition:.1s linear box-shadow;transition:.1s linear box-shadow}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-ms-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff} 13 | .pure-form{margin:0}.pure-form fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}.pure-form legend{border:0;padding:0;white-space:normal;*margin-left:-7px}.pure-form button,.pure-form input,.pure-form select,.pure-form textarea{font-size:100%;margin:0;vertical-align:baseline;*vertical-align:middle}.pure-form button,.pure-form input{line-height:normal}.pure-form button,.pure-form input[type=button],.pure-form input[type=reset],.pure-form input[type=submit]{-webkit-appearance:button;cursor:pointer;*overflow:visible}.pure-form button[disabled],.pure-form input[disabled]{cursor:default}.pure-form input[type=checkbox],.pure-form input[type=radio]{box-sizing:border-box;padding:0;*height:13px;*width:13px}.pure-form input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}.pure-form input[type=search]::-webkit-search-cancel-button,.pure-form input[type=search]::-webkit-search-decoration{-webkit-appearance:none}.pure-form button::-moz-focus-inner,.pure-form input::-moz-focus-inner{border:0;padding:0}.pure-form textarea{overflow:auto;vertical-align:top}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;font-size:.8em;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-transition:.3s linear border;-moz-transition:.3s linear border;-ms-transition:.3s linear border;-o-transition:.3s linear border;transition:.3s linear border;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-font-smoothing:antialiased}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;outline:thin dotted \9;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin dotted #333;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly],.pure-form input[readonly]:focus,.pure-form select[readonly]:focus,.pure-form textarea[readonly]:focus{background:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border:1px solid #ee5f5b}.pure-form input:focus:invalid:focus,.pure-form textarea:focus:invalid:focus,.pure-form select:focus:invalid:focus{border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em;font-size:90%}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;font-size:125%;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 10em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input{display:block;padding:10px;margin:0;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus{z-index:2}.pure-form .pure-group input:first-child{top:1px;border-radius:4px 4px 0 0}.pure-form .pure-group input:last-child{top:-2px;border-radius:0 0 4px 4px}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:90%}.pure-form-message{display:block;color:#666;font-size:90%}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:80%;padding:.2em 0 .8em}} 14 | .pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-5-24,.pure-u-7-24,.pure-u-11-24,.pure-u-13-24,.pure-u-17-24,.pure-u-19-24,.pure-u-23-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1{width:100%}.pure-u-1-2{width:50%}.pure-u-1-3{width:33.33333%}.pure-u-2-3{width:66.66666%}.pure-u-1-4{width:25%}.pure-u-3-4{width:75%}.pure-u-1-5{width:20%}.pure-u-2-5{width:40%}.pure-u-3-5{width:60%}.pure-u-4-5{width:80%}.pure-u-1-6{width:16.666%}.pure-u-5-6{width:83.33%}.pure-u-1-8{width:12.5%}.pure-u-3-8{width:37.5%}.pure-u-5-8{width:62.5%}.pure-u-7-8{width:87.5%}.pure-u-1-12{width:8.3333%}.pure-u-5-12{width:41.6666%}.pure-u-7-12{width:58.3333%}.pure-u-11-12{width:91.6666%}.pure-u-1-24{width:4.1666%}.pure-u-5-24{width:20.8333%}.pure-u-7-24{width:29.1666%}.pure-u-11-24{width:45.8333%}.pure-u-13-24{width:54.1666%}.pure-u-17-24{width:70.8333%}.pure-u-19-24{width:79.1666%}.pure-u-23-24{width:95.8333%}.pure-g-r{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em}.opera-only :-o-prefocus,.pure-g-r{word-spacing:-.43em}.pure-g-r img{max-width:100%}@media (min-width:980px){.pure-visible-phone{display:none}.pure-visible-tablet{display:none}.pure-hidden-desktop{display:none}}@media (max-width:480px){.pure-g-r>.pure-u,.pure-g-r>[class *="pure-u-"]{width:100%}}@media (max-width:767px){.pure-g-r>.pure-u,.pure-g-r>[class *="pure-u-"]{width:100%}.pure-hidden-phone{display:none}.pure-visible-desktop{display:none}}@media (min-width:768px) and (max-width:979px){.pure-hidden-tablet{display:none}.pure-visible-desktop{display:none}} 15 | .pure-menu ul{position:absolute;visibility:hidden}.pure-menu.pure-menu-open{visibility:visible;z-index:2;width:100%}.pure-menu ul{left:-10000px;list-style:none;margin:0;padding:0;top:-10000px;z-index:1}.pure-menu>ul{position:relative}.pure-menu-open>ul{left:0;top:0;visibility:visible}.pure-menu-open>ul:focus{outline:0}.pure-menu li{position:relative}.pure-menu a,.pure-menu .pure-menu-heading{display:block;color:inherit;line-height:1.5em;padding:5px 20px;text-decoration:none;white-space:nowrap}.pure-menu.pure-menu-horizontal>.pure-menu-heading{display:inline-block;*display:inline;zoom:1;margin:0;vertical-align:middle}.pure-menu.pure-menu-horizontal>ul{display:inline-block;*display:inline;zoom:1;vertical-align:middle;height:2.4em}.pure-menu li a{padding:5px 20px}.pure-menu-can-have-children>.pure-menu-label:after{content:'\25B8';float:right;font-family:'Lucida Grande','Lucida Sans Unicode','DejaVu Sans',sans-serif;margin-right:-20px;margin-top:-1px}.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-separator{background-color:#dfdfdf;display:block;height:1px;font-size:0;margin:7px 2px;overflow:hidden}.pure-menu-hidden{display:none}.pure-menu-fixed{position:fixed;top:0;left:0;width:100%}.pure-menu-horizontal li{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-horizontal li li{display:block}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label:after{content:"\25BE"}.pure-menu-horizontal>.pure-menu-children>.pure-menu-can-have-children>.pure-menu-label{padding-right:30px}.pure-menu-horizontal li.pure-menu-separator{height:50%;width:1px;margin:0 7px}.pure-menu-horizontal li li.pure-menu-separator{height:1px;width:auto;margin:7px 2px}.pure-menu.pure-menu-open,.pure-menu.pure-menu-horizontal li .pure-menu-children{background:#fff;border:1px solid #b7b7b7}.pure-menu.pure-menu-horizontal,.pure-menu.pure-menu-horizontal .pure-menu-heading{border:0}.pure-menu a{border:1px solid transparent;border-left:0;border-right:0}.pure-menu a,.pure-menu .pure-menu-can-have-children>li:after{color:#777}.pure-menu .pure-menu-can-have-children>li:hover:after{color:#fff}.pure-menu .pure-menu-open{background:#dedede}.pure-menu li a:hover,.pure-menu li a:focus{background:#eee}.pure-menu li.pure-menu-disabled a:hover,.pure-menu li.pure-menu-disabled a:focus{background:#fff;color:#bfbfbf}.pure-menu .pure-menu-disabled>a{background-image:none;border-color:transparent;cursor:default}.pure-menu .pure-menu-disabled>a,.pure-menu .pure-menu-can-have-children.pure-menu-disabled>a:after{color:#bfbfbf}.pure-menu .pure-menu-heading{color:#565d64;text-transform:uppercase;font-size:90%;margin-top:.5em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:#dfdfdf}.pure-menu .pure-menu-selected a{color:#000}.pure-menu.pure-menu-open.pure-menu-fixed{border:0;border-bottom:1px solid #b7b7b7}.pure-paginator{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;list-style:none;margin:0;padding:0}.opera-only :-o-prefocus,.pure-paginator{word-spacing:-.43em}.pure-paginator li{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-paginator .pure-button{border-radius:0;padding:.8em 1.4em;vertical-align:top;height:1.1em}.pure-paginator .pure-button:focus,.pure-paginator .pure-button:active{outline-style:none}.pure-paginator .prev,.pure-paginator .next{color:#C0C1C3;text-shadow:0 -1px 0 rgba(0,0,0,.45)}.pure-paginator .prev{border-radius:2px 0 0 2px}.pure-paginator .next{border-radius:0 2px 2px 0}@media (max-width:480px){.pure-menu-horizontal{width:100%}.pure-menu-children li{display:block;border-bottom:1px solid #000}} 16 | .pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:6px 12px}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child td,.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child td{border-bottom-width:0} 17 | -------------------------------------------------------------------------------- /public/bugger.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #ffffff; 3 | } 4 | 5 | /* from YUICSS buttons-core.css */ 6 | .pure-button { 7 | /* Structure */ 8 | display: inline-block; 9 | *display: inline; /*IE 6/7*/ 10 | zoom: 1; 11 | line-height: normal; 12 | white-space: nowrap; 13 | vertical-align: baseline; 14 | text-align: center; 15 | cursor: pointer; 16 | -webkit-user-drag: none; 17 | -webkit-user-select: none; 18 | -moz-user-select: none; 19 | -ms-user-select: none; 20 | user-select: none; 21 | } 22 | 23 | /* Firefox: Get rid of the inner focus border */ 24 | .pure-button::-moz-focus-inner{ 25 | padding: 0; 26 | border: 0; 27 | } 28 | /* end from YUICSS buttons-core.css */ 29 | /* from YUICSS buttons.css */ 30 | /*csslint unqualified-attributes:false*/ 31 | 32 | .pure-button { 33 | font-size: 100%; 34 | *font-size: 90%; /*IE 6/7 - To reduce IE's oversized button text*/ 35 | *overflow: visible; /*IE 6/7 - Because of IE's overly large left/right padding on buttons */ 36 | padding: 0.5em 1.5em 0.5em; 37 | color: #0f0f0f; /* rgba not supported (IE 8) */ 38 | /* color: rgba(0, 0, 0, 0.80); rgba supported */ 39 | /* *color: #444; IE 6 & 7 */ 40 | border: 1px solid #b6b4b4; /*IE 6/7/8*/ 41 | border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ 42 | background-color: #c0bfbf; 43 | border-radius: 2px; 44 | text-decoration: none; 45 | -webkit-font-smoothing: antialiased; 46 | /* Transitions */ 47 | -webkit-transition: 0.1s linear -webkit-box-shadow; 48 | -moz-transition: 0.1s linear -moz-box-shadow; 49 | -ms-transition: 0.1s linear box-shadow; 50 | -o-transition: 0.1s linear box-shadow; 51 | transition: 0.1s linear box-shadow; 52 | } 53 | 54 | .pure-button-hover, 55 | .pure-button:hover { 56 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#00000000', GradientType=0); 57 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.05))); 58 | background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.15)); 59 | background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.05)); 60 | background-image: -ms-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.15)); 61 | background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.05)); 62 | background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.05)); 63 | } 64 | 65 | .pure-button-active, 66 | .pure-button:active { 67 | box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset; 68 | } 69 | 70 | .pure-button[disabled], 71 | .pure-button-disabled, 72 | .pure-button-disabled:hover, 73 | .pure-button-disabled:active { 74 | border: none; 75 | background-image: none; 76 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 77 | filter: alpha(opacity=40); 78 | -khtml-opacity: 0.40; 79 | -moz-opacity: 0.40; 80 | opacity: 0.40; 81 | cursor: not-allowed; 82 | box-shadow: none; 83 | } 84 | 85 | .pure-button-hidden { 86 | display: none; 87 | } 88 | 89 | /* Firefox: Get rid of the inner focus border */ 90 | .pure-button::-moz-focus-inner{ 91 | padding: 0; 92 | border: 0; 93 | } 94 | 95 | .pure-button-primary, 96 | .pure-button-selected, 97 | a.pure-button-primary, 98 | a.pure-button-selected { 99 | background-color: #B9410E; 100 | color: #fffcfa; 101 | } 102 | 103 | .pure-button:-moz-focusring { 104 | outline-color: rgba(0, 0, 0, 0.85); 105 | } 106 | 107 | 108 | /*! Copyright 2013 Yahoo! Inc. http://yuilibrary.com/license/ */ 109 | /* This page lists core form styles adopted from Normalize.css. */ 110 | /*! Copyright (c) Nicolas Gallagher and Jonathan Neal */ 111 | 112 | /*! normalize.css v1.1.0 | MIT License | git.io/normalize */ 113 | 114 | /* This page has Normalize.css form-specific style rules applied to a .yui3-form context */ 115 | 116 | /* ========== 117 | Forms Core 118 | =========*/ 119 | 120 | 121 | /* 122 | * Corrects margin displayed oddly in IE 6/7. 123 | */ 124 | 125 | .pure-skin-bugger .pure-form { 126 | margin: 0; 127 | } 128 | 129 | /* Define consistent border, margin, and padding.*/ 130 | 131 | 132 | .pure-skin-bugger .pure-form fieldset { 133 | border: 1px solid #c0c0c0; 134 | margin: 0 2px; 135 | padding: 0.35em 0.625em 0.75em; 136 | } 137 | 138 | /* 139 | * 1. Corrects color not being inherited in IE 6/7/8/9. 140 | * 2. Corrects text not wrapping in Firefox 3. 141 | * 3. Corrects alignment displayed oddly in IE 6/7. 142 | */ 143 | 144 | .pure-skin-bugger .pure-form legend { 145 | border: 0; /* 1 */ 146 | padding: 0; 147 | white-space: normal; /* 2 */ 148 | *margin-left: -7px; /* 3 */ 149 | } 150 | 151 | /* 152 | * 1. Corrects font size not being inherited in all browsers. 153 | * 2. Addresses margins set differently in IE 6/7, Firefox 3+, Safari 5, 154 | * and Chrome. 155 | * 3. Improves appearance and consistency in all browsers. 156 | */ 157 | 158 | .pure-skin-bugger .pure-form button, 159 | .pure-skin-bugger .pure-form input, 160 | .pure-skin-bugger .pure-form select, 161 | .pure-skin-bugger .pure-form textarea { 162 | font-size: 100%; /* 1 */ 163 | margin: 0; /* 2 */ 164 | vertical-align: baseline; /* 3 */ 165 | *vertical-align: middle; /* 3 */ 166 | } 167 | 168 | /* 169 | * Addresses Firefox 3+ setting `line-height` on `input` using `!important` in 170 | * the UA stylesheet. 171 | */ 172 | 173 | .pure-skin-bugger .pure-form button, 174 | .pure-skin-bugger .pure-form input { 175 | line-height: normal; 176 | } 177 | 178 | /* 179 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 180 | * and `video` controls. 181 | * 2. Corrects inability to style clickable `input` types in iOS. 182 | * 3. Improves usability and consistency of cursor style between image-type 183 | * `input` and others. 184 | * 4. Removes inner spacing in IE 7 without affecting normal text inputs. 185 | * Known issue: inner spacing remains in IE 6. 186 | */ 187 | 188 | .pure-skin-bugger .pure-form button, 189 | .pure-skin-bugger .pure-form input[type="button"], /* 1 */ 190 | .pure-skin-bugger .pure-form input[type="reset"], 191 | .pure-skin-bugger .pure-form input[type="submit"] { 192 | -webkit-appearance: button; /* 2 */ 193 | cursor: pointer; /* 3 */ 194 | *overflow: visible; /* 4 */ 195 | } 196 | 197 | /* 198 | * Re-set default cursor for disabled elements. 199 | */ 200 | 201 | .pure-skin-bugger .pure-form button[disabled], 202 | .pure-skin-bugger .pure-form input[disabled] { 203 | cursor: default; 204 | } 205 | 206 | /* 207 | * 1. Addresses box sizing set to content-box in IE 8/9. 208 | * 2. Removes excess padding in IE 8/9. 209 | * 3. Removes excess padding in IE 7. 210 | * Known issue: excess padding remains in IE 6. 211 | */ 212 | 213 | .pure-skin-bugger .pure-form input[type="checkbox"], 214 | .pure-skin-bugger .pure-form input[type="radio"] { 215 | box-sizing: border-box; /* 1 */ 216 | padding: 0; /* 2 */ 217 | *height: 13px; /* 3 */ 218 | *width: 13px; /* 3 */ 219 | } 220 | 221 | /* 222 | * 1. Addresses `appearance` set to `searchfield` in Safari 5 and Chrome. 223 | * 2. Addresses `box-sizing` set to `border-box` in Safari 5 and Chrome 224 | * (include `-moz` to future-proof). 225 | */ 226 | 227 | .pure-skin-bugger .pure-form input[type="search"] { 228 | -webkit-appearance: textfield; /* 1 */ 229 | -moz-box-sizing: content-box; 230 | -webkit-box-sizing: content-box; /* 2 */ 231 | box-sizing: content-box; 232 | } 233 | 234 | /* 235 | * Removes inner padding and search cancel button in Safari 5 and Chrome 236 | * on OS X. 237 | */ 238 | 239 | .pure-skin-bugger .pure-form input[type="search"]::-webkit-search-cancel-button, 240 | .pure-skin-bugger .pure-form input[type="search"]::-webkit-search-decoration { 241 | -webkit-appearance: none; 242 | } 243 | 244 | /* 245 | * Removes inner padding and border in Firefox 3+. 246 | */ 247 | 248 | .pure-skin-bugger .pure-form button::-moz-focus-inner, 249 | .pure-skin-bugger .pure-form input::-moz-focus-inner { 250 | border: 0; 251 | padding: 0; 252 | } 253 | 254 | /* 255 | * 1. Removes default vertical scrollbar in IE 6/7/8/9. 256 | * 2. Improves readability and alignment in all browsers. 257 | */ 258 | 259 | .pure-skin-bugger .pure-form textarea { 260 | overflow: auto; /* 1 */ 261 | vertical-align: top; /* 2 */ 262 | } 263 | /* =============== forms-responsive.css ================ 264 | 265 | =========================================================*/ 266 | @media only screen and (max-width : 480px) { 267 | .pure-skin-bugger .pure-form button[type="submit"] { 268 | margin: 0.7em 0 0; 269 | } 270 | 271 | .pure-skin-bugger .pure-form input[type="text"], 272 | .pure-skin-bugger .pure-form input[type="password"], 273 | .pure-skin-bugger .pure-form input[type="email"], 274 | .pure-skin-bugger .pure-form input[type="url"], 275 | .pure-skin-bugger .pure-form input[type="date"], 276 | .pure-skin-bugger .pure-form input[type="month"], 277 | .pure-skin-bugger .pure-form input[type="time"], 278 | .pure-skin-bugger .pure-form input[type="datetime"], 279 | .pure-skin-bugger .pure-form input[type="datetime-local"], 280 | .pure-skin-bugger .pure-form input[type="week"], 281 | .pure-skin-bugger .pure-form input[type="number"], 282 | .pure-skin-bugger .pure-form input[type="search"], 283 | .pure-skin-bugger .pure-form input[type="tel"], 284 | .pure-skin-bugger .pure-form input[type="color"], 285 | .pure-skin-bugger .pure-form label { 286 | margin-bottom: 0.3em; 287 | display: block; 288 | } 289 | 290 | .pure-skin-bugger .pure-group input[type="text"], 291 | .pure-skin-bugger .pure-group input[type="password"], 292 | .pure-skin-bugger .pure-group input[type="email"], 293 | .pure-skin-bugger .pure-group input[type="url"], 294 | .pure-skin-bugger .pure-group input[type="date"], 295 | .pure-skin-bugger .pure-group input[type="month"], 296 | .pure-skin-bugger .pure-group input[type="time"], 297 | .pure-skin-bugger .pure-group input[type="datetime"], 298 | .pure-skin-bugger .pure-group input[type="datetime-local"], 299 | .pure-skin-bugger .pure-group input[type="week"], 300 | .pure-skin-bugger .pure-group input[type="number"], 301 | .pure-skin-bugger .pure-group input[type="search"], 302 | .pure-skin-bugger .pure-group input[type="tel"], 303 | .pure-skin-bugger .pure-group input[type="color"] { 304 | margin-bottom: 0; 305 | } 306 | 307 | .pure-skin-bugger .pure-form-aligned .pure-control-group label { 308 | margin-bottom: 0.3em; 309 | text-align: left; 310 | display: block; 311 | width: 100%; 312 | } 313 | 314 | .pure-skin-bugger .pure-form-aligned .pure-controls { 315 | margin: 1.5em 0 0 0; 316 | } 317 | 318 | /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ 319 | .pure-skin-bugger .pure-form .pure-help-inline, 320 | .pure-skin-bugger .pure-form-message-inline, 321 | .pure-skin-bugger .pure-form-message { 322 | display: block; 323 | font-size: 80%; 324 | /* increased bottom padding to make it group with its related input element */ 325 | padding: 0.2em 0 0.8em; 326 | } 327 | } 328 | 329 | /* =============== forms.css ================ 330 | 331 | =========================================================*/ 332 | .pure-skin-bugger .pure-form input[type="text"], 333 | .pure-skin-bugger .pure-form input[type="password"], 334 | .pure-skin-bugger .pure-form input[type="email"], 335 | .pure-skin-bugger .pure-form input[type="url"], 336 | .pure-skin-bugger .pure-form input[type="date"], 337 | .pure-skin-bugger .pure-form input[type="month"], 338 | .pure-skin-bugger .pure-form input[type="time"], 339 | .pure-skin-bugger .pure-form input[type="datetime"], 340 | .pure-skin-bugger .pure-form input[type="datetime-local"], 341 | .pure-skin-bugger .pure-form input[type="week"], 342 | .pure-skin-bugger .pure-form input[type="number"], 343 | .pure-skin-bugger .pure-form input[type="search"], 344 | .pure-skin-bugger .pure-form input[type="tel"], 345 | .pure-skin-bugger .pure-form input[type="color"], 346 | .pure-skin-bugger .pure-form select, 347 | .pure-skin-bugger .pure-form textarea { 348 | padding: 0.5em 0.6em; 349 | display: inline-block; 350 | border: 1px solid #e6e6e6; 351 | font-size: 0.8em; 352 | box-shadow: inset 0 1px 3px #e6e6e6; 353 | border-radius: 4px; 354 | -webkit-transition: 0.3s linear border; 355 | -moz-transition: 0.3s linear border; 356 | -ms-transition: 0.3s linear border; 357 | -o-transition: 0.3s linear border; 358 | transition: 0.3s linear border; 359 | -webkit-box-sizing: border-box; 360 | -moz-box-sizing: border-box; 361 | box-sizing: border-box; 362 | -webkit-font-smoothing: antialiased; 363 | } 364 | 365 | .pure-skin-bugger .pure-form input[type="text"]:focus, 366 | .pure-skin-bugger .pure-form input[type="password"]:focus, 367 | .pure-skin-bugger .pure-form input[type="email"]:focus, 368 | .pure-skin-bugger .pure-form input[type="url"]:focus, 369 | .pure-skin-bugger .pure-form input[type="date"]:focus, 370 | .pure-skin-bugger .pure-form input[type="month"]:focus, 371 | .pure-skin-bugger .pure-form input[type="time"]:focus, 372 | .pure-skin-bugger .pure-form input[type="datetime"]:focus, 373 | .pure-skin-bugger .pure-form input[type="datetime-local"]:focus, 374 | .pure-skin-bugger .pure-form input[type="week"]:focus, 375 | .pure-skin-bugger .pure-form input[type="number"]:focus, 376 | .pure-skin-bugger .pure-form input[type="search"]:focus, 377 | .pure-skin-bugger .pure-form input[type="tel"]:focus, 378 | .pure-skin-bugger .pure-form input[type="color"]:focus, 379 | .pure-skin-bugger .pure-form select:focus, 380 | .pure-skin-bugger .pure-form textarea:focus { 381 | outline: 0; 382 | outline: thin dotted \9; /* IE6-9 */ 383 | border-color: #129FEA; 384 | } 385 | 386 | .pure-skin-bugger .pure-form input[type="file"]:focus, 387 | .pure-skin-bugger .pure-form input[type="radio"]:focus, 388 | .pure-skin-bugger .pure-form input[type="checkbox"]:focus { 389 | outline: thin dotted #333; 390 | outline: 1px auto #129FEA; 391 | } 392 | .pure-skin-bugger .pure-form .pure-checkbox, 393 | .pure-skin-bugger .pure-form .pure-radio { 394 | margin: 0.5em 0; 395 | display: block; 396 | } 397 | .pure-skin-bugger .pure-form input[type="text"][disabled], 398 | .pure-skin-bugger .pure-form input[type="password"][disabled], 399 | .pure-skin-bugger .pure-form input[type="email"][disabled], 400 | .pure-skin-bugger .pure-form input[type="url"][disabled], 401 | .pure-skin-bugger .pure-form input[type="date"][disabled], 402 | .pure-skin-bugger .pure-form input[type="month"][disabled], 403 | .pure-skin-bugger .pure-form input[type="time"][disabled], 404 | .pure-skin-bugger .pure-form input[type="datetime"][disabled], 405 | .pure-skin-bugger .pure-form input[type="datetime-local"][disabled], 406 | .pure-skin-bugger .pure-form input[type="week"][disabled], 407 | .pure-skin-bugger .pure-form input[type="number"][disabled], 408 | .pure-skin-bugger .pure-form input[type="search"][disabled], 409 | .pure-skin-bugger .pure-form input[type="tel"][disabled], 410 | .pure-skin-bugger .pure-form input[type="color"][disabled], 411 | .pure-skin-bugger .pure-form select[disabled], 412 | .pure-skin-bugger .pure-form textarea[disabled], 413 | .pure-skin-bugger .pure-form input[readonly], 414 | .pure-skin-bugger .pure-form select[readonly], 415 | .pure-skin-bugger .pure-form textarea[readonly] { 416 | cursor: not-allowed; 417 | box-shadow: inset 0 1px 10px #ededed; 418 | background-color: #fff; 419 | color: #adadad; 420 | border-color: #e6e6e6; 421 | } 422 | .pure-skin-bugger .pure-form input:focus:invalid, 423 | .pure-skin-bugger .pure-form textarea:focus:invalid, 424 | .pure-skin-bugger .pure-form select:focus:invalid { 425 | color: #b94a48; 426 | border: 1px solid #ee5f5b; 427 | } 428 | .pure-skin-bugger .pure-form input:focus:invalid:focus, 429 | .pure-skin-bugger .pure-form textarea:focus:invalid:focus, 430 | .pure-skin-bugger .pure-form select:focus:invalid:focus { 431 | border-color: #e9322d; 432 | } 433 | .pure-skin-bugger .pure-form input[type="file"]:focus:invalid:focus, 434 | .pure-skin-bugger .pure-form input[type="radio"]:focus:invalid:focus, 435 | .pure-skin-bugger .pure-form input[type="checkbox"]:focus:invalid:focus { 436 | outline-color: #e9322d; 437 | } 438 | .pure-skin-bugger .pure-form select { 439 | border: 1px solid #e6e6e6; 440 | background-color: white; 441 | } 442 | .pure-skin-bugger .pure-form select[multiple] { 443 | height: auto; 444 | } 445 | .pure-skin-bugger .pure-form label { 446 | margin: 0.5em 0 0.2em; 447 | color: #4f4f4f; 448 | font-size:90%; 449 | } 450 | .pure-skin-bugger .pure-form fieldset { 451 | margin: 0; 452 | padding: 0.35em 0 0.75em; 453 | border: 0; 454 | } 455 | .pure-skin-bugger .pure-form legend { 456 | display: block; 457 | width: 100%; 458 | padding: 0.3em 0; 459 | margin-bottom: 0.3em; 460 | font-size: 125%; 461 | color: #262626; 462 | border-bottom: 1px solid #ededed; 463 | } 464 | 465 | .pure-skin-bugger .pure-form-stacked label { 466 | display: block; 467 | } 468 | 469 | .pure-skin-bugger .pure-form-aligned input, 470 | .pure-skin-bugger .pure-form-aligned textarea, 471 | .pure-skin-bugger .pure-form-aligned select, 472 | .pure-skin-bugger .pure-form-aligned .pure-help-inline, /* note: pure-help-inline is deprecated. Use .pure-form-message-inline instead */ 473 | .pure-form-message-inline { 474 | display: inline-block; 475 | *display: inline; /* IE7 inline-block hack */ 476 | *zoom: 1; 477 | vertical-align: middle; 478 | } 479 | 480 | /* aligned Forms */ 481 | .pure-skin-bugger .pure-form-aligned .pure-control-group { 482 | margin-bottom: 0.5em; 483 | } 484 | .pure-skin-bugger .pure-form-aligned .pure-control-group label { 485 | text-align: right; 486 | display: inline-block; 487 | vertical-align: middle; 488 | width: 10em; 489 | margin: 0 1em 0 0; 490 | } 491 | .pure-skin-bugger .pure-form-aligned .pure-controls { 492 | margin: 1.5em 0 0 10em; 493 | } 494 | 495 | /* Rounded Inputs */ 496 | .pure-skin-bugger .pure-form .pure-input-rounded { 497 | border-radius: 30px; 498 | padding-left: 1em; 499 | } 500 | 501 | /* Grouped Inputs */ 502 | .pure-skin-bugger .pure-form .pure-group fieldset { 503 | margin-bottom: 10px; 504 | } 505 | .pure-skin-bugger .pure-form .pure-group input { 506 | display: block; 507 | padding: 0.5em 0.6em; 508 | margin: 0; 509 | border-radius: 0; 510 | position: relative; 511 | top: -1px; 512 | } 513 | .pure-skin-bugger .pure-form .pure-group input:focus { 514 | z-index: 2; 515 | } 516 | .pure-skin-bugger .pure-form .pure-group input:first-child { 517 | top: 1px; 518 | border-radius: 4px 4px 0px 0px; 519 | } 520 | .pure-skin-bugger .pure-form .pure-group input:last-child { 521 | top: -2px; 522 | border-radius: 0px 0px 4px 4px; 523 | } 524 | .pure-skin-bugger .pure-form .pure-group button { 525 | margin: 0.35em 0; 526 | } 527 | 528 | .pure-skin-bugger .pure-form .pure-input-1 { 529 | width: 100%; 530 | } 531 | .pure-skin-bugger .pure-form .pure-input-2-3 { 532 | width: 66%; 533 | } 534 | .pure-skin-bugger .pure-form .pure-input-1-2 { 535 | width: 50%; 536 | } 537 | .pure-skin-bugger .pure-form .pure-input-1-3 { 538 | width: 33%; 539 | } 540 | .pure-skin-bugger .pure-form .pure-input-1-4 { 541 | width: 25%; 542 | } 543 | 544 | /* Inline help for forms */ 545 | /* Note: pure-help-inline is deprecated. Use .pure-form-message-inline instead */ 546 | .pure-skin-bugger .pure-form .pure-help-inline, 547 | .pure-skin-bugger .pure-form-message-inline { 548 | display: inline-block; 549 | padding-left: 0.3em; 550 | color: #adadad; 551 | font-size: 90%; 552 | vertical-align: middle; 553 | } 554 | 555 | /* Block help for forms */ 556 | .pure-skin-bugger .pure-form-message { 557 | display: block; 558 | margin: .5em 0 .2em; 559 | color: #adadad; 560 | font-size: 90%; 561 | } 562 | 563 | /* foundational CSS */ 564 | .pure-skin-bugger .pure-table { 565 | /* Remove spacing between table cells (from Normalize.css) */ 566 | border-collapse: separate; 567 | border-spacing: 0; 568 | empty-cells: show; 569 | border: 1px solid #dedede; 570 | } 571 | 572 | .pure-skin-bugger .pure-table caption { 573 | color: #adadad; 574 | font: italic 85%/1 arial, sans-serif; 575 | padding: 1em 0; 576 | text-align: center; 577 | } 578 | 579 | .pure-skin-bugger .pure-table td, 580 | .pure-skin-bugger .pure-table th { 581 | border-left: 1px solid #dedede;/* inner column border */ 582 | border-width: 0 0 0 1px; 583 | font-size: inherit; 584 | margin: 0; 585 | overflow: visible; /*to make ths where the title is really long work*/ 586 | padding: 0.3em 0.6em; /* cell padding */ 587 | } 588 | 589 | .pure-skin-bugger .pure-table td:first-child, 590 | .pure-skin-bugger .pure-table th:first-child { 591 | border-left-width: 0; 592 | } 593 | 594 | .pure-skin-bugger .pure-table thead { 595 | background-color: #d7d6d6; 596 | color: #272626; 597 | text-align: left; 598 | vertical-align: bottom; 599 | white-space: nowrap; 600 | } 601 | 602 | /* 603 | striping: 604 | even - #fff (white) 605 | odd - #edf5ff (light blue) 606 | */ 607 | .pure-skin-bugger .pure-table td { 608 | background-color: #ededed; 609 | color: #404040; 610 | } 611 | .pure-skin-bugger .pure-table-odd td { 612 | background-color: #dedede; 613 | color: #262626; 614 | } 615 | 616 | /* BORDERED TABLES */ 617 | .pure-skin-bugger .pure-table-bordered td { 618 | border-bottom:1px solid #dedede; 619 | } 620 | .pure-skin-bugger .pure-table-bordered tbody > tr:last-child td, 621 | .pure-skin-bugger .pure-table-horizontal tbody > tr:last-child td { 622 | border-bottom-width: 0; 623 | } 624 | 625 | /* HORIZONTAL BORDERED TABLES */ 626 | .pure-skin-bugger .pure-table-horizontal td, 627 | .pure-skin-bugger .pure-table-horizontal th { 628 | border-width: 0 0 1px 0; 629 | border-bottom:1px solid #dedede; 630 | } 631 | .pure-skin-bugger .pure-table-horizontal tbody > tr:last-child td { 632 | border-bottom-width: 0; 633 | } 634 | 635 | /* from YUICSS list-core.css */ 636 | /*csslint adjoining-classes:false, outline-none:false*/ 637 | /*TODO: Remove this lint rule override after a refactor of this code.*/ 638 | 639 | .pure-skin-bugger .pure-menu ul { 640 | position: absolute; 641 | visibility: hidden; 642 | } 643 | 644 | .pure-skin-bugger .pure-menu.pure-menu-open { 645 | visibility: visible; 646 | z-index: 2; 647 | width: 100%; 648 | } 649 | 650 | .pure-skin-bugger .pure-menu ul { 651 | left: -10000px; 652 | list-style: none; 653 | margin: 0; 654 | padding: 0; 655 | top: -10000px; 656 | z-index: 1; 657 | } 658 | 659 | .pure-skin-bugger .pure-menu > ul { position: relative; } 660 | 661 | .pure-skin-bugger .pure-menu-open > ul { 662 | left: 0; 663 | top: 0; 664 | visibility: visible; 665 | } 666 | 667 | .pure-skin-bugger .pure-menu-open > ul:focus { 668 | outline: none; 669 | } 670 | 671 | .pure-skin-bugger .pure-menu li { 672 | position: relative; 673 | } 674 | 675 | .pure-skin-bugger .pure-menu a, .pure-skin-bugger .pure-menu .pure-menu-heading { 676 | display: block; 677 | color: inherit; 678 | line-height: 1.5em; 679 | padding: 0.35em 1.4em; 680 | text-decoration: none; 681 | white-space: nowrap; 682 | } 683 | 684 | .pure-skin-bugger .pure-menu.pure-menu-horizontal > .pure-menu-heading { 685 | display: inline-block; 686 | *display: inline; 687 | zoom: 1; 688 | margin: 0; 689 | vertical-align: middle; 690 | } 691 | .pure-skin-bugger .pure-menu.pure-menu-horizontal > ul { 692 | display: inline-block; 693 | *display: inline; 694 | zoom: 1; 695 | vertical-align: middle; 696 | height: 2.4em; 697 | } 698 | 699 | .pure-skin-bugger .pure-menu li a { padding: 0.35em 1.4em; } 700 | 701 | .pure-skin-bugger .pure-menu-can-have-children > .pure-menu-label:after { 702 | content: '\25B8'; 703 | float: right; 704 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'DejaVu Sans', sans-serif; /* These specific fonts have the Unicode char we need. */ 705 | margin-right: -20px; 706 | margin-top: -1px; 707 | } 708 | 709 | .pure-skin-bugger .pure-menu-can-have-children > .pure-menu-label { 710 | padding-right: 30px; 711 | } 712 | 713 | .pure-skin-bugger .pure-menu-separator { 714 | background-color: #dedede; 715 | display: block; 716 | height: 1px; 717 | font-size: 0; 718 | margin: 7px 2px; 719 | overflow: hidden; 720 | } 721 | 722 | .pure-skin-bugger .pure-menu-hidden { 723 | display: none; 724 | } 725 | 726 | /* FIXED MENU */ 727 | .pure-skin-bugger .pure-menu-fixed { 728 | position: fixed; 729 | top:0; 730 | left:0; 731 | width: 100%; 732 | } 733 | 734 | 735 | /* HORIZONTAL MENU CODE */ 736 | 737 | /* Initial menus should be inline-block so that they are horizontal */ 738 | .pure-skin-bugger .pure-menu-horizontal li { 739 | display: inline-block; 740 | *display: inline; 741 | zoom: 1; 742 | vertical-align: middle; 743 | } 744 | 745 | /* Submenus should still be display:block; */ 746 | .pure-skin-bugger .pure-menu-horizontal li li { 747 | display: block; 748 | } 749 | 750 | /* Content after should be down arrow */ 751 | .pure-skin-bugger .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label:after { 752 | content: "\25BE"; 753 | } 754 | /*Add extra padding to elements that have the arrow so that the hover looks nice */ 755 | .pure-skin-bugger .pure-menu-horizontal > .pure-menu-children > .pure-menu-can-have-children > .pure-menu-label { 756 | padding-right:30px; 757 | } 758 | 759 | /* Adjusting separator for vertical menus */ 760 | .pure-skin-bugger .pure-menu-horizontal li.pure-menu-separator { 761 | height: 50%; 762 | width: 1px; 763 | margin: 0 7px; 764 | } 765 | 766 | /* Submenus should be horizontal separator again */ 767 | .pure-skin-bugger .pure-menu-horizontal li li.pure-menu-separator { 768 | height: 1px; 769 | width: auto; 770 | margin: 7px 2px; 771 | } 772 | 773 | 774 | /* end from yuicss/list-core.css *******************************************/ 775 | /* from yuicss list-paginator.css */ 776 | /*csslint box-model:false*/ 777 | /*TODO: Remove this lint rule override after a refactor of this code.*/ 778 | 779 | .pure-skin-bugger .pure-paginator { 780 | list-style: none; 781 | margin: 0; 782 | padding: 0; 783 | } 784 | .pure-skin-bugger .pure-paginator li { 785 | display: inline-block; 786 | *display: inline; 787 | zoom: 1; 788 | margin: 0 -0.35em 0 0; 789 | } 790 | .pure-skin-bugger .pure-paginator .pure-button { 791 | border-radius: 0; 792 | padding: 0.8em 1.4em; 793 | vertical-align: top; 794 | height: 1.1em; 795 | } 796 | .pure-skin-bugger .pure-paginator .pure-button:focus { 797 | outline-style: none; 798 | } 799 | .pure-skin-bugger .pure-paginator .prev, .pure-skin-bugger .pure-paginator .next { 800 | /*color: #C0C1C3; allow .pure-button to color text*/ 801 | } 802 | .pure-skin-bugger .pure-paginator .prev { 803 | border-radius: 4px 0px 0px 4px; 804 | } 805 | .pure-skin-bugger .pure-paginator .next { 806 | border-radius: 0px 4px 4px 0px; 807 | } 808 | /* end from YUICSS list-paginator.css ******************************/ 809 | /* from YUICSS list.css *******************************************/ 810 | /* MAIN MENU STYLING */ 811 | /*csslint adjoining-classes:false*/ 812 | /*TODO: Remove this lint rule override after a refactor of this code.*/ 813 | 814 | .pure-skin-bugger .pure-menu.pure-menu-open, 815 | .pure-skin-bugger .pure-menu.pure-menu-horizontal li .pure-menu-children { 816 | background: #ededed; /* Old browsers */ 817 | border: 1px solid #dedede; 818 | } 819 | 820 | /* remove borders for horizontal menus */ 821 | .pure-skin-bugger .pure-menu.pure-menu-horizontal, 822 | .pure-skin-bugger .pure-menu.pure-menu-horizontal .pure-menu-heading { 823 | border: none; 824 | } 825 | 826 | 827 | 828 | /* LINK STYLES */ 829 | 830 | .pure-skin-bugger .pure-menu a { 831 | border: 1px solid transparent; 832 | border-left: none; 833 | border-right: none; 834 | 835 | } 836 | 837 | .pure-skin-bugger .pure-menu a, 838 | .pure-skin-bugger .pure-menu .pure-menu-can-have-children > li:after { 839 | color: #404040; 840 | } 841 | 842 | .pure-skin-bugger .pure-menu .pure-menu-can-have-children > li:hover:after { 843 | color: #262626; 844 | } 845 | 846 | /* Focus style for a dropdown menu-item when the parent has been opened */ 847 | .pure-skin-bugger .pure-menu .pure-menu-open { 848 | background: #d6d6d6; 849 | } 850 | 851 | /* HOVER STATES */ 852 | .pure-skin-bugger .pure-menu li a:hover { 853 | background: #d6d6d6; 854 | } 855 | 856 | /* DISABLED STATES */ 857 | .pure-skin-bugger .pure-menu li.pure-menu-disabled a:hover { 858 | background: #ededed; 859 | color: #9e9e9e; 860 | } 861 | 862 | .pure-skin-bugger .pure-menu .pure-menu-disabled > a { 863 | background-image: none; 864 | border-color: transparent; 865 | cursor: default; 866 | } 867 | 868 | .pure-skin-bugger .pure-menu .pure-menu-disabled > a, 869 | .pure-skin-bugger .pure-menu .pure-menu-can-have-children.pure-menu-disabled > a:after { 870 | color: #9e9e9e; 871 | } 872 | 873 | /* HEADINGS */ 874 | .pure-skin-bugger .pure-menu .pure-menu-heading { 875 | color: #171717; 876 | text-transform: uppercase; 877 | font-size: 90%; 878 | margin-top: 0.5em; 879 | border-bottom: solid 1px #dedede; 880 | } 881 | 882 | 883 | /* SELECTED MENU ITEM */ 884 | .pure-skin-bugger .pure-menu li.pure-menu-selected a { 885 | background-color: #B9410E; 886 | color: #fffcfa; 887 | } 888 | 889 | /* FIXED MENU */ 890 | .pure-skin-bugger .pure-menu.pure-menu-open.pure-menu-fixed { 891 | border: none; 892 | border-bottom: 1px solid #dedede; 893 | } 894 | /* end from YUICSS list.css ***********************************/ 895 | /* from YUICSS list-responsive.css ****************************/ 896 | /* RESPONSIVE */ 897 | 898 | @media (max-width: 480px) { 899 | 900 | .pure-skin-bugger .pure-menu-horizontal { 901 | width:100%; 902 | } 903 | 904 | .pure-skin-bugger .pure-menu-children li { 905 | display: block; 906 | border-bottom:1px solid #dedede; 907 | } 908 | 909 | } 910 | /* end from list-responsive.css ******************/ 911 | --------------------------------------------------------------------------------