flapjack 0.7.35 → 0.8.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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -1
  3. data/Gemfile +3 -4
  4. data/Guardfile +1 -1
  5. data/README.md +38 -19
  6. data/Rakefile +1 -3
  7. data/etc/flapjack_config.yaml.example +11 -1
  8. data/features/steps/cli_steps.rb +3 -3
  9. data/features/steps/events_steps.rb +7 -6
  10. data/features/steps/flapjack-netsaint-parser_steps.rb +8 -8
  11. data/features/steps/notifications_steps.rb +10 -10
  12. data/features/steps/packaging-lintian_steps.rb +5 -9
  13. data/features/steps/time_travel_steps.rb +1 -1
  14. data/flapjack.gemspec +4 -3
  15. data/lib/flapjack/data/contact.rb +78 -6
  16. data/lib/flapjack/data/entity.rb +11 -2
  17. data/lib/flapjack/data/notification_rule.rb +67 -59
  18. data/lib/flapjack/data/semaphore.rb +44 -0
  19. data/lib/flapjack/gateways/api.rb +24 -28
  20. data/lib/flapjack/gateways/api/contact_methods.rb +1 -2
  21. data/lib/flapjack/gateways/api/entity_methods.rb +3 -3
  22. data/lib/flapjack/gateways/jsonapi.rb +249 -0
  23. data/lib/flapjack/gateways/jsonapi/contact_methods.rb +544 -0
  24. data/lib/flapjack/gateways/jsonapi/entity_check_presenter.rb +217 -0
  25. data/lib/flapjack/gateways/jsonapi/entity_methods.rb +350 -0
  26. data/lib/flapjack/gateways/jsonapi/entity_presenter.rb +75 -0
  27. data/lib/flapjack/gateways/jsonapi/rack/json_params_parser.rb +32 -0
  28. data/lib/flapjack/gateways/web.rb +78 -12
  29. data/lib/flapjack/gateways/web/public/css/bootstrap-theme.css +397 -0
  30. data/lib/flapjack/gateways/web/public/css/bootstrap-theme.min.css +7 -0
  31. data/lib/flapjack/gateways/web/public/css/bootstrap.css +7118 -0
  32. data/lib/flapjack/gateways/web/public/css/bootstrap.min.css +6 -8
  33. data/lib/flapjack/gateways/web/public/css/font-awesome.css +1338 -0
  34. data/lib/flapjack/gateways/web/public/css/font-awesome.min.css +4 -0
  35. data/lib/flapjack/gateways/web/public/css/screen.css +80 -0
  36. data/lib/flapjack/gateways/web/public/css/select2-bootstrap.css +87 -0
  37. data/lib/flapjack/gateways/web/public/css/select2.css +615 -0
  38. data/lib/flapjack/gateways/web/public/fonts/FontAwesome.otf +0 -0
  39. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.eot +0 -0
  40. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.svg +414 -0
  41. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.ttf +0 -0
  42. data/lib/flapjack/gateways/web/public/fonts/fontawesome-webfont.woff +0 -0
  43. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
  44. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.svg +229 -0
  45. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  46. data/lib/flapjack/gateways/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
  47. data/lib/flapjack/gateways/web/public/img/flapjack-2013-notext-transparent-300-300.png +0 -0
  48. data/lib/flapjack/gateways/web/public/img/select2.png +0 -0
  49. data/lib/flapjack/gateways/web/public/img/select2x2.png +0 -0
  50. data/lib/flapjack/gateways/web/public/js/backbone-min.js +2 -0
  51. data/lib/flapjack/gateways/web/public/js/backbone.js +1581 -0
  52. data/lib/flapjack/gateways/web/public/js/backbone.jsonapi.js +75 -0
  53. data/lib/flapjack/gateways/web/public/js/bootstrap.js +2276 -0
  54. data/lib/flapjack/gateways/web/public/js/contacts.js +225 -0
  55. data/lib/flapjack/gateways/web/public/js/jquery-1.10.2.js +9789 -0
  56. data/lib/flapjack/gateways/web/public/js/jquery-1.10.2.min.js +6 -0
  57. data/lib/flapjack/gateways/web/public/js/select2.js +3255 -0
  58. data/lib/flapjack/gateways/web/public/js/select2.min.js +22 -0
  59. data/lib/flapjack/gateways/web/public/js/underscore-min.js +6 -0
  60. data/lib/flapjack/gateways/web/public/js/underscore.js +1276 -0
  61. data/lib/flapjack/gateways/web/views/check.html.erb +423 -193
  62. data/lib/flapjack/gateways/web/views/checks.html.erb +51 -71
  63. data/lib/flapjack/gateways/web/views/contact.html.erb +142 -164
  64. data/lib/flapjack/gateways/web/views/contacts.html.erb +20 -40
  65. data/lib/flapjack/gateways/web/views/edit_contacts.html.erb +83 -0
  66. data/lib/flapjack/gateways/web/views/entities.html.erb +18 -37
  67. data/lib/flapjack/gateways/web/views/entity.html.erb +46 -65
  68. data/lib/flapjack/gateways/web/views/index.html.erb +6 -27
  69. data/lib/flapjack/gateways/web/views/layout.erb +95 -0
  70. data/lib/flapjack/gateways/web/views/self_stats.html.erb +100 -114
  71. data/lib/flapjack/pikelet.rb +4 -2
  72. data/lib/flapjack/version.rb +1 -1
  73. data/spec/lib/flapjack/coordinator_spec.rb +120 -120
  74. data/spec/lib/flapjack/data/contact_spec.rb +66 -58
  75. data/spec/lib/flapjack/data/entity_check_spec.rb +179 -179
  76. data/spec/lib/flapjack/data/entity_spec.rb +71 -71
  77. data/spec/lib/flapjack/data/event_spec.rb +34 -30
  78. data/spec/lib/flapjack/data/message_spec.rb +6 -6
  79. data/spec/lib/flapjack/data/notification_rule_spec.rb +24 -24
  80. data/spec/lib/flapjack/data/notification_spec.rb +19 -19
  81. data/spec/lib/flapjack/data/semaphore_spec.rb +24 -0
  82. data/spec/lib/flapjack/data/tag_spec.rb +11 -10
  83. data/spec/lib/flapjack/gateways/api/contact_methods_spec.rb +201 -201
  84. data/spec/lib/flapjack/gateways/api/entity_check_presenter_spec.rb +55 -55
  85. data/spec/lib/flapjack/gateways/api/entity_methods_spec.rb +257 -257
  86. data/spec/lib/flapjack/gateways/api/entity_presenter_spec.rb +26 -26
  87. data/spec/lib/flapjack/gateways/api_spec.rb +1 -1
  88. data/spec/lib/flapjack/gateways/email_spec.rb +4 -4
  89. data/spec/lib/flapjack/gateways/jabber_spec.rb +77 -77
  90. data/spec/lib/flapjack/gateways/jsonapi/contact_methods_spec.rb +830 -0
  91. data/spec/lib/flapjack/gateways/jsonapi/entity_check_presenter_spec.rb +211 -0
  92. data/spec/lib/flapjack/gateways/jsonapi/entity_methods_spec.rb +863 -0
  93. data/spec/lib/flapjack/gateways/jsonapi/entity_presenter_spec.rb +108 -0
  94. data/spec/lib/flapjack/gateways/jsonapi_spec.rb +8 -0
  95. data/spec/lib/flapjack/gateways/oobetet_spec.rb +35 -35
  96. data/spec/lib/flapjack/gateways/pagerduty_spec.rb +40 -40
  97. data/spec/lib/flapjack/gateways/sms_messagenet_spec.rb +3 -3
  98. data/spec/lib/flapjack/gateways/web/views/check.html.erb_spec.rb +1 -1
  99. data/spec/lib/flapjack/gateways/web/views/contact.html.erb_spec.rb +5 -5
  100. data/spec/lib/flapjack/gateways/web/views/index.html.erb_spec.rb +1 -1
  101. data/spec/lib/flapjack/gateways/web_spec.rb +73 -74
  102. data/spec/lib/flapjack/logger_spec.rb +13 -13
  103. data/spec/lib/flapjack/pikelet_spec.rb +33 -33
  104. data/spec/lib/flapjack/processor_spec.rb +22 -22
  105. data/spec/lib/flapjack/redis_pool_spec.rb +1 -1
  106. data/spec/lib/flapjack/utility_spec.rb +12 -12
  107. data/spec/spec_helper.rb +9 -9
  108. data/spec/support/erb_view_helper.rb +4 -0
  109. metadata +107 -96
  110. data/lib/flapjack/gateways/web/public/css/flapjack.css +0 -49
  111. data/lib/flapjack/gateways/web/views/_css.html.erb +0 -42
  112. data/lib/flapjack/gateways/web/views/_foot.html.erb +0 -3
  113. data/lib/flapjack/gateways/web/views/_head.html.erb +0 -5
  114. data/lib/flapjack/gateways/web/views/_nav.html.erb +0 -10
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Formats entity data for presentation by the API methods in Flapjack::Gateways::API.
4
+ # Currently this just aggregates all of the check data for an entity, leaving
5
+ # clients to make any further calculations for themselves.
6
+
7
+ require 'sinatra/base'
8
+
9
+ require 'flapjack/gateways/jsonapi/entity_check_presenter'
10
+ require 'flapjack/data/entity_check'
11
+
12
+ module Flapjack
13
+
14
+ module Gateways
15
+
16
+ class JSONAPI < Sinatra::Base
17
+
18
+ class EntityPresenter
19
+
20
+ def initialize(entity, options = {})
21
+ @entity = entity
22
+ @redis = options[:redis]
23
+ end
24
+
25
+ def status
26
+ checks.collect {|c| {:entity => @entity.name, :check => c,
27
+ :status => check_presenter(c).status } }
28
+ end
29
+
30
+ def outages(start_time, end_time)
31
+ checks.collect {|c|
32
+ {:entity => @entity.name, :check => c, :outages => check_presenter(c).outages(start_time, end_time)}
33
+ }
34
+ end
35
+
36
+ def unscheduled_maintenances(start_time, end_time)
37
+ checks.collect {|c|
38
+ {:entity => @entity.name, :check => c, :unscheduled_maintenances =>
39
+ check_presenter(c).unscheduled_maintenances(start_time, end_time)}
40
+ }
41
+ end
42
+
43
+ def scheduled_maintenances(start_time, end_time)
44
+ checks.collect {|c|
45
+ {:entity => @entity.name, :check => c, :scheduled_maintenances =>
46
+ check_presenter(c).scheduled_maintenances(start_time, end_time)}
47
+ }
48
+ end
49
+
50
+ def downtime(start_time, end_time)
51
+ checks.collect {|c|
52
+ {:entity => @entity.name, :check => c, :downtime =>
53
+ check_presenter(c).downtime(start_time, end_time)}
54
+ }
55
+ end
56
+
57
+ private
58
+
59
+ def checks
60
+ @check_list ||= @entity.check_list.sort
61
+ end
62
+
63
+ def check_presenter(check)
64
+ entity_check = Flapjack::Data::EntityCheck.for_entity(@entity, check,
65
+ :redis => @redis)
66
+ presenter = Flapjack::Gateways::JSONAPI::EntityCheckPresenter.new(entity_check)
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rack'
4
+
5
+ module Flapjack
6
+ module Gateways
7
+ class JSONAPI < Sinatra::Base
8
+ module Rack
9
+ class JsonParamsParser < Struct.new(:app)
10
+ def call(env)
11
+ if env['rack.input'] and not input_parsed?(env) and type_match?(env)
12
+ env['rack.request.form_input'] = env['rack.input']
13
+ data = env['rack.input'].read
14
+ env['rack.input'].rewind
15
+ env['rack.request.form_hash'] = data.empty? ? {} : Oj.load(data)
16
+ end
17
+ app.call(env)
18
+ end
19
+
20
+ def input_parsed? env
21
+ env['rack.request.form_input'].eql? env['rack.input']
22
+ end
23
+
24
+ def type_match? env
25
+ type = env['CONTENT_TYPE'] and
26
+ Flapjack::Gateways::JSONAPI::JSON_REQUEST_MIME_TYPES.include?(type.split(/\s*[;,]\s*/, 2).first.downcase)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -6,6 +6,7 @@ require 'sinatra/base'
6
6
  require 'erb'
