pimon 0.1.11 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/bin/pimon +26 -19
  3. data/config/config.ru +11 -3
  4. data/config/default.yml +7 -13
  5. data/config/test.yml +6 -12
  6. data/config/test_broken.yml +0 -1
  7. data/lib/pimon.rb +2 -69
  8. data/lib/pimon/app.rb +81 -0
  9. data/lib/pimon/config.rb +34 -0
  10. data/lib/pimon/probe.rb +15 -0
  11. data/lib/pimon/probe/cpu_freq.rb +14 -0
  12. data/lib/pimon/probe/cpu_usage.rb +11 -8
  13. data/lib/pimon/probe/disk_usage.rb +11 -8
  14. data/lib/pimon/probe/memory_usage.rb +15 -10
  15. data/lib/pimon/probe/swap_usage.rb +16 -10
  16. data/lib/pimon/probe/system_memory.rb +16 -16
  17. data/lib/pimon/probe/temperature.rb +11 -13
  18. data/lib/pimon/probe/uptime.rb +37 -9
  19. data/lib/pimon/public/index.js +60 -120
  20. data/lib/pimon/public/normalize.css +427 -0
  21. data/lib/pimon/public/piecon.js +194 -0
  22. data/lib/pimon/public/style.css +13 -0
  23. data/lib/pimon/stats_collector.rb +66 -66
  24. data/lib/pimon/version.rb +1 -1
  25. data/lib/pimon/views/index.haml +17 -7
  26. data/pimon.gemspec +26 -25
  27. data/spec/{pimon_spec.rb → pimon/app_spec.rb} +9 -6
  28. data/spec/pimon/config_spec.rb +33 -0
  29. data/spec/pimon/stats_collector_spec.rb +13 -0
  30. data/spec/spec_helper.rb +9 -2
  31. metadata +195 -219
  32. data/.gitignore +0 -10
  33. data/.travis.yml +0 -6
  34. data/Gemfile +0 -20
  35. data/Gemfile.lock +0 -87
  36. data/README.md +0 -68
  37. data/Rakefile +0 -13
  38. data/WTFPL-LICENSE +0 -13
  39. data/bin/free.c +0 -12
  40. data/bin/makefile +0 -2
  41. data/bin/random.c +0 -21
  42. data/bin/random.h +0 -1
  43. data/bin/vmstat.c +0 -12
  44. data/lib/pimon/hash_extensions.rb +0 -12
  45. data/lib/pimon/pimon_config.rb +0 -32
  46. data/lib/pimon/probe/probe.rb +0 -13
  47. data/lib/pimon/probe/time_check.rb +0 -11
  48. data/lib/pimon/public/piecon.min.js +0 -5
  49. data/lib/pimon/stats.rb +0 -25
  50. data/spec/pimon_config_spec.rb +0 -17
  51. data/spec/stats_collector_spec.rb +0 -67
@@ -1,13 +1,18 @@
1
- require 'pimon/probe/probe'
2
- require 'pimon/probe/system_memory'
1
+ module Pimon
2
+ module Probe
3
+ class MemoryUsage
4
+ def self.check(date = Time.now)
5
+ options = {
6
+ date: date.strftime('%Y-%m-%d %H:%M:%S'), probe_name: 'mem',
7
+ value: SystemMemory.check(:mem),
8
+ unit: unit
9
+ }
10
+ OpenStruct.new(options)
11
+ end
3
12
 
4
- class Probe::MemoryUsage < Probe
5
-
6
- def self.check
7
- SystemMemory.check(:mem)
8
- end
9
-
10
- def self.symbol
11
- :mem
13
+ def self.unit
14
+ '%'
15
+ end
16
+ end
12
17
  end
13
18
  end
@@ -1,13 +1,19 @@
1
- require 'pimon/probe/probe'
2
- require 'pimon/probe/system_memory'
1
+ module Pimon
2
+ module Probe
3
+ class SwapUsage
4
+ def self.check(date = Time.now)
5
+ options = {
6
+ date: date.strftime('%Y-%m-%d %H:%M:%S'),
7
+ probe_name: 'swap',
8
+ value: SystemMemory.check(:swap),
9
+ unit: unit
10
+ }
11
+ OpenStruct.new(options)
12
+ end
3
13
 
4
- class Probe::SwapUsage < Probe
5
-
6
- def self.check
7
- SystemMemory.check(:swap)
8
- end
9
-
10
- def self.symbol
11
- :swap
14
+ def self.unit
15
+ '%'
16
+ end
17
+ end
12
18
  end
