tomwalters@0
|
1 % method of class @frame
|
tomwalters@0
|
2 %
|
tomwalters@0
|
3 % INPUT VALUES:
|
tomwalters@0
|
4 %
|
tomwalters@0
|
5 % RETURN VALUE:
|
tomwalters@0
|
6 %
|
tomwalters@0
|
7 %
|
tomwalters@0
|
8 % (c) 2003, University of Cambridge, Medical Research Council
|
tomwalters@0
|
9 % Stefan Bleeck (stefan@bleeck.de)
|
tomwalters@0
|
10 % http://www.mrc-cbu.cam.ac.uk/cnbh/aimmanual
|
tomwalters@0
|
11 % $Date: 2003/06/27 16:05:26 $
|
tomwalters@0
|
12 % $Revision: 1.16 $
|
tomwalters@0
|
13
|
tomwalters@0
|
14 function handlestr=plot(current_frame,options,ax)
|
tomwalters@0
|
15
|
tomwalters@0
|
16
|
tomwalters@0
|
17 if nargin < 3
|
tomwalters@0
|
18 ax=gca;
|
tomwalters@0
|
19 end
|
tomwalters@0
|
20 if nargin < 2
|
tomwalters@0
|
21 options=[];
|
tomwalters@0
|
22 end
|
tomwalters@0
|
23
|
tomwalters@0
|
24 % options.plotstyle='surf';
|
tomwalters@0
|
25
|
tomwalters@0
|
26 % extra options from aimmodules?
|
tomwalters@0
|
27 if isfield(options,'extra_options');
|
tomwalters@0
|
28 has_extra_options=1; % in this case, jump at the end to a fucntion that makes colors
|
tomwalters@0
|
29 else
|
tomwalters@0
|
30 has_extra_options=0; % no extras in colors
|
tomwalters@0
|
31 end
|
tomwalters@0
|
32
|
tomwalters@0
|
33 % weather of not the plotting is linear
|
tomwalters@0
|
34 if ~isfield(options,'is_log');
|
tomwalters@0
|
35 is_log=0;
|
tomwalters@0
|
36 else
|
tomwalters@0
|
37 is_log=options.is_log;
|
tomwalters@0
|
38 end
|
tomwalters@0
|
39
|
tomwalters@0
|
40 % the viewpoint in azimuth and elevation look help for view!
|
tomwalters@0
|
41 if ~isfield(options,'viewpoint');
|
tomwalters@0
|
42 viewpoint=[0 90];
|
tomwalters@0
|
43 else
|
tomwalters@0
|
44 viewpoint=options.viewpoint;
|
tomwalters@0
|
45 end
|
tomwalters@0
|
46
|
tomwalters@0
|
47 % which plot type, usually: waterfall, other: surf
|
tomwalters@0
|
48 if ~isfield(options,'plotstyle');
|
tomwalters@0
|
49 plotstyle='waterfall';
|
tomwalters@0
|
50 else
|
tomwalters@0
|
51 plotstyle=options.plotstyle;
|
tomwalters@0
|
52 end
|
tomwalters@0
|
53
|
tomwalters@0
|
54 % if waterfall, the plotcolor can be more complicated
|
tomwalters@0
|
55 if ~isfield(options,'plotcolor');
|
tomwalters@0
|
56 has_specified_color=0;
|
tomwalters@0
|
57 else
|
tomwalters@0
|
58 plotcolor=options.plotcolor;
|
tomwalters@0
|
59 has_specified_color=1;
|
tomwalters@0
|
60 end
|
tomwalters@0
|
61
|
tomwalters@0
|
62 % if positive time is to the right or to the left
|
tomwalters@0
|
63 if isfield(options,'time_reversed');
|
tomwalters@0
|
64 time_reversed=options.time_reversed;
|
tomwalters@0
|
65 else
|
tomwalters@0
|
66 time_reversed=0;
|
tomwalters@0
|
67 end
|
tomwalters@0
|
68
|
tomwalters@0
|
69 % for compatibility.
|
tomwalters@0
|
70 if isfield(options,'minimum_time');
|
tomwalters@0
|
71 options.minimum_time_interval=options.minimum_time;
|
tomwalters@0
|
72 end
|
tomwalters@0
|
73 if isfield(options,'maximum_time');
|
tomwalters@0
|
74 options.maximum_time_interval=options.maximum_time;
|
tomwalters@0
|
75 end
|
tomwalters@0
|
76 if ~isfield(options,'minimum_time_interval');
|
tomwalters@0
|
77 if is_log
|
tomwalters@0
|
78 minimum_time_interval=0.001;
|
tomwalters@0
|
79 else
|
tomwalters@0
|
80 minimum_time_interval=getminimumtime(current_frame);
|
tomwalters@0
|
81 end
|
tomwalters@0
|
82 else
|
tomwalters@0
|
83 minimum_time_interval=options.minimum_time_interval;
|
tomwalters@0
|
84 end
|
tomwalters@0
|
85
|
tomwalters@0
|
86
|
tomwalters@0
|
87 if ~isfield(options,'maximum_time_interval');
|
tomwalters@0
|
88 % maximum_time_interval=0.035;
|
tomwalters@0
|
89 maximum_time_interval=getmaximumtime(current_frame);
|
tomwalters@0
|
90 else
|
tomwalters@0
|
91 maximum_time_interval=options.maximum_time_interval;
|
tomwalters@0
|
92 end
|
tomwalters@0
|
93
|
tomwalters@0
|
94
|
tomwalters@0
|
95 if ~isfield(options,'has_x_axis');
|
tomwalters@0
|
96 has_x_axis=1;
|
tomwalters@0
|
97 else
|
tomwalters@0
|
98 has_x_axis=options.has_x_axis;
|
tomwalters@0
|
99 end
|
tomwalters@0
|
100
|
tomwalters@0
|
101 if ~isfield(options,'has_y_axis');
|
tomwalters@0
|
102 has_y_axis=1;
|
tomwalters@0
|
103 else
|
tomwalters@0
|
104 has_y_axis=options.has_y_axis;
|
tomwalters@0
|
105 end
|
tomwalters@0
|
106
|
tomwalters@0
|
107
|
tomwalters@0
|
108
|
tomwalters@0
|
109 current_frame_values=getvalues(current_frame);
|
tomwalters@0
|
110 nr_channels=getnrchannels(current_frame);
|
tomwalters@0
|
111 sr=getsr(current_frame);
|
tomwalters@0
|
112
|
tomwalters@0
|
113 % prevent a matlab plotting-bug for empty matrices
|
tomwalters@0
|
114 if max(max(current_frame_values))==0 && min(min(current_frame_values)) == 0
|
tomwalters@0
|
115 current_frame_values(1,400)=0.001;
|
tomwalters@0
|
116 end
|
tomwalters@0
|
117
|
tomwalters@0
|
118 % length=getlength(current_frame);
|
tomwalters@0
|
119 start_time=getminimumtime(current_frame);
|
tomwalters@0
|
120
|
tomwalters@0
|
121 if start_time < 0 % these are frames read in from ams! they start with negative times. Therefore we turn around the start and stoptime
|
tomwalters@0
|
122 % temp=-maximum_time_interval;
|
tomwalters@0
|
123 % maximum_time_interval=-minimum_time_interval;
|
tomwalters@0
|
124 % minimum_time_interval=temp;
|
tomwalters@0
|
125 % time_reversed=1-time_reversed;
|
tomwalters@0
|
126 % current_frame=reverse(current_frame);
|
tomwalters@0
|
127 % % max_time=getmaximumtime(current_frame);
|
tomwalters@0
|
128 % fr=getpart(current_frame,start_time,0);
|
tomwalters@0
|
129 % start_time=0;
|
tomwalters@0
|
130 % current_frame=setstarttime(current_frame,0);
|
tomwalters@0
|
131 end
|
tomwalters@0
|
132
|
tomwalters@0
|
133 if is_log
|
tomwalters@0
|
134 min_x_screen=1; % im logarithmischen Fall muss ich die ersten Punkte mitnehmen, damit ich sie plotten kann!
|
tomwalters@0
|
135 max_x_screen=round(abs((maximum_time_interval-start_time)*sr)); % thats the first point we want to see on the screen
|
tomwalters@0
|
136 else
|
tomwalters@0
|
137 min_x_screen=round(abs((minimum_time_interval-start_time+1/sr)*sr)); % thats the first point we want to see on the screen
|
tomwalters@0
|
138 max_x_screen=round(abs((maximum_time_interval-start_time)*sr)); % thats the first point we want to see on the screen
|
tomwalters@0
|
139 end
|
tomwalters@0
|
140
|
tomwalters@0
|
141 if max_x_screen>getnrpoints(current_frame)
|
tomwalters@0
|
142 max_x_screen=getnrpoints(current_frame);
|
tomwalters@0
|
143 maximum_time_interval=(max_x_screen/sr)+start_time;
|
tomwalters@0
|
144 end
|
tomwalters@0
|
145
|
tomwalters@0
|
146 step=1;
|
tomwalters@0
|
147 if isequal(plotstyle,'surf')
|
tomwalters@0
|
148 step=1;
|
tomwalters@0
|
149 elseif isequal(plotstyle,'waterfall')
|
tomwalters@0
|
150 oldunit2=get(ax,'Units');
|
tomwalters@0
|
151 set(ax,'Units','Pixel');
|
tomwalters@0
|
152 pos=get(ax,'Position');
|
tomwalters@0
|
153 breite=pos(3)/2;
|
tomwalters@0
|
154 step=round((max_x_screen-min_x_screen)/breite);
|
tomwalters@0
|
155 % step=1;
|
tomwalters@0
|
156 if step<1 || nr_channels==1
|
tomwalters@0
|
157 step=1;
|
tomwalters@0
|
158 end
|
tomwalters@0
|
159 set(ax,'Units',oldunit2);
|
tomwalters@0
|
160
|
tomwalters@0
|
161 if min_x_screen>2
|
tomwalters@0
|
162 current_frame_values(:,1:min_x_screen-1)=0;
|
tomwalters@0
|
163 end
|
tomwalters@0
|
164 end
|
tomwalters@0
|
165
|
tomwalters@0
|
166
|
tomwalters@0
|
167 cvals=current_frame_values(:,min_x_screen:step:max_x_screen);
|
tomwalters@0
|
168 if nr_channels==1
|
tomwalters@0
|
169 handle=plot(ax,cvals);
|
tomwalters@0
|
170 ylabel('');
|
tomwalters@0
|
171 % set(ax,'YTick',[]);
|
tomwalters@0
|
172 else
|
tomwalters@0
|
173 if strcmp(plotstyle,'surf')
|
tomwalters@0
|
174 % handle=surf(ax,cvals,'LineStyle','none');
|
tomwalters@0
|
175 handle=surf(ax,cvals,'LineStyle','none');
|
tomwalters@0
|
176 % view(ax,viewpoint);
|
tomwalters@0
|
177 view(ax,[0 90]);
|
tomwalters@0
|
178 else
|
tomwalters@0
|
179 handle=waterfall(ax,cvals); % do the plotting!
|
tomwalters@0
|
180 % this is a very important trick: If we plot it from directly above ([0 80])
|
tomwalters@0
|
181 % then white lines appear on the screen. To get rid of them, we have to
|
tomwalters@0
|
182 % tilt the waterfall just marginally:
|
tomwalters@0
|
183 % if min(min(cvals))<0
|
tomwalters@0
|
184 % view(ax,[viewpoint(1)-0.01 viewpoint(2)]);
|
tomwalters@0
|
185 % else
|
tomwalters@0
|
186 view(ax,[-0.01 80]);
|
tomwalters@0
|
187 % view(ax,viewpoint);
|
tomwalters@0
|
188 % end
|
tomwalters@0
|
189 end
|
tomwalters@0
|
190 grid off;
|
tomwalters@0
|
191 end
|
tomwalters@0
|
192
|
tomwalters@0
|
193 if time_reversed
|
tomwalters@0
|
194 set(ax,'XDir','reverse') % turn them around, because the higher values shell end on the right
|
tomwalters@0
|
195 else
|
tomwalters@0
|
196 set(ax,'XDir','normal') % normale ausrichtung
|
tomwalters@0
|
197 end
|
tomwalters@0
|
198 if is_log
|
tomwalters@0
|
199 min_x_screen=round(abs((minimum_time_interval-start_time+1/sr)*sr)); % thats the first point we want to see on the screen
|
tomwalters@0
|
200 if nr_channels==1
|
tomwalters@0
|
201 set(ax,'xlim',[min_x_screen max_x_screen ])
|
tomwalters@0
|
202 set(ax,'ylim',[0 1])
|
tomwalters@0
|
203 % axis([ 0 1]);
|
tomwalters@0
|
204 else
|
tomwalters@0
|
205 if max_x_screen == min_x_screen
|
tomwalters@0
|
206 max_x_screen = min_x_screen +1;
|
tomwalters@0
|
207 end
|
tomwalters@0
|
208 set(ax,'xlim',[min_x_screen max_x_screen])
|
tomwalters@0
|
209 set(ax,'ylim',[1 nr_channels])
|
tomwalters@0
|
210 set(ax,'zlim',[0 50])
|
tomwalters@0
|
211
|
tomwalters@0
|
212 % axis([ min_x_screen max_x_screen 1 nr_channels 0 50]);
|
tomwalters@0
|
213 end
|
tomwalters@0
|
214 set(ax,'XScale','log')
|
tomwalters@0
|
215 t=minimum_time_interval;
|
tomwalters@0
|
216 ti=[t 2*t 4*t 8*t 16*t 32*t 64*t];
|
tomwalters@0
|
217 tix=(ti)*sr; % there shell be the tix
|
tomwalters@0
|
218 % tix(1)=tix(1)+1;
|
tomwalters@0
|
219 ti=(ti*1000);
|
tomwalters@0
|
220 ti=fround(ti,2);
|
tomwalters@0
|
221 else % its not logarithmic!
|
tomwalters@0
|
222 set(ax,'XScale','linear')
|
tomwalters@0
|
223 nrx=size(cvals,2);
|
tomwalters@0
|
224 if nr_channels==1
|
tomwalters@0
|
225 miny=min(cvals);
|
tomwalters@0
|
226 maxy=max(cvals);
|
tomwalters@0
|
227 set(ax,'xlim',[1 nrx])
|
tomwalters@0
|
228 set(ax,'ylim',[miny*1.3 maxy*1.3])
|
tomwalters@0
|
229 % axis([ 1 nrx miny*1.3 maxy*1.3]);
|
tomwalters@0
|
230 else
|
tomwalters@0
|
231 set(ax,'xlim',[1 nrx])
|
tomwalters@0
|
232 set(ax,'ylim',[1 nr_channels ])
|
tomwalters@0
|
233 set(ax,'zlim',[0 1])
|
tomwalters@0
|
234
|
tomwalters@0
|
235 % axis([ 1 nrx 1 nr_channels 0 1]);
|
tomwalters@0
|
236 end
|
tomwalters@0
|
237 nr_labels=8;
|
tomwalters@0
|
238 tix=1:(nrx-1)/nr_labels:nrx;
|
tomwalters@0
|
239 xstep=(maximum_time_interval-minimum_time_interval)*1000/(nr_labels); %works from -35 to 5
|
tomwalters@0
|
240 ti=([minimum_time_interval*1000:xstep:maximum_time_interval*1000+1]);
|
tomwalters@0
|
241 ti=fround(ti,1);
|
tomwalters@0
|
242 % text(min_x_screen*1.5,-scale_summe/5,'Time (ms)'); % this is at a nice position
|
tomwalters@0
|
243 end
|
tomwalters@0
|
244
|
tomwalters@0
|
245 if has_x_axis
|
tomwalters@0
|
246 if max(tix)>1
|
tomwalters@0
|
247 set(ax,'XTick',tix);
|
tomwalters@0
|
248 set(ax,'XTickLabel',ti);
|
tomwalters@0
|
249 end
|
tomwalters@0
|
250 else
|
tomwalters@0
|
251 set(ax,'xtick',[]); % we dont want any z-Ticks!
|
tomwalters@0
|
252 end % axis
|
tomwalters@0
|
253
|
tomwalters@0
|
254 if has_y_axis && nr_channels>1
|
tomwalters@0
|
255 % make y-Ticks
|
tomwalters@0
|
256 nr_labels=8;
|
tomwalters@0
|
257 ystep=(nr_channels-1)/(nr_labels-1);
|
tomwalters@0
|
258 tiy=1:ystep:nr_channels;
|
tomwalters@0
|
259 ti=(current_frame.centerfrequencies(floor(tiy))/1000);
|
tomwalters@0
|
260 ti=round(ti*10)/10;
|
tomwalters@0
|
261 set(ax,'YTick',tiy);
|
tomwalters@0
|
262 set(ax,'YTickLabel',ti);
|
tomwalters@0
|
263
|
tomwalters@0
|
264 % if has_x_axis
|
tomwalters@0
|
265 % if is_log
|
tomwalters@0
|
266 % text(min_x_screen*1.9,-2,current_frame.x_axis_label); % this is at a nice position
|
tomwalters@0
|
267 % else
|
tomwalters@0
|
268 % text(120,-2,current_frame.x_axis_label); % this is at a nice position
|
tomwalters@0
|
269 % end
|
tomwalters@0
|
270 % end
|
tomwalters@0
|
271 elseif nr_channels>1
|
tomwalters@0
|
272 set(ax,'ytick',[]); % we dont want any z-Ticks!
|
tomwalters@0
|
273 end
|
tomwalters@0
|
274
|
tomwalters@0
|
275 set(ax,'ztick',[]); % we dont want any z-Ticks!
|
tomwalters@0
|
276
|
tomwalters@0
|
277
|
tomwalters@0
|
278 if strcmp(plotstyle,'surf')
|
tomwalters@0
|
279 % which colormap should be used in case of a surf-plot
|
tomwalters@0
|
280 if ~isfield(options,'colormap');
|
tomwalters@0
|
281 clrmap=zeros(64,3);
|
tomwalters@0
|
282 else
|
tomwalters@0
|
283 clrmap=options.colormap;
|
tomwalters@0
|
284 end
|
tomwalters@0
|
285
|
tomwalters@0
|
286 % shift the colormap
|
tomwalters@0
|
287
|
tomwalters@0
|
288 % set the chosen colormap
|
tomwalters@0
|
289 colormap(clrmap);
|
tomwalters@0
|
290 % set the color limits so that it shows all colors
|
tomwalters@0
|
291 set(ax,'CLimMode','manual');
|
tomwalters@0
|
292
|
tomwalters@0
|
293 colmin=0;
|
tomwalters@0
|
294 colmax=max(max(cvals));
|
tomwalters@0
|
295 diff=colmax-colmin;
|
tomwalters@0
|
296
|
tomwalters@0
|
297 % if ~isfield(options,'shiftcolormap');
|
tomwalters@0
|
298 % shiftcolormap=0.8;
|
tomwalters@0
|
299 % else
|
tomwalters@0
|
300 % shiftcolormap=options.shiftcolormap;
|
tomwalters@0
|
301 % end
|
tomwalters@0
|
302 % colmin=colmax-2*shiftcolormap*diff;
|
tomwalters@0
|
303 % if colmax==colmin
|
tomwalters@0
|
304 % colmax=colmin+0.001;
|
tomwalters@0
|
305 % end
|
tomwalters@0
|
306
|
tomwalters@0
|
307 % set(ax,'CLim',[colmin colmax]);
|
tomwalters@0
|
308
|
tomwalters@0
|
309 % % colorbar is 1:256
|
tomwalters@0
|
310 % % actual spectrogram dynamic range is orig_dr
|
tomwalters@0
|
311 % % new spectrogram dynamic range is new_dr
|
tomwalters@0
|
312 % orig_dr = clrmap;
|
tomwalters@0
|
313 % diff_dr = new_dr - orig_dr;
|
tomwalters@0
|
314 % cmapIndices_per_dB = 256./diff(orig_dr); % a constant
|
tomwalters@0
|
315 % diff_clim = diff_dr .* cmapIndices_per_dB;
|
tomwalters@0
|
316 % cbar_clim = [1 256] + diff_clim;
|
tomwalters@0
|
317 % % set(himage_cbar,'cdatamapping','scaled'); % do during creation
|
tomwalters@0
|
318 % set(ax,'clim',cbar_clim);
|
tomwalters@0
|
319
|
tomwalters@0
|
320
|
tomwalters@0
|
321
|
tomwalters@0
|
322 % view(ax,viewpoint);
|
tomwalters@0
|
323
|
tomwalters@0
|
324 % fancy graphics, takes time
|
tomwalters@0
|
325 % shading interp
|
tomwalters@0
|
326 % if isfield(options,'camlight');
|
tomwalters@0
|
327 % % can be 'left','right' or a vector of [az el]
|
tomwalters@0
|
328 % if isnumeric(options.camlight)
|
tomwalters@0
|
329 % for i=1:size(options.camlight,1)
|
tomwalters@0
|
330 % eval(sprintf('lightangle(%f,%f);',options.camlight(i,1),options.camlight(i,2)));
|
tomwalters@0
|
331 % end
|
tomwalters@0
|
332 % else
|
tomwalters@0
|
333 % eval(sprintf('camlight(''%s'',''infinite'');',options.camlight));
|
tomwalters@0
|
334 % end
|
tomwalters@0
|
335 % end
|
tomwalters@0
|
336 %
|
tomwalters@0
|
337 % material default % looks best other options: dull, metal, shiny
|
tomwalters@0
|
338 %
|
tomwalters@0
|
339 % %
|
tomwalters@0
|
340 % if isfield(options,'lighting');
|
tomwalters@0
|
341 % eval(sprintf('lighting %s',options.lighting));
|
tomwalters@0
|
342 % end
|
tomwalters@0
|
343
|
tomwalters@0
|
344 % wheather or not there should be a colorbar
|
tomwalters@0
|
345 % can be 'off', 'vertical, 'horizontal'
|
tomwalters@0
|
346 if isfield(options,'colorbar');
|
tomwalters@0
|
347 if ~strcmp(options.colorbar,'off')
|
tomwalters@0
|
348 colorbar(options.colorbar);
|
tomwalters@0
|
349 end
|
tomwalters@0
|
350 end
|
tomwalters@0
|
351
|
tomwalters@0
|
352 else % boring waterfall plot
|
tomwalters@0
|
353 if has_specified_color==1
|
tomwalters@0
|
354 if plotcolor=='k'
|
tomwalters@0
|
355 clrmap(:,:)=0;
|
tomwalters@0
|
356 elseif plotcolor=='r'
|
tomwalters@0
|
357 clrmap(:,1)=0;
|
tomwalters@0
|
358 elseif plotcolor=='c'
|
tomwalters@0
|
359 clrmap(:,2)=0;
|
tomwalters@0
|
360 elseif plotcolor=='g'
|
tomwalters@0
|
361 clrmap(:,3)=0;
|
tomwalters@0
|
362 end
|
tomwalters@0
|
363 else
|
tomwalters@0
|
364 % if nothing is set, then set everything is set to black
|
tomwalters@0
|
365 clrmap=white;
|
tomwalters@0
|
366 clrmap(:,:)=0;
|
tomwalters@0
|
367 colormap(clrmap);
|
tomwalters@0
|
368 end
|
tomwalters@0
|
369 end
|
tomwalters@0
|
370
|
tomwalters@0
|
371
|
tomwalters@0
|
372 % if is_log
|
tomwalters@0
|
373 % x=300;y=nr_channels*1.1;
|
tomwalters@0
|
374 % else
|
tomwalters@0
|
375 % x=300;y=nr_channels*1.1;
|
tomwalters@0
|
376 % end
|
tomwalters@0
|
377 % text(x,y,current_frame.text); % this is at a nice position
|
tomwalters@0
|
378
|
tomwalters@0
|
379 % if isfield(options,'display_time')
|
tomwalters@0
|
380 % if options.display_time==1
|
tomwalters@0
|
381 % time=getcurrentframestarttime(current_frame);
|
tomwalters@0
|
382 % time=fround(time*1000,0);
|
tomwalters@0
|
383 % str=num2str(time);
|
tomwalters@0
|
384 % text(x,y,[str ' ms']); % this is at a nice position
|
tomwalters@0
|
385 % end
|
tomwalters@0
|
386 % end
|
tomwalters@0
|
387
|
tomwalters@0
|
388 if has_extra_options==1; % in this case, jump at the end to a fucntion that makes colors
|
tomwalters@0
|
389
|
tomwalters@0
|
390 % cool_frame_plot_colors(current_frame,handle,options.extra_options);
|
tomwalters@0
|
391
|
tomwalters@0
|
392 end
|
tomwalters@0
|
393
|
tomwalters@0
|
394 % set(ax,'XDir',olddir)
|
tomwalters@0
|
395 % set(ax,'XScale',oldscale);
|
tomwalters@0
|
396
|
tomwalters@0
|
397 if nargout==1
|
tomwalters@0
|
398 handlestr=handle;
|
tomwalters@0
|
399 end
|