etsy-deployinator 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +368 -0
- data/Rakefile +16 -0
- data/bin/deployinator-tailer.rb +78 -0
- data/deployinator.gemspec +31 -0
- data/lib/deployinator.rb +114 -0
- data/lib/deployinator/app.rb +204 -0
- data/lib/deployinator/base.rb +58 -0
- data/lib/deployinator/config.rb +7 -0
- data/lib/deployinator/controller.rb +147 -0
- data/lib/deployinator/helpers.rb +610 -0
- data/lib/deployinator/helpers/deploy.rb +68 -0
- data/lib/deployinator/helpers/dsh.rb +42 -0
- data/lib/deployinator/helpers/git.rb +348 -0
- data/lib/deployinator/helpers/plugin.rb +50 -0
- data/lib/deployinator/helpers/stack-tail.rb +32 -0
- data/lib/deployinator/helpers/version.rb +62 -0
- data/lib/deployinator/helpers/view.rb +67 -0
- data/lib/deployinator/logging.rb +16 -0
- data/lib/deployinator/plugin.rb +7 -0
- data/lib/deployinator/stack-tail.rb +34 -0
- data/lib/deployinator/static/css/diff_style.css +283 -0
- data/lib/deployinator/static/css/highlight.css +235 -0
- data/lib/deployinator/static/css/style.css +1223 -0
- data/lib/deployinator/static/js/flot/jquery.flot.min.js +1 -0
- data/lib/deployinator/static/js/flot/jquery.flot.selection.js +299 -0
- data/lib/deployinator/static/js/jquery-1.8.3.min.js +2 -0
- data/lib/deployinator/static/js/jquery-ui-1.8.24.min.js +5 -0
- data/lib/deployinator/static/js/jquery.timed_bar.js +36 -0
- data/lib/deployinator/tasks/initialize.rake +84 -0
- data/lib/deployinator/tasks/tests.rake +22 -0
- data/lib/deployinator/templates/deploys_status.mustache +42 -0
- data/lib/deployinator/templates/generic_single_push.mustache +64 -0
- data/lib/deployinator/templates/index.mustache +12 -0
- data/lib/deployinator/templates/layout.mustache +604 -0
- data/lib/deployinator/templates/log.mustache +24 -0
- data/lib/deployinator/templates/log_table.mustache +90 -0
- data/lib/deployinator/templates/messageboxes.mustache +29 -0
- data/lib/deployinator/templates/run_logs.mustache +15 -0
- data/lib/deployinator/templates/scroll_control.mustache +8 -0
- data/lib/deployinator/templates/stream.mustache +13 -0
- data/lib/deployinator/version.rb +3 -0
- data/lib/deployinator/views/deploys_status.rb +22 -0
- data/lib/deployinator/views/index.rb +14 -0
- data/lib/deployinator/views/layout.rb +48 -0
- data/lib/deployinator/views/log.rb +12 -0
- data/lib/deployinator/views/log_table.rb +35 -0
- data/lib/deployinator/views/run_logs.rb +32 -0
- data/templates/app.rb.erb +7 -0
- data/templates/config.ru.erb +10 -0
- data/templates/helper.rb.erb +15 -0
- data/templates/stack.rb.erb +17 -0
- data/templates/template.mustache +1 -0
- data/templates/view.rb.erb +7 -0
- data/test/unit/helpers_dsh_test.rb +40 -0
- data/test/unit/helpers_test.rb +77 -0
- data/test/unit/version_test.rb +104 -0
- metadata +245 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module Deployinator
|
2
|
+
module Helpers
|
3
|
+
module PluginHelpers
|
4
|
+
attr_accessor :plugins
|
5
|
+
@plugins = []
|
6
|
+
|
7
|
+
def register_plugins(stack)
|
8
|
+
@plugins = []
|
9
|
+
global_plugins = Deployinator.global_plugins
|
10
|
+
unless global_plugins.nil? then
|
11
|
+
Deployinator.global_plugins.each do |klass|
|
12
|
+
@plugins << Deployinator.const_get("#{klass}").new
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
unless Deployinator.stack_plugins.nil? || Deployinator.stack_plugins[stack].nil? then
|
17
|
+
Deployinator.stack_plugins[stack].each do |klass|
|
18
|
+
@plugins << Deployinator.const_get("#{klass}").new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def notify_plugins(event, state)
|
24
|
+
ret = nil
|
25
|
+
unless plugins.nil? then
|
26
|
+
@plugins.each do |plugin|
|
27
|
+
begin
|
28
|
+
new_ret = plugin.run(event, state)
|
29
|
+
if ret.nil? then
|
30
|
+
ret = new_ret
|
31
|
+
end
|
32
|
+
rescue => e
|
33
|
+
raise "Error running plugin #{plugin} with exception #{e.to_s}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
ret
|
38
|
+
end
|
39
|
+
|
40
|
+
def raise_event(event, extra_state = {})
|
41
|
+
state = extra_state
|
42
|
+
state[:username] = @username
|
43
|
+
state[:stack] = @stack
|
44
|
+
state[:stage] = @method
|
45
|
+
state[:timestamp] = Time.now.to_i
|
46
|
+
notify_plugins(event, state)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Deployinator
|
2
|
+
module Helpers
|
3
|
+
# Public: helper methods to stack tailer
|
4
|
+
module StackTailHelpers
|
5
|
+
# This is used to make sure the front end javascript loaded matches the
|
6
|
+
# same backend code for the deployinator tailer. Increment this only if
|
7
|
+
# you make protocol changes for the tailer
|
8
|
+
#
|
9
|
+
# Version format: Stack Tailer 1.X - meme name
|
10
|
+
# History: 1.0 - All Your Base
|
11
|
+
# Introduced versions
|
12
|
+
STACK_TAIL_VERSION = "Stack Tailer 1.0 - All Your Base"
|
13
|
+
|
14
|
+
# So deployinator can get at this
|
15
|
+
def stack_tail_version
|
16
|
+
STACK_TAIL_VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
# This is so the tailer can access this method without having to send()
|
20
|
+
# the method into scope. If there is a better way to do this please let
|
21
|
+
# me know
|
22
|
+
def self.get_stack_tail_version
|
23
|
+
STACK_TAIL_VERSION
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the websocket port for the stack tailer
|
27
|
+
def stack_tail_websocket_port
|
28
|
+
Deployinator.stack_tailer_port
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Deployinator
|
2
|
+
module Helpers
|
3
|
+
module VersionHelpers
|
4
|
+
# Public: wrapper function to get the short SHA of a revision. The function
|
5
|
+
# checks retrieves the part of the string before the first dash. If the part
|
6
|
+
# is a valid default git short rev, i.e. alphanumeric and length 7 it is
|
7
|
+
# returned. For an invalid rev, nil is returned.
|
8
|
+
#
|
9
|
+
# ver - String representing the revision
|
10
|
+
#
|
11
|
+
# Returns the short SHA consisting of the alphanumerics until the first dash
|
12
|
+
# or nil for an invalid version string
|
13
|
+
def get_build(ver)
|
14
|
+
# return the short sha of the rev
|
15
|
+
the_sha = (ver || "")[/^([^-]+)/]
|
16
|
+
# check that we have a default git SHA
|
17
|
+
val = /^[a-zA-Z0-9]{7,}$/.match the_sha
|
18
|
+
val.nil? ? nil : the_sha
|
19
|
+
end
|
20
|
+
module_function :get_build
|
21
|
+
|
22
|
+
# Public: function to get the current software version running on a host
|
23
|
+
#
|
24
|
+
# host - String of the hostname to check
|
25
|
+
#
|
26
|
+
# Returns the full version of the current software running on the host
|
27
|
+
def get_version(host)
|
28
|
+
host_url = "http://#{host}/"
|
29
|
+
get_version_by_url("#{host_url}version.txt")
|
30
|
+
end
|
31
|
+
module_function :get_version
|
32
|
+
|
33
|
+
# Public: function to fetch a version string from a URL. The version string
|
34
|
+
# is validated to have a valid format. The function calls a lower level
|
35
|
+
# implementation method for actually getting the version.
|
36
|
+
#
|
37
|
+
# url - String representing where to get the version from
|
38
|
+
#
|
39
|
+
# Returns the version string or nil if the format is invalid
|
40
|
+
def get_version_by_url(url)
|
41
|
+
version = curl_get_url(url)
|
42
|
+
val = /^[a-zA-Z0-9]{7,}-[0-9]{8}-[0-9]{6}-UTC$/.match version
|
43
|
+
val.nil? ? nil : version.chomp
|
44
|
+
end
|
45
|
+
module_function :get_version_by_url
|
46
|
+
|
47
|
+
# Public: this helper function wraps the actual call to get the contents of a
|
48
|
+
# version file. This helps with reducing code duplication and also stubbing
|
49
|
+
# out the actual call for unit testing.
|
50
|
+
#
|
51
|
+
# url - String representing the complete URL to query
|
52
|
+
#
|
53
|
+
# Returns the contents of the URL resource
|
54
|
+
def curl_get_url(url)
|
55
|
+
with_timeout 2, "getting version via curl from #{url}" do
|
56
|
+
`curl -s #{url}`
|
57
|
+
end
|
58
|
+
end
|
59
|
+
module_function :curl_get_url
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Deployinator
|
2
|
+
module Helpers
|
3
|
+
module ViewHelpers
|
4
|
+
|
5
|
+
def username
|
6
|
+
@username
|
7
|
+
end
|
8
|
+
|
9
|
+
def allowed_to_push_to_prod?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def groups
|
14
|
+
@groups.join(", ")
|
15
|
+
end
|
16
|
+
|
17
|
+
def my_url
|
18
|
+
"http://#{@host}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: assimilate with plugin
|
22
|
+
def logout_url
|
23
|
+
raise_event(:logout_url)
|
24
|
+
end
|
25
|
+
|
26
|
+
def my_entries
|
27
|
+
log_entries(:stack => stack)
|
28
|
+
end
|
29
|
+
|
30
|
+
def log_lines
|
31
|
+
log_to_hash(:stack => stack)
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_to_hash(opts={})
|
35
|
+
times = {}
|
36
|
+
last_time = 0
|
37
|
+
l = log_entries(opts).map do |ll|
|
38
|
+
fields = ll.split("|")
|
39
|
+
times[fields[1]] ||= []
|
40
|
+
times[fields[1]] << fields[0]
|
41
|
+
|
42
|
+
env = fields[1]
|
43
|
+
|
44
|
+
utc_time = Time.parse(fields[0] + "UTC")
|
45
|
+
{
|
46
|
+
:timestamp => fields[0],
|
47
|
+
:time => utc_time,
|
48
|
+
:time_secs => utc_time.to_i,
|
49
|
+
:env => env,
|
50
|
+
:who => fields[2],
|
51
|
+
:msg => hyperlink(fields[3]),
|
52
|
+
:old => fields[3] && fields[3][/old[\s:]*(\w+)/, 1],
|
53
|
+
:new => fields[3] && fields[3][/new[\s:]*(\w+)/, 1],
|
54
|
+
:stack => fields[4],
|
55
|
+
:run_log_url => (fields.length < 6) ? false : fields[5],
|
56
|
+
:diff_url => true,
|
57
|
+
:from_timestamp => utc_time.to_i - 1800, # + half hour before
|
58
|
+
:until_timestamp => utc_time.to_i + 1800, # + half hour after
|
59
|
+
:diff_method => 'diff'
|
60
|
+
}
|
61
|
+
end
|
62
|
+
times.each { |e,t| t.shift }
|
63
|
+
l
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Deployinator
|
2
|
+
def self.setup_logging
|
3
|
+
if Deployinator.log_file?
|
4
|
+
$deployinator_log_handle = File.new(Deployinator.log_file, "a")
|
5
|
+
def $stdout.write(string)
|
6
|
+
$deployinator_log_handle.write string
|
7
|
+
super
|
8
|
+
end
|
9
|
+
$stdout.sync = true
|
10
|
+
$stderr.reopen($deployinator_log_handle)
|
11
|
+
puts "Logging #{Deployinator.log_file}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Deployinator.setup_logging
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "em-websocket"
|
2
|
+
require "eventmachine-tail"
|
3
|
+
|
4
|
+
module Tailer
|
5
|
+
# Extends FileTail to push data tailed to an EM::Channel. All open websockets
|
6
|
+
# subscribe to a channel for the request stack and this pushes the data to
|
7
|
+
# all of them at once.
|
8
|
+
class StackTail < EventMachine::FileTail
|
9
|
+
def initialize(filename, channel, startpos=-1)
|
10
|
+
super(filename, startpos)
|
11
|
+
@channel = channel
|
12
|
+
@buffer = BufferedTokenizer.new
|
13
|
+
end
|
14
|
+
|
15
|
+
# This method is called whenever FileTail receives and inotify event for
|
16
|
+
# the tailed file. It breaks up the data per line and pushes a line at a
|
17
|
+
# time. This is to prevent the last javascript line from being broken up
|
18
|
+
# over 2 pushes thus breaking the eval on the front end.
|
19
|
+
def receive_data(data)
|
20
|
+
@buffer.extract(data).each do |line|
|
21
|
+
@channel.push line
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Checks if stack log symlink exists and creates Tailer for it
|
27
|
+
def self.stack_tail(stack, channel, channel_count)
|
28
|
+
if Deployinator.get_stacks.include?(stack)
|
29
|
+
filename = "#{Deployinator::Helpers::RUN_LOG_PATH}current-#{stack}"
|
30
|
+
start_pos = (channel_count == 0) ? 0 : -1
|
31
|
+
File.exists?(filename) ? StackTail.new(filename, channel, start_pos) : false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,283 @@
|
|
1
|
+
|
2
|
+
.ef0,.f0 { color: #000000; } .eb0,.b0 { background-color: #000000; }
|
3
|
+
.ef1,.f1 { color: #AA0000; } .eb1,.b1 { background-color: #AA0000; }
|
4
|
+
.ef2,.f2 { color: #00AA00; } .eb2,.b2 { background-color: #00AA00; }
|
5
|
+
.ef3,.f3 { color: #AA5500; } .eb3,.b3 { background-color: #AA5500; }
|
6
|
+
.ef4,.f4 { color: #0000AA; } .eb4,.b4 { background-color: #0000AA; }
|
7
|
+
.ef5,.f5 { color: #AA00AA; } .eb5,.b5 { background-color: #AA00AA; }
|
8
|
+
.ef6,.f6 { color: #00AAAA; } .eb6,.b6 { background-color: #00AAAA; }
|
9
|
+
.ef7,.f7 { color: #AAAAAA; } .eb7,.b7 { background-color: #AAAAAA; }
|
10
|
+
.ef8, .f0 > .bold,.bold > .f0 { color: #555555; font-weight: normal; }
|
11
|
+
.ef9, .f1 > .bold,.bold > .f1 { color: #FF5555; font-weight: normal; }
|
12
|
+
.ef10,.f2 > .bold,.bold > .f2 { color: #55FF55; font-weight: normal; }
|
13
|
+
.ef11,.f3 > .bold,.bold > .f3 { color: #FFFF55; font-weight: normal; }
|
14
|
+
.ef12,.f4 > .bold,.bold > .f4 { color: #5555FF; font-weight: normal; }
|
15
|
+
.ef13,.f5 > .bold,.bold > .f5 { color: #FF55FF; font-weight: normal; }
|
16
|
+
.ef14,.f6 > .bold,.bold > .f6 { color: #55FFFF; font-weight: normal; }
|
17
|
+
.ef15,.f7 > .bold,.bold > .f7 { color: #FFFFFF; font-weight: normal; }
|
18
|
+
.eb8 { background-color: #555555; }
|
19
|
+
.eb9 { background-color: #FF5555; }
|
20
|
+
.eb10 { background-color: #55FF55; }
|
21
|
+
.eb11 { background-color: #FFFF55; }
|
22
|
+
.eb12 { background-color: #5555FF; }
|
23
|
+
.eb13 { background-color: #FF55FF; }
|
24
|
+
.eb14 { background-color: #55FFFF; }
|
25
|
+
.eb15 { background-color: #FFFFFF; }
|
26
|
+
.ef16 { color: #000000; } .eb16 { background-color: #000000; }
|
27
|
+
.ef17 { color: #00005f; } .eb17 { background-color: #00005f; }
|
28
|
+
.ef18 { color: #000087; } .eb18 { background-color: #000087; }
|
29
|
+
.ef19 { color: #0000af; } .eb19 { background-color: #0000af; }
|
30
|
+
.ef20 { color: #0000d7; } .eb20 { background-color: #0000d7; }
|
31
|
+
.ef21 { color: #0000ff; } .eb21 { background-color: #0000ff; }
|
32
|
+
.ef22 { color: #005f00; } .eb22 { background-color: #005f00; }
|
33
|
+
.ef23 { color: #005f5f; } .eb23 { background-color: #005f5f; }
|
34
|
+
.ef24 { color: #005f87; } .eb24 { background-color: #005f87; }
|
35
|
+
.ef25 { color: #005faf; } .eb25 { background-color: #005faf; }
|
36
|
+
.ef26 { color: #005fd7; } .eb26 { background-color: #005fd7; }
|
37
|
+
.ef27 { color: #005fff; } .eb27 { background-color: #005fff; }
|
38
|
+
.ef28 { color: #008700; } .eb28 { background-color: #008700; }
|
39
|
+
.ef29 { color: #00875f; } .eb29 { background-color: #00875f; }
|
40
|
+
.ef30 { color: #008787; } .eb30 { background-color: #008787; }
|
41
|
+
.ef31 { color: #0087af; } .eb31 { background-color: #0087af; }
|
42
|
+
.ef32 { color: #0087d7; } .eb32 { background-color: #0087d7; }
|
43
|
+
.ef33 { color: #0087ff; } .eb33 { background-color: #0087ff; }
|
44
|
+
.ef34 { color: #00af00; } .eb34 { background-color: #00af00; }
|
45
|
+
.ef35 { color: #00af5f; } .eb35 { background-color: #00af5f; }
|
46
|
+
.ef36 { color: #00af87; } .eb36 { background-color: #00af87; }
|
47
|
+
.ef37 { color: #00afaf; } .eb37 { background-color: #00afaf; }
|
48
|
+
.ef38 { color: #00afd7; } .eb38 { background-color: #00afd7; }
|
49
|
+
.ef39 { color: #00afff; } .eb39 { background-color: #00afff; }
|
50
|
+
.ef40 { color: #00d700; } .eb40 { background-color: #00d700; }
|
51
|
+
.ef41 { color: #00d75f; } .eb41 { background-color: #00d75f; }
|
52
|
+
.ef42 { color: #00d787; } .eb42 { background-color: #00d787; }
|
53
|
+
.ef43 { color: #00d7af; } .eb43 { background-color: #00d7af; }
|
54
|
+
.ef44 { color: #00d7d7; } .eb44 { background-color: #00d7d7; }
|
55
|
+
.ef45 { color: #00d7ff; } .eb45 { background-color: #00d7ff; }
|
56
|
+
.ef46 { color: #00ff00; } .eb46 { background-color: #00ff00; }
|
57
|
+
.ef47 { color: #00ff5f; } .eb47 { background-color: #00ff5f; }
|
58
|
+
.ef48 { color: #00ff87; } .eb48 { background-color: #00ff87; }
|
59
|
+
.ef49 { color: #00ffaf; } .eb49 { background-color: #00ffaf; }
|
60
|
+
.ef50 { color: #00ffd7; } .eb50 { background-color: #00ffd7; }
|
61
|
+
.ef51 { color: #00ffff; } .eb51 { background-color: #00ffff; }
|
62
|
+
.ef52 { color: #5f0000; } .eb52 { background-color: #5f0000; }
|
63
|
+
.ef53 { color: #5f005f; } .eb53 { background-color: #5f005f; }
|
64
|
+
.ef54 { color: #5f0087; } .eb54 { background-color: #5f0087; }
|
65
|
+
.ef55 { color: #5f00af; } .eb55 { background-color: #5f00af; }
|
66
|
+
.ef56 { color: #5f00d7; } .eb56 { background-color: #5f00d7; }
|
67
|
+
.ef57 { color: #5f00ff; } .eb57 { background-color: #5f00ff; }
|
68
|
+
.ef58 { color: #5f5f00; } .eb58 { background-color: #5f5f00; }
|
69
|
+
.ef59 { color: #5f5f5f; } .eb59 { background-color: #5f5f5f; }
|
70
|
+
.ef60 { color: #5f5f87; } .eb60 { background-color: #5f5f87; }
|
71
|
+
.ef61 { color: #5f5faf; } .eb61 { background-color: #5f5faf; }
|
72
|
+
.ef62 { color: #5f5fd7; } .eb62 { background-color: #5f5fd7; }
|
73
|
+
.ef63 { color: #5f5fff; } .eb63 { background-color: #5f5fff; }
|
74
|
+
.ef64 { color: #5f8700; } .eb64 { background-color: #5f8700; }
|
75
|
+
.ef65 { color: #5f875f; } .eb65 { background-color: #5f875f; }
|
76
|
+
.ef66 { color: #5f8787; } .eb66 { background-color: #5f8787; }
|
77
|
+
.ef67 { color: #5f87af; } .eb67 { background-color: #5f87af; }
|
78
|
+
.ef68 { color: #5f87d7; } .eb68 { background-color: #5f87d7; }
|
79
|
+
.ef69 { color: #5f87ff; } .eb69 { background-color: #5f87ff; }
|
80
|
+
.ef70 { color: #5faf00; } .eb70 { background-color: #5faf00; }
|
81
|
+
.ef71 { color: #5faf5f; } .eb71 { background-color: #5faf5f; }
|
82
|
+
.ef72 { color: #5faf87; } .eb72 { background-color: #5faf87; }
|
83
|
+
.ef73 { color: #5fafaf; } .eb73 { background-color: #5fafaf; }
|
84
|
+
.ef74 { color: #5fafd7; } .eb74 { background-color: #5fafd7; }
|
85
|
+
.ef75 { color: #5fafff; } .eb75 { background-color: #5fafff; }
|
86
|
+
.ef76 { color: #5fd700; } .eb76 { background-color: #5fd700; }
|
87
|
+
.ef77 { color: #5fd75f; } .eb77 { background-color: #5fd75f; }
|
88
|
+
.ef78 { color: #5fd787; } .eb78 { background-color: #5fd787; }
|
89
|
+
.ef79 { color: #5fd7af; } .eb79 { background-color: #5fd7af; }
|
90
|
+
.ef80 { color: #5fd7d7; } .eb80 { background-color: #5fd7d7; }
|
91
|
+
.ef81 { color: #5fd7ff; } .eb81 { background-color: #5fd7ff; }
|
92
|
+
.ef82 { color: #5fff00; } .eb82 { background-color: #5fff00; }
|
93
|
+
.ef83 { color: #5fff5f; } .eb83 { background-color: #5fff5f; }
|
94
|
+
.ef84 { color: #5fff87; } .eb84 { background-color: #5fff87; }
|
95
|
+
.ef85 { color: #5fffaf; } .eb85 { background-color: #5fffaf; }
|
96
|
+
.ef86 { color: #5fffd7; } .eb86 { background-color: #5fffd7; }
|
97
|
+
.ef87 { color: #5fffff; } .eb87 { background-color: #5fffff; }
|
98
|
+
.ef88 { color: #870000; } .eb88 { background-color: #870000; }
|
99
|
+
.ef89 { color: #87005f; } .eb89 { background-color: #87005f; }
|
100
|
+
.ef90 { color: #870087; } .eb90 { background-color: #870087; }
|
101
|
+
.ef91 { color: #8700af; } .eb91 { background-color: #8700af; }
|
102
|
+
.ef92 { color: #8700d7; } .eb92 { background-color: #8700d7; }
|
103
|
+
.ef93 { color: #8700ff; } .eb93 { background-color: #8700ff; }
|
104
|
+
.ef94 { color: #875f00; } .eb94 { background-color: #875f00; }
|
105
|
+
.ef95 { color: #875f5f; } .eb95 { background-color: #875f5f; }
|
106
|
+
.ef96 { color: #875f87; } .eb96 { background-color: #875f87; }
|
107
|
+
.ef97 { color: #875faf; } .eb97 { background-color: #875faf; }
|
108
|
+
.ef98 { color: #875fd7; } .eb98 { background-color: #875fd7; }
|
109
|
+
.ef99 { color: #875fff; } .eb99 { background-color: #875fff; }
|
110
|
+
.ef100 { color: #878700; } .eb100 { background-color: #878700; }
|
111
|
+
.ef101 { color: #87875f; } .eb101 { background-color: #87875f; }
|
112
|
+
.ef102 { color: #878787; } .eb102 { background-color: #878787; }
|
113
|
+
.ef103 { color: #8787af; } .eb103 { background-color: #8787af; }
|
114
|
+
.ef104 { color: #8787d7; } .eb104 { background-color: #8787d7; }
|
115
|
+
.ef105 { color: #8787ff; } .eb105 { background-color: #8787ff; }
|
116
|
+
.ef106 { color: #87af00; } .eb106 { background-color: #87af00; }
|
117
|
+
.ef107 { color: #87af5f; } .eb107 { background-color: #87af5f; }
|
118
|
+
.ef108 { color: #87af87; } .eb108 { background-color: #87af87; }
|
119
|
+
.ef109 { color: #87afaf; } .eb109 { background-color: #87afaf; }
|
120
|
+
.ef110 { color: #87afd7; } .eb110 { background-color: #87afd7; }
|
121
|
+
.ef111 { color: #87afff; } .eb111 { background-color: #87afff; }
|
122
|
+
.ef112 { color: #87d700; } .eb112 { background-color: #87d700; }
|
123
|
+
.ef113 { color: #87d75f; } .eb113 { background-color: #87d75f; }
|
124
|
+
.ef114 { color: #87d787; } .eb114 { background-color: #87d787; }
|
125
|
+
.ef115 { color: #87d7af; } .eb115 { background-color: #87d7af; }
|
126
|
+
.ef116 { color: #87d7d7; } .eb116 { background-color: #87d7d7; }
|
127
|
+
.ef117 { color: #87d7ff; } .eb117 { background-color: #87d7ff; }
|
128
|
+
.ef118 { color: #87ff00; } .eb118 { background-color: #87ff00; }
|
129
|
+
.ef119 { color: #87ff5f; } .eb119 { background-color: #87ff5f; }
|
130
|
+
.ef120 { color: #87ff87; } .eb120 { background-color: #87ff87; }
|
131
|
+
.ef121 { color: #87ffaf; } .eb121 { background-color: #87ffaf; }
|
132
|
+
.ef122 { color: #87ffd7; } .eb122 { background-color: #87ffd7; }
|
133
|
+
.ef123 { color: #87ffff; } .eb123 { background-color: #87ffff; }
|
134
|
+
.ef124 { color: #af0000; } .eb124 { background-color: #af0000; }
|
135
|
+
.ef125 { color: #af005f; } .eb125 { background-color: #af005f; }
|
136
|
+
.ef126 { color: #af0087; } .eb126 { background-color: #af0087; }
|
137
|
+
.ef127 { color: #af00af; } .eb127 { background-color: #af00af; }
|
138
|
+
.ef128 { color: #af00d7; } .eb128 { background-color: #af00d7; }
|
139
|
+
.ef129 { color: #af00ff; } .eb129 { background-color: #af00ff; }
|
140
|
+
.ef130 { color: #af5f00; } .eb130 { background-color: #af5f00; }
|
141
|
+
.ef131 { color: #af5f5f; } .eb131 { background-color: #af5f5f; }
|
142
|
+
.ef132 { color: #af5f87; } .eb132 { background-color: #af5f87; }
|
143
|
+
.ef133 { color: #af5faf; } .eb133 { background-color: #af5faf; }
|
144
|
+
.ef134 { color: #af5fd7; } .eb134 { background-color: #af5fd7; }
|
145
|
+
.ef135 { color: #af5fff; } .eb135 { background-color: #af5fff; }
|
146
|
+
.ef136 { color: #af8700; } .eb136 { background-color: #af8700; }
|
147
|
+
.ef137 { color: #af875f; } .eb137 { background-color: #af875f; }
|
148
|
+
.ef138 { color: #af8787; } .eb138 { background-color: #af8787; }
|
149
|
+
.ef139 { color: #af87af; } .eb139 { background-color: #af87af; }
|
150
|
+
.ef140 { color: #af87d7; } .eb140 { background-color: #af87d7; }
|
151
|
+
.ef141 { color: #af87ff; } .eb141 { background-color: #af87ff; }
|
152
|
+
.ef142 { color: #afaf00; } .eb142 { background-color: #afaf00; }
|
153
|
+
.ef143 { color: #afaf5f; } .eb143 { background-color: #afaf5f; }
|
154
|
+
.ef144 { color: #afaf87; } .eb144 { background-color: #afaf87; }
|
155
|
+
.ef145 { color: #afafaf; } .eb145 { background-color: #afafaf; }
|
156
|
+
.ef146 { color: #afafd7; } .eb146 { background-color: #afafd7; }
|
157
|
+
.ef147 { color: #afafff; } .eb147 { background-color: #afafff; }
|
158
|
+
.ef148 { color: #afd700; } .eb148 { background-color: #afd700; }
|
159
|
+
.ef149 { color: #afd75f; } .eb149 { background-color: #afd75f; }
|
160
|
+
.ef150 { color: #afd787; } .eb150 { background-color: #afd787; }
|
161
|
+
.ef151 { color: #afd7af; } .eb151 { background-color: #afd7af; }
|
162
|
+
.ef152 { color: #afd7d7; } .eb152 { background-color: #afd7d7; }
|
163
|
+
.ef153 { color: #afd7ff; } .eb153 { background-color: #afd7ff; }
|
164
|
+
.ef154 { color: #afff00; } .eb154 { background-color: #afff00; }
|
165
|
+
.ef155 { color: #afff5f; } .eb155 { background-color: #afff5f; }
|
166
|
+
.ef156 { color: #afff87; } .eb156 { background-color: #afff87; }
|
167
|
+
.ef157 { color: #afffaf; } .eb157 { background-color: #afffaf; }
|
168
|
+
.ef158 { color: #afffd7; } .eb158 { background-color: #afffd7; }
|
169
|
+
.ef159 { color: #afffff; } .eb159 { background-color: #afffff; }
|
170
|
+
.ef160 { color: #d70000; } .eb160 { background-color: #d70000; }
|
171
|
+
.ef161 { color: #d7005f; } .eb161 { background-color: #d7005f; }
|
172
|
+
.ef162 { color: #d70087; } .eb162 { background-color: #d70087; }
|
173
|
+
.ef163 { color: #d700af; } .eb163 { background-color: #d700af; }
|
174
|
+
.ef164 { color: #d700d7; } .eb164 { background-color: #d700d7; }
|
175
|
+
.ef165 { color: #d700ff; } .eb165 { background-color: #d700ff; }
|
176
|
+
.ef166 { color: #d75f00; } .eb166 { background-color: #d75f00; }
|
177
|
+
.ef167 { color: #d75f5f; } .eb167 { background-color: #d75f5f; }
|
178
|
+
.ef168 { color: #d75f87; } .eb168 { background-color: #d75f87; }
|
179
|
+
.ef169 { color: #d75faf; } .eb169 { background-color: #d75faf; }
|
180
|
+
.ef170 { color: #d75fd7; } .eb170 { background-color: #d75fd7; }
|
181
|
+
.ef171 { color: #d75fff; } .eb171 { background-color: #d75fff; }
|
182
|
+
.ef172 { color: #d78700; } .eb172 { background-color: #d78700; }
|
183
|
+
.ef173 { color: #d7875f; } .eb173 { background-color: #d7875f; }
|
184
|
+
.ef174 { color: #d78787; } .eb174 { background-color: #d78787; }
|
185
|
+
.ef175 { color: #d787af; } .eb175 { background-color: #d787af; }
|
186
|
+
.ef176 { color: #d787d7; } .eb176 { background-color: #d787d7; }
|
187
|
+
.ef177 { color: #d787ff; } .eb177 { background-color: #d787ff; }
|
188
|
+
.ef178 { color: #d7af00; } .eb178 { background-color: #d7af00; }
|
189
|
+
.ef179 { color: #d7af5f; } .eb179 { background-color: #d7af5f; }
|
190
|
+
.ef180 { color: #d7af87; } .eb180 { background-color: #d7af87; }
|
191
|
+
.ef181 { color: #d7afaf; } .eb181 { background-color: #d7afaf; }
|
192
|
+
.ef182 { color: #d7afd7; } .eb182 { background-color: #d7afd7; }
|
193
|
+
.ef183 { color: #d7afff; } .eb183 { background-color: #d7afff; }
|
194
|
+
.ef184 { color: #d7d700; } .eb184 { background-color: #d7d700; }
|
195
|
+
.ef185 { color: #d7d75f; } .eb185 { background-color: #d7d75f; }
|
196
|
+
.ef186 { color: #d7d787; } .eb186 { background-color: #d7d787; }
|
197
|
+
.ef187 { color: #d7d7af; } .eb187 { background-color: #d7d7af; }
|
198
|
+
.ef188 { color: #d7d7d7; } .eb188 { background-color: #d7d7d7; }
|
199
|
+
.ef189 { color: #d7d7ff; } .eb189 { background-color: #d7d7ff; }
|
200
|
+
.ef190 { color: #d7ff00; } .eb190 { background-color: #d7ff00; }
|
201
|
+
.ef191 { color: #d7ff5f; } .eb191 { background-color: #d7ff5f; }
|
202
|
+
.ef192 { color: #d7ff87; } .eb192 { background-color: #d7ff87; }
|
203
|
+
.ef193 { color: #d7ffaf; } .eb193 { background-color: #d7ffaf; }
|
204
|
+
.ef194 { color: #d7ffd7; } .eb194 { background-color: #d7ffd7; }
|
205
|
+
.ef195 { color: #d7ffff; } .eb195 { background-color: #d7ffff; }
|
206
|
+
.ef196 { color: #ff0000; } .eb196 { background-color: #ff0000; }
|
207
|
+
.ef197 { color: #ff005f; } .eb197 { background-color: #ff005f; }
|
208
|
+
.ef198 { color: #ff0087; } .eb198 { background-color: #ff0087; }
|
209
|
+
.ef199 { color: #ff00af; } .eb199 { background-color: #ff00af; }
|
210
|
+
.ef200 { color: #ff00d7; } .eb200 { background-color: #ff00d7; }
|
211
|
+
.ef201 { color: #ff00ff; } .eb201 { background-color: #ff00ff; }
|
212
|
+
.ef202 { color: #ff5f00; } .eb202 { background-color: #ff5f00; }
|
213
|
+
.ef203 { color: #ff5f5f; } .eb203 { background-color: #ff5f5f; }
|
214
|
+
.ef204 { color: #ff5f87; } .eb204 { background-color: #ff5f87; }
|
215
|
+
.ef205 { color: #ff5faf; } .eb205 { background-color: #ff5faf; }
|
216
|
+
.ef206 { color: #ff5fd7; } .eb206 { background-color: #ff5fd7; }
|
217
|
+
.ef207 { color: #ff5fff; } .eb207 { background-color: #ff5fff; }
|
218
|
+
.ef208 { color: #ff8700; } .eb208 { background-color: #ff8700; }
|
219
|
+
.ef209 { color: #ff875f; } .eb209 { background-color: #ff875f; }
|
220
|
+
.ef210 { color: #ff8787; } .eb210 { background-color: #ff8787; }
|
221
|
+
.ef211 { color: #ff87af; } .eb211 { background-color: #ff87af; }
|
222
|
+
.ef212 { color: #ff87d7; } .eb212 { background-color: #ff87d7; }
|
223
|
+
.ef213 { color: #ff87ff; } .eb213 { background-color: #ff87ff; }
|
224
|
+
.ef214 { color: #ffaf00; } .eb214 { background-color: #ffaf00; }
|
225
|
+
.ef215 { color: #ffaf5f; } .eb215 { background-color: #ffaf5f; }
|
226
|
+
.ef216 { color: #ffaf87; } .eb216 { background-color: #ffaf87; }
|
227
|
+
.ef217 { color: #ffafaf; } .eb217 { background-color: #ffafaf; }
|
228
|
+
.ef218 { color: #ffafd7; } .eb218 { background-color: #ffafd7; }
|
229
|
+
.ef219 { color: #ffafff; } .eb219 { background-color: #ffafff; }
|
230
|
+
.ef220 { color: #ffd700; } .eb220 { background-color: #ffd700; }
|
231
|
+
.ef221 { color: #ffd75f; } .eb221 { background-color: #ffd75f; }
|
232
|
+
.ef222 { color: #ffd787; } .eb222 { background-color: #ffd787; }
|
233
|
+
.ef223 { color: #ffd7af; } .eb223 { background-color: #ffd7af; }
|
234
|
+
.ef224 { color: #ffd7d7; } .eb224 { background-color: #ffd7d7; }
|
235
|
+
.ef225 { color: #ffd7ff; } .eb225 { background-color: #ffd7ff; }
|
236
|
+
.ef226 { color: #ffff00; } .eb226 { background-color: #ffff00; }
|
237
|
+
.ef227 { color: #ffff5f; } .eb227 { background-color: #ffff5f; }
|
238
|
+
.ef228 { color: #ffff87; } .eb228 { background-color: #ffff87; }
|
239
|
+
.ef229 { color: #ffffaf; } .eb229 { background-color: #ffffaf; }
|
240
|
+
.ef230 { color: #ffffd7; } .eb230 { background-color: #ffffd7; }
|
241
|
+
.ef231 { color: #ffffff; } .eb231 { background-color: #ffffff; }
|
242
|
+
.ef232 { color: #080808; } .eb232 { background-color: #080808; }
|
243
|
+
.ef233 { color: #121212; } .eb233 { background-color: #121212; }
|
244
|
+
.ef234 { color: #1c1c1c; } .eb234 { background-color: #1c1c1c; }
|
245
|
+
.ef235 { color: #262626; } .eb235 { background-color: #262626; }
|
246
|
+
.ef236 { color: #303030; } .eb236 { background-color: #303030; }
|
247
|
+
.ef237 { color: #3a3a3a; } .eb237 { background-color: #3a3a3a; }
|
248
|
+
.ef238 { color: #444444; } .eb238 { background-color: #444444; }
|
249
|
+
.ef239 { color: #4e4e4e; } .eb239 { background-color: #4e4e4e; }
|
250
|
+
.ef240 { color: #585858; } .eb240 { background-color: #585858; }
|
251
|
+
.ef241 { color: #626262; } .eb241 { background-color: #626262; }
|
252
|
+
.ef242 { color: #6c6c6c; } .eb242 { background-color: #6c6c6c; }
|
253
|
+
.ef243 { color: #767676; } .eb243 { background-color: #767676; }
|
254
|
+
.ef244 { color: #808080; } .eb244 { background-color: #808080; }
|
255
|
+
.ef245 { color: #8a8a8a; } .eb245 { background-color: #8a8a8a; }
|
256
|
+
.ef246 { color: #949494; } .eb246 { background-color: #949494; }
|
257
|
+
.ef247 { color: #9e9e9e; } .eb247 { background-color: #9e9e9e; }
|
258
|
+
.ef248 { color: #a8a8a8; } .eb248 { background-color: #a8a8a8; }
|
259
|
+
.ef249 { color: #b2b2b2; } .eb249 { background-color: #b2b2b2; }
|
260
|
+
.ef250 { color: #bcbcbc; } .eb250 { background-color: #bcbcbc; }
|
261
|
+
.ef251 { color: #c6c6c6; } .eb251 { background-color: #c6c6c6; }
|
262
|
+
.ef252 { color: #d0d0d0; } .eb252 { background-color: #d0d0d0; }
|
263
|
+
.ef253 { color: #dadada; } .eb253 { background-color: #dadada; }
|
264
|
+
.ef254 { color: #e4e4e4; } .eb254 { background-color: #e4e4e4; }
|
265
|
+
.ef255 { color: #eeeeee; } .eb255 { background-color: #eeeeee; }
|
266
|
+
|
267
|
+
.f9 { color: #000000; }
|
268
|
+
.b9 { background-color: #FFFFFF; }
|
269
|
+
.f9 > .bold,.bold > .f9, body.f9 > pre > .bold {
|
270
|
+
/* Bold is heavy black on white, or bright white
|
271
|
+
depending on the default background */
|
272
|
+
color: #000000;
|
273
|
+
font-weight: bold;
|
274
|
+
}
|
275
|
+
.reverse {
|
276
|
+
/* CSS doesnt support swapping fg and bg colours unfortunately,
|
277
|
+
so just hardcode something that will look OK on all backgrounds. */
|
278
|
+
color: #000000; background-color: #AAAAAA;
|
279
|
+
}
|
280
|
+
.underline { text-decoration: underline; }
|
281
|
+
.line-through { text-decoration: line-through; }
|
282
|
+
.blink { text-decoration: blink; }
|
283
|
+
|