plplot 0.0.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.
- data/README +115 -0
- data/examples/x01.rb +284 -0
- data/examples/x02.rb +134 -0
- data/examples/x03.rb +81 -0
- data/examples/x04.rb +98 -0
- data/examples/x05.rb +33 -0
- data/examples/x06.rb +62 -0
- data/examples/x07.rb +69 -0
- data/examples/x08.rb +179 -0
- data/examples/x09.rb +371 -0
- data/examples/x10.rb +29 -0
- data/examples/x11.rb +151 -0
- data/examples/x12.rb +65 -0
- data/examples/x13.rb +86 -0
- data/examples/x14.rb +391 -0
- data/examples/x15.rb +266 -0
- data/examples/x16.rb +349 -0
- data/examples/x18.rb +146 -0
- data/examples/x20.rb +360 -0
- data/examples/x21.rb +280 -0
- data/examples/x22.rb +242 -0
- data/examples/x23.rb +361 -0
- data/examples/x24.rb +126 -0
- data/examples/x25.rb +114 -0
- data/examples/x26.rb +180 -0
- data/examples/x27.rb +124 -0
- data/examples/x28.rb +369 -0
- data/examples/x30.rb +141 -0
- data/examples/x31.rb +238 -0
- data/examples/x32.rb +159 -0
- data/ext/depend +1 -0
- data/ext/extconf.rb +75 -0
- data/ext/rbplplot.c +4982 -0
- data/lib/plplot.rb +101 -0
- metadata +115 -0
data/examples/x18.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$-w = true if $0 == __FILE__
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'plplot'
|
6
|
+
include PLplot
|
7
|
+
include Math
|
8
|
+
|
9
|
+
# 3-d line and point plot demo. Adapted from x08.rb.
|
10
|
+
|
11
|
+
OPT = [ 1, 0, 1, 0 ]
|
12
|
+
ALT = [ 20.0, 35.0, 50.0, 65.0 ]
|
13
|
+
AZ = [ 30.0, 40.0, 50.0, 60.0 ]
|
14
|
+
|
15
|
+
TWO_PI = 2 * PI
|
16
|
+
|
17
|
+
def theta(a)
|
18
|
+
TWO_PI * a / 20.0
|
19
|
+
end
|
20
|
+
|
21
|
+
def phi(a)
|
22
|
+
PI * a / 20.1
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_poly(k)
|
26
|
+
draw = [
|
27
|
+
[ 1, 1, 1, 1 ],
|
28
|
+
[ 1, 0, 1, 0 ],
|
29
|
+
[ 0, 1, 0, 1 ],
|
30
|
+
[ 1, 1, 0, 0 ]
|
31
|
+
]
|
32
|
+
|
33
|
+
x = NArray.float(5)
|
34
|
+
y = NArray.float(5)
|
35
|
+
z = NArray.float(5)
|
36
|
+
|
37
|
+
pladv(0)
|
38
|
+
plvpor(0.0, 1.0, 0.0, 0.9)
|
39
|
+
plwind(-1.0, 1.0, -0.9, 1.1)
|
40
|
+
plcol0(1)
|
41
|
+
plw3d(1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, ALT[k], AZ[k])
|
42
|
+
plbox3("bnstu", "x axis", 0.0, 0,
|
43
|
+
"bnstu", "y axis", 0.0, 0,
|
44
|
+
"bcdmnstuv", "z axis", 0.0, 0)
|
45
|
+
|
46
|
+
plcol0(2)
|
47
|
+
|
48
|
+
# x = r sin(phi) cos(theta)
|
49
|
+
# y = r sin(phi) sin(theta)
|
50
|
+
# z = r cos(phi)
|
51
|
+
# r = 1 :=)
|
52
|
+
|
53
|
+
20.times do |i|
|
54
|
+
20.times do |j|
|
55
|
+
x[0] = sin(phi(j)) * cos(theta(i))
|
56
|
+
y[0] = sin(phi(j)) * sin(theta(i))
|
57
|
+
z[0] = cos(phi(j))
|
58
|
+
|
59
|
+
x[1] = sin(phi(j + 1)) * cos(theta(i))
|
60
|
+
y[1] = sin(phi(j + 1)) * sin(theta(i))
|
61
|
+
z[1] = cos(phi(j + 1))
|
62
|
+
|
63
|
+
x[2] = sin(phi(j + 1)) * cos(theta(i + 1))
|
64
|
+
y[2] = sin(phi(j + 1)) * sin(theta(i + 1))
|
65
|
+
z[2] = cos(phi(j + 1))
|
66
|
+
|
67
|
+
x[3] = sin(phi(j)) * cos(theta(i + 1))
|
68
|
+
y[3] = sin(phi(j)) * sin(theta(i + 1))
|
69
|
+
z[3] = cos(phi(j))
|
70
|
+
|
71
|
+
x[4] = sin(phi(j)) * cos(theta(i))
|
72
|
+
y[4] = sin(phi(j)) * sin(theta(i))
|
73
|
+
z[4] = cos(phi(j))
|
74
|
+
|
75
|
+
plpoly3(x, y, z, draw[k], 1)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
plcol0(3)
|
80
|
+
plmtex("t", 1.0, 0.5, 0.5, "unit radius sphere")
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
#--------------------------------------------------------------------------\
|
85
|
+
# Does a series of 3-d plots for a given data set, with different
|
86
|
+
# viewing options in each plot.
|
87
|
+
#--------------------------------------------------------------------------/
|
88
|
+
|
89
|
+
NPTS = 1000
|
90
|
+
|
91
|
+
# Parse and process command line arguments
|
92
|
+
|
93
|
+
PLOptionParser.parse!
|
94
|
+
|
95
|
+
# Initialize plplot
|
96
|
+
|
97
|
+
plinit
|
98
|
+
|
99
|
+
4.times do |k|
|
100
|
+
test_poly(k)
|
101
|
+
end
|
102
|
+
|
103
|
+
x = NArray.float(NPTS)
|
104
|
+
y = NArray.float(NPTS)
|
105
|
+
z = NArray.float(NPTS)
|
106
|
+
|
107
|
+
# From the mind of a sick and twisted physicist...
|
108
|
+
|
109
|
+
NPTS.times do |i|
|
110
|
+
z[i] = -1.0 + 2.0 * i / NPTS
|
111
|
+
|
112
|
+
# Pick one ...
|
113
|
+
|
114
|
+
# r = 1.0 - (i.to_f / NPTS)
|
115
|
+
r = z[i]
|
116
|
+
|
117
|
+
x[i] = r * cos(2.0 * PI * 6.0 * i / NPTS)
|
118
|
+
y[i] = r * sin(2.0 * PI * 6.0 * i / NPTS)
|
119
|
+
end
|
120
|
+
|
121
|
+
4.times do |k|
|
122
|
+
pladv(0)
|
123
|
+
plvpor(0.0, 1.0, 0.0, 0.9)
|
124
|
+
plwind(-1.0, 1.0, -0.9, 1.1)
|
125
|
+
plcol0(1)
|
126
|
+
plw3d(1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, ALT[k], AZ[k])
|
127
|
+
plbox3("bnstu", "x axis", 0.0, 0,
|
128
|
+
"bnstu", "y axis", 0.0, 0,
|
129
|
+
"bcdmnstuv", "z axis", 0.0, 0)
|
130
|
+
|
131
|
+
plcol0(2)
|
132
|
+
|
133
|
+
if OPT[k] != 0
|
134
|
+
plline3(x, y, z)
|
135
|
+
else
|
136
|
+
plpoin3(x, y, z, 1)
|
137
|
+
end
|
138
|
+
|
139
|
+
plcol0(3)
|
140
|
+
title = sprintf("#frPLplot Example 18 - Alt=%.0f, Az=%.0f",
|
141
|
+
ALT[k], AZ[k])
|
142
|
+
plmtex("t", 1.0, 0.5, 0.5, title)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Clean up
|
146
|
+
plend
|
data/examples/x20.rb
ADDED
@@ -0,0 +1,360 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$-w = true if $0 == __FILE__
|
3
|
+
|
4
|
+
require 'scanf'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'plplot'
|
7
|
+
include PLplot
|
8
|
+
include Math
|
9
|
+
|
10
|
+
# plimage demo
|
11
|
+
|
12
|
+
XDIM = 260
|
13
|
+
YDIM = 220
|
14
|
+
|
15
|
+
StretchData = Struct.new(
|
16
|
+
:xmin, :xmax, :ymin, :ymax,
|
17
|
+
:stretch
|
18
|
+
)
|
19
|
+
|
20
|
+
# Defaults for user options. Use global variables to track user options since
|
21
|
+
# that matches the C example most closely.
|
22
|
+
|
23
|
+
$dbg = false
|
24
|
+
$nosombrero = false
|
25
|
+
$nointeractive = false
|
26
|
+
$f_name = nil
|
27
|
+
|
28
|
+
PLOP = PLOptionParser.new do |op|
|
29
|
+
op.separator('')
|
30
|
+
op.separator('x20 options:')
|
31
|
+
op.on('--dbg', "Extra debugging plot") do
|
32
|
+
$dbg = true
|
33
|
+
end
|
34
|
+
op.on('--nosombrero', "No sombrero plot") do
|
35
|
+
$nosombrero = true
|
36
|
+
end
|
37
|
+
op.on('--nointeractive', "No interactive selection") do
|
38
|
+
$nointeractive = true
|
39
|
+
end
|
40
|
+
op.on('--save FILENAME', "Save sombrero plot in color", "postscript file FILENAME") do |o|
|
41
|
+
$f_name = o
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Transformation function
|
46
|
+
def mypltr(x, y, s)
|
47
|
+
x0 = (s.xmin + s.xmax) * 0.5
|
48
|
+
y0 = (s.ymin + s.ymax) * 0.5
|
49
|
+
dy = (s.ymax - s.ymin) * 0.5
|
50
|
+
tx = x0 + (x0 - x) * (1.0 - s.stretch * cos((y - y0) / dy * PI * 0.5))
|
51
|
+
[tx, y]
|
52
|
+
end
|
53
|
+
|
54
|
+
# read image from file in binary ppm format
|
55
|
+
def read_img(fname)
|
56
|
+
imf = nil
|
57
|
+
num_col = nil
|
58
|
+
|
59
|
+
# naive grayscale binary ppm reading. If you know how to, improve it
|
60
|
+
open(fname, "rb") do |fp|
|
61
|
+
|
62
|
+
ver= fp.scanf("%s\n")[0]
|
63
|
+
|
64
|
+
if ver.nil? || ver != 'P5'
|
65
|
+
raise "unrecognized file format version"
|
66
|
+
end
|
67
|
+
# puts("version: #{ver}")
|
68
|
+
|
69
|
+
while ((c = fp.getc) == ?#) do
|
70
|
+
fp.gets # comments
|
71
|
+
end
|
72
|
+
fp.ungetc(c)
|
73
|
+
|
74
|
+
w, h, num_col = fp.scanf("%d%d%d\n") # width, height num colors
|
75
|
+
raise 'unrecognized file format dimensions' if num_col.nil?
|
76
|
+
# printf("width=%d height=%d num_col=%d\n", w, h, num_col)
|
77
|
+
|
78
|
+
# This is potentially problematic since read will read _upto_ w*h bytes,
|
79
|
+
# but it is not guaranteed to read _exactly_ w*h bytes.
|
80
|
+
img = fp.read(w*h) rescue ''
|
81
|
+
raise 'file size error' if img.size != w*h
|
82
|
+
|
83
|
+
imf = NArray.to_na(img, NArray::BYTE, w, h).transpose(1,0).to_type(NArray::FLOAT)
|
84
|
+
|
85
|
+
# flip image up-down
|
86
|
+
w.times do |i|
|
87
|
+
(h/2).times do |j|
|
88
|
+
imf[j,i], imf[-1-j,i] = imf[-1-j,i], imf[j,i]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
[imf, num_col]
|
94
|
+
end
|
95
|
+
|
96
|
+
# save plot
|
97
|
+
def save_plot(fname)
|
98
|
+
cur_strm = plgstrm # get current stream
|
99
|
+
new_strm = plmkstrm # create a new one
|
100
|
+
|
101
|
+
plsdev("psc") # new device type. Use a known existing driver
|
102
|
+
plsfnam(fname) # file name
|
103
|
+
|
104
|
+
plcpstrm(cur_strm, 0) # copy old stream parameters to new stream
|
105
|
+
plreplot # do the save
|
106
|
+
plend1 # close new device
|
107
|
+
|
108
|
+
plsstrm(cur_strm) # and return to previous one
|
109
|
+
end
|
110
|
+
|
111
|
+
# get selection square interactively
|
112
|
+
def get_clip
|
113
|
+
# enter xor mode to draw a selection rectangle
|
114
|
+
return nil unless plxormod(1)
|
115
|
+
|
116
|
+
gin = nil
|
117
|
+
start = false
|
118
|
+
sx = NArray.float(5)
|
119
|
+
sy = NArray.float(5)
|
120
|
+
|
121
|
+
loop do
|
122
|
+
plxormod(0)
|
123
|
+
gin = plGetCursor
|
124
|
+
next unless gin
|
125
|
+
plxormod(1)
|
126
|
+
|
127
|
+
if (gin.button == 1)
|
128
|
+
xxi = gin.wx; yyi = gin.wy
|
129
|
+
if (start)
|
130
|
+
plline(sx, sy) # clear previous rectangle
|
131
|
+
end
|
132
|
+
|
133
|
+
start = false
|
134
|
+
|
135
|
+
sx[0] = xxi; sy[0] = yyi
|
136
|
+
sx[4] = xxi; sy[4] = yyi
|
137
|
+
end
|
138
|
+
|
139
|
+
if gin.state & 0x100 != 0
|
140
|
+
xxe = gin.wx; yye = gin.wy
|
141
|
+
if start
|
142
|
+
plline(sx, sy) # clear previous rectangle
|
143
|
+
end
|
144
|
+
|
145
|
+
start = true
|
146
|
+
|
147
|
+
sx[2] = xxe; sy[2] = yye
|
148
|
+
sx[1] = xxe; sy[1] = sy[0]
|
149
|
+
sx[3] = sx[4]; sy[3] = yye
|
150
|
+
plline(sx, sy) # draw new rectangle
|
151
|
+
end
|
152
|
+
|
153
|
+
if (gin.button == 3 || gin.keysym == PLK::Return || gin.keysym == 'Q')
|
154
|
+
if start
|
155
|
+
plline(sx, sy) # clear previous rectangle
|
156
|
+
end
|
157
|
+
break
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
plxormod(0) # leave xor mod
|
162
|
+
|
163
|
+
xi = sx[0]
|
164
|
+
xe = sx[1]
|
165
|
+
if (xe < xi)
|
166
|
+
xi, xe = xe, xi
|
167
|
+
end
|
168
|
+
|
169
|
+
yi = sy[0]
|
170
|
+
ye = sy[3]
|
171
|
+
if (yi < ye)
|
172
|
+
yi, ye = ye, yi
|
173
|
+
end
|
174
|
+
|
175
|
+
gin.keysym == 'Q' ? nil : [xi, xe, yi, ye]
|
176
|
+
end
|
177
|
+
|
178
|
+
# set gray colormap
|
179
|
+
def gray_cmap(num_col)
|
180
|
+
v = [0, 1]
|
181
|
+
plscmap1n(num_col)
|
182
|
+
plscmap1l(1, v, v, v, v)
|
183
|
+
end
|
184
|
+
|
185
|
+
#---------
|
186
|
+
# main
|
187
|
+
#---------
|
188
|
+
|
189
|
+
# Bugs in plimage():
|
190
|
+
# -at high magnifications, the left and right edge are ragged, try
|
191
|
+
# ./x20c -dev xwin -wplt 0.3,0.3,0.6,0.6 -ori 0.5
|
192
|
+
#
|
193
|
+
# Bugs in x20c.c:
|
194
|
+
# -if the window is resized after a selection is made on "lena", when
|
195
|
+
# making a new selection the old one will re-appear.
|
196
|
+
|
197
|
+
# Parse and process command line arguments
|
198
|
+
|
199
|
+
PLOP.parse!
|
200
|
+
|
201
|
+
# Initialize plplot
|
202
|
+
|
203
|
+
plinit()
|
204
|
+
|
205
|
+
z = NArray.float(YDIM, XDIM)
|
206
|
+
|
207
|
+
# view image border pixels
|
208
|
+
if $dbg
|
209
|
+
plenv(1, XDIM, 1, YDIM, 1, 1) # no plot box
|
210
|
+
|
211
|
+
# build a one pixel square border, for diagnostics
|
212
|
+
XDIM.times do |i|
|
213
|
+
z[-1,i] = 1 # right
|
214
|
+
z[ 0,i] = 1 # left
|
215
|
+
end
|
216
|
+
|
217
|
+
YDIM.times do |i|
|
218
|
+
z[i, 0] = 1 # top
|
219
|
+
z[i,-1] = 1 # botton
|
220
|
+
end
|
221
|
+
|
222
|
+
pllab("...around a blue square.", " ", "A red border should appear...")
|
223
|
+
|
224
|
+
plimage(z, 1..XDIM, 1..YDIM, 0..0, 1..XDIM, 1..YDIM)
|
225
|
+
end
|
226
|
+
|
227
|
+
# sombrero-like demo
|
228
|
+
if !$nosombrero
|
229
|
+
plcol0(2) # draw a yellow plot box, useful for diagnostics! :(
|
230
|
+
plenv(0, 2 * PI, 0, 3 * PI, 1, -1)
|
231
|
+
|
232
|
+
XDIM.times do |i|
|
233
|
+
x = i * 2 * PI / (XDIM - 1)
|
234
|
+
YDIM.times do |j|
|
235
|
+
y = j * 3 * PI / (YDIM - 1)
|
236
|
+
r = sqrt(x * x + y * y) + 1e-3
|
237
|
+
z[j,i] = sin(r) / r
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
pllab("No, an amplitude clipped \"sombrero\"", "", "Saturn?")
|
242
|
+
plptex(2, 2, 3, 4, 0, "Transparent image")
|
243
|
+
plimage(z, 0..2*PI, 0..3*PI, 0.05..1, 0..2*PI, 0..3*PI)
|
244
|
+
|
245
|
+
# save the plot
|
246
|
+
if $f_name
|
247
|
+
save_plot($f_name)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# read Lena image
|
252
|
+
# Note we try three different locations to cover the case where this
|
253
|
+
# examples is being run from the test_c.sh script
|
254
|
+
begin
|
255
|
+
img_f, num_col = read_img(File.join(File.dirname($0), "lena.pgm"))
|
256
|
+
rescue IOError
|
257
|
+
begin
|
258
|
+
img_f, num_col = read_img("lena.pgm")
|
259
|
+
rescue IOError
|
260
|
+
begin
|
261
|
+
img_f, num_col = read_img("../lena.pgm")
|
262
|
+
rescue
|
263
|
+
plend
|
264
|
+
raise
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
height, width = img_f.shape
|
270
|
+
|
271
|
+
# set gray colormap
|
272
|
+
gray_cmap(num_col)
|
273
|
+
|
274
|
+
# display Lena
|
275
|
+
plenv(1, width, 1, height, 1, -1)
|
276
|
+
|
277
|
+
if !$nointeractive
|
278
|
+
pllab("Set and drag Button 1 to (re)set selection, Button 2 to finish.", " ", "Lena...")
|
279
|
+
else
|
280
|
+
pllab("", " ", "Lena...")
|
281
|
+
end
|
282
|
+
|
283
|
+
plimage(img_f, 1..width, 1..height, 0..0, 1..width, 1..height)
|
284
|
+
|
285
|
+
# selection/expansion demo
|
286
|
+
if !$nointeractive
|
287
|
+
xi, xe, yi, ye = get_clip # get selection rectangle
|
288
|
+
if xi.nil?
|
289
|
+
plend
|
290
|
+
exit 0
|
291
|
+
end
|
292
|
+
|
293
|
+
# If empty selection
|
294
|
+
if xi == xe || yi == ye
|
295
|
+
xi = 200; xe = 330
|
296
|
+
yi = 280; ye = 220
|
297
|
+
end
|
298
|
+
|
299
|
+
# I'm unable to continue, clearing the plot and advancing to the next
|
300
|
+
# one, without hiting the enter key, or pressing the button... help!
|
301
|
+
#
|
302
|
+
# Forcing the xwin driver to leave locate mode and destroying the
|
303
|
+
# xhairs (in GetCursorCmd()) solves some problems, but I still have
|
304
|
+
# to press the enter key or press Button-2 to go to next plot, even
|
305
|
+
# if a pladv() is not present! Using plbop() solves the problem, but
|
306
|
+
# it shouldn't be needed!
|
307
|
+
|
308
|
+
# plbop
|
309
|
+
|
310
|
+
# plspause(0), pladv(0), plspause(1), also works,
|
311
|
+
# but the above question remains.
|
312
|
+
# With this approach, the previous pause state is lost,
|
313
|
+
# as there is no API call to get its current state.
|
314
|
+
|
315
|
+
plspause(0)
|
316
|
+
pladv(0)
|
317
|
+
|
318
|
+
# display selection only
|
319
|
+
plimage(img_f, 1..width, 1..height, 0..0, xi..xe, ye..yi)
|
320
|
+
|
321
|
+
plspause(1)
|
322
|
+
|
323
|
+
# zoom in selection
|
324
|
+
plenv(xi, xe, ye, yi, 1, -1)
|
325
|
+
plimage(img_f, 1..width, 1..height, 0..0, xi..xe, ye..yi)
|
326
|
+
end
|
327
|
+
|
328
|
+
# Base the dynamic range on the image contents.
|
329
|
+
img_min, img_max = plMinMax2dGrid(img_f)
|
330
|
+
|
331
|
+
# Draw a saturated version of the original image. Only use the middle 50%
|
332
|
+
# of the image's full dynamic range.
|
333
|
+
plcol0(2)
|
334
|
+
plenv(0, width, 0, height, 1, -1)
|
335
|
+
pllab("", "", "Reduced dynamic range image example")
|
336
|
+
plimage(img_f, 0..width, 0..height, 0..0, (img_min + img_max * 0.25)..(img_max - img_max * 0.25))
|
337
|
+
|
338
|
+
# Draw a distorted version of the original image, showing its full dynamic range.
|
339
|
+
plenv(0, width, 0, height, 1, -1)
|
340
|
+
pllab("", "", "Distorted image example")
|
341
|
+
|
342
|
+
stretch = StretchData.new(0, width, 0, height, 0.5)
|
343
|
+
|
344
|
+
# Use custom transformation. This is slower than pltr2, but it does work. It
|
345
|
+
# is commented out for consistency with x20c.c.
|
346
|
+
#plimage(img_f, 0..width, 0..height, 0..0, img_min..img_max) {|x,y| mypltr(x,y,stretch)}
|
347
|
+
|
348
|
+
# Use pltr2 transformation (fast)
|
349
|
+
xg = NArray.float(height+1, width+1)
|
350
|
+
yg = NArray.float(height+1, width+1)
|
351
|
+
|
352
|
+
(0..width).each do |i|
|
353
|
+
(0..height).each do |j|
|
354
|
+
xg[j,i], yg[j,i] = mypltr(i, j, stretch)
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
plimage(img_f, 0..width, 0..height, 0..0, img_min..img_max, xg, yg)
|
359
|
+
|
360
|
+
plend
|