version 1.87, 2005/10/31 10:03:48 |
version 1.89, 2005/11/02 05:18:41 |
|
|
* DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE, |
* DEVELOPER SHALL HAVE NO LIABILITY IN CONNECTION WITH THE USE, |
* PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE. |
* PERFORMANCE OR NON-PERFORMANCE OF THE SOFTWARE. |
* |
* |
* $OpenXM: OpenXM_contrib2/asir2000/builtin/strobj.c,v 1.86 2005/10/26 23:43:23 noro Exp $ |
* $OpenXM: OpenXM_contrib2/asir2000/builtin/strobj.c,v 1.88 2005/11/01 07:24:11 noro Exp $ |
*/ |
*/ |
#include "ca.h" |
#include "ca.h" |
#include "parse.h" |
#include "parse.h" |
Line 58 extern jmp_buf environnement; |
|
Line 58 extern jmp_buf environnement; |
|
#endif |
#endif |
#include <string.h> |
#include <string.h> |
|
|
|
#if defined(__GNUC__) |
|
#define INLINE inline |
|
#elif defined(VISUAL) |
|
#define INLINE __inline |
|
#else |
|
#define INLINE |
|
#endif |
|
|
struct TeXSymbol { |
struct TeXSymbol { |
char *text; |
char *text; |
char *symbol; |
char *symbol; |
Line 88 void Pquote_is_integer(),Pquote_is_rational(),Pquote_i |
|
Line 96 void Pquote_is_integer(),Pquote_is_rational(),Pquote_i |
|
void Pquote_is_dependent(),Pquote_is_function(); |
void Pquote_is_dependent(),Pquote_is_function(); |
void Pquote_normalize(); |
void Pquote_normalize(); |
void Pquote_normalize_comp(); |
void Pquote_normalize_comp(); |
|
void Pquote_normalize_unify(); |
|
|
void Pquote_to_funargs(),Pfunargs_to_quote(),Pget_function_name(); |
void Pquote_to_funargs(),Pfunargs_to_quote(),Pget_function_name(); |
void Pquote_unify(),Pget_quote_id(),Pquote_match_rewrite(); |
void Pquote_unify(),Pget_quote_id(),Pquote_match_rewrite(); |
void Pquote_to_nary(),Pquote_to_bin(); |
void Pquote_to_nary(),Pquote_to_bin(); |
|
void fnode_do_assign(NODE arg); |
void do_assign(NODE arg); |
void do_assign(NODE arg); |
void fnodetotex_tb(FNODE f,TB tb); |
void fnodetotex_tb(FNODE f,TB tb); |
char *symbol_name(char *name); |
char *symbol_name(char *name); |
Line 137 struct ftab str_tab[] = { |
|
Line 147 struct ftab str_tab[] = { |
|
{"flatten_quote",Pflatten_quote,-2}, |
{"flatten_quote",Pflatten_quote,-2}, |
{"quote_to_funargs",Pquote_to_funargs,1}, |
{"quote_to_funargs",Pquote_to_funargs,1}, |
{"quote_unify",Pquote_unify,2}, |
{"quote_unify",Pquote_unify,2}, |
|
{"quote_normalize_unify",Pquote_normalize_unify,2}, |
{"quote_match_rewrite",Pquote_match_rewrite,-4}, |
{"quote_match_rewrite",Pquote_match_rewrite,-4}, |
{"funargs_to_quote",Pfunargs_to_quote,1}, |
{"funargs_to_quote",Pfunargs_to_quote,1}, |
{"get_function_name",Pget_function_name,1}, |
{"get_function_name",Pget_function_name,1}, |
Line 646 void Pquote_unify(NODE arg,Q *rp) |
|
Line 657 void Pquote_unify(NODE arg,Q *rp) |
|
*rp = 0; |
*rp = 0; |
} |
} |
|
|
|
void Pquote_normalize_unify(NODE arg,Q *rp) |
|
{ |
|
QUOTE fq,pq; |
|
FNODE f,p; |
|
int ret; |
|
NODE r; |
|
|
|
fq = (QUOTE)ARG0(arg); Pquote_normalize(mknode(2,fq,0),&fq); f = (FNODE)BDY(fq); |
|
pq = (QUOTE)ARG1(arg); Pquote_normalize(mknode(2,pq,0),&pq); p = (FNODE)BDY(pq); |
|
ret = fnode_normalize_unify(f,p,&r); |
|
if ( ret ) { |
|
fnode_do_assign(r); |
|
*rp = ONE; |
|
} else |
|
*rp = 0; |
|
} |
|
|
FNODE rewrite_fnode(FNODE,NODE); |
FNODE rewrite_fnode(FNODE,NODE); |
|
|
extern Obj VOIDobj; |
extern Obj VOIDobj; |
Line 704 void do_assign(NODE arg) |
|
Line 732 void do_assign(NODE arg) |
|
} |
} |
} |
} |
|
|
|
/* [[index,fnode],...] */ |
|
|
|
void fnode_do_assign(NODE arg) |
|
{ |
|
NODE t,pair; |
|
int pv; |
|
FNODE f; |
|
QUOTE value; |
|
|
|
for ( t = arg; t; t = NEXT(t) ) { |
|
pair = (NODE)BDY(t); |
|
pv = (int)BDY(pair); |
|
f = (FNODE)(BDY(NEXT(pair))); |
|
MKQUOTE(value,f); |
|
ASSPV(pv,value); |
|
} |
|
} |
|
|
/* |
/* |
/* consistency check and merge |
/* consistency check and merge |
*/ |
*/ |
Line 1967 void Pquote_normalize_comp(NODE arg,Q *rp) |
|
Line 2013 void Pquote_normalize_comp(NODE arg,Q *rp) |
|
STOQ(r,*rp); |
STOQ(r,*rp); |
} |
} |
|
|
int fnode_is_number(FNODE f) |
INLINE int fnode_is_number(FNODE f) |
{ |
{ |
Obj obj; |
Obj obj; |
|
|
Line 2130 FNODE fnode_normalize(FNODE f,int expand) |
|
Line 2176 FNODE fnode_normalize(FNODE f,int expand) |
|
NODE n; |
NODE n; |
Q q; |
Q q; |
|
|
|
if ( f->normalized && (f->expanded || !expand) ) return f; |
STOQ(-1,q); |
STOQ(-1,q); |
mone = mkfnode(1,I_FORMULA,q); |
mone = mkfnode(1,I_FORMULA,q); |
switch ( f->id ) { |
switch ( f->id ) { |
case I_PAREN: |
case I_PAREN: |
return fnode_normalize(FA0(f),expand); |
r = fnode_normalize(FA0(f),expand); |
|
break; |
|
|
case I_MINUS: |
case I_MINUS: |
return fnode_normalize_mul_coef((Num)q, |
r = fnode_normalize_mul_coef((Num)q, |
fnode_normalize(FA0(f),expand),expand); |
fnode_normalize(FA0(f),expand),expand); |
|
break; |
|
|
case I_BOP: |
case I_BOP: |
/* arf fnode fnode */ |
/* arf fnode fnode */ |
Line 2146 FNODE fnode_normalize(FNODE f,int expand) |
|
Line 2195 FNODE fnode_normalize(FNODE f,int expand) |
|
a2 = fnode_normalize(FA2(f),expand); |
a2 = fnode_normalize(FA2(f),expand); |
switch ( OPNAME(f) ) { |
switch ( OPNAME(f) ) { |
case '+': |
case '+': |
return fnode_normalize_add(a1,a2,expand); |
r = fnode_normalize_add(a1,a2,expand); |
|
break; |
case '-': |
case '-': |
a2 = fnode_normalize_mul_coef((Num)q,a2,expand); |
a2 = fnode_normalize_mul_coef((Num)q,a2,expand); |
return fnode_normalize_add(a1,a2,expand); |
r = fnode_normalize_add(a1,a2,expand); |
|
break; |
case '*': |
case '*': |
return fnode_normalize_mul(a1,a2,expand); |
r = fnode_normalize_mul(a1,a2,expand); |
|
break; |
case '/': |
case '/': |
a2 = fnode_normalize_pwr(a2,mone,expand); |
a2 = fnode_normalize_pwr(a2,mone,expand); |
return fnode_normalize_mul(a1,a2,expand); |
r = fnode_normalize_mul(a1,a2,expand); |
|
break; |
case '^': |
case '^': |
return fnode_normalize_pwr(a1,a2,expand); |
r = fnode_normalize_pwr(a1,a2,expand); |
|
break; |
default: |
default: |
return mkfnode(3,I_BOP,FA0(f),a1,a2); |
r = mkfnode(3,I_BOP,FA0(f),a1,a2); |
|
break; |
} |
} |
break; |
break; |
|
|
Line 2171 FNODE fnode_normalize(FNODE f,int expand) |
|
Line 2226 FNODE fnode_normalize(FNODE f,int expand) |
|
a1 = fnode_normalize(BDY(n),expand); |
a1 = fnode_normalize(BDY(n),expand); |
r = fnode_normalize_add(r,a1,expand); |
r = fnode_normalize_add(r,a1,expand); |
} |
} |
return r; |
break; |
case '*': |
case '*': |
n = (NODE)FA1(f); |
n = (NODE)FA1(f); |
r = fnode_normalize(BDY(n),expand); n = NEXT(n); |
r = fnode_normalize(BDY(n),expand); n = NEXT(n); |
Line 2179 FNODE fnode_normalize(FNODE f,int expand) |
|
Line 2234 FNODE fnode_normalize(FNODE f,int expand) |
|
a1 = fnode_normalize(BDY(n),expand); |
a1 = fnode_normalize(BDY(n),expand); |
r = fnode_normalize_mul(r,a1,expand); |
r = fnode_normalize_mul(r,a1,expand); |
} |
} |
return r; |
break; |
default: |
default: |
error("fnode_normallize : cannot happen"); |
error("fnode_normallize : cannot happen"); |
} |
} |
|
break; |
|
|
default: |
default: |
return fnode_apply(f,fnode_normalize,expand); |
return fnode_apply(f,fnode_normalize,expand); |
} |
} |
|
r->normalized = 1; |
|
r->expanded = expand; |
|
return r; |
} |
} |
|
|
FNODE fnode_apply(FNODE f,FNODE (*func)(),int expand) |
FNODE fnode_apply(FNODE f,FNODE (*func)(),int expand) |
Line 2339 FNODE fnode_normalize_mul(FNODE f1,FNODE f2,int expand |
|
Line 2398 FNODE fnode_normalize_mul(FNODE f1,FNODE f2,int expand |
|
|
|
FNODE fnode_normalize_pwr(FNODE f1,FNODE f2,int expand) |
FNODE fnode_normalize_pwr(FNODE f1,FNODE f2,int expand) |
{ |
{ |
FNODE b,b1,e1,e,cc,r; |
FNODE b,b1,e1,e,cc,r,mf2,mone,inv; |
Num c,c1; |
Num c,c1,nf2; |
NODE arg,n; |
int ee; |
|
NODE arg,n,t0,t1; |
Q q; |
Q q; |
|
|
if ( IS_ZERO(f2) ) return mkfnode(1,I_FORMULA,ONE); |
if ( IS_ZERO(f2) ) return mkfnode(1,I_FORMULA,ONE); |
Line 2360 FNODE fnode_normalize_pwr(FNODE f1,FNODE f2,int expand |
|
Line 2420 FNODE fnode_normalize_pwr(FNODE f1,FNODE f2,int expand |
|
return b1; |
return b1; |
else |
else |
return mkfnode(3,I_BOP,FA0(f1),b1,e); |
return mkfnode(3,I_BOP,FA0(f1),b1,e); |
} else if ( IS_NARYMUL(f1) && fnode_is_integer(f2) ) { |
} else if ( expand && IS_NARYMUL(f1) && fnode_is_integer(f2) ) { |
fnode_coef_body(f1,&c1,&b1); |
fnode_coef_body(f1,&c1,&b1); |
pwrnum(0,(Num)c1,(Num)eval(f2),&c); |
nf2 = (Num)eval(f2); |
|
pwrnum(0,(Num)c1,nf2,&c); |
|
ee = QTOS((Q)nf2); |
cc = mkfnode(1,I_FORMULA,c); |
cc = mkfnode(1,I_FORMULA,c); |
b = fnode_normalize_pwr(b1,f2,expand); |
if ( fnode_is_nonnegative_integer(f2) ) |
|
b = fnode_expand_pwr(b1,ee); |
|
else { |
|
STOQ(-1,q); |
|
mone = mkfnode(1,I_FORMULA,q); |
|
for ( t0 = 0, n = (NODE)FA1(b1); n; n = NEXT(n) ) { |
|
inv = mkfnode(3,I_BOP,pwrfs,BDY(n),mone); |
|
MKNODE(t1,inv,t0); t0 = t1; |
|
} |
|
b1 = mkfnode(2,I_NARYOP,FA0(f1),t0); |
|
b = fnode_expand_pwr(b1,-ee); |
|
} |
if ( fnode_is_one(cc) ) |
if ( fnode_is_one(cc) ) |
return b; |
return b; |
else |
else |
Line 2619 int fnode_normalize_comp_pwr(FNODE f1,FNODE f2) |
|
Line 2692 int fnode_normalize_comp_pwr(FNODE f1,FNODE f2) |
|
} else return fnode_normalize_comp(e1,e2); |
} else return fnode_normalize_comp(e1,e2); |
} |
} |
|
|
|
NODE append_node(NODE a1,NODE a2) |
|
{ |
|
NODE t,t0; |
|
|
|
if ( !a1 ) |
|
return a2; |
|
else { |
|
for ( t0 = 0; a1; a1 = NEXT(a1) ) { |
|
NEXTNODE(t0,t); BDY(t) = BDY(a1); |
|
} |
|
NEXT(t) = a2; |
|
return t0; |
|
} |
|
} |
|
|
int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
{ |
{ |
NODE m,m1,m2,base,exp,fa,pa,n; |
NODE m,m1,m2,base,exp,fa,pa,n; |
LIST l; |
LIST l; |
QUOTE qp,qf; |
QUOTE qp,qf; |
FNODE fbase,fexp; |
FNODE fbase,fexp,a; |
FUNC ff,pf; |
FUNC ff,pf; |
int r; |
int r; |
|
|
switch ( pat->id ) { |
switch ( pat->id ) { |
case I_PVAR: |
case I_PVAR: |
/* [[pat,f]] */ |
/* [[pat,f]] */ |
MKQUOTE(qf,f); |
*rp = mknode(1,mknode(2,(int)FA0(pat),f),0); |
MKQUOTE(qp,pat); |
|
n = mknode(2,qp,qf); MKLIST(l,n); |
|
*rp = mknode(1,l); |
|
return 1; |
return 1; |
|
|
case I_FORMULA: |
case I_FORMULA: |
Line 2652 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
Line 2737 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
} else { |
} else { |
fbase = f; fexp = mkfnode(1,I_FORMULA,ONE); |
fbase = f; fexp = mkfnode(1,I_FORMULA,ONE); |
} |
} |
r = fnode_normalize_unify(fbase,FA1(pat),&base); |
if ( !fnode_normalize_unify(fbase,FA1(pat),&base) ) return 0; |
if ( !r ) return 0; |
a = rewrite_fnode(FA2(pat),base); |
r = fnode_normalize_unify(fexp,FA2(pat),&exp); |
if ( !fnode_normalize_unify(fexp,a,&exp) ) return 0; |
if ( !r ) return 0; |
else { |
else return merge_matching_node(base,exp,rp); |
*rp = append_node(base,exp); |
|
return 1; |
|
} |
break; |
break; |
|
|
case I_FUNC: |
case I_FUNC: |
Line 2668 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
Line 2755 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
pa = (NODE)FA0((FNODE)FA1(pat)); |
pa = (NODE)FA0((FNODE)FA1(pat)); |
m = 0; |
m = 0; |
while ( fa && pa ) { |
while ( fa && pa ) { |
r = fnode_normalize_unify(BDY(fa),BDY(pa),&m1); |
a = rewrite_fnode(BDY(pa),m); |
if ( !r ) return 0; |
if ( !fnode_normalize_unify(BDY(fa),a,&m1) ) return 0; |
r = merge_matching_node(m,m1,&m2); |
m = append_node(m1,m); |
if ( !r ) return 0; |
fa = NEXT(fa); pa = NEXT(pa); |
else m = m2; |
|
} |
} |
if ( fa || pa ) return 0; |
if ( fa || pa ) return 0; |
else { |
else { |
Line 2694 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
Line 2780 int fnode_normalize_unify(FNODE f,FNODE pat,NODE *rp) |
|
} |
} |
} |
} |
|
|
int fnode_normalize_unify_naryadd(FNODE f,FNODE pat,NODE *rp){} |
/* remove i-th element */ |
|
|
int fnode_normalize_unify_narymul(FNODE f,FNODE pat,NODE *rp){} |
FNODE fnode_removeith_naryadd(FNODE p,int i) |
|
{ |
|
int k,l; |
|
NODE t,r0,r,a; |
|
|
/* |
a = (NODE)FA1(p); |
int fnode_normalize_unify_naryadd(FNODE f,FNODE pat,NODE *rp) |
l = length(a); |
|
if ( i < 0 || i >= l ) error("fnode_removeith_naryadd: invalid index"); |
|
else if ( i == 0 ) |
|
return fnode_node_to_naryadd(NEXT(a)); |
|
else { |
|
for ( r0 = 0, k = 0, t = a; k < i; k++, t = NEXT(t) ) { |
|
NEXTNODE(r0,r); |
|
BDY(r) = BDY(t); |
|
} |
|
t = NEXT(t); |
|
NEXT(r) = 0; |
|
return fnode_node_to_naryadd(r0); |
|
} |
|
|
|
} |
|
|
|
/* a0,...,a(i-1) */ |
|
FNODE fnode_left_narymul(FNODE p,int i) |
{ |
{ |
int lf,lp; |
int k,l; |
|
NODE t,r0,r,a; |
|
|
|
a = (NODE)FA1(p); |
|
l = length(a); |
|
if ( i < 0 || i >= l ) error("fnode_left_narymul : invalid index"); |
|
if ( i == 0 ) return mkfnode(1,I_FORMULA,ONE); |
|
else if ( i == 1 ) return (FNODE)BDY(a); |
|
else { |
|
for ( r0 = 0, k = 0, t = a; k < i; k++, t = NEXT(t) ) { |
|
NEXTNODE(r0,r); |
|
BDY(r) = BDY(t); |
|
} |
|
NEXT(r) = 0; |
|
return fnode_node_to_narymul(r0); |
|
} |
|
} |
|
|
|
/* a(i+1),...,a(l-1) */ |
|
FNODE fnode_right_narymul(FNODE p,int i) |
|
{ |
|
NODE a,t; |
|
int l,k; |
|
|
|
a = (NODE)FA1(p); |
|
l = length(a); |
|
if ( i < 0 || i >= l ) error("fnode_right_narymul : invalid index"); |
|
if ( i == l-1 ) return mkfnode(1,I_FORMULA,ONE); |
|
else { |
|
for ( k = 0, t = a; k <= i; k++, t = NEXT(t) ); |
|
return fnode_node_to_narymul(t); |
|
} |
|
} |
|
|
|
int fnode_normalize_unify_naryadd(FNODE f,FNODE p,NODE *rp) |
|
{ |
|
int fl,pl,fi,pi; |
|
NODE fa,pa,t,s,m,m1; |
|
FNODE fr,pr,prr,pivot; |
|
|
f = to_naryadd(f); |
f = to_naryadd(f); |
lf = length((NODE)FA1(f)); |
fa = (NODE)FA1(f); fl = length(fa); |
lp = length((NODE)FA1(pat)); |
pa = (NODE)FA1(p); pl = length(pa); |
if ( lf < lp ) return 0; |
if ( fl < pl ) return 0; |
else if ( lp == 1 ) { |
else if ( pl == 1 ) { |
if ( lf == 1 ) |
if ( fl == 1 ) |
return fnode_normalize_unify( |
return fnode_normalize_unify(BDY(fa),BDY(pa),rp); |
BDY((NODE)FA1(f)),BDY((NODE)FA1(pat)),rp); |
|
else |
else |
return 0; |
return 0; |
} else { |
} else { |
sel = (int *)ALLOCA(lf); |
for ( t = pa, pi = 0; t; t = NEXT(t), pi++ ) |
|
if ( ((FNODE)BDY(t))->id != I_PVAR ) break; |
|
if ( !t ) { |
|
/* all are I_PVAR */ |
|
m = 0; |
|
for ( t = pa, s = fa; NEXT(t); t = NEXT(t), s = NEXT(s) ) { |
|
fnode_normalize_unify(BDY(s),BDY(t),&m1); |
|
m = append_node(m1,m); |
|
} |
|
if ( !NEXT(s) ) |
|
fr = (FNODE)BDY(s); |
|
else |
|
fr = mkfnode(2,I_NARYOP,FA0(f),s); |
|
fnode_normalize_unify(fr,BDY(t),&m1); |
|
*rp = append_node(m1,m); |
|
return 1; |
|
} else { |
|
pivot = (FNODE)BDY(t); |
|
pr = fnode_removeith_naryadd(p,pi); |
|
for ( s = fa, fi = 0; s; s = NEXT(s), fi++ ) { |
|
if ( fnode_normalize_unify(BDY(s),pivot,&m) ) { |
|
fr = fnode_removeith_naryadd(f,fi); |
|
prr = rewrite_fnode(pr,m); |
|
if ( fnode_normalize_unify(fr,prr,&m1) ) { |
|
*rp = append_node(m,m1); |
|
return 1; |
|
} |
|
} |
|
} |
|
return 0; |
|
} |
} |
} |
} |
} |
*/ |
|
|
|
|
int fnode_normalize_unify_narymul(FNODE f,FNODE p,NODE *rp) |
|
{ |
|
int fl,pl,fi,pi; |
|
NODE fa,pa,t,s,m,m1; |
|
FNODE fr,pr,pleft,pleft1,pright,pright1,fleft,fright,pivot; |
|
|
|
f = to_narymul(f); |
|
fa = (NODE)FA1(f); fl = length(fa); |
|
pa = (NODE)FA1(p); pl = length(pa); |
|
if ( fl < pl ) return 0; |
|
else if ( pl == 1 ) { |
|
if ( fl == 1 ) |
|
return fnode_normalize_unify(BDY(fa),BDY(pa),rp); |
|
else |
|
return 0; |
|
} else { |
|
for ( t = pa, pi = 0; t; t = NEXT(t), pi++ ) |
|
if ( ((FNODE)BDY(t))->id != I_PVAR ) break; |
|
if ( !t ) { |
|
/* all are I_PVAR */ |
|
m = 0; |
|
for ( t = pa, s = fa; NEXT(t); t = NEXT(t), s = NEXT(s) ) { |
|
pr = rewrite_fnode(BDY(t),m); |
|
if ( !fnode_normalize_unify(BDY(s),pr,&m1) ) return 0; |
|
m = append_node(m1,m); |
|
} |
|
if ( !NEXT(s) ) |
|
fr = (FNODE)BDY(s); |
|
else |
|
fr = mkfnode(2,I_NARYOP,FA0(f),s); |
|
pr = rewrite_fnode(BDY(t),m); |
|
if ( !fnode_normalize_unify(fr,pr,&m1) ) return 0; |
|
*rp = append_node(m1,m); |
|
return 1; |
|
} else { |
|
pivot = (FNODE)BDY(t); |
|
pleft = fnode_left_narymul(p,pi); |
|
pright = fnode_right_narymul(p,pi); |
|
/* XXX : incomplete */ |
|
for ( s = fa, fi = 0; s; s = NEXT(s), fi++ ) { |
|
if ( fnode_normalize_unify(BDY(s),pivot,&m) ) { |
|
fleft = fnode_left_narymul(f,fi); |
|
pleft1 = rewrite_fnode(pleft,m); |
|
if ( fnode_normalize_unify(fleft,pleft1,&m1) ) { |
|
m = append_node(m1,m); |
|
fright = fnode_right_narymul(f,fi); |
|
pright1 = rewrite_fnode(pright,m); |
|
if ( fnode_normalize_unify(fright,pright1,&m1) ) { |
|
*rp = append_node(m1,m); |
|
return 1; |
|
} |
|
} |
|
} |
|
} |
|
return 0; |
|
} |
|
} |
|
} |