quality_meter 0.0.2
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +34 -0
- data/app/assets/javascripts/quality_meter/jquery-v1.11.2.js +4 -0
- data/app/assets/javascripts/quality_meter/quality_meter.js +312 -0
- data/app/assets/stylesheets/quality_meter/quality_meter.css +229 -0
- data/app/controllers/quality_meter/report_controller.rb +35 -0
- data/app/views/quality_meter/report/index.html.erb +276 -0
- data/config/routes.rb +4 -0
- data/lib/quality_meter.rb +170 -0
- data/lib/quality_meter/engine.rb +5 -0
- data/lib/quality_meter/string.rb +7 -0
- data/lib/quality_meter/templates/summary_report.html.erb +248 -0
- data/lib/quality_meter/version.rb +3 -0
- data/lib/tasks/quality_meter_tasks.rake +97 -0
- metadata +128 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module QaulityMeter
|
4
|
+
class ReportController < ::ApplicationController
|
5
|
+
|
6
|
+
# GET::report#index
|
7
|
+
# localhost:3000/qmeter
|
8
|
+
def index
|
9
|
+
thresholds = {}
|
10
|
+
thresholds['security_warnings_min'] = 1
|
11
|
+
thresholds['security_warnings_max'] = 100
|
12
|
+
|
13
|
+
thresholds['rails_best_practices_min'] = 30
|
14
|
+
thresholds['rails_best_practices_max'] = 100
|
15
|
+
|
16
|
+
thresholds['flog_complexity_min'] = 3
|
17
|
+
thresholds['flog_complexity_max'] = 25
|
18
|
+
|
19
|
+
thresholds['stats_ratio_min'] = 0.0
|
20
|
+
thresholds['stats_ratio_max'] = 5.0
|
21
|
+
|
22
|
+
extend QaulityMeter
|
23
|
+
# Call methods from lib/qmeter.rb
|
24
|
+
self.initialize_thresholds(thresholds)
|
25
|
+
self.generate_final_report
|
26
|
+
self.choose_color
|
27
|
+
|
28
|
+
# move report.html from root to the /public folder
|
29
|
+
FileUtils.cp('report.html', 'public/') if File.file?("#{Rails.root}/report.html")
|
30
|
+
|
31
|
+
render layout: false
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
<!DOCTYPE HTML SYSTEM>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
5
|
+
<title>Quality Report</title>
|
6
|
+
<%= stylesheet_link_tag 'quality_meter/quality_meter' %>
|
7
|
+
<%= javascript_include_tag 'quality_meter/jquery-v1.11.2' %>
|
8
|
+
<%= javascript_include_tag 'quality_meter/quality_meter' %>
|
9
|
+
<script type="text/javascript">
|
10
|
+
// Custom JS
|
11
|
+
// Get previous report data
|
12
|
+
var data = <%= raw @previous_reports.to_json %>;
|
13
|
+
|
14
|
+
// Transpose array
|
15
|
+
var newArray = data[0].map(function(col, i) {
|
16
|
+
return data.map(function(row) {
|
17
|
+
return row[i]
|
18
|
+
})
|
19
|
+
});
|
20
|
+
|
21
|
+
|
22
|
+
// Get time intervals
|
23
|
+
time = newArray[newArray.length-1]
|
24
|
+
|
25
|
+
// Get data of each modules
|
26
|
+
arr_flog = newArray[newArray.length-5]
|
27
|
+
arr_stats = newArray[newArray.length-4]
|
28
|
+
arr_best_practise = newArray[newArray.length-3]
|
29
|
+
arr_security_warnings = newArray[newArray.length-2]
|
30
|
+
|
31
|
+
// Parse flog & stats data into float
|
32
|
+
arr_flog_hash = [];
|
33
|
+
for( var i = 0, len = arr_flog.length; i < len; i++ ) {
|
34
|
+
arr_flog_hash[i] = {X: time[i] , Y: parseFloat( arr_flog[i] ) };
|
35
|
+
}
|
36
|
+
arr_stats_hash = [];
|
37
|
+
for( var i = 0, len = arr_stats.length; i < len; i++ ) {
|
38
|
+
arr_stats_hash[i] = {X: time[i], Y: parseFloat( arr_stats[i] )};
|
39
|
+
}
|
40
|
+
arr_best_practise_hash = [];
|
41
|
+
for( var i = 0, len = arr_best_practise.length; i < len; i++ ) {
|
42
|
+
arr_best_practise_hash[i] ={X: time[i], Y: parseInt( arr_best_practise[i] )};
|
43
|
+
}
|
44
|
+
arr_security_warnings_hash = [];
|
45
|
+
for( var i = 0, len = arr_security_warnings.length; i < len; i++ ) {
|
46
|
+
arr_security_warnings_hash[i] ={X: time[i], Y: parseInt( arr_security_warnings[i] )};
|
47
|
+
}
|
48
|
+
|
49
|
+
var graphdata1 = {
|
50
|
+
linecolor: "Random",
|
51
|
+
values: arr_flog_hash
|
52
|
+
};
|
53
|
+
|
54
|
+
var graphdata2 = {
|
55
|
+
linecolor: "Random",
|
56
|
+
values: arr_stats_hash
|
57
|
+
};
|
58
|
+
|
59
|
+
var graphdata3 = {
|
60
|
+
linecolor: "Random",
|
61
|
+
values: arr_security_warnings_hash
|
62
|
+
};
|
63
|
+
|
64
|
+
var graphdata4 = {
|
65
|
+
linecolor: "Random",
|
66
|
+
title: 'rails practise',
|
67
|
+
values: arr_best_practise_hash
|
68
|
+
};
|
69
|
+
|
70
|
+
$(function () {
|
71
|
+
$("#Linegraph").SimpleChart({
|
72
|
+
toolwidth: "150",
|
73
|
+
toolheight: "25",
|
74
|
+
axiscolor: "#E6E6E6",
|
75
|
+
textcolor: "#6E6E6E",
|
76
|
+
title: 'flog',
|
77
|
+
data: [graphdata1],
|
78
|
+
});
|
79
|
+
|
80
|
+
$("#Linegraph1").SimpleChart({
|
81
|
+
toolwidth: "150",
|
82
|
+
toolheight: "25",
|
83
|
+
axiscolor: "#E6E6E6",
|
84
|
+
textcolor: "#6E6E6E",
|
85
|
+
title: 'stats',
|
86
|
+
data: [graphdata2],
|
87
|
+
});
|
88
|
+
|
89
|
+
$("#Linegraph2").SimpleChart({
|
90
|
+
toolwidth: "150",
|
91
|
+
toolheight: "25",
|
92
|
+
axiscolor: "#E6E6E6",
|
93
|
+
textcolor: "#6E6E6E",
|
94
|
+
title: 'security warnings',
|
95
|
+
data: [graphdata3],
|
96
|
+
});
|
97
|
+
|
98
|
+
$("#Linegraph3").SimpleChart({
|
99
|
+
toolwidth: "150",
|
100
|
+
toolheight: "25",
|
101
|
+
axiscolor: "#E6E6E6",
|
102
|
+
textcolor: "#6E6E6E",
|
103
|
+
title: 'rails practise',
|
104
|
+
data: [graphdata4],
|
105
|
+
});
|
106
|
+
});
|
107
|
+
</script>
|
108
|
+
</head>
|
109
|
+
<body class="quality_meter">
|
110
|
+
<h2 class="tophead"> Q-meter Dashboard</h2>
|
111
|
+
<%if @app_data.present?%>
|
112
|
+
<fieldset>
|
113
|
+
<legend>App Info</legend>
|
114
|
+
<table>
|
115
|
+
|
116
|
+
<%#@app_data.each do |k,v|%>
|
117
|
+
<tr>
|
118
|
+
<td><%=@app_data.keys[0].to_s.humanize%> : </td>
|
119
|
+
<td colspan="1"> <%=@app_data.values[0]%></td>
|
120
|
+
<td><%=@app_data.keys[1].to_s.humanize%> : </td>
|
121
|
+
<td colspan="1"> <%=@app_data.values[1]%></td>
|
122
|
+
</tr>
|
123
|
+
<tr>
|
124
|
+
<td><%=@app_data.keys[2].to_s.humanize%> : </td>
|
125
|
+
<td colspan="1"> <%=@app_data.values[2]%></td>
|
126
|
+
<td><%=@app_data.keys[3].to_s.humanize%> : </td>
|
127
|
+
<td colspan="1"> <%=@app_data.values[3]%></td>
|
128
|
+
</tr>
|
129
|
+
<tr>
|
130
|
+
<td><%=@app_data.keys[4].to_s.humanize%> : </td>
|
131
|
+
<td colspan="1"> <%=@app_data.values[4]%></td>
|
132
|
+
<td><%=@app_data.keys[5].to_s.humanize%> : </td>
|
133
|
+
<td colspan="1"> <%=@app_data.values[5]%></td>
|
134
|
+
</tr>
|
135
|
+
<%#end%>
|
136
|
+
</table>
|
137
|
+
</fieldset>
|
138
|
+
<%end%>
|
139
|
+
<fieldset>
|
140
|
+
<legend>Quick View</legend>
|
141
|
+
<table class="headings" align="left">
|
142
|
+
<tr>
|
143
|
+
<th>Stat</th>
|
144
|
+
<th >Rails Best Practise</th>
|
145
|
+
<th>Code Complexity</th>
|
146
|
+
<th>Security Warnings</th>
|
147
|
+
</tr>
|
148
|
+
|
149
|
+
<tr >
|
150
|
+
<th>
|
151
|
+
<a href="/metric_fu/stats.html" target="_blank">
|
152
|
+
<div class="pie" style="<%= @stats_rgy %>">
|
153
|
+
<div class="title"></div>
|
154
|
+
<div class="outer-right mask" id= "10deg">
|
155
|
+
<div class="inner-right"></div>
|
156
|
+
</div>
|
157
|
+
|
158
|
+
<div class="outer-left mask">
|
159
|
+
<div class="inner-left"></div>
|
160
|
+
</div>
|
161
|
+
<div class="content">
|
162
|
+
<span><%= @stats_code_to_test_ratio %></span>
|
163
|
+
</div>
|
164
|
+
</div>
|
165
|
+
</a>
|
166
|
+
<p></p>
|
167
|
+
<a href="/metric_fu/stats.html" target="_blank">Details</a>
|
168
|
+
</th>
|
169
|
+
<th>
|
170
|
+
<a href="/metric_fu/rails_best_practices.html" target="_blank">
|
171
|
+
<div class="pie" style="<%= @rails_best_practices_rgy %>">
|
172
|
+
<div class="title"></div>
|
173
|
+
<div class="outer-right mask" id= "10deg">
|
174
|
+
</div>
|
175
|
+
|
176
|
+
<div class="outer-left mask">
|
177
|
+
<div class="inner-left"></div>
|
178
|
+
</div>
|
179
|
+
<div class="content">
|
180
|
+
<span><%= @rails_best_practices_total %></span>
|
181
|
+
</div>
|
182
|
+
</div>
|
183
|
+
</a>
|
184
|
+
<p></p>
|
185
|
+
<a href="/metric_fu/rails_best_practices.html" target="_blank">Details</a>
|
186
|
+
</th>
|
187
|
+
<th>
|
188
|
+
<a href="/metric_fu/flog.html" target="_blank">
|
189
|
+
<div class="pie" style="<%= @flog_rgy %>">
|
190
|
+
<div class="title"></div>
|
191
|
+
<div class="outer-right mask" id= "10deg">
|
192
|
+
<div class="inner-right"></div>
|
193
|
+
</div>
|
194
|
+
|
195
|
+
<div class="outer-left mask">
|
196
|
+
<div class="inner-left"></div>
|
197
|
+
</div>
|
198
|
+
<div class="content">
|
199
|
+
<span><%= @flog_average_complexity %></span>
|
200
|
+
</div>
|
201
|
+
</div>
|
202
|
+
</a>
|
203
|
+
<p></p>
|
204
|
+
<a href="/metric_fu/flog.html" target="_blank">Details</a>
|
205
|
+
</th>
|
206
|
+
<th>
|
207
|
+
<a href="report.html" target="_blank">
|
208
|
+
<div class="pie" style="<%= @brakeman_warnings_rgy %>">
|
209
|
+
<div class="title"></div>
|
210
|
+
<div class="outer-right mask" id= "10deg"></div>
|
211
|
+
<div class="inner-right"></div>
|
212
|
+
|
213
|
+
<div class="outer-left mask">
|
214
|
+
<div class="inner-left"></div>
|
215
|
+
</div>
|
216
|
+
<div class="content">
|
217
|
+
<span><%= @warnings_count %></span>
|
218
|
+
</div>
|
219
|
+
</div>
|
220
|
+
</a>
|
221
|
+
<p></p>
|
222
|
+
<a href="report.html" target="_blank">Details</a>
|
223
|
+
</th>
|
224
|
+
</tr>
|
225
|
+
<tr><td colspan="4"></td></tr>
|
226
|
+
<tr>
|
227
|
+
<td colspan="4">
|
228
|
+
<div class="small-box green-box"></div><span class="small_span">Nice</span>
|
229
|
+
<div class="small-box yellow-box"></div><span class="small_span">Good</span>
|
230
|
+
<div class="small-box orange-box"></div><span class="small_span">Medium</span>
|
231
|
+
<div class="small-box red-box"></div><span class="small_span">Needs Improvement (Low)</span>
|
232
|
+
</td>
|
233
|
+
</tr>
|
234
|
+
</table>
|
235
|
+
|
236
|
+
</fieldset>
|
237
|
+
<fieldset>
|
238
|
+
<legend> Security Warning in Detail </legend>
|
239
|
+
<table align="right">
|
240
|
+
<% unless @brakeman_warnings.blank? %>
|
241
|
+
<% @brakeman_warnings.each do |warning| %>
|
242
|
+
<tr>
|
243
|
+
<td><%= warning[0] %></td>
|
244
|
+
<td align="right" style="font-weight:700"><%= warning[1] %></td>
|
245
|
+
</tr>
|
246
|
+
<% end %>
|
247
|
+
<% else %>
|
248
|
+
<tr><td>No Security Warnings</td></tr>
|
249
|
+
<% end %>
|
250
|
+
</table>
|
251
|
+
</fieldset>
|
252
|
+
<fieldset>
|
253
|
+
<legend> Commit Wise Reports (History) </legend>
|
254
|
+
<table align="center">
|
255
|
+
<tr>
|
256
|
+
<% unless @previous_reports.blank? %>
|
257
|
+
<tr>
|
258
|
+
<th><div id="Linegraph2" style=" height: 200px"></div></th>
|
259
|
+
<tr><th> <div id="Linegraph3" style=" height: 200px"></div></th>
|
260
|
+
</tr>
|
261
|
+
<tr>
|
262
|
+
<th><div id="Linegraph" style="height: 200px"></div></th>
|
263
|
+
</tr>
|
264
|
+
<tr><th><div id="Linegraph1" style="height: 200px"></div></th></tr>
|
265
|
+
<!-- tr bgcolor="#A5FF88">
|
266
|
+
<td colspan="2" align="center" style="font-size: 9pt;"><%#= "Generated on #{Time.now}" %></td>
|
267
|
+
</tr> -->
|
268
|
+
<% else %>
|
269
|
+
<div class='git-commit'>No commits with quality_meter yet</div>
|
270
|
+
<% end %>
|
271
|
+
</table> <!-- -->
|
272
|
+
</fieldset>
|
273
|
+
|
274
|
+
<body>
|
275
|
+
</html>
|
276
|
+
|
data/config/routes.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require "qmeter/version"
|
2
|
+
require 'qmeter/railtie' if defined?(Rails)
|
3
|
+
require "csv"
|
4
|
+
require "qmeter/engine"
|
5
|
+
|
6
|
+
module QualityMeter
|
7
|
+
def initialize_thresholds(thresholds)
|
8
|
+
# Initialize threshold values
|
9
|
+
@security_warnings_min = thresholds['security_warnings_min']
|
10
|
+
@security_warnings_max = thresholds['security_warnings_max']
|
11
|
+
|
12
|
+
@rails_best_practices_min = thresholds['rails_best_practices_min']
|
13
|
+
@rails_best_practices_max = thresholds['rails_best_practices_max']
|
14
|
+
|
15
|
+
@flog_complexity_min = thresholds['flog_complexity_min']
|
16
|
+
@flog_complexity_max = thresholds['flog_complexity_max']
|
17
|
+
|
18
|
+
@stats_ratio_min = thresholds['stats_ratio_min']
|
19
|
+
@stats_ratio_max = thresholds['stats_ratio_max']
|
20
|
+
|
21
|
+
@app_data = []
|
22
|
+
end
|
23
|
+
|
24
|
+
def collect_brakeman_details
|
25
|
+
# Breakman source file
|
26
|
+
file = check_and_assign_file_path('report.json')
|
27
|
+
if file
|
28
|
+
data_hash = JSON.parse(file)
|
29
|
+
### change array to hash and check it contain warnings or not
|
30
|
+
if data_hash.present? && data_hash.class == Hash ? data_hash.has_key?('warnings') : data_hash[0].has_key?('warnings')
|
31
|
+
warning_type = data_hash['warnings'].map {|a| a = a['warning_type'] }
|
32
|
+
assign_warnings(warning_type, data_hash['warnings'].count)
|
33
|
+
elsif data_hash[0].has_key?('warning_type')
|
34
|
+
assign_warnings([data_hash[0]['warning_type']])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def collect_app_data
|
40
|
+
@app_data = {app_path: "/home/arpit/applications/G8way/g8way",rails_version: "3.2.11",security_warnings: 84}
|
41
|
+
# Breakman source file
|
42
|
+
file = check_and_assign_file_path('report.json')
|
43
|
+
if file
|
44
|
+
data_hash = JSON.parse(file)
|
45
|
+
# change array to hash and check it contain warnings or not
|
46
|
+
if data_hash.present? && data_hash.has_key?('scan_info')
|
47
|
+
@app_data = {application: data_hash['scan_info']['app_path'].split("/").last, ruby_version: data_hash['scan_info']['ruby_version'], rails_version: data_hash['scan_info']['rails_version'], number_of_models: data_hash['scan_info']['number_of_models'], number_of_controllers: data_hash['scan_info']['number_of_controllers'], number_of_templates: data_hash['scan_info']['number_of_templates']}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
### Assign warnings to @breakeman_warnings ###
|
53
|
+
def assign_warnings(warning_type, warnings_count=1)
|
54
|
+
@brakeman_warnings = Hash.new(0)
|
55
|
+
# warning_type = data_hash[0]['warning_type']
|
56
|
+
@warnings_count = warnings_count
|
57
|
+
warning_type.each do |v|
|
58
|
+
@brakeman_warnings[v] += 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def collect_metric_fu_details
|
63
|
+
# parsing metric_fu report from .yml file
|
64
|
+
file = check_and_assign_file_path('tmp/metric_fu/report.yml')
|
65
|
+
if file
|
66
|
+
@surveys = YAML.load(ERB.new(file).result)
|
67
|
+
@surveys.each do |survey|
|
68
|
+
assign_status(survey) if survey.present?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
### assing ration ,complexity and bestpractice of code ###
|
74
|
+
def assign_status(survey)
|
75
|
+
case survey[0]
|
76
|
+
when :flog
|
77
|
+
@flog_average_complexity = survey[1][:average].round(1)
|
78
|
+
when :stats
|
79
|
+
@stats_code_to_test_ratio = survey[1][:code_to_test_ratio]
|
80
|
+
when :rails_best_practices
|
81
|
+
@rails_best_practices_total = survey[1][:total].first.gsub(/[^\d]/, '').to_i
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def generate_final_report
|
86
|
+
collect_app_data
|
87
|
+
collect_metric_fu_details
|
88
|
+
collect_brakeman_details
|
89
|
+
@app_root = Rails.root
|
90
|
+
get_previour_result
|
91
|
+
end
|
92
|
+
|
93
|
+
def save_report
|
94
|
+
# Save report data into the CSV
|
95
|
+
### Hide this because we are not using this currently
|
96
|
+
#flag = false
|
97
|
+
#flag = File.file?("#{Rails.root}/qmeter.csv")
|
98
|
+
CSV.open("#{Rails.root}/qmeter.csv", "a") do |csv|
|
99
|
+
#csv << ['flog','stats','rails_best_practices','warnings', 'timestamp'] if flag == false
|
100
|
+
sha = `git rev-parse HEAD`
|
101
|
+
csv << [@flog_average_complexity, @stats_code_to_test_ratio, @rails_best_practices_total, @warnings_count, sha]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_previour_result
|
106
|
+
# Get previous report data
|
107
|
+
@previous_reports = CSV.read("#{Rails.root}/qmeter.csv").last(4) if File.file?("#{Rails.root}/qmeter.csv")
|
108
|
+
end
|
109
|
+
|
110
|
+
def choose_color
|
111
|
+
# Check threashhold
|
112
|
+
### set color to the variables ###
|
113
|
+
@brakeman_warnings_rgy = set_color(@warnings_count, @security_warnings_max, @security_warnings_min)
|
114
|
+
@rails_best_practices_rgy = set_color(@rails_best_practices_total, @rails_best_practices_max, @rails_best_practices_min)
|
115
|
+
@flog_rgy = set_color(@flog_average_complexity, @flog_complexity_max, @flog_complexity_min)
|
116
|
+
@stats_rgy = set_stat_color(@stats_code_to_test_ratio, @stats_ratio_max, @stats_ratio_min )
|
117
|
+
end
|
118
|
+
|
119
|
+
### method to check file is exist or not ###
|
120
|
+
def check_and_assign_file_path(path)
|
121
|
+
file = "#{Rails.root}/#{path}"
|
122
|
+
File.exist?(file) ? File.read(path) : nil
|
123
|
+
end
|
124
|
+
|
125
|
+
### send proper color according to data ###
|
126
|
+
def set_color(count, max, min)
|
127
|
+
if count.present? && count > max
|
128
|
+
'background-color:#D00000;'
|
129
|
+
elsif count.present? && count > min && count < max
|
130
|
+
avg = max.to_f / 2.to_f
|
131
|
+
low_avg = avg / 2.to_f
|
132
|
+
high_avg = avg + low_avg
|
133
|
+
if count >= high_avg
|
134
|
+
'background-color:#D00000;'
|
135
|
+
elsif count >= avg && count < high_avg
|
136
|
+
'background-color:orange;'
|
137
|
+
elsif count <= low_avg
|
138
|
+
'background-color:green;'
|
139
|
+
elsif count >= low_avg
|
140
|
+
'background-color:yellow;'
|
141
|
+
else
|
142
|
+
'background-color:#D00000;'
|
143
|
+
end
|
144
|
+
else
|
145
|
+
'background-color:#006633;'
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
### @arpit: send proper color according to data ###
|
150
|
+
def set_stat_color(count, max, min)
|
151
|
+
if count.present? && count > max
|
152
|
+
'background-color:#D00000;'
|
153
|
+
elsif count.present? && count > min && count < max
|
154
|
+
avg = max.to_f / 2.to_f
|
155
|
+
low_avg = avg / 2.to_f
|
156
|
+
if count > avg
|
157
|
+
'background-color:green;'
|
158
|
+
elsif count < avg && count < low_avg
|
159
|
+
'background-color:#D00000;'
|
160
|
+
elsif count < avg && count > low_avg
|
161
|
+
'background-color:orange;'
|
162
|
+
else
|
163
|
+
'background-color:#D00000;'
|
164
|
+
end
|
165
|
+
else
|
166
|
+
'background-color:#006633;'
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
end
|