Skip to content

Commit f5b0365

Browse files
committed
1.012 2022/11/07 SNOOPYJC issue s140: doesn't work, issue s141: Naming a sub 'main' fails to pythonize properly, issue s142: Autovivification doesn't work on @argv, also fix range assignment for @argv, issue s143: Complex hash assignment with regex substitute generates incorrect code, issue s144: my statement with a comma-separated list of initializations generates bad code, issue s145: complex nested hash/array initialization fails translation, issue s146: for loop that starts by incrementing the loop counter is not handled, issue s147: multiple do{...} until(...) with nested trailing 'if' does not translate properly, issue s148: chomp/chop on an array element or hash value fails to translate, issue s149: multi-line q string with blank lines doesn't translate properly, issue s150: GetOptions or die generates bad code, other fixes to GetOptions to handle -option and check for invalid options
1 parent e629d49 commit f5b0365

51 files changed

Lines changed: 1657 additions & 256 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Config/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__author__ = """Joe Cool"""
44
___email__ = 'snoopyjc@gmail.com'
5-
__version__ = '1.011'
5+
__version__ = '1.012'
66

77
import perllib
88
import subprocess

File/Path.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"""Implementation of perl File::Path package"""
44
__author__ = """Joe Cool"""
55
__email__ = "snoopyjc@gmail.com"
6-
__version__ = "1.011"
6+
__version__ = "1.012"
77
import builtins, perllib, os, re
88

99
_str = lambda s: "" if s is None else str(s)

HISTORY.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22
History
33
=======
44

5+
1.012 (2022-11-07)
6+
------------------
7+
8+
* Issue s142: add Array.remove(item), issue s150: add _preprocess_arguments, _postprocess_arguments
9+
510
1.011 (2022-11-03)
611
------------------
712

8-
* Issue s135: Add _filter_map
13+
* Issue s135: Add _filter_map
914

1015
1.010 (2022-11-03)
1116
------------------

Math/Complex.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
__author__ = """Pythonizer"""
55
___email__ = 'snoopyjc@gmail.com'
6-
__version__ = '1.011'
6+
__version__ = '1.012'
77

88
# Generated by "pythonizer -v3 -d5 ../Math/Complex.pm" v0.966 run by JO2742 on Tue Mar 29 17:57:14 2022
99
#

Perlscan.pm

Lines changed: 107 additions & 39 deletions
Large diffs are not rendered by default.

Pyconfig.pm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ package Pyconfig;
99

1010
require Exporter;
1111
our @ISA = qw(Exporter);
12-
our @EXPORT = qw( $TABSIZE $MAXNESTING $MAXLINELEN $DEFAULT_VAR $DEFAULT_MATCH $PERL_ARG_ARRAY $PERL_SORT_ $GLOB_LIST $ARG_PARSER $DIAMOND $EVAL_RESULT $EVAL_RETURN_EXCEPTION $SUBPROCESS_RC $SCRIPT_START $DO_CONTROL $ANONYMOUS_SUB $DIE_TRACEBACK %CONSTANT_MAP %GLOBALS %GLOBAL_TYPES %PYTHON_KEYWORD_SET %PYTHON_RESERVED_SET array_var_name hash_var_name scalar_var_name loop_var_name label_exception_name state_flag_name $ELSIF_TEMP $INDEX_TEMP $KEY_TEMP $SUBSCRIPT_TEMP %CONVERTER_MAP $LOCALS_STACK %SIGIL_MAP $MAIN_MODULE %BUILTIN_LIBRARY_SET $IMPORT_PATH_TEMP $IMPORT_MODULE_TEMP $MODULES_DIR $SUBPROCESS_OPTIONS $PERL_VERSION %PYF_CALLS %PYF_OUT_PARAMETERS $FUNCTION_RETURN_EXCEPTION %STAT_SUB %LSTAT_SUB %DASH_X $MAX_CHUNKS $MAX_DEPTH $DEFAULT_PACKAGE %ARRAY_INDEX_FUNCS %AUTOVIVIFICATION_CONVERTER_MAP $PERLLIB %PREDEFINED_PACKAGES @STANDARD_LIBRARY_DIRS $PRETTY_PRINTER $SHEBANG %OVERLOAD_MAP %CLASS_METHOD_SET $AUTHORS_FILE $SWITCH_VAR $SWITCH_LABEL $NON_REGEX_CHARS);
12+
our @EXPORT = qw( $TABSIZE $MAXNESTING $MAXLINELEN $DEFAULT_VAR $DEFAULT_MATCH $PERL_ARG_ARRAY $PERL_SORT_ $GLOB_LIST $ARG_PARSER $DIAMOND $EVAL_RESULT $EVAL_RETURN_EXCEPTION $SUBPROCESS_RC $SCRIPT_START $DO_CONTROL $ANONYMOUS_SUB $DIE_TRACEBACK %CONSTANT_MAP %GLOBALS %GLOBAL_TYPES %PYTHON_KEYWORD_SET %PYTHON_RESERVED_SET array_var_name hash_var_name scalar_var_name loop_var_name label_exception_name state_flag_name $ELSIF_TEMP $INDEX_TEMP $KEY_TEMP $SUBSCRIPT_TEMP %CONVERTER_MAP $LOCALS_STACK %SIGIL_MAP $MAIN_MODULE %BUILTIN_LIBRARY_SET $IMPORT_PATH_TEMP $IMPORT_MODULE_TEMP $MODULES_DIR $SUBPROCESS_OPTIONS $PERL_VERSION %PYF_CALLS %PYF_OUT_PARAMETERS $FUNCTION_RETURN_EXCEPTION %STAT_SUB %LSTAT_SUB %DASH_X $MAX_CHUNKS $MAX_DEPTH $DEFAULT_PACKAGE %ARRAY_INDEX_FUNCS %AUTOVIVIFICATION_CONVERTER_MAP $PERLLIB %PREDEFINED_PACKAGES @STANDARD_LIBRARY_DIRS $PRETTY_PRINTER $SHEBANG %OVERLOAD_MAP %CLASS_METHOD_SET $AUTHORS_FILE $SWITCH_VAR $SWITCH_LABEL $NON_REGEX_CHARS %STATEMENT_FUNCTIONS);
1313

1414
# use Readonly; # Readonly is not installed by default so skip it!
1515

@@ -190,6 +190,7 @@ our %PYF_CALLS=(_basename=>'_fileparse', _croak=>'_shortmess', _confess=>'_longm
190190
_unpack=>'_pack', _assign_sparse=>'_int',
191191
_carp=>'_shortmess', _cluck=>'_longmess'); # Who calls who
192192
our %PYF_OUT_PARAMETERS=(); # Functions with out parameters - which parameter (counting from 1) is "out"?
193+
our %STATEMENT_FUNCTIONS=(getopts=>1, GetOptions=>1); # issue s150: These functions generate statements and must be pulled out of expressions/conditions
193194
our %STAT_SUB=('File::stat'=>'_fstat'); # Substitution for stat if they use File::stat
194195
our %LSTAT_SUB=('File::stat'=>'_flstat'); # Substitution for stat if they use File::stat
195196

Pythonizer.pm

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,9 @@ my %DeclaredVarH=(); # list of my varibles in the current subroute
500500
if( $ValClass[$k]=~/[sah]/ ){
501501
check_ref($CurSubName, $k); # SNOOPYJC
502502
if($ValClass[$k] eq 's' && $ValPerl[$k] eq '$_' && $k+1 <= $#ValClass &&
503-
($ValClass[$k+1] eq '=' ||
504-
($ValClass[$k+1] eq '~' && $ValClass[$k+2] eq 'f' && $ValPerl[$k+2] =~ /^(?:re|tr)$/)) # issue ddts
505-
) {
503+
($ValClass[$k+1] eq '=' ||
504+
($ValClass[$k+1] eq '~' && $ValClass[$k+2] eq 'f' && $ValPerl[$k+2] =~ /^(?:re|tr)$/)) # issue ddts
505+
) {
506506
# issue s84 $SubAttributes{$CurSubName}{modifies_arglist} = 1; # SNOOPYJC: This sub mods it's args
507507
$SubAttributes{&Perlscan::cur_sub()}{modifies_arglist} = 1; # SNOOPYJC: This sub mods it's args, issue s84
508508
}
@@ -533,30 +533,30 @@ my %DeclaredVarH=(); # list of my varibles in the current subroute
533533
} elsif($ValClass[$k] eq 'f' && ($ValPerl[$k] eq 're' && $ValPy[$k] =~ /\b$DEFAULT_VAR\b/) ||
534534
($ValPerl[$k] eq 'tr' && ($k == 0 || $ValClass[$k-1] ne '~'))) { # issue s8: sets the $DEFAULT_VAR
535535

536-
my $t = merge_types($DEFAULT_VAR, $CurSubName, 'S'); # issue s104
536+
my $t = merge_types($DEFAULT_VAR, $CurSubName, 'S'); # issue s104
537537
$VarType{$DEFAULT_VAR}{$CurSubName} = $t; # issue s8, issue s104
538538
$VarSubMap{$DEFAULT_VAR}{$CurSubName}='+'; # issue s103
539539
$NeedsInitializing{$CurSubName}{$DEFAULT_VAR} = $t if(!exists $initialized{$CurSubName}{$DEFAULT_VAR}); # issue s8, issue s104
540-
} elsif($ValClass[$k] eq 'f' && arg_type($ValPerl[$k], $ValPy[$k], 0, 0) eq 'H' && $#ValClass > $k) { # issue s101: handle file handles across subs
541-
my $h = $k+1;
542-
$h++ if($ValClass[$h] eq '(');
543-
if($ValClass[$h] eq 'i' && index($ValPy[$h],'.') < 0) { # Do this for bareword file handles, but not STDxx
544-
$VarSubMap{$ValPy[$h]}{$CurSubName}='+';
545-
}
540+
} elsif($ValClass[$k] eq 'f' && arg_type($ValPerl[$k], $ValPy[$k], 0, 0) eq 'H' && $#ValClass > $k) { # issue s101: handle file handles across subs
541+
my $h = $k+1;
542+
$h++ if($ValClass[$h] eq '(');
543+
if($ValClass[$h] eq 'i' && index($ValPy[$h],'.') < 0) { # Do this for bareword file handles, but not STDxx
544+
$VarSubMap{$ValPy[$h]}{$CurSubName}='+';
545+
}
546546
} elsif($ValClass[$k] eq 'f' &&
547-
((($ValPerl[$k] eq 'chomp' || $ValPerl[$k] eq 'chop' || $ValPerl[$k] eq 'eval' || $ValPerl[$k] eq 'split' ||
548-
$ValPerl[$k] eq 'defined' || $ValPerl[$k] eq 'mkdir' || $ValPerl[$k] eq 'ord' || $ValPerl[$k] eq 'chr' ||
549-
$ValPerl[$k] eq 'quotemeta' || $ValPerl[$k] eq 'oct' || $ValPerl[$k] eq 'hex' || $ValPerl[$k] eq 'require' ||
550-
$ValPerl[$k] eq 'stat' || $ValPerl[$k] eq 'lstat' || $ValPerl[$k] eq 'reverse') && $#ValClass == $k || end_of_function($k) == $k) ||
551-
($ValPerl[$k] eq 'split' && $#ValClass == $k+1) ||
552-
(($ValPerl[$k] eq 'print' || $ValPerl[$k] eq 'printf') && ($#ValClass == $k || ($#ValClass == $k+1 && $ValClass[$k+1] eq 'i'))))) { # issue s103
553-
my $t = 'S'; # issue s104
554-
$t = 'm' if $ValPerl[$k] eq 'defined'; # issue s104
547+
((($ValPerl[$k] eq 'chomp' || $ValPerl[$k] eq 'chop' || $ValPerl[$k] eq 'eval' || $ValPerl[$k] eq 'split' ||
548+
$ValPerl[$k] eq 'defined' || $ValPerl[$k] eq 'mkdir' || $ValPerl[$k] eq 'ord' || $ValPerl[$k] eq 'chr' ||
549+
$ValPerl[$k] eq 'quotemeta' || $ValPerl[$k] eq 'oct' || $ValPerl[$k] eq 'hex' || $ValPerl[$k] eq 'require' ||
550+
$ValPerl[$k] eq 'stat' || $ValPerl[$k] eq 'lstat' || $ValPerl[$k] eq 'reverse') && $#ValClass == $k || end_of_function($k) == $k) ||
551+
($ValPerl[$k] eq 'split' && $#ValClass == $k+1) ||
552+
(($ValPerl[$k] eq 'print' || $ValPerl[$k] eq 'printf') && ($#ValClass == $k || ($#ValClass == $k+1 && $ValClass[$k+1] eq 'i'))))) { # issue s103
553+
my $t = 'S'; # issue s104
554+
$t = 'm' if $ValPerl[$k] eq 'defined'; # issue s104
555555
$t = merge_types($DEFAULT_VAR, $CurSubName, $t); # issue s104
556556
$VarType{$DEFAULT_VAR}{$CurSubName} = $t; # issue s104
557-
$VarSubMap{$DEFAULT_VAR}{$CurSubName}='+'; # issue s103
558-
$NeedsInitializing{$CurSubName}{$DEFAULT_VAR} = $t if(!exists $initialized{$CurSubName}{$DEFAULT_VAR}); # issue s103, issue s104
559-
}
557+
$VarSubMap{$DEFAULT_VAR}{$CurSubName}='+'; # issue s103
558+
$NeedsInitializing{$CurSubName}{$DEFAULT_VAR} = $t if(!exists $initialized{$CurSubName}{$DEFAULT_VAR}); # issue s103, issue s104
559+
}
560560

561561
} # for
562562
if(scalar(@ValClass) > 0 && $ValClass[0] eq 'k' && $ValPerl[0] eq 'return') { # SNOOPYJC: return statement
@@ -901,9 +901,9 @@ my %DeclaredVarH=(); # list of my varibles in the current subroute
901901
my $vn = substr($varname, $dx+1);
902902
my $ig = '_init_global';
903903
$ig = "$PERLLIB.init_global" if($::import_perllib);
904-
if(exists $Packages{$packname}) { # Only init if the named package is defined here
904+
if(exists $Packages{$packname}) { # Only init if the named package is defined here
905905
$InitVar{$subname} .= "\n$varname = $ig('$packname', '$vn', " .init_val($NeedsInitializing{$subname}{$varname}) . ')';
906-
}
906+
}
907907
}
908908
}
909909
}
@@ -968,6 +968,11 @@ sub check_ref # SNOOPYJC: Check references to variables so we can type
968968
say STDERR "check_ref($CurSub, $name) at $k";
969969
}
970970

971+
if(exists $Perlscan::sub_varclasses{$CurSub}{$ValPerl[$k]} && $Perlscan::sub_varclasses{$CurSub}{$ValPerl[$k]} eq 'local') { # issue s144
972+
# issue s144: 'local' variables aren't really local
973+
$CurSub = '__main__'
974+
}
975+
971976
# Record if we are modifying the loop counter
972977
if($ValPy[0] ne 'for' && $class eq 's' &&
973978
(($k != 0 && $ValClass[$k-1] eq '^') || ($k+1 <= $#ValClass && ($ValClass[$k+1] eq '=' || $ValClass[$k+1] eq '^')))) {
@@ -1078,11 +1083,11 @@ sub check_ref # SNOOPYJC: Check references to variables so we can type
10781083
} else {
10791084
$type = 'u';
10801085
}
1081-
if($ValClass[$k] eq 'a') { # issue s95
1082-
$type = 'a'; # issue s95
1083-
} elsif($ValClass[$k] eq 'h') { # issue s95
1084-
$type = 'h'; # issue s95
1085-
}
1086+
if($ValClass[$k] eq 'a') { # issue s95
1087+
$type = 'a'; # issue s95
1088+
} elsif($ValClass[$k] eq 'h') { # issue s95
1089+
$type = 'h'; # issue s95
1090+
}
10861091
$initialized{$CurSub}{$name} = $type unless(&Perlscan::in_conditional($k));
10871092
}
10881093
}
@@ -1147,27 +1152,46 @@ sub check_ref # SNOOPYJC: Check references to variables so we can type
11471152
} elsif(index(')x*/%+-.HI>&|0r?:,Ao"', $ValClass[$p]) >= 0) {
11481153
return; # Just a reference to the array
11491154
}
1155+
} elsif($k-1 >= 0 && $ValClass[$k-1] eq 'f' && ($ValPerl[$k-1] eq 'chop' || $ValPerl[$k-1] eq 'chomp')) { # issue s148
1156+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of S");
1157+
} elsif($k-2 >= 0 && $ValClass[$k-1] eq '(' && $ValClass[$k-2] eq 'f' && ($ValPerl[$k-2] eq 'chop' || $ValPerl[$k-2] eq 'chomp')) { # issue s148
1158+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of S");
11501159
} else {
11511160
return; # Just a reference to the array
11521161
}
1153-
# issue s98 if(defined $rhs_type) {
1154-
# issue s98 $VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of $rhs_type");
1155-
# issue s98 } else {
1156-
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of m");
1162+
# issue s98 if(defined $rhs_type) {
1163+
# issue s98 $VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of $rhs_type");
1164+
# issue s98 } else {
1165+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, "$type of m");
11571166
# issue s98 }
1167+
} elsif($class eq 's' && $k-1 >= 0 && $ValClass[$k-1] eq 'f' && ($ValPerl[$k-1] eq 'chop' || $ValPerl[$k-1] eq 'chomp')) { # issue s148
1168+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, 'S');
1169+
} elsif($class eq 's' && $k-2 >= 0 && $ValClass[$k-1] eq '(' && $ValClass[$k-2] eq 'f' && ($ValPerl[$k-2] eq 'chop' || $ValPerl[$k-2] eq 'chomp')) { # issue s148
1170+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, 'S');
11581171
} elsif($class eq 'a' || $class eq 'h') { # e.g. if(@arr) or if(%hash) or push @arr, ...
11591172
$type = $class;
11601173
if($k-1 >= 0 && $ValClass[$k-1] eq 'f' && ($ValPerl[$k-1] eq 'push' || $ValPerl[$k-1] eq 'unshift') && $k+2 <= $#ValClass) {
11611174
$type = expr_type($k+2, $#ValClass, $CurSub);
11621175
$type = "$class of $type";
11631176
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, $type);
1177+
} elsif($k-2 >= 0 && $ValClass[$k-1] eq '(' && $ValClass[$k-2] eq 'f' && ($ValPerl[$k-2] eq 'push' || $ValPerl[$k-2] eq 'unshift') && $k+2 <= $#ValClass) {
1178+
my $match = matching_br($k-1);
1179+
$type = expr_type($k+2, $match-1, $CurSub);
1180+
$type = "$class of $type";
1181+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, $type);
1182+
} elsif($k-1 >= 0 && $ValClass[$k-1] eq 'f' && ($ValPerl[$k-1] eq 'chop' || $ValPerl[$k-1] eq 'chomp')) { # issue s148
1183+
$type = "$class of S";
1184+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, $type);
1185+
} elsif($k-2 >= 0 && $ValClass[$k-1] eq '(' && $ValClass[$k-2] eq 'f' && ($ValPerl[$k-2] eq 'chop' || $ValPerl[$k-2] eq 'chomp')) { # issue s148
1186+
$type = "$class of S";
1187+
$VarType{$name}{$CurSub} = merge_types($name, $CurSub, $type);
11641188
# issue s93 } elsif(substr($ValPy[$k],0,4) eq 'len(') {
11651189
} elsif($name =~ /^\(len\((.*)\)-1\)$/) { # issue s93: $#myArray
11661190
$NeedsInitializing{$CurSub}{$1} = 'a' if(!exists $initialized{$CurSub}{$1}); # issue s93
1167-
$type = 'I'; # issue s93
1191+
$type = 'I'; # issue s93
11681192
} elsif($name =~ /^len\((.*)\)$/) { # issue s93: scalar(@myArray)
11691193
$NeedsInitializing{$CurSub}{$1} = 'a' if(!exists $initialized{$CurSub}{$1}); # issue s93
1170-
$type = 'I'; # issue s93
1194+
$type = 'I'; # issue s93
11711195
} # issue s93
11721196
# issue s93 $type = 'I';
11731197
# issue s93 }

