bandido 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README.rdoc +77 -0
- data/Rakefile +34 -0
- data/bandit.gemspec +22 -0
- data/lib/bandit/config.rb +33 -0
- data/lib/bandit/date_hour.rb +82 -0
- data/lib/bandit/exceptions.rb +10 -0
- data/lib/bandit/experiment.rb +63 -0
- data/lib/bandit/extensions/array.rb +3 -0
- data/lib/bandit/extensions/controller_concerns.rb +33 -0
- data/lib/bandit/extensions/string.rb +5 -0
- data/lib/bandit/extensions/time.rb +5 -0
- data/lib/bandit/extensions/view_concerns.rb +40 -0
- data/lib/bandit/memoizable.rb +32 -0
- data/lib/bandit/players/base.rb +37 -0
- data/lib/bandit/players/epsilon_greedy.rb +32 -0
- data/lib/bandit/players/round_robin.rb +7 -0
- data/lib/bandit/storage/base.rb +134 -0
- data/lib/bandit/storage/memcache.rb +44 -0
- data/lib/bandit/storage/memory.rb +31 -0
- data/lib/bandit/storage/redis.rb +47 -0
- data/lib/bandit/version.rb +3 -0
- data/lib/bandit.rb +69 -0
- data/lib/generators/bandit/USAGE +3 -0
- data/lib/generators/bandit/dashboard_generator.rb +31 -0
- data/lib/generators/bandit/install_generator.rb +22 -0
- data/lib/generators/bandit/templates/bandit.rake +20 -0
- data/lib/generators/bandit/templates/bandit.rb +18 -0
- data/lib/generators/bandit/templates/bandit.yml +16 -0
- data/lib/generators/bandit/templates/bandit_controller.rb +30 -0
- data/lib/generators/bandit/templates/dashboard/bandit.html.erb +43 -0
- data/lib/generators/bandit/templates/dashboard/css/application.css +7 -0
- data/lib/generators/bandit/templates/dashboard/css/base.css +28 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/buttons.css +101 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/forms.css +89 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/modules.css +30 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/reset.css +42 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/structure.css +124 -0
- data/lib/generators/bandit/templates/dashboard/css/toupee/typography.css +103 -0
- data/lib/generators/bandit/templates/dashboard/helpers/bandit_helper.rb +23 -0
- data/lib/generators/bandit/templates/dashboard/js/bandit.js +51 -0
- data/lib/generators/bandit/templates/dashboard/js/highstock.js +215 -0
- data/lib/generators/bandit/templates/dashboard/js/jquery.min.js +154 -0
- data/lib/generators/bandit/templates/dashboard/view/_experiment_table.html.erb +19 -0
- data/lib/generators/bandit/templates/dashboard/view/index.html.erb +14 -0
- data/lib/generators/bandit/templates/dashboard/view/show.html.erb +19 -0
- data/players.rdoc +21 -0
- data/test/config.yml +7 -0
- data/test/helper.rb +18 -0
- data/test/memcache_storage_test.rb +17 -0
- data/test/memory_storage_test.rb +16 -0
- data/test/redis_storage_test.rb +17 -0
- data/test/storage_test_base.rb +54 -0
- data/whybandit.rdoc +31 -0
- metadata +166 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
/* --------------------------------------------------------------
|
2
|
+
RESET // Resets default browser CSS.
|
3
|
+
-------------------------------------------------------------- */
|
4
|
+
|
5
|
+
html, body, div, span, object, iframe,
|
6
|
+
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
7
|
+
a, abbr, acronym, address, code,
|
8
|
+
del, dfn, em, img, q, dl, dt, dd, ol, ul, li,
|
9
|
+
fieldset, form, label, legend,
|
10
|
+
table, caption, tbody, tfoot, thead, tr, th, td,
|
11
|
+
article, aside, dialog, figure, footer, header,
|
12
|
+
hgroup, nav, section {
|
13
|
+
margin: 0;
|
14
|
+
padding: 0;
|
15
|
+
border: 0;
|
16
|
+
font-weight: inherit;
|
17
|
+
font-style: inherit;
|
18
|
+
font-size: 100%;
|
19
|
+
font-family: inherit;
|
20
|
+
vertical-align: baseline;
|
21
|
+
}
|
22
|
+
|
23
|
+
article, aside, dialog, figure, footer, header,
|
24
|
+
hgroup, nav, section {
|
25
|
+
display:block;
|
26
|
+
}
|
27
|
+
|
28
|
+
body {
|
29
|
+
line-height: 1.5;
|
30
|
+
}
|
31
|
+
|
32
|
+
/* Tables still need 'cellspacing="0"' in the markup. */
|
33
|
+
table { border-collapse: separate; border-spacing: 0; }
|
34
|
+
caption, th, td { text-align: left; font-weight: normal; }
|
35
|
+
table, td, th { vertical-align: middle; }
|
36
|
+
|
37
|
+
/* Remove possible quote marks (") from <q>, <blockquote>. */
|
38
|
+
blockquote:before, blockquote:after, q:before, q:after { content: ""; }
|
39
|
+
blockquote, q { quotes: "" ""; }
|
40
|
+
|
41
|
+
/* Remove annoying border on linked images. */
|
42
|
+
a img { border: none; }
|
@@ -0,0 +1,124 @@
|
|
1
|
+
/* A container should group all your columns. */
|
2
|
+
.container { width: 950px; margin: 0 auto; }
|
3
|
+
|
4
|
+
/* Columns
|
5
|
+
-------------------------------------------------------------- */
|
6
|
+
/* Sets up basic grid floating and margin. */
|
7
|
+
.span-1, .span-2, .span-3, .span-4, .span-5, .span-6, .span-7, .span-8, .span-9, .span-10, .span-11, .span-12, .span-13, .span-14, .span-15, .span-16, .span-17, .span-18, .span-19, .span-20, .span-21, .span-22, .span-23, .span-24 {
|
8
|
+
float: left;
|
9
|
+
margin-right: 10px;
|
10
|
+
}
|
11
|
+
|
12
|
+
/* The last column in a row needs this class. */
|
13
|
+
.last { margin-right: 0; }
|
14
|
+
|
15
|
+
/* Use these classes to set the width of a column. */
|
16
|
+
.span-1 {width: 30px;}
|
17
|
+
.span-2 {width: 70px;}
|
18
|
+
.span-3 {width: 110px;}
|
19
|
+
.span-4 {width: 150px;}
|
20
|
+
.span-5 {width: 190px;}
|
21
|
+
.span-6 {width: 230px;}
|
22
|
+
.span-7 {width: 270px;}
|
23
|
+
.span-8 {width: 310px;}
|
24
|
+
.span-9 {width: 350px;}
|
25
|
+
.span-10 {width: 390px;}
|
26
|
+
.span-11 {width: 430px;}
|
27
|
+
.span-12 {width: 470px;}
|
28
|
+
.span-13 {width: 510px;}
|
29
|
+
.span-14 {width: 550px;}
|
30
|
+
.span-15 {width: 590px;}
|
31
|
+
.span-16 {width: 630px;}
|
32
|
+
.span-17 {width: 670px;}
|
33
|
+
.span-18 {width: 710px;}
|
34
|
+
.span-19 {width: 750px;}
|
35
|
+
.span-20 {width: 790px;}
|
36
|
+
.span-21 {width: 830px;}
|
37
|
+
.span-22 {width: 870px;}
|
38
|
+
.span-23 {width: 910px;}
|
39
|
+
.span-24 {width:950px; margin-right:0;}
|
40
|
+
|
41
|
+
/* Add these to a column to append empty cols. */
|
42
|
+
.append-1 { padding-right: 40px;}
|
43
|
+
.append-2 { padding-right: 80px;}
|
44
|
+
.append-3 { padding-right: 120px;}
|
45
|
+
.append-4 { padding-right: 160px;}
|
46
|
+
.append-5 { padding-right: 200px;}
|
47
|
+
.append-6 { padding-right: 240px;}
|
48
|
+
.append-7 { padding-right: 280px;}
|
49
|
+
.append-8 { padding-right: 320px;}
|
50
|
+
.append-9 { padding-right: 360px;}
|
51
|
+
.append-10 { padding-right: 400px;}
|
52
|
+
.append-11 { padding-right: 440px;}
|
53
|
+
.append-12 { padding-right: 480px;}
|
54
|
+
.append-13 { padding-right: 520px;}
|
55
|
+
.append-14 { padding-right: 560px;}
|
56
|
+
.append-15 { padding-right: 600px;}
|
57
|
+
.append-16 { padding-right: 640px;}
|
58
|
+
.append-17 { padding-right: 680px;}
|
59
|
+
.append-18 { padding-right: 720px;}
|
60
|
+
.append-19 { padding-right: 760px;}
|
61
|
+
.append-20 { padding-right: 800px;}
|
62
|
+
.append-21 { padding-right: 840px;}
|
63
|
+
.append-22 { padding-right: 880px;}
|
64
|
+
.append-23 { padding-right: 920px;}
|
65
|
+
|
66
|
+
/* Add these to a column to prepend empty cols. */
|
67
|
+
.prepend-1 { padding-left: 40px;}
|
68
|
+
.prepend-2 { padding-left: 80px;}
|
69
|
+
.prepend-3 { padding-left: 120px;}
|
70
|
+
.prepend-4 { padding-left: 160px;}
|
71
|
+
.prepend-5 { padding-left: 200px;}
|
72
|
+
.prepend-6 { padding-left: 240px;}
|
73
|
+
.prepend-7 { padding-left: 280px;}
|
74
|
+
.prepend-8 { padding-left: 320px;}
|
75
|
+
.prepend-9 { padding-left: 360px;}
|
76
|
+
.prepend-10 { padding-left: 400px;}
|
77
|
+
.prepend-11 { padding-left: 440px;}
|
78
|
+
.prepend-12 { padding-left: 480px;}
|
79
|
+
.prepend-13 { padding-left: 520px;}
|
80
|
+
.prepend-14 { padding-left: 560px;}
|
81
|
+
.prepend-15 { padding-left: 600px;}
|
82
|
+
.prepend-16 { padding-left: 640px;}
|
83
|
+
.prepend-17 { padding-left: 680px;}
|
84
|
+
.prepend-18 { padding-left: 720px;}
|
85
|
+
.prepend-19 { padding-left: 760px;}
|
86
|
+
.prepend-20 { padding-left: 800px;}
|
87
|
+
.prepend-21 { padding-left: 840px;}
|
88
|
+
.prepend-22 { padding-left: 880px;}
|
89
|
+
.prepend-23 { padding-left: 920px;}
|
90
|
+
|
91
|
+
/* Border on right hand side of a column. */
|
92
|
+
.border { padding-right: 4px; margin-right: 5px; border-right: 1px solid #eee; }
|
93
|
+
|
94
|
+
/* Border with more whitespace, spans one column. */
|
95
|
+
.colborder { padding-right: 24px; margin-right: 25px; border-right: 1px solid #eee; }
|
96
|
+
|
97
|
+
/* Use this to create a horizontal ruler across a column. */
|
98
|
+
hr {
|
99
|
+
background: #ddd;
|
100
|
+
color: #ddd;
|
101
|
+
clear: both;
|
102
|
+
float: none;
|
103
|
+
width: 100%;
|
104
|
+
height: .1em;
|
105
|
+
margin: 0 0 1.45em;
|
106
|
+
border: none;
|
107
|
+
}
|
108
|
+
|
109
|
+
/* Clearing floats without extra markup
|
110
|
+
Based on How To Clear Floats Without Structural Markup by PiE
|
111
|
+
[http://www.positioniseverything.net/easyclearing.html] */
|
112
|
+
|
113
|
+
.clearfix:after, .container:after {
|
114
|
+
content: "\0020";
|
115
|
+
display: block;
|
116
|
+
height: 0;
|
117
|
+
clear: both;
|
118
|
+
visibility: hidden;
|
119
|
+
overflow:hidden;
|
120
|
+
}
|
121
|
+
.clearfix, .container {display: block;}
|
122
|
+
|
123
|
+
.clear { clear:both; }
|
124
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
/* --------------------------------------------------------------
|
2
|
+
|
3
|
+
typography.css
|
4
|
+
* Sets Up A Default Typography.
|
5
|
+
|
6
|
+
-------------------------------------------------------------- */
|
7
|
+
|
8
|
+
html { font-size:100.01%; -webkit-font-smoothing: antialiased; }
|
9
|
+
body {
|
10
|
+
font-size: 75%;
|
11
|
+
color: #222;
|
12
|
+
background: #fff;
|
13
|
+
font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
|
14
|
+
}
|
15
|
+
|
16
|
+
/* HEADINGS
|
17
|
+
========================= */
|
18
|
+
|
19
|
+
h1,h2,h3,h4,h5,h6 { font-weight: normal; color: #333; word-spacing:-1px; font-family: "Lucida Grande","Lucida Sans Unicode", Arial,Verdana,sans-serif; }
|
20
|
+
|
21
|
+
h1 { font-size: 2.5em; font-weight: bold; line-height: 1.2em; margin-bottom: 0.5em; }
|
22
|
+
h2 { font-size: 2em; margin-bottom: 0.75em; }
|
23
|
+
h3 { font-size: 1.5em; line-height: 1; margin-bottom: .5em; }
|
24
|
+
h4 { font-size: 1.2em; line-height: 1.25; margin-bottom: 1.25em; }
|
25
|
+
h5 { font-size: 1em; font-weight: bold; margin-bottom: 1.5em; }
|
26
|
+
h6 { font-size: 1em; font-weight: bold; }
|
27
|
+
|
28
|
+
|
29
|
+
/* TEXT ELEMENTS
|
30
|
+
========================= */
|
31
|
+
|
32
|
+
p { margin: 0 0 1em; }
|
33
|
+
|
34
|
+
a:focus,
|
35
|
+
a:hover { color: #000; }
|
36
|
+
a { color: #2e71b3; text-decoration: underline; outline-style: none; }
|
37
|
+
|
38
|
+
blockquote { margin: 1.5em; color: #666; font-style: italic; }
|
39
|
+
strong { font-weight: bold; }
|
40
|
+
em,dfn { font-style: italic; }
|
41
|
+
dfn { font-weight: bold; }
|
42
|
+
sup, sub { line-height: 0; }
|
43
|
+
|
44
|
+
abbr,
|
45
|
+
acronym { border-bottom: 1px dotted #666; }
|
46
|
+
address { margin: 0 0 1.5em; font-style: italic; }
|
47
|
+
del { color:#666; }
|
48
|
+
|
49
|
+
pre { margin: 1.5em 0; white-space: pre; }
|
50
|
+
pre,code,tt { font: 1em 'andale mono', 'lucida console', monospace; line-height: 1.5; }
|
51
|
+
|
52
|
+
|
53
|
+
/* LISTS
|
54
|
+
========================= */
|
55
|
+
|
56
|
+
li ul,
|
57
|
+
li ol { margin: 0; }
|
58
|
+
ul, ol { margin: 0 1.5em 1.5em 0; padding-left: 1.333em; }
|
59
|
+
|
60
|
+
ul { list-style:square outside none; }
|
61
|
+
ol { list-style-type: decimal; }
|
62
|
+
|
63
|
+
dl { margin: 0 0 1.5em 0; }
|
64
|
+
dl dt { font-weight: bold; }
|
65
|
+
dd { margin-left: 1.5em;}
|
66
|
+
|
67
|
+
|
68
|
+
/* TABLES
|
69
|
+
========================= */
|
70
|
+
|
71
|
+
table { width: 100%; background: #fff; }
|
72
|
+
table caption { margin: 0; padding: 8px 10px; text-align: left; border: 1px solid #000; border-bottom: none; background: #fff; }
|
73
|
+
table th, table td { margin: 0; padding: 8px 10px; text-align: center; border-bottom: 1px solid #e1e1e1; }
|
74
|
+
table th { font-size: 14px; font-weight: bold; }
|
75
|
+
table th.left { -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; }
|
76
|
+
table th.right { -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; }
|
77
|
+
table .name { text-align: left; }
|
78
|
+
table tr { background-color: #fff; }
|
79
|
+
table tr.last td { border-bottom: none; }
|
80
|
+
table tr.alt { background-color: #e5ecf9; }
|
81
|
+
table td a,
|
82
|
+
table td a:hover { font-weight: bold; border: none; }
|
83
|
+
|
84
|
+
|
85
|
+
/* Misc classes
|
86
|
+
-------------------------------------------------------------- */
|
87
|
+
.reset { margin: 0; padding:0; }
|
88
|
+
.right { float: right; }
|
89
|
+
.left { float: left; }
|
90
|
+
.reset { margin: 0; padding: 0; }
|
91
|
+
.small { font-size: 10px; }
|
92
|
+
.large { font-size: 16px; }
|
93
|
+
.hide { display: none; }
|
94
|
+
.quiet { color: #bbb; }
|
95
|
+
.loud { color: #000; font-weight: bold; }
|
96
|
+
.required { color: #ff0000; }
|
97
|
+
.highlight { background-color:#ff0; padding: 2px 6px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; }
|
98
|
+
.success { background-color:#060; color: #fff; padding: 2px 6px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px;}
|
99
|
+
.error { background-color:#fcc; border: 1px solid #f00; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px }
|
100
|
+
.pending { background-color:#ffc; border: 1px solid yellow; padding: 2px 6px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; }
|
101
|
+
.removed { background-color:#900; color: #fff; padding: 2px 6px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; }
|
102
|
+
|
103
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module BanditHelper
|
2
|
+
def storage_name
|
3
|
+
Bandit.config.storage.titleize
|
4
|
+
end
|
5
|
+
|
6
|
+
def round_percent(percent)
|
7
|
+
(percent * 100).round / 100.0
|
8
|
+
end
|
9
|
+
|
10
|
+
def player_name
|
11
|
+
Bandit.config.player.titleize
|
12
|
+
end
|
13
|
+
|
14
|
+
def storage_config
|
15
|
+
c = Bandit.config.storage_config.map { |k,v| "#{k}: #{v}" }.join(", ")
|
16
|
+
c.blank? ? "" : "(#{c})"
|
17
|
+
end
|
18
|
+
|
19
|
+
def player_config
|
20
|
+
c = Bandit.config.player_config.map { |k,v| "#{k}: #{v}" }.join(", ")
|
21
|
+
c.blank? ? "" : "(#{c})"
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
function show_chart(title, url) {
|
2
|
+
$.get(url, function(data) { show_chart_data(title, data) });
|
3
|
+
}
|
4
|
+
|
5
|
+
function show_chart_data(title, data) {
|
6
|
+
var options = {
|
7
|
+
chart: { renderTo: 'totals_gcontainer' },
|
8
|
+
title: { text: title },
|
9
|
+
rangeSelector: { selected: 1 },
|
10
|
+
subtitle: { text: "participant / conversion totals" },
|
11
|
+
yAxis: { title: { text: "people" } },
|
12
|
+
series: []
|
13
|
+
};
|
14
|
+
|
15
|
+
var percent_options = {
|
16
|
+
chart: { renderTo: 'percents_gcontainer' },
|
17
|
+
title: { text: title },
|
18
|
+
rangeSelector: { selected: 1 },
|
19
|
+
subtitle: { text: "conversion percents" },
|
20
|
+
yAxis: { title: { text: "% converted" } },
|
21
|
+
series: []
|
22
|
+
};
|
23
|
+
|
24
|
+
var series_c = null;
|
25
|
+
var series_p = null;
|
26
|
+
var series_percent = null;
|
27
|
+
$.each(data.split('\n'), function(lineNo, line) {
|
28
|
+
var items = line.split("\t");
|
29
|
+
var ctitle = items[0] + " conversions";
|
30
|
+
var ptitle = items[0] + " participants";
|
31
|
+
var percent_title = items[0] + " conversion %";
|
32
|
+
if(series_c == null || series_c.name != ctitle) {
|
33
|
+
if(series_c != null) { options.series.push(series_p); options.series.push(series_c); percent_options.series.push(series_percent); }
|
34
|
+
series_c = { data: [], name: ctitle };
|
35
|
+
series_p = { data: [], name: ptitle };
|
36
|
+
series_percent = { data: [], name: percent_title, yDecimals: 2 };
|
37
|
+
}
|
38
|
+
var date = Date.UTC(parseInt(items[1]), parseInt(items[2]), parseInt(items[3]));
|
39
|
+
var participants = parseFloat(items[4]);
|
40
|
+
var conversions = parseFloat(items[5]);
|
41
|
+
var conversion_percent = Math.round((conversions / participants) * 100) / 100;
|
42
|
+
series_p.data.push([date, participants]);
|
43
|
+
series_c.data.push([date, conversions]);
|
44
|
+
series_percent.data.push([date, conversion_percent]);
|
45
|
+
});
|
46
|
+
options.series.push(series_p);
|
47
|
+
options.series.push(series_c);
|
48
|
+
percent_options.series.push(series_percent);
|
49
|
+
var chart = new Highcharts.StockChart(options);
|
50
|
+
var charttwo = new Highcharts.StockChart(percent_options);
|
51
|
+
}
|