visage-app 0.1.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 (40) hide show
  1. data/.gitignore +9 -0
  2. data/README.md +138 -0
  3. data/Rakefile +33 -0
  4. data/VERSION +1 -0
  5. data/bin/visage +17 -0
  6. data/config.ru +7 -0
  7. data/features/json.feature +66 -0
  8. data/features/site.feature +9 -0
  9. data/features/step_definitions/form_steps.rb +6 -0
  10. data/features/step_definitions/json_steps.rb +79 -0
  11. data/features/step_definitions/result_steps.rb +19 -0
  12. data/features/step_definitions/site_steps.rb +4 -0
  13. data/features/step_definitions/visage_steps.rb +20 -0
  14. data/features/step_definitions/webrat_steps.rb +42 -0
  15. data/features/support/env.rb +36 -0
  16. data/features/visage.feature +11 -0
  17. data/lib/visage/collectd/json.rb +142 -0
  18. data/lib/visage/collectd/profile.rb +36 -0
  19. data/lib/visage/config/fallback-colors.yaml +82 -0
  20. data/lib/visage/config/init.rb +33 -0
  21. data/lib/visage/config/plugin-colors.yaml +63 -0
  22. data/lib/visage/config/profiles.yaml +35 -0
  23. data/lib/visage/config/profiles.yaml.sample +33 -0
  24. data/lib/visage/config.rb +51 -0
  25. data/lib/visage/patches.rb +18 -0
  26. data/lib/visage/public/favicon.gif +0 -0
  27. data/lib/visage/public/javascripts/application.js +4 -0
  28. data/lib/visage/public/javascripts/g.line.js +217 -0
  29. data/lib/visage/public/javascripts/g.raphael.js +7 -0
  30. data/lib/visage/public/javascripts/graph.js +510 -0
  31. data/lib/visage/public/javascripts/mootools-1.2.3-core.js +4036 -0
  32. data/lib/visage/public/javascripts/mootools-1.2.3.1-more.js +104 -0
  33. data/lib/visage/public/javascripts/raphael-min.js +7 -0
  34. data/lib/visage/public/javascripts/raphael.js +3215 -0
  35. data/lib/visage/public/stylesheets/screen.css +96 -0
  36. data/lib/visage/views/index.haml +48 -0
  37. data/lib/visage/views/layout.haml +22 -0
  38. data/lib/visage/views/single.haml +43 -0
  39. data/lib/visage-app.rb +81 -0
  40. metadata +142 -0
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+ require 'ostruct'
5
+
6
+ class CollectdProfile
7
+
8
+ def initialize(opts={})
9
+ @profile = opts[:profile]
10
+ end
11
+
12
+ class << self
13
+
14
+ attr_accessor :profiles
15
+
16
+ def get(id)
17
+ id.gsub!(/\s+/, '+')
18
+ if found = @profiles.find {|p| p[1]["splat"] == id }
19
+ OpenStruct.new(found[1])
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ def all
26
+ # here be ugliness
27
+ profiles = @profiles.to_a.sort_by { |profile|
28
+ profile[1]["order"]
29
+ }.map { |profile|
30
+ OpenStruct.new(profile[1].merge({'name' => profile[0]}))
31
+ }
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,82 @@
1
+ ---
2
+ Aluminium 1:
3
+ color: "#eeeeec"
4
+ fallback_order: 20
5
+ Aluminium 2:
6
+ color: "#d3d7cf"
7
+ fallback_order: 20
8
+ Aluminium 3:
9
+ color: "#babdb6"
10
+ fallback_order: 15
11
+ Aluminium 4:
12
+ color: "#888a85"
13
+ fallback_order: 20
14
+ Aluminium 5:
15
+ color: "#555753"
16
+ fallback_order: 20
17
+ Aluminium 6:
18
+ color: "#2e3436"
19
+ fallback_order: 7
20
+ Butter 1:
21
+ color: "#fce94f"
22
+ fallback_order: 12
23
+ Butter 2:
24
+ color: "#edd400"
25
+ fallback_order: 4
26
+ Butter 3:
27
+ color: "#c4a000"
28
+ fallback_order: 20
29
+ Chameleon 1:
30
+ color: "#8ae234"
31
+ fallback_order: 11
32
+ Chameleon 2:
33
+ color: "#73d216"
34
+ fallback_order: 1
35
+ Chameleon 3:
36
+ color: "#4e9a06"
37
+ fallback_order: 20
38
+ Chocolate 1:
39
+ color: "#e9b96e"
40
+ fallback_order: 14
41
+ Chocolate 2:
42
+ color: "#c17d11"
43
+ fallback_order: 5
44
+ Chocolate 3:
45
+ color: "#8f5902"
46
+ fallback_order: 20
47
+ Orange 1:
48
+ color: "#fcaf3e"
49
+ fallback_order: 13
50
+ Orange 2:
51
+ color: "#f57900"
52
+ fallback_order: 5
53
+ Orange 3:
54
+ color: "#ce5c00"
55
+ fallback_order: 20
56
+ Plum 1:
57
+ color: "#ad7fa8"
58
+ fallback_order: 9
59
+ Plum 2:
60
+ color: "#5c3566"
61
+ fallback_order: 20
62
+ Plum 3:
63
+ color: "#5c3566"
64
+ fallback_order: 1
65
+ Scarlet Red 1:
66
+ color: "#ef2929"
67
+ fallback_order: 8
68
+ Scarlet Red 2:
69
+ color: "#cc0000"
70
+ fallback_order: 0
71
+ Scarlet Red 3:
72
+ color: "#a40000"
73
+ fallback_order: 20
74
+ Sky Blue 1:
75
+ color: "#729fcf"
76
+ fallback_order: 10
77
+ Sky Blue 2:
78
+ color: "#3465a4"
79
+ fallback_order: 2
80
+ Sky Blue 3:
81
+ color: "#204a87"
82
+ fallback_order: 20
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ __DIR__ = File.expand_path(File.dirname(__FILE__))
4
+ require File.join(__DIR__, '..', 'config')
5
+
6
+ Visage::Config.use do |c|
7
+ c['fallback_colors'] = YAML::load(File.read(File.join(__DIR__, 'fallback-colors.yaml')))
8
+
9
+ profile_filename = File.join(__DIR__, 'profiles.yaml')
10
+ unless File.exists?(profile_filename)
11
+ puts "You need to specify a list of profiles in config/profile.yaml!"
12
+ puts "Check out config/profiles.yaml.sample for an example."
13
+ exit 1
14
+ end
15
+ YAML::load(File.read(profile_filename)).each_pair do |key, value|
16
+ c[key] = value
17
+ end
18
+
19
+ plugin_colors_filename = File.join(__DIR__, 'plugin-colors.yaml')
20
+ unless File.exists?(plugin_colors_filename)
21
+ puts "It's highly recommended you specify graph line colors in config/plugin-colors.yaml!"
22
+ end
23
+ YAML::load(File.read(plugin_colors_filename)).each_pair do |key, value|
24
+ c[key] = value
25
+ end
26
+
27
+ # Location of collectd's RRD - you may want to edit this!
28
+ c['rrddir'] = "/var/lib/collectd/rrd"
29
+
30
+ # whether to shade in graphs
31
+ c['shade'] = false
32
+ end
33
+
@@ -0,0 +1,63 @@
1
+ ---
2
+ plugin_colors:
3
+ memory:
4
+ memory-used:
5
+ value: "#cc0000"
6
+ memory-buffered:
7
+ value: "#edd400"
8
+ memory-cached:
9
+ value: "#3465a4"
10
+ memory-free:
11
+ value: "#73d216"
12
+ cpu:
13
+ cpu-idle:
14
+ value: "#eeeeec"
15
+ cpu-wait:
16
+ value: "#edd400"
17
+ cpu-user:
18
+ value: "#3465a4"
19
+ cpu-system:
20
+ value: "#cc0000"
21
+ cpu-nice:
22
+ value: "#73d216"
23
+ cpu-softirq:
24
+ value: "#ad7fa8"
25
+ cpu-interrupt:
26
+ value: "#5c3566"
27
+ cpu-steal:
28
+ value: "#2e3436"
29
+ swap:
30
+ swap-used:
31
+ value: "#cc0000"
32
+ swap-free:
33
+ value: "#73d216"
34
+ swap-cached:
35
+ value: "#3465a4"
36
+ load:
37
+ load:
38
+ longterm: "#ef2929"
39
+ shortterm: "#73d216"
40
+ midterm: "#3465a4"
41
+ df:
42
+ df:
43
+ used: "#cc0000"
44
+ free: "#73d216"
45
+ disk:
46
+ disk_merged:
47
+ read: "#8ae234"
48
+ write: "#ef2929"
49
+ disk_time:
50
+ read: "#729fcf"
51
+ write: "#fcaf3e"
52
+ disk_ops:
53
+ read: "#ad7fa8"
54
+ write: "#fce94f"
55
+ disk_octets:
56
+ read: "#c17d11"
57
+ write: "#888a85"
58
+
59
+
60
+
61
+
62
+
63
+
@@ -0,0 +1,35 @@
1
+ ---
2
+ profiles:
3
+ CPU + Load:
4
+ plugins:
5
+ - cpu-0/cpu-user/cpu-system/cpu-idle/cpu-wait/cpu-interrupt
6
+ - cpu-1
7
+ - load/load
8
+ - battery-0
9
+ splat: cpu+load
10
+ order: 1
11
+ Memory:
12
+ plugins:
13
+ - memory
14
+ - swap
15
+ splat: memory
16
+ order: 2
17
+ Disk Usage:
18
+ plugins:
19
+ - df/df-root
20
+ - disk-sda
21
+ splat: disk+usage
22
+ order: 3
23
+ Networking:
24
+ plugins:
25
+ - tcpconns-9393-local
26
+ - tcpconns-80-local
27
+ - tcpconns-22-local
28
+ splat: network
29
+ order: 4
30
+ Processes:
31
+ plugins:
32
+ - processes
33
+ - processes-collectd
34
+ splat: processes
35
+ order: 5
@@ -0,0 +1,33 @@
1
+ ---
2
+ profiles:
3
+ cpu+load:
4
+ plugins:
5
+ - cpu-0
6
+ - cpu-1
7
+ - load/load
8
+ - battery-0
9
+ name: CPU + Load
10
+ order: 1
11
+ memory:
12
+ plugins:
13
+ - memory
14
+ - swap
15
+ name: Memory
16
+ order: 2
17
+ disk+usage:
18
+ plugins:
19
+ - df/df-root
20
+ - disk-sda
21
+ name: Disk Usage
22
+ order: 3
23
+ network:
24
+ plugins:
25
+ - tcpconns-9393-local
26
+ - tcpconns-80-local
27
+ name: Networking
28
+ order: 4
29
+ processes:
30
+ plugins:
31
+ - processes
32
+ name: Processes
33
+ order: 5
@@ -0,0 +1,51 @@
1
+ module Visage
2
+ class Config
3
+
4
+ class << self
5
+ def use
6
+ @configuration ||= {}
7
+ yield @configuration
8
+ nil
9
+ end
10
+
11
+ def method_missing(method, *args)
12
+ if method.to_s[-1,1] == '='
13
+ @configuration[method.to_s.tr('=','')] = *args
14
+ else
15
+ @configuration[method.to_s]
16
+ end
17
+ end
18
+
19
+ def to_hash
20
+ @configuration
21
+ end
22
+ end
23
+
24
+ class Profiles
25
+ class << self
26
+ require 'ostruct'
27
+
28
+ attr_accessor :profiles
29
+
30
+ def get(id)
31
+ id.gsub!(/\s+/, '+')
32
+ if found = @profiles.find {|p| p[1]["splat"] == id }
33
+ OpenStruct.new(found[1])
34
+ else
35
+ nil
36
+ end
37
+ end
38
+
39
+ def all
40
+ # here be ugliness
41
+ profiles = @profiles.to_a.sort_by { |profile|
42
+ profile[1]["order"]
43
+ }.map { |profile|
44
+ OpenStruct.new(profile[1].merge({'name' => profile[0]}))
45
+ }
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,18 @@
1
+ # extracted from Extlib.
2
+ # FIXME: what's the licensing here?
3
+ class String
4
+ def camel_case
5
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
6
+ split('_').map{|e| e.capitalize}.join
7
+ end
8
+
9
+ def blank?
10
+ strip.empty?
11
+ end
12
+ end
13
+
14
+ class NilClass
15
+ def blank?
16
+ true
17
+ end
18
+ end
Binary file
@@ -0,0 +1,4 @@
1
+ window.addEvent('domready', function () {
2
+
3
+ });
4
+
@@ -0,0 +1,217 @@
1
+ /*
2
+ * g.Raphael 0.4 - Charting library, based on Raphaël
3
+ *
4
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6
+ */
7
+ Raphael.fn.g.linechart = function (x, y, width, height, valuesx, valuesy, opts) {
8
+ function shrink(values, dim) {
9
+ var k = values.length / dim,
10
+ j = 0,
11
+ l = k,
12
+ sum = 0,
13
+ res = [];
14
+ while (j < values.length) {
15
+ l--;
16
+ if (l < 0) {
17
+ sum += values[j] * (1 + l);
18
+ res.push(sum / k);
19
+ sum = values[j++] * -l;
20
+ l += k;
21
+ } else {
22
+ sum += values[j++];
23
+ }
24
+ }
25
+ return res;
26
+ }
27
+ opts = opts || {};
28
+ if (!this.raphael.is(valuesx[0], "array")) {
29
+ valuesx = [valuesx];
30
+ }
31
+ if (!this.raphael.is(valuesy[0], "array")) {
32
+ valuesy = [valuesy];
33
+ }
34
+ var allx = Array.prototype.concat.apply([], valuesx),
35
+ ally = Array.prototype.concat.apply([], valuesy),
36
+ xdim = this.g.snapEnds(Math.min.apply(Math, allx), Math.max.apply(Math, allx), valuesx[0].length - 1),
37
+ minx = xdim.from,
38
+ maxx = xdim.to,
39
+ gutter = opts.gutter || 10,
40
+ kx = (width - gutter * 2) / (maxx - minx),
41
+ ydim = this.g.snapEnds(Math.min.apply(Math, ally), Math.max.apply(Math, ally), valuesy[0].length - 1),
42
+ miny = ydim.from,
43
+ maxy = ydim.to,
44
+ ky = (height - gutter * 2) / (maxy - miny),
45
+ len = Math.max(valuesx[0].length, valuesy[0].length),
46
+ symbol = opts.symbol || "",
47
+ colors = opts.colors || Raphael.fn.g.colors,
48
+ that = this,
49
+ columns = null,
50
+ dots = null,
51
+ chart = this.set(),
52
+ path = [];
53
+
54
+ for (var i = 0, ii = valuesy.length; i < ii; i++) {
55
+ len = Math.max(len, valuesy[i].length);
56
+ }
57
+ var shades = this.set();
58
+ for (var i = 0, ii = valuesy.length; i < ii; i++) {
59
+ if (opts.shade) {
60
+ shades.push(this.path().attr({stroke: "none", fill: colors[i], opacity: opts.nostroke ? 1 : .3}));
61
+ }
62
+ if (valuesy[i].length > width - 2 * gutter) {
63
+ valuesy[i] = shrink(valuesy[i], width - 2 * gutter);
64
+ len = width - 2 * gutter;
65
+ }
66
+ if (valuesx[i] && valuesx[i].length > width - 2 * gutter) {
67
+ valuesx[i] = shrink(valuesx[i], width - 2 * gutter);
68
+ }
69
+ }
70
+ var axis = this.set();
71
+ if (opts.axis) {
72
+ var ax = (opts.axis + "").split(/[,\s]+/);
73
+ +ax[0] && axis.push(this.g.axis(x + gutter, y + gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 2));
74
+ +ax[1] && axis.push(this.g.axis(x + width - gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 3));
75
+ +ax[2] && axis.push(this.g.axis(x + gutter, y + height - gutter, width - 2 * gutter, minx, maxx, opts.axisxstep || Math.floor((width - 2 * gutter) / 20), 0));
76
+ +ax[3] && axis.push(this.g.axis(x + gutter, y + height - gutter, height - 2 * gutter, miny, maxy, opts.axisystep || Math.floor((height - 2 * gutter) / 20), 1));
77
+ }
78
+ var lines = this.set(),
79
+ symbols = this.set(),
80
+ line;
81
+ for (var i = 0, ii = valuesy.length; i < ii; i++) {
82
+ if (!opts.nostroke) {
83
+ lines.push(line = this.path().attr({
84
+ stroke: colors[i],
85
+ "stroke-width": opts.width || 2,
86
+ "stroke-linejoin": "round",
87
+ "stroke-linecap": "round",
88
+ "stroke-dasharray": opts.dash || ""
89
+ }));
90
+ }
91
+ var sym = this.raphael.is(symbol, "array") ? symbol[i] : symbol,
92
+ symset = this.set();
93
+ path = [];
94
+ for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
95
+ var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx;
96
+ var Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
97
+ (Raphael.is(sym, "array") ? sym[j] : sym) && symset.push(this.g[Raphael.fn.g.markers[this.raphael.is(sym, "array") ? sym[j] : sym]](X, Y, (opts.width || 2) * 3).attr({fill: colors[i], stroke: "none"}));
98
+ path = path.concat([j ? "L" : "M", X, Y]);
99
+ }
100
+ symbols.push(symset);
101
+ if (opts.shade) {
102
+ shades[i].attr({path: path.concat(["L", X, y + height - gutter, "L", x + gutter + ((valuesx[i] || valuesx[0])[0] - minx) * kx, y + height - gutter, "z"]).join(",")});
103
+ }
104
+ !opts.nostroke && line.attr({path: path.join(",")});
105
+ }
106
+ function createColumns(f) {
107
+ // unite Xs together
108
+ var Xs = [];
109
+ for (var i = 0, ii = valuesx.length; i < ii; i++) {
110
+ Xs = Xs.concat(valuesx[i]);
111
+ }
112
+ Xs.sort();
113
+ // remove duplicates
114
+ var Xs2 = [],
115
+ xs = [];
116
+ for (var i = 0, ii = Xs.length; i < ii; i++) {
117
+ Xs[i] != Xs[i - 1] && Xs2.push(Xs[i]) && xs.push(x + gutter + (Xs[i] - minx) * kx);
118
+ }
119
+ Xs = Xs2;
120
+ ii = Xs.length;
121
+ var cvrs = f || that.set();
122
+ for (var i = 0; i < ii; i++) {
123
+ var X = xs[i] - (xs[i] - (xs[i - 1] || x)) / 2,
124
+ w = ((xs[i + 1] || x + width) - xs[i]) / 2 + (xs[i] - (xs[i - 1] || x)) / 2,
125
+ C;
126
+ f ? (C = {}) : cvrs.push(C = that.rect(X - 1, y, Math.max(w + 1, 1), height).attr({stroke: "none", fill: "#000", opacity: 0}));
127
+ C.values = [];
128
+ C.symbols = that.set();
129
+ C.y = [];
130
+ C.x = xs[i];
131
+ C.axis = Xs[i];
132
+ for (var j = 0, jj = valuesy.length; j < jj; j++) {
133
+ Xs2 = valuesx[j] || valuesx[0];
134
+ for (var k = 0, kk = Xs2.length; k < kk; k++) {
135
+ if (Xs2[k] == Xs[i]) {
136
+ C.values.push(valuesy[j][k]);
137
+ C.y.push(y + height - gutter - (valuesy[j][k] - miny) * ky);
138
+ C.symbols.push(chart.symbols[j][k]);
139
+ }
140
+ }
141
+ }
142
+ f && f.call(C);
143
+ }
144
+ !f && (columns = cvrs);
145
+ }
146
+ function createDots(f) {
147
+ var cvrs = f || that.set(),
148
+ C;
149
+ for (var i = 0, ii = valuesy.length; i < ii; i++) {
150
+ for (var j = 0, jj = valuesy[i].length; j < jj; j++) {
151
+ var X = x + gutter + ((valuesx[i] || valuesx[0])[j] - minx) * kx,
152
+ nearX = x + gutter + ((valuesx[i] || valuesx[0])[j ? j - 1 : 1] - minx) * kx,
153
+ Y = y + height - gutter - (valuesy[i][j] - miny) * ky;
154
+ f ? (C = {}) : cvrs.push(C = that.circle(X, Y, Math.abs(nearX - X) / 2).attr({stroke: "none", fill: "#000", opacity: 0}));
155
+ C.x = X;
156
+ C.y = Y;
157
+ C.value = valuesy[i][j];
158
+ C.line = chart.lines[i];
159
+ C.shade = chart.shades[i];
160
+ C.symbol = chart.symbols[i][j];
161
+ C.symbols = chart.symbols[i];
162
+ C.axis = (valuesx[i] || valuesx[0])[j];
163
+ f && f.call(C);
164
+ }
165
+ }
166
+ !f && (dots = cvrs);
167
+ }
168
+ chart.push(lines, shades, symbols, axis, columns, dots);
169
+ chart.lines = lines;
170
+ chart.shades = shades;
171
+ chart.symbols = symbols;
172
+ chart.axis = axis;
173
+ chart.hoverColumn = function (fin, fout) {
174
+ !columns && createColumns();
175
+ columns.mouseover(fin).mouseout(fout);
176
+ return this;
177
+ };
178
+ chart.clickColumn = function (f) {
179
+ !columns && createColumns();
180
+ columns.click(f);
181
+ return this;
182
+ };
183
+ chart.hrefColumn = function (cols) {
184
+ var hrefs = that.raphael.is(arguments[0], "array") ? arguments[0] : arguments;
185
+ if (!(arguments.length - 1) && typeof cols == "object") {
186
+ for (var x in cols) {
187
+ for (var i = 0, ii = columns.length; i < ii; i++) if (columns[i].axis == x) {
188
+ columns[i].attr("href", cols[x]);
189
+ }
190
+ }
191
+ }
192
+ !columns && createColumns();
193
+ for (var i = 0, ii = hrefs.length; i < ii; i++) {
194
+ columns[i] && columns[i].attr("href", hrefs[i]);
195
+ }
196
+ return this;
197
+ };
198
+ chart.hover = function (fin, fout) {
199
+ !dots && createDots();
200
+ dots.mouseover(fin).mouseout(fout);
201
+ return this;
202
+ };
203
+ chart.click = function (f) {
204
+ !dots && createDots();
205
+ dots.click(f);
206
+ return this;
207
+ };
208
+ chart.each = function (f) {
209
+ createDots(f);
210
+ return this;
211
+ };
212
+ chart.eachColumn = function (f) {
213
+ createColumns(f);
214
+ return this;
215
+ };
216
+ return chart;
217
+ };
@@ -0,0 +1,7 @@
1
+ /*
2
+ * g.Raphael 0.4 - Charting library, based on Raphaël
3
+ *
4
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6
+ */
7
+ (function(){Raphael.fn.g=Raphael.fn.g||{};Raphael.fn.g.markers={disc:"disc",o:"disc",flower:"flower",f:"flower",diamond:"diamond",d:"diamond",square:"square",s:"square",triangle:"triangle",t:"triangle",star:"star","*":"star",cross:"cross",x:"cross",plus:"plus","+":"plus",arrow:"arrow","->":"arrow"};Raphael.fn.g.shim={stroke:"none",fill:"#000","fill-opacity":0};Raphael.fn.g.txtattr={font:"12px Arial, sans-serif"};Raphael.fn.g.colors=[];var b=[0.6,0.2,0.05,0.1333,0.75,0];for(var a=0;a<10;a++){if(a<b.length){Raphael.fn.g.colors.push("hsb("+b[a]+", .75, .75)");}else{Raphael.fn.g.colors.push("hsb("+b[a-b.length]+", 1, .5)");}}Raphael.fn.g.text=function(c,f,e){return this.text(c,f,e).attr(this.g.txtattr);};Raphael.fn.g.labelise=function(c,f,e){if(c){return(c+"").replace(/(##+(?:\.#+)?)|(%%+(?:\.%+)?)/g,function(g,i,h){if(i){return(+f).toFixed(i.replace(/^#+\.?/g,"").length);}if(h){return(f*100/e).toFixed(h.replace(/^%+\.?/g,"").length)+"%";}});}else{return(+f).toFixed(0);}};Raphael.fn.g.finger=function(j,i,e,k,f,g,h){if((f&&!k)||(!f&&!e)){return h?"":this.path();}g={square:"square",sharp:"sharp",soft:"soft"}[g]||"round";var m;k=Math.round(k);e=Math.round(e);j=Math.round(j);i=Math.round(i);switch(g){case"round":if(!f){var c=Math.floor(k/2);if(e<c){c=e;m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",0,0,"a",c,Math.floor(k/2),0,0,1,0,k,"l",0,0,"z"];}else{m=["M",j+0.5,i+0.5-c,"l",e-c,0,"a",c,c,0,1,1,0,k,"l",c-e,0,"z"];}}else{var c=Math.floor(e/2);if(k<c){c=k;m=["M",j-Math.floor(e/2),i,"l",0,0,"a",Math.floor(e/2),c,0,0,1,e,0,"l",0,0,"z"];}else{m=["M",j-c,i,"l",0,c-k,"a",c,c,0,1,1,e,0,"l",0,k-c,"z"];}}break;case"sharp":if(!f){var l=Math.floor(k/2);m=["M",j,i+l,"l",0,-k,Math.max(e-l,0),0,Math.min(l,e),l,-Math.min(l,e),l+(l*2<k),"z"];}else{var l=Math.floor(e/2);m=["M",j+l,i,"l",-e,0,0,-Math.max(k-l,0),l,-Math.min(l,k),l,Math.min(l,k),l,"z"];}break;case"square":if(!f){m=["M",j,i+Math.floor(k/2),"l",0,-k,e,0,0,k,"z"];}else{m=["M",j+Math.floor(e/2),i,"l",1-e,0,0,-k,e-1,0,"z"];}break;case"soft":var c;if(!f){c=Math.min(e,Math.round(k/5));m=["M",j+0.5,i+0.5-Math.floor(k/2),"l",e-c,0,"a",c,c,0,0,1,c,c,"l",0,k-c*2,"a",c,c,0,0,1,-c,c,"l",c-e,0,"z"];}else{c=Math.min(Math.round(e/5),k);m=["M",j-Math.floor(e/2),i,"l",0,c-k,"a",c,c,0,0,1,c,-c,"l",e-2*c,0,"a",c,c,0,0,1,c,c,"l",0,k-c,"z"];}}if(h){return m.join(",");}else{return this.path(m);}};Raphael.fn.g.disc=function(c,f,e){return this.circle(c,f,e);};Raphael.fn.g.line=function(c,f,e){return this.rect(c-e,f-e/5,2*e,2*e/5);};Raphael.fn.g.square=function(c,f,e){e=e*0.7;return this.rect(c-e,f-e,2*e,2*e);};Raphael.fn.g.triangle=function(c,f,e){e*=1.75;return this.path("M".concat(c,",",f,"m0-",e*0.58,"l",e*0.5,",",e*0.87,"-",e,",0z"));};Raphael.fn.g.diamond=function(c,f,e){return this.path(["M",c,f-e,"l",e,e,-e,e,-e,-e,e,-e,"z"]);};Raphael.fn.g.flower=function(g,f,c,e){c=c*1.25;var l=c,k=l*0.5;e=+e<3||!e?5:e;var m=["M",g,f+k,"Q"],j;for(var h=1;h<e*2+1;h++){j=h%2?l:k;m=m.concat([+(g+j*Math.sin(h*Math.PI/e)).toFixed(3),+(f+j*Math.cos(h*Math.PI/e)).toFixed(3)]);}m.push("z");return this.path(m.join(","));};Raphael.fn.g.star=function(c,k,j,e){e=e||j*0.5;var h=["M",c,k+e,"L"],g;for(var f=1;f<10;f++){g=f%2?j:e;h=h.concat([(c+g*Math.sin(f*Math.PI*0.2)).toFixed(3),(k+g*Math.cos(f*Math.PI*0.2)).toFixed(3)]);}h.push("z");return this.path(h.join(","));};Raphael.fn.g.cross=function(c,f,e){e=e/2.5;return this.path("M".concat(c-e,",",f,"l",[-e,-e,e,-e,e,e,e,-e,e,e,-e,e,e,e,-e,e,-e,-e,-e,e,-e,-e,"z"]));};Raphael.fn.g.plus=function(c,f,e){e=e/2;return this.path("M".concat(c-e/2,",",f-e/2,"l",[0,-e,e,0,0,e,e,0,0,e,-e,0,0,e,-e,0,0,-e,-e,0,0,-e,"z"]));};Raphael.fn.g.arrow=function(c,f,e){return this.path("M".concat(c-e*0.7,",",f-e*0.4,"l",[e*0.6,0,0,-e*0.4,e,e*0.8,-e,e*0.8,0,-e*0.4,-e*0.6,0],"z"));};Raphael.fn.g.tag=function(c,k,j,i,g){i=i||0;g=g==null?5:g;j=j==null?"$9.99":j;var f=0.5522*g,e=this.set(),h=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,k,j).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){this.rotate(0,c,k);var m=this[1].getBBox();if(m.height>=g*2){this[0].attr({path:["M",c,k+g,"a",g,g,0,1,1,0,-g*2,g,g,0,1,1,0,g*2,"m",0,-g*2-h,"a",g+h,g+h,0,1,0,0,(g+h)*2,"L",c+g+h,k+m.height/2+h,"l",m.width+2*h,0,0,-m.height-2*h,-m.width-2*h,0,"L",c,k-g-h].join(",")});}else{var l=Math.sqrt(Math.pow(g+h,2)-Math.pow(m.height/2+h,2));this[0].attr({path:["M",c,k+g,"c",-f,0,-g,f-g,-g,-g,0,-f,g-f,-g,g,-g,f,0,g,g-f,g,g,0,f,f-g,g,-g,g,"M",c+l,k-m.height/2-h,"a",g+h,g+h,0,1,0,0,m.height+2*h,"l",g+h-l+m.width+2*h,0,0,-m.height-2*h,"L",c+l,k-m.height/2-h].join(",")});}this[1].attr({x:c+g+h+m.width/2,y:k});i=(360-i)%360;this.rotate(i,c,k);i>90&&i<270&&this[1].attr({x:c-g-h-m.width/2,y:k,rotation:[180+i,c,k]});return this;};e.update();return e;};Raphael.fn.g.popupit=function(j,i,k,e,q){e=e==null?2:e;q=q||5;j=Math.round(j)+0.5;i=Math.round(i)+0.5;var g=k.getBBox(),l=Math.round(g.width/2),f=Math.round(g.height/2),o=[0,l+q*2,0,-l-q*2],m=[-f*2-q*3,-f-q,0,-f-q],c=["M",j-o[e],i-m[e],"l",-q,(e==2)*-q,-Math.max(l-q,0),0,"a",q,q,0,0,1,-q,-q,"l",0,-Math.max(f-q,0),(e==3)*-q,-q,(e==3)*q,-q,0,-Math.max(f-q,0),"a",q,q,0,0,1,q,-q,"l",Math.max(l-q,0),0,q,!e*-q,q,!e*q,Math.max(l-q,0),0,"a",q,q,0,0,1,q,q,"l",0,Math.max(f-q,0),(e==1)*q,q,(e==1)*-q,q,0,Math.max(f-q,0),"a",q,q,0,0,1,-q,q,"l",-Math.max(l-q,0),0,"z"].join(","),n=[{x:j,y:i+q*2+f},{x:j-q*2-l,y:i},{x:j,y:i-q*2-f},{x:j+q*2+l,y:i}][e];k.translate(n.x-l-g.x,n.y-f-g.y);return this.path(c).attr({fill:"#000",stroke:"none"}).insertBefore(k.node?k:k[0]);};Raphael.fn.g.popup=function(c,j,i,e,g){e=e==null?2:e;g=g||5;i=i||"$9.99";var f=this.set(),h=3;f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(c,j,i).attr(this.g.txtattr).attr({fill:"#fff"}));f.update=function(m,l,n){m=m||c;l=l||j;var q=this[1].getBBox(),s=q.width/2,o=q.height/2,v=[0,s+g*2,0,-s-g*2],t=[-o*2-g*3,-o-g,0,-o-g],k=["M",m-v[e],l-t[e],"l",-g,(e==2)*-g,-Math.max(s-g,0),0,"a",g,g,0,0,1,-g,-g,"l",0,-Math.max(o-g,0),(e==3)*-g,-g,(e==3)*g,-g,0,-Math.max(o-g,0),"a",g,g,0,0,1,g,-g,"l",Math.max(s-g,0),0,g,!e*-g,g,!e*g,Math.max(s-g,0),0,"a",g,g,0,0,1,g,g,"l",0,Math.max(o-g,0),(e==1)*g,g,(e==1)*-g,g,0,Math.max(o-g,0),"a",g,g,0,0,1,-g,g,"l",-Math.max(s-g,0),0,"z"].join(","),u=[{x:m,y:l+g*2+o},{x:m-g*2-s,y:l},{x:m,y:l-g*2-o},{x:m+g*2+s,y:l}][e];if(n){this[0].animate({path:k},500,">");this[1].animate(u,500,">");}else{this[0].attr({path:k});this[1].attr(u);}return this;};return f.update(c,j);};Raphael.fn.g.flag=function(c,i,h,g){g=g||0;h=h||"$9.99";var e=this.set(),f=3;e.push(this.path().attr({fill:"#000",stroke:"none"}));e.push(this.text(c,i,h).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(j,m){this.rotate(0,j,m);var l=this[1].getBBox(),k=l.height/2;this[0].attr({path:["M",j,m,"l",k+f,-k-f,l.width+2*f,0,0,l.height+2*f,-l.width-2*f,0,"z"].join(",")});this[1].attr({x:j+k+f+l.width/2,y:m});g=360-g;this.rotate(g,j,m);g>90&&g<270&&this[1].attr({x:j-r-f-l.width/2,y:m,rotation:[180+g,j,m]});return this;};return e.update(c,i);};Raphael.fn.g.label=function(c,g,f){var e=this.set();e.push(this.rect(c,g,10,10).attr({stroke:"none",fill:"#000"}));e.push(this.text(c,g,f).attr(this.g.txtattr).attr({fill:"#fff"}));e.update=function(){var i=this[1].getBBox(),h=Math.min(i.width+10,i.height+10)/2;this[0].attr({x:i.x-h/2,y:i.y-h/2,width:i.width+h,height:i.height+h,r:h});};e.update();return e;};Raphael.fn.g.labelit=function(f){var e=f.getBBox(),c=Math.min(20,e.width+10,e.height+10)/2;return this.rect(e.x-c/2,e.y-c/2,e.width+c,e.height+c,c).attr({stroke:"none",fill:"#000"}).insertBefore(f[0]);};Raphael.fn.g.drop=function(c,i,h,f,g){f=f||30;g=g||0;var e=this.set();e.push(this.path(["M",c,i,"l",f,0,"A",f*0.4,f*0.4,0,1,0,c+f*0.7,i-f*0.7,"z"]).attr({fill:"#000",stroke:"none",rotation:[22.5-g,c,i]}));g=(g+90)*Math.PI/180;e.push(this.text(c+f*Math.sin(g),i+f*Math.cos(g),h).attr(this.g.txtattr).attr({"font-size":f*12/30,fill:"#fff"}));e.drop=e[0];e.text=e[1];return e;};Raphael.fn.g.blob=function(e,k,j,i,g){i=(+i+1?i:45)+90;g=g||12;var c=Math.PI/180,h=g*12/12;var f=this.set();f.push(this.path().attr({fill:"#000",stroke:"none"}));f.push(this.text(e+g*Math.sin((i)*c),k+g*Math.cos((i)*c)-h/2,j).attr(this.g.txtattr).attr({"font-size":h,fill:"#fff"}));f.update=function(q,p,v){q=q||e;p=p||k;var y=this[1].getBBox(),B=Math.max(y.width+h,g*25/12),x=Math.max(y.height+h,g*25/12),m=q+g*Math.sin((i-22.5)*c),z=p+g*Math.cos((i-22.5)*c),o=q+g*Math.sin((i+22.5)*c),A=p+g*Math.cos((i+22.5)*c),D=(o-m)/2,C=(A-z)/2,n=B/2,l=x/2,u=-Math.sqrt(Math.abs(n*n*l*l-n*n*C*C-l*l*D*D)/(n*n*C*C+l*l*D*D)),t=u*n*C/l+(o+m)/2,s=u*-l*D/n+(A+z)/2;if(v){this.animate({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")},500,">");}else{this.attr({x:t,y:s,path:["M",e,k,"L",o,A,"A",n,l,0,1,1,m,z,"z"].join(",")});}return this;};f.update(e,k);return f;};Raphael.fn.g.colorValue=function(g,f,e,c){return"hsb("+[Math.min((1-g/f)*0.4,1),e||0.75,c||0.75]+")";};Raphael.fn.g.snapEnds=function(l,m,k){var h=l,n=m;if(h==n){return{from:h,to:n,power:0};}function o(f){return Math.abs(f-0.5)<0.25?Math.floor(f)+0.5:Math.round(f);}var j=(n-h)/k,c=Math.floor(j),g=c,e=0;if(c){while(g){e--;g=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);}e++;}else{while(!c){e=e||1;c=Math.floor(j*Math.pow(10,e))/Math.pow(10,e);e++;}e&&e--;}var n=o(m*Math.pow(10,e))/Math.pow(10,e);if(n<m){n=o((m+0.5)*Math.pow(10,e))/Math.pow(10,e);}var h=o((l-(e>0?0:0.5))*Math.pow(10,e))/Math.pow(10,e);return{from:h,to:n,power:e};};Raphael.fn.g.axis=function(s,q,m,E,h,H,k,J,l,c){c=c==null?2:c;l=l||"t";H=H||10;var D=l=="|"||l==" "?["M",s+0.5,q,"l",0,0.001]:k==1||k==3?["M",s+0.5,q,"l",0,-m]:["M",s,q+0.5,"l",m,0],v=this.g.snapEnds(E,h,H),I=v.from,z=v.to,G=v.power,F=0,A=this.set();d=(z-I)/H;var p=I,o=G>0?G:0;u=m/H;if(+k==1||+k==3){var e=q,w=(k-1?1:-1)*(c+3+!!(k-1));while(e>=q-m){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),e+0.5,"l",c*2+1,0]));A.push(this.text(s+w,e,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));p+=d;e-=u;}if(Math.round(e+u-(q-m))){l!="-"&&l!=" "&&(D=D.concat(["M",s-(l=="+"||l=="|"?c:!(k-1)*c*2),q-m+0.5,"l",c*2+1,0]));A.push(this.text(s+w,q-m,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr).attr({"text-anchor":k-1?"start":"end"}));}}else{var g=s,p=I,o=G>0?G:0,w=(k?-1:1)*(c+9+!k),u=m/H,B=0,C=0;while(g<=s+m){l!="-"&&l!=" "&&(D=D.concat(["M",g+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(B=this.text(g,q+w,(J&&J[F++])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));var n=B.getBBox();if(C>=n.x-5){A.pop(A.length-1).remove();}else{C=n.x+n.width;}p+=d;g+=u;}if(Math.round(g-u-s-m)){l!="-"&&l!=" "&&(D=D.concat(["M",s+m+0.5,q-(l=="+"?c:!!k*c*2),"l",0,c*2+1]));A.push(this.text(s+m,q+w,(J&&J[F])||(Math.round(p)==p?p:+p.toFixed(o))).attr(this.g.txtattr));}}var K=this.path(D);K.text=A;K.all=this.set([K,A]);K.remove=function(){this.text.remove();this.constructor.prototype.remove.call(this);};return K;};Raphael.el.lighter=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].b=Math.min(c[0].b*e,1);c[0].s=c[0].s/e;c[1].b=Math.min(c[1].b*e,1);c[1].s=c[1].s/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.darker=function(e){e=e||2;var c=[this.attrs.fill,this.attrs.stroke];this.fs=this.fs||[c[0],c[1]];c[0]=Raphael.rgb2hsb(Raphael.getRGB(c[0]).hex);c[1]=Raphael.rgb2hsb(Raphael.getRGB(c[1]).hex);c[0].s=Math.min(c[0].s*e,1);c[0].b=c[0].b/e;c[1].s=Math.min(c[1].s*e,1);c[1].b=c[1].b/e;this.attr({fill:"hsb("+[c[0].h,c[0].s,c[0].b]+")",stroke:"hsb("+[c[1].h,c[1].s,c[1].b]+")"});};Raphael.el.original=function(){if(this.fs){this.attr({fill:this.fs[0],stroke:this.fs[1]});delete this.fs;}};})();