flapjack 0.7.35 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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
+ }