1
2
3
4 package codec
5
6 import (
7 "math"
8 "reflect"
9 "time"
10 )
11
12 const (
13 _ uint8 = iota
14 simpleVdNil = 1
15 simpleVdFalse = 2
16 simpleVdTrue = 3
17 simpleVdFloat32 = 4
18 simpleVdFloat64 = 5
19
20
21 simpleVdPosInt = 8
22 simpleVdNegInt = 12
23
24 simpleVdTime = 24
25
26
27 simpleVdString = 216
28 simpleVdByteArray = 224
29 simpleVdArray = 232
30 simpleVdMap = 240
31 simpleVdExt = 248
32 )
33
34 var simpledescNames = map[byte]string{
35 simpleVdNil: "null",
36 simpleVdFalse: "false",
37 simpleVdTrue: "true",
38 simpleVdFloat32: "float32",
39 simpleVdFloat64: "float64",
40
41 simpleVdPosInt: "+int",
42 simpleVdNegInt: "-int",
43
44 simpleVdTime: "time",
45
46 simpleVdString: "string",
47 simpleVdByteArray: "binary",
48 simpleVdArray: "array",
49 simpleVdMap: "map",
50 simpleVdExt: "ext",
51 }
52
53 func simpledesc(bd byte) (s string) {
54 s = simpledescNames[bd]
55 if s == "" {
56 s = "unknown"
57 }
58 return
59 }
60
61 type simpleEncDriver struct {
62 noBuiltInTypes
63 encDriverNoopContainerWriter
64 encDriverNoState
65 h *SimpleHandle
66
67 e Encoder
68 }
69
70 func (e *simpleEncDriver) encoder() *Encoder {
71 return &e.e
72 }
73
74 func (e *simpleEncDriver) EncodeNil() {
75 e.e.encWr.writen1(simpleVdNil)
76 }
77
78 func (e *simpleEncDriver) EncodeBool(b bool) {
79 if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && !b {
80 e.EncodeNil()
81 return
82 }
83 if b {
84 e.e.encWr.writen1(simpleVdTrue)
85 } else {
86 e.e.encWr.writen1(simpleVdFalse)
87 }
88 }
89
90 func (e *simpleEncDriver) EncodeFloat32(f float32) {
91 if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && f == 0.0 {
92 e.EncodeNil()
93 return
94 }
95 e.e.encWr.writen1(simpleVdFloat32)
96 bigen.writeUint32(e.e.w(), math.Float32bits(f))
97 }
98
99 func (e *simpleEncDriver) EncodeFloat64(f float64) {
100 if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && f == 0.0 {
101 e.EncodeNil()
102 return
103 }
104 e.e.encWr.writen1(simpleVdFloat64)
105 bigen.writeUint64(e.e.w(), math.Float64bits(f))
106 }
107
108 func (e *simpleEncDriver) EncodeInt(v int64) {
109 if v < 0 {
110 e.encUint(uint64(-v), simpleVdNegInt)
111 } else {
112 e.encUint(uint64(v), simpleVdPosInt)
113 }
114 }
115
116 func (e *simpleEncDriver) EncodeUint(v uint64) {
117 e.encUint(v, simpleVdPosInt)
118 }
119
120 func (e *simpleEncDriver) encUint(v uint64, bd uint8) {
121 if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && v == 0 {
122 e.EncodeNil()
123 return
124 }
125 if v <= math.MaxUint8 {
126 e.e.encWr.writen2(bd, uint8(v))
127 } else if v <= math.MaxUint16 {
128 e.e.encWr.writen1(bd + 1)
129 bigen.writeUint16(e.e.w(), uint16(v))
130 } else if v <= math.MaxUint32 {
131 e.e.encWr.writen1(bd + 2)
132 bigen.writeUint32(e.e.w(), uint32(v))
133 } else {
134 e.e.encWr.writen1(bd + 3)
135 bigen.writeUint64(e.e.w(), v)
136 }
137 }
138
139 func (e *simpleEncDriver) encLen(bd byte, length int) {
140 if length == 0 {
141 e.e.encWr.writen1(bd)
142 } else if length <= math.MaxUint8 {
143 e.e.encWr.writen1(bd + 1)
144 e.e.encWr.writen1(uint8(length))
145 } else if length <= math.MaxUint16 {
146 e.e.encWr.writen1(bd + 2)
147 bigen.writeUint16(e.e.w(), uint16(length))
148 } else if int64(length) <= math.MaxUint32 {
149 e.e.encWr.writen1(bd + 3)
150 bigen.writeUint32(e.e.w(), uint32(length))
151 } else {
152 e.e.encWr.writen1(bd + 4)
153 bigen.writeUint64(e.e.w(), uint64(length))
154 }
155 }
156
157 func (e *simpleEncDriver) EncodeExt(v interface{}, basetype reflect.Type, xtag uint64, ext Ext) {
158 var bs0, bs []byte
159 if ext == SelfExt {
160 bs0 = e.e.blist.get(1024)
161 bs = bs0
162 e.e.sideEncode(v, basetype, &bs)
163 } else {
164 bs = ext.WriteExt(v)
165 }
166 if bs == nil {
167 e.EncodeNil()
168 goto END
169 }
170 e.encodeExtPreamble(uint8(xtag), len(bs))
171 e.e.encWr.writeb(bs)
172 END:
173 if ext == SelfExt {
174 e.e.blist.put(bs)
175 if !byteSliceSameData(bs0, bs) {
176 e.e.blist.put(bs0)
177 }
178 }
179 }
180
181 func (e *simpleEncDriver) EncodeRawExt(re *RawExt) {
182 e.encodeExtPreamble(uint8(re.Tag), len(re.Data))
183 e.e.encWr.writeb(re.Data)
184 }
185
186 func (e *simpleEncDriver) encodeExtPreamble(xtag byte, length int) {
187 e.encLen(simpleVdExt, length)
188 e.e.encWr.writen1(xtag)
189 }
190
191 func (e *simpleEncDriver) WriteArrayStart(length int) {
192 e.encLen(simpleVdArray, length)
193 }
194
195 func (e *simpleEncDriver) WriteMapStart(length int) {
196 e.encLen(simpleVdMap, length)
197 }
198
199 func (e *simpleEncDriver) EncodeString(v string) {
200 if e.h.EncZeroValuesAsNil && e.e.c != containerMapKey && v == "" {
201 e.EncodeNil()
202 return
203 }
204 if e.h.StringToRaw {
205 e.encLen(simpleVdByteArray, len(v))
206 } else {
207 e.encLen(simpleVdString, len(v))
208 }
209 e.e.encWr.writestr(v)
210 }
211
212 func (e *simpleEncDriver) EncodeStringBytesRaw(v []byte) {
213
214 if v == nil {
215 e.EncodeNil()
216 return
217 }
218 e.encLen(simpleVdByteArray, len(v))
219 e.e.encWr.writeb(v)
220 }
221
222 func (e *simpleEncDriver) EncodeTime(t time.Time) {
223
224 if t.IsZero() {
225 e.EncodeNil()
226 return
227 }
228 v, err := t.MarshalBinary()
229 e.e.onerror(err)
230 e.e.encWr.writen2(simpleVdTime, uint8(len(v)))
231 e.e.encWr.writeb(v)
232 }
233
234
235
236 type simpleDecDriver struct {
237 h *SimpleHandle
238 bdAndBdread
239 _ bool
240 noBuiltInTypes
241 decDriverNoopContainerReader
242 decDriverNoopNumberHelper
243 d Decoder
244 }
245
246 func (d *simpleDecDriver) decoder() *Decoder {
247 return &d.d
248 }
249
250 func (d *simpleDecDriver) descBd() string {
251 return sprintf("%v (%s)", d.bd, simpledesc(d.bd))
252 }
253
254 func (d *simpleDecDriver) readNextBd() {
255 d.bd = d.d.decRd.readn1()
256 d.bdRead = true
257 }
258
259 func (d *simpleDecDriver) advanceNil() (null bool) {
260 if !d.bdRead {
261 d.readNextBd()
262 }
263 if d.bd == simpleVdNil {
264 d.bdRead = false
265 return true
266 }
267 return
268 }
269
270 func (d *simpleDecDriver) ContainerType() (vt valueType) {
271 if !d.bdRead {
272 d.readNextBd()
273 }
274 switch d.bd {
275 case simpleVdNil:
276 d.bdRead = false
277 return valueTypeNil
278 case simpleVdByteArray, simpleVdByteArray + 1,
279 simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
280 return valueTypeBytes
281 case simpleVdString, simpleVdString + 1,
282 simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
283 return valueTypeString
284 case simpleVdArray, simpleVdArray + 1,
285 simpleVdArray + 2, simpleVdArray + 3, simpleVdArray + 4:
286 return valueTypeArray
287 case simpleVdMap, simpleVdMap + 1,
288 simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
289 return valueTypeMap
290 }
291 return valueTypeUnset
292 }
293
294 func (d *simpleDecDriver) TryNil() bool {
295 return d.advanceNil()
296 }
297
298 func (d *simpleDecDriver) decFloat() (f float64, ok bool) {
299 ok = true
300 switch d.bd {
301 case simpleVdFloat32:
302 f = float64(math.Float32frombits(bigen.Uint32(d.d.decRd.readn4())))
303 case simpleVdFloat64:
304 f = math.Float64frombits(bigen.Uint64(d.d.decRd.readn8()))
305 default:
306 ok = false
307 }
308 return
309 }
310
311 func (d *simpleDecDriver) decInteger() (ui uint64, neg, ok bool) {
312 ok = true
313 switch d.bd {
314 case simpleVdPosInt:
315 ui = uint64(d.d.decRd.readn1())
316 case simpleVdPosInt + 1:
317 ui = uint64(bigen.Uint16(d.d.decRd.readn2()))
318 case simpleVdPosInt + 2:
319 ui = uint64(bigen.Uint32(d.d.decRd.readn4()))
320 case simpleVdPosInt + 3:
321 ui = uint64(bigen.Uint64(d.d.decRd.readn8()))
322 case simpleVdNegInt:
323 ui = uint64(d.d.decRd.readn1())
324 neg = true
325 case simpleVdNegInt + 1:
326 ui = uint64(bigen.Uint16(d.d.decRd.readn2()))
327 neg = true
328 case simpleVdNegInt + 2:
329 ui = uint64(bigen.Uint32(d.d.decRd.readn4()))
330 neg = true
331 case simpleVdNegInt + 3:
332 ui = uint64(bigen.Uint64(d.d.decRd.readn8()))
333 neg = true
334 default:
335 ok = false
336
337 }
338
339
340
341
342
343
344 return
345 }
346
347 func (d *simpleDecDriver) DecodeInt64() (i int64) {
348 if d.advanceNil() {
349 return
350 }
351 i = decNegintPosintFloatNumberHelper{&d.d}.int64(d.decInteger())
352 d.bdRead = false
353 return
354 }
355
356 func (d *simpleDecDriver) DecodeUint64() (ui uint64) {
357 if d.advanceNil() {
358 return
359 }
360 ui = decNegintPosintFloatNumberHelper{&d.d}.uint64(d.decInteger())
361 d.bdRead = false
362 return
363 }
364
365 func (d *simpleDecDriver) DecodeFloat64() (f float64) {
366 if d.advanceNil() {
367 return
368 }
369 f = decNegintPosintFloatNumberHelper{&d.d}.float64(d.decFloat())
370 d.bdRead = false
371 return
372 }
373
374
375 func (d *simpleDecDriver) DecodeBool() (b bool) {
376 if d.advanceNil() {
377 return
378 }
379 if d.bd == simpleVdFalse {
380 } else if d.bd == simpleVdTrue {
381 b = true
382 } else {
383 d.d.errorf("cannot decode bool - %s: %x", msgBadDesc, d.bd)
384 }
385 d.bdRead = false
386 return
387 }
388
389 func (d *simpleDecDriver) ReadMapStart() (length int) {
390 if d.advanceNil() {
391 return containerLenNil
392 }
393 d.bdRead = false
394 return d.decLen()
395 }
396
397 func (d *simpleDecDriver) ReadArrayStart() (length int) {
398 if d.advanceNil() {
399 return containerLenNil
400 }
401 d.bdRead = false
402 return d.decLen()
403 }
404
405 func (d *simpleDecDriver) uint2Len(ui uint64) int {
406 if chkOvf.Uint(ui, intBitsize) {
407 d.d.errorf("overflow integer: %v", ui)
408 }
409 return int(ui)
410 }
411
412 func (d *simpleDecDriver) decLen() int {
413 switch d.bd & 7 {
414 case 0:
415 return 0
416 case 1:
417 return int(d.d.decRd.readn1())
418 case 2:
419 return int(bigen.Uint16(d.d.decRd.readn2()))
420 case 3:
421 return d.uint2Len(uint64(bigen.Uint32(d.d.decRd.readn4())))
422 case 4:
423 return d.uint2Len(bigen.Uint64(d.d.decRd.readn8()))
424 }
425 d.d.errorf("cannot read length: bd%%8 must be in range 0..4. Got: %d", d.bd%8)
426 return -1
427 }
428
429 func (d *simpleDecDriver) DecodeStringAsBytes() (s []byte) {
430 return d.DecodeBytes(nil)
431 }
432
433 func (d *simpleDecDriver) DecodeBytes(bs []byte) (bsOut []byte) {
434 d.d.decByteState = decByteStateNone
435 if d.advanceNil() {
436 return
437 }
438
439 if d.bd >= simpleVdArray && d.bd <= simpleVdMap+4 {
440 if bs == nil {
441 d.d.decByteState = decByteStateReuseBuf
442 bs = d.d.b[:]
443 }
444 slen := d.ReadArrayStart()
445 var changed bool
446 if bs, changed = usableByteSlice(bs, slen); changed {
447 d.d.decByteState = decByteStateNone
448 }
449 for i := 0; i < len(bs); i++ {
450 bs[i] = uint8(chkOvf.UintV(d.DecodeUint64(), 8))
451 }
452 for i := len(bs); i < slen; i++ {
453 bs = append(bs, uint8(chkOvf.UintV(d.DecodeUint64(), 8)))
454 }
455 return bs
456 }
457
458 clen := d.decLen()
459 d.bdRead = false
460 if d.d.zerocopy() {
461 d.d.decByteState = decByteStateZerocopy
462 return d.d.decRd.rb.readx(uint(clen))
463 }
464 if bs == nil {
465 d.d.decByteState = decByteStateReuseBuf
466 bs = d.d.b[:]
467 }
468 return decByteSlice(d.d.r(), clen, d.d.h.MaxInitLen, bs)
469 }
470
471 func (d *simpleDecDriver) DecodeTime() (t time.Time) {
472 if d.advanceNil() {
473 return
474 }
475 if d.bd != simpleVdTime {
476 d.d.errorf("invalid descriptor for time.Time - expect 0x%x, received 0x%x", simpleVdTime, d.bd)
477 }
478 d.bdRead = false
479 clen := uint(d.d.decRd.readn1())
480 b := d.d.decRd.readx(clen)
481 d.d.onerror((&t).UnmarshalBinary(b))
482 return
483 }
484
485 func (d *simpleDecDriver) DecodeExt(rv interface{}, basetype reflect.Type, xtag uint64, ext Ext) {
486 if xtag > 0xff {
487 d.d.errorf("ext: tag must be <= 0xff; got: %v", xtag)
488 }
489 if d.advanceNil() {
490 return
491 }
492 xbs, realxtag1, zerocopy := d.decodeExtV(ext != nil, uint8(xtag))
493 realxtag := uint64(realxtag1)
494 if ext == nil {
495 re := rv.(*RawExt)
496 re.Tag = realxtag
497 re.setData(xbs, zerocopy)
498 } else if ext == SelfExt {
499 d.d.sideDecode(rv, basetype, xbs)
500 } else {
501 ext.ReadExt(rv, xbs)
502 }
503 }
504
505 func (d *simpleDecDriver) decodeExtV(verifyTag bool, tag byte) (xbs []byte, xtag byte, zerocopy bool) {
506 switch d.bd {
507 case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
508 l := d.decLen()
509 xtag = d.d.decRd.readn1()
510 if verifyTag && xtag != tag {
511 d.d.errorf("wrong extension tag. Got %b. Expecting: %v", xtag, tag)
512 }
513 if d.d.bytes {
514 xbs = d.d.decRd.rb.readx(uint(l))
515 zerocopy = true
516 } else {
517 xbs = decByteSlice(d.d.r(), l, d.d.h.MaxInitLen, d.d.b[:])
518 }
519 case simpleVdByteArray, simpleVdByteArray + 1,
520 simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
521 xbs = d.DecodeBytes(nil)
522 default:
523 d.d.errorf("ext - %s - expecting extensions/bytearray, got: 0x%x", msgBadDesc, d.bd)
524 }
525 d.bdRead = false
526 return
527 }
528
529 func (d *simpleDecDriver) DecodeNaked() {
530 if !d.bdRead {
531 d.readNextBd()
532 }
533
534 n := d.d.naked()
535 var decodeFurther bool
536
537 switch d.bd {
538 case simpleVdNil:
539 n.v = valueTypeNil
540 case simpleVdFalse:
541 n.v = valueTypeBool
542 n.b = false
543 case simpleVdTrue:
544 n.v = valueTypeBool
545 n.b = true
546 case simpleVdPosInt, simpleVdPosInt + 1, simpleVdPosInt + 2, simpleVdPosInt + 3:
547 if d.h.SignedInteger {
548 n.v = valueTypeInt
549 n.i = d.DecodeInt64()
550 } else {
551 n.v = valueTypeUint
552 n.u = d.DecodeUint64()
553 }
554 case simpleVdNegInt, simpleVdNegInt + 1, simpleVdNegInt + 2, simpleVdNegInt + 3:
555 n.v = valueTypeInt
556 n.i = d.DecodeInt64()
557 case simpleVdFloat32:
558 n.v = valueTypeFloat
559 n.f = d.DecodeFloat64()
560 case simpleVdFloat64:
561 n.v = valueTypeFloat
562 n.f = d.DecodeFloat64()
563 case simpleVdTime:
564 n.v = valueTypeTime
565 n.t = d.DecodeTime()
566 case simpleVdString, simpleVdString + 1,
567 simpleVdString + 2, simpleVdString + 3, simpleVdString + 4:
568 n.v = valueTypeString
569 n.s = d.d.stringZC(d.DecodeStringAsBytes())
570 case simpleVdByteArray, simpleVdByteArray + 1,
571 simpleVdByteArray + 2, simpleVdByteArray + 3, simpleVdByteArray + 4:
572 d.d.fauxUnionReadRawBytes(false)
573 case simpleVdExt, simpleVdExt + 1, simpleVdExt + 2, simpleVdExt + 3, simpleVdExt + 4:
574 n.v = valueTypeExt
575 l := d.decLen()
576 n.u = uint64(d.d.decRd.readn1())
577 if d.d.bytes {
578 n.l = d.d.decRd.rb.readx(uint(l))
579 } else {
580 n.l = decByteSlice(d.d.r(), l, d.d.h.MaxInitLen, d.d.b[:])
581 }
582 case simpleVdArray, simpleVdArray + 1, simpleVdArray + 2,
583 simpleVdArray + 3, simpleVdArray + 4:
584 n.v = valueTypeArray
585 decodeFurther = true
586 case simpleVdMap, simpleVdMap + 1, simpleVdMap + 2, simpleVdMap + 3, simpleVdMap + 4:
587 n.v = valueTypeMap
588 decodeFurther = true
589 default:
590 d.d.errorf("cannot infer value - %s 0x%x", msgBadDesc, d.bd)
591 }
592
593 if !decodeFurther {
594 d.bdRead = false
595 }
596 }
597
598 func (d *simpleDecDriver) nextValueBytes(v0 []byte) (v []byte) {
599 if !d.bdRead {
600 d.readNextBd()
601 }
602 v = v0
603 var h = decNextValueBytesHelper{d: &d.d}
604 var cursor = d.d.rb.c - 1
605 h.append1(&v, d.bd)
606 v = d.nextValueBytesBdReadR(v)
607 d.bdRead = false
608 h.bytesRdV(&v, cursor)
609 return
610 }
611
612 func (d *simpleDecDriver) nextValueBytesR(v0 []byte) (v []byte) {
613 d.readNextBd()
614 v = v0
615 var h = decNextValueBytesHelper{d: &d.d}
616 h.append1(&v, d.bd)
617 return d.nextValueBytesBdReadR(v)
618 }
619
620 func (d *simpleDecDriver) nextValueBytesBdReadR(v0 []byte) (v []byte) {
621 v = v0
622 var h = decNextValueBytesHelper{d: &d.d}
623
624 c := d.bd
625
626 var length uint
627
628 switch c {
629 case simpleVdNil, simpleVdFalse, simpleVdTrue, simpleVdString, simpleVdByteArray:
630
631 case simpleVdPosInt, simpleVdNegInt:
632 h.append1(&v, d.d.decRd.readn1())
633 case simpleVdPosInt + 1, simpleVdNegInt + 1:
634 h.appendN(&v, d.d.decRd.readx(2)...)
635 case simpleVdPosInt + 2, simpleVdNegInt + 2, simpleVdFloat32:
636 h.appendN(&v, d.d.decRd.readx(4)...)
637 case simpleVdPosInt + 3, simpleVdNegInt + 3, simpleVdFloat64:
638 h.appendN(&v, d.d.decRd.readx(8)...)
639 case simpleVdTime:
640 c = d.d.decRd.readn1()
641 h.append1(&v, c)
642 h.appendN(&v, d.d.decRd.readx(uint(c))...)
643
644 default:
645 switch c & 7 {
646 case 0:
647 length = 0
648 case 1:
649 b := d.d.decRd.readn1()
650 length = uint(b)
651 h.append1(&v, b)
652 case 2:
653 x := d.d.decRd.readn2()
654 length = uint(bigen.Uint16(x))
655 h.appendN(&v, x[:]...)
656 case 3:
657 x := d.d.decRd.readn4()
658 length = uint(bigen.Uint32(x))
659 h.appendN(&v, x[:]...)
660 case 4:
661 x := d.d.decRd.readn8()
662 length = uint(bigen.Uint64(x))
663 h.appendN(&v, x[:]...)
664 }
665
666 bExt := c >= simpleVdExt && c <= simpleVdExt+7
667 bStr := c >= simpleVdString && c <= simpleVdString+7
668 bByteArray := c >= simpleVdByteArray && c <= simpleVdByteArray+7
669 bArray := c >= simpleVdArray && c <= simpleVdArray+7
670 bMap := c >= simpleVdMap && c <= simpleVdMap+7
671
672 if !(bExt || bStr || bByteArray || bArray || bMap) {
673 d.d.errorf("cannot infer value - %s 0x%x", msgBadDesc, c)
674 }
675
676 if bExt {
677 h.append1(&v, d.d.decRd.readn1())
678 }
679
680 if length == 0 {
681 break
682 }
683
684 if bArray {
685 for i := uint(0); i < length; i++ {
686 v = d.nextValueBytesR(v)
687 }
688 } else if bMap {
689 for i := uint(0); i < length; i++ {
690 v = d.nextValueBytesR(v)
691 v = d.nextValueBytesR(v)
692 }
693 } else {
694 h.appendN(&v, d.d.decRd.readx(length)...)
695 }
696 }
697 return
698 }
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721 type SimpleHandle struct {
722 binaryEncodingType
723 BasicHandle
724
725 EncZeroValuesAsNil bool
726 }
727
728
729 func (h *SimpleHandle) Name() string { return "simple" }
730
731 func (h *SimpleHandle) desc(bd byte) string { return simpledesc(bd) }
732
733 func (h *SimpleHandle) newEncDriver() encDriver {
734 var e = &simpleEncDriver{h: h}
735 e.e.e = e
736 e.e.init(h)
737 e.reset()
738 return e
739 }
740
741 func (h *SimpleHandle) newDecDriver() decDriver {
742 d := &simpleDecDriver{h: h}
743 d.d.d = d
744 d.d.init(h)
745 d.reset()
746 return d
747 }
748
749 var _ decDriver = (*simpleDecDriver)(nil)
750 var _ encDriver = (*simpleEncDriver)(nil)
751
View as plain text