ts-admin 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +3 -0
- data/app.rb +21 -0
- data/app.yml.example +12 -0
- data/bin/ts-admin +26 -0
- data/config.ru +19 -0
- data/controller/init.rb +55 -0
- data/controller/main.rb +10 -0
- data/controller/remap.rb +86 -0
- data/layout/default.xhtml +47 -0
- data/lib/ts-admin/traffic_server.rb +157 -0
- data/lib/ts-admin/version.rb +3 -0
- data/lib/ts-admin.rb +5 -0
- data/public/css/font-awesome.min.css +24 -0
- data/public/css/grid.css +107 -0
- data/public/css/layout.css +254 -0
- data/public/css/reset.css +123 -0
- data/public/css/text.css +109 -0
- data/public/favicon.ico +0 -0
- data/public/font/FontAwesome.otf +0 -0
- data/public/font/fontawesome-webfont.eot +0 -0
- data/public/font/fontawesome-webfont.svg +339 -0
- data/public/font/fontawesome-webfont.ttf +0 -0
- data/public/font/fontawesome-webfont.woff +0 -0
- data/public/images/bg.png +0 -0
- data/spec/helper.rb +39 -0
- data/task/ramaze.rake +57 -0
- data/ts-admin.gemspec +25 -0
- data/view/index.xhtml +3 -0
- data/view/remap/form.xhtml +18 -0
- data/view/remap/index.xhtml +2 -0
- data/view/remap/list.xhtml +23 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a38d80d69b3c2bbae9e237d74acf92504366ce6a
|
4
|
+
data.tar.gz: e84f8bf4205e3ed0120aeeb2534f8501c53cccea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 443bd6c4b09851e653eaf1fa7d097c39c03d08b792e22b5a7b765b8ebc71b4248f6221c2a3332d6ec66e024dc035d85c78027f67b711cdc39b42a65489f4c6b0
|
7
|
+
data.tar.gz: f6700bed37709a9d606bbcfd7be7720969f07ebbf0a93f4ac641f3f1a690b73632160fd56c2f3fe5f8124ee7e8821d520c043de0b5b42b2150eefaae580f75c9
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
ts-admin (0.2.0)
|
5
|
+
ramaze (>= 2.0.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
innate (2013.02.21)
|
11
|
+
rack (~> 1.5.2)
|
12
|
+
rack (1.5.2)
|
13
|
+
rake (10.0.4)
|
14
|
+
ramaze (2012.12.08)
|
15
|
+
innate (>= 2012.12)
|
16
|
+
rake
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
ruby
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
bundler (~> 1.3)
|
23
|
+
rake
|
24
|
+
ts-admin!
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 SIC! Software GmbH
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Apache Traffic Server Frontend
|
2
|
+
|
3
|
+
This is a simple web frontend for the remap.config configuration file for the Apache Traffic Server.
|
4
|
+
It is used to manage reverse proxy mappings and 301 redirects. Please refer to [this blog post](http://blog.sic-software.com/2012/03/02/eine-administrationsoberflache-fur-den-apache-traffic-server/) for more information.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
$ gem install ts-admin
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
Create a configuration file:
|
13
|
+
|
14
|
+
```yaml
|
15
|
+
port: 7000
|
16
|
+
|
17
|
+
auth:
|
18
|
+
username: admin
|
19
|
+
password: d033e22ae348aeb5660fc2140aec35850c4da997 # SHA1 hash
|
20
|
+
|
21
|
+
traffic_server:
|
22
|
+
config_path: /etc/trafficserver
|
23
|
+
restart_cmd: /etc/init.d/trafficserver restart
|
24
|
+
|
25
|
+
info:
|
26
|
+
external_ip: 192.168.0.1
|
27
|
+
```
|
28
|
+
|
29
|
+
Start the server:
|
30
|
+
|
31
|
+
$ ts-admin --config /path/to/your/config.yml
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/app.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This file contains your application, it requires dependencies and necessary
|
2
|
+
# parts of the application.
|
3
|
+
require 'rubygems'
|
4
|
+
require 'yaml'
|
5
|
+
require 'ramaze'
|
6
|
+
|
7
|
+
# Load app configuration
|
8
|
+
config_path = __DIR__('app.yml')
|
9
|
+
config_path = OPTIONS[:config] if defined?(OPTIONS)
|
10
|
+
APP_CONFIG = {
|
11
|
+
'auth' => {
|
12
|
+
'username' => 'admin',
|
13
|
+
'password' => '-'
|
14
|
+
}
|
15
|
+
}.merge(YAML.load_file(config_path))
|
16
|
+
|
17
|
+
# Make sure that Ramaze knows where you are
|
18
|
+
Ramaze.options.roots = [__DIR__]
|
19
|
+
|
20
|
+
require __DIR__('lib/ts-admin/traffic_server')
|
21
|
+
require __DIR__('controller/init')
|
data/app.yml.example
ADDED
data/bin/ts-admin
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Parse options
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
OPTIONS = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: tsadmin [options]"
|
9
|
+
|
10
|
+
opts.on("-c", "--config [path]", "Port") do |config|
|
11
|
+
OPTIONS[:config] = config
|
12
|
+
end
|
13
|
+
opts.on("-p", "--port [port]", "Port") do |port|
|
14
|
+
OPTIONS[:port] = port.to_i
|
15
|
+
end
|
16
|
+
end.parse!
|
17
|
+
|
18
|
+
# Start TSAdmin
|
19
|
+
require File.expand_path('../../app', __FILE__)
|
20
|
+
|
21
|
+
Ramaze.start(
|
22
|
+
:adapter => :webrick,
|
23
|
+
:port => OPTIONS[:port] || APP_CONFIG['port'] || 7000,
|
24
|
+
:file => __FILE__,
|
25
|
+
:root => Ramaze.options.roots
|
26
|
+
)
|
data/config.ru
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env rackup
|
2
|
+
#
|
3
|
+
# config.ru for ramaze apps
|
4
|
+
#
|
5
|
+
# Rackup is a useful tool for running Rack applications, which uses the
|
6
|
+
# Rack::Builder DSL to configure middleware and build up applications easily.
|
7
|
+
#
|
8
|
+
# Rackup automatically figures out the environment it is run in, and runs your
|
9
|
+
# application as FastCGI, CGI, or standalone with Mongrel or WEBrick -- all from
|
10
|
+
# the same configuration.
|
11
|
+
#
|
12
|
+
# Do not set the adapter.handler in here, it will be ignored.
|
13
|
+
# You can choose the adapter like `ramaze start -s mongrel` or set it in the
|
14
|
+
# 'start.rb' and use `ruby start.rb` instead.
|
15
|
+
require ::File.expand_path('../app', __FILE__)
|
16
|
+
|
17
|
+
Ramaze.start(:root => Ramaze.options.roots, :started => true)
|
18
|
+
|
19
|
+
run Ramaze
|
data/controller/init.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# Define a subclass of Ramaze::Controller holding your defaults for all controllers. Note
|
2
|
+
# that these changes can be overwritten in sub controllers by simply calling the method
|
3
|
+
# but with a different value.
|
4
|
+
|
5
|
+
class Controller < Ramaze::Controller
|
6
|
+
layout :default
|
7
|
+
helper :auth
|
8
|
+
helper :xhtml
|
9
|
+
helper :link
|
10
|
+
helper :flash
|
11
|
+
engine :etanni
|
12
|
+
|
13
|
+
def login
|
14
|
+
if logged_in?
|
15
|
+
call(r('/'))
|
16
|
+
else
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def auth_template
|
24
|
+
<<-TEMPLATE.strip!
|
25
|
+
<div class="grid_12 content login"><header><h2>Login</h2></header><div class="list-form">#{super}</div></div>
|
26
|
+
TEMPLATE
|
27
|
+
end
|
28
|
+
|
29
|
+
def auth_login(username, password)
|
30
|
+
return unless username and password
|
31
|
+
return if username.empty? or password.empty?
|
32
|
+
|
33
|
+
return unless APP_CONFIG['auth']['username'].downcase == username.downcase
|
34
|
+
return unless APP_CONFIG['auth']['password'] == Digest::SHA1.hexdigest(password)
|
35
|
+
|
36
|
+
session[:logged_in] = true
|
37
|
+
session[:username] = APP_CONFIG['auth']['username']
|
38
|
+
end
|
39
|
+
|
40
|
+
def login_required
|
41
|
+
super
|
42
|
+
@username = session[:username]
|
43
|
+
end
|
44
|
+
|
45
|
+
def traffic_server
|
46
|
+
@_traffic_server ||= ::TSAdmin::TrafficServer.new(APP_CONFIG['traffic_server'])
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
# Here you can require all your other controllers. Note that if you have multiple
|
52
|
+
# controllers you might want to do something like the following:
|
53
|
+
Dir.glob("#{__DIR__}/*.rb").each do |controller|
|
54
|
+
require(controller)
|
55
|
+
end
|
data/controller/main.rb
ADDED
data/controller/remap.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
class RemapController < Controller
|
2
|
+
|
3
|
+
def index
|
4
|
+
return unless login_required
|
5
|
+
set_env
|
6
|
+
|
7
|
+
@traffic_server = traffic_server
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
return unless login_required
|
12
|
+
set_env
|
13
|
+
|
14
|
+
if request.post?
|
15
|
+
@from = request[:from]
|
16
|
+
@to = request[:to]
|
17
|
+
if traffic_server.add_remap(@type, @from, @to)
|
18
|
+
traffic_server.save
|
19
|
+
traffic_server.restart
|
20
|
+
flash[:info] = "Remap entry added"
|
21
|
+
call(r('/'))
|
22
|
+
else
|
23
|
+
flash[:error] = "Invalid Remap entry"
|
24
|
+
render_view :form
|
25
|
+
end
|
26
|
+
else
|
27
|
+
render_view :form
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def edit
|
32
|
+
return unless login_required
|
33
|
+
set_env
|
34
|
+
|
35
|
+
@id = request[:id]
|
36
|
+
|
37
|
+
if request.post?
|
38
|
+
@from = request[:from]
|
39
|
+
@to = request[:to]
|
40
|
+
if traffic_server.edit_remap(@id, @from, @to)
|
41
|
+
traffic_server.save
|
42
|
+
traffic_server.restart
|
43
|
+
flash[:info] = "Remap entry updated"
|
44
|
+
call(r('/'))
|
45
|
+
else
|
46
|
+
flash[:error] = "Invalid Remap entry"
|
47
|
+
render_view :form
|
48
|
+
end
|
49
|
+
else
|
50
|
+
@entry = traffic_server.find_remap_by_id(@id)
|
51
|
+
@from = @entry[:from]
|
52
|
+
@to = @entry[:to]
|
53
|
+
@type = @entry[:type]
|
54
|
+
render_view :form
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete
|
59
|
+
return unless login_required
|
60
|
+
set_env
|
61
|
+
|
62
|
+
traffic_server.delete_remap(request[:id])
|
63
|
+
traffic_server.save
|
64
|
+
traffic_server.restart
|
65
|
+
|
66
|
+
flash[:info] = "Remap entry removed"
|
67
|
+
|
68
|
+
call(r('/'))
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def remap_url_highlight_scheme(url)
|
74
|
+
scheme, hostpath = url.downcase.split(/:\/\//, 2)
|
75
|
+
<<-LINK.strip!
|
76
|
+
<span class="#{scheme}">#{scheme}</span>://#{hostpath}
|
77
|
+
LINK
|
78
|
+
end
|
79
|
+
|
80
|
+
def set_env
|
81
|
+
@title = 'Remap'
|
82
|
+
@nav = :remap
|
83
|
+
@type = request[:type]
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8" />
|
5
|
+
<title>TSAdmin#{" :: #{@title}" if defined?(@title)}</title>
|
6
|
+
#{css('reset')}
|
7
|
+
#{css('grid')}
|
8
|
+
#{css('layout')}
|
9
|
+
#{css('text')}
|
10
|
+
#{css('font-awesome.min')}
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<div class="container">
|
14
|
+
<div id="container" class="row">
|
15
|
+
<div id="top" class="grid_12">
|
16
|
+
<header class="grid_6">
|
17
|
+
<h1><a href="/">TSAdmin</a></h1>
|
18
|
+
</header>
|
19
|
+
|
20
|
+
<?r if @username ?>
|
21
|
+
<nav class="grid_6 last">
|
22
|
+
<ul class="clearfix">
|
23
|
+
<li>
|
24
|
+
<a href="/remap" class="#{'current' if @nav == :remap}">Remap</a>
|
25
|
+
</li>
|
26
|
+
<li>
|
27
|
+
<a href="/logout">Logout</a>
|
28
|
+
</li>
|
29
|
+
</ul>
|
30
|
+
</nav>
|
31
|
+
<?r end ?>
|
32
|
+
</div>
|
33
|
+
|
34
|
+
#{flashbox}
|
35
|
+
|
36
|
+
#{@content}
|
37
|
+
</div>
|
38
|
+
|
39
|
+
<footer id="footer">
|
40
|
+
<p>
|
41
|
+
© 2012-2013 SIC! Software GmbH<br />
|
42
|
+
TSAdmin is free software and is licensed under the MIT license.
|
43
|
+
</p>
|
44
|
+
</footer>
|
45
|
+
</div>
|
46
|
+
</body>
|
47
|
+
</html>
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module TSAdmin
|
5
|
+
class TrafficServer
|
6
|
+
MARKER_TEXT = "CONFIGURATION FROM TSADMIN"
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@options = {
|
10
|
+
'config_path' => '/etc/trafficserver',
|
11
|
+
'restart_cmd' => '/etc/init.d/trafficserver restart'
|
12
|
+
}.merge(options)
|
13
|
+
@config_path = @options['config_path']
|
14
|
+
end
|
15
|
+
|
16
|
+
def redirects
|
17
|
+
load unless defined?(@redirects)
|
18
|
+
@redirects.dup.freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def maps
|
22
|
+
load unless defined?(@maps)
|
23
|
+
@maps.dup.freeze
|
24
|
+
end
|
25
|
+
|
26
|
+
def find_remap_by_id(id)
|
27
|
+
(maps + redirects).select{|m| m[:id] == id}.first
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_remap(type, from, to, options={})
|
31
|
+
load
|
32
|
+
|
33
|
+
return unless list = case type.to_sym
|
34
|
+
when :map
|
35
|
+
@maps
|
36
|
+
when :redirect
|
37
|
+
@redirects
|
38
|
+
else
|
39
|
+
nil
|
40
|
+
end
|
41
|
+
|
42
|
+
id = Digest::SHA1.hexdigest("#{from}_#{to}")
|
43
|
+
|
44
|
+
return false if find_remap_by_id(id)
|
45
|
+
return false unless validate_url(from) && validate_url(to)
|
46
|
+
|
47
|
+
list << {:id => id, :type => type.to_sym, :from => from, :to => to, :options => options}
|
48
|
+
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def edit_remap(id, from, to, options=nil)
|
53
|
+
return false unless validate_url(from) && validate_url(to)
|
54
|
+
return false unless entry = find_remap_by_id(id)
|
55
|
+
entry[:from] = from
|
56
|
+
entry[:to] = to
|
57
|
+
entry[:options] = options unless options.nil?
|
58
|
+
entry[:id] = Digest::SHA1.hexdigest("#{from}_#{to}")
|
59
|
+
end
|
60
|
+
|
61
|
+
def delete_remap(id)
|
62
|
+
load
|
63
|
+
|
64
|
+
@maps.delete_if{|m| m[:id] == id}
|
65
|
+
@redirects.delete_if{|m| m[:id] == id}
|
66
|
+
|
67
|
+
true
|
68
|
+
end
|
69
|
+
|
70
|
+
def save
|
71
|
+
own_config = ''
|
72
|
+
own_config << "#{marker_begin}\n"
|
73
|
+
redirects.each do |redirect|
|
74
|
+
own_config << "redirect #{redirect[:from]} #{redirect[:to]} #{redirect[:options] if redirect[:options]}\n"
|
75
|
+
end
|
76
|
+
maps.each do |map|
|
77
|
+
own_config << "map #{map[:from]} #{map[:to]} #{map[:options] if map[:options]}\n"
|
78
|
+
end
|
79
|
+
own_config << "#{marker_end}\n"
|
80
|
+
|
81
|
+
file_content = ''
|
82
|
+
in_config_block = false
|
83
|
+
own_config_written = false
|
84
|
+
File.read(remap_path).each_line do |line|
|
85
|
+
if line.strip == marker_begin
|
86
|
+
in_config_block = true
|
87
|
+
next
|
88
|
+
elsif line.strip == marker_end
|
89
|
+
in_config_block = false
|
90
|
+
next
|
91
|
+
end
|
92
|
+
|
93
|
+
if in_config_block
|
94
|
+
file_content << own_config unless own_config_written
|
95
|
+
own_config_written = true
|
96
|
+
else
|
97
|
+
file_content << line
|
98
|
+
end
|
99
|
+
end
|
100
|
+
file_content << own_config unless own_config_written
|
101
|
+
|
102
|
+
remap_file = File.new(remap_path, 'w')
|
103
|
+
remap_file.write(file_content)
|
104
|
+
remap_file.close
|
105
|
+
end
|
106
|
+
|
107
|
+
def restart
|
108
|
+
`#{@options['restart_cmd']}`
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def marker_begin
|
114
|
+
"# BEGIN #{MARKER_TEXT}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def marker_end
|
118
|
+
"# END #{MARKER_TEXT}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def remap_path
|
122
|
+
File.join(@config_path, 'remap.config')
|
123
|
+
end
|
124
|
+
|
125
|
+
def load
|
126
|
+
@redirects = []
|
127
|
+
@maps = []
|
128
|
+
|
129
|
+
in_config_block = false
|
130
|
+
File.read(remap_path).each_line do |line|
|
131
|
+
if line.strip == marker_begin
|
132
|
+
in_config_block = true
|
133
|
+
next
|
134
|
+
elsif line.strip == marker_end
|
135
|
+
in_config_block = false
|
136
|
+
next
|
137
|
+
end
|
138
|
+
|
139
|
+
next unless in_config_block
|
140
|
+
|
141
|
+
type, from, to, *options = line.split(/\s+/)
|
142
|
+
id = Digest::SHA1.hexdigest("#{from}_#{to}")
|
143
|
+
case type.to_sym
|
144
|
+
when :redirect
|
145
|
+
@redirects << {:id => id, :type => type.to_sym, :from => from, :to => to, :options => {}}
|
146
|
+
when :map
|
147
|
+
@maps << {:id => id, :type => type.to_sym, :from => from, :to => to, :options => {}}
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def validate_url(url)
|
153
|
+
!!(url =~ URI::regexp) rescue false
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
data/lib/ts-admin.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/*!
|
2
|
+
* Font Awesome 3.1.0
|
3
|
+
* the iconic font designed for Bootstrap
|
4
|
+
* -------------------------------------------------------
|
5
|
+
* The full suite of pictographic icons, examples, and documentation
|
6
|
+
* can be found at: http://fontawesome.io
|
7
|
+
*
|
8
|
+
* License
|
9
|
+
* -------------------------------------------------------
|
10
|
+
* - The Font Awesome font is licensed under the SIL Open Font License v1.1 -
|
11
|
+
* http://scripts.sil.org/OFL
|
12
|
+
* - Font Awesome CSS, LESS, and SASS files are licensed under the MIT License -
|
13
|
+
* http://opensource.org/licenses/mit-license.html
|
14
|
+
* - Font Awesome documentation licensed under CC BY 3.0 License -
|
15
|
+
* http://creativecommons.org/licenses/by/3.0/
|
16
|
+
* - Attribution is no longer required in Font Awesome 3.0, but much appreciated:
|
17
|
+
* "Font Awesome by Dave Gandy - http://fontawesome.io"
|
18
|
+
|
19
|
+
* Contact
|
20
|
+
* -------------------------------------------------------
|
21
|
+
* Email: dave@fontawesome.io
|
22
|
+
* Twitter: http://twitter.com/fortaweso_me
|
23
|
+
* Work: Lead Product Designer @ http://kyruus.com
|
24
|
+
*/@font-face{font-family:'FontAwesome';src:url('../font/fontawesome-webfont.eot?v=3.1.0');src:url('../font/fontawesome-webfont.eot?#iefix&v=3.1.0') format('embedded-opentype'),url('../font/fontawesome-webfont.woff?v=3.1.0') format('woff'),url('../font/fontawesome-webfont.ttf?v=3.1.0') format('truetype'),url('../font/fontawesome-webfont.svg#fontawesomeregular?v=3.1.0') format('svg');font-weight:normal;font-style:normal}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em}[class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none}.icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em}a [class^="icon-"],a [class*=" icon-"],a [class^="icon-"]:before,a [class*=" icon-"]:before{display:inline}[class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.2857142857142858em;text-align:center}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.5714285714285714em}ul.icons-ul{list-style-type:none;text-indent:-0.7142857142857143em;margin-left:2.142857142857143em}ul.icons-ul>li .icon-li{width:.7142857142857143em;display:inline-block;text-align:center}[class^="icon-"].hide,[class*=" icon-"].hide{display:none}.icon-muted{color:#eee}.icon-light{color:#fff}.icon-dark{color:#333}.icon-border{border:solid 1px #eee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.icon-2x{font-size:2em}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.icon-3x{font-size:3em}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.icon-4x{font-size:4em}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.icon-5x{font-size:5em}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px}.pull-right{float:right}.pull-left{float:left}[class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em}[class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em}[class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0 0;background-repeat:repeat;margin-top:0}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none}.btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block}.nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em}.btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em}.btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em}.btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em}.btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em}.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em}.icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em}.icon-stack .icon-stack-base{font-size:2em;*line-height:1em}.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg)}100%{-ms-transform:rotate(359deg)}}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1)}.icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2)}.icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3)}.icon-flip-horizontal:before{-webkit-transform:scale(-1,1);-moz-transform:scale(-1,1);-ms-transform:scale(-1,1);-o-transform:scale(-1,1);transform:scale(-1,1)}.icon-flip-vertical:before{-webkit-transform:scale(1,-1);-moz-transform:scale(1,-1);-ms-transform:scale(1,-1);-o-transform:scale(1,-1);transform:scale(1,-1)}.icon-glass:before{content:"\f000"}.icon-music:before{content:"\f001"}.icon-search:before{content:"\f002"}.icon-envelope:before{content:"\f003"}.icon-heart:before{content:"\f004"}.icon-star:before{content:"\f005"}.icon-star-empty:before{content:"\f006"}.icon-user:before{content:"\f007"}.icon-film:before{content:"\f008"}.icon-th-large:before{content:"\f009"}.icon-th:before{content:"\f00a"}.icon-th-list:before{content:"\f00b"}.icon-ok:before{content:"\f00c"}.icon-remove:before{content:"\f00d"}.icon-zoom-in:before{content:"\f00e"}.icon-zoom-out:before{content:"\f010"}.icon-off:before{content:"\f011"}.icon-signal:before{content:"\f012"}.icon-cog:before{content:"\f013"}.icon-trash:before{content:"\f014"}.icon-home:before{content:"\f015"}.icon-file:before{content:"\f016"}.icon-time:before{content:"\f017"}.icon-road:before{content:"\f018"}.icon-download-alt:before{content:"\f019"}.icon-download:before{content:"\f01a"}.icon-upload:before{content:"\f01b"}.icon-inbox:before{content:"\f01c"}.icon-play-circle:before{content:"\f01d"}.icon-repeat:before,.icon-rotate-right:before{content:"\f01e"}.icon-refresh:before{content:"\f021"}.icon-list-alt:before{content:"\f022"}.icon-lock:before{content:"\f023"}.icon-flag:before{content:"\f024"}.icon-headphones:before{content:"\f025"}.icon-volume-off:before{content:"\f026"}.icon-volume-down:before{content:"\f027"}.icon-volume-up:before{content:"\f028"}.icon-qrcode:before{content:"\f029"}.icon-barcode:before{content:"\f02a"}.icon-tag:before{content:"\f02b"}.icon-tags:before{content:"\f02c"}.icon-book:before{content:"\f02d"}.icon-bookmark:before{content:"\f02e"}.icon-print:before{content:"\f02f"}.icon-camera:before{content:"\f030"}.icon-font:before{content:"\f031"}.icon-bold:before{content:"\f032"}.icon-italic:before{content:"\f033"}.icon-text-height:before{content:"\f034"}.icon-text-width:before{content:"\f035"}.icon-align-left:before{content:"\f036"}.icon-align-center:before{content:"\f037"}.icon-align-right:before{content:"\f038"}.icon-align-justify:before{content:"\f039"}.icon-list:before{content:"\f03a"}.icon-indent-left:before{content:"\f03b"}.icon-indent-right:before{content:"\f03c"}.icon-facetime-video:before{content:"\f03d"}.icon-picture:before{content:"\f03e"}.icon-pencil:before{content:"\f040"}.icon-map-marker:before{content:"\f041"}.icon-adjust:before{content:"\f042"}.icon-tint:before{content:"\f043"}.icon-edit:before{content:"\f044"}.icon-share:before{content:"\f045"}.icon-check:before{content:"\f046"}.icon-move:before{content:"\f047"}.icon-step-backward:before{content:"\f048"}.icon-fast-backward:before{content:"\f049"}.icon-backward:before{content:"\f04a"}.icon-play:before{content:"\f04b"}.icon-pause:before{content:"\f04c"}.icon-stop:before{content:"\f04d"}.icon-forward:before{content:"\f04e"}.icon-fast-forward:before{content:"\f050"}.icon-step-forward:before{content:"\f051"}.icon-eject:before{content:"\f052"}.icon-chevron-left:before{content:"\f053"}.icon-chevron-right:before{content:"\f054"}.icon-plus-sign:before{content:"\f055"}.icon-minus-sign:before{content:"\f056"}.icon-remove-sign:before{content:"\f057"}.icon-ok-sign:before{content:"\f058"}.icon-question-sign:before{content:"\f059"}.icon-info-sign:before{content:"\f05a"}.icon-screenshot:before{content:"\f05b"}.icon-remove-circle:before{content:"\f05c"}.icon-ok-circle:before{content:"\f05d"}.icon-ban-circle:before{content:"\f05e"}.icon-arrow-left:before{content:"\f060"}.icon-arrow-right:before{content:"\f061"}.icon-arrow-up:before{content:"\f062"}.icon-arrow-down:before{content:"\f063"}.icon-share-alt:before,.icon-mail-forward:before{content:"\f064"}.icon-resize-full:before{content:"\f065"}.icon-resize-small:before{content:"\f066"}.icon-plus:before{content:"\f067"}.icon-minus:before{content:"\f068"}.icon-asterisk:before{content:"\f069"}.icon-exclamation-sign:before{content:"\f06a"}.icon-gift:before{content:"\f06b"}.icon-leaf:before{content:"\f06c"}.icon-fire:before{content:"\f06d"}.icon-eye-open:before{content:"\f06e"}.icon-eye-close:before{content:"\f070"}.icon-warning-sign:before{content:"\f071"}.icon-plane:before{content:"\f072"}.icon-calendar:before{content:"\f073"}.icon-random:before{content:"\f074"}.icon-comment:before{content:"\f075"}.icon-magnet:before{content:"\f076"}.icon-chevron-up:before{content:"\f077"}.icon-chevron-down:before{content:"\f078"}.icon-retweet:before{content:"\f079"}.icon-shopping-cart:before{content:"\f07a"}.icon-folder-close:before{content:"\f07b"}.icon-folder-open:before{content:"\f07c"}.icon-resize-vertical:before{content:"\f07d"}.icon-resize-horizontal:before{content:"\f07e"}.icon-bar-chart:before{content:"\f080"}.icon-twitter-sign:before{content:"\f081"}.icon-facebook-sign:before{content:"\f082"}.icon-camera-retro:before{content:"\f083"}.icon-key:before{content:"\f084"}.icon-cogs:before{content:"\f085"}.icon-comments:before{content:"\f086"}.icon-thumbs-up:before{content:"\f087"}.icon-thumbs-down:before{content:"\f088"}.icon-star-half:before{content:"\f089"}.icon-heart-empty:before{content:"\f08a"}.icon-signout:before{content:"\f08b"}.icon-linkedin-sign:before{content:"\f08c"}.icon-pushpin:before{content:"\f08d"}.icon-external-link:before{content:"\f08e"}.icon-signin:before{content:"\f090"}.icon-trophy:before{content:"\f091"}.icon-github-sign:before{content:"\f092"}.icon-upload-alt:before{content:"\f093"}.icon-lemon:before{content:"\f094"}.icon-phone:before{content:"\f095"}.icon-check-empty:before{content:"\f096"}.icon-bookmark-empty:before{content:"\f097"}.icon-phone-sign:before{content:"\f098"}.icon-twitter:before{content:"\f099"}.icon-facebook:before{content:"\f09a"}.icon-github:before{content:"\f09b"}.icon-unlock:before{content:"\f09c"}.icon-credit-card:before{content:"\f09d"}.icon-rss:before{content:"\f09e"}.icon-hdd:before{content:"\f0a0"}.icon-bullhorn:before{content:"\f0a1"}.icon-bell:before{content:"\f0a2"}.icon-certificate:before{content:"\f0a3"}.icon-hand-right:before{content:"\f0a4"}.icon-hand-left:before{content:"\f0a5"}.icon-hand-up:before{content:"\f0a6"}.icon-hand-down:before{content:"\f0a7"}.icon-circle-arrow-left:before{content:"\f0a8"}.icon-circle-arrow-right:before{content:"\f0a9"}.icon-circle-arrow-up:before{content:"\f0aa"}.icon-circle-arrow-down:before{content:"\f0ab"}.icon-globe:before{content:"\f0ac"}.icon-wrench:before{content:"\f0ad"}.icon-tasks:before{content:"\f0ae"}.icon-filter:before{content:"\f0b0"}.icon-briefcase:before{content:"\f0b1"}.icon-fullscreen:before{content:"\f0b2"}.icon-group:before{content:"\f0c0"}.icon-link:before{content:"\f0c1"}.icon-cloud:before{content:"\f0c2"}.icon-beaker:before{content:"\f0c3"}.icon-cut:before{content:"\f0c4"}.icon-copy:before{content:"\f0c5"}.icon-paper-clip:before{content:"\f0c6"}.icon-save:before{content:"\f0c7"}.icon-sign-blank:before{content:"\f0c8"}.icon-reorder:before{content:"\f0c9"}.icon-list-ul:before{content:"\f0ca"}.icon-list-ol:before{content:"\f0cb"}.icon-strikethrough:before{content:"\f0cc"}.icon-underline:before{content:"\f0cd"}.icon-table:before{content:"\f0ce"}.icon-magic:before{content:"\f0d0"}.icon-truck:before{content:"\f0d1"}.icon-pinterest:before{content:"\f0d2"}.icon-pinterest-sign:before{content:"\f0d3"}.icon-google-plus-sign:before{content:"\f0d4"}.icon-google-plus:before{content:"\f0d5"}.icon-money:before{content:"\f0d6"}.icon-caret-down:before{content:"\f0d7"}.icon-caret-up:before{content:"\f0d8"}.icon-caret-left:before{content:"\f0d9"}.icon-caret-right:before{content:"\f0da"}.icon-columns:before{content:"\f0db"}.icon-sort:before{content:"\f0dc"}.icon-sort-down:before{content:"\f0dd"}.icon-sort-up:before{content:"\f0de"}.icon-envelope-alt:before{content:"\f0e0"}.icon-linkedin:before{content:"\f0e1"}.icon-undo:before,.icon-rotate-left:before{content:"\f0e2"}.icon-legal:before{content:"\f0e3"}.icon-dashboard:before{content:"\f0e4"}.icon-comment-alt:before{content:"\f0e5"}.icon-comments-alt:before{content:"\f0e6"}.icon-bolt:before{content:"\f0e7"}.icon-sitemap:before{content:"\f0e8"}.icon-umbrella:before{content:"\f0e9"}.icon-paste:before{content:"\f0ea"}.icon-lightbulb:before{content:"\f0eb"}.icon-exchange:before{content:"\f0ec"}.icon-cloud-download:before{content:"\f0ed"}.icon-cloud-upload:before{content:"\f0ee"}.icon-user-md:before{content:"\f0f0"}.icon-stethoscope:before{content:"\f0f1"}.icon-suitcase:before{content:"\f0f2"}.icon-bell-alt:before{content:"\f0f3"}.icon-coffee:before{content:"\f0f4"}.icon-food:before{content:"\f0f5"}.icon-file-alt:before{content:"\f0f6"}.icon-building:before{content:"\f0f7"}.icon-hospital:before{content:"\f0f8"}.icon-ambulance:before{content:"\f0f9"}.icon-medkit:before{content:"\f0fa"}.icon-fighter-jet:before{content:"\f0fb"}.icon-beer:before{content:"\f0fc"}.icon-h-sign:before{content:"\f0fd"}.icon-plus-sign-alt:before{content:"\f0fe"}.icon-double-angle-left:before{content:"\f100"}.icon-double-angle-right:before{content:"\f101"}.icon-double-angle-up:before{content:"\f102"}.icon-double-angle-down:before{content:"\f103"}.icon-angle-left:before{content:"\f104"}.icon-angle-right:before{content:"\f105"}.icon-angle-up:before{content:"\f106"}.icon-angle-down:before{content:"\f107"}.icon-desktop:before{content:"\f108"}.icon-laptop:before{content:"\f109"}.icon-tablet:before{content:"\f10a"}.icon-mobile-phone:before{content:"\f10b"}.icon-circle-blank:before{content:"\f10c"}.icon-quote-left:before{content:"\f10d"}.icon-quote-right:before{content:"\f10e"}.icon-spinner:before{content:"\f110"}.icon-circle:before{content:"\f111"}.icon-reply:before,.icon-mail-reply:before{content:"\f112"}.icon-folder-close-alt:before{content:"\f114"}.icon-folder-open-alt:before{content:"\f115"}.icon-expand-alt:before{content:"\f116"}.icon-collapse-alt:before{content:"\f117"}.icon-smile:before{content:"\f118"}.icon-frown:before{content:"\f119"}.icon-meh:before{content:"\f11a"}.icon-gamepad:before{content:"\f11b"}.icon-keyboard:before{content:"\f11c"}.icon-flag-alt:before{content:"\f11d"}.icon-flag-checkered:before{content:"\f11e"}.icon-terminal:before{content:"\f120"}.icon-code:before{content:"\f121"}.icon-reply-all:before{content:"\f122"}.icon-mail-reply-all:before{content:"\f122"}.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123"}.icon-location-arrow:before{content:"\f124"}.icon-crop:before{content:"\f125"}.icon-code-fork:before{content:"\f126"}.icon-unlink:before{content:"\f127"}.icon-question:before{content:"\f128"}.icon-info:before{content:"\f129"}.icon-exclamation:before{content:"\f12a"}.icon-superscript:before{content:"\f12b"}.icon-subscript:before{content:"\f12c"}.icon-eraser:before{content:"\f12d"}.icon-puzzle-piece:before{content:"\f12e"}.icon-microphone:before{content:"\f130"}.icon-microphone-off:before{content:"\f131"}.icon-shield:before{content:"\f132"}.icon-calendar-empty:before{content:"\f133"}.icon-fire-extinguisher:before{content:"\f134"}.icon-rocket:before{content:"\f135"}.icon-maxcdn:before{content:"\f136"}.icon-chevron-sign-left:before{content:"\f137"}.icon-chevron-sign-right:before{content:"\f138"}.icon-chevron-sign-up:before{content:"\f139"}.icon-chevron-sign-down:before{content:"\f13a"}.icon-html5:before{content:"\f13b"}.icon-css3:before{content:"\f13c"}.icon-anchor:before{content:"\f13d"}.icon-unlock-alt:before{content:"\f13e"}.icon-bullseye:before{content:"\f140"}.icon-ellipsis-horizontal:before{content:"\f141"}.icon-ellipsis-vertical:before{content:"\f142"}.icon-rss-sign:before{content:"\f143"}.icon-play-sign:before{content:"\f144"}.icon-ticket:before{content:"\f145"}.icon-minus-sign-alt:before{content:"\f146"}.icon-check-minus:before{content:"\f147"}.icon-level-up:before{content:"\f148"}.icon-level-down:before{content:"\f149"}.icon-check-sign:before{content:"\f14a"}.icon-edit-sign:before{content:"\f14b"}.icon-external-link-sign:before{content:"\f14c"}.icon-share-sign:before{content:"\f14d"}
|