jirametrics 2.7 → 2.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jirametrics/chart_base.rb +11 -3
- data/lib/jirametrics/data_quality_report.rb +121 -1
- data/lib/jirametrics/examples/aggregated_project.rb +0 -2
- data/lib/jirametrics/examples/standard_project.rb +0 -2
- data/lib/jirametrics/flow_efficiency_scatterplot.rb +1 -3
- data/lib/jirametrics/html/index.css +10 -3
- data/lib/jirametrics/issue.rb +1 -1
- data/lib/jirametrics/project_config.rb +10 -0
- metadata +5 -6
- data/lib/jirametrics/html/data_quality_report.erb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b747372b77be9d3ec514c09b57f479741a47688dd6e634e6823aa9feefe3154e
|
4
|
+
data.tar.gz: df7b9bdc06211d7d2fd89df18af5aa8ab4b780aa58f798c29c45ca8033c1986f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f4873e816019b7b2903b7b2a5c905484a6e1ef5d2601f9bb8dd0cec78a306646a4d145a6bb76981a4bd3ce46d884e5e7b8e8e3ccef4f179a2a7067e26b58a43
|
7
|
+
data.tar.gz: 40790878004dd12d1aa362cbe72988a2c6ed13152066b48ab1f38855a74bf89f8aae926d13d3e721990ca568c20f5adbd1c99d0ce5b81aaece19d04701b8eddd
|
@@ -25,6 +25,14 @@ class ChartBase
|
|
25
25
|
@aggregated_project
|
26
26
|
end
|
27
27
|
|
28
|
+
def html_directory
|
29
|
+
pathname = Pathname.new(File.realpath(__FILE__))
|
30
|
+
# basename = pathname.basename.to_s
|
31
|
+
# raise "Unexpected filename #{basename.inspect}" unless basename.match?(/^(.+)\.rb$/)
|
32
|
+
|
33
|
+
"#{pathname.dirname}/html"
|
34
|
+
end
|
35
|
+
|
28
36
|
def render caller_binding, file
|
29
37
|
pathname = Pathname.new(File.realpath(file))
|
30
38
|
basename = pathname.basename.to_s
|
@@ -33,8 +41,8 @@ class ChartBase
|
|
33
41
|
# Insert a incrementing chart_id so that all the chart names on the page are unique
|
34
42
|
caller_binding.eval "chart_id='chart#{next_id}'" # chart_id=chart3
|
35
43
|
|
36
|
-
@html_directory = "#{pathname.dirname}/html"
|
37
|
-
erb = ERB.new file_system.load "#{
|
44
|
+
# @html_directory = "#{pathname.dirname}/html"
|
45
|
+
erb = ERB.new file_system.load "#{html_directory}/#{$1}.erb"
|
38
46
|
erb.result(caller_binding)
|
39
47
|
end
|
40
48
|
|
@@ -100,7 +108,7 @@ class ChartBase
|
|
100
108
|
issues_id = next_id
|
101
109
|
|
102
110
|
issue_descriptions.sort! { |a, b| a[0].key_as_i <=> b[0].key_as_i }
|
103
|
-
erb = ERB.new file_system.load
|
111
|
+
erb = ERB.new file_system.load File.join(html_directory, 'collapsible_issues_panel.erb')
|
104
112
|
erb.result(binding)
|
105
113
|
end
|
106
114
|
|
@@ -57,7 +57,25 @@ class DataQualityReport < ChartBase
|
|
57
57
|
entries_with_problems = entries_with_problems()
|
58
58
|
return '' if entries_with_problems.empty?
|
59
59
|
|
60
|
-
|
60
|
+
caller_binding = binding
|
61
|
+
result = +''
|
62
|
+
result << render_top_text(caller_binding)
|
63
|
+
|
64
|
+
result << '<ul class="quality_report">'
|
65
|
+
result << render_problem_type(:discarded_changes)
|
66
|
+
result << render_problem_type(:completed_but_not_started)
|
67
|
+
result << render_problem_type(:status_changes_after_done)
|
68
|
+
result << render_problem_type(:backwards_through_status_categories)
|
69
|
+
result << render_problem_type(:backwords_through_statuses)
|
70
|
+
result << render_problem_type(:status_not_on_board)
|
71
|
+
result << render_problem_type(:created_in_wrong_status)
|
72
|
+
result << render_problem_type(:stopped_before_started)
|
73
|
+
result << render_problem_type(:issue_not_started_but_subtasks_have)
|
74
|
+
result << render_problem_type(:incomplete_subtasks_when_issue_done)
|
75
|
+
result << render_problem_type(:issue_on_multiple_boards)
|
76
|
+
result << '</ul>'
|
77
|
+
|
78
|
+
result
|
61
79
|
end
|
62
80
|
|
63
81
|
def problems_for key
|
@@ -70,6 +88,18 @@ class DataQualityReport < ChartBase
|
|
70
88
|
result
|
71
89
|
end
|
72
90
|
|
91
|
+
def render_problem_type problem_key
|
92
|
+
problems = problems_for problem_key
|
93
|
+
return '' if problems.empty?
|
94
|
+
|
95
|
+
<<-HTML
|
96
|
+
<li>
|
97
|
+
#{__send__ :"render_#{problem_key}", problems}
|
98
|
+
#{collapsible_issues_panel problems}
|
99
|
+
</li>
|
100
|
+
HTML
|
101
|
+
end
|
102
|
+
|
73
103
|
# Return a format that's easier to assert against
|
74
104
|
def testable_entries
|
75
105
|
format = '%Y-%m-%d %H:%M:%S %z'
|
@@ -317,4 +347,94 @@ class DataQualityReport < ChartBase
|
|
317
347
|
)
|
318
348
|
end
|
319
349
|
end
|
350
|
+
|
351
|
+
def render_discarded_changes problems
|
352
|
+
<<-HTML
|
353
|
+
#{label_issues problems.size} have had information discarded. This configuration is set
|
354
|
+
to "reset the clock" if an item is moved back to the backlog after it's been started. This hides important
|
355
|
+
information and makes the data less accurate. <b>Moving items back to the backlog is strongly discouraged.</b> HTML
|
356
|
+
HTML
|
357
|
+
end
|
358
|
+
|
359
|
+
def render_completed_but_not_started problems
|
360
|
+
percentage_work_included = ((issues.size - problems.size).to_f / issues.size * 100).to_i
|
361
|
+
html = <<-HTML
|
362
|
+
#{label_issues problems.size} were discarded from all charts using cycletime (scatterplot, histogram, etc)
|
363
|
+
as we couldn't determine when they started.
|
364
|
+
HTML
|
365
|
+
if percentage_work_included < 85
|
366
|
+
html << <<-HTML
|
367
|
+
Consider whether looking at only #{percentage_work_included}% of the total data points is enough
|
368
|
+
to come to any reasonable conclusions. See <a href="https://en.wikipedia.org/wiki/Survivorship_bias">
|
369
|
+
Survivorship Bias</a>.
|
370
|
+
HTML
|
371
|
+
end
|
372
|
+
html
|
373
|
+
end
|
374
|
+
|
375
|
+
def render_status_changes_after_done problems
|
376
|
+
<<-HTML
|
377
|
+
#{label_issues problems.size} had a status change after being identified as done. We should question
|
378
|
+
whether they were really done at that point or if we stopped the clock too early.
|
379
|
+
HTML
|
380
|
+
end
|
381
|
+
|
382
|
+
def render_backwards_through_status_categories problems
|
383
|
+
<<-HTML
|
384
|
+
#{label_issues problems.size} moved backwards across the board, <b>crossing status categories</b>.
|
385
|
+
This will almost certainly have impacted timings as the end times are often taken at status category
|
386
|
+
boundaries. You should assume that any timing measurements for this item are wrong.
|
387
|
+
HTML
|
388
|
+
end
|
389
|
+
|
390
|
+
def render_backwords_through_statuses problems
|
391
|
+
<<-HTML
|
392
|
+
#{label_issues problems.size} moved backwards across the board. Depending where we have set the
|
393
|
+
start and end points, this may give us incorrect timing data. Note that these items did not cross
|
394
|
+
a status category and may not have affected metrics.
|
395
|
+
HTML
|
396
|
+
end
|
397
|
+
|
398
|
+
def render_status_not_on_board problems
|
399
|
+
<<-HTML
|
400
|
+
#{label_issues problems.size} were not visible on the board for some period of time. This may impact
|
401
|
+
timings as the work was likely to have been forgotten if it wasn't visible.
|
402
|
+
HTML
|
403
|
+
end
|
404
|
+
|
405
|
+
def render_created_in_wrong_status problems
|
406
|
+
<<-HTML
|
407
|
+
#{label_issues problems.size} were created in a status not designated as Backlog. This will impact
|
408
|
+
the measurement of start times and will therefore impact whether it's shown as in progress or not.
|
409
|
+
HTML
|
410
|
+
end
|
411
|
+
|
412
|
+
def render_stopped_before_started problems
|
413
|
+
<<-HTML
|
414
|
+
#{label_issues problems.size} were stopped before they were started and this will play havoc with
|
415
|
+
any cycletime or WIP calculations. The most common case for this is when an item gets closed and
|
416
|
+
then moved back into an in-progress status.
|
417
|
+
HTML
|
418
|
+
end
|
419
|
+
|
420
|
+
def render_issue_not_started_but_subtasks_have problems
|
421
|
+
<<-HTML
|
422
|
+
#{label_issues problems.size} still showing 'not started' while sub-tasks underneath them have
|
423
|
+
started. This is almost always a mistake; if we're working on subtasks, the top level item should
|
424
|
+
also have started.
|
425
|
+
HTML
|
426
|
+
end
|
427
|
+
|
428
|
+
def render_incomplete_subtasks_when_issue_done problems
|
429
|
+
<<-HTML
|
430
|
+
#{label_issues problems.size} issues were marked as done while subtasks were still not done.
|
431
|
+
HTML
|
432
|
+
end
|
433
|
+
|
434
|
+
def render_issue_on_multiple_boards problems
|
435
|
+
<<-HTML
|
436
|
+
For #{label_issues problems.size}, we have an issue that shows up on more than one board. This
|
437
|
+
could result in more data points showing up on a chart then there really should be.
|
438
|
+
HTML
|
439
|
+
end
|
320
440
|
end
|
@@ -3,8 +3,6 @@
|
|
3
3
|
# This file is really intended to give you ideas about how you might configure your own reports, not
|
4
4
|
# as a complete setup that will work in every case.
|
5
5
|
#
|
6
|
-
# See https://github.com/mikebowler/jirametrics/wiki/Examples-folder for more details
|
7
|
-
#
|
8
6
|
# The point of an AGGREGATED report is that we're now looking at a higher level. We might use this in a
|
9
7
|
# S2 meeting (Scrum of Scrums) to talk about the things that are happening across teams, not within a
|
10
8
|
# single team. For that reason, we look at slightly different things that we would on a single team board.
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
# This file is really intended to give you ideas about how you might configure your own reports, not
|
4
4
|
# as a complete setup that will work in every case.
|
5
|
-
#
|
6
|
-
# See https://github.com/mikebowler/jirametrics/wiki/Examples-folder for more
|
7
5
|
class Exporter
|
8
6
|
def standard_project name:, file_prefix:, ignore_issues: nil, starting_status: nil, boards: {},
|
9
7
|
default_board: nil, anonymize: false, settings: {}, status_category_mappings: {},
|
@@ -19,14 +19,12 @@ class FlowEfficiencyScatterplot < ChartBase
|
|
19
19
|
</div>
|
20
20
|
<div class="p">
|
21
21
|
<math>
|
22
|
-
<mn>Flow efficiency</mn>
|
22
|
+
<mn>Flow efficiency (%)</mn>
|
23
23
|
<mo>=</mo>
|
24
24
|
<mfrac>
|
25
25
|
<mrow><mn>Time adding value</mn></mrow>
|
26
26
|
<mrow><mn>Total time</mn></mrow>
|
27
27
|
</mfrac>
|
28
|
-
<mo>x</mo>
|
29
|
-
<mn>100%</mn>
|
30
28
|
</math>
|
31
29
|
</div>
|
32
30
|
<div style="background: yellow">Note that for this calculation to be accurate, we must be moving items into a
|
@@ -99,9 +99,6 @@ table.standard {
|
|
99
99
|
background-color: #eee;
|
100
100
|
}
|
101
101
|
}
|
102
|
-
.quality_note_bullet {
|
103
|
-
color: red;
|
104
|
-
}
|
105
102
|
|
106
103
|
.chart {
|
107
104
|
background-color: white;
|
@@ -119,6 +116,16 @@ div.color_block {
|
|
119
116
|
border: 1px solid black;
|
120
117
|
}
|
121
118
|
|
119
|
+
ul.quality_report {
|
120
|
+
list-style-type: '⮕';
|
121
|
+
::marker {
|
122
|
+
color: red;
|
123
|
+
}
|
124
|
+
li {
|
125
|
+
padding: 0.2em;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
122
129
|
@media screen and (prefers-color-scheme: dark) {
|
123
130
|
:root {
|
124
131
|
--non-working-days-color: #2f2f2f;
|
data/lib/jirametrics/issue.rb
CHANGED
@@ -141,7 +141,7 @@ class Issue
|
|
141
141
|
@board.project_config.file_system.log(
|
142
142
|
"Warning: Status name #{name.inspect} for issue #{key} not found in" \
|
143
143
|
" #{board.possible_statuses.collect(&:name).inspect}" \
|
144
|
-
"\n See
|
144
|
+
"\n See https://jirametrics.org/faq/#q1\n",
|
145
145
|
also_write_to_stderr: true
|
146
146
|
)
|
147
147
|
status = Status.new(name: name, category_name: 'In Progress')
|
@@ -31,6 +31,10 @@ class ProjectConfig
|
|
31
31
|
instance_eval(&@block) if @block
|
32
32
|
end
|
33
33
|
|
34
|
+
def data_downloaded?
|
35
|
+
File.exist? File.join(@target_path, "#{file_prefix}_meta.json")
|
36
|
+
end
|
37
|
+
|
34
38
|
def load_data
|
35
39
|
return if @has_loaded_data
|
36
40
|
|
@@ -43,6 +47,8 @@ class ProjectConfig
|
|
43
47
|
end
|
44
48
|
|
45
49
|
def run load_only: false
|
50
|
+
return if @exporter.downloading?
|
51
|
+
|
46
52
|
load_data unless aggregated_project?
|
47
53
|
anonymize_data if @anonymizer_needed
|
48
54
|
|
@@ -304,6 +310,10 @@ class ProjectConfig
|
|
304
310
|
raise 'This is an aggregated project and issues should have been included with the include_issues_from ' \
|
305
311
|
'declaration but none are here. Check your config.'
|
306
312
|
end
|
313
|
+
|
314
|
+
return @issues = [] if @exporter.downloading?
|
315
|
+
raise 'No data found. Must do a download before an export' unless data_downloaded?
|
316
|
+
|
307
317
|
load_data if all_boards.empty?
|
308
318
|
|
309
319
|
timezone_offset = exporter.timezone_offset
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jirametrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Bowler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: random-word
|
@@ -106,7 +106,6 @@ files:
|
|
106
106
|
- lib/jirametrics/html/cycletime_histogram.erb
|
107
107
|
- lib/jirametrics/html/cycletime_scatterplot.erb
|
108
108
|
- lib/jirametrics/html/daily_wip_chart.erb
|
109
|
-
- lib/jirametrics/html/data_quality_report.erb
|
110
109
|
- lib/jirametrics/html/estimate_accuracy_chart.erb
|
111
110
|
- lib/jirametrics/html/expedited_chart.erb
|
112
111
|
- lib/jirametrics/html/flow_efficiency_scatterplot.erb
|
@@ -132,14 +131,14 @@ files:
|
|
132
131
|
- lib/jirametrics/tree_organizer.rb
|
133
132
|
- lib/jirametrics/trend_line_calculator.rb
|
134
133
|
- lib/jirametrics/value_equality.rb
|
135
|
-
homepage: https://
|
134
|
+
homepage: https://jirametrics.org
|
136
135
|
licenses:
|
137
136
|
- Apache-2.0
|
138
137
|
metadata:
|
139
138
|
rubygems_mfa_required: 'true'
|
140
139
|
bug_tracker_uri: https://github.com/mikebowler/jirametrics/issues
|
141
|
-
changelog_uri: https://
|
142
|
-
documentation_uri: https://
|
140
|
+
changelog_uri: https://jirametrics.org/changes
|
141
|
+
documentation_uri: https://jirametrics.org
|
143
142
|
post_install_message:
|
144
143
|
rdoc_options: []
|
145
144
|
require_paths:
|
@@ -1,138 +0,0 @@
|
|
1
|
-
<%
|
2
|
-
problems = problems_for :discarded_changes
|
3
|
-
unless problems.empty?
|
4
|
-
%>
|
5
|
-
<p>
|
6
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> have had information discarded. This configuration is set
|
7
|
-
to "reset the clock" if an item is moved back to the backlog after it's been started. This hides important
|
8
|
-
information and makes the data less accurate. <b>Moving items back to the backlog is strongly discouraged.</b>
|
9
|
-
<%= collapsible_issues_panel problems %>
|
10
|
-
</p>
|
11
|
-
<%
|
12
|
-
end
|
13
|
-
%>
|
14
|
-
|
15
|
-
<%
|
16
|
-
problems = problems_for :completed_but_not_started
|
17
|
-
unless problems.empty?
|
18
|
-
percentage_work_included = ((issues.size - problems.size).to_f / issues.size * 100).to_i
|
19
|
-
%>
|
20
|
-
<p>
|
21
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> were discarded from all charts using cycletime (scatterplot, histogram, etc) as we couldn't determine when they started.
|
22
|
-
<% if percentage_work_included < 85 %>
|
23
|
-
Consider whether looking at only <%= percentage_work_included %>% of the total data points is enough to come to any reasonable conclusions. See <a href="https://en.wikipedia.org/wiki/Survivorship_bias">Survivorship Bias</a>.
|
24
|
-
<% end %>
|
25
|
-
<%= collapsible_issues_panel problems %>
|
26
|
-
</p>
|
27
|
-
<%
|
28
|
-
end
|
29
|
-
%>
|
30
|
-
|
31
|
-
<%
|
32
|
-
problems = problems_for :status_changes_after_done
|
33
|
-
unless problems.empty?
|
34
|
-
%>
|
35
|
-
<p>
|
36
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> had a status change after being identified as done. We should question whether they were really done at that point or if we stopped the clock too early.
|
37
|
-
<%= collapsible_issues_panel problems %>
|
38
|
-
</p>
|
39
|
-
<%
|
40
|
-
end
|
41
|
-
%>
|
42
|
-
|
43
|
-
<%
|
44
|
-
problems = problems_for :backwards_through_status_categories
|
45
|
-
unless problems.empty?
|
46
|
-
%>
|
47
|
-
<p>
|
48
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> moved backwards across the board, <b>crossing status categories</b>. This will almost certainly have impacted timings as the end times are often taken at status category boundaries. You should assume that any timing measurements for this item are wrong.
|
49
|
-
<%= collapsible_issues_panel problems %>
|
50
|
-
</p>
|
51
|
-
<%
|
52
|
-
end
|
53
|
-
%>
|
54
|
-
|
55
|
-
<%
|
56
|
-
problems = problems_for :backwords_through_statuses
|
57
|
-
unless problems.empty?
|
58
|
-
%>
|
59
|
-
<p>
|
60
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> moved backwards across the board. Depending where we have set the start and end points, this may give us incorrect timing data. Note that these items did not cross a status category and may not have affected metrics.
|
61
|
-
<%= collapsible_issues_panel problems %>
|
62
|
-
</p>
|
63
|
-
<%
|
64
|
-
end
|
65
|
-
%>
|
66
|
-
|
67
|
-
<%
|
68
|
-
problems = problems_for :status_not_on_board
|
69
|
-
unless problems.empty?
|
70
|
-
%>
|
71
|
-
<p>
|
72
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> were not visible on the board for some period of time. This may impact timings as the work was likely to have been forgotten if it wasn't visible.
|
73
|
-
<%= collapsible_issues_panel problems %>
|
74
|
-
</p>
|
75
|
-
<%
|
76
|
-
end
|
77
|
-
%>
|
78
|
-
|
79
|
-
<%
|
80
|
-
problems = problems_for :created_in_wrong_status
|
81
|
-
unless problems.empty?
|
82
|
-
%>
|
83
|
-
<p>
|
84
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> were created in a status not designated as Backlog. This will impact the measurement of start times and will therefore impact whether it's shown as in progress or not.
|
85
|
-
<%= collapsible_issues_panel problems %>
|
86
|
-
</p>
|
87
|
-
<%
|
88
|
-
end
|
89
|
-
%>
|
90
|
-
|
91
|
-
<%
|
92
|
-
problems = problems_for :stopped_before_started
|
93
|
-
unless problems.empty?
|
94
|
-
%>
|
95
|
-
<p>
|
96
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> were stopped before they were started and this will play havoc with any cycletime or WIP calculations. The most common case for this is when an item gets closed and then moved back into an in-progress status.
|
97
|
-
<%= collapsible_issues_panel problems %>
|
98
|
-
</p>
|
99
|
-
<%
|
100
|
-
end
|
101
|
-
%>
|
102
|
-
|
103
|
-
<%
|
104
|
-
problems = problems_for :issue_not_started_but_subtasks_have
|
105
|
-
unless problems.empty?
|
106
|
-
%>
|
107
|
-
<p>
|
108
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> still showing 'not started' while sub-tasks underneath them have started. This is almost always a mistake; if we're working on subtasks, the top level
|
109
|
-
item should also have started.
|
110
|
-
<%= collapsible_issues_panel problems %>
|
111
|
-
</p>
|
112
|
-
<%
|
113
|
-
end
|
114
|
-
%>
|
115
|
-
|
116
|
-
<%
|
117
|
-
problems = problems_for :incomplete_subtasks_when_issue_done
|
118
|
-
unless problems.empty?
|
119
|
-
%>
|
120
|
-
<p>
|
121
|
-
<span class="quality_note_bullet">⮕</span> <%= label_issues problems.size %> issues were marked as done while subtasks were still not done.
|
122
|
-
<%= collapsible_issues_panel problems %>
|
123
|
-
</p>
|
124
|
-
<%
|
125
|
-
end
|
126
|
-
%>
|
127
|
-
|
128
|
-
<%
|
129
|
-
problems = problems_for :issue_on_multiple_boards
|
130
|
-
unless problems.empty?
|
131
|
-
%>
|
132
|
-
<p>
|
133
|
-
<span class="quality_note_bullet">⮕</span> For <%= label_issues problems.size %>, we have an issue that shows up on more than one board. This could result in more data points showing up on a chart then there really should be.
|
134
|
-
<%= collapsible_issues_panel problems, :hide_board_column %>
|
135
|
-
</p>
|
136
|
-
<%
|
137
|
-
end
|
138
|
-
%>
|