1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package zeus.concepts;
29
30 import java.util.*;
31 import java.io.*;
32
33 import zeus.util.*;
34 import zeus.concepts.fn.*;
35
36 /***
37 * The Fact class is key conceptual data structure in ZEUS, since Fact objects
38 * store the information that collectively forms the application ontology.
39 * Each fact consists of a number of attribute-value pairs, which are stored
40 * in the {@link AttributeList} variable. <p>
41 * Fact objects come in two forms:
42 * <ul>
43 * <li> Fact Descriptions - these represent actual entities (always shown prefixed
44 * with an @ symbol).
45 * <li> Fact Variables - these are descriptions of virtual entities that can
46 * be instantiated as Facts (these always shown prefixed with a ? symbol).
47 * </ul> <p>
48 * Facts originate from template descriptions, so they can only be created
49 * from an existing ontology by invoking the {@link OntologyDb#getFact}
50 * method of the agent's {@link OntologyDb}.
51 *
52 *This class is a little case study in how a little knowledge can be a dangerous
53 *thing. It seems that the concept of checking boolean flags one at a time didn't
54 *appeal to whoever implemented it (DN?) and instead a int based mask system
55 *has been used to check and set the characteristics of the class. Unfortunately
56 *I suspect that the mask is used in side effects for a number of algorithms
57 *in the core reasoners, so while I would like to remove this nonsense, I so far
58 *haven't summed up the courage!
59 */
60
61 public class Fact {
62 public static final String NONVAR = "fact";
63 public static final String VAR = "var";
64 public static final String V_STR = "?";
65 public static final char V_CHR = '?';
66 public static final String F_STR = "@";
67 public static final char F_CHR = '@';
68 public static final String A_STR = ".";
69 public static final char A_CHR = '.';
70
71
72 public static final boolean FACT = false;
73 public static final boolean VARIABLE = true;
74 public static final String SELF_NAME = "self";
75 public static final String THIS_NAME = "this";
76 public static final String THIS = V_STR + THIS_NAME;
77 public static final String SELF = V_STR + SELF_NAME;
78
79 public static final String newVar(GenSym genSym) {
80 return genSym.plainId(V_STR+VAR);
81 }
82
83 protected static String name(boolean isVariable, GenSym genSym) {
84 String s = (isVariable ? VAR : NONVAR);
85 return genSym.plainId(s);
86
87 }
88
89
90
91
92
93
94 protected static final int IS_VARIABLE = 1;
95 protected static final int IS_NEGATION = 2;
96 protected static final int IS_READ_ONLY = 4;
97 protected static final int IS_REPLACED = 8;
98 protected static final int IS_LOCAL = 16;
99 protected static final int IS_SIDE_EFFECT = 32;
100
101 transient ValueFunction functor = null;
102 transient String descp = null;
103
104 protected String id;
105 protected String type;
106 protected int modifiers;
107 protected AttributeList attr;
108 protected OntologyDb ontology;
109
110 public Fact () {
111 ;
112 }
113
114 Fact(boolean is_variable, String type, OntologyDb ontology, GenSym genSym) {
115 this.id = name(is_variable,genSym);
116 this.type = type;
117 this.modifiers = is_variable ? IS_VARIABLE : 0;
118 this.ontology = ontology;
119 setFunctor();
120 }
121
122
123 public Fact(Fact fact) {
124 this.id = fact.ID();
125 this.type = fact.getType();
126 this.modifiers = fact.getModifiers();
127 this.attr = new AttributeList(fact.getAttributeList());
128 this.ontology = fact.getOntologyDb();
129 setFunctor();
130 }
131
132
133 public Fact(boolean is_variable, Fact fact) {
134 this(fact);
135 setIsVariable(is_variable);
136 }
137
138
139 protected Fact(String type, String id, int modifiers,
140 AttributeList attr, OntologyDb ontology) {
141 this.id = id;
142 this.type = type;
143 this.modifiers = modifiers;
144 this.attr = attr;
145 this.ontology = ontology;
146 setFunctor();
147 }
148
149
150 /***
151 *made this accessor public (simon 23/9/02)
152 *with the object of using it to get service description information
153 **/
154 public OntologyDb getOntologyDb() {
155 return ontology;
156 }
157
158
159 /***
160 * Here mode defines whether or not this fact owns the attribute
161 * being edited, where 'true' implies the fact owns the attribute
162 */
163 public TreeNode createAttributeTree(boolean mode) {
164
165 String name = (mode) ? SELF : getId();
166 return ontology.createAttributeTree(type,name);
167 }
168
169
170
171
172
173
174
175 public static boolean isVariable(int x) { return (x&IS_VARIABLE) != 0; }
176 public static boolean isNegative(int x) { return (x&IS_NEGATION) != 0; }
177 public static boolean isReadOnly(int x) { return (x&IS_READ_ONLY) != 0; }
178 public static boolean isLocal(int x) { return (x&IS_LOCAL) != 0; }
179 public static boolean isReplaced(int x) { return (x&IS_REPLACED) != 0; }
180 public static boolean isSideEffect(int x) { return (x&IS_SIDE_EFFECT) != 0; }
181
182 public boolean isVariable() { return isVariable(modifiers); }
183 public boolean isNegative() { return isNegative(modifiers); }
184 public boolean isReadOnly() { return isReadOnly(modifiers); }
185 public boolean isLocal() { return isLocal(modifiers); }
186 public boolean isReplaced() { return isReplaced(modifiers); }
187 public boolean isSideEffect() { return isSideEffect(modifiers); }
188
189 public String ID() { return id; }
190 public String getId() { return descp; }
191 public String getType() { return type; }
192 public int getModifiers() { return modifiers; }
193
194 public void setId(String id) {
195 Assert.notNull(id);
196 this.id = id;
197 setFunctor();
198 }
199
200 public void setType(String type) {
201 Assert.notNull(type);
202 this.type = type;
203 setFunctor();
204 }
205
206
207 public void setModifiers(int modifiers) {
208 this.modifiers = modifiers;
209 setFunctor();
210 }
211
212 public static int setIsVariable(int x, boolean set) {
213 if ( set )
214 x |= IS_VARIABLE;
215 else
216 x &= ~IS_VARIABLE;
217 return x;
218 }
219
220 public static int setIsNegative(int x, boolean set) {
221
222
223 if ( set ) {
224 x &= ~(IS_READ_ONLY|IS_LOCAL|IS_REPLACED);
225 x |= IS_NEGATION;
226 }
227 else
228 x &= ~IS_NEGATION;
229 return x;
230 }
231
232 public static int setIsReadOnly(int x, boolean set) {
233
234
235 if ( set ) {
236 x &= ~(IS_NEGATION|IS_REPLACED);
237 x |= IS_READ_ONLY;
238 }
239 else
240 x &= ~IS_READ_ONLY;
241 return x;
242 }
243
244 public static int setIsLocal(int x, boolean set) {
245
246
247 if ( set ) {
248 x &= ~IS_NEGATION;
249 x |= IS_LOCAL;
250 }
251 else
252 x &= ~IS_LOCAL;
253 return x;
254 }
255
256 public static int setIsReplaced(int x, boolean set) {
257
258
259 if ( set ) {
260 x &= ~(IS_READ_ONLY|IS_NEGATION);
261 x |= IS_REPLACED;
262 }
263 else
264 x &= ~IS_REPLACED;
265 return x;
266 }
267
268 public static int setIsSideEffect(int x, boolean set) {
269 if ( set )
270 x |= IS_SIDE_EFFECT;
271 else
272 x &= ~IS_SIDE_EFFECT;
273 return x;
274 }
275
276
277 public void setIsVariable(boolean set) {
278 modifiers = setIsVariable(modifiers,set);
279 setFunctor();
280 }
281 public void setIsNegative(boolean set) {
282 modifiers = setIsNegative(modifiers,set);
283 }
284 public void setIsReadOnly(boolean set) {
285 modifiers = setIsReadOnly(modifiers,set);
286 }
287 public void setIsLocal(boolean set) {
288 modifiers = setIsLocal(modifiers,set);
289 }
290 public void setIsReplaced(boolean set) {
291 modifiers = setIsReplaced(modifiers,set);
292 }
293 public void setIsSideEffect(boolean set) {
294 modifiers = setIsSideEffect(modifiers,set);
295 }
296
297 public String[] listAttributes() {
298 return attr.listAttributes();
299 }
300 public ValueFunction[] listValues() {
301 return attr.listValues();
302 }
303 public ValueFunction[] variables() {
304 Vector out = attr.variables();
305 if ( isVariable() && !out.contains(functor()) )
306 out.addElement(functor());
307
308 ValueFunction[] result = new ValueFunction[out.size()];
309 for(int i = 0; i < result.length; i++ )
310 result[i] = (ValueFunction)out.elementAt(i);
311 return result;
312 }
313
314 /***
315 getAttributeList returns a list of the attributes of the Fact.
316 This is public in 1.2.1 so that it can be manipulated directly
317 */
318 public AttributeList getAttributeList() {
319 return attr;
320 }
321
322 public String getValue(String attribute) {
323 String value = attr.getValue(attribute);
324 if ( value == null )
325 Core.USER_ERROR("Fact.getValue(): No attribute \'" + attribute +
326 "\' found in fact \'" + this + "\'");
327 return value;
328 }
329
330
331 public ValueFunction getFn(String attribute) {
332 ValueFunction value = attr.getFn(attribute);
333 if ( value == null )
334 Core.USER_ERROR("Fact.getValue(): No attribute \'" + attribute +
335 "\' found in fact \'" + this + "\'");
336 return value;
337 }
338
339 public int getInt(String attribute) {
340 try {
341 PrimitiveNumericFn fn;
342 fn = (PrimitiveNumericFn)attr.getFn(attribute);
343 return fn.intValue();
344 }
345 catch(ClassCastException e) {
346 Core.USER_ERROR("Fact.getInt(\'" + attribute +
347 "\') called for non-ground value \'" + this + "\'");
348 return 0;
349 }
350 catch(NullPointerException e1) {
351 Core.USER_ERROR("Fact.getInt(): No attribute \'" + attribute +
352 "\' found in fact \'" + this + "\'");
353 return 0;
354 }
355 }
356
357 public double getDouble(String attribute) {
358 try {
359 PrimitiveNumericFn fn;
360 fn = (PrimitiveNumericFn)attr.getFn(attribute);
361 return fn.doubleValue();
362 }
363 catch(ClassCastException e) {
364 Core.USER_ERROR("Fact.getDouble(\'" + attribute +
365 "\') called for non-ground value \'" + this + "\'");
366 return 0;
367 }
368 catch(NullPointerException e1) {
369 Core.USER_ERROR("Fact.getDouble(): No attribute \'" + attribute +
370 "\' found in fact \'" + this + "\'");
371 return 0;
372 }
373 }
374
375 public long getLong(String attribute) {
376 try {
377 PrimitiveNumericFn fn;
378 fn = (PrimitiveNumericFn)attr.getFn(attribute);
379 return fn.longValue();
380 }
381 catch(ClassCastException e) {
382 Core.USER_ERROR("Fact.getLong(\'" + attribute +
383 "\') called for non-ground value \'" + this + "\'");
384 return 0;
385 }
386 catch(NullPointerException e1) {
387 Core.USER_ERROR("Fact.getLong(): No attribute \'" + attribute +
388 "\' found in fact \'" + this + "\'");
389 return 0;
390 }
391 }
392
393 public int getNumber() {
394 if ( !isa(OntologyDb.ENTITY) ) return 1;
395
396 try {
397 PrimitiveNumericFn fn;
398 fn = (PrimitiveNumericFn)attr.getFn(OntologyDb.NUMBER);
399 return fn.intValue();
400 }
401 catch(ClassCastException e) {
402
403 e.printStackTrace();
404
405 Core.USER_ERROR("getNumber() called for non-ground value \'" +
406 this + "\'");
407 return 0;
408 }
409 }
410
411 public void setNumber(int x) {
412 if ( isa(OntologyDb.ENTITY) )
413 setValue(OntologyDb.NUMBER,x);
414 else if ( x != 1 )
415 Core.USER_ERROR("setNumber() called for non-" + OntologyDb.ENTITY +
416 " object \'" + this + "\'");
417 }
418 public void setNumber(VarFn var1) {
419 if ( isa(OntologyDb.ENTITY) )
420 setValue(OntologyDb.NUMBER,var1);
421 else
422 Core.USER_ERROR("setNumber() called for non-" + OntologyDb.ENTITY +
423 " object \'" + this + "\'");
424 }
425
426 public double getNetCost() {
427 if ( isa(OntologyDb.ENTITY) && !isDeterminate(OntologyDb.COST) ) return 0;
428 return getNumber() * getUnitCost();
429 }
430 public double getUnitCost() {
431 if ( !isa(OntologyDb.ENTITY) ) return 0;
432
433 try {
434 PrimitiveNumericFn fn;
435 fn = (PrimitiveNumericFn)attr.getFn(OntologyDb.COST);
436 return fn.doubleValue();
437 }
438 catch(ClassCastException e) {
439 Core.USER_ERROR("getUnitCost() called for non-ground value \'" +
440 this + "\'");
441 return 0;
442 }
443 }
444 public void setUnitCost(double x) {
445 if ( isa(OntologyDb.ENTITY) )
446 setValue(OntologyDb.COST,x);
447 else
448 Core.USER_ERROR("setUnitCost() called for non-" + OntologyDb.ENTITY +
449 " object \'" + this + "\'");
450 }
451 public void setUnitCost(VarFn var1) {
452 if ( isa(OntologyDb.ENTITY) )
453 setValue(OntologyDb.COST,var1);
454 else
455 Core.USER_ERROR("setUnitCost() called for non-" + OntologyDb.ENTITY +
456 " object \'" + this + "\'");
457 }
458
459 public VarFn newVar() {
460 return new VarFn(newVar(ontology.GenSym()));
461 }
462
463 public void setValue(String attribute, int value) {
464 setValue(attribute, new IntFn(value));
465 }
466 public void setValue(String attribute, long value) {
467 setValue(attribute, new IntFn(value));
468 }
469 public void setValue(String attribute, double value) {
470 setValue(attribute, new RealFn(value));
471 }
472 public void setValue(String attribute, boolean value) {
473 setValue(attribute, BoolFn.newBoolFn(value));
474 }
475 public void setValue(String attribute, String value) {
476 ValueFunction fn = ZeusParser.Expression(ontology,value);
477 if ( fn == null )
478 Core.USER_ERROR("Cannot parse value \'" + value +
479 "\' in Fact.setValue()");
480 else
481 setValue(attribute,fn);
482 }
483 public void setValue(String attribute, ValueFunction value) {
484 if ( !ontology.validate(type,attribute,value) )
485 Core.USER_ERROR("Setting value \'" + value + "\' for " +
486 "attribute \'" + attribute + "\' in fact \'" + this + "\'");
487 else
488 attr.setValue(attribute, value);
489 }
490 void setAttributeList(AttributeList List) {
491 Assert.notNull(List);
492 attr = List;
493 }
494
495 public void setValues(String[] input) {
496 if ( input.length%2 != 0 ) {
497 Core.USER_ERROR("Fact.setValues():: improper input length \"{" +
498 Misc.concat(input) + "}\".");
499 return;
500 }
501
502 for(int i = 0; i < input.length; i += 2 )
503 setValue(input[i],input[i+1]);
504 }
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543 /***
544 possibly this should return a true if it is equals in an oo sense?
545 */
546 public boolean equals(Object obj) {
547 debug ("normal equality " + this.toString());
548 if ( !(obj instanceof Fact) ) return false;
549 Fact f = (Fact)obj;
550 if ( !type.equals(f.getType()) )
551 return false;
552 if ( isVariable() || f.isVariable() )
553 return attr.equals(f.getAttributeList());
554 else
555 return descp.equals(f.getId());
556 }
557
558
559 protected void setFunctor() {
560 descp = isVariable() ? V_STR + id : F_STR + id;
561 functor = isVariable() ? (ValueFunction)(new VarFn(descp))
562 : (ValueFunction)(new TypeFn(descp));
563 }
564
565 public boolean isDeterminate() {
566 return isVariable() ? false : attr.isDeterminate();
567 }
568
569 public boolean isDeterminate(String attribute) {
570 return attr.isDeterminate(attribute);
571 }
572
573 public String[] objectAttributeNames() {
574 String[] a = attr.listAttributes();
575 String object = getId();
576 for(int i = 0; i < a.length; i++ )
577 a[i] = object + A_STR + a[i];
578 return a;
579 }
580
581 public String toString() {
582
583
584
585
586 String s = "(:type " + type + " " +
587 ":id " + id + " " +
588 ":modifiers " + modifiers;
589 if ( !attr.isEmpty() )
590 s += " :attributes " + attr.toString();
591 return s + ")";
592 }
593
594
595
596 /***
597 added by Simon on 20/02/02
598 Get the SL value of this fact
599 An abs factory implementation would be better, but I want to have a go at this
600 first before investing too heavily in a final implementation
601 */
602 public String toSL () {
603 String s = "(" + type+" ";
604 if (!attr.isEmpty())
605 s += attr.toSL();
606 return s +")";
607 }
608
609
610
611 public String pprint() {
612 return pprint(0);
613 }
614
615
616 public String pprint(int sp) {
617 String suffix, prefix;
618 String tabs = Misc.spaces(sp);
619 String eol = "\n" + tabs + " ";
620
621 String s = "(:type " + type + eol +
622 ":id " + id + eol +
623 ":modifiers " + modifiers + eol;
624
625 if ( !attr.isEmpty() ) {
626 prefix = ":attributes ";
627 suffix = Misc.spaces(1 + sp + prefix.length());
628 s += prefix + attr.pprint(suffix.length());
629 }
630 return s.trim() + "\n" + tabs + ")";
631 }
632
633
634 /***
635 *this is a bit of a mess, because we are passing a parameter that is
636 *used to ppring the fact into DAML format...
637 *header is the front of the parameter, footer is the close tag
638 */
639 public String printDAML (String header,String footer) {
640 String names [] = attr.getNames();
641 String out = new String ();
642 for (int count = 0;count<names.length; count++) {
643 out += header + "#" + type +":" + names[count] + "=" + attr.getValue(names[count]) + "//\""+footer+"//n\";\n";
644 }
645 return out;
646 }
647
648 public boolean unifiesWith(Fact f, Bindings bindings) {
649 if ( type.equals(f.getType()) ) {
650
651 if ( !isVariable() && !f.isVariable() && !descp.equals(f.getId()) )
652 return false;
653
654 Bindings b = new Bindings(bindings);
655 ValueFunction me = functor();
656 ValueFunction you = f.functor();
657
658 if ( me.unifiesWith(you,b) == null ||
659 !attr.unifiesWith(f.getAttributeList(),b) )
660 return false;
661
662 bindings.set(b);
663 return true;
664 }
665 return false;
666 }
667
668 public boolean unifiesWithChild(Fact f, Bindings bindings) {
669 if ( type.equals(f.getType()) )
670 return unifiesWith(f,bindings);
671
672 else if ( ontology.isAncestorOf(f.getType(),type) ) {
673 if ( !isVariable() && !f.isVariable() )
674 return false;
675
676 Bindings b = new Bindings(bindings);
677
678 if ( !attr.unifiesWith(f.getAttributeList(),b) )
679 return false;
680
681 bindings.set(b);
682 return true;
683 }
684 return false;
685 }
686
687 public boolean isa(String ancestor) {
688 return type.equals(ancestor) || ontology.isAncestorOf(type,ancestor);
689 }
690
691 public ValueFunction functor() {
692 return (ValueFunction) functor;
693 }
694 public boolean resolve(Bindings bindings) {
695 return resolve(new ResolutionContext(),bindings);
696 }
697 public boolean resolve(ResolutionContext context, Bindings bindings) {
698 Object obj = context.put(THIS,this);
699 boolean status = attr.resolve(context,bindings);
700 if ( obj != null ) context.put(THIS,obj);
701 return status;
702 }
703
704 public boolean disjoin(Fact f) {
705 if ( !type.equals(f.getType()) ) return false;
706 attr.disjoin(f.getAttributeList());
707 return true;
708 }
709
710 public Fact duplicate(String name, GenSym genSym) {
711 DuplicationTable table = new DuplicationTable(name,genSym);
712 return duplicate(table);
713 }
714
715
716 public Fact duplicate(DuplicationTable table) {
717 String id1 = table.getRef(id);
718 AttributeList attr1 = attr.duplicate(table);
719 Fact f1 = new Fact(type,id1,modifiers,attr1,ontology);
720 return f1;
721 }
722
723 /***
724 test to see if any of the values in this fact are mapped to
725 the valeus in the @param mapper, make a map of attno to attno for all the
726 attributes so that they can be mapped in the method map
727 */
728 public synchronized String[] buildMap(Fact mapper) {
729 debug (this.type);
730 String [] retVal = new String[attr.size()];
731 Enumeration keys = attr.keys();
732 AttributeList mapperAttr = mapper.getAttributeList();
733 int count = 0;
734 while (keys.hasMoreElements()){
735 Enumeration mapperKeys = mapperAttr.keys();
736 String key = (String) keys.nextElement();
737 String val = attr.getValue(key);
738 int count2 = 0;
739 boolean done = false;
740 while (mapperKeys.hasMoreElements()&& !done) {
741 String mkey = (String) mapperKeys.nextElement();
742 String mval = mapperAttr.getValue(mkey);
743 ValueFunction mVf = mapperAttr.getFn (mkey);
744 debug ("mVf = " + mVf.toString() + " " + mVf.getClass());
745 ValueFunction vf = attr.getFn (key);
746 debug ("vf = " + vf.toString());
747 if (mVf.equals (vf)) {
748 debug ("mVf == vf");
749 }
750 else {
751 debug ("mVf != vf");
752 }
753 debug ("in buildMap mkey = " + mkey + " mval = " + mval + " val = " + val);
754 if (mval.equals (val) && val.startsWith("?")) {
755 debug ("mapping:" + mval + " = " + val);
756 retVal[count] = mkey;
757 done = true;
758 }
759 else if (val.startsWith(mapper.getId())) {
760 debug("ID's match!!");
761 String attrVal = val.substring(mapper.getId().length()+1, val.length());
762 debug ("attrVal == " + attrVal);
763 if (!mkey.equals(attrVal)) {
764 debug (mkey + " != " + attrVal);
765 retVal [count] = null;}
766 else {
767 debug (mkey + " == " + attrVal);
768 retVal [count] = mkey;
769 done = true;
770 }
771 }
772 else {
773 retVal [count] = null; }
774 count2++;
775 }
776 count++;
777 }
778 return (retVal);
779 }
780
781 /***
782 map the values of the attributes in this fact to the values in the
783 fact mapper. map is an array of ints such that map[1] = 3 indicates
784 that the attribute value[3] of mapper should be mapped to the value 1 of
785 this fact
786 */
787 public synchronized void doMap (Fact mapper, String [] tmap) {
788 Core.DEBUG(1,"in doMap in Fact\n");
789 AttributeList mapperAttr = mapper.getAttributeList();
790 debug ("attr == " + attr.toString());
791 debug ("mapperAttr = " + mapperAttr.toString());
792 AttributeList newAttr = attr.duplicate("newAttr", new GenSym("temp"));
793
794 debug ("newAttr == " + newAttr.toString());
795 Enumeration keys = attr.keys();
796 int count = 0;
797 while (keys.hasMoreElements()){
798 String key = (String) keys.nextElement();
799 debug("int doMap key = " + key);
800 ValueFunction val = attr.getFn(key);
801 if (tmap [count] != null) {
802 debug("altering value");
803 newAttr.remove(key);
804 debug ("tmap = " + tmap [count]);
805 debug("count = " + String.valueOf(count));
806
807 debug ("mapper.getFn(tmap[count]) = " + mapper.getFn(tmap[count]));
808 newAttr.put(key,mapper.getFn(tmap[count]));
809 }
810 else
811 newAttr.put (key, val);
812 count++;
813 }
814 attr = newAttr;
815
816 }
817
818
819
820 public synchronized ValueFunction getVal(int pos) {
821 Enumeration keys = attr.keys();
822 int count = 0;
823 if (pos < attr.size()) {
824 String key = null;
825 for (count = 0; count <= pos; count++) {
826 key = (String)keys.nextElement();
827 }
828 debug ("key = " + key);
829
830 return attr.getFn(key); }
831 else
832 debug (String.valueOf(attr.size()));
833 return null;
834 }
835
836
837 public void map (Fact toMap) {
838 String [] mapval = buildMap (toMap);
839 doMap (toMap, mapval);
840 }
841
842
843 private void debug (String str) {
844
845 }
846
847
848 public static void main (String argv[]) {
849 ;
850
851
852 }
853
854 }