Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
mpim-sw
cdo
Commits
be7e9b1a
Commit
be7e9b1a
authored
Nov 21, 2016
by
Uwe Schulzweida
Browse files
Added sellist.c.
parent
b9ae349d
Changes
8
Hide whitespace changes
Inline
Side-by-side
src/Makefile.am
View file @
be7e9b1a
...
...
@@ -111,6 +111,8 @@ libcdo_la_SOURCES = \
pml.h
\
pmlist.c
\
pmlist.h
\
sellist.c
\
sellist.h
\
pragma_omp_atomic_update.h
\
printinfo.h
\
process.c
\
...
...
src/Makefile.in
View file @
be7e9b1a
...
...
@@ -131,7 +131,7 @@ am_libcdo_la_OBJECTS = libcdo_la-cdo_pthread.lo libcdo_la-cdo_vlist.lo \
libcdo_la-par_io.lo libcdo_la-parse_literal.lo \
libcdo_la-percentiles_hist.lo libcdo_la-percentiles.lo \
libcdo_la-pipe.lo libcdo_la-pml.lo libcdo_la-pmlist.lo \
libcdo_la-process.lo libcdo_la-pstream.lo \
libcdo_la-sellist.lo
libcdo_la-process.lo libcdo_la-pstream.lo \
libcdo_la-pthread_debug.lo libcdo_la-readline.lo \
libcdo_la-realtime.lo libcdo_la-remaplib.lo \
libcdo_la-remapsort.lo libcdo_la-remap_scrip_io.lo \
...
...
@@ -523,18 +523,18 @@ libcdo_la_SOURCES = cdo_int.h compare.h cdo_pthread.c cdo_vlist.c \
nth_element.h operator_help.h par_io.c par_io.h \
parse_literal.c percentiles_hist.c percentiles_hist.h \
percentiles.c percentiles.h pipe.c pipe.h pml.c pml.h pmlist.c \
pmlist.h pragma_omp_atomic_update.h
printinfo.h process.c
\
pr
ocess.h pstream.c pstream
.h pstream
_write.h
pstream
_int
.h \
pt
h
rea
d_debug.c pthread_debug.h readline.c realtime.c remap
.h \
re
maplib.c remapsort.c remap_scrip_io.c remap_search_reg2d
.c \
remap_s
earch_latbins.c remap_store_link.c remap_store_link.h
\
remap_store_link
_cnsrv.c
remap_store_link_cnsrv.
h
\
remap_conserv.c remap_conserv_scrip.c
remap_distwgt.c
\
remap_bicubic_scrip.c remap_bilinear_scrip.c
stdnametable.c
\
stdnametable.h specspace.c specspace.h
statistic.c statistic.h
\
table.c text.c text.h timebase.h
timer.c userlog.c uthash.h
\
util.c util.h zaxis.c json/jsmn.h
json/jsmn.c
\
kdtreelib/kdtree.h kdtreelib/kdtree_cartesian.c \
pmlist.h
sellist.c sellist.h
pragma_omp_atomic_update.h \
pr
intinfo.h process.c process
.h pstream
.c
pstream.h \
p
s
trea
m_write.h pstream_int.h pthread_debug.c pthread_debug
.h \
re
adline.c realtime.c remap.h remaplib.c remapsort
.c \
remap_s
crip_io.c remap_search_reg2d.c remap_search_latbins.c
\
remap_store_link
.c remap_store_link.h
remap_store_link_cnsrv.
c
\
remap_store_link_cnsrv.h
remap_conserv.c remap_conserv_scrip.c \
remap_distwgt.c
remap_bicubic_scrip.c remap_bilinear_scrip.c \
stdnametable.c
stdnametable.h specspace.c specspace.h \
statistic.c statistic.h
table.c text.c text.h timebase.h \
timer.c userlog.c uthash.h
util.c util.h zaxis.c json/jsmn.h \
json/jsmn.c
kdtreelib/kdtree.h kdtreelib/kdtree_cartesian.c \
kdtreelib/kdtree_common.c kdtreelib/kdtree_spherical.c \
kdtreelib/qsort.c kdtreelib/pmergesort.c kdtreelib/pqueue.c \
kdtreelib/pqueue.h clipping/clipping.c clipping/clipping.h \
...
...
@@ -1075,6 +1075,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-remap_store_link_cnsrv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-remaplib.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-remapsort.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-sellist.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-specspace.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-statistic.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcdo_la-stdnametable.Plo@am__quote@
...
...
@@ -1563,6 +1564,13 @@ libcdo_la-pmlist.lo: pmlist.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-pmlist.lo `test -f 'pmlist.c' || echo '$(srcdir)/'`pmlist.c
libcdo_la-sellist.lo: sellist.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-sellist.lo -MD -MP -MF $(DEPDIR)/libcdo_la-sellist.Tpo -c -o libcdo_la-sellist.lo `test -f 'sellist.c' || echo '$(srcdir)/'`sellist.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-sellist.Tpo $(DEPDIR)/libcdo_la-sellist.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sellist.c' object='libcdo_la-sellist.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcdo_la-sellist.lo `test -f 'sellist.c' || echo '$(srcdir)/'`sellist.c
libcdo_la-process.lo: process.c
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcdo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcdo_la-process.lo -MD -MP -MF $(DEPDIR)/libcdo_la-process.Tpo -c -o libcdo_la-process.lo `test -f 'process.c' || echo '$(srcdir)/'`process.c
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcdo_la-process.Tpo $(DEPDIR)/libcdo_la-process.Plo
...
...
src/Select.c
View file @
be7e9b1a
...
...
@@ -20,6 +20,7 @@
Select select Select fields
*/
//#define TEST_KVL
#include
<cdi.h>
#include
"cdo.h"
...
...
@@ -29,6 +30,9 @@
#include
"util.h"
#include
"pml.h"
#include
"pmlist.h"
#ifdef TEST_KVL
#include
"sellist.h"
#endif
double
datestr_to_double
(
const
char
*
datestr
,
int
opt
);
...
...
@@ -59,7 +63,6 @@ void write_const_vars(int streamID2, int vlistID2, int nvars, double **vardata2)
}
}
//#define TEST_KVL
void
*
Select
(
void
*
argument
)
{
...
...
@@ -105,9 +108,35 @@ void *Select(void *argument)
cdoPrint
(
"name %d = %s"
,
i
+
1
,
argnames
[
i
]);
#ifdef TEST_KVL
list_t
*
kvl
=
kvlist_new
(
"SELECT"
);
if
(
kvlist_parse_cmdline
(
kvl
,
nsel
,
argnames
)
!=
0
)
cdoAbort
(
"Parse error!"
);
if
(
cdoVerbose
)
kvlist_print
(
kvl
);
//src/cdo infon -select,name=var129,var152,level=0 ../../test/data/pl_data
list_t
*
kvlist
=
kvlist_new
(
"SELECT"
);
if
(
kvlist_parse_cmdline
(
kvlist
,
nsel
,
argnames
)
!=
0
)
cdoAbort
(
"Parse error!"
);
if
(
cdoVerbose
)
kvlist_print
(
kvlist
);
sellist_t
*
sellist
=
sellist_create
(
kvlist
);
SELLIST_ADD_INT
(
sellist
,
timestep_of_year
,
"Timestep of year"
);
SELLIST_ADD_INT
(
sellist
,
timestep
,
"Timestep"
);
SELLIST_ADD_INT
(
sellist
,
year
,
"Year"
);
SELLIST_ADD_INT
(
sellist
,
month
,
"Month"
);
SELLIST_ADD_INT
(
sellist
,
day
,
"Day"
);
SELLIST_ADD_INT
(
sellist
,
hour
,
"Hour"
);
SELLIST_ADD_INT
(
sellist
,
minute
,
"Minute"
);
SELLIST_ADD_INT
(
sellist
,
code
,
"Code number"
);
SELLIST_ADD_INT
(
sellist
,
levidx
,
"Level index"
);
SELLIST_ADD_INT
(
sellist
,
ltype
,
"Level type"
);
SELLIST_ADD_INT
(
sellist
,
zaxisnum
,
"Zaxis number"
);
SELLIST_ADD_INT
(
sellist
,
gridnum
,
"Grid number"
);
SELLIST_ADD_FLT
(
sellist
,
level
,
"Level"
);
SELLIST_ADD_WORD
(
sellist
,
name
,
"Variable name"
);
SELLIST_ADD_WORD
(
sellist
,
param
,
"Parameter"
);
SELLIST_ADD_WORD
(
sellist
,
zaxisname
,
"Zaxis name"
);
SELLIST_ADD_WORD
(
sellist
,
gridname
,
"Grid name"
);
SELLIST_ADD_WORD
(
sellist
,
steptype
,
"Time step type"
);
SELLIST_ADD_WORD
(
sellist
,
startdate
,
"Start date"
);
SELLIST_ADD_WORD
(
sellist
,
enddate
,
"End date"
);
SELLIST_ADD_WORD
(
sellist
,
season
,
"Season"
);
SELLIST_ADD_WORD
(
sellist
,
date
,
"Date"
);
#endif
pml_t
*
pml
=
pml_create
(
"SELECT"
);
...
...
@@ -160,7 +189,7 @@ void *Select(void *argument)
if
(
indf
==
0
)
{
bool
xresult
=
fals
e
;
bool
xresult
=
tru
e
;
// vlistID0 = vlistDuplicate(vlistID1);
...
...
@@ -179,16 +208,31 @@ void *Select(void *argument)
vlistDefFlag
(
vlistID1
,
varID
,
levID
,
TRUE
);
}
}
else
if
(
operatorID
==
SELECT
)
{
xresult
=
true
;
}
#ifdef TEST_KVL
bool
lvarsel
=
SELLIST_NOCC
(
sellist
,
code
)
||
SELLIST_NOCC
(
sellist
,
ltype
)
||
SELLIST_NOCC
(
sellist
,
zaxisnum
)
||
SELLIST_NOCC
(
sellist
,
gridnum
)
||
SELLIST_NOCC
(
sellist
,
name
)
||
SELLIST_NOCC
(
sellist
,
param
)
||
SELLIST_NOCC
(
sellist
,
zaxisname
)
||
SELLIST_NOCC
(
sellist
,
gridname
)
||
SELLIST_NOCC
(
sellist
,
steptype
);
bool
llevsel
=
SELLIST_NOCC
(
sellist
,
level
)
||
SELLIST_NOCC
(
sellist
,
levidx
);
ltimsel
=
SELLIST_NOCC
(
sellist
,
date
)
||
SELLIST_NOCC
(
sellist
,
startdate
)
||
SELLIST_NOCC
(
sellist
,
enddate
)
||
SELLIST_NOCC
(
sellist
,
season
)
||
SELLIST_NOCC
(
sellist
,
timestep_of_year
)
||
SELLIST_NOCC
(
sellist
,
timestep
)
||
SELLIST_NOCC
(
sellist
,
year
)
||
SELLIST_NOCC
(
sellist
,
month
)
||
SELLIST_NOCC
(
sellist
,
day
)
||
SELLIST_NOCC
(
sellist
,
hour
)
||
SELLIST_NOCC
(
sellist
,
minute
);
printf
(
"lvarsel=%d llevsel=%d ltimsel=%d
\n
"
,
lvarsel
,
llevsel
,
ltimsel
);
#else
bool
lvarsel
=
PML_NOCC
(
pml
,
code
)
||
PML_NOCC
(
pml
,
ltype
)
||
PML_NOCC
(
pml
,
zaxisnum
)
||
PML_NOCC
(
pml
,
gridnum
)
||
PML_NOCC
(
pml
,
name
)
||
PML_NOCC
(
pml
,
param
)
||
PML_NOCC
(
pml
,
zaxisname
)
||
PML_NOCC
(
pml
,
gridname
)
||
PML_NOCC
(
pml
,
steptype
);
bool
llevsel
=
PML_NOCC
(
pml
,
level
)
||
PML_NOCC
(
pml
,
levidx
);
ltimsel
=
PML_NOCC
(
pml
,
date
)
||
PML_NOCC
(
pml
,
startdate
)
||
PML_NOCC
(
pml
,
enddate
)
||
PML_NOCC
(
pml
,
season
)
||
PML_NOCC
(
pml
,
timestep_of_year
)
||
PML_NOCC
(
pml
,
timestep
)
||
PML_NOCC
(
pml
,
year
)
||
PML_NOCC
(
pml
,
month
)
||
PML_NOCC
(
pml
,
day
)
||
PML_NOCC
(
pml
,
hour
)
||
PML_NOCC
(
pml
,
minute
);
#endif
ltimsel
=
PML_NOCC
(
pml
,
date
)
||
PML_NOCC
(
pml
,
startdate
)
||
PML_NOCC
(
pml
,
enddate
)
||
PML_NOCC
(
pml
,
season
)
||
PML_NOCC
(
pml
,
timestep_of_year
)
||
PML_NOCC
(
pml
,
timestep
)
||
PML_NOCC
(
pml
,
year
)
||
PML_NOCC
(
pml
,
month
)
||
PML_NOCC
(
pml
,
day
)
||
PML_NOCC
(
pml
,
hour
)
||
PML_NOCC
(
pml
,
minute
);
...
...
@@ -667,7 +711,8 @@ void *Select(void *argument)
pml_destroy
(
pml
);
#ifdef TEST_KVL
kvlist_destroy
(
kvl
);
sellist_destroy
(
sellist
);
kvlist_destroy
(
kvlist
);
#endif
if
(
array
)
Free
(
array
);
...
...
src/Smooth.c
View file @
be7e9b1a
...
...
@@ -362,11 +362,11 @@ void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
{
char
**
pargv
=
operatorArgv
();
list_t
*
kvl
=
list_new
(
sizeof
(
keyValues_t
*
),
free_keyval
,
"SMOOTH"
);
if
(
kvlist_parse_cmdline
(
kvl
,
pargc
,
pargv
)
!=
0
)
cdoAbort
(
"Parse error!"
);
if
(
cdoVerbose
)
kvlist_print
(
kvl
);
list_t
*
kvl
ist
=
list_new
(
sizeof
(
keyValues_t
*
),
free_keyval
,
"SMOOTH"
);
if
(
kvlist_parse_cmdline
(
kvl
ist
,
pargc
,
pargv
)
!=
0
)
cdoAbort
(
"Parse error!"
);
if
(
cdoVerbose
)
kvlist_print
(
kvl
ist
);
for
(
listNode_t
*
kvnode
=
kvl
->
head
;
kvnode
;
kvnode
=
kvnode
->
next
)
for
(
listNode_t
*
kvnode
=
kvl
ist
->
head
;
kvnode
;
kvnode
=
kvnode
->
next
)
{
keyValues_t
*
kv
=
*
(
keyValues_t
**
)
kvnode
->
data
;
const
char
*
key
=
kv
->
key
;
...
...
@@ -383,7 +383,7 @@ void smooth_set_parameter(int *xnsmooth, smoothpoint_t *spoint)
else
cdoAbort
(
"Invalid parameter key >%s<!"
,
key
);
}
list_destroy
(
kvl
);
list_destroy
(
kvl
ist
);
}
if
(
cdoVerbose
)
...
...
src/list.h
View file @
be7e9b1a
#ifndef _LIST_H
#define _LIST_H
#include
<stdio.h>
#include
<stdbool.h>
// a common function used to free malloc'd objects
...
...
src/pml.h
View file @
be7e9b1a
...
...
@@ -21,8 +21,6 @@
#define PML_INT 1
#define PML_FLT 2
#define PML_WORD 3
#define PML_DATE 4
#define PML_TIME 4
#define PML_INIT(name, size) memset(flag_##name, 0, size * sizeof(bool))
#define PML_DEF(name, size) bool flag_##name[size]
...
...
src/sellist.c
0 → 100644
View file @
be7e9b1a
#include
<stdio.h>
#include
<stdlib.h>
#include
<string.h>
#include
"sellist.h"
sellist_t
*
sellist_create
(
list_t
*
kvlist
)
{
printf
(
"kvlist size %d
\n
"
,
list_size
(
kvlist
));
sellist_t
*
sellist
=
(
sellist_t
*
)
malloc
(
sizeof
(
sellist_t
));
sellist
->
size
=
list_size
(
kvlist
);
sellist
->
entry
=
(
selentry_t
*
)
malloc
(
sellist
->
size
*
sizeof
(
selentry_t
));
int
i
=
0
;
for
(
listNode_t
*
kvnode
=
kvlist
->
head
;
kvnode
;
kvnode
=
kvnode
->
next
)
{
keyValues_t
*
kv
=
*
(
keyValues_t
**
)
kvnode
->
data
;
sellist
->
entry
[
i
].
key
=
kv
->
key
;
sellist
->
entry
[
i
].
values
=
kv
->
values
;
sellist
->
entry
[
i
].
nvalues
=
kv
->
nvalues
;
const
char
*
key
=
kv
->
key
;
char
**
values
=
kv
->
values
;
int
nvalues
=
kv
->
nvalues
;
printf
(
"%s ="
,
key
);
for
(
int
i
=
0
;
i
<
nvalues
;
++
i
)
printf
(
" '%s'"
,
values
[
i
]);
printf
(
"
\n
"
);
++
i
;
}
for
(
int
i
=
0
;
i
<
sellist
->
size
;
++
i
)
{
const
char
*
key
=
sellist
->
entry
[
i
].
key
;
char
**
values
=
sellist
->
entry
[
i
].
values
;
int
nvalues
=
sellist
->
entry
[
i
].
nvalues
;
sellist
->
entry
[
i
].
flag
=
NULL
;
if
(
nvalues
)
sellist
->
entry
[
i
].
flag
=
(
bool
*
)
calloc
(
nvalues
,
sizeof
(
bool
));
printf
(
"%s ="
,
key
);
for
(
int
i
=
0
;
i
<
nvalues
;
++
i
)
printf
(
" '%s'"
,
values
[
i
]);
printf
(
"
\n
"
);
}
return
sellist
;
}
void
sellist_destroy
(
sellist_t
*
sellist
)
{
if
(
sellist
)
{
for
(
int
i
=
0
;
i
<
sellist
->
size
;
++
i
)
{
const
char
*
key
=
sellist
->
entry
[
i
].
key
;
char
**
values
=
sellist
->
entry
[
i
].
values
;
int
nvalues
=
sellist
->
entry
[
i
].
nvalues
;
sellist
->
entry
[
i
].
flag
=
NULL
;
if
(
sellist
->
entry
[
i
].
flag
)
free
(
sellist
->
entry
[
i
].
flag
);
if
(
sellist
->
entry
[
i
].
txt
)
free
(
sellist
->
entry
[
i
].
txt
);
}
free
(
sellist
);
}
}
int
sellist_add
(
sellist_t
*
sellist
,
const
char
*
txt
,
const
char
*
name
,
int
type
)
{
int
entry
=
-
1
;
if
(
sellist
)
{
for
(
int
i
=
0
;
i
<
sellist
->
size
;
++
i
)
{
const
char
*
key
=
sellist
->
entry
[
i
].
key
;
if
(
strcmp
(
key
,
name
)
==
0
)
{
sellist
->
entry
[
i
].
type
=
type
;
sellist
->
entry
[
i
].
txt
=
strdup
(
txt
);
entry
=
i
;
break
;
}
}
}
return
entry
;
}
int
sellist_num_par
(
sellist_t
*
sellist
,
int
entry
)
{
int
num_par
=
0
;
if
(
sellist
&&
entry
>=
0
&&
entry
<
sellist
->
size
)
num_par
=
sellist
->
entry
[
entry
].
nvalues
;
return
num_par
;
}
src/sellist.h
0 → 100644
View file @
be7e9b1a
#ifndef _SELLIST_H
#define _SELLIST_H
#include
"pmlist.h"
typedef
struct
{
int
nvalues
;
char
*
key
;
char
**
values
;
bool
*
flag
;
int
type
;
char
*
txt
;
}
selentry_t
;
typedef
struct
{
int
size
;
selentry_t
*
entry
;
}
sellist_t
;
#define SELLIST_INT 1
#define SELLIST_FLT 2
#define SELLIST_WORD 3
#define SELLIST_DEF_INT(name) int x_##name = 0
#define SELLIST_DEF_FLT(name) double x_##name = 0
#define SELLIST_DEF_WORD(name) const char *x_##name = 0
#define SELLIST_ADD_INT(sellist, name, txt) SELLIST_DEF_INT(name); int xpid_##name = sellist_add(sellist, txt, #name, PML_INT)
#define SELLIST_ADD_FLT(sellist, name, txt) SELLIST_DEF_FLT(name); int xpid_##name = sellist_add(sellist, txt, #name, PML_FLT)
#define SELLIST_ADD_WORD(sellist, name, txt) SELLIST_DEF_WORD(name); int xpid_##name = sellist_add(sellist, txt, #name, PML_WORD)
#define SELLIST_NOCC(sellist, name) sellist_num_par(sellist, xpid_##name)
sellist_t
*
sellist_create
(
list_t
*
kvlist
);
void
sellist_destroy
(
sellist_t
*
sellist
);
int
sellist_add
(
sellist_t
*
sellist
,
const
char
*
txt
,
const
char
*
name
,
int
type
);
int
sellist_num_par
(
sellist_t
*
sellist
,
int
entry
);
#endif
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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