Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393
Commits
fc15b864
Commit
fc15b864
authored
Jan 02, 2018
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added Python code for testing MCLT window shift
parent
fcb4d602
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
515 additions
and
0 deletions
+515
-0
dct_iv.ods
dsp/dct_iv.ods
+0
-0
dtt_rad2.py
py393/dtt_rad2.py
+373
-0
test_mclt_shift.py
py393/test_mclt_shift.py
+142
-0
No files found.
dsp/dct_iv.ods
View file @
fc15b864
No preview for this file type
py393/dtt_rad2.py
0 → 100755
View file @
fc15b864
#!/usr/bin/env python
# encoding: utf-8
from
__future__
import
division
from
__future__
import
print_function
'''
# Copyright (C) 2016, Elphel.inc.
# Class to calculate DCT-IV and DST-IV
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
@author: Andrey Filippov
@copyright: 2017 Elphel, Inc.
@license: GPLv3.0+
@contact: andrey@elphel.coml
@deffield updated: Updated
'''
__author__
=
"Andrey Filippov"
__copyright__
=
"Copyright 2015, Elphel, Inc."
__license__
=
"GPL"
__version__
=
"3.0+"
__maintainer__
=
"Andrey Filippov"
__email__
=
"andrey@elphel.com"
__status__
=
"Development"
import
math
#import sys
#import pickle
COSPI_1_8_SQRT2
=
math
.
cos
(
math
.
pi
/
8
)
*
math
.
sqrt
(
2.0
);
COSPI_3_8_SQRT2
=
math
.
cos
(
3
*
math
.
pi
/
8
)
*
math
.
sqrt
(
2.0
);
SQRT2
=
math
.
sqrt
(
2.0
);
SQRT1_2
=
1
/
SQRT2
class
DttRad2
(
object
):
CN1
=
{}
SN1
=
{}
def
__init__
(
self
):
pass
def
ilog2
(
self
,
n
):
i
=
0
while
n
>
1
:
i
+=
1
n
>>=
1
return
i
def
setup_arrays
(
self
,
n
):
if
n
in
self
.
CN1
.
keys
():
return
n1
=
n
>>
1
if
n1
>
2
:
self
.
setup_arrays
(
n1
)
self
.
CN1
[
n
]
=
[
0.0
]
*
n1
self
.
SN1
[
n
]
=
[
0.0
]
*
n1
pi_4n
=
math
.
pi
/
(
8
*
n1
)
# // n1 = n/2
for
k
in
range
(
n1
):
self
.
CN1
[
n
][
k
]
=
math
.
cos
((
2
*
k
+
1
)
*
pi_4n
);
self
.
SN1
[
n
][
k
]
=
math
.
sin
((
2
*
k
+
1
)
*
pi_4n
);
print
(
"CN1="
,
self
.
CN1
)
print
(
"SN1="
,
self
.
SN1
)
def
_dctii_recurs
(
self
,
x
):
n
=
len
(
x
)
if
(
n
==
2
):
return
[
x
[
0
]
+
x
[
1
],
x
[
0
]
-
x
[
1
]]
n1
=
n
>>
1
;
u0
=
[
0.0
]
*
n1
u1
=
[
0.0
]
*
n1
# // u = sqrt(2)*Tn(0) * x
for
j
in
range
(
n1
):
u0
[
j
]
=
(
x
[
j
]
+
x
[
n
-
j
-
1
])
u1
[
j
]
=
(
x
[
j
]
-
x
[
n
-
j
-
1
])
v0
=
self
.
_dctii_recurs
(
u0
);
v1
=
self
.
_dctiv_recurs
(
u1
);
y
=
[
0.0
]
*
n
for
j
in
range
(
n1
):
y
[
2
*
j
]
=
v0
[
j
]
y
[
2
*
j
+
1
]
=
v1
[
j
]
return
y
def
_dctiv_recurs
(
self
,
x
):
n
=
len
(
x
)
if
(
n
==
2
):
return
[
COSPI_1_8_SQRT2
*
x
[
0
]
+
COSPI_3_8_SQRT2
*
x
[
1
],
COSPI_3_8_SQRT2
*
x
[
0
]
-
COSPI_1_8_SQRT2
*
x
[
1
]]
n1
=
n
>>
1
u0
=
[
0.0
]
*
n1
u1
=
[
0.0
]
*
n1
#// u = sqrt(2)*Tn(1) * x
for
j
in
range
(
n1
):
# print("n=",n," n1=",n1," j=",j)
u0
[
j
]
=
(
self
.
CN1
[
n
][
j
]
*
x
[
j
]
+
self
.
SN1
[
n
][
j
]
*
x
[
n
-
j
-
1
]);
u1
[
j
]
=
(
1
-
2
*
(
j
&
1
))
*
(
-
self
.
SN1
[
n
][
n1
-
j
-
1
]
*
x
[
n1
-
j
-
1
]
+
self
.
CN1
[
n
][
n1
-
j
-
1
]
*
x
[
n1
+
j
]);
v0
=
self
.
_dctii_recurs
(
u0
)
v1
=
self
.
_dctii_recurs
(
u1
)
# //both cos-II
w0
=
[
0.0
]
*
n1
w1
=
[
0.0
]
*
n1
w0
[
0
]
=
SQRT2
*
v0
[
0
];
w1
[
n1
-
1
]
=
SQRT2
*
v1
[
0
];
for
j
in
range
(
n1
):
sgn
=
(
1
-
2
*
(
j
&
1
));
if
(
j
>
0
):
w0
[
j
]
=
v0
[
j
]
-
sgn
*
v1
[
n1
-
j
];
if
(
j
<
(
n1
-
1
)):
w1
[
j
]
=
v0
[
j
+
1
]
-
sgn
*
v1
[
n1
-
j
-
1
];
y
=
[
0.0
]
*
n
for
j
in
range
(
n1
):
y
[
2
*
j
]
=
w0
[
j
];
y
[
2
*
j
+
1
]
=
w1
[
j
];
return
y
def
dct_ii
(
self
,
x
):
n
=
len
(
x
)
self
.
setup_arrays
(
n
)
y
=
self
.
_dctii_recurs
(
x
);
scale
=
1.0
/
math
.
sqrt
(
n
)
for
i
in
range
(
n
):
y
[
i
]
*=
scale
return
y
def
dct_iv
(
self
,
x
):
n
=
len
(
x
)
self
.
setup_arrays
(
n
)
y
=
self
.
_dctiv_recurs
(
x
);
scale
=
1.0
/
math
.
sqrt
(
n
)
for
i
in
range
(
n
):
y
[
i
]
*=
scale
return
y
def
dst_iv
(
self
,
x
):
n
=
len
(
x
)
self
.
setup_arrays
(
n
)
xr
=
x
[:]
# clone
xr
.
reverse
()
y
=
self
.
_dctiv_recurs
(
xr
);
scale
=
1.0
/
math
.
sqrt
(
n
);
for
i
in
range
(
n
):
y
[
i
]
*=
scale
;
scale
=
-
scale
;
return
y
;
def
mclt_window_sin
(
self
,
n
,
offset
=
0
):
"""
Generate offset MCLT sine window
@param n - DTT length (half MCLT)
@param offset - window offset
@return window array 2*n elements long. All positive in the range 0.0..1.0
"""
n2
=
2
*
n
w
=
[
0.0
]
*
n2
for
i
in
range
(
n2
):
w
[
i
]
=
math
.
sin
(
math
.
pi
*
(
i
+
0.5
-
offset
)
/
n2
)
return
w
def
mclt_window_sin_mod
(
self
,
n
,
offset
=
0.0
,
flat
=
0.0
):
"""
Generate offset MCLT sine window
@param n - DTT length (half MCLT)
@param offset - window offset
@param flat - extend zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return window array 2*n elements long. All positive in the range 0.0..1.0
"""
n2
=
2
*
n
w
=
[
0.0
]
*
n2
# k = 1.0*(n- 2 * flat)/n
k
=
1.0
*
n
/
(
n
-
2
*
flat
)
for
i
in
range
(
n2
):
a
=
(
i
+
0.5
-
offset
)
/
n2
# 1.0 is pi
if
a
>
0.5
:
a
=
1.0
-
a
a
=
0.25
+
k
*
(
a
-
0.25
)
if
a
<
0
:
a
=
0
elif
a
>
0.5
:
a
=
0.5
w
[
i
]
=
math
.
sin
(
math
.
pi
*
a
)
return
w
def
fold_dtt
(
self
,
x
,
sine_mode
=
False
):
"""
Fold MDCT/MDST sequence twice making an input for DCT-IV /DST-IV conversion (half length
@param x input data sequence
@param sine_mode: False - for DCT-IV, True - for DST-IV
@return array of DCT-IV/DST-IV folded data, 1/2 length of the input sequence
"""
n2
=
len
(
x
)
n
=
n2
>>
1
n05
=
n
>>
1
n15
=
n
+
n05
y
=
[
0.0
]
*
n
sgn
=
(
1.0
,
-
1.0
)[
sine_mode
]
for
i
in
range
(
n05
):
y
[
i
]
=
-
sgn
*
x
[
n15
-
1
-
i
]
-
x
[
n15
+
i
]
# -/+ c' - d
y
[
n05
+
i
]
=
x
[
i
]
-
sgn
*
x
[
n
-
1
-
i
]
# a -/+ b'
return
y
def
mclt_norot
(
self
,
x
,
offset
=
0.0
,
flat
=
0.0
):
"""
Perform direct MCLT transform, using offset (and modified) sine window
@param x input data sequence (will not be modified)
@param offset - window offset
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of [[DCT-IV],[DST-IV]], each 1/2 length of the input sequence
"""
n2
=
len
(
x
)
n
=
n2
>>
1
w
=
self
.
mclt_window_sin_mod
(
n
,
offset
,
flat
)
xc
=
x
[:]
for
i
in
range
(
n2
):
xc
[
i
]
*=
w
[
i
]
return
(
self
.
dct_iv
(
self
.
fold_dtt
(
xc
,
False
)),
# DCT-IV
self
.
dst_iv
(
self
.
fold_dtt
(
xc
,
True
)))
# DST-IV
def
unfold_dtt
(
self
,
x
,
sine_mode
=
False
):
"""
Unfold MDCT/MDST sequence twice after IDTT-IV before multiplying by a window
[F,S]: after DCT-IV: [S, -S', -F', -F], after DST-IV: [S, S', F', -F]
@param x input data sequence from IDCT-IV/IDST-IV
@param sine_mode: False - for IDCT-IV, True - for IDST-IV
@return array of unfolded data, twice length of the input sequence
"""
n
=
len
(
x
)
n2
=
n
<<
1
n05
=
n
>>
1
n15
=
n
+
n05
y
=
[
0.0
]
*
n2
sgn
=
(
1.0
,
-
1.0
)[
sine_mode
]
for
i
in
range
(
n05
):
y
[
i
]
=
x
[
n05
+
i
]
# S
y
[
n05
+
i
]
=
-
sgn
*
x
[
n
-
1
-
i
]
# -/+S'
y
[
n
+
i
]
=
-
sgn
*
x
[
n05
-
1
-
i
]
# -/+F'
y
[
n15
+
i
]
=
-
x
[
i
]
# -F
return
y
def
imclt
(
self
,
cs
,
flat
=
0.0
):
"""
Perform inverse MCLT transform, using modified sine window
@param cs - frequency domain data [[IDCT-IV],[IDST-IV]]
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of pixel domain lapped data, twice dct size
"""
n
=
len
(
cs
[
0
])
n2
=
n
<<
1
xc
=
self
.
unfold_dtt
(
self
.
dct_iv
(
cs
[
0
]),
False
)
xs
=
self
.
unfold_dtt
(
self
.
dst_iv
(
cs
[
1
]),
True
)
w
=
self
.
mclt_window_sin_mod
(
n
,
0
,
flat
)
# may use cached data
for
i
in
range
(
n2
):
xc
[
i
]
=
0.5
*
w
[
i
]
*
(
xc
[
i
]
+
xs
[
i
])
return
xc
def
clt_rot
(
self
,
cs
,
shft
):
"""
Perform frequency domain phase rotation equivalent to pixel shift
@param cs - frequency domain data [[IDCT-IV],[IDST-IV]]
@param shft - shift in pixels
@return same format as input - rotated(shifted) frequency domain data
"""
n
=
len
(
cs
[
0
])
rcs
=
[[
0.0
]
*
n
,
[
0.0
]
*
n
]
a
=
math
.
pi
*
shft
/
n
for
i
in
range
(
n
):
cosi
=
math
.
cos
(
a
*
(
i
+
0.5
))
sini
=
math
.
sin
(
a
*
(
i
+
0.5
))
rcs
[
0
][
i
]
=
cs
[
0
][
i
]
*
cosi
-
cs
[
1
][
i
]
*
sini
rcs
[
1
][
i
]
=
cs
[
1
][
i
]
*
cosi
+
cs
[
0
][
i
]
*
sini
return
rcs
##################
def
test_mclt
(
self
,
plt
,
dbg_x
,
cmode
,
x
,
offset
=
0.0
,
flat
=
0.0
):
"""
Perform direct MCLT transform, using offset (and modified) sine window
@param x input data sequence (will not be modified)
@param offset - window offset
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of [[DCT-IV],[DST-IV]], each 1/2 length of the input sequence
"""
n2
=
len
(
x
)
n
=
n2
>>
1
w
=
self
.
mclt_window_sin_mod
(
n
,
offset
,
flat
)
print
(
"w="
,
w
)
xc
=
x
[:]
for
i
in
range
(
n2
):
xc
[
i
]
*=
w
[
i
]
plt
.
plot
(
dbg_x
,
xc
,
cmode
)
print
(
"test_mclt xc="
,
xc
)
print
(
"test_mclt cos="
,
self
.
fold_dtt
(
xc
,
False
))
print
(
"test_mclt sin="
,
self
.
fold_dtt
(
xc
,
True
))
return
(
self
.
fold_dtt
(
xc
,
False
),
# DCT-IV
self
.
fold_dtt
(
xc
,
True
))
# DST-IV
def
test_mclt0
(
self
,
plt
,
dbg_x
,
cmode
,
x
,
offset
=
0.0
,
flat
=
0.0
):
"""
Perform direct MCLT transform, using offset (and modified) sine window
@param x input data sequence (will not be modified)
@param offset - window offset
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of [[DCT-IV],[DST-IV]], each 1/2 length of the input sequence
"""
n2
=
len
(
x
)
n
=
n2
>>
1
w
=
self
.
mclt_window_sin_mod
(
n
,
offset
,
flat
)
print
(
"w="
,
w
)
xc
=
x
[:]
for
i
in
range
(
n2
):
xc
[
i
]
*=
w
[
i
]
plt
.
plot
(
dbg_x
,
xc
,
cmode
)
return
xc
return
(
self
.
fold_dtt
(
xc
,
False
),
# DCT-IV
self
.
fold_dtt
(
xc
,
True
))
# DST-IV
def
test_imclt0
(
self
,
mx
,
flat
=
0.0
):
"""
Perform inverse MCLT transform, using modified sine window
@param cs - frequency domain data [[IDCT-IV],[IDST-IV]]
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of pixel domain lapped data, twice dct size
"""
n2
=
len
(
mx
)
n
=
n2
>>
1
xc
=
mx
[:]
# xc = self.unfold_dtt(cs[0], False)
# xs = self.unfold_dtt(cs[1], True)
w
=
self
.
mclt_window_sin_mod
(
n
,
0
,
flat
)
# may use cached data
for
i
in
range
(
n2
):
xc
[
i
]
=
mx
[
i
]
*
w
[
i
]
# (xc[i]+xs[i])
return
xc
def
test_imclt
(
self
,
cs
,
flat
=
0.0
):
"""
Perform inverse MCLT transform, using modified sine window
@param cs - frequency domain data [[IDCT-IV],[IDST-IV]]
@param flat - extend window zeros on the ends (by this), flat 1.0 in the center (by twice that).
Valid Princen-Bradley condition
@return array of pixel domain lapped data, twice dct size
"""
n
=
len
(
cs
[
0
])
n2
=
n
<<
1
xc
=
self
.
unfold_dtt
(
cs
[
0
],
False
)
xs
=
self
.
unfold_dtt
(
cs
[
1
],
True
)
w
=
self
.
mclt_window_sin_mod
(
n
,
0
,
flat
)
# may use cached data
for
i
in
range
(
n2
):
xc
[
i
]
=
0.5
*
w
[
i
]
*
(
xc
[
i
]
+
xs
[
i
])
# xc[i] = 0.5* w[i]*(xc[i])
return
xc
py393/test_mclt_shift.py
0 → 100755
View file @
fc15b864
#!/usr/bin/env python
# encoding: utf-8
from
__future__
import
division
from
__future__
import
print_function
from
ast
import
parse
'''
# Copyright (C) 2016, Elphel.inc.
# Class to calculate DCT-IV and DST-IV
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http:#www.gnu.org/licenses/>.
@author: Andrey Filippov
@copyright: 2017 Elphel, Inc.
@license: GPLv3.0+
@contact: andrey@elphel.coml
@deffield updated: Updated
'''
__author__
=
"Andrey Filippov"
__copyright__
=
"Copyright 2015, Elphel, Inc."
__license__
=
"GPL"
__version__
=
"3.0+"
__maintainer__
=
"Andrey Filippov"
__email__
=
"andrey@elphel.com"
__status__
=
"Development"
import
math
import
matplotlib.pyplot
as
plt
import
dtt_rad2
#import sys
def
test1
():
# x=[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
# x=[0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
x
=
[
1.0
,
2.0
,
3.0
,
4.0
,
5.0
,
6.0
,
7.0
,
8.0
]
dtt
=
dtt_rad2
.
DttRad2
()
print
(
"CN1="
,
dtt
.
CN1
)
print
(
"SN1="
,
dtt
.
SN1
)
print
(
"x="
,
x
)
# y = dtt.dct_ii(x)
# print ("dctii(x)=",y)
y
=
dtt
.
dct_iv
(
x
)
print
(
"dctiv(x)="
,
y
)
z
=
dtt
.
dct_iv
(
y
)
print
(
"dctiv(dctiv(x))="
,
z
)
y
=
dtt
.
dst_iv
(
x
)
print
(
"dstiv(x)="
,
y
)
z
=
dtt
.
dst_iv
(
y
)
print
(
"dstiv(dstiv(x))="
,
z
)
# x = create_test1(l = 1.0, k = 4, p = 5, n = 8)
x
=
create_test1
(
l
=
100.0
,
k
=
4
,
p
=
7
,
n
=
8
)
# pars = setup_test1()
# pars = setup_test2()
pars
=
setup_test2
()
# plt.plot(x)
plt
.
plot
(
x
,
"bo"
)
y
=
test_clt_iclt
(
plt
,
dtt
,
x
,
pars
,
flat
=
0.0
)
plt
.
plot
(
y
,
"g"
)
plt
.
ylabel
(
'values'
)
plt
.
show
()
def
create_test1
(
l
=
1.0
,
k
=
4
,
p
=
5
,
n
=
8
):
x
=
[
0
]
*
n
*
(
k
+
1
)
for
i
in
range
(
len
(
x
)):
x
[
i
]
=
l
;
j
=
i
%
p
if
j
==
0
:
x
[
i
]
+=
1
elif
j
==
1
:
x
[
i
]
+=
2
elif
j
==
2
:
x
[
i
]
+=
3
return
x
def
setup_test1
():
return
[{
"poffs"
:
-
1
,
"woffs"
:
1.0
,
"roffs"
:
-
1.0
},
{
"poffs"
:
-
1
,
"woffs"
:
1.0
,
"roffs"
:
-
1.0
},
{
"poffs"
:
1
,
"woffs"
:
-
1.0
,
"roffs"
:
1.0
},
{
"poffs"
:
1
,
"woffs"
:
-
1.0
,
"roffs"
:
1.0
}]
def
setup_test2
():
return
[{
"poffs"
:
0
,
"woffs"
:
.5
,
"roffs"
:
-
.5
},
{
"poffs"
:
0
,
"woffs"
:
.5
,
"roffs"
:
-
.5
},
{
"poffs"
:
1
,
"woffs"
:
-
.5
,
"roffs"
:
.5
},
{
"poffs"
:
1
,
"woffs"
:
-
.5
,
"roffs"
:
.5
}]
def
setup_test20
():
return
[{
"poffs"
:
0
,
"woffs"
:
.0
,
"roffs"
:
-
.5
},
{
"poffs"
:
0
,
"woffs"
:
.0
,
"roffs"
:
-
.5
},
{
"poffs"
:
1
,
"woffs"
:
.0
,
"roffs"
:
.5
},
{
"poffs"
:
1
,
"woffs"
:
.0
,
"roffs"
:
.5
}]
def
test_clt_iclt
(
plt
,
dtt
,
x
,
pars
,
flat
=
0
):
y
=
[
0.0
]
*
len
(
x
)
t
=
len
(
pars
)
n
=
len
(
x
)
//
(
t
+
1
)
n2
=
n
*
2
cmodes
=
(
"r--"
,
"b--"
,
"v--"
,
'y--'
)
for
it
in
range
(
t
):
x_start
=
n
*
it
+
pars
[
it
][
"poffs"
]
mx
=
[
0
]
*
n2
dbg_x
=
[]
for
i
in
range
(
n2
):
j
=
x_start
+
i
if
j
<
0
:
j
=
0
if
j
>=
len
(
x
):
j
=
len
(
x
)
-
1
mx
[
i
]
=
x
[
j
]
dbg_x
.
append
(
j
)
print
(
"it="
,
it
)
print
(
"dbg_x="
,
dbg_x
)
print
(
"mx="
,
mx
)
# plt.plot(dbg_x,mx, "r")
# plt.plot(y,"g--")
cs
=
dtt
.
mclt_norot
(
mx
,
offset
=
pars
[
it
][
"woffs"
],
flat
=
flat
)
## cs= dtt.test_mclt(plt, dbg_x, cmodes[it], mx, offset=pars[it]["woffs"], flat = flat)
if
pars
[
it
][
"roffs"
]
!=
0.0
:
cs
=
dtt
.
clt_rot
(
cs
,
pars
[
it
][
"roffs"
])
mix
=
dtt
.
imclt
(
cs
,
flat
=
flat
)
## mix= dtt.test_imclt(cs, flat = flat)
for
i
in
range
(
n2
):
y
[
n
*
it
+
i
]
+=
mix
[
i
]
return
y
test1
()
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment