├── .env ├── requestbin ├── storage │ ├── __init__.py │ ├── memory.py │ └── redis.py ├── static │ ├── robots.txt │ ├── lock.png │ ├── favicon.ico │ ├── img │ │ ├── logo.png │ │ ├── ico-1.png │ │ ├── ico-2.png │ │ ├── ico-3.png │ │ ├── ico-4.png │ │ ├── logo-2x.png │ │ ├── bg-stripe.png │ │ ├── runscope-hero.png │ │ ├── logo-runscope-1x.png │ │ ├── logo-runscope-2x.png │ │ ├── glyphicons-halflings.png │ │ └── glyphicons-halflings-white.png │ ├── font │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff │ ├── less │ │ ├── layouts.less │ │ ├── component-animations.less │ │ ├── utilities.less │ │ ├── grid.less │ │ ├── breadcrumbs.less │ │ ├── responsive-768px-979px.less │ │ ├── hero-unit.less │ │ ├── wells.less │ │ ├── responsive-1200px-min.less │ │ ├── close.less │ │ ├── accordion.less │ │ ├── pager.less │ │ ├── media.less │ │ ├── scaffolding.less │ │ ├── responsive.less │ │ ├── thumbnails.less │ │ ├── code.less │ │ ├── alerts.less │ │ ├── bootstrap.less │ │ ├── responsive-utilities.less │ │ ├── tooltip.less │ │ ├── labels-badges.less │ │ ├── modals.less │ │ ├── pagination.less │ │ ├── carousel.less │ │ ├── progress-bars.less │ │ ├── popovers.less │ │ ├── responsive-767px-max.less │ │ ├── responsive-navbar.less │ │ ├── reset.less │ │ ├── buttons.less │ │ ├── type.less │ │ ├── button-groups.less │ │ ├── dropdowns.less │ │ ├── tables.less │ │ ├── navs.less │ │ ├── variables.less │ │ ├── custom.less │ │ ├── sprites.less │ │ └── navbar.less │ ├── css │ │ ├── prettify.css │ │ └── styles.css │ └── js │ │ └── prettify.js ├── templates │ ├── doc.html │ ├── home.html │ ├── layout.html │ └── bin.html ├── util.py ├── db.py ├── config.py ├── views.py ├── api.py ├── __init__.py ├── filters.py └── models.py ├── runtime.txt ├── Procfile ├── .gitignore ├── web.py ├── docker-compose.yml ├── requirements.txt ├── setup.py ├── app.json ├── Dockerfile ├── LICENSE └── README.md /.env: -------------------------------------------------------------------------------- 1 | workon requestbin 2 | -------------------------------------------------------------------------------- /requestbin/storage/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-2.7.16 2 | -------------------------------------------------------------------------------- /requestbin/static/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: / -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: gunicorn --worker-class gevent --workers 2 --max-requests 1000 requestbin:app -------------------------------------------------------------------------------- /requestbin/static/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/lock.png -------------------------------------------------------------------------------- /requestbin/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/favicon.ico -------------------------------------------------------------------------------- /requestbin/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/logo.png -------------------------------------------------------------------------------- /requestbin/static/img/ico-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/ico-1.png -------------------------------------------------------------------------------- /requestbin/static/img/ico-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/ico-2.png -------------------------------------------------------------------------------- /requestbin/static/img/ico-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/ico-3.png -------------------------------------------------------------------------------- /requestbin/static/img/ico-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/ico-4.png -------------------------------------------------------------------------------- /requestbin/static/img/logo-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/logo-2x.png -------------------------------------------------------------------------------- /requestbin/static/img/bg-stripe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/bg-stripe.png -------------------------------------------------------------------------------- /requestbin/static/font/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/font/FontAwesome.otf -------------------------------------------------------------------------------- /requestbin/static/img/runscope-hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/runscope-hero.png -------------------------------------------------------------------------------- /requestbin/static/img/logo-runscope-1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/logo-runscope-1x.png -------------------------------------------------------------------------------- /requestbin/static/img/logo-runscope-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/logo-runscope-2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/**/*.pyc 2 | *.egg-info 3 | **/*.pyc 4 | serviced.log 5 | 6 | codekit-config.json 7 | 8 | # Mac Files 9 | **/.DS_Store 10 | -------------------------------------------------------------------------------- /requestbin/static/font/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/font/fontawesome-webfont.eot -------------------------------------------------------------------------------- /requestbin/static/font/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/font/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /requestbin/static/font/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/font/fontawesome-webfont.woff -------------------------------------------------------------------------------- /requestbin/static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /requestbin/static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adaptive/requestbin/master/requestbin/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /web.py: -------------------------------------------------------------------------------- 1 | from requestbin import config 2 | import os 3 | 4 | from requestbin import app 5 | 6 | if __name__ == "__main__": 7 | port = int(os.environ.get('PORT', config.PORT_NUMBER)) 8 | app.run(host='0.0.0.0', port=port, debug=config.DEBUG) -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | app: 2 | build: . 3 | environment: 4 | REALM: prod 5 | REDIS_URL: "//redis:6379" 6 | links: 7 | - redis 8 | ports: 9 | - "8000:8000" 10 | 11 | redis: 12 | image: redis 13 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | gevent==1.3.7 2 | greenlet==0.4.15 3 | ProxyTypes==0.10.0 4 | nose==1.3.7 5 | wsgiref==0.1.2 6 | feedparser==5.2.1 7 | Jinja2==2.10 8 | Werkzeug==0.14.1 9 | Flask==1.0.2 10 | Flask-Cors==3.0.6 11 | redis==2.10.6 12 | msgpack-python==0.5.6 13 | python-dateutil==2.7.3 14 | gunicorn 15 | bugsnag 16 | blinker 17 | -------------------------------------------------------------------------------- /requestbin/templates/doc.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block head %} 3 | 6 | {% endblock %} 7 | {% block content %} 8 | 11 | {{content|safe}} 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | from setuptools import setup, find_packages 4 | 5 | setup( 6 | name='requestbin', 7 | version='2.0.0', 8 | author='Runscope', 9 | author_email='requestbin@runscope.com', 10 | description='HTTP request collector and inspector', 11 | packages=find_packages(), 12 | install_requires=['feedparser'], 13 | data_files=[], 14 | ) 15 | -------------------------------------------------------------------------------- /requestbin/static/less/layouts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Layouts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Container (centered, fixed-width layouts) 7 | .container { 8 | .container-fixed(); 9 | } 10 | 11 | // Fluid layouts (left aligned, with sidebar, min- & max-width content) 12 | .container-fluid { 13 | padding-right: @gridGutterWidth; 14 | padding-left: @gridGutterWidth; 15 | .clearfix(); 16 | } -------------------------------------------------------------------------------- /requestbin/static/less/component-animations.less: -------------------------------------------------------------------------------- 1 | // 2 | // Component animations 3 | // -------------------------------------------------- 4 | 5 | 6 | .fade { 7 | opacity: 0; 8 | .transition(opacity .15s linear); 9 | &.in { 10 | opacity: 1; 11 | } 12 | } 13 | 14 | .collapse { 15 | position: relative; 16 | height: 0; 17 | overflow: hidden; 18 | .transition(height .35s ease); 19 | &.in { 20 | height: auto; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /requestbin/static/less/utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // Quick floats 7 | .pull-right { 8 | float: right; 9 | } 10 | .pull-left { 11 | float: left; 12 | } 13 | 14 | // Toggling content 15 | .hide { 16 | display: none; 17 | } 18 | .show { 19 | display: block; 20 | } 21 | 22 | // Visibility 23 | .invisible { 24 | visibility: hidden; 25 | } 26 | 27 | // For Affix plugin 28 | .affix { 29 | position: fixed; 30 | } 31 | -------------------------------------------------------------------------------- /requestbin/static/less/grid.less: -------------------------------------------------------------------------------- 1 | // 2 | // Grid system 3 | // -------------------------------------------------- 4 | 5 | 6 | // Fixed (940px) 7 | #grid > .core(@gridColumnWidth, @gridGutterWidth); 8 | 9 | // Fluid (940px) 10 | #grid > .fluid(@fluidGridColumnWidth, @fluidGridGutterWidth); 11 | 12 | // Reset utility classes due to specificity 13 | [class*="span"].hide, 14 | .row-fluid [class*="span"].hide { 15 | display: none; 16 | } 17 | 18 | [class*="span"].pull-right, 19 | .row-fluid [class*="span"].pull-right { 20 | float: right; 21 | } 22 | -------------------------------------------------------------------------------- /requestbin/static/less/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Breadcrumbs 3 | // -------------------------------------------------- 4 | 5 | 6 | .breadcrumb { 7 | padding: 8px 15px; 8 | margin: 0 0 @baseLineHeight; 9 | list-style: none; 10 | background-color: #f5f5f5; 11 | .border-radius(@baseBorderRadius); 12 | > li { 13 | display: inline-block; 14 | .ie7-inline-block(); 15 | text-shadow: 0 1px 0 @white; 16 | > .divider { 17 | padding: 0 5px; 18 | color: #ccc; 19 | } 20 | } 21 | > .active { 22 | color: @grayLight; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "requestbin", 3 | "description": "Inspect HTTP requests. Debug webhooks.", 4 | "website": "http://requestb.in/", 5 | "repository": "https://github.com/Runscope/requestbin", 6 | "logo": "https://raw.githubusercontent.com/Runscope/requestbin/master/requestbin/static/img/logo-runscope-2x.png", 7 | "keywords": ["python"], 8 | "env": { 9 | "REALM": { 10 | "description": "The number of processes to run.", 11 | "value": "prod" 12 | } 13 | }, 14 | "addons": [ 15 | "heroku-redis", 16 | "papertrail:choklad" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /requestbin/static/less/responsive-768px-979px.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Tablet to desktop 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 768px) and (max-width: 979px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth768, @gridGutterWidth768); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth768, @fluidGridGutterWidth768); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth768, @gridGutterWidth768); 16 | 17 | // No need to reset .thumbnails here since it's the same @gridGutterWidth 18 | 19 | } 20 | -------------------------------------------------------------------------------- /requestbin/static/css/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /requestbin/static/less/hero-unit.less: -------------------------------------------------------------------------------- 1 | // 2 | // Hero unit 3 | // -------------------------------------------------- 4 | 5 | 6 | .hero-unit { 7 | padding: 60px; 8 | margin-bottom: 30px; 9 | font-size: 18px; 10 | font-weight: 200; 11 | line-height: @baseLineHeight * 1.5; 12 | color: @heroUnitLeadColor; 13 | background-color: @heroUnitBackground; 14 | .border-radius(6px); 15 | h1 { 16 | margin-bottom: 0; 17 | font-size: 60px; 18 | line-height: 1; 19 | color: @heroUnitHeadingColor; 20 | letter-spacing: -1px; 21 | } 22 | li { 23 | line-height: @baseLineHeight * 1.5; // Reset since we specify in type.less 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /requestbin/static/less/wells.less: -------------------------------------------------------------------------------- 1 | // 2 | // Wells 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .well { 8 | min-height: 20px; 9 | padding: 19px; 10 | margin-bottom: 20px; 11 | background-color: @wellBackground; 12 | border: 1px solid darken(@wellBackground, 7%); 13 | .border-radius(@baseBorderRadius); 14 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.05)); 15 | blockquote { 16 | border-color: #ddd; 17 | border-color: rgba(0,0,0,.15); 18 | } 19 | } 20 | 21 | // Sizes 22 | .well-large { 23 | padding: 24px; 24 | .border-radius(@borderRadiusLarge); 25 | } 26 | .well-small { 27 | padding: 9px; 28 | .border-radius(@borderRadiusSmall); 29 | } 30 | -------------------------------------------------------------------------------- /requestbin/static/less/responsive-1200px-min.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Large desktop and up 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (min-width: 1200px) { 7 | 8 | // Fixed grid 9 | #grid > .core(@gridColumnWidth1200, @gridGutterWidth1200); 10 | 11 | // Fluid grid 12 | #grid > .fluid(@fluidGridColumnWidth1200, @fluidGridGutterWidth1200); 13 | 14 | // Input grid 15 | #grid > .input(@gridColumnWidth1200, @gridGutterWidth1200); 16 | 17 | // Thumbnails 18 | .thumbnails { 19 | margin-left: -@gridGutterWidth1200; 20 | } 21 | .thumbnails > li { 22 | margin-left: @gridGutterWidth1200; 23 | } 24 | .row-fluid .thumbnails { 25 | margin-left: 0; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /requestbin/static/less/close.less: -------------------------------------------------------------------------------- 1 | // 2 | // Close icons 3 | // -------------------------------------------------- 4 | 5 | 6 | .close { 7 | float: right; 8 | font-size: 20px; 9 | font-weight: bold; 10 | line-height: @baseLineHeight; 11 | color: @black; 12 | text-shadow: 0 1px 0 rgba(255,255,255,1); 13 | .opacity(20); 14 | &:hover, 15 | &:focus { 16 | color: @black; 17 | text-decoration: none; 18 | cursor: pointer; 19 | .opacity(40); 20 | } 21 | } 22 | 23 | // Additional properties for button version 24 | // iOS requires the button element instead of an anchor tag. 25 | // If you want the anchor version, it requires `href="#"`. 26 | button.close { 27 | padding: 0; 28 | cursor: pointer; 29 | background: transparent; 30 | border: 0; 31 | -webkit-appearance: none; 32 | } -------------------------------------------------------------------------------- /requestbin/static/less/accordion.less: -------------------------------------------------------------------------------- 1 | // 2 | // Accordion 3 | // -------------------------------------------------- 4 | 5 | 6 | // Parent container 7 | .accordion { 8 | margin-bottom: @baseLineHeight; 9 | } 10 | 11 | // Group == heading + body 12 | .accordion-group { 13 | margin-bottom: 2px; 14 | border: 1px solid #e5e5e5; 15 | .border-radius(@baseBorderRadius); 16 | } 17 | .accordion-heading { 18 | border-bottom: 0; 19 | } 20 | .accordion-heading .accordion-toggle { 21 | display: block; 22 | padding: 8px 15px; 23 | } 24 | 25 | // General toggle styles 26 | .accordion-toggle { 27 | cursor: pointer; 28 | } 29 | 30 | // Inner needs the styles because you can't animate properly with any styles on the element 31 | .accordion-inner { 32 | padding: 9px 15px; 33 | border-top: 1px solid #e5e5e5; 34 | } 35 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:2.7-alpine 2 | 3 | RUN apk update && apk upgrade && \ 4 | apk add \ 5 | gcc python python-dev py-pip \ 6 | # greenlet 7 | musl-dev \ 8 | # sys/queue.h 9 | bsd-compat-headers \ 10 | # event.h 11 | libevent-dev \ 12 | && rm -rf /var/cache/apk/* 13 | 14 | # want all dependencies first so that if it's just a code change, don't have to 15 | # rebuild as much of the container 16 | ADD requirements.txt /opt/requestbin/ 17 | RUN pip install -r /opt/requestbin/requirements.txt \ 18 | && rm -rf ~/.pip/cache 19 | 20 | # the code 21 | ADD requestbin /opt/requestbin/requestbin/ 22 | 23 | EXPOSE 8000 24 | 25 | WORKDIR /opt/requestbin 26 | CMD gunicorn -b 0.0.0.0:8000 --worker-class gevent --workers 2 --max-requests 1000 requestbin:app 27 | 28 | 29 | -------------------------------------------------------------------------------- /requestbin/util.py: -------------------------------------------------------------------------------- 1 | import time 2 | import random 3 | import base64 4 | 5 | def random_byte(gradient=None, floor=0): 6 | factor = gradient or 1 7 | max = int(255 / factor) 8 | return random.randint(floor, max) * factor 9 | 10 | def solid16x16gif_datauri(r,g,b): 11 | return "data:image/gif;base64,R0lGODlhEAAQAIAA%sACH5BAQAAAAALAAAAAAQABAAAAIOhI+py+0Po5y02ouzPgUAOw==" \ 12 | % base64.b64encode(bytearray([0,r,g,b,0,0])) 13 | 14 | def random_color(): 15 | return random_byte(10, 5), random_byte(10, 5), random_byte(10, 5) 16 | 17 | def baseN(num,b,numerals="0123456789abcdefghijklmnopqrstuvwxyz"): 18 | return ((num == 0) and "0" ) or (baseN(num // b, b).lstrip("0") + numerals[num % b]) 19 | 20 | def tinyid(size=6): 21 | id = '%s%s' % ( 22 | baseN(abs(hash(time.time())), 36), 23 | baseN(abs(hash(time.time())), 36)) 24 | return id[0:size] 25 | -------------------------------------------------------------------------------- /requestbin/db.py: -------------------------------------------------------------------------------- 1 | import feedparser 2 | import time 3 | import re 4 | from requestbin import config 5 | 6 | bin_ttl = config.BIN_TTL 7 | storage_backend = config.STORAGE_BACKEND 8 | 9 | storage_module, storage_class = storage_backend.rsplit('.', 1) 10 | 11 | try: 12 | klass = getattr(__import__(storage_module, fromlist=[storage_class]), storage_class) 13 | except ImportError, e: 14 | raise ImportError("Unable to load storage backend '{}': {}".format(storage_backend, e)) 15 | 16 | db = klass(bin_ttl) 17 | 18 | def create_bin(private=False): 19 | return db.create_bin(private) 20 | 21 | def create_request(bin, request): 22 | return db.create_request(bin, request) 23 | 24 | def lookup_bin(name): 25 | name=re.split(r"[/.]", name)[0] 26 | return db.lookup_bin(name) 27 | 28 | def count_bins(): 29 | return db.count_bins() 30 | 31 | def count_requests(): 32 | return db.count_requests() 33 | 34 | def avg_req_size(): 35 | return db.avg_req_size() 36 | -------------------------------------------------------------------------------- /requestbin/static/less/pager.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pager pagination 3 | // -------------------------------------------------- 4 | 5 | 6 | .pager { 7 | margin: @baseLineHeight 0; 8 | list-style: none; 9 | text-align: center; 10 | .clearfix(); 11 | } 12 | .pager li { 13 | display: inline; 14 | } 15 | .pager li > a, 16 | .pager li > span { 17 | display: inline-block; 18 | padding: 5px 14px; 19 | background-color: #fff; 20 | border: 1px solid #ddd; 21 | .border-radius(15px); 22 | } 23 | .pager li > a:hover, 24 | .pager li > a:focus { 25 | text-decoration: none; 26 | background-color: #f5f5f5; 27 | } 28 | .pager .next > a, 29 | .pager .next > span { 30 | float: right; 31 | } 32 | .pager .previous > a, 33 | .pager .previous > span { 34 | float: left; 35 | } 36 | .pager .disabled > a, 37 | .pager .disabled > a:hover, 38 | .pager .disabled > a:focus, 39 | .pager .disabled > span { 40 | color: @grayLight; 41 | background-color: #fff; 42 | cursor: default; 43 | } -------------------------------------------------------------------------------- /requestbin/static/less/media.less: -------------------------------------------------------------------------------- 1 | // Media objects 2 | // Source: http://stubbornella.org/content/?p=497 3 | // -------------------------------------------------- 4 | 5 | 6 | // Common styles 7 | // ------------------------- 8 | 9 | // Clear the floats 10 | .media, 11 | .media-body { 12 | overflow: hidden; 13 | *overflow: visible; 14 | zoom: 1; 15 | } 16 | 17 | // Proper spacing between instances of .media 18 | .media, 19 | .media .media { 20 | margin-top: 15px; 21 | } 22 | .media:first-child { 23 | margin-top: 0; 24 | } 25 | 26 | // For images and videos, set to block 27 | .media-object { 28 | display: block; 29 | } 30 | 31 | // Reset margins on headings for tighter default spacing 32 | .media-heading { 33 | margin: 0 0 5px; 34 | } 35 | 36 | 37 | // Media image alignment 38 | // ------------------------- 39 | 40 | .media > .pull-left { 41 | margin-right: 10px; 42 | } 43 | .media > .pull-right { 44 | margin-left: 10px; 45 | } 46 | 47 | 48 | // Media list variation 49 | // ------------------------- 50 | 51 | // Undo default ul/ol styles 52 | .media-list { 53 | margin-left: 0; 54 | list-style: none; 55 | } 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Jeff Lindsay 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /requestbin/static/less/scaffolding.less: -------------------------------------------------------------------------------- 1 | // 2 | // Scaffolding 3 | // -------------------------------------------------- 4 | 5 | 6 | // Body reset 7 | // ------------------------- 8 | 9 | body { 10 | margin: 0; 11 | font-family: @baseFontFamily; 12 | font-size: @baseFontSize; 13 | line-height: @baseLineHeight; 14 | color: @textColor; 15 | background-color: @bodyBackground; 16 | } 17 | 18 | 19 | // Links 20 | // ------------------------- 21 | 22 | a { 23 | color: @linkColor; 24 | text-decoration: none; 25 | } 26 | a:hover, 27 | a:focus { 28 | color: @linkColorHover; 29 | text-decoration: underline; 30 | } 31 | 32 | 33 | // Images 34 | // ------------------------- 35 | 36 | // Rounded corners 37 | .img-rounded { 38 | .border-radius(6px); 39 | } 40 | 41 | // Add polaroid-esque trim 42 | .img-polaroid { 43 | padding: 4px; 44 | background-color: #fff; 45 | border: 1px solid #ccc; 46 | border: 1px solid rgba(0,0,0,.2); 47 | .box-shadow(0 1px 3px rgba(0,0,0,.1)); 48 | } 49 | 50 | // Perfect circle 51 | .img-circle { 52 | .border-radius(500px); // crank the border-radius so it works with most reasonably sized images 53 | } 54 | -------------------------------------------------------------------------------- /requestbin/static/less/responsive.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Responsive v2.3.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | 12 | // Responsive.less 13 | // For phone and tablet devices 14 | // ------------------------------------------------------------- 15 | 16 | 17 | // REPEAT VARIABLES & MIXINS 18 | // ------------------------- 19 | // Required since we compile the responsive stuff separately 20 | 21 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 22 | @import "mixins.less"; 23 | 24 | 25 | // RESPONSIVE CLASSES 26 | // ------------------ 27 | 28 | @import "responsive-utilities.less"; 29 | 30 | 31 | // MEDIA QUERIES 32 | // ------------------ 33 | 34 | // Large desktops 35 | @import "responsive-1200px-min.less"; 36 | 37 | // Tablets to regular desktops 38 | @import "responsive-768px-979px.less"; 39 | 40 | // Phones to portrait tablets and narrow desktops 41 | @import "responsive-767px-max.less"; 42 | 43 | 44 | // RESPONSIVE NAVBAR 45 | // ------------------ 46 | 47 | // From 979px and below, show a button to toggle navbar contents 48 | @import "responsive-navbar.less"; 49 | 50 | 51 | // Custom overrides 52 | @import "custom.less"; -------------------------------------------------------------------------------- /requestbin/storage/memory.py: -------------------------------------------------------------------------------- 1 | import time 2 | import operator 3 | 4 | from ..models import Bin 5 | 6 | from requestbin import config 7 | 8 | class MemoryStorage(): 9 | cleanup_interval = config.CLEANUP_INTERVAL 10 | 11 | def __init__(self, bin_ttl): 12 | self.bin_ttl = bin_ttl 13 | self.bins = {} 14 | self.request_count = 0 15 | 16 | def do_start(self): 17 | self.spawn(self._cleanup_loop) 18 | 19 | def _cleanup_loop(self): 20 | while True: 21 | self.async.sleep(self.cleanup_interval) 22 | self._expire_bins() 23 | 24 | def _expire_bins(self): 25 | expiry = time.time() - self.bin_ttl 26 | for name, bin in self.bins.items(): 27 | if bin.created < expiry: 28 | self.bins.pop(name) 29 | 30 | def create_bin(self, private=False): 31 | bin = Bin(private) 32 | self.bins[bin.name] = bin 33 | return self.bins[bin.name] 34 | 35 | def create_request(self, bin, request): 36 | bin.add(request) 37 | self.request_count += 1 38 | 39 | def count_bins(self): 40 | return len(self.bins) 41 | 42 | def count_requests(self): 43 | return self.request_count 44 | 45 | def avg_req_size(self): 46 | return None 47 | 48 | def lookup_bin(self, name): 49 | return self.bins[name] 50 | -------------------------------------------------------------------------------- /requestbin/static/less/thumbnails.less: -------------------------------------------------------------------------------- 1 | // 2 | // Thumbnails 3 | // -------------------------------------------------- 4 | 5 | 6 | // Note: `.thumbnails` and `.thumbnails > li` are overriden in responsive files 7 | 8 | // Make wrapper ul behave like the grid 9 | .thumbnails { 10 | margin-left: -@gridGutterWidth; 11 | list-style: none; 12 | .clearfix(); 13 | } 14 | // Fluid rows have no left margin 15 | .row-fluid .thumbnails { 16 | margin-left: 0; 17 | } 18 | 19 | // Float li to make thumbnails appear in a row 20 | .thumbnails > li { 21 | float: left; // Explicity set the float since we don't require .span* classes 22 | margin-bottom: @baseLineHeight; 23 | margin-left: @gridGutterWidth; 24 | } 25 | 26 | // The actual thumbnail (can be `a` or `div`) 27 | .thumbnail { 28 | display: block; 29 | padding: 4px; 30 | line-height: @baseLineHeight; 31 | border: 1px solid #ddd; 32 | .border-radius(@baseBorderRadius); 33 | .box-shadow(0 1px 3px rgba(0,0,0,.055)); 34 | .transition(all .2s ease-in-out); 35 | } 36 | // Add a hover/focus state for linked versions only 37 | a.thumbnail:hover, 38 | a.thumbnail:focus { 39 | border-color: @linkColor; 40 | .box-shadow(0 1px 4px rgba(0,105,214,.25)); 41 | } 42 | 43 | // Images and captions 44 | .thumbnail > img { 45 | display: block; 46 | max-width: 100%; 47 | margin-left: auto; 48 | margin-right: auto; 49 | } 50 | .thumbnail .caption { 51 | padding: 9px; 52 | color: @gray; 53 | } 54 | -------------------------------------------------------------------------------- /requestbin/static/less/code.less: -------------------------------------------------------------------------------- 1 | // 2 | // Code (inline and blocK) 3 | // -------------------------------------------------- 4 | 5 | 6 | // Inline and block code styles 7 | code, 8 | pre { 9 | padding: 0 3px 2px; 10 | #font > #family > .monospace; 11 | font-size: @baseFontSize - 2; 12 | color: @grayDark; 13 | .border-radius(3px); 14 | } 15 | 16 | // Inline code 17 | code { 18 | padding: 2px 4px; 19 | color: #d14; 20 | background-color: #f7f7f9; 21 | border: 1px solid #e1e1e8; 22 | white-space: nowrap; 23 | } 24 | 25 | // Blocks of code 26 | pre { 27 | display: block; 28 | padding: (@baseLineHeight - 1) / 2; 29 | margin: 0 0 @baseLineHeight / 2; 30 | font-size: @baseFontSize - 1; // 14px to 13px 31 | line-height: @baseLineHeight; 32 | word-break: break-all; 33 | word-wrap: break-word; 34 | white-space: pre; 35 | white-space: pre-wrap; 36 | background-color: #f5f5f5; 37 | border: 1px solid #ccc; // fallback for IE7-8 38 | border: 1px solid rgba(0,0,0,.15); 39 | .border-radius(@baseBorderRadius); 40 | 41 | // Make prettyprint styles more spaced out for readability 42 | &.prettyprint { 43 | margin-bottom: @baseLineHeight; 44 | } 45 | 46 | // Account for some code outputs that place code tags in pre tags 47 | code { 48 | padding: 0; 49 | color: inherit; 50 | white-space: pre; 51 | white-space: pre-wrap; 52 | background-color: transparent; 53 | border: 0; 54 | } 55 | } 56 | 57 | // Enable scrollable blocks of code 58 | .pre-scrollable { 59 | max-height: 340px; 60 | overflow-y: scroll; 61 | } -------------------------------------------------------------------------------- /requestbin/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block head %} 3 | 13 | {% endblock %} 14 | {% block content %} 15 |
16 | 34 |
35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /requestbin/config.py: -------------------------------------------------------------------------------- 1 | import os, urlparse 2 | DEBUG = True 3 | REALM = os.environ.get('REALM', 'local') 4 | 5 | ROOT_URL = "http://localhost:4000" 6 | 7 | PORT_NUMBER = 4000 8 | 9 | ENABLE_CORS = False 10 | CORS_ORIGINS = "*" 11 | 12 | FLASK_SESSION_SECRET_KEY = os.environ.get("SESSION_SECRET_KEY", "N1BKhJLnBqLpexOZdklsfDKFJDKFadsfs9a3r324YB7B73AglRmrHMDQ9RhXz35") 13 | 14 | BIN_TTL = 48*3600 15 | STORAGE_BACKEND = "requestbin.storage.memory.MemoryStorage" 16 | MAX_RAW_SIZE = int(os.environ.get('MAX_RAW_SIZE', 1024*10)) 17 | IGNORE_HEADERS = [] 18 | MAX_REQUESTS = 20 19 | CLEANUP_INTERVAL = 3600 20 | 21 | REDIS_URL = "" 22 | REDIS_HOST = "localhost" 23 | REDIS_PORT = 6379 24 | REDIS_PASSWORD = None 25 | REDIS_DB = 9 26 | 27 | REDIS_PREFIX = "requestbin" 28 | 29 | BUGSNAG_KEY = "" 30 | 31 | if REALM == 'prod': 32 | DEBUG = False 33 | ROOT_URL = "http://requestb.in" 34 | 35 | FLASK_SESSION_SECRET_KEY = os.environ.get("SESSION_SECRET_KEY", FLASK_SESSION_SECRET_KEY) 36 | 37 | STORAGE_BACKEND = "requestbin.storage.redis.RedisStorage" 38 | 39 | REDIS_URL = os.environ.get("REDIS_URL") 40 | url_parts = urlparse.urlparse(REDIS_URL) 41 | REDIS_HOST = url_parts.hostname 42 | REDIS_PORT = url_parts.port 43 | REDIS_PASSWORD = url_parts.password 44 | REDIS_DB = url_parts.fragment 45 | 46 | BUGSNAG_KEY = os.environ.get("BUGSNAG_KEY", BUGSNAG_KEY) 47 | 48 | IGNORE_HEADERS = """ 49 | X-Varnish 50 | X-Forwarded-For 51 | X-Heroku-Dynos-In-Use 52 | X-Request-Start 53 | X-Heroku-Queue-Wait-Time 54 | X-Heroku-Queue-Depth 55 | X-Real-Ip 56 | X-Forwarded-Proto 57 | X-Via 58 | X-Forwarded-Port 59 | """.split("\n")[1:-1] 60 | -------------------------------------------------------------------------------- /requestbin/static/less/alerts.less: -------------------------------------------------------------------------------- 1 | // 2 | // Alerts 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // ------------------------- 8 | 9 | .alert { 10 | padding: 8px 35px 8px 14px; 11 | margin-bottom: @baseLineHeight; 12 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 13 | background-color: @warningBackground; 14 | border: 1px solid @warningBorder; 15 | .border-radius(@baseBorderRadius); 16 | } 17 | .alert, 18 | .alert h4 { 19 | // Specified for the h4 to prevent conflicts of changing @headingsColor 20 | color: @warningText; 21 | } 22 | .alert h4 { 23 | margin: 0; 24 | } 25 | 26 | // Adjust close link position 27 | .alert .close { 28 | position: relative; 29 | top: -2px; 30 | right: -21px; 31 | line-height: @baseLineHeight; 32 | } 33 | 34 | 35 | // Alternate styles 36 | // ------------------------- 37 | 38 | .alert-success { 39 | background-color: @successBackground; 40 | border-color: @successBorder; 41 | color: @successText; 42 | } 43 | .alert-success h4 { 44 | color: @successText; 45 | } 46 | .alert-danger, 47 | .alert-error { 48 | background-color: @errorBackground; 49 | border-color: @errorBorder; 50 | color: @errorText; 51 | } 52 | .alert-danger h4, 53 | .alert-error h4 { 54 | color: @errorText; 55 | } 56 | .alert-info { 57 | background-color: @infoBackground; 58 | border-color: @infoBorder; 59 | color: @infoText; 60 | } 61 | .alert-info h4 { 62 | color: @infoText; 63 | } 64 | 65 | 66 | // Block alerts 67 | // ------------------------- 68 | 69 | .alert-block { 70 | padding-top: 14px; 71 | padding-bottom: 14px; 72 | } 73 | .alert-block > p, 74 | .alert-block > ul { 75 | margin-bottom: 0; 76 | } 77 | .alert-block p + p { 78 | margin-top: 5px; 79 | } 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # We have discontinued the publicly hosted version of RequestBin due to ongoing abuse that made it very difficult to keep the site up reliably. Please see instructions below for setting up your own self-hosted instance. 2 | 3 | Originally Created by [Jeff Lindsay](http://progrium.com) 4 | 5 | License 6 | ------- 7 | MIT 8 | 9 | 10 | Looking to self-host? 11 | ===================== 12 | 13 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) 14 | 15 | ## Deploy your own instance using Heroku 16 | Create a Heroku account if you haven't, then grab the RequestBin source using git: 17 | 18 | `$ git clone git://github.com/Runscope/requestbin.git` 19 | 20 | From the project directory, create a Heroku application: 21 | 22 | `$ heroku create` 23 | 24 | Add Heroku's redis addon: 25 | 26 | `$ heroku addons:add heroku-redis` 27 | 28 | Set an environment variable to indicate production: 29 | 30 | `$ heroku config:set REALM=prod` 31 | 32 | Now just deploy via git: 33 | 34 | `$ git push heroku master` 35 | 36 | It will push to Heroku and give you a URL that your own private RequestBin will be running. 37 | 38 | 39 | ## Deploy your own instance using Docker 40 | 41 | On the server/machine you want to host this, you'll first need a machine with 42 | docker and docker-compose installed, then grab the RequestBin source using git: 43 | 44 | `$ git clone git://github.com/Runscope/requestbin.git` 45 | 46 | Go into the project directory and then build and start the containers 47 | 48 | ``` 49 | $ sudo docker-compose build 50 | $ sudo docker-compose up -d 51 | ``` 52 | 53 | Your own private RequestBin will be running on this server. 54 | 55 | 56 | Contributors 57 | ------------ 58 | * Barry Carlyon 59 | * Jeff Lindsay 60 | -------------------------------------------------------------------------------- /requestbin/static/less/bootstrap.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v2.3.2 3 | * 4 | * Copyright 2012 Twitter, Inc 5 | * Licensed under the Apache License v2.0 6 | * http://www.apache.org/licenses/LICENSE-2.0 7 | * 8 | * Designed and built with all the love in the world @twitter by @mdo and @fat. 9 | */ 10 | 11 | // Core variables and mixins 12 | @import "variables.less"; // Modify this for custom colors, font-sizes, etc 13 | @import "mixins.less"; 14 | 15 | // CSS Reset 16 | @import "reset.less"; 17 | 18 | // Grid system and page structure 19 | @import "scaffolding.less"; 20 | @import "grid.less"; 21 | @import "layouts.less"; 22 | 23 | // Base CSS 24 | @import "type.less"; 25 | @import "code.less"; 26 | @import "forms.less"; 27 | @import "tables.less"; 28 | 29 | // Components: common 30 | @import "sprites.less"; 31 | @import "dropdowns.less"; 32 | @import "wells.less"; 33 | @import "component-animations.less"; 34 | @import "close.less"; 35 | 36 | // Components: Buttons & Alerts 37 | @import "buttons.less"; 38 | @import "button-groups.less"; 39 | @import "alerts.less"; // Note: alerts share common CSS with buttons and thus have styles in buttons.less 40 | 41 | // Components: Nav 42 | @import "navs.less"; 43 | @import "navbar.less"; 44 | @import "breadcrumbs.less"; 45 | @import "pagination.less"; 46 | @import "pager.less"; 47 | 48 | // Components: Popovers 49 | @import "modals.less"; 50 | @import "tooltip.less"; 51 | @import "popovers.less"; 52 | 53 | // Components: Misc 54 | @import "thumbnails.less"; 55 | @import "media.less"; 56 | @import "labels-badges.less"; 57 | @import "progress-bars.less"; 58 | @import "accordion.less"; 59 | @import "carousel.less"; 60 | @import "hero-unit.less"; 61 | 62 | // Utility classes 63 | @import "utilities.less"; // Has to be last to override when necessary 64 | 65 | 66 | // Custom overrides 67 | @import "custom.less"; -------------------------------------------------------------------------------- /requestbin/static/less/responsive-utilities.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Utility classes 3 | // -------------------------------------------------- 4 | 5 | 6 | // IE10 Metro responsive 7 | // Required for Windows 8 Metro split-screen snapping with IE10 8 | // Source: http://timkadlec.com/2012/10/ie10-snap-mode-and-responsive-design/ 9 | @-ms-viewport{ 10 | width: device-width; 11 | } 12 | 13 | // Hide from screenreaders and browsers 14 | // Credit: HTML5 Boilerplate 15 | .hidden { 16 | display: none; 17 | visibility: hidden; 18 | } 19 | 20 | // Visibility utilities 21 | 22 | // For desktops 23 | .visible-phone { display: none !important; } 24 | .visible-tablet { display: none !important; } 25 | .hidden-phone { } 26 | .hidden-tablet { } 27 | .hidden-desktop { display: none !important; } 28 | .visible-desktop { display: inherit !important; } 29 | 30 | // Tablets & small desktops only 31 | @media (min-width: 768px) and (max-width: 979px) { 32 | // Hide everything else 33 | .hidden-desktop { display: inherit !important; } 34 | .visible-desktop { display: none !important ; } 35 | // Show 36 | .visible-tablet { display: inherit !important; } 37 | // Hide 38 | .hidden-tablet { display: none !important; } 39 | } 40 | 41 | // Phones only 42 | @media (max-width: 767px) { 43 | // Hide everything else 44 | .hidden-desktop { display: inherit !important; } 45 | .visible-desktop { display: none !important; } 46 | // Show 47 | .visible-phone { display: inherit !important; } // Use inherit to restore previous behavior 48 | // Hide 49 | .hidden-phone { display: none !important; } 50 | } 51 | 52 | // Print utilities 53 | .visible-print { display: none !important; } 54 | .hidden-print { } 55 | 56 | @media print { 57 | .visible-print { display: inherit !important; } 58 | .hidden-print { display: none !important; } 59 | } 60 | -------------------------------------------------------------------------------- /requestbin/static/less/tooltip.less: -------------------------------------------------------------------------------- 1 | // 2 | // Tooltips 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base class 7 | .tooltip { 8 | position: absolute; 9 | z-index: @zindexTooltip; 10 | display: block; 11 | visibility: visible; 12 | font-size: 11px; 13 | line-height: 1.4; 14 | .opacity(0); 15 | &.in { .opacity(80); } 16 | &.top { margin-top: -3px; padding: 5px 0; } 17 | &.right { margin-left: 3px; padding: 0 5px; } 18 | &.bottom { margin-top: 3px; padding: 5px 0; } 19 | &.left { margin-left: -3px; padding: 0 5px; } 20 | } 21 | 22 | // Wrapper for the tooltip content 23 | .tooltip-inner { 24 | max-width: 200px; 25 | padding: 8px; 26 | color: @tooltipColor; 27 | text-align: center; 28 | text-decoration: none; 29 | background-color: @tooltipBackground; 30 | .border-radius(@baseBorderRadius); 31 | } 32 | 33 | // Arrows 34 | .tooltip-arrow { 35 | position: absolute; 36 | width: 0; 37 | height: 0; 38 | border-color: transparent; 39 | border-style: solid; 40 | } 41 | .tooltip { 42 | &.top .tooltip-arrow { 43 | bottom: 0; 44 | left: 50%; 45 | margin-left: -@tooltipArrowWidth; 46 | border-width: @tooltipArrowWidth @tooltipArrowWidth 0; 47 | border-top-color: @tooltipArrowColor; 48 | } 49 | &.right .tooltip-arrow { 50 | top: 50%; 51 | left: 0; 52 | margin-top: -@tooltipArrowWidth; 53 | border-width: @tooltipArrowWidth @tooltipArrowWidth @tooltipArrowWidth 0; 54 | border-right-color: @tooltipArrowColor; 55 | } 56 | &.left .tooltip-arrow { 57 | top: 50%; 58 | right: 0; 59 | margin-top: -@tooltipArrowWidth; 60 | border-width: @tooltipArrowWidth 0 @tooltipArrowWidth @tooltipArrowWidth; 61 | border-left-color: @tooltipArrowColor; 62 | } 63 | &.bottom .tooltip-arrow { 64 | top: 0; 65 | left: 50%; 66 | margin-left: -@tooltipArrowWidth; 67 | border-width: 0 @tooltipArrowWidth @tooltipArrowWidth; 68 | border-bottom-color: @tooltipArrowColor; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /requestbin/storage/redis.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | 3 | import time 4 | import cPickle as pickle 5 | 6 | import redis 7 | 8 | from ..models import Bin 9 | 10 | from requestbin import config 11 | 12 | class RedisStorage(): 13 | prefix = config.REDIS_PREFIX 14 | 15 | def __init__(self, bin_ttl): 16 | self.bin_ttl = bin_ttl 17 | self.redis = redis.StrictRedis(host=config.REDIS_HOST, port=config.REDIS_PORT, db=config.REDIS_DB, password=config.REDIS_PASSWORD) 18 | 19 | def _key(self, name): 20 | return '{}_{}'.format(self.prefix, name) 21 | 22 | def _request_count_key(self): 23 | return '{}-requests'.format(self.prefix) 24 | 25 | def create_bin(self, private=False): 26 | bin = Bin(private) 27 | key = self._key(bin.name) 28 | self.redis.set(key, bin.dump()) 29 | self.redis.expireat(key, int(bin.created+self.bin_ttl)) 30 | return bin 31 | 32 | def create_request(self, bin, request): 33 | bin.add(request) 34 | key = self._key(bin.name) 35 | self.redis.set(key, bin.dump()) 36 | self.redis.expireat(key, int(bin.created+self.bin_ttl)) 37 | 38 | self.redis.setnx(self._request_count_key(), 0) 39 | self.redis.incr(self._request_count_key()) 40 | 41 | def count_bins(self): 42 | keys = self.redis.keys("{}_*".format(self.prefix)) 43 | return len(keys) 44 | 45 | def count_requests(self): 46 | return int(self.redis.get(self._request_count_key()) or 0) 47 | 48 | def avg_req_size(self): 49 | info = self.redis.info() 50 | return info['used_memory'] / info['db0']['keys'] / 1024 51 | 52 | def lookup_bin(self, name): 53 | key = self._key(name) 54 | serialized_bin = self.redis.get(key) 55 | try: 56 | bin = Bin.load(serialized_bin) 57 | return bin 58 | except TypeError: 59 | self.redis.delete(key) # clear bad data 60 | raise KeyError("Bin not found") 61 | -------------------------------------------------------------------------------- /requestbin/views.py: -------------------------------------------------------------------------------- 1 | import urllib 2 | from flask import session, redirect, url_for, escape, request, render_template, make_response 3 | 4 | from requestbin import app, db 5 | 6 | def update_recent_bins(name): 7 | if 'recent' not in session: 8 | session['recent'] = [] 9 | if name in session['recent']: 10 | session['recent'].remove(name) 11 | session['recent'].insert(0, name) 12 | if len(session['recent']) > 10: 13 | session['recent'] = session['recent'][:10] 14 | session.modified = True 15 | 16 | 17 | def expand_recent_bins(): 18 | if 'recent' not in session: 19 | session['recent'] = [] 20 | recent = [] 21 | for name in session['recent']: 22 | try: 23 | recent.append(db.lookup_bin(name)) 24 | except KeyError: 25 | session['recent'].remove(name) 26 | session.modified = True 27 | return recent 28 | 29 | @app.endpoint('views.home') 30 | def home(): 31 | return render_template('home.html', recent=expand_recent_bins()) 32 | 33 | 34 | @app.endpoint('views.bin') 35 | def bin(name): 36 | try: 37 | bin = db.lookup_bin(name) 38 | except KeyError: 39 | return "Not found\n", 404 40 | if request.query_string == 'inspect': 41 | if bin.private and session.get(bin.name) != bin.secret_key: 42 | return "Private bin\n", 403 43 | update_recent_bins(name) 44 | return render_template('bin.html', 45 | bin=bin, 46 | base_url=request.scheme+'://'+request.host) 47 | else: 48 | db.create_request(bin, request) 49 | resp = make_response("ok\n") 50 | resp.headers['Sponsored-By'] = "https://www.runscope.com" 51 | return resp 52 | 53 | 54 | @app.endpoint('views.docs') 55 | def docs(name): 56 | doc = db.lookup_doc(name) 57 | if doc: 58 | return render_template('doc.html', 59 | content=doc['content'], 60 | title=doc['title'], 61 | recent=expand_recent_bins()) 62 | else: 63 | return "Not found", 404 64 | -------------------------------------------------------------------------------- /requestbin/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import operator 3 | 4 | from flask import session, make_response, request, render_template 5 | from requestbin import app, db 6 | 7 | def _response(object, code=200): 8 | jsonp = request.args.get('jsonp') 9 | if jsonp: 10 | resp = make_response('%s(%s)' % (jsonp, json.dumps(object)), 200) 11 | resp.headers['Content-Type'] = 'text/javascript' 12 | else: 13 | resp = make_response(json.dumps(object), code) 14 | resp.headers['Content-Type'] = 'application/json' 15 | resp.headers['Access-Control-Allow-Origin'] = '*' 16 | return resp 17 | 18 | 19 | @app.endpoint('api.bins') 20 | def bins(): 21 | private = request.form.get('private') in ['true', 'on'] 22 | bin = db.create_bin(private) 23 | if bin.private: 24 | session[bin.name] = bin.secret_key 25 | return _response(bin.to_dict()) 26 | 27 | 28 | @app.endpoint('api.bin') 29 | def bin(name): 30 | try: 31 | bin = db.lookup_bin(name) 32 | except KeyError: 33 | return _response({'error': "Bin not found"}, 404) 34 | 35 | return _response(bin.to_dict()) 36 | 37 | 38 | @app.endpoint('api.requests') 39 | def requests(bin): 40 | try: 41 | bin = db.lookup_bin(bin) 42 | except KeyError: 43 | return _response({'error': "Bin not found"}, 404) 44 | 45 | return _response([r.to_dict() for r in bin.requests]) 46 | 47 | 48 | @app.endpoint('api.request') 49 | def request_(bin, name): 50 | try: 51 | bin = db.lookup_bin(bin) 52 | except KeyError: 53 | return _response({'error': "Bin not found"}, 404) 54 | 55 | for req in bin.requests: 56 | if req.id == name: 57 | return _response(req.to_dict()) 58 | 59 | return _response({'error': "Request not found"}, 404) 60 | 61 | 62 | @app.endpoint('api.stats') 63 | def stats(): 64 | stats = { 65 | 'bin_count': db.count_bins(), 66 | 'request_count': db.count_requests(), 67 | 'avg_req_size_kb': db.avg_req_size(), } 68 | resp = make_response(json.dumps(stats), 200) 69 | resp.headers['Content-Type'] = 'application/json' 70 | return resp 71 | -------------------------------------------------------------------------------- /requestbin/static/less/labels-badges.less: -------------------------------------------------------------------------------- 1 | // 2 | // Labels and badges 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base classes 7 | .label, 8 | .badge { 9 | display: inline-block; 10 | padding: 2px 4px; 11 | font-size: @baseFontSize * .846; 12 | font-weight: bold; 13 | line-height: 14px; // ensure proper line-height if floated 14 | color: @white; 15 | vertical-align: baseline; 16 | white-space: nowrap; 17 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 18 | background-color: @grayLight; 19 | } 20 | // Set unique padding and border-radii 21 | .label { 22 | .border-radius(3px); 23 | } 24 | .badge { 25 | padding-left: 9px; 26 | padding-right: 9px; 27 | .border-radius(9px); 28 | } 29 | 30 | // Empty labels/badges collapse 31 | .label, 32 | .badge { 33 | &:empty { 34 | display: none; 35 | } 36 | } 37 | 38 | // Hover/focus state, but only for links 39 | a { 40 | &.label:hover, 41 | &.label:focus, 42 | &.badge:hover, 43 | &.badge:focus { 44 | color: @white; 45 | text-decoration: none; 46 | cursor: pointer; 47 | } 48 | } 49 | 50 | // Colors 51 | // Only give background-color difference to links (and to simplify, we don't qualifty with `a` but [href] attribute) 52 | .label, 53 | .badge { 54 | // Important (red) 55 | &-important { background-color: @errorText; } 56 | &-important[href] { background-color: darken(@errorText, 10%); } 57 | // Warnings (orange) 58 | &-warning { background-color: @orange; } 59 | &-warning[href] { background-color: darken(@orange, 10%); } 60 | // Success (green) 61 | &-success { background-color: @successText; } 62 | &-success[href] { background-color: darken(@successText, 10%); } 63 | // Info (turquoise) 64 | &-info { background-color: @infoText; } 65 | &-info[href] { background-color: darken(@infoText, 10%); } 66 | // Inverse (black) 67 | &-inverse { background-color: @grayDark; } 68 | &-inverse[href] { background-color: darken(@grayDark, 10%); } 69 | } 70 | 71 | // Quick fix for labels/badges in buttons 72 | .btn { 73 | .label, 74 | .badge { 75 | position: relative; 76 | top: -1px; 77 | } 78 | } 79 | .btn-mini { 80 | .label, 81 | .badge { 82 | top: 0; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /requestbin/static/less/modals.less: -------------------------------------------------------------------------------- 1 | // 2 | // Modals 3 | // -------------------------------------------------- 4 | 5 | // Background 6 | .modal-backdrop { 7 | position: fixed; 8 | top: 0; 9 | right: 0; 10 | bottom: 0; 11 | left: 0; 12 | z-index: @zindexModalBackdrop; 13 | background-color: @black; 14 | // Fade for backdrop 15 | &.fade { opacity: 0; } 16 | } 17 | 18 | .modal-backdrop, 19 | .modal-backdrop.fade.in { 20 | .opacity(80); 21 | } 22 | 23 | // Base modal 24 | .modal { 25 | position: fixed; 26 | top: 10%; 27 | left: 50%; 28 | z-index: @zindexModal; 29 | width: 560px; 30 | margin-left: -280px; 31 | background-color: @white; 32 | border: 1px solid #999; 33 | border: 1px solid rgba(0,0,0,.3); 34 | *border: 1px solid #999; /* IE6-7 */ 35 | .border-radius(6px); 36 | .box-shadow(0 3px 7px rgba(0,0,0,0.3)); 37 | .background-clip(padding-box); 38 | // Remove focus outline from opened modal 39 | outline: none; 40 | 41 | &.fade { 42 | .transition(e('opacity .3s linear, top .3s ease-out')); 43 | top: -25%; 44 | } 45 | &.fade.in { top: 10%; } 46 | } 47 | .modal-header { 48 | padding: 9px 15px; 49 | border-bottom: 1px solid #eee; 50 | // Close icon 51 | .close { margin-top: 2px; } 52 | // Heading 53 | h3 { 54 | margin: 0; 55 | line-height: 30px; 56 | } 57 | } 58 | 59 | // Body (where all modal content resides) 60 | .modal-body { 61 | position: relative; 62 | overflow-y: auto; 63 | max-height: 400px; 64 | padding: 15px; 65 | } 66 | // Remove bottom margin if need be 67 | .modal-form { 68 | margin-bottom: 0; 69 | } 70 | 71 | // Footer (for actions) 72 | .modal-footer { 73 | padding: 14px 15px 15px; 74 | margin-bottom: 0; 75 | text-align: right; // right align buttons 76 | background-color: #f5f5f5; 77 | border-top: 1px solid #ddd; 78 | .border-radius(0 0 6px 6px); 79 | .box-shadow(inset 0 1px 0 @white); 80 | .clearfix(); // clear it in case folks use .pull-* classes on buttons 81 | 82 | // Properly space out buttons 83 | .btn + .btn { 84 | margin-left: 5px; 85 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs 86 | } 87 | // but override that for button groups 88 | .btn-group .btn + .btn { 89 | margin-left: -1px; 90 | } 91 | // and override it for block buttons as well 92 | .btn-block + .btn-block { 93 | margin-left: 0; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /requestbin/__init__.py: -------------------------------------------------------------------------------- 1 | import config 2 | import os 3 | from cStringIO import StringIO 4 | 5 | from flask import Flask 6 | from flask_cors import CORS 7 | 8 | 9 | class WSGIRawBody(object): 10 | def __init__(self, application): 11 | self.application = application 12 | 13 | def __call__(self, environ, start_response): 14 | 15 | length = environ.get('CONTENT_LENGTH', '0') 16 | length = 0 if length == '' else int(length) 17 | 18 | body = environ['wsgi.input'].read(length) 19 | environ['raw'] = body 20 | environ['wsgi.input'] = StringIO(body) 21 | 22 | # Call the wrapped application 23 | app_iter = self.application(environ, self._sr_callback(start_response)) 24 | 25 | # Return modified response 26 | return app_iter 27 | 28 | def _sr_callback(self, start_response): 29 | def callback(status, headers, exc_info=None): 30 | 31 | # Call upstream start_response 32 | start_response(status, headers, exc_info) 33 | return callback 34 | 35 | 36 | 37 | app = Flask(__name__) 38 | 39 | if os.environ.get('ENABLE_CORS', config.ENABLE_CORS): 40 | cors = CORS(app, resources={r"*": {"origins": os.environ.get('CORS_ORIGINS', config.CORS_ORIGINS)}}) 41 | 42 | from werkzeug.contrib.fixers import ProxyFix 43 | app.wsgi_app = WSGIRawBody(ProxyFix(app.wsgi_app)) 44 | 45 | app.debug = config.DEBUG 46 | app.secret_key = config.FLASK_SESSION_SECRET_KEY 47 | app.root_path = os.path.abspath(os.path.dirname(__file__)) 48 | 49 | if config.BUGSNAG_KEY: 50 | import bugsnag 51 | from bugsnag.flask import handle_exceptions 52 | bugsnag.configure( 53 | api_key=config.BUGSNAG_KEY, 54 | project_root=app.root_path, 55 | # 'production' is a magic string for bugsnag, rest are arbitrary 56 | release_stage = config.REALM.replace("prod", "production"), 57 | notify_release_stages=["production", "test"], 58 | use_ssl = True 59 | ) 60 | handle_exceptions(app) 61 | 62 | from filters import * 63 | app.jinja_env.filters['status_class'] = status_class 64 | app.jinja_env.filters['friendly_time'] = friendly_time 65 | app.jinja_env.filters['friendly_size'] = friendly_size 66 | app.jinja_env.filters['to_qs'] = to_qs 67 | app.jinja_env.filters['approximate_time'] = approximate_time 68 | app.jinja_env.filters['exact_time'] = exact_time 69 | app.jinja_env.filters['short_date'] = short_date 70 | 71 | app.add_url_rule('/', 'views.home') 72 | app.add_url_rule('/', 'views.bin', methods=['GET', 'POST', 'DELETE', 'PUT', 'OPTIONS', 'HEAD', 'PATCH', 'TRACE']) 73 | 74 | app.add_url_rule('/docs/', 'views.docs') 75 | app.add_url_rule('/api/v1/bins', 'api.bins', methods=['POST']) 76 | app.add_url_rule('/api/v1/bins/', 'api.bin', methods=['GET']) 77 | app.add_url_rule('/api/v1/bins//requests', 'api.requests', methods=['GET']) 78 | app.add_url_rule('/api/v1/bins//requests/', 'api.request', methods=['GET']) 79 | 80 | app.add_url_rule('/api/v1/stats', 'api.stats') 81 | 82 | # app.add_url_rule('/robots.txt', redirect_to=url_for('static', filename='robots.txt')) 83 | 84 | from requestbin import api, views 85 | -------------------------------------------------------------------------------- /requestbin/filters.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from dateutil.parser import parse 3 | import hashlib 4 | import os 5 | import time 6 | import urllib 7 | 8 | def approximate_time(ts): 9 | if not isinstance(ts, (int, long, float, complex)): 10 | return "" 11 | 12 | now = time.time() 13 | diff = now - ts 14 | 15 | if diff < 0: 16 | return "now" 17 | elif diff < 60: 18 | return "{}s".format(int(diff)) 19 | elif diff < 60 * 60: 20 | minutes = diff / 60.0 21 | return "{}m".format(int(minutes)) 22 | elif diff < 60 * 60 * 24: 23 | hours = diff / (60.0 * 60.0) 24 | return "{}h".format(int(hours)) 25 | else: 26 | days = diff / (60.0 * 60.0 * 24.0) 27 | return "{}d".format(int(days)) 28 | 29 | 30 | def friendly_size(bytes): 31 | if isinstance(bytes, str): 32 | return bytes 33 | 34 | unit = "" 35 | if bytes <= 1024: 36 | unit = "bytes" 37 | elif bytes <= 1024 * 1024: 38 | bytes = round(bytes / 1024.0, 2) 39 | unit = "kB" 40 | 41 | return "{} {}".format(bytes, unit) 42 | 43 | 44 | def status_class(status_code): 45 | status_code = str(status_code or "0") 46 | lookup = { 47 | "0" : "", 48 | "2" : "ok", 49 | "3" : "info", 50 | "4" : "warning", 51 | "5" : "error" 52 | } 53 | 54 | return lookup.get(status_code[0], "") 55 | 56 | 57 | def friendly_time(secs): 58 | if isinstance(secs, str): 59 | return secs 60 | 61 | ms = int(round(secs * 1000.0)) 62 | unit = "ms" 63 | if ms > 60000: 64 | unit = "minutes" 65 | ms = round(ms / 60000.0, 2) 66 | elif ms > 3000: 67 | ms = round(ms / 1000.0, 2) 68 | unit = "sec" if (ms == 1) else "secs" 69 | 70 | return "{} {}".format(ms, unit) 71 | 72 | 73 | def friendly_number(input): 74 | if not isinstance(input, (int, long, float, complex)): 75 | return "" 76 | return "{:,}".format(input) 77 | 78 | 79 | def exact_time(ts): 80 | if not isinstance(ts, (int, long, float, complex)): 81 | return None 82 | 83 | return datetime.datetime.utcfromtimestamp(ts) 84 | 85 | 86 | def time_class(secs): 87 | if not isinstance(secs, (int, long, float, complex)): 88 | return "" 89 | 90 | ms = secs * 1000.0 91 | if ms > 3000: 92 | return "error" 93 | 94 | if ms > 1000: 95 | return "warning" 96 | 97 | return "" 98 | 99 | 100 | def to_qs(params_dict): 101 | if not params_dict or not isinstance(params_dict, dict): 102 | return "" 103 | 104 | qs = u"?" if params_dict else u"" 105 | 106 | for k, v in params_dict.items(): 107 | if len(qs) > 1: # more than just the ? 108 | qs = qs + u"&" 109 | if v is None: 110 | qs = qs + k 111 | else: 112 | qs = qs + u"{}={}".format(k, v) 113 | return qs 114 | 115 | 116 | def short_date(input): 117 | dt = None 118 | if isinstance(input, (str, unicode)): 119 | dt = parse(input) 120 | elif isinstance(input, (int, long, float, complex)): 121 | dt = datetime.datetime.utcfromtimestamp(float(input)) 122 | else: 123 | return "" 124 | 125 | return dt.strftime("%b %d, %Y") -------------------------------------------------------------------------------- /requestbin/static/less/pagination.less: -------------------------------------------------------------------------------- 1 | // 2 | // Pagination (multiple pages) 3 | // -------------------------------------------------- 4 | 5 | // Space out pagination from surrounding content 6 | .pagination { 7 | margin: @baseLineHeight 0; 8 | } 9 | 10 | .pagination ul { 11 | // Allow for text-based alignment 12 | display: inline-block; 13 | .ie7-inline-block(); 14 | // Reset default ul styles 15 | margin-left: 0; 16 | margin-bottom: 0; 17 | // Visuals 18 | .border-radius(@baseBorderRadius); 19 | .box-shadow(0 1px 2px rgba(0,0,0,.05)); 20 | } 21 | .pagination ul > li { 22 | display: inline; // Remove list-style and block-level defaults 23 | } 24 | .pagination ul > li > a, 25 | .pagination ul > li > span { 26 | float: left; // Collapse white-space 27 | padding: 4px 12px; 28 | line-height: @baseLineHeight; 29 | text-decoration: none; 30 | background-color: @paginationBackground; 31 | border: 1px solid @paginationBorder; 32 | border-left-width: 0; 33 | } 34 | .pagination ul > li > a:hover, 35 | .pagination ul > li > a:focus, 36 | .pagination ul > .active > a, 37 | .pagination ul > .active > span { 38 | background-color: @paginationActiveBackground; 39 | } 40 | .pagination ul > .active > a, 41 | .pagination ul > .active > span { 42 | color: @grayLight; 43 | cursor: default; 44 | } 45 | .pagination ul > .disabled > span, 46 | .pagination ul > .disabled > a, 47 | .pagination ul > .disabled > a:hover, 48 | .pagination ul > .disabled > a:focus { 49 | color: @grayLight; 50 | background-color: transparent; 51 | cursor: default; 52 | } 53 | .pagination ul > li:first-child > a, 54 | .pagination ul > li:first-child > span { 55 | border-left-width: 1px; 56 | .border-left-radius(@baseBorderRadius); 57 | } 58 | .pagination ul > li:last-child > a, 59 | .pagination ul > li:last-child > span { 60 | .border-right-radius(@baseBorderRadius); 61 | } 62 | 63 | 64 | // Alignment 65 | // -------------------------------------------------- 66 | 67 | .pagination-centered { 68 | text-align: center; 69 | } 70 | .pagination-right { 71 | text-align: right; 72 | } 73 | 74 | 75 | // Sizing 76 | // -------------------------------------------------- 77 | 78 | // Large 79 | .pagination-large { 80 | ul > li > a, 81 | ul > li > span { 82 | padding: @paddingLarge; 83 | font-size: @fontSizeLarge; 84 | } 85 | ul > li:first-child > a, 86 | ul > li:first-child > span { 87 | .border-left-radius(@borderRadiusLarge); 88 | } 89 | ul > li:last-child > a, 90 | ul > li:last-child > span { 91 | .border-right-radius(@borderRadiusLarge); 92 | } 93 | } 94 | 95 | // Small and mini 96 | .pagination-mini, 97 | .pagination-small { 98 | ul > li:first-child > a, 99 | ul > li:first-child > span { 100 | .border-left-radius(@borderRadiusSmall); 101 | } 102 | ul > li:last-child > a, 103 | ul > li:last-child > span { 104 | .border-right-radius(@borderRadiusSmall); 105 | } 106 | } 107 | 108 | // Small 109 | .pagination-small { 110 | ul > li > a, 111 | ul > li > span { 112 | padding: @paddingSmall; 113 | font-size: @fontSizeSmall; 114 | } 115 | } 116 | // Mini 117 | .pagination-mini { 118 | ul > li > a, 119 | ul > li > span { 120 | padding: @paddingMini; 121 | font-size: @fontSizeMini; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /requestbin/static/less/carousel.less: -------------------------------------------------------------------------------- 1 | // 2 | // Carousel 3 | // -------------------------------------------------- 4 | 5 | 6 | .carousel { 7 | position: relative; 8 | margin-bottom: @baseLineHeight; 9 | line-height: 1; 10 | } 11 | 12 | .carousel-inner { 13 | overflow: hidden; 14 | width: 100%; 15 | position: relative; 16 | } 17 | 18 | .carousel-inner { 19 | 20 | > .item { 21 | display: none; 22 | position: relative; 23 | .transition(.6s ease-in-out left); 24 | 25 | // Account for jankitude on images 26 | > img, 27 | > a > img { 28 | display: block; 29 | line-height: 1; 30 | } 31 | } 32 | 33 | > .active, 34 | > .next, 35 | > .prev { display: block; } 36 | 37 | > .active { 38 | left: 0; 39 | } 40 | 41 | > .next, 42 | > .prev { 43 | position: absolute; 44 | top: 0; 45 | width: 100%; 46 | } 47 | 48 | > .next { 49 | left: 100%; 50 | } 51 | > .prev { 52 | left: -100%; 53 | } 54 | > .next.left, 55 | > .prev.right { 56 | left: 0; 57 | } 58 | 59 | > .active.left { 60 | left: -100%; 61 | } 62 | > .active.right { 63 | left: 100%; 64 | } 65 | 66 | } 67 | 68 | // Left/right controls for nav 69 | // --------------------------- 70 | 71 | .carousel-control { 72 | position: absolute; 73 | top: 40%; 74 | left: 15px; 75 | width: 40px; 76 | height: 40px; 77 | margin-top: -20px; 78 | font-size: 60px; 79 | font-weight: 100; 80 | line-height: 30px; 81 | color: @white; 82 | text-align: center; 83 | background: @grayDarker; 84 | border: 3px solid @white; 85 | .border-radius(23px); 86 | .opacity(50); 87 | 88 | // we can't have this transition here 89 | // because webkit cancels the carousel 90 | // animation if you trip this while 91 | // in the middle of another animation 92 | // ;_; 93 | // .transition(opacity .2s linear); 94 | 95 | // Reposition the right one 96 | &.right { 97 | left: auto; 98 | right: 15px; 99 | } 100 | 101 | // Hover/focus state 102 | &:hover, 103 | &:focus { 104 | color: @white; 105 | text-decoration: none; 106 | .opacity(90); 107 | } 108 | } 109 | 110 | // Carousel indicator pips 111 | // ----------------------------- 112 | .carousel-indicators { 113 | position: absolute; 114 | top: 15px; 115 | right: 15px; 116 | z-index: 5; 117 | margin: 0; 118 | list-style: none; 119 | 120 | li { 121 | display: block; 122 | float: left; 123 | width: 10px; 124 | height: 10px; 125 | margin-left: 5px; 126 | text-indent: -999px; 127 | background-color: #ccc; 128 | background-color: rgba(255,255,255,.25); 129 | border-radius: 5px; 130 | } 131 | .active { 132 | background-color: #fff; 133 | } 134 | } 135 | 136 | // Caption for text below images 137 | // ----------------------------- 138 | 139 | .carousel-caption { 140 | position: absolute; 141 | left: 0; 142 | right: 0; 143 | bottom: 0; 144 | padding: 15px; 145 | background: @grayDark; 146 | background: rgba(0,0,0,.75); 147 | } 148 | .carousel-caption h4, 149 | .carousel-caption p { 150 | color: @white; 151 | line-height: @baseLineHeight; 152 | } 153 | .carousel-caption h4 { 154 | margin: 0 0 5px; 155 | } 156 | .carousel-caption p { 157 | margin-bottom: 0; 158 | } 159 | -------------------------------------------------------------------------------- /requestbin/static/less/progress-bars.less: -------------------------------------------------------------------------------- 1 | // 2 | // Progress bars 3 | // -------------------------------------------------- 4 | 5 | 6 | // ANIMATIONS 7 | // ---------- 8 | 9 | // Webkit 10 | @-webkit-keyframes progress-bar-stripes { 11 | from { background-position: 40px 0; } 12 | to { background-position: 0 0; } 13 | } 14 | 15 | // Firefox 16 | @-moz-keyframes progress-bar-stripes { 17 | from { background-position: 40px 0; } 18 | to { background-position: 0 0; } 19 | } 20 | 21 | // IE9 22 | @-ms-keyframes progress-bar-stripes { 23 | from { background-position: 40px 0; } 24 | to { background-position: 0 0; } 25 | } 26 | 27 | // Opera 28 | @-o-keyframes progress-bar-stripes { 29 | from { background-position: 0 0; } 30 | to { background-position: 40px 0; } 31 | } 32 | 33 | // Spec 34 | @keyframes progress-bar-stripes { 35 | from { background-position: 40px 0; } 36 | to { background-position: 0 0; } 37 | } 38 | 39 | 40 | 41 | // THE BARS 42 | // -------- 43 | 44 | // Outer container 45 | .progress { 46 | overflow: hidden; 47 | height: @baseLineHeight; 48 | margin-bottom: @baseLineHeight; 49 | #gradient > .vertical(#f5f5f5, #f9f9f9); 50 | .box-shadow(inset 0 1px 2px rgba(0,0,0,.1)); 51 | .border-radius(@baseBorderRadius); 52 | } 53 | 54 | // Bar of progress 55 | .progress .bar { 56 | width: 0%; 57 | height: 100%; 58 | color: @white; 59 | float: left; 60 | font-size: 12px; 61 | text-align: center; 62 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 63 | #gradient > .vertical(#149bdf, #0480be); 64 | .box-shadow(inset 0 -1px 0 rgba(0,0,0,.15)); 65 | .box-sizing(border-box); 66 | .transition(width .6s ease); 67 | } 68 | .progress .bar + .bar { 69 | .box-shadow(~"inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15)"); 70 | } 71 | 72 | // Striped bars 73 | .progress-striped .bar { 74 | #gradient > .striped(#149bdf); 75 | .background-size(40px 40px); 76 | } 77 | 78 | // Call animation for the active one 79 | .progress.active .bar { 80 | -webkit-animation: progress-bar-stripes 2s linear infinite; 81 | -moz-animation: progress-bar-stripes 2s linear infinite; 82 | -ms-animation: progress-bar-stripes 2s linear infinite; 83 | -o-animation: progress-bar-stripes 2s linear infinite; 84 | animation: progress-bar-stripes 2s linear infinite; 85 | } 86 | 87 | 88 | 89 | // COLORS 90 | // ------ 91 | 92 | // Danger (red) 93 | .progress-danger .bar, .progress .bar-danger { 94 | #gradient > .vertical(#ee5f5b, #c43c35); 95 | } 96 | .progress-danger.progress-striped .bar, .progress-striped .bar-danger { 97 | #gradient > .striped(#ee5f5b); 98 | } 99 | 100 | // Success (green) 101 | .progress-success .bar, .progress .bar-success { 102 | #gradient > .vertical(#62c462, #57a957); 103 | } 104 | .progress-success.progress-striped .bar, .progress-striped .bar-success { 105 | #gradient > .striped(#62c462); 106 | } 107 | 108 | // Info (teal) 109 | .progress-info .bar, .progress .bar-info { 110 | #gradient > .vertical(#5bc0de, #339bb9); 111 | } 112 | .progress-info.progress-striped .bar, .progress-striped .bar-info { 113 | #gradient > .striped(#5bc0de); 114 | } 115 | 116 | // Warning (orange) 117 | .progress-warning .bar, .progress .bar-warning { 118 | #gradient > .vertical(lighten(@orange, 15%), @orange); 119 | } 120 | .progress-warning.progress-striped .bar, .progress-striped .bar-warning { 121 | #gradient > .striped(lighten(@orange, 15%)); 122 | } 123 | -------------------------------------------------------------------------------- /requestbin/static/less/popovers.less: -------------------------------------------------------------------------------- 1 | // 2 | // Popovers 3 | // -------------------------------------------------- 4 | 5 | 6 | .popover { 7 | position: absolute; 8 | top: 0; 9 | left: 0; 10 | z-index: @zindexPopover; 11 | display: none; 12 | max-width: 276px; 13 | padding: 1px; 14 | text-align: left; // Reset given new insertion method 15 | background-color: @popoverBackground; 16 | -webkit-background-clip: padding-box; 17 | -moz-background-clip: padding; 18 | background-clip: padding-box; 19 | border: 1px solid #ccc; 20 | border: 1px solid rgba(0,0,0,.2); 21 | .border-radius(6px); 22 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 23 | 24 | // Overrides for proper insertion 25 | white-space: normal; 26 | 27 | // Offset the popover to account for the popover arrow 28 | &.top { margin-top: -10px; } 29 | &.right { margin-left: 10px; } 30 | &.bottom { margin-top: 10px; } 31 | &.left { margin-left: -10px; } 32 | } 33 | 34 | .popover-title { 35 | margin: 0; // reset heading margin 36 | padding: 8px 14px; 37 | font-size: 14px; 38 | font-weight: normal; 39 | line-height: 18px; 40 | background-color: @popoverTitleBackground; 41 | border-bottom: 1px solid darken(@popoverTitleBackground, 5%); 42 | .border-radius(5px 5px 0 0); 43 | 44 | &:empty { 45 | display: none; 46 | } 47 | } 48 | 49 | .popover-content { 50 | padding: 9px 14px; 51 | } 52 | 53 | // Arrows 54 | // 55 | // .arrow is outer, .arrow:after is inner 56 | 57 | .popover .arrow, 58 | .popover .arrow:after { 59 | position: absolute; 60 | display: block; 61 | width: 0; 62 | height: 0; 63 | border-color: transparent; 64 | border-style: solid; 65 | } 66 | .popover .arrow { 67 | border-width: @popoverArrowOuterWidth; 68 | } 69 | .popover .arrow:after { 70 | border-width: @popoverArrowWidth; 71 | content: ""; 72 | } 73 | 74 | .popover { 75 | &.top .arrow { 76 | left: 50%; 77 | margin-left: -@popoverArrowOuterWidth; 78 | border-bottom-width: 0; 79 | border-top-color: #999; // IE8 fallback 80 | border-top-color: @popoverArrowOuterColor; 81 | bottom: -@popoverArrowOuterWidth; 82 | &:after { 83 | bottom: 1px; 84 | margin-left: -@popoverArrowWidth; 85 | border-bottom-width: 0; 86 | border-top-color: @popoverArrowColor; 87 | } 88 | } 89 | &.right .arrow { 90 | top: 50%; 91 | left: -@popoverArrowOuterWidth; 92 | margin-top: -@popoverArrowOuterWidth; 93 | border-left-width: 0; 94 | border-right-color: #999; // IE8 fallback 95 | border-right-color: @popoverArrowOuterColor; 96 | &:after { 97 | left: 1px; 98 | bottom: -@popoverArrowWidth; 99 | border-left-width: 0; 100 | border-right-color: @popoverArrowColor; 101 | } 102 | } 103 | &.bottom .arrow { 104 | left: 50%; 105 | margin-left: -@popoverArrowOuterWidth; 106 | border-top-width: 0; 107 | border-bottom-color: #999; // IE8 fallback 108 | border-bottom-color: @popoverArrowOuterColor; 109 | top: -@popoverArrowOuterWidth; 110 | &:after { 111 | top: 1px; 112 | margin-left: -@popoverArrowWidth; 113 | border-top-width: 0; 114 | border-bottom-color: @popoverArrowColor; 115 | } 116 | } 117 | 118 | &.left .arrow { 119 | top: 50%; 120 | right: -@popoverArrowOuterWidth; 121 | margin-top: -@popoverArrowOuterWidth; 122 | border-right-width: 0; 123 | border-left-color: #999; // IE8 fallback 124 | border-left-color: @popoverArrowOuterColor; 125 | &:after { 126 | right: 1px; 127 | border-right-width: 0; 128 | border-left-color: @popoverArrowColor; 129 | bottom: -@popoverArrowWidth; 130 | } 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /requestbin/static/less/responsive-767px-max.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Landscape phone to desktop/tablet 3 | // -------------------------------------------------- 4 | 5 | 6 | @media (max-width: 767px) { 7 | 8 | // Padding to set content in a bit 9 | body { 10 | padding-left: 20px; 11 | padding-right: 20px; 12 | } 13 | // Negative indent the now static "fixed" navbar 14 | .navbar-fixed-top, 15 | .navbar-fixed-bottom, 16 | .navbar-static-top { 17 | margin-left: -20px; 18 | margin-right: -20px; 19 | } 20 | // Remove padding on container given explicit padding set on body 21 | .container-fluid { 22 | padding: 0; 23 | } 24 | 25 | // TYPOGRAPHY 26 | // ---------- 27 | // Reset horizontal dl 28 | .dl-horizontal { 29 | dt { 30 | float: none; 31 | clear: none; 32 | width: auto; 33 | text-align: left; 34 | } 35 | dd { 36 | margin-left: 0; 37 | } 38 | } 39 | 40 | // GRID & CONTAINERS 41 | // ----------------- 42 | // Remove width from containers 43 | .container { 44 | width: auto; 45 | } 46 | // Fluid rows 47 | .row-fluid { 48 | width: 100%; 49 | } 50 | // Undo negative margin on rows and thumbnails 51 | .row, 52 | .thumbnails { 53 | margin-left: 0; 54 | } 55 | .thumbnails > li { 56 | float: none; 57 | margin-left: 0; // Reset the default margin for all li elements when no .span* classes are present 58 | } 59 | // Make all grid-sized elements block level again 60 | [class*="span"], 61 | .uneditable-input[class*="span"], // Makes uneditable inputs full-width when using grid sizing 62 | .row-fluid [class*="span"] { 63 | float: none; 64 | display: block; 65 | width: 100%; 66 | margin-left: 0; 67 | .box-sizing(border-box); 68 | } 69 | .span12, 70 | .row-fluid .span12 { 71 | width: 100%; 72 | .box-sizing(border-box); 73 | } 74 | .row-fluid [class*="offset"]:first-child { 75 | margin-left: 0; 76 | } 77 | 78 | // FORM FIELDS 79 | // ----------- 80 | // Make span* classes full width 81 | .input-large, 82 | .input-xlarge, 83 | .input-xxlarge, 84 | input[class*="span"], 85 | select[class*="span"], 86 | textarea[class*="span"], 87 | .uneditable-input { 88 | .input-block-level(); 89 | } 90 | // But don't let it screw up prepend/append inputs 91 | .input-prepend input, 92 | .input-append input, 93 | .input-prepend input[class*="span"], 94 | .input-append input[class*="span"] { 95 | display: inline-block; // redeclare so they don't wrap to new lines 96 | width: auto; 97 | } 98 | .controls-row [class*="span"] + [class*="span"] { 99 | margin-left: 0; 100 | } 101 | 102 | // Modals 103 | .modal { 104 | position: fixed; 105 | top: 20px; 106 | left: 20px; 107 | right: 20px; 108 | width: auto; 109 | margin: 0; 110 | &.fade { top: -100px; } 111 | &.fade.in { top: 20px; } 112 | } 113 | 114 | } 115 | 116 | 117 | 118 | // UP TO LANDSCAPE PHONE 119 | // --------------------- 120 | 121 | @media (max-width: 480px) { 122 | 123 | // Smooth out the collapsing/expanding nav 124 | .nav-collapse { 125 | -webkit-transform: translate3d(0, 0, 0); // activate the GPU 126 | } 127 | 128 | // Block level the page header small tag for readability 129 | .page-header h1 small { 130 | display: block; 131 | line-height: @baseLineHeight; 132 | } 133 | 134 | // Update checkboxes for iOS 135 | input[type="checkbox"], 136 | input[type="radio"] { 137 | border: 1px solid #ccc; 138 | } 139 | 140 | // Remove the horizontal form styles 141 | .form-horizontal { 142 | .control-label { 143 | float: none; 144 | width: auto; 145 | padding-top: 0; 146 | text-align: left; 147 | } 148 | // Move over all input controls and content 149 | .controls { 150 | margin-left: 0; 151 | } 152 | // Move the options list down to align with labels 153 | .control-list { 154 | padding-top: 0; // has to be padding because margin collaspes 155 | } 156 | // Move over buttons in .form-actions to align with .controls 157 | .form-actions { 158 | padding-left: 10px; 159 | padding-right: 10px; 160 | } 161 | } 162 | 163 | // Medias 164 | // Reset float and spacing to stack 165 | .media .pull-left, 166 | .media .pull-right { 167 | float: none; 168 | display: block; 169 | margin-bottom: 10px; 170 | } 171 | // Remove side margins since we stack instead of indent 172 | .media-object { 173 | margin-right: 0; 174 | margin-left: 0; 175 | } 176 | 177 | // Modals 178 | .modal { 179 | top: 10px; 180 | left: 10px; 181 | right: 10px; 182 | } 183 | .modal-header .close { 184 | padding: 10px; 185 | margin: -10px; 186 | } 187 | 188 | // Carousel 189 | .carousel-caption { 190 | position: static; 191 | } 192 | 193 | } 194 | -------------------------------------------------------------------------------- /requestbin/static/less/responsive-navbar.less: -------------------------------------------------------------------------------- 1 | // 2 | // Responsive: Navbar 3 | // -------------------------------------------------- 4 | 5 | 6 | // TABLETS AND BELOW 7 | // ----------------- 8 | @media (max-width: @navbarCollapseWidth) { 9 | 10 | // UNFIX THE TOPBAR 11 | // ---------------- 12 | // Remove any padding from the body 13 | body { 14 | padding-top: 0; 15 | } 16 | // Unfix the navbars 17 | .navbar-fixed-top, 18 | .navbar-fixed-bottom { 19 | position: static; 20 | } 21 | .navbar-fixed-top { 22 | margin-bottom: @baseLineHeight; 23 | } 24 | .navbar-fixed-bottom { 25 | margin-top: @baseLineHeight; 26 | } 27 | .navbar-fixed-top .navbar-inner, 28 | .navbar-fixed-bottom .navbar-inner { 29 | padding: 5px; 30 | } 31 | .navbar .container { 32 | width: auto; 33 | padding: 0; 34 | } 35 | // Account for brand name 36 | .navbar .brand { 37 | padding-left: 10px; 38 | padding-right: 10px; 39 | margin: 0 0 0 -5px; 40 | } 41 | 42 | // COLLAPSIBLE NAVBAR 43 | // ------------------ 44 | // Nav collapse clears brand 45 | .nav-collapse { 46 | clear: both; 47 | } 48 | // Block-level the nav 49 | .nav-collapse .nav { 50 | float: none; 51 | margin: 0 0 (@baseLineHeight / 2); 52 | } 53 | .nav-collapse .nav > li { 54 | float: none; 55 | } 56 | .nav-collapse .nav > li > a { 57 | margin-bottom: 2px; 58 | } 59 | .nav-collapse .nav > .divider-vertical { 60 | display: none; 61 | } 62 | .nav-collapse .nav .nav-header { 63 | color: @navbarText; 64 | text-shadow: none; 65 | } 66 | // Nav and dropdown links in navbar 67 | .nav-collapse .nav > li > a, 68 | .nav-collapse .dropdown-menu a { 69 | padding: 9px 15px; 70 | font-weight: bold; 71 | color: @navbarLinkColor; 72 | .border-radius(3px); 73 | } 74 | // Buttons 75 | .nav-collapse .btn { 76 | padding: 4px 10px 4px; 77 | font-weight: normal; 78 | .border-radius(@baseBorderRadius); 79 | } 80 | .nav-collapse .dropdown-menu li + li a { 81 | margin-bottom: 2px; 82 | } 83 | .nav-collapse .nav > li > a:hover, 84 | .nav-collapse .nav > li > a:focus, 85 | .nav-collapse .dropdown-menu a:hover, 86 | .nav-collapse .dropdown-menu a:focus { 87 | background-color: @navbarBackground; 88 | } 89 | .navbar-inverse .nav-collapse .nav > li > a, 90 | .navbar-inverse .nav-collapse .dropdown-menu a { 91 | color: @navbarInverseLinkColor; 92 | } 93 | .navbar-inverse .nav-collapse .nav > li > a:hover, 94 | .navbar-inverse .nav-collapse .nav > li > a:focus, 95 | .navbar-inverse .nav-collapse .dropdown-menu a:hover, 96 | .navbar-inverse .nav-collapse .dropdown-menu a:focus { 97 | background-color: @navbarInverseBackground; 98 | } 99 | // Buttons in the navbar 100 | .nav-collapse.in .btn-group { 101 | margin-top: 5px; 102 | padding: 0; 103 | } 104 | // Dropdowns in the navbar 105 | .nav-collapse .dropdown-menu { 106 | position: static; 107 | top: auto; 108 | left: auto; 109 | float: none; 110 | display: none; 111 | max-width: none; 112 | margin: 0 15px; 113 | padding: 0; 114 | background-color: transparent; 115 | border: none; 116 | .border-radius(0); 117 | .box-shadow(none); 118 | } 119 | .nav-collapse .open > .dropdown-menu { 120 | display: block; 121 | } 122 | 123 | .nav-collapse .dropdown-menu:before, 124 | .nav-collapse .dropdown-menu:after { 125 | display: none; 126 | } 127 | .nav-collapse .dropdown-menu .divider { 128 | display: none; 129 | } 130 | .nav-collapse .nav > li > .dropdown-menu { 131 | &:before, 132 | &:after { 133 | display: none; 134 | } 135 | } 136 | // Forms in navbar 137 | .nav-collapse .navbar-form, 138 | .nav-collapse .navbar-search { 139 | float: none; 140 | padding: (@baseLineHeight / 2) 15px; 141 | margin: (@baseLineHeight / 2) 0; 142 | border-top: 1px solid @navbarBackground; 143 | border-bottom: 1px solid @navbarBackground; 144 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1)"); 145 | } 146 | .navbar-inverse .nav-collapse .navbar-form, 147 | .navbar-inverse .nav-collapse .navbar-search { 148 | border-top-color: @navbarInverseBackground; 149 | border-bottom-color: @navbarInverseBackground; 150 | } 151 | // Pull right (secondary) nav content 152 | .navbar .nav-collapse .nav.pull-right { 153 | float: none; 154 | margin-left: 0; 155 | } 156 | // Hide everything in the navbar save .brand and toggle button */ 157 | .nav-collapse, 158 | .nav-collapse.collapse { 159 | overflow: hidden; 160 | height: 0; 161 | } 162 | // Navbar button 163 | .navbar .btn-navbar { 164 | display: block; 165 | } 166 | 167 | // STATIC NAVBAR 168 | // ------------- 169 | .navbar-static .navbar-inner { 170 | padding-left: 10px; 171 | padding-right: 10px; 172 | } 173 | 174 | 175 | } 176 | 177 | 178 | // DEFAULT DESKTOP 179 | // --------------- 180 | 181 | @media (min-width: @navbarCollapseDesktopWidth) { 182 | 183 | // Required to make the collapsing navbar work on regular desktops 184 | .nav-collapse.collapse { 185 | height: auto !important; 186 | overflow: visible !important; 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /requestbin/static/less/reset.less: -------------------------------------------------------------------------------- 1 | // 2 | // Reset CSS 3 | // Adapted from http://github.com/necolas/normalize.css 4 | // -------------------------------------------------- 5 | 6 | 7 | // Display in IE6-9 and FF3 8 | // ------------------------- 9 | 10 | article, 11 | aside, 12 | details, 13 | figcaption, 14 | figure, 15 | footer, 16 | header, 17 | hgroup, 18 | nav, 19 | section { 20 | display: block; 21 | } 22 | 23 | // Display block in IE6-9 and FF3 24 | // ------------------------- 25 | 26 | audio, 27 | canvas, 28 | video { 29 | display: inline-block; 30 | *display: inline; 31 | *zoom: 1; 32 | } 33 | 34 | // Prevents modern browsers from displaying 'audio' without controls 35 | // ------------------------- 36 | 37 | audio:not([controls]) { 38 | display: none; 39 | } 40 | 41 | // Base settings 42 | // ------------------------- 43 | 44 | html { 45 | font-size: 100%; 46 | -webkit-text-size-adjust: 100%; 47 | -ms-text-size-adjust: 100%; 48 | } 49 | // Focus states 50 | a:focus { 51 | .tab-focus(); 52 | } 53 | // Hover & Active 54 | a:hover, 55 | a:active { 56 | outline: 0; 57 | } 58 | 59 | // Prevents sub and sup affecting line-height in all browsers 60 | // ------------------------- 61 | 62 | sub, 63 | sup { 64 | position: relative; 65 | font-size: 75%; 66 | line-height: 0; 67 | vertical-align: baseline; 68 | } 69 | sup { 70 | top: -0.5em; 71 | } 72 | sub { 73 | bottom: -0.25em; 74 | } 75 | 76 | // Img border in a's and image quality 77 | // ------------------------- 78 | 79 | img { 80 | /* Responsive images (ensure images don't scale beyond their parents) */ 81 | max-width: 100%; /* Part 1: Set a maxium relative to the parent */ 82 | width: auto\9; /* IE7-8 need help adjusting responsive images */ 83 | height: auto; /* Part 2: Scale the height according to the width, otherwise you get stretching */ 84 | 85 | vertical-align: middle; 86 | border: 0; 87 | -ms-interpolation-mode: bicubic; 88 | } 89 | 90 | // Prevent max-width from affecting Google Maps 91 | #map_canvas img, 92 | .google-maps img { 93 | max-width: none; 94 | } 95 | 96 | // Forms 97 | // ------------------------- 98 | 99 | // Font size in all browsers, margin changes, misc consistency 100 | button, 101 | input, 102 | select, 103 | textarea { 104 | margin: 0; 105 | font-size: 100%; 106 | vertical-align: middle; 107 | } 108 | button, 109 | input { 110 | *overflow: visible; // Inner spacing ie IE6/7 111 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet 112 | } 113 | button::-moz-focus-inner, 114 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 115 | padding: 0; 116 | border: 0; 117 | } 118 | button, 119 | html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. 120 | input[type="reset"], 121 | input[type="submit"] { 122 | -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS. 123 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. 124 | } 125 | label, 126 | select, 127 | button, 128 | input[type="button"], 129 | input[type="reset"], 130 | input[type="submit"], 131 | input[type="radio"], 132 | input[type="checkbox"] { 133 | cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. 134 | } 135 | input[type="search"] { // Appearance in Safari/Chrome 136 | .box-sizing(content-box); 137 | -webkit-appearance: textfield; 138 | } 139 | input[type="search"]::-webkit-search-decoration, 140 | input[type="search"]::-webkit-search-cancel-button { 141 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 142 | } 143 | textarea { 144 | overflow: auto; // Remove vertical scrollbar in IE6-9 145 | vertical-align: top; // Readability and alignment cross-browser 146 | } 147 | 148 | 149 | // Printing 150 | // ------------------------- 151 | // Source: https://github.com/h5bp/html5-boilerplate/blob/master/css/main.css 152 | 153 | @media print { 154 | 155 | * { 156 | text-shadow: none !important; 157 | color: #000 !important; // Black prints faster: h5bp.com/s 158 | background: transparent !important; 159 | box-shadow: none !important; 160 | } 161 | 162 | a, 163 | a:visited { 164 | text-decoration: underline; 165 | } 166 | 167 | a[href]:after { 168 | content: " (" attr(href) ")"; 169 | } 170 | 171 | abbr[title]:after { 172 | content: " (" attr(title) ")"; 173 | } 174 | 175 | // Don't show links for images, or javascript/internal links 176 | .ir a:after, 177 | a[href^="javascript:"]:after, 178 | a[href^="#"]:after { 179 | content: ""; 180 | } 181 | 182 | pre, 183 | blockquote { 184 | border: 1px solid #999; 185 | page-break-inside: avoid; 186 | } 187 | 188 | thead { 189 | display: table-header-group; // h5bp.com/t 190 | } 191 | 192 | tr, 193 | img { 194 | page-break-inside: avoid; 195 | } 196 | 197 | img { 198 | max-width: 100% !important; 199 | } 200 | 201 | @page { 202 | margin: 0.5cm; 203 | } 204 | 205 | p, 206 | h2, 207 | h3 { 208 | orphans: 3; 209 | widows: 3; 210 | } 211 | 212 | h2, 213 | h3 { 214 | page-break-after: avoid; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /requestbin/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block title %}RequestBin — Collect, inspect and debug HTTP requests and webhooks{% endblock %} 5 | {% block icon %}{% endblock %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% block head %}{% endblock %} 14 | 15 | 16 | 17 |
18 |
19 |

A Runscope community project. Send us feedback!

20 |
21 |
22 |
23 |
24 |
25 |

26 | 27 | RequestBin 28 |

29 | 34 |
35 |
36 |
37 | 38 |
39 | {% set width = 12 %} 40 | {% if recent %} {% set width = 10 %} {% endif %} 41 |
42 | {% block content %} 43 | {% endblock %} 44 |
45 | 46 | {% if recent %} 47 |
48 | {% block sidebar %} 49 |
History
50 |
    51 | {% for bin in recent %} 52 |
  • 53 | 54 | {{bin.name}} {% if bin.private %}{% endif %} 55 | ({{bin.request_count}}) 56 | 57 |
  • 58 | {% else %} 59 |

    60 | No recent bins. 61 |

    62 | {% endfor %} 63 |
64 | {% endblock %} 65 |
66 | {% endif %} 67 |
68 | 69 | 98 | 99 | {% block script %} 100 | {% endblock %} 101 | 102 | 103 | -------------------------------------------------------------------------------- /requestbin/static/less/buttons.less: -------------------------------------------------------------------------------- 1 | // 2 | // Buttons 3 | // -------------------------------------------------- 4 | 5 | 6 | // Base styles 7 | // -------------------------------------------------- 8 | 9 | // Core 10 | .btn { 11 | display: inline-block; 12 | .ie7-inline-block(); 13 | padding: 4px 12px; 14 | margin-bottom: 0; // For input.btn 15 | font-size: @baseFontSize; 16 | line-height: @baseLineHeight; 17 | text-align: center; 18 | vertical-align: middle; 19 | cursor: pointer; 20 | .buttonBackground(@btnBackground, @btnBackgroundHighlight, @grayDark, 0 1px 1px rgba(255,255,255,.75)); 21 | border: 1px solid @btnBorder; 22 | *border: 0; // Remove the border to prevent IE7's black border on input:focus 23 | border-bottom-color: darken(@btnBorder, 10%); 24 | .border-radius(@baseBorderRadius); 25 | .ie7-restore-left-whitespace(); // Give IE7 some love 26 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 27 | 28 | // Hover/focus state 29 | &:hover, 30 | &:focus { 31 | color: @grayDark; 32 | text-decoration: none; 33 | background-position: 0 -15px; 34 | 35 | // transition is only when going to hover/focus, otherwise the background 36 | // behind the gradient (there for IE<=9 fallback) gets mismatched 37 | .transition(background-position .1s linear); 38 | } 39 | 40 | // Focus state for keyboard and accessibility 41 | &:focus { 42 | .tab-focus(); 43 | } 44 | 45 | // Active state 46 | &.active, 47 | &:active { 48 | background-image: none; 49 | outline: 0; 50 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); 51 | } 52 | 53 | // Disabled state 54 | &.disabled, 55 | &[disabled] { 56 | cursor: default; 57 | background-image: none; 58 | .opacity(65); 59 | .box-shadow(none); 60 | } 61 | 62 | } 63 | 64 | 65 | 66 | // Button Sizes 67 | // -------------------------------------------------- 68 | 69 | // Large 70 | .btn-large { 71 | padding: @paddingLarge; 72 | font-size: @fontSizeLarge; 73 | .border-radius(@borderRadiusLarge); 74 | } 75 | .btn-large [class^="icon-"], 76 | .btn-large [class*=" icon-"] { 77 | margin-top: 4px; 78 | } 79 | 80 | // Small 81 | .btn-small { 82 | padding: @paddingSmall; 83 | font-size: @fontSizeSmall; 84 | .border-radius(@borderRadiusSmall); 85 | } 86 | .btn-small [class^="icon-"], 87 | .btn-small [class*=" icon-"] { 88 | margin-top: 0; 89 | } 90 | .btn-mini [class^="icon-"], 91 | .btn-mini [class*=" icon-"] { 92 | margin-top: -1px; 93 | } 94 | 95 | // Mini 96 | .btn-mini { 97 | padding: @paddingMini; 98 | font-size: @fontSizeMini; 99 | .border-radius(@borderRadiusSmall); 100 | } 101 | 102 | 103 | // Block button 104 | // ------------------------- 105 | 106 | .btn-block { 107 | display: block; 108 | width: 100%; 109 | padding-left: 0; 110 | padding-right: 0; 111 | .box-sizing(border-box); 112 | } 113 | 114 | // Vertically space out multiple block buttons 115 | .btn-block + .btn-block { 116 | margin-top: 5px; 117 | } 118 | 119 | // Specificity overrides 120 | input[type="submit"], 121 | input[type="reset"], 122 | input[type="button"] { 123 | &.btn-block { 124 | width: 100%; 125 | } 126 | } 127 | 128 | 129 | 130 | // Alternate buttons 131 | // -------------------------------------------------- 132 | 133 | // Provide *some* extra contrast for those who can get it 134 | .btn-primary.active, 135 | .btn-warning.active, 136 | .btn-danger.active, 137 | .btn-success.active, 138 | .btn-info.active, 139 | .btn-inverse.active { 140 | color: rgba(255,255,255,.75); 141 | } 142 | 143 | // Set the backgrounds 144 | // ------------------------- 145 | .btn-primary { 146 | .buttonBackground(@btnPrimaryBackground, @btnPrimaryBackgroundHighlight); 147 | } 148 | // Warning appears are orange 149 | .btn-warning { 150 | .buttonBackground(@btnWarningBackground, @btnWarningBackgroundHighlight); 151 | } 152 | // Danger and error appear as red 153 | .btn-danger { 154 | .buttonBackground(@btnDangerBackground, @btnDangerBackgroundHighlight); 155 | } 156 | // Success appears as green 157 | .btn-success { 158 | .buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight); 159 | } 160 | // Info appears as a neutral blue 161 | .btn-info { 162 | .buttonBackground(@btnInfoBackground, @btnInfoBackgroundHighlight); 163 | } 164 | // Inverse appears as dark gray 165 | .btn-inverse { 166 | .buttonBackground(@btnInverseBackground, @btnInverseBackgroundHighlight); 167 | } 168 | 169 | 170 | // Cross-browser Jank 171 | // -------------------------------------------------- 172 | 173 | button.btn, 174 | input[type="submit"].btn { 175 | 176 | // Firefox 3.6 only I believe 177 | &::-moz-focus-inner { 178 | padding: 0; 179 | border: 0; 180 | } 181 | 182 | // IE7 has some default padding on button controls 183 | *padding-top: 3px; 184 | *padding-bottom: 3px; 185 | 186 | &.btn-large { 187 | *padding-top: 7px; 188 | *padding-bottom: 7px; 189 | } 190 | &.btn-small { 191 | *padding-top: 3px; 192 | *padding-bottom: 3px; 193 | } 194 | &.btn-mini { 195 | *padding-top: 1px; 196 | *padding-bottom: 1px; 197 | } 198 | } 199 | 200 | 201 | // Link buttons 202 | // -------------------------------------------------- 203 | 204 | // Make a button look and behave like a link 205 | .btn-link, 206 | .btn-link:active, 207 | .btn-link[disabled] { 208 | background-color: transparent; 209 | background-image: none; 210 | .box-shadow(none); 211 | } 212 | .btn-link { 213 | border-color: transparent; 214 | cursor: pointer; 215 | color: @linkColor; 216 | .border-radius(0); 217 | } 218 | .btn-link:hover, 219 | .btn-link:focus { 220 | color: @linkColorHover; 221 | text-decoration: underline; 222 | background-color: transparent; 223 | } 224 | .btn-link[disabled]:hover, 225 | .btn-link[disabled]:focus { 226 | color: @grayDark; 227 | text-decoration: none; 228 | } 229 | -------------------------------------------------------------------------------- /requestbin/models.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import json 3 | import time 4 | import datetime 5 | import os 6 | import re 7 | import logging 8 | 9 | import msgpack 10 | 11 | from .util import random_color 12 | from .util import tinyid 13 | from .util import solid16x16gif_datauri 14 | 15 | from requestbin import config 16 | 17 | __MAX_JSON_TO_PRETTYPARSE_IN_BYTES = 300*1024 18 | 19 | class Bin(object): 20 | max_requests = config.MAX_REQUESTS 21 | 22 | def __init__(self, private=False): 23 | self.created = time.time() 24 | self.private = private 25 | self.color = random_color() 26 | self.name = tinyid(8) 27 | self.favicon_uri = solid16x16gif_datauri(*self.color) 28 | self.requests = [] 29 | self.secret_key = os.urandom(24) if self.private else None 30 | 31 | def json(self): 32 | return json.dumps(self.to_dict()) 33 | 34 | def to_dict(self): 35 | return dict( 36 | private=self.private, 37 | color=self.color, 38 | name=self.name, 39 | request_count=self.request_count) 40 | 41 | def dump(self): 42 | o = copy.copy(self.__dict__) 43 | o['requests'] = [r.dump() for r in self.requests] 44 | return msgpack.dumps(o) 45 | 46 | @staticmethod 47 | def load(data): 48 | o = msgpack.loads(data) 49 | o['requests'] = [Request.load(r) for r in o['requests']] 50 | b = Bin() 51 | b.__dict__ = o 52 | return b 53 | 54 | @property 55 | def request_count(self): 56 | return len(self.requests) 57 | 58 | def add(self, request): 59 | self.requests.insert(0, Request(request)) 60 | if len(self.requests) > self.max_requests: 61 | for _ in xrange(self.max_requests, len(self.requests)): 62 | self.requests.pop(self.max_requests) 63 | 64 | 65 | class Request(object): 66 | ignore_headers = config.IGNORE_HEADERS 67 | max_raw_size = config.MAX_RAW_SIZE 68 | 69 | def __init__(self, input=None): 70 | if input: 71 | self.id = tinyid(6) 72 | self.time = time.time() 73 | self.remote_addr = input.headers.get('X-Forwarded-For', input.remote_addr) 74 | self.method = input.method 75 | self.headers = dict(input.headers) 76 | 77 | for header in self.ignore_headers: 78 | self.headers.pop(header, None) 79 | 80 | self.query_string = input.args.to_dict(flat=True) 81 | self.form_data = [] 82 | 83 | for k in input.form: 84 | self.form_data.append([k, input.values[k]]) 85 | 86 | self.body = input.data 87 | self.path = input.path 88 | self.content_type = self.headers.get("Content-Type", "") 89 | 90 | self.raw = input.environ.get('raw') 91 | self.content_length = len(self.raw) 92 | 93 | # for header in self.ignore_headers: 94 | # self.raw = re.sub(r'{}: [^\n]+\n'.format(header), 95 | # '', self.raw, flags=re.IGNORECASE) 96 | if self.raw and len(self.raw) > self.max_raw_size: 97 | self.raw = self.raw[0:self.max_raw_size] 98 | 99 | 100 | def to_dict(self): 101 | return dict( 102 | id=self.id, 103 | time=self.time, 104 | remote_addr=self.remote_addr, 105 | method=self.method, 106 | headers=self.headers, 107 | query_string=self.query_string, 108 | raw=self.raw, 109 | form_data=self.form_data, 110 | body=self.body, 111 | path=self.path, 112 | content_length=self.content_length, 113 | content_type=self.content_type, 114 | ) 115 | 116 | def get_raw(self): 117 | if self.raw: 118 | try: 119 | if self.content_type == 'application/json' and self.content_length < __MAX_JSON_TO_PRETTYPARSE_IN_BYTES: 120 | return json.dumps(json.loads(self.raw), indent=4) 121 | except Exception as e: 122 | logging.exception("Error parsing json to show: %s" % e) 123 | 124 | return self.raw 125 | 126 | return None 127 | 128 | @property 129 | def created(self): 130 | return datetime.datetime.fromtimestamp(self.time) 131 | 132 | def dump(self): 133 | return msgpack.dumps(self.__dict__) 134 | 135 | @staticmethod 136 | def load(data): 137 | r = Request() 138 | try: 139 | r.__dict__ = msgpack.loads(data, encoding="utf-8") 140 | except (UnicodeDecodeError): 141 | r.__dict__ = msgpack.loads(data, encoding="ISO-8859-1") 142 | 143 | return r 144 | 145 | # def __iter__(self): 146 | # out = [] 147 | # if self.form_data: 148 | # if hasattr(self.form_data, 'items'): 149 | # items = self.form_data.items() 150 | # else: 151 | # items = self.form_data 152 | # for k,v in items: 153 | # try: 154 | # outval = json.dumps(json.loads(v), sort_keys=True, indent=2) 155 | # except (ValueError, TypeError): 156 | # outval = v 157 | # out.append((k, outval)) 158 | # else: 159 | # try: 160 | # out = (('body', json.dumps(json.loads(self.body), sort_keys=True, indent=2)),) 161 | # except (ValueError, TypeError): 162 | # out = (('body', self.body),) 163 | 164 | # # Sort by field/file then by field name 165 | # files = list() 166 | # fields = list() 167 | # for (k,v) in out: 168 | # if type(v) is dict: 169 | # files.append((k,v)) 170 | # else: 171 | # fields.append((k,v)) 172 | # return iter(sorted(fields) + sorted(files)) 173 | 174 | -------------------------------------------------------------------------------- /requestbin/static/less/type.less: -------------------------------------------------------------------------------- 1 | // 2 | // Typography 3 | // -------------------------------------------------- 4 | 5 | 6 | // Body text 7 | // ------------------------- 8 | 9 | p { 10 | margin: 0 0 @baseLineHeight / 2; 11 | } 12 | .lead { 13 | margin-bottom: @baseLineHeight; 14 | font-size: @baseFontSize * 1.5; 15 | font-weight: 200; 16 | line-height: @baseLineHeight * 1.5; 17 | } 18 | 19 | 20 | // Emphasis & misc 21 | // ------------------------- 22 | 23 | // Ex: 14px base font * 85% = about 12px 24 | small { font-size: 85%; } 25 | 26 | strong { font-weight: bold; } 27 | em { font-style: italic; } 28 | cite { font-style: normal; } 29 | 30 | // Utility classes 31 | .muted { color: @grayLight; } 32 | a.muted:hover, 33 | a.muted:focus { color: darken(@grayLight, 10%); } 34 | 35 | .text-warning { color: @warningText; } 36 | a.text-warning:hover, 37 | a.text-warning:focus { color: darken(@warningText, 10%); } 38 | 39 | .text-error { color: @errorText; } 40 | a.text-error:hover, 41 | a.text-error:focus { color: darken(@errorText, 10%); } 42 | 43 | .text-info { color: @infoText; } 44 | a.text-info:hover, 45 | a.text-info:focus { color: darken(@infoText, 10%); } 46 | 47 | .text-success { color: @successText; } 48 | a.text-success:hover, 49 | a.text-success:focus { color: darken(@successText, 10%); } 50 | 51 | .text-left { text-align: left; } 52 | .text-right { text-align: right; } 53 | .text-center { text-align: center; } 54 | 55 | 56 | // Headings 57 | // ------------------------- 58 | 59 | h1, h2, h3, h4, h5, h6 { 60 | margin: (@baseLineHeight / 2) 0; 61 | font-family: @headingsFontFamily; 62 | font-weight: @headingsFontWeight; 63 | line-height: @baseLineHeight; 64 | color: @headingsColor; 65 | text-rendering: optimizelegibility; // Fix the character spacing for headings 66 | small { 67 | font-weight: normal; 68 | line-height: 1; 69 | color: @grayLight; 70 | } 71 | } 72 | 73 | h1, 74 | h2, 75 | h3 { line-height: @baseLineHeight * 2; } 76 | 77 | h1 { font-size: @baseFontSize * 2.75; } // ~38px 78 | h2 { font-size: @baseFontSize * 2.25; } // ~32px 79 | h3 { font-size: @baseFontSize * 1.75; } // ~24px 80 | h4 { font-size: @baseFontSize * 1.25; } // ~18px 81 | h5 { font-size: @baseFontSize; } 82 | h6 { font-size: @baseFontSize * 0.85; } // ~12px 83 | 84 | h1 small { font-size: @baseFontSize * 1.75; } // ~24px 85 | h2 small { font-size: @baseFontSize * 1.25; } // ~18px 86 | h3 small { font-size: @baseFontSize; } 87 | h4 small { font-size: @baseFontSize; } 88 | 89 | 90 | // Page header 91 | // ------------------------- 92 | 93 | .page-header { 94 | padding-bottom: (@baseLineHeight / 2) - 1; 95 | margin: @baseLineHeight 0 (@baseLineHeight * 1.5); 96 | border-bottom: 1px solid @grayLighter; 97 | } 98 | 99 | 100 | 101 | // Lists 102 | // -------------------------------------------------- 103 | 104 | // Unordered and Ordered lists 105 | ul, ol { 106 | padding: 0; 107 | margin: 0 0 @baseLineHeight / 2 25px; 108 | } 109 | ul ul, 110 | ul ol, 111 | ol ol, 112 | ol ul { 113 | margin-bottom: 0; 114 | } 115 | li { 116 | line-height: @baseLineHeight; 117 | } 118 | 119 | // Remove default list styles 120 | ul.unstyled, 121 | ol.unstyled { 122 | margin-left: 0; 123 | list-style: none; 124 | } 125 | 126 | // Single-line list items 127 | ul.inline, 128 | ol.inline { 129 | margin-left: 0; 130 | list-style: none; 131 | > li { 132 | display: inline-block; 133 | .ie7-inline-block(); 134 | padding-left: 5px; 135 | padding-right: 5px; 136 | } 137 | } 138 | 139 | // Description Lists 140 | dl { 141 | margin-bottom: @baseLineHeight; 142 | } 143 | dt, 144 | dd { 145 | line-height: @baseLineHeight; 146 | } 147 | dt { 148 | font-weight: bold; 149 | } 150 | dd { 151 | margin-left: @baseLineHeight / 2; 152 | } 153 | // Horizontal layout (like forms) 154 | .dl-horizontal { 155 | .clearfix(); // Ensure dl clears floats if empty dd elements present 156 | dt { 157 | float: left; 158 | width: @horizontalComponentOffset - 20; 159 | clear: left; 160 | text-align: right; 161 | .text-overflow(); 162 | } 163 | dd { 164 | margin-left: @horizontalComponentOffset; 165 | } 166 | } 167 | 168 | // MISC 169 | // ---- 170 | 171 | // Horizontal rules 172 | hr { 173 | margin: @baseLineHeight 0; 174 | border: 0; 175 | border-top: 1px solid @hrBorder; 176 | border-bottom: 1px solid @white; 177 | } 178 | 179 | // Abbreviations and acronyms 180 | abbr[title], 181 | // Added data-* attribute to help out our tooltip plugin, per https://github.com/twitter/bootstrap/issues/5257 182 | abbr[data-original-title] { 183 | cursor: help; 184 | border-bottom: 1px dotted @grayLight; 185 | } 186 | abbr.initialism { 187 | font-size: 90%; 188 | text-transform: uppercase; 189 | } 190 | 191 | // Blockquotes 192 | blockquote { 193 | padding: 0 0 0 15px; 194 | margin: 0 0 @baseLineHeight; 195 | border-left: 5px solid @grayLighter; 196 | p { 197 | margin-bottom: 0; 198 | font-size: @baseFontSize * 1.25; 199 | font-weight: 300; 200 | line-height: 1.25; 201 | } 202 | small { 203 | display: block; 204 | line-height: @baseLineHeight; 205 | color: @grayLight; 206 | &:before { 207 | content: '\2014 \00A0'; 208 | } 209 | } 210 | 211 | // Float right with text-align: right 212 | &.pull-right { 213 | float: right; 214 | padding-right: 15px; 215 | padding-left: 0; 216 | border-right: 5px solid @grayLighter; 217 | border-left: 0; 218 | p, 219 | small { 220 | text-align: right; 221 | } 222 | small { 223 | &:before { 224 | content: ''; 225 | } 226 | &:after { 227 | content: '\00A0 \2014'; 228 | } 229 | } 230 | } 231 | } 232 | 233 | // Quotes 234 | q:before, 235 | q:after, 236 | blockquote:before, 237 | blockquote:after { 238 | content: ""; 239 | } 240 | 241 | // Addresses 242 | address { 243 | display: block; 244 | margin-bottom: @baseLineHeight; 245 | font-style: normal; 246 | line-height: @baseLineHeight; 247 | } 248 | -------------------------------------------------------------------------------- /requestbin/static/less/button-groups.less: -------------------------------------------------------------------------------- 1 | // 2 | // Button groups 3 | // -------------------------------------------------- 4 | 5 | 6 | // Make the div behave like a button 7 | .btn-group { 8 | position: relative; 9 | display: inline-block; 10 | .ie7-inline-block(); 11 | font-size: 0; // remove as part 1 of font-size inline-block hack 12 | vertical-align: middle; // match .btn alignment given font-size hack above 13 | white-space: nowrap; // prevent buttons from wrapping when in tight spaces (e.g., the table on the tests page) 14 | .ie7-restore-left-whitespace(); 15 | } 16 | 17 | // Space out series of button groups 18 | .btn-group + .btn-group { 19 | margin-left: 5px; 20 | } 21 | 22 | // Optional: Group multiple button groups together for a toolbar 23 | .btn-toolbar { 24 | font-size: 0; // Hack to remove whitespace that results from using inline-block 25 | margin-top: @baseLineHeight / 2; 26 | margin-bottom: @baseLineHeight / 2; 27 | > .btn + .btn, 28 | > .btn-group + .btn, 29 | > .btn + .btn-group { 30 | margin-left: 5px; 31 | } 32 | } 33 | 34 | // Float them, remove border radius, then re-add to first and last elements 35 | .btn-group > .btn { 36 | position: relative; 37 | .border-radius(0); 38 | } 39 | .btn-group > .btn + .btn { 40 | margin-left: -1px; 41 | } 42 | .btn-group > .btn, 43 | .btn-group > .dropdown-menu, 44 | .btn-group > .popover { 45 | font-size: @baseFontSize; // redeclare as part 2 of font-size inline-block hack 46 | } 47 | 48 | // Reset fonts for other sizes 49 | .btn-group > .btn-mini { 50 | font-size: @fontSizeMini; 51 | } 52 | .btn-group > .btn-small { 53 | font-size: @fontSizeSmall; 54 | } 55 | .btn-group > .btn-large { 56 | font-size: @fontSizeLarge; 57 | } 58 | 59 | // Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match 60 | .btn-group > .btn:first-child { 61 | margin-left: 0; 62 | .border-top-left-radius(@baseBorderRadius); 63 | .border-bottom-left-radius(@baseBorderRadius); 64 | } 65 | // Need .dropdown-toggle since :last-child doesn't apply given a .dropdown-menu immediately after it 66 | .btn-group > .btn:last-child, 67 | .btn-group > .dropdown-toggle { 68 | .border-top-right-radius(@baseBorderRadius); 69 | .border-bottom-right-radius(@baseBorderRadius); 70 | } 71 | // Reset corners for large buttons 72 | .btn-group > .btn.large:first-child { 73 | margin-left: 0; 74 | .border-top-left-radius(@borderRadiusLarge); 75 | .border-bottom-left-radius(@borderRadiusLarge); 76 | } 77 | .btn-group > .btn.large:last-child, 78 | .btn-group > .large.dropdown-toggle { 79 | .border-top-right-radius(@borderRadiusLarge); 80 | .border-bottom-right-radius(@borderRadiusLarge); 81 | } 82 | 83 | // On hover/focus/active, bring the proper btn to front 84 | .btn-group > .btn:hover, 85 | .btn-group > .btn:focus, 86 | .btn-group > .btn:active, 87 | .btn-group > .btn.active { 88 | z-index: 2; 89 | } 90 | 91 | // On active and open, don't show outline 92 | .btn-group .dropdown-toggle:active, 93 | .btn-group.open .dropdown-toggle { 94 | outline: 0; 95 | } 96 | 97 | 98 | 99 | // Split button dropdowns 100 | // ---------------------- 101 | 102 | // Give the line between buttons some depth 103 | .btn-group > .btn + .dropdown-toggle { 104 | padding-left: 8px; 105 | padding-right: 8px; 106 | .box-shadow(~"inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)"); 107 | *padding-top: 5px; 108 | *padding-bottom: 5px; 109 | } 110 | .btn-group > .btn-mini + .dropdown-toggle { 111 | padding-left: 5px; 112 | padding-right: 5px; 113 | *padding-top: 2px; 114 | *padding-bottom: 2px; 115 | } 116 | .btn-group > .btn-small + .dropdown-toggle { 117 | *padding-top: 5px; 118 | *padding-bottom: 4px; 119 | } 120 | .btn-group > .btn-large + .dropdown-toggle { 121 | padding-left: 12px; 122 | padding-right: 12px; 123 | *padding-top: 7px; 124 | *padding-bottom: 7px; 125 | } 126 | 127 | .btn-group.open { 128 | 129 | // The clickable button for toggling the menu 130 | // Remove the gradient and set the same inset shadow as the :active state 131 | .dropdown-toggle { 132 | background-image: none; 133 | .box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)"); 134 | } 135 | 136 | // Keep the hover's background when dropdown is open 137 | .btn.dropdown-toggle { 138 | background-color: @btnBackgroundHighlight; 139 | } 140 | .btn-primary.dropdown-toggle { 141 | background-color: @btnPrimaryBackgroundHighlight; 142 | } 143 | .btn-warning.dropdown-toggle { 144 | background-color: @btnWarningBackgroundHighlight; 145 | } 146 | .btn-danger.dropdown-toggle { 147 | background-color: @btnDangerBackgroundHighlight; 148 | } 149 | .btn-success.dropdown-toggle { 150 | background-color: @btnSuccessBackgroundHighlight; 151 | } 152 | .btn-info.dropdown-toggle { 153 | background-color: @btnInfoBackgroundHighlight; 154 | } 155 | .btn-inverse.dropdown-toggle { 156 | background-color: @btnInverseBackgroundHighlight; 157 | } 158 | } 159 | 160 | 161 | // Reposition the caret 162 | .btn .caret { 163 | margin-top: 8px; 164 | margin-left: 0; 165 | } 166 | // Carets in other button sizes 167 | .btn-large .caret { 168 | margin-top: 6px; 169 | } 170 | .btn-large .caret { 171 | border-left-width: 5px; 172 | border-right-width: 5px; 173 | border-top-width: 5px; 174 | } 175 | .btn-mini .caret, 176 | .btn-small .caret { 177 | margin-top: 8px; 178 | } 179 | // Upside down carets for .dropup 180 | .dropup .btn-large .caret { 181 | border-bottom-width: 5px; 182 | } 183 | 184 | 185 | 186 | // Account for other colors 187 | .btn-primary, 188 | .btn-warning, 189 | .btn-danger, 190 | .btn-info, 191 | .btn-success, 192 | .btn-inverse { 193 | .caret { 194 | border-top-color: @white; 195 | border-bottom-color: @white; 196 | } 197 | } 198 | 199 | 200 | 201 | // Vertical button groups 202 | // ---------------------- 203 | 204 | .btn-group-vertical { 205 | display: inline-block; // makes buttons only take up the width they need 206 | .ie7-inline-block(); 207 | } 208 | .btn-group-vertical > .btn { 209 | display: block; 210 | float: none; 211 | max-width: 100%; 212 | .border-radius(0); 213 | } 214 | .btn-group-vertical > .btn + .btn { 215 | margin-left: 0; 216 | margin-top: -1px; 217 | } 218 | .btn-group-vertical > .btn:first-child { 219 | .border-radius(@baseBorderRadius @baseBorderRadius 0 0); 220 | } 221 | .btn-group-vertical > .btn:last-child { 222 | .border-radius(0 0 @baseBorderRadius @baseBorderRadius); 223 | } 224 | .btn-group-vertical > .btn-large:first-child { 225 | .border-radius(@borderRadiusLarge @borderRadiusLarge 0 0); 226 | } 227 | .btn-group-vertical > .btn-large:last-child { 228 | .border-radius(0 0 @borderRadiusLarge @borderRadiusLarge); 229 | } 230 | -------------------------------------------------------------------------------- /requestbin/static/less/dropdowns.less: -------------------------------------------------------------------------------- 1 | // 2 | // Dropdown menus 3 | // -------------------------------------------------- 4 | 5 | 6 | // Use the .menu class on any
  • element within the topbar or ul.tabs and you'll get some superfancy dropdowns 7 | .dropup, 8 | .dropdown { 9 | position: relative; 10 | } 11 | .dropdown-toggle { 12 | // The caret makes the toggle a bit too tall in IE7 13 | *margin-bottom: -3px; 14 | } 15 | .dropdown-toggle:active, 16 | .open .dropdown-toggle { 17 | outline: 0; 18 | } 19 | 20 | // Dropdown arrow/caret 21 | // -------------------- 22 | .caret { 23 | display: inline-block; 24 | width: 0; 25 | height: 0; 26 | vertical-align: top; 27 | border-top: 4px solid @black; 28 | border-right: 4px solid transparent; 29 | border-left: 4px solid transparent; 30 | content: ""; 31 | } 32 | 33 | // Place the caret 34 | .dropdown .caret { 35 | margin-top: 8px; 36 | margin-left: 2px; 37 | } 38 | 39 | // The dropdown menu (ul) 40 | // ---------------------- 41 | .dropdown-menu { 42 | position: absolute; 43 | top: 100%; 44 | left: 0; 45 | z-index: @zindexDropdown; 46 | display: none; // none by default, but block on "open" of the menu 47 | float: left; 48 | min-width: 160px; 49 | padding: 5px 0; 50 | margin: 2px 0 0; // override default ul 51 | list-style: none; 52 | background-color: @dropdownBackground; 53 | border: 1px solid #ccc; // Fallback for IE7-8 54 | border: 1px solid @dropdownBorder; 55 | *border-right-width: 2px; 56 | *border-bottom-width: 2px; 57 | .border-radius(6px); 58 | .box-shadow(0 5px 10px rgba(0,0,0,.2)); 59 | -webkit-background-clip: padding-box; 60 | -moz-background-clip: padding; 61 | background-clip: padding-box; 62 | 63 | // Aligns the dropdown menu to right 64 | &.pull-right { 65 | right: 0; 66 | left: auto; 67 | } 68 | 69 | // Dividers (basically an hr) within the dropdown 70 | .divider { 71 | .nav-divider(@dropdownDividerTop, @dropdownDividerBottom); 72 | } 73 | 74 | // Links within the dropdown menu 75 | > li > a { 76 | display: block; 77 | padding: 3px 20px; 78 | clear: both; 79 | font-weight: normal; 80 | line-height: @baseLineHeight; 81 | color: @dropdownLinkColor; 82 | white-space: nowrap; 83 | } 84 | } 85 | 86 | // Hover/Focus state 87 | // ----------- 88 | .dropdown-menu > li > a:hover, 89 | .dropdown-menu > li > a:focus, 90 | .dropdown-submenu:hover > a, 91 | .dropdown-submenu:focus > a { 92 | text-decoration: none; 93 | color: @dropdownLinkColorHover; 94 | #gradient > .vertical(@dropdownLinkBackgroundHover, darken(@dropdownLinkBackgroundHover, 5%)); 95 | } 96 | 97 | // Active state 98 | // ------------ 99 | .dropdown-menu > .active > a, 100 | .dropdown-menu > .active > a:hover, 101 | .dropdown-menu > .active > a:focus { 102 | color: @dropdownLinkColorActive; 103 | text-decoration: none; 104 | outline: 0; 105 | #gradient > .vertical(@dropdownLinkBackgroundActive, darken(@dropdownLinkBackgroundActive, 5%)); 106 | } 107 | 108 | // Disabled state 109 | // -------------- 110 | // Gray out text and ensure the hover/focus state remains gray 111 | .dropdown-menu > .disabled > a, 112 | .dropdown-menu > .disabled > a:hover, 113 | .dropdown-menu > .disabled > a:focus { 114 | color: @grayLight; 115 | } 116 | // Nuke hover/focus effects 117 | .dropdown-menu > .disabled > a:hover, 118 | .dropdown-menu > .disabled > a:focus { 119 | text-decoration: none; 120 | background-color: transparent; 121 | background-image: none; // Remove CSS gradient 122 | .reset-filter(); 123 | cursor: default; 124 | } 125 | 126 | // Open state for the dropdown 127 | // --------------------------- 128 | .open { 129 | // IE7's z-index only goes to the nearest positioned ancestor, which would 130 | // make the menu appear below buttons that appeared later on the page 131 | *z-index: @zindexDropdown; 132 | 133 | & > .dropdown-menu { 134 | display: block; 135 | } 136 | } 137 | 138 | // Backdrop to catch body clicks on mobile, etc. 139 | // --------------------------- 140 | .dropdown-backdrop { 141 | position: fixed; 142 | left: 0; 143 | right: 0; 144 | bottom: 0; 145 | top: 0; 146 | z-index: @zindexDropdown - 10; 147 | } 148 | 149 | // Right aligned dropdowns 150 | // --------------------------- 151 | .pull-right > .dropdown-menu { 152 | right: 0; 153 | left: auto; 154 | } 155 | 156 | // Allow for dropdowns to go bottom up (aka, dropup-menu) 157 | // ------------------------------------------------------ 158 | // Just add .dropup after the standard .dropdown class and you're set, bro. 159 | // TODO: abstract this so that the navbar fixed styles are not placed here? 160 | .dropup, 161 | .navbar-fixed-bottom .dropdown { 162 | // Reverse the caret 163 | .caret { 164 | border-top: 0; 165 | border-bottom: 4px solid @black; 166 | content: ""; 167 | } 168 | // Different positioning for bottom up menu 169 | .dropdown-menu { 170 | top: auto; 171 | bottom: 100%; 172 | margin-bottom: 1px; 173 | } 174 | } 175 | 176 | // Sub menus 177 | // --------------------------- 178 | .dropdown-submenu { 179 | position: relative; 180 | } 181 | // Default dropdowns 182 | .dropdown-submenu > .dropdown-menu { 183 | top: 0; 184 | left: 100%; 185 | margin-top: -6px; 186 | margin-left: -1px; 187 | .border-radius(0 6px 6px 6px); 188 | } 189 | .dropdown-submenu:hover > .dropdown-menu { 190 | display: block; 191 | } 192 | 193 | // Dropups 194 | .dropup .dropdown-submenu > .dropdown-menu { 195 | top: auto; 196 | bottom: 0; 197 | margin-top: 0; 198 | margin-bottom: -2px; 199 | .border-radius(5px 5px 5px 0); 200 | } 201 | 202 | // Caret to indicate there is a submenu 203 | .dropdown-submenu > a:after { 204 | display: block; 205 | content: " "; 206 | float: right; 207 | width: 0; 208 | height: 0; 209 | border-color: transparent; 210 | border-style: solid; 211 | border-width: 5px 0 5px 5px; 212 | border-left-color: darken(@dropdownBackground, 20%); 213 | margin-top: 5px; 214 | margin-right: -10px; 215 | } 216 | .dropdown-submenu:hover > a:after { 217 | border-left-color: @dropdownLinkColorHover; 218 | } 219 | 220 | // Left aligned submenus 221 | .dropdown-submenu.pull-left { 222 | // Undo the float 223 | // Yes, this is awkward since .pull-left adds a float, but it sticks to our conventions elsewhere. 224 | float: none; 225 | 226 | // Positioning the submenu 227 | > .dropdown-menu { 228 | left: -100%; 229 | margin-left: 10px; 230 | .border-radius(6px 0 6px 6px); 231 | } 232 | } 233 | 234 | // Tweak nav headers 235 | // ----------------- 236 | // Increase padding from 15px to 20px on sides 237 | .dropdown .dropdown-menu .nav-header { 238 | padding-left: 20px; 239 | padding-right: 20px; 240 | } 241 | 242 | // Typeahead 243 | // --------- 244 | .typeahead { 245 | z-index: 1051; 246 | margin-top: 2px; // give it some space to breathe 247 | .border-radius(@baseBorderRadius); 248 | } 249 | -------------------------------------------------------------------------------- /requestbin/templates/bin.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block title %}RequestBin - {{bin.name}}{% endblock %} 3 | {% block icon %}{% endblock %} 4 | 5 | {% block sidebar %}{% endblock %} 6 | 7 | {% block binurl %} 8 | 9 | 10 | {% if bin.private %}{% endif %} 11 | {% endblock %} 12 | 13 | {% block head %} 14 | {% endblock %} 15 | 16 | {% block content %} 17 | {% for request in bin.requests %} 18 |
    19 |
    20 |
    21 |
    22 | {{base_url}}
    23 | {{request.method}} 24 | {{request.path}}{{request.query_string|to_qs}} 25 |
    26 |
    27 | {% if request.content_type %}{% endif %} {{request.content_type}}
    28 | {{request.content_length|friendly_size}} 29 |
    30 |
    31 | {{request.time|approximate_time}} ago 32 | 33 |
    34 | From {{request.remote_addr}} 35 |
    36 |
    37 |
    38 | 39 |
    40 | {{ message_detail(request) }} 41 |
    42 |
    43 | {% else %} 44 | 45 |

    Bin URL

    46 |

    47 |

    48 |

    {% if bin.private %}This is a private bin. Requests are only viewable from this computer.{% endif %} 49 | 50 |


    51 |
    52 |
    53 | 54 |

    Make a request to get started.

    55 | 56 |
    cURL
    57 |
    curl -X POST -d "fizz=buzz" {{base_url}}/{{bin.name}}
    58 | 59 |
    Python (with Requests)
    60 |
    import requests, time
     61 | r = requests.post('{{base_url}}/{{bin.name}}', data={"ts":time.time()})
     62 | print r.status_code
     63 | print r.content
    64 | 65 |
    Node.js (with request)
    66 |
    var request = require('request');
     67 | var url ='{{base_url}}/{{bin.name}}'
     68 | request(url, function (error, response, body) {
     69 |   if (!error) {
     70 |     console.log(body);
     71 |   }
     72 | });
    73 | 74 |
    Ruby
    75 |
    require 'open-uri'
     76 | result = open('{{base_url}}/{{bin.name}}')
     77 | result.lines { |f| f.each_line {|line| p line} }
    78 | 79 |
    C# / .NET
    80 |
    using System;
     81 | using System.Net.Http;
     82 | using System.Threading.Tasks;
     83 | 
     84 | namespace RequestBinExample
     85 | {
     86 |   class Program
     87 |   {
     88 |     static void Main(string[] args)
     89 |     {
     90 |       MakeRequest();
     91 |     }
     92 | 
     93 |     private static async Task MakeRequest()
     94 |     {
     95 |       var httpClient = new HttpClient();
     96 |       var response = await httpClient.GetAsync(new Uri("{{base_url}}/{{bin.name}}"));
     97 |       var body = await response.Content.ReadAsStringAsync();
     98 |       Console.WriteLine(body);
     99 |     }
    100 |   }
    101 | }
    102 | 103 |
    Java
    104 |
    import org.apache.commons.httpclient.*;
    105 | import org.apache.commons.httpclient.methods.*;
    106 | import org.apache.commons.httpclient.params.HttpMethodParams;
    107 | 
    108 | import java.io.*;
    109 | 
    110 | public class RequestBinTutorial {
    111 |   public static void main(String[] args) {
    112 |     HttpClient client = new HttpClient();
    113 |     GetMethod method = new GetMethod("{{base_url}}/{{bin.name}}");
    114 |     try {
    115 |       int statusCode = client.executeMethod(method);
    116 |       byte[] responseBody = method.getResponseBody();
    117 |       System.out.println(new String(responseBody));
    118 |     } catch (Exception e) {
    119 |       System.err.println("Fatal error: " + e.getMessage());
    120 |       e.printStackTrace();
    121 |     } finally {
    122 |       method.releaseConnection();
    123 |     }
    124 |   }
    125 | }
    126 | 127 |
    PHP
    128 |
    <?php
    129 |     $result = file_get_contents('{{base_url}}/{{bin.name}}');
    130 |     echo $result;
    131 | ?>
    132 | 133 |
    134 |
    135 | 136 | {% endfor %} 137 | 138 |
    139 | 140 |
    141 |

    Limits

    142 |

    This {% if bin.private %}private{% endif %} 143 | bin will keep the last 20 requests made to it and remain available for 48 hours after it was created. 144 | However, data might be cleared at any time, so treat bins as highly ephemeral.

    145 | 146 |

    Need more?

    147 |

    Sign up for a free Runscope account. Runscope request captures give you live updates, permanent URLs, file handling and much more.

    148 |
    149 | {% endblock %} 150 | 151 | 152 | {% macro message_detail(request) %} 153 |
    154 |
    155 |
    156 |
    FORM/POST PARAMETERS
    157 | {% for k,v in request.form_data %} 158 |

    {{k}}: {{v}}

    159 | {% else %} 160 | None 161 | {% endfor %} 162 | 163 | {% if request.query_string and not request.query_string is string %} 164 |
    QUERYSTRING
    165 | {% for k,v in request.query_string|dictsort: %} 166 | {% if not v %} 167 |

    {{k}}

    168 | {% else %} 169 |

    {{k}}: {{v}}

    170 | {% endif %} 171 | {% endfor %} 172 | {% endif %} 173 |
    174 |
    175 | {% if request.headers %} 176 |
    HEADERS
    177 | {% for header in request.headers.items() %} 178 |

    {{header.0}}: {{header.1|escape}}

    179 | {% endfor %} 180 | {% endif %} 181 |
    182 |
    183 | 184 |
    RAW BODY
    185 |
    186 |
    {{ request.get_raw() or "None" }}
    187 |
    188 |
    189 | {% endmacro %} 190 | -------------------------------------------------------------------------------- /requestbin/static/less/tables.less: -------------------------------------------------------------------------------- 1 | // 2 | // Tables 3 | // -------------------------------------------------- 4 | 5 | 6 | // BASE TABLES 7 | // ----------------- 8 | 9 | table { 10 | max-width: 100%; 11 | background-color: @tableBackground; 12 | border-collapse: collapse; 13 | border-spacing: 0; 14 | } 15 | 16 | // BASELINE STYLES 17 | // --------------- 18 | 19 | .table { 20 | width: 100%; 21 | margin-bottom: @baseLineHeight; 22 | // Cells 23 | th, 24 | td { 25 | padding: 8px; 26 | line-height: @baseLineHeight; 27 | text-align: left; 28 | vertical-align: top; 29 | border-top: 1px solid @tableBorder; 30 | } 31 | th { 32 | font-weight: bold; 33 | } 34 | // Bottom align for column headings 35 | thead th { 36 | vertical-align: bottom; 37 | } 38 | // Remove top border from thead by default 39 | caption + thead tr:first-child th, 40 | caption + thead tr:first-child td, 41 | colgroup + thead tr:first-child th, 42 | colgroup + thead tr:first-child td, 43 | thead:first-child tr:first-child th, 44 | thead:first-child tr:first-child td { 45 | border-top: 0; 46 | } 47 | // Account for multiple tbody instances 48 | tbody + tbody { 49 | border-top: 2px solid @tableBorder; 50 | } 51 | 52 | // Nesting 53 | .table { 54 | background-color: @bodyBackground; 55 | } 56 | } 57 | 58 | 59 | 60 | // CONDENSED TABLE W/ HALF PADDING 61 | // ------------------------------- 62 | 63 | .table-condensed { 64 | th, 65 | td { 66 | padding: 4px 5px; 67 | } 68 | } 69 | 70 | 71 | // BORDERED VERSION 72 | // ---------------- 73 | 74 | .table-bordered { 75 | border: 1px solid @tableBorder; 76 | border-collapse: separate; // Done so we can round those corners! 77 | *border-collapse: collapse; // IE7 can't round corners anyway 78 | border-left: 0; 79 | .border-radius(@baseBorderRadius); 80 | th, 81 | td { 82 | border-left: 1px solid @tableBorder; 83 | } 84 | // Prevent a double border 85 | caption + thead tr:first-child th, 86 | caption + tbody tr:first-child th, 87 | caption + tbody tr:first-child td, 88 | colgroup + thead tr:first-child th, 89 | colgroup + tbody tr:first-child th, 90 | colgroup + tbody tr:first-child td, 91 | thead:first-child tr:first-child th, 92 | tbody:first-child tr:first-child th, 93 | tbody:first-child tr:first-child td { 94 | border-top: 0; 95 | } 96 | // For first th/td in the first row in the first thead or tbody 97 | thead:first-child tr:first-child > th:first-child, 98 | tbody:first-child tr:first-child > td:first-child, 99 | tbody:first-child tr:first-child > th:first-child { 100 | .border-top-left-radius(@baseBorderRadius); 101 | } 102 | // For last th/td in the first row in the first thead or tbody 103 | thead:first-child tr:first-child > th:last-child, 104 | tbody:first-child tr:first-child > td:last-child, 105 | tbody:first-child tr:first-child > th:last-child { 106 | .border-top-right-radius(@baseBorderRadius); 107 | } 108 | // For first th/td (can be either) in the last row in the last thead, tbody, and tfoot 109 | thead:last-child tr:last-child > th:first-child, 110 | tbody:last-child tr:last-child > td:first-child, 111 | tbody:last-child tr:last-child > th:first-child, 112 | tfoot:last-child tr:last-child > td:first-child, 113 | tfoot:last-child tr:last-child > th:first-child { 114 | .border-bottom-left-radius(@baseBorderRadius); 115 | } 116 | // For last th/td (can be either) in the last row in the last thead, tbody, and tfoot 117 | thead:last-child tr:last-child > th:last-child, 118 | tbody:last-child tr:last-child > td:last-child, 119 | tbody:last-child tr:last-child > th:last-child, 120 | tfoot:last-child tr:last-child > td:last-child, 121 | tfoot:last-child tr:last-child > th:last-child { 122 | .border-bottom-right-radius(@baseBorderRadius); 123 | } 124 | 125 | // Clear border-radius for first and last td in the last row in the last tbody for table with tfoot 126 | tfoot + tbody:last-child tr:last-child td:first-child { 127 | .border-bottom-left-radius(0); 128 | } 129 | tfoot + tbody:last-child tr:last-child td:last-child { 130 | .border-bottom-right-radius(0); 131 | } 132 | 133 | // Special fixes to round the left border on the first td/th 134 | caption + thead tr:first-child th:first-child, 135 | caption + tbody tr:first-child td:first-child, 136 | colgroup + thead tr:first-child th:first-child, 137 | colgroup + tbody tr:first-child td:first-child { 138 | .border-top-left-radius(@baseBorderRadius); 139 | } 140 | caption + thead tr:first-child th:last-child, 141 | caption + tbody tr:first-child td:last-child, 142 | colgroup + thead tr:first-child th:last-child, 143 | colgroup + tbody tr:first-child td:last-child { 144 | .border-top-right-radius(@baseBorderRadius); 145 | } 146 | 147 | } 148 | 149 | 150 | 151 | 152 | // ZEBRA-STRIPING 153 | // -------------- 154 | 155 | // Default zebra-stripe styles (alternating gray and transparent backgrounds) 156 | .table-striped { 157 | tbody { 158 | > tr:nth-child(odd) > td, 159 | > tr:nth-child(odd) > th { 160 | background-color: @tableBackgroundAccent; 161 | } 162 | } 163 | } 164 | 165 | 166 | // HOVER EFFECT 167 | // ------------ 168 | // Placed here since it has to come after the potential zebra striping 169 | .table-hover { 170 | tbody { 171 | tr:hover > td, 172 | tr:hover > th { 173 | background-color: @tableBackgroundHover; 174 | } 175 | } 176 | } 177 | 178 | 179 | // TABLE CELL SIZING 180 | // ----------------- 181 | 182 | // Reset default grid behavior 183 | table td[class*="span"], 184 | table th[class*="span"], 185 | .row-fluid table td[class*="span"], 186 | .row-fluid table th[class*="span"] { 187 | display: table-cell; 188 | float: none; // undo default grid column styles 189 | margin-left: 0; // undo default grid column styles 190 | } 191 | 192 | // Change the column widths to account for td/th padding 193 | .table td, 194 | .table th { 195 | &.span1 { .tableColumns(1); } 196 | &.span2 { .tableColumns(2); } 197 | &.span3 { .tableColumns(3); } 198 | &.span4 { .tableColumns(4); } 199 | &.span5 { .tableColumns(5); } 200 | &.span6 { .tableColumns(6); } 201 | &.span7 { .tableColumns(7); } 202 | &.span8 { .tableColumns(8); } 203 | &.span9 { .tableColumns(9); } 204 | &.span10 { .tableColumns(10); } 205 | &.span11 { .tableColumns(11); } 206 | &.span12 { .tableColumns(12); } 207 | } 208 | 209 | 210 | 211 | // TABLE BACKGROUNDS 212 | // ----------------- 213 | // Exact selectors below required to override .table-striped 214 | 215 | .table tbody tr { 216 | &.success > td { 217 | background-color: @successBackground; 218 | } 219 | &.error > td { 220 | background-color: @errorBackground; 221 | } 222 | &.warning > td { 223 | background-color: @warningBackground; 224 | } 225 | &.info > td { 226 | background-color: @infoBackground; 227 | } 228 | } 229 | 230 | // Hover states for .table-hover 231 | .table-hover tbody tr { 232 | &.success:hover > td { 233 | background-color: darken(@successBackground, 5%); 234 | } 235 | &.error:hover > td { 236 | background-color: darken(@errorBackground, 5%); 237 | } 238 | &.warning:hover > td { 239 | background-color: darken(@warningBackground, 5%); 240 | } 241 | &.info:hover > td { 242 | background-color: darken(@infoBackground, 5%); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /requestbin/static/less/navs.less: -------------------------------------------------------------------------------- 1 | // 2 | // Navs 3 | // -------------------------------------------------- 4 | 5 | 6 | // BASE CLASS 7 | // ---------- 8 | 9 | .nav { 10 | margin-left: 0; 11 | margin-bottom: @baseLineHeight; 12 | list-style: none; 13 | } 14 | 15 | // Make links block level 16 | .nav > li > a { 17 | display: block; 18 | } 19 | .nav > li > a:hover, 20 | .nav > li > a:focus { 21 | text-decoration: none; 22 | background-color: @grayLighter; 23 | } 24 | 25 | // Prevent IE8 from misplacing imgs 26 | // See https://github.com/h5bp/html5-boilerplate/issues/984#issuecomment-3985989 27 | .nav > li > a > img { 28 | max-width: none; 29 | } 30 | 31 | // Redeclare pull classes because of specifity 32 | .nav > .pull-right { 33 | float: right; 34 | } 35 | 36 | // Nav headers (for dropdowns and lists) 37 | .nav-header { 38 | display: block; 39 | padding: 3px 15px; 40 | font-size: 11px; 41 | font-weight: bold; 42 | line-height: @baseLineHeight; 43 | color: @grayLight; 44 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 45 | text-transform: uppercase; 46 | } 47 | // Space them out when they follow another list item (link) 48 | .nav li + .nav-header { 49 | margin-top: 9px; 50 | } 51 | 52 | 53 | 54 | // NAV LIST 55 | // -------- 56 | 57 | .nav-list { 58 | padding-left: 15px; 59 | padding-right: 15px; 60 | margin-bottom: 0; 61 | } 62 | .nav-list > li > a, 63 | .nav-list .nav-header { 64 | margin-left: -15px; 65 | margin-right: -15px; 66 | text-shadow: 0 1px 0 rgba(255,255,255,.5); 67 | } 68 | .nav-list > li > a { 69 | padding: 3px 15px; 70 | } 71 | .nav-list > .active > a, 72 | .nav-list > .active > a:hover, 73 | .nav-list > .active > a:focus { 74 | color: @white; 75 | text-shadow: 0 -1px 0 rgba(0,0,0,.2); 76 | background-color: @linkColor; 77 | } 78 | .nav-list [class^="icon-"], 79 | .nav-list [class*=" icon-"] { 80 | margin-right: 2px; 81 | } 82 | // Dividers (basically an hr) within the dropdown 83 | .nav-list .divider { 84 | .nav-divider(); 85 | } 86 | 87 | 88 | 89 | // TABS AND PILLS 90 | // ------------- 91 | 92 | // Common styles 93 | .nav-tabs, 94 | .nav-pills { 95 | .clearfix(); 96 | } 97 | .nav-tabs > li, 98 | .nav-pills > li { 99 | float: left; 100 | } 101 | .nav-tabs > li > a, 102 | .nav-pills > li > a { 103 | padding-right: 12px; 104 | padding-left: 12px; 105 | margin-right: 2px; 106 | line-height: 14px; // keeps the overall height an even number 107 | } 108 | 109 | // TABS 110 | // ---- 111 | 112 | // Give the tabs something to sit on 113 | .nav-tabs { 114 | border-bottom: 1px solid #ddd; 115 | } 116 | // Make the list-items overlay the bottom border 117 | .nav-tabs > li { 118 | margin-bottom: -1px; 119 | } 120 | // Actual tabs (as links) 121 | .nav-tabs > li > a { 122 | padding-top: 8px; 123 | padding-bottom: 8px; 124 | line-height: @baseLineHeight; 125 | border: 1px solid transparent; 126 | .border-radius(4px 4px 0 0); 127 | &:hover, 128 | &:focus { 129 | border-color: @grayLighter @grayLighter #ddd; 130 | } 131 | } 132 | // Active state, and it's :hover/:focus to override normal :hover/:focus 133 | .nav-tabs > .active > a, 134 | .nav-tabs > .active > a:hover, 135 | .nav-tabs > .active > a:focus { 136 | color: @gray; 137 | background-color: @bodyBackground; 138 | border: 1px solid #ddd; 139 | border-bottom-color: transparent; 140 | cursor: default; 141 | } 142 | 143 | 144 | // PILLS 145 | // ----- 146 | 147 | // Links rendered as pills 148 | .nav-pills > li > a { 149 | padding-top: 8px; 150 | padding-bottom: 8px; 151 | margin-top: 2px; 152 | margin-bottom: 2px; 153 | .border-radius(5px); 154 | } 155 | 156 | // Active state 157 | .nav-pills > .active > a, 158 | .nav-pills > .active > a:hover, 159 | .nav-pills > .active > a:focus { 160 | color: @white; 161 | background-color: @linkColor; 162 | } 163 | 164 | 165 | 166 | // STACKED NAV 167 | // ----------- 168 | 169 | // Stacked tabs and pills 170 | .nav-stacked > li { 171 | float: none; 172 | } 173 | .nav-stacked > li > a { 174 | margin-right: 0; // no need for the gap between nav items 175 | } 176 | 177 | // Tabs 178 | .nav-tabs.nav-stacked { 179 | border-bottom: 0; 180 | } 181 | .nav-tabs.nav-stacked > li > a { 182 | border: 1px solid #ddd; 183 | .border-radius(0); 184 | } 185 | .nav-tabs.nav-stacked > li:first-child > a { 186 | .border-top-radius(4px); 187 | } 188 | .nav-tabs.nav-stacked > li:last-child > a { 189 | .border-bottom-radius(4px); 190 | } 191 | .nav-tabs.nav-stacked > li > a:hover, 192 | .nav-tabs.nav-stacked > li > a:focus { 193 | border-color: #ddd; 194 | z-index: 2; 195 | } 196 | 197 | // Pills 198 | .nav-pills.nav-stacked > li > a { 199 | margin-bottom: 3px; 200 | } 201 | .nav-pills.nav-stacked > li:last-child > a { 202 | margin-bottom: 1px; // decrease margin to match sizing of stacked tabs 203 | } 204 | 205 | 206 | 207 | // DROPDOWNS 208 | // --------- 209 | 210 | .nav-tabs .dropdown-menu { 211 | .border-radius(0 0 6px 6px); // remove the top rounded corners here since there is a hard edge above the menu 212 | } 213 | .nav-pills .dropdown-menu { 214 | .border-radius(6px); // make rounded corners match the pills 215 | } 216 | 217 | // Default dropdown links 218 | // ------------------------- 219 | // Make carets use linkColor to start 220 | .nav .dropdown-toggle .caret { 221 | border-top-color: @linkColor; 222 | border-bottom-color: @linkColor; 223 | margin-top: 6px; 224 | } 225 | .nav .dropdown-toggle:hover .caret, 226 | .nav .dropdown-toggle:focus .caret { 227 | border-top-color: @linkColorHover; 228 | border-bottom-color: @linkColorHover; 229 | } 230 | /* move down carets for tabs */ 231 | .nav-tabs .dropdown-toggle .caret { 232 | margin-top: 8px; 233 | } 234 | 235 | // Active dropdown links 236 | // ------------------------- 237 | .nav .active .dropdown-toggle .caret { 238 | border-top-color: #fff; 239 | border-bottom-color: #fff; 240 | } 241 | .nav-tabs .active .dropdown-toggle .caret { 242 | border-top-color: @gray; 243 | border-bottom-color: @gray; 244 | } 245 | 246 | // Active:hover/:focus dropdown links 247 | // ------------------------- 248 | .nav > .dropdown.active > a:hover, 249 | .nav > .dropdown.active > a:focus { 250 | cursor: pointer; 251 | } 252 | 253 | // Open dropdowns 254 | // ------------------------- 255 | .nav-tabs .open .dropdown-toggle, 256 | .nav-pills .open .dropdown-toggle, 257 | .nav > li.dropdown.open.active > a:hover, 258 | .nav > li.dropdown.open.active > a:focus { 259 | color: @white; 260 | background-color: @grayLight; 261 | border-color: @grayLight; 262 | } 263 | .nav li.dropdown.open .caret, 264 | .nav li.dropdown.open.active .caret, 265 | .nav li.dropdown.open a:hover .caret, 266 | .nav li.dropdown.open a:focus .caret { 267 | border-top-color: @white; 268 | border-bottom-color: @white; 269 | .opacity(100); 270 | } 271 | 272 | // Dropdowns in stacked tabs 273 | .tabs-stacked .open > a:hover, 274 | .tabs-stacked .open > a:focus { 275 | border-color: @grayLight; 276 | } 277 | 278 | 279 | 280 | // TABBABLE 281 | // -------- 282 | 283 | 284 | // COMMON STYLES 285 | // ------------- 286 | 287 | // Clear any floats 288 | .tabbable { 289 | .clearfix(); 290 | } 291 | .tab-content { 292 | overflow: auto; // prevent content from running below tabs 293 | } 294 | 295 | // Remove border on bottom, left, right 296 | .tabs-below > .nav-tabs, 297 | .tabs-right > .nav-tabs, 298 | .tabs-left > .nav-tabs { 299 | border-bottom: 0; 300 | } 301 | 302 | // Show/hide tabbable areas 303 | .tab-content > .tab-pane, 304 | .pill-content > .pill-pane { 305 | display: none; 306 | } 307 | .tab-content > .active, 308 | .pill-content > .active { 309 | display: block; 310 | } 311 | 312 | 313 | // BOTTOM 314 | // ------ 315 | 316 | .tabs-below > .nav-tabs { 317 | border-top: 1px solid #ddd; 318 | } 319 | .tabs-below > .nav-tabs > li { 320 | margin-top: -1px; 321 | margin-bottom: 0; 322 | } 323 | .tabs-below > .nav-tabs > li > a { 324 | .border-radius(0 0 4px 4px); 325 | &:hover, 326 | &:focus { 327 | border-bottom-color: transparent; 328 | border-top-color: #ddd; 329 | } 330 | } 331 | .tabs-below > .nav-tabs > .active > a, 332 | .tabs-below > .nav-tabs > .active > a:hover, 333 | .tabs-below > .nav-tabs > .active > a:focus { 334 | border-color: transparent #ddd #ddd #ddd; 335 | } 336 | 337 | // LEFT & RIGHT 338 | // ------------ 339 | 340 | // Common styles 341 | .tabs-left > .nav-tabs > li, 342 | .tabs-right > .nav-tabs > li { 343 | float: none; 344 | } 345 | .tabs-left > .nav-tabs > li > a, 346 | .tabs-right > .nav-tabs > li > a { 347 | min-width: 74px; 348 | margin-right: 0; 349 | margin-bottom: 3px; 350 | } 351 | 352 | // Tabs on the left 353 | .tabs-left > .nav-tabs { 354 | float: left; 355 | margin-right: 19px; 356 | border-right: 1px solid #ddd; 357 | } 358 | .tabs-left > .nav-tabs > li > a { 359 | margin-right: -1px; 360 | .border-radius(4px 0 0 4px); 361 | } 362 | .tabs-left > .nav-tabs > li > a:hover, 363 | .tabs-left > .nav-tabs > li > a:focus { 364 | border-color: @grayLighter #ddd @grayLighter @grayLighter; 365 | } 366 | .tabs-left > .nav-tabs .active > a, 367 | .tabs-left > .nav-tabs .active > a:hover, 368 | .tabs-left > .nav-tabs .active > a:focus { 369 | border-color: #ddd transparent #ddd #ddd; 370 | *border-right-color: @white; 371 | } 372 | 373 | // Tabs on the right 374 | .tabs-right > .nav-tabs { 375 | float: right; 376 | margin-left: 19px; 377 | border-left: 1px solid #ddd; 378 | } 379 | .tabs-right > .nav-tabs > li > a { 380 | margin-left: -1px; 381 | .border-radius(0 4px 4px 0); 382 | } 383 | .tabs-right > .nav-tabs > li > a:hover, 384 | .tabs-right > .nav-tabs > li > a:focus { 385 | border-color: @grayLighter @grayLighter @grayLighter #ddd; 386 | } 387 | .tabs-right > .nav-tabs .active > a, 388 | .tabs-right > .nav-tabs .active > a:hover, 389 | .tabs-right > .nav-tabs .active > a:focus { 390 | border-color: #ddd #ddd #ddd transparent; 391 | *border-left-color: @white; 392 | } 393 | 394 | 395 | 396 | // DISABLED STATES 397 | // --------------- 398 | 399 | // Gray out text 400 | .nav > .disabled > a { 401 | color: @grayLight; 402 | } 403 | // Nuke hover/focus effects 404 | .nav > .disabled > a:hover, 405 | .nav > .disabled > a:focus { 406 | text-decoration: none; 407 | background-color: transparent; 408 | cursor: default; 409 | } 410 | -------------------------------------------------------------------------------- /requestbin/static/less/variables.less: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | 6 | // Global values 7 | // -------------------------------------------------- 8 | 9 | 10 | // Grays 11 | // ------------------------- 12 | @black: #000; 13 | @grayDarker: #222; 14 | @grayDark: #333; 15 | @gray: #555; 16 | @grayLight: #999; 17 | @grayLighter: #eee; 18 | @white: #fff; 19 | 20 | 21 | // Accent colors 22 | // ------------------------- 23 | @blue: #049cdb; 24 | @blueDark: #0064cd; 25 | @green: #46a546; 26 | @red: #9d261d; 27 | @yellow: #ffc40d; 28 | @orange: #f89406; 29 | @pink: #c3325f; 30 | @purple: #7a43b6; 31 | 32 | 33 | // Scaffolding 34 | // ------------------------- 35 | @bodyBackground: @white; 36 | @textColor: @grayDark; 37 | 38 | 39 | // Links 40 | // ------------------------- 41 | @linkColor: #08c; 42 | @linkColorHover: darken(@linkColor, 15%); 43 | 44 | 45 | // Typography 46 | // ------------------------- 47 | @sansFontFamily: "Helvetica Neue", Helvetica, Arial, sans-serif; 48 | @serifFontFamily: Georgia, "Times New Roman", Times, serif; 49 | @monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace; 50 | 51 | @baseFontSize: 14px; 52 | @baseFontFamily: @sansFontFamily; 53 | @baseLineHeight: 20px; 54 | @altFontFamily: @serifFontFamily; 55 | 56 | @headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily 57 | @headingsFontWeight: bold; // instead of browser default, bold 58 | @headingsColor: inherit; // empty to use BS default, @textColor 59 | 60 | 61 | // Component sizing 62 | // ------------------------- 63 | // Based on 14px font-size and 20px line-height 64 | 65 | @fontSizeLarge: @baseFontSize * 1.25; // ~18px 66 | @fontSizeSmall: @baseFontSize * 0.85; // ~12px 67 | @fontSizeMini: @baseFontSize * 0.75; // ~11px 68 | 69 | @paddingLarge: 11px 19px; // 44px 70 | @paddingSmall: 2px 10px; // 26px 71 | @paddingMini: 0 6px; // 22px 72 | 73 | @baseBorderRadius: 4px; 74 | @borderRadiusLarge: 6px; 75 | @borderRadiusSmall: 3px; 76 | 77 | 78 | // Tables 79 | // ------------------------- 80 | @tableBackground: transparent; // overall background-color 81 | @tableBackgroundAccent: #f9f9f9; // for striping 82 | @tableBackgroundHover: #f5f5f5; // for hover 83 | @tableBorder: #ddd; // table and cell border 84 | 85 | // Buttons 86 | // ------------------------- 87 | @btnBackground: @white; 88 | @btnBackgroundHighlight: darken(@white, 10%); 89 | @btnBorder: #ccc; 90 | 91 | @btnPrimaryBackground: @linkColor; 92 | @btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); 93 | 94 | @btnInfoBackground: #5bc0de; 95 | @btnInfoBackgroundHighlight: #2f96b4; 96 | 97 | @btnSuccessBackground: #62c462; 98 | @btnSuccessBackgroundHighlight: #51a351; 99 | 100 | @btnWarningBackground: lighten(@orange, 15%); 101 | @btnWarningBackgroundHighlight: @orange; 102 | 103 | @btnDangerBackground: #ee5f5b; 104 | @btnDangerBackgroundHighlight: #bd362f; 105 | 106 | @btnInverseBackground: #444; 107 | @btnInverseBackgroundHighlight: @grayDarker; 108 | 109 | 110 | // Forms 111 | // ------------------------- 112 | @inputBackground: @white; 113 | @inputBorder: #ccc; 114 | @inputBorderRadius: @baseBorderRadius; 115 | @inputDisabledBackground: @grayLighter; 116 | @formActionsBackground: #f5f5f5; 117 | @inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border 118 | 119 | 120 | // Dropdowns 121 | // ------------------------- 122 | @dropdownBackground: @white; 123 | @dropdownBorder: rgba(0,0,0,.2); 124 | @dropdownDividerTop: #e5e5e5; 125 | @dropdownDividerBottom: @white; 126 | 127 | @dropdownLinkColor: @grayDark; 128 | @dropdownLinkColorHover: @white; 129 | @dropdownLinkColorActive: @white; 130 | 131 | @dropdownLinkBackgroundActive: @linkColor; 132 | @dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; 133 | 134 | 135 | 136 | // COMPONENT VARIABLES 137 | // -------------------------------------------------- 138 | 139 | 140 | // Z-index master list 141 | // ------------------------- 142 | // Used for a bird's eye view of components dependent on the z-axis 143 | // Try to avoid customizing these :) 144 | @zindexDropdown: 1000; 145 | @zindexPopover: 1010; 146 | @zindexTooltip: 1030; 147 | @zindexFixedNavbar: 1030; 148 | @zindexModalBackdrop: 1040; 149 | @zindexModal: 1050; 150 | 151 | 152 | // Sprite icons path 153 | // ------------------------- 154 | @iconSpritePath: "../img/glyphicons-halflings.png"; 155 | @iconWhiteSpritePath: "../img/glyphicons-halflings-white.png"; 156 | 157 | 158 | // Input placeholder text color 159 | // ------------------------- 160 | @placeholderText: @grayLight; 161 | 162 | 163 | // Hr border color 164 | // ------------------------- 165 | @hrBorder: @grayLighter; 166 | 167 | 168 | // Horizontal forms & lists 169 | // ------------------------- 170 | @horizontalComponentOffset: 180px; 171 | 172 | 173 | // Wells 174 | // ------------------------- 175 | @wellBackground: #f5f5f5; 176 | 177 | 178 | // Navbar 179 | // ------------------------- 180 | @navbarCollapseWidth: 979px; 181 | @navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; 182 | 183 | @navbarHeight: 40px; 184 | @navbarBackgroundHighlight: #ffffff; 185 | @navbarBackground: darken(@navbarBackgroundHighlight, 5%); 186 | @navbarBorder: darken(@navbarBackground, 12%); 187 | 188 | @navbarText: #777; 189 | @navbarLinkColor: #777; 190 | @navbarLinkColorHover: @grayDark; 191 | @navbarLinkColorActive: @gray; 192 | @navbarLinkBackgroundHover: transparent; 193 | @navbarLinkBackgroundActive: darken(@navbarBackground, 5%); 194 | 195 | @navbarBrandColor: @navbarLinkColor; 196 | 197 | // Inverted navbar 198 | @navbarInverseBackground: #111111; 199 | @navbarInverseBackgroundHighlight: #222222; 200 | @navbarInverseBorder: #252525; 201 | 202 | @navbarInverseText: @grayLight; 203 | @navbarInverseLinkColor: @grayLight; 204 | @navbarInverseLinkColorHover: @white; 205 | @navbarInverseLinkColorActive: @navbarInverseLinkColorHover; 206 | @navbarInverseLinkBackgroundHover: transparent; 207 | @navbarInverseLinkBackgroundActive: @navbarInverseBackground; 208 | 209 | @navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); 210 | @navbarInverseSearchBackgroundFocus: @white; 211 | @navbarInverseSearchBorder: @navbarInverseBackground; 212 | @navbarInverseSearchPlaceholderColor: #ccc; 213 | 214 | @navbarInverseBrandColor: @navbarInverseLinkColor; 215 | 216 | 217 | // Pagination 218 | // ------------------------- 219 | @paginationBackground: #fff; 220 | @paginationBorder: #ddd; 221 | @paginationActiveBackground: #f5f5f5; 222 | 223 | 224 | // Hero unit 225 | // ------------------------- 226 | @heroUnitBackground: @grayLighter; 227 | @heroUnitHeadingColor: inherit; 228 | @heroUnitLeadColor: inherit; 229 | 230 | 231 | // Form states and alerts 232 | // ------------------------- 233 | @warningText: #c09853; 234 | @warningBackground: #fcf8e3; 235 | @warningBorder: darken(spin(@warningBackground, -10), 3%); 236 | 237 | @errorText: #b94a48; 238 | @errorBackground: #f2dede; 239 | @errorBorder: darken(spin(@errorBackground, -10), 3%); 240 | 241 | @successText: #468847; 242 | @successBackground: #dff0d8; 243 | @successBorder: darken(spin(@successBackground, -10), 5%); 244 | 245 | @infoText: #3a87ad; 246 | @infoBackground: #d9edf7; 247 | @infoBorder: darken(spin(@infoBackground, -10), 7%); 248 | 249 | 250 | // Tooltips and popovers 251 | // ------------------------- 252 | @tooltipColor: #fff; 253 | @tooltipBackground: #000; 254 | @tooltipArrowWidth: 5px; 255 | @tooltipArrowColor: @tooltipBackground; 256 | 257 | @popoverBackground: #fff; 258 | @popoverArrowWidth: 10px; 259 | @popoverArrowColor: #fff; 260 | @popoverTitleBackground: darken(@popoverBackground, 3%); 261 | 262 | // Special enhancement for popovers 263 | @popoverArrowOuterWidth: @popoverArrowWidth + 1; 264 | @popoverArrowOuterColor: rgba(0,0,0,.25); 265 | 266 | 267 | 268 | // GRID 269 | // -------------------------------------------------- 270 | 271 | 272 | // Default 940px grid 273 | // ------------------------- 274 | @gridColumns: 12; 275 | @gridColumnWidth: 60px; 276 | @gridGutterWidth: 20px; 277 | @gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); 278 | 279 | // 1200px min 280 | @gridColumnWidth1200: 70px; 281 | @gridGutterWidth1200: 30px; 282 | @gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); 283 | 284 | // 768px-979px 285 | @gridColumnWidth768: 42px; 286 | @gridGutterWidth768: 20px; 287 | @gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); 288 | 289 | 290 | // Fluid grid 291 | // ------------------------- 292 | @fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); 293 | @fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth); 294 | 295 | // 1200px min 296 | @fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200); 297 | @fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200); 298 | 299 | // 768px-979px 300 | @fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768); 301 | @fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768); 302 | -------------------------------------------------------------------------------- /requestbin/static/less/custom.less: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | 6 | // Global values 7 | // -------------------------------------------------- 8 | 9 | 10 | // Runscope Colors 11 | // ------------------------- 12 | @rsNavy: #061427; 13 | @rsRoyal: #1b70e0; 14 | @rsGreen: #2ecc71; 15 | @rsRed: #e74c3c; 16 | 17 | 18 | // Grays 19 | // ------------------------- 20 | @black: #000; 21 | @grayDarker: #222; 22 | @grayDark: #333; 23 | @gray: #555; 24 | @grayLight: #999; 25 | @grayLighter: #eee; 26 | @grayLightest: #f9f9f9; 27 | @white: #fff; 28 | 29 | 30 | // Accent colors 31 | // ------------------------- 32 | @blue: #049cdb; 33 | @blueDark: #0064cd; 34 | @green: #46a546; 35 | @red: #9d261d; 36 | @yellow: #ffc40d; 37 | @orange: #f89406; 38 | @pink: #c3325f; 39 | @purple: #7a43b6; 40 | 41 | 42 | // Scaffolding 43 | // ------------------------- 44 | @bodyBackground: @white; 45 | @textColor: @grayDark; 46 | 47 | 48 | // Links 49 | // ------------------------- 50 | @linkColor: #1b70e0; 51 | @linkColorHover: darken(@linkColor, 15%); 52 | 53 | 54 | // Typography 55 | // ------------------------- 56 | @sansFontFamily: "PT Sans", Helvetica, Arial, sans-serif; 57 | @serifFontFamily: Georgia, "Times New Roman", Times, serif; 58 | @monoFontFamily: Monaco, Menlo, Consolas, "Courier New", monospace; 59 | 60 | @baseFontSize: 14px; 61 | @baseFontFamily: @sansFontFamily; 62 | @baseLineHeight: 20px; 63 | @altFontFamily: @serifFontFamily; 64 | 65 | @headingsFontFamily: inherit; // empty to use BS default, @baseFontFamily 66 | @headingsFontWeight: bold; // instead of browser default, bold 67 | @headingsColor: inherit; // empty to use BS default, @textColor 68 | 69 | 70 | // Component sizing 71 | // ------------------------- 72 | // Based on 14px font-size and 20px line-height 73 | 74 | @fontSizeExtraLarge: @baseFontSize * 1.75; 75 | @fontSizeLarge: @baseFontSize * 1.25; // ~18px 76 | @fontSizeSmall: @baseFontSize * 0.85; // ~12px 77 | @fontSizeMini: @baseFontSize * 0.75; // ~11px 78 | 79 | @paddingLarge: 11px 19px; // 44px 80 | @paddingSmall: 2px 10px; // 26px 81 | @paddingMini: 0 6px; // 22px 82 | 83 | @baseBorderRadius: 2px; 84 | @borderRadiusLarge: 2px; 85 | @borderRadiusSmall: 2px; 86 | 87 | 88 | // Tables 89 | // ------------------------- 90 | @tableBackground: transparent; // overall background-color 91 | @tableBackgroundAccent: #f9f9f9; // for striping 92 | @tableBackgroundHover: #f5f5f5; // for hover 93 | @tableBorder: #ddd; // table and cell border 94 | 95 | // Buttons 96 | // ------------------------- 97 | @btnBackground: @white; 98 | @btnBackgroundHighlight: darken(@white, 10%); 99 | @btnBorder: #ccc; 100 | 101 | @btnPrimaryBackground: @linkColor; 102 | @btnPrimaryBackgroundHighlight: spin(@btnPrimaryBackground, 20%); 103 | 104 | @btnInfoBackground: #5bc0de; 105 | @btnInfoBackgroundHighlight: #2f96b4; 106 | 107 | @btnSuccessBackground: #62c462; 108 | @btnSuccessBackgroundHighlight: #51a351; 109 | 110 | @btnWarningBackground: lighten(@orange, 15%); 111 | @btnWarningBackgroundHighlight: @orange; 112 | 113 | @btnDangerBackground: #ee5f5b; 114 | @btnDangerBackgroundHighlight: #bd362f; 115 | 116 | @btnInverseBackground: #444; 117 | @btnInverseBackgroundHighlight: @grayDarker; 118 | 119 | 120 | // Forms 121 | // ------------------------- 122 | @inputBackground: @white; 123 | @inputBorder: #ccc; 124 | @inputBorderRadius: @baseBorderRadius; 125 | @inputDisabledBackground: @grayLighter; 126 | @formActionsBackground: #f5f5f5; 127 | @inputHeight: @baseLineHeight + 10px; // base line-height + 8px vertical padding + 2px top/bottom border 128 | 129 | 130 | // Dropdowns 131 | // ------------------------- 132 | @dropdownBackground: @white; 133 | @dropdownBorder: rgba(0,0,0,.2); 134 | @dropdownDividerTop: #e5e5e5; 135 | @dropdownDividerBottom: @white; 136 | 137 | @dropdownLinkColor: @grayDark; 138 | @dropdownLinkColorHover: @white; 139 | @dropdownLinkColorActive: @white; 140 | 141 | @dropdownLinkBackgroundActive: @linkColor; 142 | @dropdownLinkBackgroundHover: @dropdownLinkBackgroundActive; 143 | 144 | 145 | 146 | // COMPONENT VARIABLES 147 | // -------------------------------------------------- 148 | 149 | 150 | // Z-index master list 151 | // ------------------------- 152 | // Used for a bird's eye view of components dependent on the z-axis 153 | // Try to avoid customizing these :) 154 | @zindexDropdown: 1000; 155 | @zindexPopover: 1010; 156 | @zindexTooltip: 1030; 157 | @zindexFixedNavbar: 1030; 158 | @zindexModalBackdrop: 1040; 159 | @zindexModal: 1050; 160 | 161 | 162 | // Sprite icons path 163 | // ------------------------- 164 | @iconSpritePath: "../img/glyphicons-halflings.png"; 165 | @iconWhiteSpritePath: "../img/glyphicons-halflings-white.png"; 166 | 167 | 168 | // Input placeholder text color 169 | // ------------------------- 170 | @placeholderText: @grayLight; 171 | 172 | 173 | // Hr border color 174 | // ------------------------- 175 | @hrBorder: @grayLighter; 176 | 177 | 178 | // Horizontal forms & lists 179 | // ------------------------- 180 | @horizontalComponentOffset: 180px; 181 | 182 | 183 | // Wells 184 | // ------------------------- 185 | @wellBackground: #f5f5f5; 186 | 187 | 188 | // Navbar 189 | // ------------------------- 190 | @navbarCollapseWidth: 979px; 191 | @navbarCollapseDesktopWidth: @navbarCollapseWidth + 1; 192 | 193 | @navbarHeight: 40px; 194 | @navbarBackgroundHighlight: #ffffff; 195 | @navbarBackground: darken(@navbarBackgroundHighlight, 5%); 196 | @navbarBorder: darken(@navbarBackground, 12%); 197 | 198 | @navbarText: #777; 199 | @navbarLinkColor: #777; 200 | @navbarLinkColorHover: @grayDark; 201 | @navbarLinkColorActive: @gray; 202 | @navbarLinkBackgroundHover: transparent; 203 | @navbarLinkBackgroundActive: darken(@navbarBackground, 5%); 204 | 205 | @navbarBrandColor: @navbarLinkColor; 206 | 207 | // Inverted navbar 208 | @navbarInverseBackground: #111111; 209 | @navbarInverseBackgroundHighlight: #222222; 210 | @navbarInverseBorder: #252525; 211 | 212 | @navbarInverseText: @grayLight; 213 | @navbarInverseLinkColor: @grayLight; 214 | @navbarInverseLinkColorHover: @white; 215 | @navbarInverseLinkColorActive: @navbarInverseLinkColorHover; 216 | @navbarInverseLinkBackgroundHover: transparent; 217 | @navbarInverseLinkBackgroundActive: @navbarInverseBackground; 218 | 219 | @navbarInverseSearchBackground: lighten(@navbarInverseBackground, 25%); 220 | @navbarInverseSearchBackgroundFocus: @white; 221 | @navbarInverseSearchBorder: @navbarInverseBackground; 222 | @navbarInverseSearchPlaceholderColor: #ccc; 223 | 224 | @navbarInverseBrandColor: @navbarInverseLinkColor; 225 | 226 | 227 | // Pagination 228 | // ------------------------- 229 | @paginationBackground: #fff; 230 | @paginationBorder: #ddd; 231 | @paginationActiveBackground: #f5f5f5; 232 | 233 | 234 | // Hero unit 235 | // ------------------------- 236 | @heroUnitBackground: @grayLighter; 237 | @heroUnitHeadingColor: inherit; 238 | @heroUnitLeadColor: inherit; 239 | 240 | 241 | // Form states and alerts 242 | // ------------------------- 243 | @warningText: #c09853; 244 | @warningBackground: #fcf8e3; 245 | @warningBorder: darken(spin(@warningBackground, -10), 3%); 246 | 247 | @errorText: #b94a48; 248 | @errorBackground: #f2dede; 249 | @errorBorder: darken(spin(@errorBackground, -10), 3%); 250 | 251 | @successText: #468847; 252 | @successBackground: #dff0d8; 253 | @successBorder: darken(spin(@successBackground, -10), 5%); 254 | 255 | @infoText: #3a87ad; 256 | @infoBackground: #d9edf7; 257 | @infoBorder: darken(spin(@infoBackground, -10), 7%); 258 | 259 | 260 | // Tooltips and popovers 261 | // ------------------------- 262 | @tooltipColor: #fff; 263 | @tooltipBackground: #000; 264 | @tooltipArrowWidth: 5px; 265 | @tooltipArrowColor: @tooltipBackground; 266 | 267 | @popoverBackground: #fff; 268 | @popoverArrowWidth: 10px; 269 | @popoverArrowColor: #fff; 270 | @popoverTitleBackground: darken(@popoverBackground, 3%); 271 | 272 | // Special enhancement for popovers 273 | @popoverArrowOuterWidth: @popoverArrowWidth + 1; 274 | @popoverArrowOuterColor: rgba(0,0,0,.25); 275 | 276 | 277 | 278 | // GRID 279 | // -------------------------------------------------- 280 | 281 | 282 | // Default 940px grid 283 | // ------------------------- 284 | @gridColumns: 12; 285 | @gridColumnWidth: 60px; 286 | @gridGutterWidth: 20px; 287 | @gridRowWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1)); 288 | 289 | // 1200px min 290 | @gridColumnWidth1200: 70px; 291 | @gridGutterWidth1200: 30px; 292 | @gridRowWidth1200: (@gridColumns * @gridColumnWidth1200) + (@gridGutterWidth1200 * (@gridColumns - 1)); 293 | 294 | // 768px-979px 295 | @gridColumnWidth768: 42px; 296 | @gridGutterWidth768: 20px; 297 | @gridRowWidth768: (@gridColumns * @gridColumnWidth768) + (@gridGutterWidth768 * (@gridColumns - 1)); 298 | 299 | 300 | // Fluid grid 301 | // ------------------------- 302 | @fluidGridColumnWidth: percentage(@gridColumnWidth/@gridRowWidth); 303 | @fluidGridGutterWidth: percentage(@gridGutterWidth/@gridRowWidth); 304 | 305 | // 1200px min 306 | @fluidGridColumnWidth1200: percentage(@gridColumnWidth1200/@gridRowWidth1200); 307 | @fluidGridGutterWidth1200: percentage(@gridGutterWidth1200/@gridRowWidth1200); 308 | 309 | // 768px-979px 310 | @fluidGridColumnWidth768: percentage(@gridColumnWidth768/@gridRowWidth768); 311 | @fluidGridGutterWidth768: percentage(@gridGutterWidth768/@gridRowWidth768); 312 | -------------------------------------------------------------------------------- /requestbin/static/less/sprites.less: -------------------------------------------------------------------------------- 1 | // 2 | // Sprites 3 | // -------------------------------------------------- 4 | 5 | 6 | // ICONS 7 | // ----- 8 | 9 | // All icons receive the styles of the tag with a base class 10 | // of .i and are then given a unique class to add width, height, 11 | // and background-position. Your resulting HTML will look like 12 | // . 13 | 14 | // For the white version of the icons, just add the .icon-white class: 15 | // 16 | 17 | [class^="icon-"], 18 | [class*=" icon-"] { 19 | display: inline-block; 20 | width: 14px; 21 | height: 14px; 22 | .ie7-restore-right-whitespace(); 23 | line-height: 14px; 24 | vertical-align: text-top; 25 | background-image: url("@{iconSpritePath}"); 26 | background-position: 14px 14px; 27 | background-repeat: no-repeat; 28 | margin-top: 1px; 29 | } 30 | 31 | /* White icons with optional class, or on hover/focus/active states of certain elements */ 32 | .icon-white, 33 | .nav-pills > .active > a > [class^="icon-"], 34 | .nav-pills > .active > a > [class*=" icon-"], 35 | .nav-list > .active > a > [class^="icon-"], 36 | .nav-list > .active > a > [class*=" icon-"], 37 | .navbar-inverse .nav > .active > a > [class^="icon-"], 38 | .navbar-inverse .nav > .active > a > [class*=" icon-"], 39 | .dropdown-menu > li > a:hover > [class^="icon-"], 40 | .dropdown-menu > li > a:focus > [class^="icon-"], 41 | .dropdown-menu > li > a:hover > [class*=" icon-"], 42 | .dropdown-menu > li > a:focus > [class*=" icon-"], 43 | .dropdown-menu > .active > a > [class^="icon-"], 44 | .dropdown-menu > .active > a > [class*=" icon-"], 45 | .dropdown-submenu:hover > a > [class^="icon-"], 46 | .dropdown-submenu:focus > a > [class^="icon-"], 47 | .dropdown-submenu:hover > a > [class*=" icon-"], 48 | .dropdown-submenu:focus > a > [class*=" icon-"] { 49 | background-image: url("@{iconWhiteSpritePath}"); 50 | } 51 | 52 | .icon-glass { background-position: 0 0; } 53 | .icon-music { background-position: -24px 0; } 54 | .icon-search { background-position: -48px 0; } 55 | .icon-envelope { background-position: -72px 0; } 56 | .icon-heart { background-position: -96px 0; } 57 | .icon-star { background-position: -120px 0; } 58 | .icon-star-empty { background-position: -144px 0; } 59 | .icon-user { background-position: -168px 0; } 60 | .icon-film { background-position: -192px 0; } 61 | .icon-th-large { background-position: -216px 0; } 62 | .icon-th { background-position: -240px 0; } 63 | .icon-th-list { background-position: -264px 0; } 64 | .icon-ok { background-position: -288px 0; } 65 | .icon-remove { background-position: -312px 0; } 66 | .icon-zoom-in { background-position: -336px 0; } 67 | .icon-zoom-out { background-position: -360px 0; } 68 | .icon-off { background-position: -384px 0; } 69 | .icon-signal { background-position: -408px 0; } 70 | .icon-cog { background-position: -432px 0; } 71 | .icon-trash { background-position: -456px 0; } 72 | 73 | .icon-home { background-position: 0 -24px; } 74 | .icon-file { background-position: -24px -24px; } 75 | .icon-time { background-position: -48px -24px; } 76 | .icon-road { background-position: -72px -24px; } 77 | .icon-download-alt { background-position: -96px -24px; } 78 | .icon-download { background-position: -120px -24px; } 79 | .icon-upload { background-position: -144px -24px; } 80 | .icon-inbox { background-position: -168px -24px; } 81 | .icon-play-circle { background-position: -192px -24px; } 82 | .icon-repeat { background-position: -216px -24px; } 83 | .icon-refresh { background-position: -240px -24px; } 84 | .icon-list-alt { background-position: -264px -24px; } 85 | .icon-lock { background-position: -287px -24px; } // 1px off 86 | .icon-flag { background-position: -312px -24px; } 87 | .icon-headphones { background-position: -336px -24px; } 88 | .icon-volume-off { background-position: -360px -24px; } 89 | .icon-volume-down { background-position: -384px -24px; } 90 | .icon-volume-up { background-position: -408px -24px; } 91 | .icon-qrcode { background-position: -432px -24px; } 92 | .icon-barcode { background-position: -456px -24px; } 93 | 94 | .icon-tag { background-position: 0 -48px; } 95 | .icon-tags { background-position: -25px -48px; } // 1px off 96 | .icon-book { background-position: -48px -48px; } 97 | .icon-bookmark { background-position: -72px -48px; } 98 | .icon-print { background-position: -96px -48px; } 99 | .icon-camera { background-position: -120px -48px; } 100 | .icon-font { background-position: -144px -48px; } 101 | .icon-bold { background-position: -167px -48px; } // 1px off 102 | .icon-italic { background-position: -192px -48px; } 103 | .icon-text-height { background-position: -216px -48px; } 104 | .icon-text-width { background-position: -240px -48px; } 105 | .icon-align-left { background-position: -264px -48px; } 106 | .icon-align-center { background-position: -288px -48px; } 107 | .icon-align-right { background-position: -312px -48px; } 108 | .icon-align-justify { background-position: -336px -48px; } 109 | .icon-list { background-position: -360px -48px; } 110 | .icon-indent-left { background-position: -384px -48px; } 111 | .icon-indent-right { background-position: -408px -48px; } 112 | .icon-facetime-video { background-position: -432px -48px; } 113 | .icon-picture { background-position: -456px -48px; } 114 | 115 | .icon-pencil { background-position: 0 -72px; } 116 | .icon-map-marker { background-position: -24px -72px; } 117 | .icon-adjust { background-position: -48px -72px; } 118 | .icon-tint { background-position: -72px -72px; } 119 | .icon-edit { background-position: -96px -72px; } 120 | .icon-share { background-position: -120px -72px; } 121 | .icon-check { background-position: -144px -72px; } 122 | .icon-move { background-position: -168px -72px; } 123 | .icon-step-backward { background-position: -192px -72px; } 124 | .icon-fast-backward { background-position: -216px -72px; } 125 | .icon-backward { background-position: -240px -72px; } 126 | .icon-play { background-position: -264px -72px; } 127 | .icon-pause { background-position: -288px -72px; } 128 | .icon-stop { background-position: -312px -72px; } 129 | .icon-forward { background-position: -336px -72px; } 130 | .icon-fast-forward { background-position: -360px -72px; } 131 | .icon-step-forward { background-position: -384px -72px; } 132 | .icon-eject { background-position: -408px -72px; } 133 | .icon-chevron-left { background-position: -432px -72px; } 134 | .icon-chevron-right { background-position: -456px -72px; } 135 | 136 | .icon-plus-sign { background-position: 0 -96px; } 137 | .icon-minus-sign { background-position: -24px -96px; } 138 | .icon-remove-sign { background-position: -48px -96px; } 139 | .icon-ok-sign { background-position: -72px -96px; } 140 | .icon-question-sign { background-position: -96px -96px; } 141 | .icon-info-sign { background-position: -120px -96px; } 142 | .icon-screenshot { background-position: -144px -96px; } 143 | .icon-remove-circle { background-position: -168px -96px; } 144 | .icon-ok-circle { background-position: -192px -96px; } 145 | .icon-ban-circle { background-position: -216px -96px; } 146 | .icon-arrow-left { background-position: -240px -96px; } 147 | .icon-arrow-right { background-position: -264px -96px; } 148 | .icon-arrow-up { background-position: -289px -96px; } // 1px off 149 | .icon-arrow-down { background-position: -312px -96px; } 150 | .icon-share-alt { background-position: -336px -96px; } 151 | .icon-resize-full { background-position: -360px -96px; } 152 | .icon-resize-small { background-position: -384px -96px; } 153 | .icon-plus { background-position: -408px -96px; } 154 | .icon-minus { background-position: -433px -96px; } 155 | .icon-asterisk { background-position: -456px -96px; } 156 | 157 | .icon-exclamation-sign { background-position: 0 -120px; } 158 | .icon-gift { background-position: -24px -120px; } 159 | .icon-leaf { background-position: -48px -120px; } 160 | .icon-fire { background-position: -72px -120px; } 161 | .icon-eye-open { background-position: -96px -120px; } 162 | .icon-eye-close { background-position: -120px -120px; } 163 | .icon-warning-sign { background-position: -144px -120px; } 164 | .icon-plane { background-position: -168px -120px; } 165 | .icon-calendar { background-position: -192px -120px; } 166 | .icon-random { background-position: -216px -120px; width: 16px; } 167 | .icon-comment { background-position: -240px -120px; } 168 | .icon-magnet { background-position: -264px -120px; } 169 | .icon-chevron-up { background-position: -288px -120px; } 170 | .icon-chevron-down { background-position: -313px -119px; } // 1px, 1px off 171 | .icon-retweet { background-position: -336px -120px; } 172 | .icon-shopping-cart { background-position: -360px -120px; } 173 | .icon-folder-close { background-position: -384px -120px; width: 16px; } 174 | .icon-folder-open { background-position: -408px -120px; width: 16px; } 175 | .icon-resize-vertical { background-position: -432px -119px; } // 1px, 1px off 176 | .icon-resize-horizontal { background-position: -456px -118px; } // 1px, 2px off 177 | 178 | .icon-hdd { background-position: 0 -144px; } 179 | .icon-bullhorn { background-position: -24px -144px; } 180 | .icon-bell { background-position: -48px -144px; } 181 | .icon-certificate { background-position: -72px -144px; } 182 | .icon-thumbs-up { background-position: -96px -144px; } 183 | .icon-thumbs-down { background-position: -120px -144px; } 184 | .icon-hand-right { background-position: -144px -144px; } 185 | .icon-hand-left { background-position: -168px -144px; } 186 | .icon-hand-up { background-position: -192px -144px; } 187 | .icon-hand-down { background-position: -216px -144px; } 188 | .icon-circle-arrow-right { background-position: -240px -144px; } 189 | .icon-circle-arrow-left { background-position: -264px -144px; } 190 | .icon-circle-arrow-up { background-position: -288px -144px; } 191 | .icon-circle-arrow-down { background-position: -312px -144px; } 192 | .icon-globe { background-position: -336px -144px; } 193 | .icon-wrench { background-position: -360px -144px; } 194 | .icon-tasks { background-position: -384px -144px; } 195 | .icon-filter { background-position: -408px -144px; } 196 | .icon-briefcase { background-position: -432px -144px; } 197 | .icon-fullscreen { background-position: -456px -144px; } 198 | -------------------------------------------------------------------------------- /requestbin/static/js/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p .vertical(@navbarBackgroundHighlight, @navbarBackground); 26 | border: 1px solid @navbarBorder; 27 | .border-radius(@baseBorderRadius); 28 | .box-shadow(0 1px 4px rgba(0,0,0,.065)); 29 | 30 | // Prevent floats from breaking the navbar 31 | .clearfix(); 32 | } 33 | 34 | // Set width to auto for default container 35 | // We then reset it for fixed navbars in the #gridSystem mixin 36 | .navbar .container { 37 | width: auto; 38 | } 39 | 40 | // Override the default collapsed state 41 | .nav-collapse.collapse { 42 | height: auto; 43 | overflow: visible; 44 | } 45 | 46 | 47 | // Brand: website or project name 48 | // ------------------------- 49 | .navbar .brand { 50 | float: left; 51 | display: block; 52 | // Vertically center the text given @navbarHeight 53 | padding: ((@navbarHeight - @baseLineHeight) / 2) 20px ((@navbarHeight - @baseLineHeight) / 2); 54 | margin-left: -20px; // negative indent to left-align the text down the page 55 | font-size: 20px; 56 | font-weight: 200; 57 | color: @navbarBrandColor; 58 | text-shadow: 0 1px 0 @navbarBackgroundHighlight; 59 | &:hover, 60 | &:focus { 61 | text-decoration: none; 62 | } 63 | } 64 | 65 | // Plain text in topbar 66 | // ------------------------- 67 | .navbar-text { 68 | margin-bottom: 0; 69 | line-height: @navbarHeight; 70 | color: @navbarText; 71 | } 72 | 73 | // Janky solution for now to account for links outside the .nav 74 | // ------------------------- 75 | .navbar-link { 76 | color: @navbarLinkColor; 77 | &:hover, 78 | &:focus { 79 | color: @navbarLinkColorHover; 80 | } 81 | } 82 | 83 | // Dividers in navbar 84 | // ------------------------- 85 | .navbar .divider-vertical { 86 | height: @navbarHeight; 87 | margin: 0 9px; 88 | border-left: 1px solid @navbarBackground; 89 | border-right: 1px solid @navbarBackgroundHighlight; 90 | } 91 | 92 | // Buttons in navbar 93 | // ------------------------- 94 | .navbar .btn, 95 | .navbar .btn-group { 96 | .navbarVerticalAlign(30px); // Vertically center in navbar 97 | } 98 | .navbar .btn-group .btn, 99 | .navbar .input-prepend .btn, 100 | .navbar .input-append .btn, 101 | .navbar .input-prepend .btn-group, 102 | .navbar .input-append .btn-group { 103 | margin-top: 0; // then undo the margin here so we don't accidentally double it 104 | } 105 | 106 | // Navbar forms 107 | // ------------------------- 108 | .navbar-form { 109 | margin-bottom: 0; // remove default bottom margin 110 | .clearfix(); 111 | input, 112 | select, 113 | .radio, 114 | .checkbox { 115 | .navbarVerticalAlign(30px); // Vertically center in navbar 116 | } 117 | input, 118 | select, 119 | .btn { 120 | display: inline-block; 121 | margin-bottom: 0; 122 | } 123 | input[type="image"], 124 | input[type="checkbox"], 125 | input[type="radio"] { 126 | margin-top: 3px; 127 | } 128 | .input-append, 129 | .input-prepend { 130 | margin-top: 5px; 131 | white-space: nowrap; // preven two items from separating within a .navbar-form that has .pull-left 132 | input { 133 | margin-top: 0; // remove the margin on top since it's on the parent 134 | } 135 | } 136 | } 137 | 138 | // Navbar search 139 | // ------------------------- 140 | .navbar-search { 141 | position: relative; 142 | float: left; 143 | .navbarVerticalAlign(30px); // Vertically center in navbar 144 | margin-bottom: 0; 145 | .search-query { 146 | margin-bottom: 0; 147 | padding: 4px 14px; 148 | #font > .sans-serif(13px, normal, 1); 149 | .border-radius(15px); // redeclare because of specificity of the type attribute 150 | } 151 | } 152 | 153 | 154 | 155 | // Static navbar 156 | // ------------------------- 157 | 158 | .navbar-static-top { 159 | position: static; 160 | margin-bottom: 0; // remove 18px margin for default navbar 161 | .navbar-inner { 162 | .border-radius(0); 163 | } 164 | } 165 | 166 | 167 | 168 | // Fixed navbar 169 | // ------------------------- 170 | 171 | // Shared (top/bottom) styles 172 | .navbar-fixed-top, 173 | .navbar-fixed-bottom { 174 | position: fixed; 175 | right: 0; 176 | left: 0; 177 | z-index: @zindexFixedNavbar; 178 | margin-bottom: 0; // remove 18px margin for default navbar 179 | } 180 | .navbar-fixed-top .navbar-inner, 181 | .navbar-static-top .navbar-inner { 182 | border-width: 0 0 1px; 183 | } 184 | .navbar-fixed-bottom .navbar-inner { 185 | border-width: 1px 0 0; 186 | } 187 | .navbar-fixed-top .navbar-inner, 188 | .navbar-fixed-bottom .navbar-inner { 189 | padding-left: 0; 190 | padding-right: 0; 191 | .border-radius(0); 192 | } 193 | 194 | // Reset container width 195 | // Required here as we reset the width earlier on and the grid mixins don't override early enough 196 | .navbar-static-top .container, 197 | .navbar-fixed-top .container, 198 | .navbar-fixed-bottom .container { 199 | #grid > .core > .span(@gridColumns); 200 | } 201 | 202 | // Fixed to top 203 | .navbar-fixed-top { 204 | top: 0; 205 | } 206 | .navbar-fixed-top, 207 | .navbar-static-top { 208 | .navbar-inner { 209 | .box-shadow(~"0 1px 10px rgba(0,0,0,.1)"); 210 | } 211 | } 212 | 213 | // Fixed to bottom 214 | .navbar-fixed-bottom { 215 | bottom: 0; 216 | .navbar-inner { 217 | .box-shadow(~"0 -1px 10px rgba(0,0,0,.1)"); 218 | } 219 | } 220 | 221 | 222 | 223 | // NAVIGATION 224 | // ---------- 225 | 226 | .navbar .nav { 227 | position: relative; 228 | left: 0; 229 | display: block; 230 | float: left; 231 | margin: 0 10px 0 0; 232 | } 233 | .navbar .nav.pull-right { 234 | float: right; // redeclare due to specificity 235 | margin-right: 0; // remove margin on float right nav 236 | } 237 | .navbar .nav > li { 238 | float: left; 239 | } 240 | 241 | // Links 242 | .navbar .nav > li > a { 243 | float: none; 244 | // Vertically center the text given @navbarHeight 245 | padding: ((@navbarHeight - @baseLineHeight) / 2) 15px ((@navbarHeight - @baseLineHeight) / 2); 246 | color: @navbarLinkColor; 247 | text-decoration: none; 248 | text-shadow: 0 1px 0 @navbarBackgroundHighlight; 249 | } 250 | .navbar .nav .dropdown-toggle .caret { 251 | margin-top: 8px; 252 | } 253 | 254 | // Hover/focus 255 | .navbar .nav > li > a:focus, 256 | .navbar .nav > li > a:hover { 257 | background-color: @navbarLinkBackgroundHover; // "transparent" is default to differentiate :hover/:focus from .active 258 | color: @navbarLinkColorHover; 259 | text-decoration: none; 260 | } 261 | 262 | // Active nav items 263 | .navbar .nav > .active > a, 264 | .navbar .nav > .active > a:hover, 265 | .navbar .nav > .active > a:focus { 266 | color: @navbarLinkColorActive; 267 | text-decoration: none; 268 | background-color: @navbarLinkBackgroundActive; 269 | .box-shadow(inset 0 3px 8px rgba(0,0,0,.125)); 270 | } 271 | 272 | // Navbar button for toggling navbar items in responsive layouts 273 | // These definitions need to come after '.navbar .btn' 274 | .navbar .btn-navbar { 275 | display: none; 276 | float: right; 277 | padding: 7px 10px; 278 | margin-left: 5px; 279 | margin-right: 5px; 280 | .buttonBackground(darken(@navbarBackgroundHighlight, 5%), darken(@navbarBackground, 5%)); 281 | .box-shadow(~"inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075)"); 282 | } 283 | .navbar .btn-navbar .icon-bar { 284 | display: block; 285 | width: 18px; 286 | height: 2px; 287 | background-color: #f5f5f5; 288 | .border-radius(1px); 289 | .box-shadow(0 1px 0 rgba(0,0,0,.25)); 290 | } 291 | .btn-navbar .icon-bar + .icon-bar { 292 | margin-top: 3px; 293 | } 294 | 295 | 296 | 297 | // Dropdown menus 298 | // -------------- 299 | 300 | // Menu position and menu carets 301 | .navbar .nav > li > .dropdown-menu { 302 | &:before { 303 | content: ''; 304 | display: inline-block; 305 | border-left: 7px solid transparent; 306 | border-right: 7px solid transparent; 307 | border-bottom: 7px solid #ccc; 308 | border-bottom-color: @dropdownBorder; 309 | position: absolute; 310 | top: -7px; 311 | left: 9px; 312 | } 313 | &:after { 314 | content: ''; 315 | display: inline-block; 316 | border-left: 6px solid transparent; 317 | border-right: 6px solid transparent; 318 | border-bottom: 6px solid @dropdownBackground; 319 | position: absolute; 320 | top: -6px; 321 | left: 10px; 322 | } 323 | } 324 | // Menu position and menu caret support for dropups via extra dropup class 325 | .navbar-fixed-bottom .nav > li > .dropdown-menu { 326 | &:before { 327 | border-top: 7px solid #ccc; 328 | border-top-color: @dropdownBorder; 329 | border-bottom: 0; 330 | bottom: -7px; 331 | top: auto; 332 | } 333 | &:after { 334 | border-top: 6px solid @dropdownBackground; 335 | border-bottom: 0; 336 | bottom: -6px; 337 | top: auto; 338 | } 339 | } 340 | 341 | // Caret should match text color on hover/focus 342 | .navbar .nav li.dropdown > a:hover .caret, 343 | .navbar .nav li.dropdown > a:focus .caret { 344 | border-top-color: @navbarLinkColorHover; 345 | border-bottom-color: @navbarLinkColorHover; 346 | } 347 | 348 | // Remove background color from open dropdown 349 | .navbar .nav li.dropdown.open > .dropdown-toggle, 350 | .navbar .nav li.dropdown.active > .dropdown-toggle, 351 | .navbar .nav li.dropdown.open.active > .dropdown-toggle { 352 | background-color: @navbarLinkBackgroundActive; 353 | color: @navbarLinkColorActive; 354 | } 355 | .navbar .nav li.dropdown > .dropdown-toggle .caret { 356 | border-top-color: @navbarLinkColor; 357 | border-bottom-color: @navbarLinkColor; 358 | } 359 | .navbar .nav li.dropdown.open > .dropdown-toggle .caret, 360 | .navbar .nav li.dropdown.active > .dropdown-toggle .caret, 361 | .navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { 362 | border-top-color: @navbarLinkColorActive; 363 | border-bottom-color: @navbarLinkColorActive; 364 | } 365 | 366 | // Right aligned menus need alt position 367 | .navbar .pull-right > li > .dropdown-menu, 368 | .navbar .nav > li > .dropdown-menu.pull-right { 369 | left: auto; 370 | right: 0; 371 | &:before { 372 | left: auto; 373 | right: 12px; 374 | } 375 | &:after { 376 | left: auto; 377 | right: 13px; 378 | } 379 | .dropdown-menu { 380 | left: auto; 381 | right: 100%; 382 | margin-left: 0; 383 | margin-right: -1px; 384 | .border-radius(6px 0 6px 6px); 385 | } 386 | } 387 | 388 | 389 | // Inverted navbar 390 | // ------------------------- 391 | 392 | .navbar-inverse { 393 | 394 | .navbar-inner { 395 | #gradient > .vertical(@navbarInverseBackgroundHighlight, @navbarInverseBackground); 396 | border-color: @navbarInverseBorder; 397 | } 398 | 399 | .brand, 400 | .nav > li > a { 401 | color: @navbarInverseLinkColor; 402 | text-shadow: 0 -1px 0 rgba(0,0,0,.25); 403 | &:hover, 404 | &:focus { 405 | color: @navbarInverseLinkColorHover; 406 | } 407 | } 408 | 409 | .brand { 410 | color: @navbarInverseBrandColor; 411 | } 412 | 413 | .navbar-text { 414 | color: @navbarInverseText; 415 | } 416 | 417 | .nav > li > a:focus, 418 | .nav > li > a:hover { 419 | background-color: @navbarInverseLinkBackgroundHover; 420 | color: @navbarInverseLinkColorHover; 421 | } 422 | 423 | .nav .active > a, 424 | .nav .active > a:hover, 425 | .nav .active > a:focus { 426 | color: @navbarInverseLinkColorActive; 427 | background-color: @navbarInverseLinkBackgroundActive; 428 | } 429 | 430 | // Inline text links 431 | .navbar-link { 432 | color: @navbarInverseLinkColor; 433 | &:hover, 434 | &:focus { 435 | color: @navbarInverseLinkColorHover; 436 | } 437 | } 438 | 439 | // Dividers in navbar 440 | .divider-vertical { 441 | border-left-color: @navbarInverseBackground; 442 | border-right-color: @navbarInverseBackgroundHighlight; 443 | } 444 | 445 | // Dropdowns 446 | .nav li.dropdown.open > .dropdown-toggle, 447 | .nav li.dropdown.active > .dropdown-toggle, 448 | .nav li.dropdown.open.active > .dropdown-toggle { 449 | background-color: @navbarInverseLinkBackgroundActive; 450 | color: @navbarInverseLinkColorActive; 451 | } 452 | .nav li.dropdown > a:hover .caret, 453 | .nav li.dropdown > a:focus .caret { 454 | border-top-color: @navbarInverseLinkColorActive; 455 | border-bottom-color: @navbarInverseLinkColorActive; 456 | } 457 | .nav li.dropdown > .dropdown-toggle .caret { 458 | border-top-color: @navbarInverseLinkColor; 459 | border-bottom-color: @navbarInverseLinkColor; 460 | } 461 | .nav li.dropdown.open > .dropdown-toggle .caret, 462 | .nav li.dropdown.active > .dropdown-toggle .caret, 463 | .nav li.dropdown.open.active > .dropdown-toggle .caret { 464 | border-top-color: @navbarInverseLinkColorActive; 465 | border-bottom-color: @navbarInverseLinkColorActive; 466 | } 467 | 468 | // Navbar search 469 | .navbar-search { 470 | .search-query { 471 | color: @white; 472 | background-color: @navbarInverseSearchBackground; 473 | border-color: @navbarInverseSearchBorder; 474 | .box-shadow(~"inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15)"); 475 | .transition(none); 476 | .placeholder(@navbarInverseSearchPlaceholderColor); 477 | 478 | // Focus states (we use .focused since IE7-8 and down doesn't support :focus) 479 | &:focus, 480 | &.focused { 481 | padding: 5px 15px; 482 | color: @grayDark; 483 | text-shadow: 0 1px 0 @white; 484 | background-color: @navbarInverseSearchBackgroundFocus; 485 | border: 0; 486 | .box-shadow(0 0 3px rgba(0,0,0,.15)); 487 | outline: 0; 488 | } 489 | } 490 | } 491 | 492 | // Navbar collapse button 493 | .btn-navbar { 494 | .buttonBackground(darken(@navbarInverseBackgroundHighlight, 5%), darken(@navbarInverseBackground, 5%)); 495 | } 496 | 497 | } 498 | --------------------------------------------------------------------------------