snowman-io 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +3 -0
  3. data/README.md +4 -6
  4. data/bin/snowman +1 -1
  5. data/lib/config/mongoid.yml +5 -0
  6. data/lib/snowman-io.rb +62 -30
  7. data/lib/snowman-io/aggregate.rb +97 -0
  8. data/lib/snowman-io/api.rb +33 -65
  9. data/lib/snowman-io/api/agent.rb +27 -0
  10. data/lib/snowman-io/api/apps.rb +45 -0
  11. data/lib/snowman-io/api/auth_helpers.rb +76 -0
  12. data/lib/snowman-io/api/checks.rb +59 -0
  13. data/lib/snowman-io/api/extra/meteor.rb +45 -0
  14. data/lib/snowman-io/api/fridge.rb +14 -0
  15. data/lib/snowman-io/api/info.rb +30 -0
  16. data/lib/snowman-io/api/metrics.rb +115 -0
  17. data/lib/snowman-io/api/users.rb +231 -0
  18. data/lib/snowman-io/cli.rb +69 -0
  19. data/lib/snowman-io/launcher.rb +12 -11
  20. data/lib/snowman-io/loop/check_processor.rb +29 -0
  21. data/lib/snowman-io/loop/checks.rb +59 -0
  22. data/lib/snowman-io/loop/main.rb +43 -0
  23. data/lib/snowman-io/loop/ping.rb +25 -0
  24. data/lib/snowman-io/migration.rb +79 -0
  25. data/lib/snowman-io/models/aggregation.rb +15 -0
  26. data/lib/snowman-io/models/app.rb +61 -0
  27. data/lib/snowman-io/models/check.rb +48 -0
  28. data/lib/snowman-io/models/concerns/tokenable.rb +15 -0
  29. data/lib/snowman-io/models/data_point.rb +9 -0
  30. data/lib/snowman-io/models/deleted.rb +9 -0
  31. data/lib/snowman-io/models/following.rb +8 -0
  32. data/lib/snowman-io/models/metric.rb +36 -0
  33. data/lib/snowman-io/models/setting.rb +24 -0
  34. data/lib/snowman-io/models/user.rb +73 -0
  35. data/lib/snowman-io/options.rb +11 -3
  36. data/lib/snowman-io/report_mailer.rb +88 -0
  37. data/lib/snowman-io/reports.rb +16 -0
  38. data/lib/snowman-io/ui/AUTO_GENERATED_FOLDER +2 -0
  39. data/lib/snowman-io/ui/assets/ui-0e39dafcb798020fb855e325931c8451.css +1 -0
  40. data/lib/snowman-io/ui/assets/ui-d30809d0ae0a003d841fa95a352d624b.js +9 -0
  41. data/lib/snowman-io/ui/assets/vendor-7edfd1432c1bbd806306d5583c75b1fc.css +5 -0
  42. data/lib/snowman-io/ui/assets/vendor-c22e2ccc87c9bc7609b95939c308bc7f.js +24 -0
  43. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css +0 -0
  44. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.css.map +0 -0
  45. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap-theme.min.css +0 -0
  46. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css +0 -0
  47. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.css.map +0 -0
  48. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/css/bootstrap.min.css +0 -0
  49. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.eot +0 -0
  50. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.svg +0 -0
  51. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.ttf +0 -0
  52. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/fonts/glyphicons-halflings-regular.woff +0 -0
  53. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.js +0 -0
  54. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/bootstrap.min.js +0 -0
  55. data/lib/snowman-io/{api/public/bootstrap → ui/bootstrap-3.3.1}/js/npm.js +0 -0
  56. data/lib/snowman-io/ui/crossdomain.xml +15 -0
  57. data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.eot +0 -0
  58. data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.svg +229 -0
  59. data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.ttf +0 -0
  60. data/lib/snowman-io/ui/fonts/glyphicons-halflings-regular.woff +0 -0
  61. data/lib/snowman-io/ui/index.html +175 -0
  62. data/lib/snowman-io/ui/robots.txt +2 -0
  63. data/lib/snowman-io/utils.rb +66 -0
  64. data/lib/snowman-io/version.rb +1 -1
  65. data/lib/snowman-io/views/layouts/custom.css +42 -0
  66. data/lib/snowman-io/views/layouts/main.html.erb +38 -0
  67. data/lib/snowman-io/views/layouts/styles.css +264 -0
  68. data/lib/snowman-io/views/layouts/transactional-email-templates-LICENSE +21 -0
  69. data/lib/snowman-io/views/report_mailer/check_triggered.html.erb +16 -0
  70. data/lib/snowman-io/views/report_mailer/checks/_human_last_value_limit.html.erb +2 -0
  71. data/lib/snowman-io/views/report_mailer/checks/_human_prev_day_datapoints_limit.html.erb +2 -0
  72. data/lib/snowman-io/views/report_mailer/daily_report.html.erb +40 -0
  73. data/lib/snowman-io/views/report_mailer/restore_password.html.erb +28 -0
  74. data/lib/snowman-io/views/report_mailer/send_invite.html.erb +32 -0
  75. data/lib/snowman-io/web.rb +28 -0
  76. data/lib/snowman-io/web_server.rb +107 -0
  77. data/snowman-io.gemspec +15 -5
  78. metadata +220 -49
  79. data/lib/snowman-io/api/public/README.md +0 -36
  80. data/lib/snowman-io/api/public/css/normalize.css +0 -406
  81. data/lib/snowman-io/api/public/css/style.css +0 -4
  82. data/lib/snowman-io/api/public/js/app.js +0 -13
  83. data/lib/snowman-io/api/public/js/libs/ember-1.8.1.js +0 -49740
  84. data/lib/snowman-io/api/public/js/libs/handlebars-v1.3.0.js +0 -2746
  85. data/lib/snowman-io/api/public/js/libs/jquery-1.10.2.js +0 -9789
  86. data/lib/snowman-io/api/public/tests/runner.css +0 -14
  87. data/lib/snowman-io/api/public/tests/runner.js +0 -13
  88. data/lib/snowman-io/api/public/tests/tests.js +0 -30
  89. data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.css +0 -244
  90. data/lib/snowman-io/api/public/tests/vendor/qunit-1.12.0.js +0 -2212
  91. data/lib/snowman-io/api/views/index.erb +0 -26
  92. data/lib/snowman-io/api/views/layout.erb +0 -24
  93. data/lib/snowman-io/api/views/login.erb +0 -21
  94. data/lib/snowman-io/api/views/unpacking.erb +0 -21
  95. data/lib/snowman-io/check.rb +0 -49
  96. data/lib/snowman-io/check_result.rb +0 -15
  97. data/lib/snowman-io/checks/hosted_graphite.rb +0 -23
  98. data/lib/snowman-io/handler.rb +0 -27
  99. data/lib/snowman-io/notifiers/slack.rb +0 -76
  100. data/lib/snowman-io/processor.rb +0 -32
  101. data/lib/snowman-io/scheduler.rb +0 -42
@@ -0,0 +1,175 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1">
7
+ <title>SnowmanIO: be a little snowy</title>
8
+
9
+ <base href="/" />
10
+ <meta name="ui/config/environment" content="%7B%22modulePrefix%22%3A%22ui%22%2C%22environment%22%3A%22production%22%2C%22baseURL%22%3A%22/%22%2C%22apiPrefix%22%3A%22api%22%2C%22locationType%22%3A%22auto%22%2C%22EmberENV%22%3A%7B%22FEATURES%22%3A%7B%7D%7D%2C%22APP%22%3A%7B%22name%22%3A%22ui%22%2C%22version%22%3A%220.0.0.ab87a49e%22%7D%2C%22simple-auth-devise%22%3A%7B%22serverTokenEndpoint%22%3A%22/api/users/login%22%2C%22identificationAttributeName%22%3A%22email%22%7D%2C%22simple-auth%22%3A%7B%22authorizer%22%3A%22simple-auth-authorizer%3Adevise%22%2C%22routeAfterAuthentication%22%3A%22apps%22%7D%2C%22api%22%3A%22/api%22%2C%22contentSecurityPolicyHeader%22%3A%22Content-Security-Policy-Report-Only%22%2C%22contentSecurityPolicy%22%3A%7B%22default-src%22%3A%22%27none%27%22%2C%22script-src%22%3A%22%27self%27%22%2C%22font-src%22%3A%22%27self%27%22%2C%22connect-src%22%3A%22%27self%27%22%2C%22img-src%22%3A%22%27self%27%22%2C%22style-src%22%3A%22%27self%27%22%2C%22media-src%22%3A%22%27self%27%22%7D%2C%22exportApplicationGlobal%22%3Afalse%7D" />
11
+
12
+
13
+
14
+ <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
15
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
16
+ <!--[if lt IE 9]>
17
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
18
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
19
+ <![endif]-->
20
+
21
+ <script>
22
+ /*!
23
+ loadCSS: load a CSS file asynchronously.
24
+ [c]2014 @scottjehl, Filament Group, Inc.
25
+ Licensed MIT
26
+ */
27
+
28
+ /* exported loadCSS */
29
+ function loadCSS( href, before, media, callback ){
30
+ "use strict";
31
+ // Arguments explained:
32
+ // `href` is the URL for your CSS file.
33
+ // `before` optionally defines the element we'll use as a reference for injecting our <link>
34
+ // By default, `before` uses the first <script> element in the page.
35
+ // However, since the order in which stylesheets are referenced matters, you might need a more specific location in your document.
36
+ // If so, pass a different reference element to the `before` argument and it'll insert before that instead
37
+ // note: `insertBefore` is used instead of `appendChild`, for safety re: http://www.paulirish.com/2011/surefire-dom-element-insertion/
38
+ var ss = window.document.createElement( "link" );
39
+ var ref = before || window.document.getElementsByTagName( "script" )[ 0 ];
40
+ var sheets = window.document.styleSheets;
41
+ ss.rel = "stylesheet";
42
+ ss.href = href;
43
+ // temporarily, set media to something non-matching to ensure it'll fetch without blocking render
44
+ ss.media = "only x";
45
+ // DEPRECATED
46
+ if( callback ) {
47
+ ss.onload = callback;
48
+ }
49
+
50
+ // inject link
51
+ ref.parentNode.insertBefore( ss, ref );
52
+ // This function sets the link's media back to `all` so that the stylesheet applies once it loads
53
+ // It is designed to poll until document.styleSheets includes the new sheet.
54
+ ss.onloadcssdefined = function( cb ){
55
+ var defined;
56
+ for( var i = 0; i < sheets.length; i++ ){
57
+ if( sheets[ i ].href && sheets[ i ].href === ss.href ){
58
+ defined = true;
59
+ }
60
+ }
61
+ if( defined ){
62
+ cb();
63
+ } else {
64
+ setTimeout(function() {
65
+ ss.onloadcssdefined( cb );
66
+ });
67
+ }
68
+ };
69
+ ss.onloadcssdefined(function() {
70
+ ss.media = media || "all";
71
+ });
72
+ return ss;
73
+ }
74
+ </script>
75
+
76
+ <script>
77
+ /*!
78
+ onloadCSS: adds onload support for asynchronous stylesheets loaded with loadCSS.
79
+ [c]2014 @zachleat, Filament Group, Inc.
80
+ Licensed MIT
81
+ */
82
+
83
+ /* global navigator */
84
+ /* exported onloadCSS */
85
+ function onloadCSS( ss, callback ) {
86
+ ss.onload = function() {
87
+ ss.onload = null;
88
+ if( callback ) {
89
+ callback.call( ss );
90
+ }
91
+ };
92
+
93
+ // This code is for browsers that don’t support onload, any browser that
94
+ // supports onload should use that instead.
95
+ // No support for onload:
96
+ // * Android 4.3 (Samsung Galaxy S4, Browserstack)
97
+ // * Android 4.2 Browser (Samsung Galaxy SIII Mini GT-I8200L)
98
+ // * Android 2.3 (Pantech Burst P9070)
99
+
100
+ // Weak inference targets Android < 4.4
101
+ if( "isApplicationInstalled" in navigator && "onloadcssdefined" in ss ) {
102
+ ss.onloadcssdefined( callback );
103
+ }
104
+ }
105
+ </script>
106
+
107
+ <script>
108
+ // from: http://stackoverflow.com/questions/7718935/load-scripts-asynchronously
109
+ //this function will work cross-browser for loading scripts asynchronously
110
+ function loadScript(src, callback)
111
+ {
112
+ var s,
113
+ r,
114
+ t;
115
+ r = false;
116
+ s = document.createElement('script');
117
+ s.type = 'text/javascript';
118
+ s.src = src;
119
+ s.onload = s.onreadystatechange = function() {
120
+ //console.log( this.readyState ); //uncomment this line to see which ready states are called.
121
+ if ( !r && (!this.readyState || this.readyState == 'complete') )
122
+ {
123
+ r = true;
124
+ callback();
125
+ }
126
+ };
127
+ t = document.getElementsByTagName('script')[0];
128
+ t.parentNode.insertBefore(s, t);
129
+ }
130
+ </script>
131
+ <style>
132
+ html,body{ margin:0; padding:0; height:100%; width:100%; }
133
+ </style>
134
+
135
+
136
+ </head>
137
+ <body>
138
+
139
+
140
+ <div id="progress-holder" style="position:relative;background-color:white;width:100%;height:100%;">
141
+ <div style="position:absolute;top:42%;height:30px;width:100%">
142
+ <div style="width:550px;height:30px;background-color:#aaccff;margin:0 auto;">
143
+ <div id="progress" style="height:30px;width:50px;background-color:#5577ff;">
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>
148
+
149
+ <noscript>We are very sorry, bun SnowmanIO needs javascript enabled.</noscript>
150
+
151
+ <script>
152
+ (function() {
153
+ var vendor = loadCSS( "assets/vendor-7edfd1432c1bbd806306d5583c75b1fc.css" );
154
+ var progress = document.getElementById("progress");
155
+ var holder = document.getElementById("holder");
156
+
157
+ onloadCSS(vendor, function() {
158
+ progress.style.width = "150px";
159
+ var ui = loadCSS( "assets/ui-0e39dafcb798020fb855e325931c8451.css" );
160
+ onloadCSS(ui, function() {
161
+ progress.style.width = "250px";
162
+ loadScript("assets/vendor-c22e2ccc87c9bc7609b95939c308bc7f.js", function() {
163
+ progress.style.width = "350px";
164
+ loadScript("assets/ui-d30809d0ae0a003d841fa95a352d624b.js", function() {
165
+ progress.style.width = "450px";
166
+ });
167
+ });
168
+ });
169
+ });
170
+ })();
171
+ </script>
172
+
173
+
174
+ </body>
175
+ </html>
@@ -0,0 +1,2 @@
1
+ # http://www.robotstxt.org
2
+ User-agent: *
@@ -0,0 +1,66 @@
1
+ module SnowmanIO
2
+ module Utils
3
+ def self.floor_5sec(time)
4
+ Time.new(time.year, time.month, time.day, time.hour, time.min, (time.sec/5)*5)
5
+ end
6
+
7
+ def self.floor_10sec(time)
8
+ Time.new(time.year, time.month, time.day, time.hour, time.min, (time.sec/10)*10)
9
+ end
10
+
11
+ def self.floor_5min(time)
12
+ Time.new(time.year, time.month, time.day, time.hour, (time.min/5)*5)
13
+ end
14
+
15
+ def self.avg(arr)
16
+ arr.inject(:+).to_f/arr.length
17
+ end
18
+
19
+ # `up` value is close to 90 percentile by meaning, but it slightly
20
+ # depends of every element (weighted avarage). This metric is especially usefull for small arrays.
21
+ def self.up(arr)
22
+ sorted = arr.sort
23
+ if sorted.length <= 1
24
+ sorted[0]
25
+ else
26
+ sum = 0
27
+ amount = 0
28
+ sorted.each_with_index { |e, i|
29
+ w = i.to_f/sorted.length
30
+ if w <= 0.9
31
+ a = w + 0.1
32
+ else
33
+ a = 1.9 - w
34
+ end
35
+ sum += e*a
36
+ amount += a
37
+ }
38
+ sum/amount
39
+ end
40
+ end
41
+
42
+ def self.human_value(value)
43
+ return unless value
44
+
45
+ if value > 1_000_000
46
+ (value/1000000).round(1).to_s + "M"
47
+ elsif value > 1_000
48
+ (value/1000).round(1).to_s + "k"
49
+ elsif value > 10
50
+ value.round(1)
51
+ elsif value > 0.1
52
+ value.round(2)
53
+ elsif value > 0.01
54
+ value.round(3)
55
+ elsif value > 0.001
56
+ value.round(4)
57
+ elsif value > 0.0001
58
+ value.round(5)
59
+ elsif value > 0.00001
60
+ value.round(6)
61
+ else
62
+ value
63
+ end
64
+ end
65
+ end
66
+ end
@@ -1,3 +1,3 @@
1
1
  module SnowmanIO
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,42 @@
1
+ /* Custom styles */
2
+ td.header {
3
+ background-color: #eee;
4
+ vertical-align: middle;
5
+ font-size: 120%;
6
+ font-weight: bold;
7
+ padding-left: 10px;
8
+ padding-bottom: 5px;
9
+ }
10
+
11
+ table.app-stats th.first {
12
+ width: 20%;
13
+ }
14
+ table.app-stats th {
15
+ width: 40%;
16
+ font-weight: bold;
17
+ }
18
+
19
+ table.app-stats td.value {
20
+ text-align: right;
21
+ }
22
+
23
+ span.positive {
24
+ color: green;
25
+ }
26
+ span.negative {
27
+ color: red;
28
+ }
29
+ span.neutral {
30
+ color: #9370DB;
31
+ }
32
+ span.white {
33
+ color: white;
34
+ }
35
+
36
+ td.center {
37
+ text-align: center;
38
+ }
39
+
40
+ .alert.alert-info {
41
+ background-color: #5bc0de;
42
+ }
@@ -0,0 +1,38 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta name="viewport" content="width=device-width" />
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <title>Actionable emails e.g. reset password</title>
7
+ <link href="styles.css" media="all" rel="stylesheet" type="text/css" />
8
+ <link href="custom.css" media="all" rel="stylesheet" type="text/css" />
9
+ </head>
10
+
11
+ <body>
12
+ <table class="body-wrap">
13
+ <tr>
14
+ <td></td>
15
+ <td class="container" width="600">
16
+ <div class="content">
17
+ <table class="main" width="100%" cellpadding="0" cellspacing="0">
18
+ <%= yield :header %>
19
+ <tr>
20
+ <td class="content-wrap">
21
+ <%= yield %>
22
+ </td>
23
+ </tr>
24
+ </table>
25
+ <div class="footer">
26
+ <table width="100%">
27
+ <tr>
28
+ <td class="aligncenter content-block">SnowmanIO, 2014-<%= Time.now.year %></td>
29
+ </tr>
30
+ </table>
31
+ </div></div>
32
+ </td>
33
+ <td></td>
34
+ </tr>
35
+ </table>
36
+ </body>
37
+
38
+ </html>
@@ -0,0 +1,264 @@
1
+ /* -------------------------------------
2
+ GLOBAL
3
+ A very basic CSS reset
4
+ ------------------------------------- */
5
+ * {
6
+ margin: 0;
7
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
8
+ box-sizing: border-box;
9
+ font-size: 14px;
10
+ }
11
+
12
+ img {
13
+ max-width: 100%;
14
+ }
15
+
16
+ body {
17
+ -webkit-font-smoothing: antialiased;
18
+ -webkit-text-size-adjust: none;
19
+ width: 100% !important;
20
+ height: 100%;
21
+ line-height: 1.6;
22
+ }
23
+
24
+ /* Let's make sure all tables have defaults */
25
+ table td {
26
+ vertical-align: top;
27
+ }
28
+
29
+ /* -------------------------------------
30
+ BODY & CONTAINER
31
+ ------------------------------------- */
32
+ body {
33
+ background-color: #f6f6f6;
34
+ }
35
+
36
+ .body-wrap {
37
+ background-color: #f6f6f6;
38
+ width: 100%;
39
+ }
40
+
41
+ .container {
42
+ display: block !important;
43
+ max-width: 600px !important;
44
+ margin: 0 auto !important;
45
+ /* makes it centered */
46
+ clear: both !important;
47
+ }
48
+
49
+ .content {
50
+ max-width: 600px;
51
+ margin: 0 auto;
52
+ display: block;
53
+ padding: 20px;
54
+ }
55
+
56
+ /* -------------------------------------
57
+ HEADER, FOOTER, MAIN
58
+ ------------------------------------- */
59
+ .main {
60
+ background-color: #fff;
61
+ border: 1px solid #e9e9e9;
62
+ border-radius: 3px;
63
+ }
64
+
65
+ .content-wrap {
66
+ padding: 20px;
67
+ }
68
+
69
+ .content-block {
70
+ padding: 0 0 20px;
71
+ }
72
+
73
+ .header {
74
+ width: 100%;
75
+ margin-bottom: 20px;
76
+ }
77
+
78
+ .footer {
79
+ width: 100%;
80
+ clear: both;
81
+ color: #999;
82
+ padding: 20px;
83
+ }
84
+ .footer a {
85
+ color: #999;
86
+ }
87
+ .footer p, .footer a, .footer unsubscribe, .footer td {
88
+ font-size: 12px;
89
+ }
90
+
91
+ /* -------------------------------------
92
+ TYPOGRAPHY
93
+ ------------------------------------- */
94
+ h1, h2, h3 {
95
+ font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
96
+ color: #000;
97
+ margin: 40px 0 0;
98
+ line-height: 1.2;
99
+ font-weight: 400;
100
+ }
101
+
102
+ h1 {
103
+ font-size: 32px;
104
+ font-weight: 500;
105
+ }
106
+
107
+ h2 {
108
+ font-size: 24px;
109
+ }
110
+
111
+ h3 {
112
+ font-size: 18px;
113
+ }
114
+
115
+ h4 {
116
+ font-size: 14px;
117
+ font-weight: 600;
118
+ }
119
+
120
+ p, ul, ol {
121
+ margin-bottom: 10px;
122
+ font-weight: normal;
123
+ }
124
+ p li, ul li, ol li {
125
+ margin-left: 5px;
126
+ list-style-position: inside;
127
+ }
128
+
129
+ /* -------------------------------------
130
+ LINKS & BUTTONS
131
+ ------------------------------------- */
132
+ a {
133
+ color: #348eda;
134
+ text-decoration: underline;
135
+ }
136
+
137
+ .btn-primary {
138
+ text-decoration: none;
139
+ color: #FFF;
140
+ background-color: #348eda;
141
+ border: solid #348eda;
142
+ border-width: 10px 20px;
143
+ line-height: 2;
144
+ font-weight: bold;
145
+ text-align: center;
146
+ cursor: pointer;
147
+ display: inline-block;
148
+ border-radius: 5px;
149
+ text-transform: capitalize;
150
+ }
151
+
152
+ /* -------------------------------------
153
+ OTHER STYLES THAT MIGHT BE USEFUL
154
+ ------------------------------------- */
155
+ .last {
156
+ margin-bottom: 0;
157
+ }
158
+
159
+ .first {
160
+ margin-top: 0;
161
+ }
162
+
163
+ .aligncenter {
164
+ text-align: center;
165
+ }
166
+
167
+ .alignright {
168
+ text-align: right;
169
+ }
170
+
171
+ .alignleft {
172
+ text-align: left;
173
+ }
174
+
175
+ .clear {
176
+ clear: both;
177
+ }
178
+
179
+ /* -------------------------------------
180
+ ALERTS
181
+ Change the class depending on warning email, good email or bad email
182
+ ------------------------------------- */
183
+ .alert {
184
+ font-size: 16px;
185
+ color: #fff;
186
+ font-weight: 500;
187
+ padding: 20px;
188
+ text-align: center;
189
+ border-radius: 3px 3px 0 0;
190
+ }
191
+ .alert a {
192
+ color: #fff;
193
+ text-decoration: none;
194
+ font-weight: 500;
195
+ font-size: 16px;
196
+ }
197
+ .alert.alert-warning {
198
+ background-color: #FF9F00;
199
+ }
200
+ .alert.alert-bad {
201
+ background-color: #D0021B;
202
+ }
203
+ .alert.alert-good {
204
+ background-color: #68B90F;
205
+ }
206
+
207
+ /* -------------------------------------
208
+ INVOICE
209
+ Styles for the billing table
210
+ ------------------------------------- */
211
+ .invoice {
212
+ margin: 40px auto;
213
+ text-align: left;
214
+ width: 80%;
215
+ }
216
+ .invoice td {
217
+ padding: 5px 0;
218
+ }
219
+ .invoice .invoice-items {
220
+ width: 100%;
221
+ }
222
+ .invoice .invoice-items td {
223
+ border-top: #eee 1px solid;
224
+ }
225
+ .invoice .invoice-items .total td {
226
+ border-top: 2px solid #333;
227
+ border-bottom: 2px solid #333;
228
+ font-weight: 700;
229
+ }
230
+
231
+ /* -------------------------------------
232
+ RESPONSIVE AND MOBILE FRIENDLY STYLES
233
+ ------------------------------------- */
234
+ @media only screen and (max-width: 640px) {
235
+ h1, h2, h3, h4 {
236
+ font-weight: 600 !important;
237
+ margin: 20px 0 5px !important;
238
+ }
239
+
240
+ h1 {
241
+ font-size: 22px !important;
242
+ }
243
+
244
+ h2 {
245
+ font-size: 18px !important;
246
+ }
247
+
248
+ h3 {
249
+ font-size: 16px !important;
250
+ }
251
+
252
+ .container {
253
+ width: 100% !important;
254
+ }
255
+
256
+ .content, .content-wrap {
257
+ padding: 10px !important;
258
+ }
259
+
260
+ .invoice {
261
+ width: 100% !important;
262
+ }
263
+ }
264
+