13
19
  end
@@ -1,19 +1,19 @@
1
- class SystemMemory
2
-
3
- def self.check(type)
4
- case type
5
- when :mem
6
- index = 1
7
- when :swap
8
- index = 2
9
- else
10
- raise "Undefined memory type: #{type}"
1
+ module Pimon
2
+ module Probe
3
+ class SystemMemory
4
+ TYPE_INDEX = {
5
+ mem: 1,
6
+ swap: 2
7
+ }
8
+
9
+ def self.check(type)
10
+ memory = `free -o -m`.split(/\n/)[TYPE_INDEX[type]].split(' ')
11
+
12
+ return 0 if memory[1].to_i == 0
13
+ # memory[1] holds total memory
14
+ # memory[2] holds used memory
15
+ ((memory[2].to_f / memory[1].to_f) * 100).to_i
16
+ end
11
17
  end
12
-
13
- memory = `free -o -m`.split(/\n/)[index].split(" ")
14
-
15
- # memory[1] holds total memory
16
- # memory[2] holds used memory
17
- ((memory[2].to_f / memory[1].to_f) * 100).to_i
18
18
  end
19
19
  end
@@ -1,16 +1,14 @@
1
- # encoding: UTF-8
2
- require 'pimon/probe/probe'
1
+ module Pimon
2
+ module Probe
3
+ class Temperature
4
+ def self.check(date = Time.now)
5
+ value = `cat /sys/class/thermal/thermal_zone0/temp`[0..1].to_i
6
+ OpenStruct.new(date: date.strftime('%Y-%m-%d %H:%M:%S'), probe_name: 'temp', value: value, unit: unit)
7
+ end
3
8
 
4
- class Probe::Temperature < Probe
5
- def self.check
6
- `cat /sys/class/thermal/thermal_zone0/temp`[0..1].to_i
7
- end
8
-
9
- def self.symbol
10
- :temp
11
- end
12
-
13
- def self.unit
14
- 'ºC'
9
+ def self.unit
10
+ 'ºC'
11
+ end
12
+ end
15
13
  end
16
14
  end
@@ -1,13 +1,41 @@
1
- require 'pimon/probe/probe'
2
1
  require 'sys/uptime'
3
2
 
4
- class Probe::Uptime < Probe
5
-
6
- def self.check
7
- Sys::Uptime.dhms
8
- end
9
-
10
- def self.symbol
11
- :uptime
3
+ module Pimon
4
+ module Probe
5
+ class Uptime
6
+ def self.check(date = Time.now)
7
+ OpenStruct.new(date: date.strftime('%Y-%m-%d %H:%M:%S'), probe_name: 'uptime', value: formatted_uptime)
8
+ end
9
+
10
+ def self.formatted_uptime
11
+ days, hours, minutes, seconds = Sys::Uptime.dhms.map(&:to_i)
12
+
13
+ uptime = ''
14
+ { day: days, hour: hours, minute: minutes, second: seconds }.each do |time_unit, value|
15
+ next if value == 0
16
+ case time_unit
17
+ when :day
18
+ uptime = "#{days}#{pluralize(value, time_unit)}"
19
+ when :second
20
+ uptime = "#{insert_word_connector(uptime, ' and ')}#{value}#{pluralize(value, time_unit)}"
21
+ when :hour, :minute
22
+ uptime = "#{insert_word_connector(uptime, ', ')}#{value}#{pluralize(value, time_unit)}"
23
+ end
24
+ end
25
+ uptime
26
+ end
27
+
28
+ def self.pluralize(count, word)
29
+ " #{word}#{count == 1 ? '' : 's'}"
30
+ end
31
+
32
+ def self.insert_word_connector(text, connector)
33
+ "#{text}#{text == '' ? '' : connector}"
34
+ end
35
+
36
+ def self.unit
37
+ nil
38
+ end
39
+ end
12
40
  end
13
41
  end