7
7
  require 'rack/fiber_pool'
8
8
  require 'json'
9
+ require 'uri'
9
10
 
10
11
  require 'flapjack/rack_logger'
11
12
 
@@ -54,6 +55,18 @@ module Flapjack
54
55
  use Flapjack::CommonLogger, access_logger
55
56
  end
56
57
 
58
+ @api_url = @config['api_url']
59
+ if @api_url
60
+ if (@api_url =~ /^#{URI::regexp(%w(http https))}$/).nil?
61
+ @logger.error "api_url is not a valid http or https URI (#{@api_url})"
62
+ @api_url = nil
63
+ end
64
+ end
65
+
66
+ unless @api_url
67
+ @logger.error "api_url is not configured, parts of the web interface will be broken"
68
+ end
69
+
57
70
  end
58
71
  end
59
72
 
@@ -80,6 +93,10 @@ module Flapjack
80
93
  self.class.instance_variable_get('@logger')
81
94
  end
82
95
 
96
+ def api_url
97
+ self.class.instance_variable_get('@api_url')
98
+ end
99
+
83
100
  get '/' do
84
101
  check_stats
85
102
  entity_stats
@@ -289,6 +306,11 @@ module Flapjack
289
306
  erb 'contacts.html'.to_sym
290
307
  end
291
308
 
309
+ get '/edit_contacts' do
310
+ @api_url = api_url
311
+ erb 'edit_contacts.html'.to_sym
312
+ end
313
+
292
314
  get "/contacts/:contact" do
293
315
  contact_id = params[:contact]
294
316
 
@@ -313,16 +335,6 @@ module Flapjack
313
335
  erb 'contact.html'.to_sym
314
336
  end
315
337
 
316
- protected
317
-
318
- # TODO cache constructed erb object to improve performance -- check mtime
319
- # to know when to refresh; would need to synchronize accesses to the cache,
320
- # to lock out reads while it's being refreshed
321
- def render_erb(file, bind)
322
- erb = ERB.new(File.read(File.dirname(__FILE__) + '/web/views/' + file))
323
- erb.result(bind)
324
- end
325
-
326
338
  private
327
339
 
328
340
  def get_entity_check(entity, check)
@@ -421,8 +433,62 @@ module Flapjack
421
433
  end
422
434
  end
423
435
 
424
- end
436
+ def require_css(*css)
437
+ @required_css ||= []
438
+ @required_css += css
439
+ end
425
440
 
426
- end
441
+ def require_js(*js)
442
+ @required_js ||= []
443
+ @required_js += js
444
+ end
445
+
446
+ def include_required_js
447
+ if @required_js
448
+ @required_js.map { |filename|
449
+ "<script type='text/javascript' src='#{link_to("/js/#{filename}.js")}'></script>"
450
+ }.join("\n ")
451
+ else
452
+ ""
453
+ end
454
+ end
427
455
 
456
+ def include_required_css
457
+ if @required_css
458
+ @required_css.map { |filename|
459
+ %(<link rel="stylesheet" href="#{link_to("/css/#{filename}.css")}" media="screen">)
460
+ }.join("\n ")
461
+ else
462
+ ""
463
+ end
464
+ end
465
+
466
+ # from http://gist.github.com/98310
467
+ def link_to(url_fragment, mode=:path_only)
468
+ case mode
469
+ when :path_only
470
+ base = request.script_name
471
+ when :full_url
472
+ if (request.scheme == 'http' && request.port == 80 ||
473
+ request.scheme == 'https' && request.port == 443)
474
+ port = ""
475
+ else
476
+ port = ":#{request.port}"
477
+ end
478
+ base = "#{request.scheme}://#{request.host}#{port}#{request.script_name}"
479
+ else
480
+ raise "Unknown script_url mode #{mode}"
481
+ end
482
+ "#{base}#{url_fragment}"
483
+ end
484
+
485
+ def page_title(string)
486
+ @page_title = string
487
+ end
488
+
489
+ def include_page_title
490
+ @page_title ? "#{@page_title} | Flapjack" : "Flapjack"
491
+ end
492
+ end
493
+ end
428
494
  end
@@ -0,0 +1,397 @@
1
+ /*!
2
+ * Bootstrap v3.0.3 (http://getbootstrap.com)
3
+ * Copyright 2013 Twitter, Inc.
4
+ * Licensed under http://www.apache.org/licenses/LICENSE-2.0
5
+ */
6
+
7
+ .btn-default,
8
+ .btn-primary,
9
+ .btn-success,
10
+ .btn-info,
11
+ .btn-warning,
12
+ .btn-danger {
13
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
14
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
15
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
16
+ }
17
+
18
+ .btn-default:active,
19
+ .btn-primary:active,
20
+ .btn-success:active,
21
+ .btn-info:active,
22
+ .btn-warning:active,
23
+ .btn-danger:active,
24
+ .btn-default.active,
25
+ .btn-primary.active,
26
+ .btn-success.active,
27
+ .btn-info.active,
28
+ .btn-warning.active,
29
+ .btn-danger.active {
30
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
31
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
32
+ }
33
+
34
+ .btn:active,
35
+ .btn.active {
36
+ background-image: none;
37
+ }
38
+
39
+ .btn-default {
40
+ text-shadow: 0 1px 0 #fff;
41
+ background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
42
+ background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);
43
+ background-repeat: repeat-x;
44
+ border-color: #dbdbdb;
45
+ border-color: #ccc;
46
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
47
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
48
+ }
49
+
50
+ .btn-default:hover,
51
+ .btn-default:focus {
52
+ background-color: #e0e0e0;
53
+ background-position: 0 -15px;
54
+ }
55
+
56
+ .btn-default:active,
57
+ .btn-default.active {
58
+ background-color: #e0e0e0;
59
+ border-color: #dbdbdb;
60
+ }
61
+
62
+ .btn-primary {
63
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
64
+ background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
65
+ background-repeat: repeat-x;
66
+ border-color: #2b669a;
67
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
68
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
69
+ }
70
+
71
+ .btn-primary:hover,
72
+ .btn-primary:focus {
73
+ background-color: #2d6ca2;
74
+ background-position: 0 -15px;
75
+ }
76
+
77
+ .btn-primary:active,
78
+ .btn-primary.active {
79
+ background-color: #2d6ca2;
80
+ border-color: #2b669a;
81
+ }
82
+
83
+ .btn-success {
84
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
85
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
86
+ background-repeat: repeat-x;
87
+ border-color: #3e8f3e;
88
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
89
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
90
+ }
91
+
92
+ .btn-success:hover,
93
+ .btn-success:focus {
94
+ background-color: #419641;
95
+ background-position: 0 -15px;
96
+ }
97
+
98
+ .btn-success:active,
99
+ .btn-success.active {
100
+ background-color: #419641;
101
+ border-color: #3e8f3e;
102
+ }
103
+
104
+ .btn-warning {
105
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
106
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
107
+ background-repeat: repeat-x;
108
+ border-color: #e38d13;
109
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
110
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
111
+ }
112
+
113
+ .btn-warning:hover,
114
+ .btn-warning:focus {
115
+ background-color: #eb9316;
116
+ background-position: 0 -15px;
117
+ }
118
+
119
+ .btn-warning:active,
120
+ .btn-warning.active {
121
+ background-color: #eb9316;
122
+ border-color: #e38d13;
123
+ }
124
+
125
+ .btn-danger {
126
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
127
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
128
+ background-repeat: repeat-x;
129
+ border-color: #b92c28;
130
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
131
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
132
+ }
133
+
134
+ .btn-danger:hover,
135
+ .btn-danger:focus {
136
+ background-color: #c12e2a;
137
+ background-position: 0 -15px;
138
+ }
139
+
140
+ .btn-danger:active,
141
+ .btn-danger.active {
142
+ background-color: #c12e2a;
143
+ border-color: #b92c28;
144
+ }
145
+
146
+ .btn-info {
147
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
148
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
149
+ background-repeat: repeat-x;
150
+ border-color: #28a4c9;
151
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
152
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
153
+ }
154
+
155
+ .btn-info:hover,
156
+ .btn-info:focus {
157
+ background-color: #2aabd2;
158
+ background-position: 0 -15px;
159
+ }
160
+
161
+ .btn-info:active,
162
+ .btn-info.active {
163
+ background-color: #2aabd2;
164
+ border-color: #28a4c9;
165
+ }
166
+
167
+ .thumbnail,
168
+ .img-thumbnail {
169
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
170
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
171
+ }
172
+
173
+ .dropdown-menu > li > a:hover,
174
+ .dropdown-menu > li > a:focus {
175
+ background-color: #e8e8e8;
176
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
177
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
178
+ background-repeat: repeat-x;
179
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
180
+ }
181
+
182
+ .dropdown-menu > .active > a,
183
+ .dropdown-menu > .active > a:hover,
184
+ .dropdown-menu > .active > a:focus {
185
+ background-color: #357ebd;
186
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
187
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
188
+ background-repeat: repeat-x;
189
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
190
+ }
191
+
192
+ .navbar-default {
193
+ background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
194
+ background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
195
+ background-repeat: repeat-x;
196
+ border-radius: 4px;
197
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
198
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
199
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
200
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
201
+ }
202
+
203
+ .navbar-default .navbar-nav > .active > a {
204
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
205
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
206
+ background-repeat: repeat-x;
207
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
208
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
209
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
210
+ }
211
+
212
+ .navbar-brand,
213
+ .navbar-nav > li > a {
214
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
215
+ }
216
+
217
+ .navbar-inverse {
218
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);
219
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);
220
+ background-repeat: repeat-x;
221
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
222
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
223
+ }
224
+
225
+ .navbar-inverse .navbar-nav > .active > a {
226
+ background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%);
227
+ background-image: linear-gradient(to bottom, #222222 0%, #282828 100%);
228
+ background-repeat: repeat-x;
229
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
230
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
231
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
232
+ }
233
+
234
+ .navbar-inverse .navbar-brand,
235
+ .navbar-inverse .navbar-nav > li > a {
236
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
237
+ }
238
+
239
+ .navbar-static-top,
240
+ .navbar-fixed-top,
241
+ .navbar-fixed-bottom {
242
+ border-radius: 0;
243
+ }
244
+
245
+ .alert {
246
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
247
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
248
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
249
+ }
250
+
251
+ .alert-success {
252
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
253
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
254
+ background-repeat: repeat-x;
255
+ border-color: #b2dba1;
256
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
257
+ }
258
+
259
+ .alert-info {
260
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
261
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
262
+ background-repeat: repeat-x;
263
+ border-color: #9acfea;
264
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
265
+ }
266
+
267
+ .alert-warning {
268
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
269
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
270
+ background-repeat: repeat-x;
271
+ border-color: #f5e79e;
272
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
273
+ }
274
+
275
+ .alert-danger {
276
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
277
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
278
+ background-repeat: repeat-x;
279
+ border-color: #dca7a7;
280
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
281
+ }
282
+
283
+ .progress {
284
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
285
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
286
+ background-repeat: repeat-x;
287
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
288
+ }
289
+
290
+ .progress-bar {
291
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
292
+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
293
+ background-repeat: repeat-x;
294
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
295
+ }
296
+
297
+ .progress-bar-success {
298
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
299
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
300
+ background-repeat: repeat-x;
301
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
302
+ }
303
+
304
+ .progress-bar-info {
305
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
306
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
307
+ background-repeat: repeat-x;
308
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
309
+ }
310
+
311
+ .progress-bar-warning {
312
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
313
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
314
+ background-repeat: repeat-x;
315
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
316
+ }
317
+
318
+ .progress-bar-danger {
319
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
320
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
321
+ background-repeat: repeat-x;
322
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
323
+ }
324
+
325
+ .list-group {
326
+ border-radius: 4px;
327
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
328
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
329
+ }
330
+
331
+ .list-group-item.active,
332
+ .list-group-item.active:hover,
333
+ .list-group-item.active:focus {
334
+ text-shadow: 0 -1px 0 #3071a9;
335
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
336
+ background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
337
+ background-repeat: repeat-x;
338
+ border-color: #3278b3;
339
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
340
+ }
341
+
342
+ .panel {
343
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
344
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
345
+ }
346
+
347
+ .panel-default > .panel-heading {
348
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
349
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
350
+ background-repeat: repeat-x;
351
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
352
+ }
353
+
354
+ .panel-primary > .panel-heading {
355
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
356
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
357
+ background-repeat: repeat-x;
358
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
359
+ }
360
+
361
+ .panel-success > .panel-heading {
362
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
363
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
364
+ background-repeat: repeat-x;
365
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
366
+ }
367
+
368
+ .panel-info > .panel-heading {
369
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
370
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
371
+ background-repeat: repeat-x;
372
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
373
+ }
374
+
375
+ .panel-warning > .panel-heading {
376
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
377
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
378
+ background-repeat: repeat-x;
379
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
380
+ }
381
+
382
+ .panel-danger > .panel-heading {
383
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
384
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
385
+ background-repeat: repeat-x;
386
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
387
+ }
388
+
389
+ .well {
390
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
391
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
392
+ background-repeat: repeat-x;
393
+ border-color: #dcdcdc;
394
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
395
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
396
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
397
+ }