source: trunk/quest-plugin-jfc/src/main/java/de/ugoe/cs/quest/plugin/jfc/JFCTraceCorrector.java @ 834

Last change on this file since 834 was 834, checked in by pharms, 12 years ago
  • improved memory usage
File size: 28.9 KB
Line 
1package de.ugoe.cs.quest.plugin.jfc;
2
3import java.io.BufferedOutputStream;
4import java.io.File;
5import java.io.FileInputStream;
6import java.io.FileNotFoundException;
7import java.io.FileOutputStream;
8import java.io.IOException;
9import java.io.InputStreamReader;
10import java.io.PrintStream;
11import java.io.UnsupportedEncodingException;
12import java.util.ArrayList;
13import java.util.HashMap;
14import java.util.List;
15import java.util.Map;
16
17import javax.xml.parsers.ParserConfigurationException;
18import javax.xml.parsers.SAXParser;
19import javax.xml.parsers.SAXParserFactory;
20
21import org.xml.sax.Attributes;
22import org.xml.sax.InputSource;
23import org.xml.sax.SAXException;
24import org.xml.sax.SAXParseException;
25import org.xml.sax.helpers.DefaultHandler;
26
27import de.ugoe.cs.util.StringTools;
28import de.ugoe.cs.util.console.Console;
29
30/**
31 * <p>
32 * corrects older JFC log files which sometimes do not contain correct source specifications for
33 * events. It parses the file and adds component specifications to the sources, that do not have
34 * them. For each invalid source it checks, if there is another source with the same
35 * <code>toString</code> parameter but a complete list of components. If one is found, it is reused
36 * as source for the event with the wrong source. If none is found, a new component list is
37 * generated. This contains as parent components the components of the source of the previous event.
38 * The leaf component is parsed from the <code>toString</code> parameter that is provided with the
39 * source specifications. The resulting leaf nodes are not fully correct. They may pretend to
40 * be equal although they are not. Furthermore they may resist at a position in the GUI tree where
41 * they are not in reality. But more correctness is not achievable based on the
42 * <code>toString</code> parameter.
43 * </p>
44 *
45 * @version $Revision: $ $Date: 05.09.2012$
46 * @author 2012, last modified by $Author: pharms$
47 */
48public class JFCTraceCorrector  extends DefaultHandler {
49
50    /**
51     * <p>
52     * the file to write the result into
53     * </p>
54     */
55    private PrintStream outFile;
56   
57    /**
58     * <p>
59     * the currently parsed event
60     * </p>
61     */
62    private Event currentEvent;
63
64    /**
65     * <p>
66     * the currently parsed source of the currently parsed event
67     * </p>
68     */
69    private Source currentSource;
70
71    /**
72     * <p>
73     * the list of all sources parsed in a file identified through their <code>toString</code>
74     * representation
75     * </p>
76     */
77    private Map<String, List<Source>> allSources = new HashMap<String, List<Source>>();
78
79    /**
80     * <p>
81     * the currently parsed component of the currently parsed source of the currently parsed event
82     * </p>
83     */
84    private Component currentComponent;
85
86    /**
87     * <p>
88     * the currently parsed session
89     * </p>
90     */
91    private Session currentSession;
92
93    /**
94     * <p>
95     * corrects the given file and returns the name of the file into which the result was written
96     * </p>
97     *
98     * @param filename the name of the file to be corrected
99     *
100     * @return the name of the file with the corrected logfile
101     *
102     * @throws IllegalArgumentException if the filename is null
103     */
104    public String correctFile(String filename) throws IllegalArgumentException {
105        if (filename == null) {
106            throw new IllegalArgumentException("filename must not be null");
107        }
108
109        return correctFile(new File(filename)).getAbsolutePath();
110    }
111
112    /**
113     * <p>
114     * corrects the given file, stores the result in the second provided file and returns the
115     * name of the file into which the result was written
116     * </p>
117     *
118     * @param filename   the name of the file to be corrected
119     * @param resultFile the name of the file into which the corrected log shall be written
120     *
121     * @return the name of the file with the corrected logfile
122     *
123     * @throws IllegalArgumentException if the filename or resultFile is null
124     */
125    public String correctFile(String filename, String resultFile) throws IllegalArgumentException {
126        if ((filename == null) | (resultFile == null)) {
127            throw new IllegalArgumentException("filename and resultFile must not be null");
128        }
129
130        return correctFile(new File(filename), new File(resultFile)).getAbsolutePath();
131    }
132
133    /**
134     * <p>
135     * corrects the given file and returns the file into which the result was written. The name
136     * of the resulting file is contains the suffix "_corrected" before the dot.
137     * </p>
138     *
139     * @param file the file to be corrected
140     *
141     * @return the file containing the corrected logfile
142     *
143     * @throws IllegalArgumentException if the file is null
144     */
145    public File correctFile(File file) throws IllegalArgumentException {
146        if (file == null) {
147            throw new IllegalArgumentException("file must not be null");
148        }
149
150        int index = file.getName().lastIndexOf('.');
151        String fileName =
152            file.getName().substring(0, index) + "_corrected" + file.getName().substring(index);
153
154        File resultFile = new File(file.getParentFile(), fileName);
155
156        return correctFile(file, resultFile);
157    }
158
159    /**
160     * <p>
161     * corrects the given file, stores the result in the second provided file and returns the
162     * file into which the result was written
163     * </p>
164     *
165     * @param file       the file to be corrected
166     * @param resultFile the file into which the corrected log shall be written
167     *
168     * @return the file with the corrected logfile
169     *
170     * @throws IllegalArgumentException if the file or resultFile is null or if they are equal
171     */
172    public File correctFile(File file, File resultFile) throws IllegalArgumentException {
173        if ((file == null) || (resultFile == null)) {
174            throw new IllegalArgumentException("file and result file must not be null");
175        }
176       
177        if (file.getAbsolutePath().equals(resultFile.getAbsolutePath())) {
178            throw new IllegalArgumentException("file and result file must not be equal");
179        }
180       
181        try {
182            outFile = new PrintStream(new BufferedOutputStream(new FileOutputStream(resultFile)));
183            outFile.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
184        }
185        catch (FileNotFoundException e1) {
186            throw new IllegalArgumentException("could not create a corrected file name " +
187                                               resultFile + " next to " + file);
188        }
189       
190
191        SAXParserFactory spf = SAXParserFactory.newInstance();
192        spf.setValidating(true);
193
194        SAXParser saxParser = null;
195        InputSource inputSource = null;
196        try {
197            saxParser = spf.newSAXParser();
198            inputSource =
199                new InputSource(new InputStreamReader(new FileInputStream(file), "UTF-8"));
200        }
201        catch (UnsupportedEncodingException e) {
202            Console.printerr("Error parsing file + " + file.getName());
203            Console.logException(e);
204            return null;
205        }
206        catch (ParserConfigurationException e) {
207            Console.printerr("Error parsing file + " + file.getName());
208            Console.logException(e);
209            return null;
210        }
211        catch (SAXException e) {
212            Console.printerr("Error parsing file + " + file.getName());
213            Console.logException(e);
214            return null;
215        }
216        catch (FileNotFoundException e) {
217            Console.printerr("Error parsing file + " + file.getName());
218            Console.logException(e);
219            return null;
220        }
221        if (inputSource != null) {
222            inputSource.setSystemId("file://" + file.getAbsolutePath());
223            try {
224                if (saxParser == null) {
225                    throw new RuntimeException("SAXParser creation failed");
226                }
227                saxParser.parse(inputSource, this);
228            }
229            catch (SAXParseException e) {
230                Console.printerrln("Failure parsing file in line " + e.getLineNumber() +
231                    ", column " + e.getColumnNumber() + ".");
232                Console.logException(e);
233                return null;
234            }
235            catch (SAXException e) {
236                Console.printerr("Error parsing file + " + file.getName());
237                Console.logException(e);
238                return null;
239            }
240            catch (IOException e) {
241                Console.printerr("Error parsing file + " + file.getName());
242                Console.logException(e);
243                return null;
244            }
245        }
246       
247        if (outFile != null) {
248            outFile.close();
249        }
250       
251        return resultFile;
252    }
253
254    /*
255     * (non-Javadoc)
256     *
257     * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String,
258     * java.lang.String, org.xml.sax.Attributes)
259     */
260    public void startElement(String uri, String localName, String qName, Attributes atts)
261        throws SAXException
262    {
263        if (qName.equals("sessions")) {
264            currentSession = new Session();
265            currentSession.type = "sessions";
266        }
267        else if (qName.equals("newsession")) {
268            if (currentSession != null) {
269                currentSession.dump(outFile);
270            }
271           
272            currentSession = new Session();
273            currentSession.type = "newsession";
274        }
275        else if (qName.equals("event")) {
276            currentEvent = new Event();
277            currentEvent.id = atts.getValue("id");
278        }
279        else if (qName.equals("source")) {
280            currentSource = new Source();
281        }
282        else if (qName.equals("component")) {
283            currentComponent = new Component();
284        }
285        else if (qName.equals("param")) {
286            if (currentComponent != null) {
287                currentComponent.params.add
288                    (new String[] {atts.getValue("name"), atts.getValue("value") });
289            }
290            else if (currentSource != null) {
291                currentSource.params.add
292                    (new String[] {atts.getValue("name"), atts.getValue("value") });
293            }
294            else if (currentEvent != null) {
295                currentEvent.params.add
296                    (new String[] {atts.getValue("name"), atts.getValue("value") });
297            }
298            else {
299                throw new SAXException("parameter occurred at an unexpected place");
300            }
301        }
302        else {
303            throw new SAXException("unexpected tag " + qName);
304        }
305    }
306
307    /*
308     * (non-Javadoc)
309     *
310     * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String,
311     * java.lang.String)
312     */
313    @Override
314    public void endElement(String uri, String localName, String qName) throws SAXException {
315        if (qName.equals("sessions")) {
316            correctSources(currentSession);
317
318            currentSession.dump(outFile);
319            currentSession = null;
320            allSources.clear();
321        }
322        else if (qName.equals("newsession")) {
323            correctSources(currentSession);
324           
325            currentSession.dump(outFile);
326            currentSession = null;
327            allSources.clear();
328        }
329        else if (qName.equals("event")) {
330            currentSession.events.add(currentEvent);
331            currentEvent = null;
332        }
333        else if (qName.equals("source")) {
334            currentEvent.source = getUniqueSource(currentSource);
335            currentSource = null;
336        }
337        else if (qName.equals("component")) {
338            currentSource.components.add(currentComponent);
339            currentComponent = null;
340        }
341        else if (!qName.equals("param")) {
342            throw new SAXException("unexpected closing tag " + qName);
343        }
344
345    }
346
347    /**
348     * <p>
349     * stores a parsed source for later correction or reuse
350     * </p>
351     *
352     * @param source the source to store
353     */
354    private Source getUniqueSource(Source source) {
355        String toStringValue = getToStringParam(source);
356
357        Source existingSource = findSource(toStringValue);
358       
359        if (existingSource == null) {
360            List<Source> sources = allSources.get(toStringValue);
361       
362            if (sources == null) {
363                sources = new ArrayList<Source>();
364                allSources.put(toStringValue, sources);
365            }
366           
367            sources.add(source);
368            existingSource = source;
369        }
370       
371        return existingSource;
372    }
373
374    /**
375     * <p>
376     * convenience method to find a source based on its <code>toString</code> parameter value.
377     * The method only returns sources, which match the provided <code>toString</code>
378     * representation and which have a valid list of components.
379     * </p>
380     *
381     * @param toStringValue the value of the <code>toString</code> parameter the source to find
382     *                      must have
383     *
384     * @return the source matching the parameter and having a valid list of components or null if
385     *         none is found
386     */
387    private Source findSource(String toStringValue) {
388        Source existingSource = null;
389       
390        List<Source> candidates = allSources.get(toStringValue);
391       
392        if (candidates != null) {
393            for (Source candidate : candidates) {
394                if (toStringValue.equals(getToStringParam(candidate)) &&
395                    (candidate.components != null) && (candidate.components.size() > 0))
396                {
397                    existingSource = candidate;
398                    break;
399                }
400            }
401        }
402       
403        return existingSource;
404    }
405
406    /**
407     * <p>
408     * corrects all wrong sources in the events of the session. For each wrong resource, the
409     * {@link #correctEventSource(Event, Source)} method is called.
410     * </p>
411     *
412     * @param session the session of which the events shall be corrected
413     */
414    private void correctSources(Session session) {
415        Source previousSource = null;
416        for (Event event : session.events) {
417            if ((event.source == null) || (event.source.components == null) ||
418                (event.source.components.size() == 0))
419            {
420                correctEventSource(event, previousSource);
421            }
422           
423            previousSource = event.source;
424        }
425    }
426
427    /**
428     * <p>
429     * corrects the source of an event. It first searches for a correct source with an equal
430     * <code>toString</code> parameter. If there is any, this is reused. Otherwise it creates a
431     * new correct source. For this, it copies all parameters of the source of the provided previous
432     * event if they are not included in the source already. Furthermore, it adds all components
433     * of the source of the previous event. At last, it adds a further component based on the
434     * information found in the <code>toString</code> parameter of the source.
435     * </p>
436     *
437     * @param event          the event of which the source must be corrected
438     * @param previousSource the source of the previous event to be potentially reused partially
439     */
440    private void correctEventSource(Event event, Source previousSource) {
441        String toStringValue = null;
442       
443        if ((event.source != null) && (event.source.params != null)) {
444            toStringValue = getToStringParam(event.source);
445        }
446       
447        Source existingSource = null;
448       
449        if (toStringValue != null) {
450            existingSource = findSource(toStringValue);
451        }
452       
453        if (existingSource != null) {
454            event.source = existingSource;
455        }
456        else {
457            if (previousSource != null) {
458                for (String[] parameterOfPreviousSource : previousSource.params) {
459                    boolean foundParameter = false;
460                    for (String[] parameter : event.source.params) {
461                        if (parameter[0].equals(parameterOfPreviousSource[0])) {
462                            foundParameter = true;
463                            break;
464                        }
465                    }
466
467                    if (!foundParameter) {
468                        event.source.params.add(parameterOfPreviousSource);
469                    }
470                }
471   
472                for (Component component : previousSource.components) {
473                    if (!(component instanceof ComponentFromToString)) {
474                        event.source.components.add(component);
475                    }
476                }
477            }
478
479            event.source.components.add(getComponentFromToString(toStringValue));
480        }
481    }
482
483    /**
484     * <p>
485     * retrieves the value of the <code>toString</code> parameter of the provided source.
486     * </p>
487     *
488     * @param source the source to read the parameter of
489     * @return the value of the parameter
490     */
491    private String getToStringParam(Source source) {
492        String value = null;
493       
494        for (String[] param : source.params) {
495            if (("toString".equals(param[0])) && (param[1] != null) && (!"".equals(param[1]))) {
496                value = param[1];
497                break;
498            }
499        }
500       
501        return value;
502    }
503
504    /**
505     * <p>
506     * determines a component based on the <code>toString</code> parameter of a source.
507     * For this, it parses the parameter value and tries to determine several infos such as the
508     * type and the name of it. The resulting components are not always distinguishable. This is,
509     * because the <code>toString</code> parameter does not contain sufficient information for
510     * correct identification.
511     * </p>
512     *
513     * @param toStringValue the <code>toString</code> parameter of a source
514     *
515     * @return the component parsed from the <code>toString</code> parameter
516     */
517    private Component getComponentFromToString(String toStringValue) {
518        ComponentFromToString component = new ComponentFromToString();
519       
520        // search for the beginning of the parameters section. Up to this position we find the class
521        int start = toStringValue.indexOf('[');
522        String clazz = toStringValue.substring(0, start);
523       
524        // the first parameters are x and y coordinate as well as the size. The size is one
525        // parameter, where with and height are separated with an 'x'
526        start = toStringValue.indexOf(',', start) + 1;
527        int end = toStringValue.indexOf(',', start);
528       
529        component.x = Integer.parseInt(toStringValue.substring(start, end));
530       
531        start = end + 1;
532        end = toStringValue.indexOf(',', start);
533
534        component.y = Integer.parseInt(toStringValue.substring(start, end));
535
536        start = end + 1;
537        end = toStringValue.indexOf('x', start);
538
539        component.width = Integer.parseInt(toStringValue.substring(start, end));
540
541        start = end + 1;
542        end = toStringValue.indexOf(',', start);
543
544        component.height = Integer.parseInt(toStringValue.substring(start, end));
545
546        // no start parsing the rest of the parameters and extract those having a key and a
547        // value and whose key is text, defaultIcon, or an alignment
548        int intermediate;
549        start = end + 1;
550
551        String title = null;
552        String icon = null;
553        String alignment = null;
554       
555        do {
556            end = toStringValue.indexOf(',', start);
557            intermediate = toStringValue.indexOf('[', start);
558           
559            if ((intermediate >= 0) && (intermediate < end)) {
560                // the value of the parameter itself contains brackets. So try to determine the
561                // real end of the parameter
562                end = toStringValue.indexOf(']', intermediate);
563                end = toStringValue.indexOf(',', end);
564            }
565           
566            if (end < 0) {
567                //we reached the end of the stream. So the the end to the "end"
568                end = toStringValue.lastIndexOf(']');
569            }
570           
571            intermediate = toStringValue.indexOf('=', start);
572           
573            if ((intermediate >= 0) && (intermediate < end)) {
574                // this is a key value pair, so store the the parameter
575                String key = toStringValue.substring(start, intermediate);
576                String value = toStringValue.substring(intermediate + 1, end);
577               
578                if ("text".equals(key)) {
579                    title = value;
580                }
581                else if ("defaultIcon".equals(key)) {
582                    icon = value;
583                }
584                else if ("alignmentX".equals(key) || "alignmentY".equals(key)) {
585                    if (alignment == null) {
586                        alignment = value;
587                    }
588                    else {
589                        alignment += "/" + value;
590                    }
591                }
592            }
593            /*else {
594                // this is a simple value, for now simply ignore it
595                String key = toStringValue.substring(start, end);
596                if (!"invalid".equals(key)) {
597                    componentHash += key.hashCode();
598                    component.params.add(new String[] { key, "true" });
599                }
600            }*/
601           
602            start = end + 1;
603        }
604        while (start < toStringValue.lastIndexOf(']'));
605       
606        // finish the component specification by setting the parameters
607        if ((title == null) || "".equals(title) || "null".equals(title)) {
608            if ((icon == null) || "".equals(icon) || "null".equals(icon)) {
609                title = clazz.substring(clazz.lastIndexOf('.') + 1) + "(";
610               
611                // to be able to distinguish some elements, that usually have no name and icon, try
612                // to include some of their specific identifying information in their name.
613                if ("org.tigris.gef.presentation.FigTextEditor".equals(clazz) ||
614                    "org.argouml.core.propertypanels.ui.UMLTextField".equals(clazz))
615                {
616                    title += "height " + component.height + ", ";
617                }
618                else if ("org.argouml.core.propertypanels.ui.UMLLinkedList".equals(clazz) ||
619                         "org.argouml.core.propertypanels.ui.LabelledComponent".equals(clazz))
620                {
621                    title += "position " + component.x + "/" + component.y + ", ";
622                }
623               
624                title += "alignment " + alignment + ")";
625            }
626            else {
627                title = icon;
628            }
629        }
630       
631        component.params.add(new String[] { "title", title } );
632        component.params.add(new String[] { "class", clazz } );
633        component.params.add(new String[] { "icon", icon } );
634        component.params.add(new String[] { "index", "-1" });
635       
636        int hashCode = clazz.hashCode() + title.hashCode();
637       
638        if (hashCode < 0) {
639            hashCode = -hashCode;
640        }
641       
642        component.params.add(new String[] { "hash", Integer.toString(hashCode, 16) });
643
644        return component;
645    }   
646
647    /**
648     * <p>
649     * used to dump a list of parameters to the provided print stream
650     * </p>
651     */
652    private void dumpParams(PrintStream out, List<String[]> params, String indent) {
653        for (String[] param : params) {
654            out.print(indent);
655            out.print("<param name=\"");
656            out.print(StringTools.xmlEntityReplacement(param[0]));
657            out.print("\" value=\"");
658            out.print(StringTools.xmlEntityReplacement(param[1]));
659            out.println("\" />");
660        }
661       
662    }
663   
664    /**
665     * <p>
666     * used to carry all events of a session and to dump it to the output file
667     * </p>
668     */
669    private class Session {
670        private String type;
671        private List<Event> events = new ArrayList<Event>();
672       
673        public void dump(PrintStream out) {
674            out.print("<");
675            out.print(type);
676            out.println(">");
677
678            for (Event event : events) {
679                event.dump(out);
680            }
681           
682            out.print("</");
683            out.print(type);
684            out.println(">");
685        }
686    }
687
688    /**
689     * <p>
690     * used to carry all information about an event and to dump it to the output file
691     * </p>
692     */
693    private class Event {
694        private String id;
695        private List<String[]> params = new ArrayList<String[]>();
696        private Source source;
697       
698        private void dump(PrintStream out) {
699            out.print("<event id=\"");
700            out.print(StringTools.xmlEntityReplacement(id));
701            out.println("\">");
702           
703            dumpParams(out, params, " ");
704            source.dump(out);
705           
706            out.println("</event>");
707        }
708    }
709
710    /**
711     * <p>
712     * used to carry all information about a source of an event and to dump it to the output file
713     * </p>
714     */
715    private class Source {
716        private List<String[]> params = new ArrayList<String[]>();
717        private List<Component> components = new ArrayList<Component>();
718
719        private void dump(PrintStream out) {
720            out.println(" <source>");
721           
722            dumpParams(out, params, "  ");
723           
724            for (Component component : components) {
725                component.dump(out);
726            }
727           
728            out.println(" </source>");
729        }
730    }
731   
732    /**
733     * <p>
734     * used to carry all information about a component of a source and to dump it to the output file
735     * </p>
736     */
737    private class Component {
738        protected List<String[]> params = new ArrayList<String[]>();
739       
740        protected void dump(PrintStream out) {
741            out.println("  <component>");
742            dumpParams(out, params, "   ");
743            out.println("  </component>");
744        }
745
746        public boolean equals(Object other) {
747            if (this == other) {
748                return true;
749            }
750           
751            if (!(other instanceof Component)) {
752                return false;
753            }
754           
755            Component otherComp = (Component) other;
756           
757            boolean allParamsEqual = (params.size() == otherComp.params.size());
758           
759            if (allParamsEqual) {
760                for (int i = 0; i < params.size(); i++) {
761                    if (!params.get(i)[0].equals(otherComp.params.get(i)[0]) &&
762                        !params.get(i)[1].equals(otherComp.params.get(i)[1]))
763                    {
764                        allParamsEqual = false;
765                        break;
766                    }
767                }
768            }
769           
770            return allParamsEqual;
771        }
772    }
773
774    /**
775     * <p>
776     * represents a specific component, which was read from the toString parameter of a source
777     * </p>
778     */
779    private class ComponentFromToString extends Component {
780        private int x;
781        private int y;
782        private int width;
783        private int height;
784       
785        @Override
786        protected void dump(PrintStream out) {
787            out.println("  <component>");
788           
789            out.print("   ");
790            out.print("<param name=\"x\" value=\"");
791            out.print(x);
792            out.println("\" />");
793
794            out.print("   ");
795            out.print("<param name=\"y\" value=\"");
796            out.print(y);
797            out.println("\" />");
798
799            out.print("   ");
800            out.print("<param name=\"width\" value=\"");
801            out.print(width);
802            out.println("\" />");
803
804            out.print("   ");
805            out.print("<param name=\"height\" value=\"");
806            out.print(height);
807            out.println("\" />");
808
809            dumpParams(out, params, "   ");
810            out.println("  </component>");
811        }
812       
813        /*public boolean equals(Object other) {
814            if (this == other) {
815                return true;
816            }
817           
818            if (!(other instanceof ComponentFromToString)) {
819                return false;
820            }
821           
822            ComponentFromToString otherComp = (ComponentFromToString) other;
823           
824            // ignore the coordinates and the width as it may change over time
825            boolean allParamsEqual =
826                (height == otherComp.height) && (params.size() == otherComp.params.size());
827           
828            if (allParamsEqual) {
829                for (int i = 0; i < params.size(); i++) {
830                    if (!"x".equals(params.get(i)[0]) && !"y".equals(params.get(i)[0]) &&
831                        !"width".equals(params.get(i)[0]) && !"height".equals(params.get(i)[0]) &&
832                        !"index".equals(params.get(i)[0]) && !"hash".equals(params.get(i)[0]) &&
833                        !params.get(i)[0].equals(otherComp.params.get(i)[0]) &&
834                        !params.get(i)[1].equals(otherComp.params.get(i)[1]))
835                    {
836                        allParamsEqual = false;
837                        break;
838                    }
839                }
840            }
841           
842            return allParamsEqual;
843        }*/
844    }
845
846}
Note: See TracBrowser for help on using the repository browser.