graphgraph 0.3.0 → 0.4.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04906ef2c40cf20088fd506ce24010a74c843a9e
|
4
|
+
data.tar.gz: c1df406623ae9e18f5d76dabadb91f11f0e02e67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 609528540517687646fc0e7bbf0fc627b4f68d5415cc2f19ced2bccfbeffc430efbac59257ee09b751d9b0b9c0e50b567ae6f95258c49f013c05c8ef0f05a882
|
7
|
+
data.tar.gz: d4a8d1c3b683a50a91caa21aaf6ba60500b095eb1c5628994aa2f5c76e40db055ef51cdb6c99f639e087771f0fd384ffcabe32035fc86190eedcdf9589811da0
|
Binary file
|
@@ -1,60 +1,52 @@
|
|
1
1
|
class <%= @scope_prefix %>GraphgraphsController < ApplicationController
|
2
2
|
def graphgraph
|
3
|
+
|
3
4
|
@scopeName= <%= @scope.capitalize %>
|
4
5
|
@testData= <%= @scope.capitalize %>.all
|
5
6
|
@columnNames = <%= @scope.capitalize %>.column_names
|
6
|
-
|
7
|
-
@columnHash = <%= @scope.capitalize %>.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
|
7
|
+
@columnHash = %= @scope.capitalize %>.columns_hash.each {|k,v| puts "#{k} => #{v.type}"}
|
8
8
|
@selectoptions =[]
|
9
9
|
@columnNames.each do |c|
|
10
10
|
@selectoptions << c.to_s + " : " + @columnHash[c].type.to_s
|
11
11
|
end
|
12
|
+
call_counts
|
13
|
+
set_graph
|
14
|
+
set_user_template
|
15
|
+
puts @foruser
|
16
|
+
set_bargraph
|
17
|
+
set_linegraph
|
18
|
+
set_areagraph
|
19
|
+
set_scattergraph
|
20
|
+
|
21
|
+
if params[:fromuser]=="fromuser"
|
22
|
+
call_counts
|
23
|
+
set_graph
|
24
|
+
set_user_template
|
25
|
+
puts @foruser
|
26
|
+
set_bargraph
|
27
|
+
set_linegraph
|
28
|
+
set_areagraph
|
29
|
+
set_scattergraph
|
30
|
+
@mainchart=@chartline||@chartbar||@chartarea||@chartscatter
|
31
|
+
redirect_to <%= @scope.capitalize %>s_path(options: @mainchart.objects.to_s, placeholder: @mainchart.placeholder.to_s, series_data: @mainchart.series_data.to_s)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def call_counts
|
12
37
|
if (params[:xaxis]!=nil)
|
13
38
|
if params[:xaxis].include? "datetime"
|
14
39
|
get_counts(params[:xaxis],params[:yaxis],params[:xstart].split(/\s+/),params[:xend].split(/\s+/))
|
15
40
|
end
|
16
41
|
end
|
17
|
-
|
18
|
-
if (params[:graphtype].to_s == "Bar Graph")
|
19
|
-
|
20
|
-
# puts "import !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
21
|
-
tempx = params[:xaxis].slice(0..(params[:xaxis].index(' '))) # determine user-given variable name
|
22
|
-
final_x = tempx.strip
|
23
|
-
tempy = params[:yaxis].slice(0..(params[:yaxis].index(' '))) # determine user-given variable name
|
24
|
-
final_y = tempy.strip
|
25
|
-
# instance_variable_set("@#{variable_name}", params[:xaxis])
|
26
|
-
# puts <%= @scope.capitalize %>.pluck(final_x)
|
27
|
-
@barcat=[]
|
28
|
-
@bardata=[]
|
29
|
-
@chartbar = LazyHighCharts::HighChart.new('column') do |f|
|
30
|
-
if (@x_ticks!=nil)
|
31
|
-
@x_ticks.each do |x|
|
32
|
-
@barcat << x[0]
|
33
|
-
@bardata << x[1]
|
34
|
-
end
|
35
|
-
f.xAxis(:categories => @barcat)
|
36
|
-
f.series(:data=> @bardata)
|
37
|
-
else
|
38
|
-
f.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
39
|
-
f.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
40
|
-
end
|
41
|
-
|
42
|
-
# f.series(:name=>'Jane',:data=>[1, 3, 4, 3, 3, 5, 4,-46] )
|
43
|
-
f.title({ :text=>params[:title].to_s})
|
44
|
-
f.legend(:layout=> 'horizontal',:style=> {:left=> 'auto', :bottom=> 'auto',:right=> '50px',:top=> '100px'})
|
45
|
-
|
46
|
-
|
47
|
-
### Options for Bar
|
48
|
-
### f.options[:chart][:defaultSeriesType] = "bar"
|
49
|
-
### f.plot_options({:series=>{:stacking=>"normal"}})
|
42
|
+
end
|
50
43
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
44
|
+
def set_graph
|
45
|
+
@graphtype=["Bar Graph", "Line Graph", "Area Graph", "Scatter Graph"]
|
46
|
+
end
|
56
47
|
|
57
|
-
|
48
|
+
def set_scattergraph
|
49
|
+
if (params[:graphtype].to_s == "Scatter Graph")
|
58
50
|
|
59
51
|
# puts "import !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
60
52
|
tempx = params[:xaxis].slice(0..(params[:xaxis].index(' '))) # determine user-given variable name
|
@@ -63,35 +55,42 @@ class <%= @scope_prefix %>GraphgraphsController < ApplicationController
|
|
63
55
|
final_y = tempy.strip
|
64
56
|
# instance_variable_set("@#{variable_name}", params[:xaxis])
|
65
57
|
# puts <%= @scope.capitalize %>.pluck(final_x)
|
66
|
-
@
|
67
|
-
@
|
68
|
-
@
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
f.xAxis(:categories => @linecat)
|
75
|
-
f.series(:data=> @linedata)
|
76
|
-
else
|
77
|
-
f.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
78
|
-
f.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
58
|
+
@scattercat=[]
|
59
|
+
@scatterdata=[]
|
60
|
+
@chartscatter = LazyHighCharts::HighChart.new('scatter') do |f2|
|
61
|
+
if (@x_ticks!=nil)
|
62
|
+
@x_ticks.each do |x|
|
63
|
+
@scattercat << x[0]
|
64
|
+
@scatterdata << x[1]
|
79
65
|
end
|
80
|
-
|
81
|
-
|
82
|
-
|
66
|
+
f2.xAxis(:categories => @scattercat)
|
67
|
+
f2.series(:data=> @scatterdata)
|
68
|
+
else
|
69
|
+
f2.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
70
|
+
f2.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
71
|
+
end
|
72
|
+
# f.series(:name=>'Jane',:data=>[1, 3, 4, 3, 3, 5, 4,-46] )
|
73
|
+
f2.title({ :text=>params[:title].to_s})
|
74
|
+
f2.plot_options(series: {
|
75
|
+
stacking:'normal'
|
76
|
+
})
|
77
|
+
f2.chart({ defaultSeriesType: 'scatter'})
|
78
|
+
f2.legend(:layout=> 'horizontal',:style=> {:left=> 'auto', :bottom=> 'auto',:right=> '50px',:top=> '100px'})
|
83
79
|
|
84
80
|
|
85
|
-
|
86
|
-
|
87
|
-
|
81
|
+
### Options for Bar
|
82
|
+
### f.options[:chart][:defaultSeriesType] = "bar"
|
83
|
+
### f.plot_options({:series=>{:stacking=>"normal"}})
|
88
84
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
85
|
+
## or options for column
|
86
|
+
# f.options[:chart][:defaultSeriesType] = "column"
|
87
|
+
# f.plot_options({:column=>{:stacking=>"percent"}})
|
88
|
+
|
89
|
+
end
|
93
90
|
end
|
91
|
+
end
|
94
92
|
|
93
|
+
def set_areagraph
|
95
94
|
if (params[:graphtype].to_s == "Area Graph")
|
96
95
|
|
97
96
|
# puts "import !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
@@ -134,8 +133,10 @@ class <%= @scope_prefix %>GraphgraphsController < ApplicationController
|
|
134
133
|
|
135
134
|
end
|
136
135
|
end
|
136
|
+
end
|
137
137
|
|
138
|
-
|
138
|
+
def set_linegraph
|
139
|
+
if (params[:graphtype].to_s == "Line Graph")
|
139
140
|
|
140
141
|
# puts "import !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
141
142
|
tempx = params[:xaxis].slice(0..(params[:xaxis].index(' '))) # determine user-given variable name
|
@@ -144,42 +145,135 @@ class <%= @scope_prefix %>GraphgraphsController < ApplicationController
|
|
144
145
|
final_y = tempy.strip
|
145
146
|
# instance_variable_set("@#{variable_name}", params[:xaxis])
|
146
147
|
# puts <%= @scope.capitalize %>.pluck(final_x)
|
147
|
-
@
|
148
|
-
@
|
149
|
-
@
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
148
|
+
@linecat=[]
|
149
|
+
@linedata=[]
|
150
|
+
@chartline = LazyHighCharts::HighChart.new('line') do |f|
|
151
|
+
if (@x_ticks!=nil)
|
152
|
+
@x_ticks.each do |x|
|
153
|
+
@linecat << x[0]
|
154
|
+
@linedata << x[1]
|
155
|
+
end
|
156
|
+
f.xAxis(:categories => @linecat)
|
157
|
+
f.series(:data=> @linedata)
|
158
|
+
else
|
159
|
+
f.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
160
|
+
f.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
154
161
|
end
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
f2.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
159
|
-
f2.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
160
|
-
end
|
161
|
-
# f.series(:name=>'Jane',:data=>[1, 3, 4, 3, 3, 5, 4,-46] )
|
162
|
-
f2.title({ :text=>params[:title].to_s})
|
163
|
-
f2.plot_options(series: {
|
164
|
-
stacking:'normal'
|
165
|
-
})
|
166
|
-
f2.chart({ defaultSeriesType: 'scatter'})
|
167
|
-
f2.legend(:layout=> 'horizontal',:style=> {:left=> 'auto', :bottom=> 'auto',:right=> '50px',:top=> '100px'})
|
162
|
+
# f.series(:name=>'Jane',:data=>[1, 3, 4, 3, 3, 5, 4,-46] )
|
163
|
+
f.title({ :text=>params[:title].to_s})
|
164
|
+
f.legend(:layout=> 'horizontal',:style=> {:left=> 'auto', :bottom=> 'auto',:right=> '50px',:top=> '100px'})
|
168
165
|
|
169
166
|
|
170
|
-
|
171
|
-
|
172
|
-
|
167
|
+
### Options for Bar
|
168
|
+
### f.options[:chart][:defaultSeriesType] = "bar"
|
169
|
+
### f.plot_options({:series=>{:stacking=>"normal"}})
|
173
170
|
|
174
|
-
|
175
|
-
|
176
|
-
|
171
|
+
## or options for column
|
172
|
+
# f.options[:chart][:defaultSeriesType] = "column"
|
173
|
+
# f.plot_options({:column=>{:stacking=>"percent"}})
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
177
|
|
178
|
-
|
178
|
+
def set_bargraph
|
179
|
+
if (params[:graphtype].to_s == "Bar Graph")
|
180
|
+
|
181
|
+
# puts "import !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
182
|
+
tempx = params[:xaxis].slice(0..(params[:xaxis].index(' '))) # determine user-given variable name
|
183
|
+
final_x = tempx.strip
|
184
|
+
tempy = params[:yaxis].slice(0..(params[:yaxis].index(' '))) # determine user-given variable name
|
185
|
+
final_y = tempy.strip
|
186
|
+
# instance_variable_set("@#{variable_name}", params[:xaxis])
|
187
|
+
# puts <%= @scope.capitalize %>.pluck(final_x)
|
188
|
+
@barcat=[]
|
189
|
+
@bardata=[]
|
190
|
+
@chartbar = LazyHighCharts::HighChart.new('column') do |f|
|
191
|
+
if (@x_ticks!=nil)
|
192
|
+
@x_ticks.each do |x|
|
193
|
+
@barcat << x[0]
|
194
|
+
@bardata << x[1]
|
195
|
+
end
|
196
|
+
f.xAxis(:categories => @barcat)
|
197
|
+
f.series(:data=> @bardata)
|
198
|
+
else
|
199
|
+
f.xAxis(:categories => <%= @scope.capitalize %>.pluck(final_x))
|
200
|
+
f.series(:data=> <%= @scope.capitalize %>.pluck(final_y))
|
201
|
+
end
|
202
|
+
|
203
|
+
# f.series(:name=>'Jane',:data=>[1, 3, 4, 3, 3, 5, 4,-46] )
|
204
|
+
f.title({ :text=>params[:title].to_s})
|
205
|
+
f.legend(:layout=> 'horizontal',:style=> {:left=> 'auto', :bottom=> 'auto',:right=> '50px',:top=> '100px'})
|
206
|
+
|
207
|
+
|
208
|
+
### Options for Bar
|
209
|
+
### f.options[:chart][:defaultSeriesType] = "bar"
|
210
|
+
### f.plot_options({:series=>{:stacking=>"normal"}})
|
211
|
+
|
212
|
+
## or options for column
|
213
|
+
f.options[:chart][:defaultSeriesType] = "column"
|
214
|
+
# f.plot_options({:column=>{:stacking=>"percent"}})
|
215
|
+
end
|
179
216
|
end
|
180
217
|
end
|
181
218
|
|
182
|
-
|
219
|
+
def set_user_template
|
220
|
+
current_model_path=<%= @scope.capitalize %>.to_s.downcase+"s"
|
221
|
+
@foruser="<%= form_tag(\"/#{current_model_path}/graphgraph\", method: \"get\") do %>
|
222
|
+
<input type=\"text\" name=\"graphtype\" id=\"graphtype\" value=\"#{params[:graphtype]}\" hidden>
|
223
|
+
<input type=\"text\" name=\"yaxis\" id=\"yaxis\" value=\"#{params[:yaxis]}\" hidden>
|
224
|
+
<input type=\"text\" name=\"xaxis\" id=\"xaxis\" value=\"#{params[:xaxis]}\" hidden>
|
225
|
+
<input type=\"text\" name=\"fromuser\" id=\"fromuser\" value=\"fromuser\" hidden>
|
226
|
+
|
227
|
+
<div class='col-sm-2' id=\"datepickerforxview\" hidden>
|
228
|
+
<input type='text' name=\"xstart\" class=\"form-control\" id='datetimepicker1view' />
|
229
|
+
to
|
230
|
+
<input type='text' name=\"xend\" class=\"form-control\" id='datetimepicker2view' /></br>
|
231
|
+
<input type=\"radio\" name=\"rangetypex\" value=\"minute\"> per Minute<br>
|
232
|
+
<input type=\"radio\" name=\"rangetypex\" value=\"hourly\" checked> Hourly<br>
|
233
|
+
<input type=\"radio\" name=\"rangetypex\" value=\"daily\"> Daily<br>
|
234
|
+
<input type=\"radio\" name=\"rangetypex\" value=\"monthly\"> Monthly<br>
|
235
|
+
</div>
|
236
|
+
<%= submit_tag 'Generate Graph', :id=>\"submitselection\"%>
|
237
|
+
<% end %>
|
238
|
+
<script>
|
239
|
+
$(function () {
|
240
|
+
$('#datetimepicker1view').datetimepicker();
|
241
|
+
$('#datetimepicker2view').datetimepicker({
|
242
|
+
useCurrent: false //Important! See issue #1075
|
243
|
+
});
|
244
|
+
$(\"#datetimepicker1view\").on(\"dp.change\", function (e) {
|
245
|
+
$('#datetimepicker2view').data(\"DateTimePicker\").minDate(e.date);
|
246
|
+
});
|
247
|
+
$(\"#datetimepicker2view\").on(\"dp.change\", function (e) {
|
248
|
+
$('#datetimepicker1view').data(\"DateTimePicker\").maxDate(e.date);
|
249
|
+
});
|
250
|
+
});
|
251
|
+
$(document).ready(function() {
|
252
|
+
if (document.getElementById('xaxis').value.indexOf('datetime')!=-1)
|
253
|
+
document.getElementById('datepickerforxview').style.display= \"inline\";
|
254
|
+
else
|
255
|
+
document.getElementById('datepickerforxview').style.display= \"none\";
|
256
|
+
});
|
257
|
+
</script>
|
258
|
+
<% if params[:options]!=nil %>
|
259
|
+
<% newchart=LazyHighCharts::HighChart.new() %>
|
260
|
+
<% newchart.options=eval(params[:options]) %>
|
261
|
+
<% newchart.placeholder=params[:placeholder] %>
|
262
|
+
<% newchart.series_data=eval(params[:series_data]) %>
|
263
|
+
<% if (\"#{params[:graphtype]}\"==\"Bar Graph\") %>
|
264
|
+
<%= high_chart(\"my_bar_div\", newchart) %>
|
265
|
+
<% end %>
|
266
|
+
<% if (\"#{params[:graphtype]}\"==\"Line Graph\") %>
|
267
|
+
<%= high_chart(\"my_line_div\", newchart) %>
|
268
|
+
<% end %>
|
269
|
+
<% if (\"#{params[:graphtype]}\"==\"Area Graph\") %>
|
270
|
+
<%= high_chart(\"my_area_div\", newchart) %>
|
271
|
+
<% end %>
|
272
|
+
<% if (\"#{params[:graphtype]}\"==\"Scatter Graph\") %>
|
273
|
+
<%= high_chart(\"my_scatter_div\", newchart) %>
|
274
|
+
<% end %>
|
275
|
+
<% end %>"
|
276
|
+
end
|
183
277
|
|
184
278
|
def get_counts(dateValue,pluckValue,startvalue,endvalue)
|
185
279
|
@newx= startvalue
|
@@ -238,8 +332,16 @@ class <%= @scope_prefix %>GraphgraphsController < ApplicationController
|
|
238
332
|
end
|
239
333
|
# @groups = [:camera_id, "year(#{ts_conversion})", "month(#{ts_conversion})"]
|
240
334
|
end
|
241
|
-
|
242
|
-
|
243
|
-
#
|
335
|
+
|
336
|
+
|
337
|
+
# @counts = LicensePlate.
|
338
|
+
# where(camera_id: @cameras.map { |cam| cam.id }).
|
339
|
+
# where('timestamp >= ?', @begin_date).
|
340
|
+
# where('timestamp <= ?', @end_date).
|
341
|
+
# where('license_id like ?', "%#{@plate_query}%").
|
342
|
+
# group(@groups).count
|
343
|
+
# @series = @cameras.map do |cam|
|
344
|
+
# { name: cam.name, yAxis: 0, data: @x_ticks.map { |xtick| @counts[counts_index(cam, xtick)] || 0 } }
|
244
345
|
# end
|
245
346
|
end
|
347
|
+
end
|
@@ -59,9 +59,7 @@
|
|
59
59
|
$('#datetimepicker3').data("DateTimePicker").maxDate(e.date);
|
60
60
|
});
|
61
61
|
});
|
62
|
-
function showSource(
|
63
|
-
console.log(dividsource);
|
64
|
-
document.getElementById("sourceArea").value=document.getElementById(dividsource).innerHTML;
|
62
|
+
function showSource() {
|
65
63
|
document.getElementById("sourceArea").style.display="block";
|
66
64
|
}
|
67
65
|
function typecheckx(){
|
@@ -125,19 +123,19 @@
|
|
125
123
|
<br>
|
126
124
|
<% if (params[:graphtype]=="Bar Graph") %>
|
127
125
|
<%= high_chart("my_bar_div", @chartbar) %>
|
128
|
-
<button onclick="showSource(
|
126
|
+
<button onclick="showSource()">Show Source</button>
|
129
127
|
<% end %>
|
130
128
|
<% if (params[:graphtype]=="Line Graph") %>
|
131
129
|
<%= high_chart("my_line_div", @chartline) %>
|
132
|
-
<button onclick="showSource(
|
130
|
+
<button onclick="showSource()">Show Source</button>
|
133
131
|
<% end %>
|
134
132
|
<% if (params[:graphtype]=="Area Graph") %>
|
135
133
|
<%= high_chart("my_area_div", @chartarea) %>
|
136
|
-
<button onclick="showSource(
|
134
|
+
<button onclick="showSource()">Show Source</button>
|
137
135
|
<% end %>
|
138
136
|
<% if (params[:graphtype]=="Scatter Graph") %>
|
139
137
|
<%= high_chart("my_scatter_div", @chartscatter) %>
|
140
|
-
<button onclick="showSource(
|
138
|
+
<button onclick="showSource()">Show Source</button>
|
141
139
|
<% end %>
|
142
140
|
|
143
|
-
<textarea id="sourceArea" style="width: 900px; height: 300px;" hidden
|
141
|
+
<textarea id="sourceArea" style="width: 900px; height: 300px;" hidden><%= @foruser.html_safe %></textarea>
|
data/lib/graphgraph/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: graphgraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Suhas Shrestha
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -170,6 +170,7 @@ files:
|
|
170
170
|
- bin/setup
|
171
171
|
- config/routes.rb
|
172
172
|
- graphgraph-0.2.0.gem
|
173
|
+
- graphgraph-0.3.0.gem
|
173
174
|
- graphgraph.gemspec
|
174
175
|
- lib/generators/graphgraph/controllers_generator.rb
|
175
176
|
- lib/generators/graphgraph/install_generator.rb
|
@@ -205,4 +206,3 @@ signing_key:
|
|
205
206
|
specification_version: 4
|
206
207
|
summary: This gem will generate graphs based on models it is wrapped around.
|
207
208
|
test_files: []
|
208
|
-
has_rdoc:
|