Sys/Hostname.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
__author__ = """Joe Cool"""
66
___email__ = 'snoopyjc@gmail.com'
7-
__version__ = '1.011'
7+
__version__ = '1.012'
88

99
import signal, re, perllib, builtins, os
1010

bump.yaml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
bump.yaml:
2-
^(.*)(1.011)(.*)$: replace
2+
^(.*)(1.012)(.*)$: replace
33
pythonizer:
4-
'^(# )(1.011)( )(\d\d\d\d\/\d\d\/\d\d)( SNOOPYJC)': append
5-
^(.*\$VERSION=')(1.011)(';): replace
4+
'^(# )(1.012)( )(\d\d\d\d\/\d\d\/\d\d)( SNOOPYJC)': append
5+
^(.*\$VERSION=')(1.012)(';): replace
66
setup.py:
7-
^(.*version=')(1.011)(',): replace
7+
^(.*version=')(1.012)(',): replace
88
user_guide.html:
9-
^(.*Version )(1.011)( \()([A-Z][a-z][a-z] \d*, \d\d\d\d)(\).*)$: replace
9+
^(.*Version )(1.012)( \()([A-Z][a-z][a-z] \d*, \d\d\d\d)(\).*)$: replace
1010
HISTORY.rst:
11-
^(1.011)( \()(\d\d\d\d-\d\d-\d\d)(\))$: history
11+
^(1.012)( \()(\d\d\d\d-\d\d-\d\d)(\))$: history
1212
readme.md:
13-
^(###.*)(1.011)(.*)$: replace
13+
^(###.*)(1.012)(.*)$: replace
1414
charnames/__init__.py:
15-
^(__version__ =.')(1.011)(')$: replace
15+
^(__version__ =.')(1.012)(')$: replace
1616
Config/__init__.py:
17-
^(__version__ =.')(1.011)(')$: replace
17+
^(__version__ =.')(1.012)(')$: replace
1818
Math/Complex.py:
19-
^(__version__ =.')(1.011)(')$: replace
19+
^(__version__ =.')(1.012)(')$: replace
2020
Sys/Hostname.py:
21-
^(__version__ =.')(1.011)(')$: replace
21+
^(__version__ =.')(1.012)(')$: replace
2222
File/Path.py:
23-
^(__version__ =.")(1.011)(")$: replace
23+
^(__version__ =.")(1.012)(")$: replace
2424
FindBin/__init__.py:
25-
^(__version__ =.')(1.011)(')$: replace
25+
^(__version__ =.')(1.012)(')$: replace

charnames/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
__author__ = """Joe Cool"""
44
___email__ = 'snoopyjc@gmail.com'
5-
__version__ = '1.011'
5+
__version__ = '1.012'
66

77
import perllib
88
import unicodedata

0 commit comments

Comments
 (0)