@@ -4,17 +4,25 @@ $(function () {
4
4
  rotateFaviconInterval,
5
5
  ws;
6
6
 
7
- function changeFavicon(o) {
8
- titleStats = [
9
- { 'legend' : 'CPU', 'stat' : o.cpu.stats[o.cpu.stats.length - 1], 'color' : o.cpu.color, 'unit' : o.cpu.unit } ,
10
- { 'legend' : 'MEM', 'stat' : o.mem.stats[o.mem.stats.length - 1], 'color' : o.mem.color, 'unit' : o.mem.unit } ,
11
- { 'legend' : 'SWAP', 'stat' : o.swap.stats[o.swap.stats.length - 1], 'color' : o.swap.color, 'unit' : o.swap.unit},
12
- { 'legend' : 'DISK', 'stat' : o.disk.stats[o.disk.stats.length - 1], 'color' : o.disk.color, 'unit' : o.disk.unit},
13
- { 'legend' : 'TEMP', 'stat' : o.temp.stats[o.temp.stats.length - 1], 'color' : o.temp.color, 'unit' : o.temp.unit} ];
7
+ function changeFavicon(chartStats) {
8
+ titleStats = [];
9
+
10
+ for (var probe in chartStats) {
11
+ if (probe !== 'colors') {
12
+ var pieChartOption = {
13
+ 'legend' : probe,
14
+ 'stat' : chartStats[probe].value,
15
+ 'color' : stats.colors[probe],
16
+ 'unit' : chartStats[probe].unit
17
+ }
18
+ titleStats.push(pieChartOption);
19
+ }
20
+ }
21
+
14
22
  i = 0;
15
23
  if (rotateFaviconInterval === undefined) {
16
24
  rotateFavicon(titleStats);
17
- rotateFaviconInterval = setInterval(function() { rotateFavicon(titleStats); }, 3000);
25
+ rotateFaviconInterval = setInterval(function() { rotateFavicon(titleStats); }, 2000);
18
26
  }
19
27
  }
20
28
 
@@ -33,122 +41,54 @@ $(function () {
33
41
  i = 0;
34
42
  }
35
43
  }
36
-
37
- function drawChart(o) {
38
- new Highcharts.Chart({
39
- chart: {
40
- renderTo: 'chart',
41
- type: 'line',
42
- marginRight: 130,
43
- marginBottom: 25
44
- },
45
- title: {
46
- text: 'Pimon',
47
- x: -20
48
- },
49
- subtitle: {
50
- text: o.hostname,
51
- x: -20
52
- },
53
- xAxis: {
54
- categories: o.time.stats
55
- },
56
- yAxis: {
57
- title: {
58
- text: 'Usage'
59
- },
60
- plotLines: [{
61
- value: 0,
62
- width: 1,
63
- color: '#808080'
64
- }],
65
- max: 100,
66
- min: 0
67
- },
68
- tooltip: {
69
- formatter: function() {
70
- return '<b>'+ this.series.name +'</b><br/>'+
71
- this.x +': '+ this.y + (this.series.name === 'temp' ? o.temp.unit : '%');
72
- }
73
- },
74
- legend: {
75
- layout: 'vertical',
76
- align: 'right',
77
- verticalAlign: 'top',
78
- x: -10,
79
- y: 100,
80
- borderWidth: 0
81
- },
82
- series: [{
83
- name: 'cpu',
84
- color: o.cpu.color,
85
- data: o.cpu.stats
86
- },
87
- {
88
- name: 'mem',
89
- color: o.mem.color,
90
- data: o.mem.stats
91
- },
92
- {
93
- name: 'swap',
94
- color: o.swap.color,
95
- data: o.swap.stats
96
- },
97
- {
98
- name: 'disk',
99
- color: o.disk.color,
100
- data: o.disk.stats
101
- },
102
- {
103
- name: 'temp',
104
- color: o.temp.color,
105
- data: o.temp.stats
106
- }],
107
- credits: {
108
- enabled: false
44
+
45
+ function updateSingleStats(singleStats) {
46
+ for (var probe in singleStats) {
47
+ var probeReading = stats.single[probe].value;
48
+
49
+ if (stats.single[probe].unit !== undefined) {
50
+ probeReading = probeReading + ' ' + stats.single[probe].unit;
109
51
  }
110
- });
111
- }
112
-
113
- function maybeInsertWordConnector(text, connector) {
114
- return text !== '' ? text + connector : text;
115
- }
116
-
117
- function pluralize(count, word) {
118
- return ((count === '1') ? ' ' + word : ' ' + word + 's');
119
- }
120
-
121
- function formatUptime(uptimeArray) {
122
- var uptime = '',
123
- days = uptimeArray[0],
124
- hours = uptimeArray[1],
125
- minutes = uptimeArray[2],
126
- seconds = uptimeArray[3];
127
-
128
- if (days !== '0') {
129
- uptime = days + ' ' + pluralize(days, 'day');
130
- }
131
-
132
- if (hours !== '0') {
133
- uptime = maybeInsertWordConnector(uptime, ', ') + hours + ' ' + pluralize(hours, 'hour');
52
+
53
+ $('#' + probe + ' .stat').text(probeReading);
134
54
  }
135
-
136
- if (minutes !== '0') {
137
- uptime = maybeInsertWordConnector(uptime, ', ') + minutes + ' ' + pluralize(minutes, 'minute');
138
- }
139
-
140
- if (seconds !== '0') {
141
- uptime = maybeInsertWordConnector(uptime, ' and ') + seconds + ' ' + pluralize(seconds, 'second');
55
+ }
56
+
57
+ function updateCharts(chartStats) {
58
+ for (var probe in chartStats) {
59
+ if (chartTimeSeries[probe] === undefined) {
60
+ chartTimeSeries[probe] = new TimeSeries();
61
+ }
62
+ if (charts[probe] === undefined) {
63
+ chartOptions = {
64
+ millisPerPixel: 100,
65
+ maxValue: 100,
66
+ minValue: 0,
67
+ grid:{ millisPerLine: 10000 },
68
+ timestampFormatter:SmoothieChart.timeFormatter
69
+ }
70
+
71
+ charts[probe] = new SmoothieChart(chartOptions);
72
+
73
+ charts[probe].addTimeSeries(chartTimeSeries[probe], { strokeStyle: stats.colors[probe], fillStyle: 'rgba(0, 255, 0, 0.2)', lineWidth: 2 });
74
+ charts[probe].streamTo(document.getElementById(probe + '_chart'), 10000);
75
+ }
76
+ chartTimeSeries[probe].append(Date.parse(chartStats[probe].date), chartStats[probe].value);
142
77
  }
143
- return uptime;
144
78
  }
145
-
146
- ws = new WebSocket('ws://' + window.location.host + window.location.pathname);
79
+
80
+ var chartTimeSeries = [],
81
+ charts = [],
82
+ ws = new WebSocket('ws://' + window.location.host + '/stats'),
83
+ stats;
84
+
147
85
  ws.onclose = function() { alert('Connection to Pimon server lost...'); };
148
- ws.onmessage = function(m) {
149
- var o = $.parseJSON(m.data);
150
- drawChart(o);
151
- changeFavicon(o);
152
- $('#uptime .up').text(formatUptime(o.uptime.slice(-1)[0]));
86
+
87
+ ws.onmessage = function(message) {
88
+ stats = $.parseJSON(message.data);
89
+
90
+ updateSingleStats(stats.single);
91
+ updateCharts(stats.charts);
92
+ changeFavicon(stats.charts);
153
93
  };
154
94
  });
@@ -0,0 +1,427 @@
1
+ /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2
+
3
+ /**
4
+ * 1. Set default font family to sans-serif.
5
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
6
+ * user zoom.
7
+ */
8
+
9
+ html {
10
+ font-family: sans-serif; /* 1 */
11
+ -ms-text-size-adjust: 100%; /* 2 */
12
+ -webkit-text-size-adjust: 100%; /* 2 */
13
+ }
14
+
15
+ /**
16
+ * Remove default margin.
17
+ */
18
+
19
+ body {
20
+ margin: 0;
21
+ }
22
+
23
+ /* HTML5 display definitions
24
+ ========================================================================== */
25
+
26
+ /**
27
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
28
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
29
+ * and Firefox.
30
+ * Correct `block` display not defined for `main` in IE 11.
31
+ */
32
+
33
+ article,
34
+ aside,
35
+ details,
36
+ figcaption,
37
+ figure,
38
+ footer,
39
+ header,
40
+ hgroup,
41
+ main,
42
+ menu,
43
+ nav,
44
+ section,
45
+ summary {
46
+ display: block;
47
+ }
48
+
49
+ /**
50
+ * 1. Correct `inline-block` display not defined in IE 8/9.
51
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52
+ */
53
+
54
+ audio,
55
+ canvas,
56
+ progress,
57
+ video {
58
+ display: inline-block; /* 1 */
59
+ vertical-align: baseline; /* 2 */
60
+ }
61
+
62
+ /**
63
+ * Prevent modern browsers from displaying `audio` without controls.
64
+ * Remove excess height in iOS 5 devices.
65
+ */
66
+
67
+ audio:not([controls]) {
68
+ display: none;
69
+ height: 0;
70
+ }
71
+
72
+ /**
73
+ * Address `[hidden]` styling not present in IE 8/9/10.
74
+ * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75
+ */
76
+
77
+ [hidden],
78
+ template {
79
+ display: none;
80
+ }
81
+
82
+ /* Links
83
+ ========================================================================== */
84
+
85
+ /**
86
+ * Remove the gray background color from active links in IE 10.
87
+ */
88
+
89
+ a {
90
+ background-color: transparent;
91
+ }
92
+
93
+ /**
94
+ * Improve readability when focused and also mouse hovered in all browsers.
95
+ */
96
+
97
+ a:active,
98
+ a:hover {
99
+ outline: 0;
100
+ }
101
+
102
+ /* Text-level semantics
103
+ ========================================================================== */
104
+
105
+ /**
106
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107
+ */
108
+
109
+ abbr[title] {
110
+ border-bottom: 1px dotted;
111
+ }
112
+
113
+ /**
114
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115
+ */
116
+
117
+ b,
118
+ strong {
119
+ font-weight: bold;
120
+ }
121
+
122
+ /**
123
+ * Address styling not present in Safari and Chrome.
124
+ */
125
+
126
+ dfn {
127
+ font-style: italic;
128
+ }
129
+
130
+ /**
131
+ * Address variable `h1` font-size and margin within `section` and `article`
132
+ * contexts in Firefox 4+, Safari, and Chrome.
133
+ */
134
+
135
+ h1 {
136
+ font-size: 2em;
137
+ margin: 0.67em 0;
138
+ }
139
+
140
+ /**
141
+ * Address styling not present in IE 8/9.
142
+ */
143
+
144
+ mark {
145
+ background: #ff0;
146
+ color: #000;
147
+ }
148
+
149
+ /**
150
+ * Address inconsistent and variable font size in all browsers.
151
+ */
152
+
153
+ small {
154
+ font-size: 80%;
155
+ }
156
+
157
+ /**
158
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159
+ */
160
+
161
+ sub,
162
+ sup {
163
+ font-size: 75%;
164
+ line-height: 0;
165
+ position: relative;
166
+ vertical-align: baseline;
167
+ }
168
+
169
+ sup {
170
+ top: -0.5em;
171
+ }
172
+
173
+ sub {
174
+ bottom: -0.25em;
175
+ }
176
+
177
+ /* Embedded content
178
+ ========================================================================== */
179
+
180
+ /**
181
+ * Remove border when inside `a` element in IE 8/9/10.
182
+ */
183
+
184
+ img {
185
+ border: 0;
186
+ }
187
+
188
+ /**
189
+ * Correct overflow not hidden in IE 9/10/11.
190
+ */
191
+
192
+ svg:not(:root) {
193
+ overflow: hidden;
194
+ }
195
+
196
+ /* Grouping content
197
+ ========================================================================== */
198
+
199
+ /**
200
+ * Address margin not present in IE 8/9 and Safari.
201
+ */
202
+
203
+ figure {
204
+ margin: 1em 40px;
205
+ }
206
+
207
+ /**
208
+ * Address differences between Firefox and other browsers.
209
+ */
210
+
211
+ hr {
212
+ -moz-box-sizing: content-box;
213
+ box-sizing: content-box;
214
+ height: 0;
215
+ }
216
+
217
+ /**
218
+ * Contain overflow in all browsers.
219
+ */
220
+
221
+ pre {
222
+ overflow: auto;
223
+ }
224
+
225
+ /**
226
+ * Address odd `em`-unit font size rendering in all browsers.
227
+ */
228
+
229
+ code,
230
+ kbd,
231
+ pre,
232
+ samp {
233
+ font-family: monospace, monospace;
234
+ font-size: 1em;
235
+ }
236
+
237
+ /* Forms
238
+ ========================================================================== */
239
+
240
+ /**
241
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
242
+ * styling of `select`, unless a `border` property is set.
243
+ */
244
+
245
+ /**
246
+ * 1. Correct color not being inherited.
247
+ * Known issue: affects color of disabled elements.
248
+ * 2. Correct font properties not being inherited.
249
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
250
+ */
251
+
252
+ button,
253
+ input,
254
+ optgroup,
255
+ select,
256
+ textarea {
257
+ color: inherit; /* 1 */
258
+ font: inherit; /* 2 */
259
+ margin: 0; /* 3 */
260
+ }
261
+
262
+ /**
263
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
264
+ */
265
+
266
+ button {
267
+ overflow: visible;
268
+ }
269
+
270
+ /**
271
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
272
+ * All other form control elements do not inherit `text-transform` values.
273
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
274
+ * Correct `select` style inheritance in Firefox.
275
+ */
276
+
277
+ button,
278
+ select {
279
+ text-transform: none;
280
+ }
281
+
282
+ /**
283
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
284
+ * and `video` controls.
285
+ * 2. Correct inability to style clickable `input` types in iOS.
286
+ * 3. Improve usability and consistency of cursor style between image-type
287
+ * `input` and others.
288
+ */
289
+
290
+ button,
291
+ html input[type="button"], /* 1 */
292
+ input[type="reset"],
293
+ input[type="submit"] {
294
+ -webkit-appearance: button; /* 2 */
295
+ cursor: pointer; /* 3 */
296
+ }
297
+
298
+ /**
299
+ * Re-set default cursor for disabled elements.
300
+ */
301
+
302
+ button[disabled],
303
+ html input[disabled] {
304
+ cursor: default;
305
+ }
306
+
307
+ /**
308
+ * Remove inner padding and border in Firefox 4+.
309
+ */
310
+
311
+ button::-moz-focus-inner,
312
+ input::-moz-focus-inner {
313
+ border: 0;
314
+ padding: 0;
315
+ }
316
+
317
+ /**
318
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
319
+ * the UA stylesheet.
320
+ */
321
+
322
+ input {
323
+ line-height: normal;
324
+ }
325
+
326
+ /**
327
+ * It's recommended that you don't attempt to style these elements.
328
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
329
+ *
330
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
331
+ * 2. Remove excess padding in IE 8/9/10.
332
+ */
333
+
334
+ input[type="checkbox"],
335
+ input[type="radio"] {
336
+ box-sizing: border-box; /* 1 */
337
+ padding: 0; /* 2 */
338
+ }
339
+
340
+ /**
341
+ * Fix the cursor style for Chrome's increment/decrement buttons. For certain
342
+ * `font-size` values of the `input`, it causes the cursor style of the
343
+ * decrement button to change from `default` to `text`.
344
+ */
345
+
346
+ input[type="number"]::-webkit-inner-spin-button,
347
+ input[type="number"]::-webkit-outer-spin-button {
348
+ height: auto;
349
+ }
350
+
351
+ /**
352
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
353
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
354
+ * (include `-moz` to future-proof).
355
+ */
356
+
357
+ input[type="search"] {
358
+ -webkit-appearance: textfield; /* 1 */
359
+ -moz-box-sizing: content-box;
360
+ -webkit-box-sizing: content-box; /* 2 */
361
+ box-sizing: content-box;
362
+ }
363
+
364
+ /**
365
+ * Remove inner padding and search cancel button in Safari and Chrome on OS X.
366
+ * Safari (but not Chrome) clips the cancel button when the search input has
367
+ * padding (and `textfield` appearance).
368
+ */
369
+
370
+ input[type="search"]::-webkit-search-cancel-button,
371
+ input[type="search"]::-webkit-search-decoration {
372
+ -webkit-appearance: none;
373
+ }
374
+
375
+ /**
376
+ * Define consistent border, margin, and padding.
377
+ */
378
+
379
+ fieldset {
380
+ border: 1px solid #c0c0c0;
381
+ margin: 0 2px;
382
+ padding: 0.35em 0.625em 0.75em;
383
+ }
384
+
385
+ /**
386
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
387
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
388
+ */
389
+
390
+ legend {
391
+ border: 0; /* 1 */
392
+ padding: 0; /* 2 */
393
+ }
394
+
395
+ /**
396
+ * Remove default vertical scrollbar in IE 8/9/10/11.
397
+ */
398
+
399
+ textarea {
400
+ overflow: auto;
401
+ }
402
+
403
+ /**
404
+ * Don't inherit the `font-weight` (applied by a rule above).
405
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
406
+ */
407
+
408
+ optgroup {
409
+ font-weight: bold;
410
+ }
411
+
412
+ /* Tables
413
+ ========================================================================== */
414
+
415
+ /**
416
+ * Remove most spacing between table cells.
417
+ */
418
+
419
+ table {
420
+ border-collapse: collapse;
421
+ border-spacing: 0;
422
+ }
423
+
424
+ td,
425
+ th {
426
+ padding: 0;
427
+ }