etsy-deployinator 1.0.1
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/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
|
+
|