Statistics
| Revision:

root / tmp / org.txm.groovy.core / src / groovy / org / txm / scripts / importer / tmx / compiler.groovy @ 1804

History | View | Annotate | Download (18.4 kB)

1
// Copyright © 2010-2013 ENS de Lyon.
2
// Copyright © 2007-2010 ENS de Lyon, CNRS, INRP, University of
3
// Lyon 2, University of Franche-Comté, University of Nice
4
// Sophia Antipolis, University of Paris 3.
5
// 
6
// The TXM platform is free software: you can redistribute it
7
// and/or modify it under the terms of the GNU General Public
8
// License as published by the Free Software Foundation,
9
// either version 2 of the License, or (at your option) any
10
// later version.
11
// 
12
// The TXM platform is distributed in the hope that it will be
13
// useful, but WITHOUT ANY WARRANTY; without even the implied
14
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15
// PURPOSE. See the GNU General Public License for more
16
// details.
17
// 
18
// You should have received a copy of the GNU General
19
// Public License along with the TXM platform. If not, see
20
// http://www.gnu.org/licenses.
21
//
22
//
23
//
24
// $LastChangedDate: 2017-01-24 18:11:42 +0100 (mar. 24 janv. 2017) $
25
// $LastChangedRevision: 3400 $
26
// $LastChangedBy: mdecorde $
27
//
28
package org.txm.scripts.importer.tmx;
29

    
30
import org.txm.importer.cwb.BuildAlignOut;
31
import org.txm.importer.cwb.CwbAlign;
32
import org.txm.importer.cwb.CwbEncode
33
import org.txm.importer.cwb.CwbMakeAll
34
import org.txm.importer.cwb.PatchCwbRegistry;
35
import org.txm.scripts.importer.*;
36
import org.txm.scripts.*;
37
import org.txm.importer.scripts.xmltxm.*;
38
import org.txm.utils.logger.Log;
39
import org.txm.utils.treetagger.TreeTagger;
40
import org.txm.objects.*;
41
import org.txm.searchengine.cqp.corpus.*;
42
import javax.xml.stream.*;
43
import java.net.URL;
44
import java.io.File;
45
import java.io.IOException;
46
import java.util.ArrayList;
47
import java.util.HashMap;
48
import java.util.List;
49

    
50
/**
51
 * The Class compiler builds the aligned CQP corpus indexes
52
 */
53
class compiler {
54
        /** The debug. */
55
        private boolean debug= false;
56

    
57
        /** The input data. */
58
        private def inputData;
59

    
60
        /** The factory. */
61
        private def factory;
62

    
63
        /** The parser. */
64
        private XMLStreamReader parser;
65

    
66
        /** The dir. */
67
        private def dir;
68

    
69
        /** The output. */
70
        private def output;
71

    
72
        /** The url. */
73
        private def url;
74

    
75
        /** The text. */
76
        String text="";
77

    
78
        /** The base. */
79
        String base="";
80

    
81
        /** The project. */
82
        String projectName="";
83

    
84
        /** The anahash. */
85
        static boolean firstWord = true;
86
        private def anaTypes = [];
87
        public def getAnaTypes() { return anaTypes; }
88
        private HashMap<String,String> anahash = new HashMap<String,String>() ;
89

    
90
        private static SAttributesListener sattrsListener;
91
        private static HashMap<String,ArrayList<String>> structs;
92
        private static HashMap<String, Integer> structsProf;
93
        def headerAttrs; // only for TMX
94

    
95
        /** The tuprops. */
96
        List<String> tuprops;
97

    
98
        /** The corporanames. */
99
        List<String> corporanames = new ArrayList<String>();
100

    
101
        /** The align structure. */
102
        String alignStructure;
103

    
104
        /** The align attribute. */
105
        String alignAttribute;
106

    
107
        /** The do align. */
108
        boolean doAlign = false;
109
        public static HashMap<String, Integer> segs_id = [:]; // static so the id are uniques
110
        public static int seg_id = 0;
111

    
112
        /**
113
         * initialize.
114
         *
115
         */
116
        public compiler(){}
117

    
118
        /**
119
         * Instantiates a new compiler.
120
         *
121
         * @param url the url
122
         * @param text the text
123
         * @param base the base
124
         * @param project the project
125
         * @param tuprops the tuprops
126
         */
127
        public compiler(URL url, String text, String base, String project, List<String> tuprops)
128
        {
129
                this.text = text
130
                this.base = base;
131
                this.projectName = project;
132
                this.tuprops = tuprops;
133
                try {
134
                        this.url = url;
135
                        inputData = url.openStream();
136
                        factory = XMLInputFactory.newInstance();
137
                        parser = factory.createXMLStreamReader(inputData);
138

    
139
                        if (sattrsListener == null)
140
                                sattrsListener = new SAttributesListener(parser);
141
                        else
142
                                sattrsListener.start(parser)
143
                } catch (XMLStreamException ex) {
144
                        System.out.println(ex);
145
                }catch (IOException ex) {
146
                        System.err.println("IOException while parsing ");
147
                }
148
        }
149

    
150
        /**
151
         * Creates the output.
152
         *
153
         * @param dirPathName the dir path name
154
         * @param fileName the file name
155
         * @return true, if successful
156
         */
157
        private boolean createOutput(String dirPathName, String fileName){
158
                try {
159
                        File f = new File(dirPathName, fileName)
160
                        //We don't want to concatenate the cqp files
161
                        output = new OutputStreamWriter(new FileOutputStream(f, f.exists()) , "UTF-8");
162
                        return true;
163
                } catch (Exception e) {
164
                        System.err.println(e);
165

    
166
                        return false;
167
                }
168
        }
169

    
170
        /**
171
         * Go to text.
172
         */
173
        private void GoToText()
174
        {
175
                for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next())
176
                {
177
                        if(event == XMLStreamConstants.END_ELEMENT)
178
                                if(parser.getLocalName().equals("teiHeader"))
179
                                        return;
180
                }
181
        }
182

    
183
        /**
184
         * Transfom file cqp.
185
         *
186
         * @param dirPathName the dir path name
187
         * @param fileName the file name
188
         * @return true, if successful
189
         */
190
        public boolean transfomFileCqp(String dirPathName, String fileName)
191
        {
192
                createOutput(dirPathName, fileName);
193

    
194
                GoToText();
195
                firstWord = true;
196
                String headvalue = ""
197
                String vAna = "";
198
                String vForm = "";
199
                String wordid= "";
200
                String vHead = "";
201

    
202
                boolean captureword = false;
203
                boolean flagForm = false;
204
                boolean flagAna = false;
205

    
206
                String anaType;
207
                String tuRef;
208
                try {
209
                        for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next())
210
                        {
211
                                switch (event) {
212
                                        case XMLStreamConstants.START_ELEMENT:
213
                                                sattrsListener.startElement(parser.getLocalName());
214
                                                switch (parser.getLocalName()) {
215
                                                        case "header": // capture header attributes
216
                                                                headerAttrs = [:];
217
                                                                for ( int i = 0 ; i < parser.getAttributeCount() ; i++) {
218
                                                                        headerAttrs[parser.getAttributeLocalName(i)] =  parser.getAttributeValue(i);
219
                                                                }
220
                                                                break;
221
                                                        case "text":
222
                                                                output.write("<text id=\""+text+"\" base=\""+base+"\"" +
223
                                                                " project=\""+projectName+"\"");
224
                                                                def textAttrs = [];
225
                                                                for ( int i = 0 ; i < parser.getAttributeCount() ; i++)
226
                                                                {
227
                                                                        String attrname = parser.getAttributeLocalName(i);
228
                                                                        String attrvalue = parser.getAttributeValue(i);
229
                                                                        if(attrname != "id")
230
                                                                                output.write(" "+attrname+"=\""+attrvalue+"\"")
231
                                                                        textAttrs << attrname
232
                                                                }
233
                                                                if (headerAttrs != null)
234
                                                                        for( String key : headerAttrs.keySet()) {
235
                                                                                if (!textAttrs.contains(key))
236
                                                                                        output.write(" "+key+"=\""+headerAttrs[key]+"\"")
237
                                                                        }
238
                                                                output.write(">\n");
239

    
240
                                                                break;
241

    
242
                                                        case "tu":
243
                                                                output.write("<tu");
244
                                                                for( String attrname : tuprops)
245
                                                                {
246
                                                                        String attrvalue = parser.getAttributeValue(null, attrname);
247
                                                                        attrname = attrname.toLowerCase();
248
                                                                        if(attrvalue == null)
249
                                                                                output.write(" "+attrname+"=\"N/A\"")
250
                                                                        else
251
                                                                                output.write(" "+attrname+"=\""+attrvalue+"\"")
252
                                                                }
253
                                                                tuRef = text;
254
                                                                for (int i = 0 ; i < parser.getAttributeCount() ; i++) {
255
                                                                        output.write(" "+parser.getAttributeLocalName(i)+"=\""+parser.getAttributeValue(i)+"\"")
256
                                                                        if (parser.getAttributeLocalName(i) == "ref")
257
                                                                                tuRef = parser.getAttributeValue(i);
258
                                                                }
259
                                                                output.write(">\n");
260
                                                                break;
261
                                                        case "seg":
262
                                                                output.write("<seg")
263
                                                                for (int i = 0 ; i < parser.getAttributeCount() ; i++) {
264
                                                                        output.write(" "+parser.getAttributeLocalName(i)+"=\""+parser.getAttributeValue(i)+"\"")
265
                                                                }
266
                                                                output.write(">\n")
267
                                                                break;
268

    
269
                                                        case "w":
270
                                                                for(int i = 0 ; i < parser.getAttributeCount(); i++)
271
                                                                        if(parser.getAttributeLocalName(i).equals("id"))
272
                                                                {
273
                                                                        wordid = parser.getAttributeValue(i);
274
                                                                }
275
                                                                break;
276
                                                        case "form":
277
                                                                flagForm = true;
278
                                                                vForm = "";
279
                                                                anahash.clear();
280
                                                                break;
281

    
282
                                                        case "ana":
283
                                                                flagAna = true;
284
                                                                anaType = parser.getAttributeValue(null, "type")
285
                                                                if (anaType.length() > 0) anaType = anaType.substring(1);
286
                                                                //println "anatype $anaType"
287
                                                                anahash.put(anaType, "");
288
                                                                if (firstWord) {
289
                                                                        anaTypes << anaType;
290
                                                                }
291
                                                                break;
292
                                                }
293
                                                break;
294

    
295
                                        case XMLStreamConstants.END_ELEMENT:
296
                                                sattrsListener.endElement(parser.getLocalName());
297
                                                switch (parser.getLocalName())
298
                                                {
299
                                                        case "text":
300
                                                                output.write("</text>\n");
301
                                                                break;
302

    
303
                                                        case "tu":
304
                                                                output.write("</tu>\n")
305
                                                                break;
306
                                                        case "seg":
307
                                                                output.write("</seg>\n")
308
                                                                break;
309

    
310
                                                        case "w":
311
                                                                firstWord = false;
312
                                                                output.write( vForm.replaceAll("&", "&amp;").replaceAll("<", "&lt;")
313
                                                                         +"\t"+wordid+"\t"+tuRef);
314
                                                                for(String type : anaTypes) {
315
                                                                        output.write("\t"+anahash.get(type));
316
                                                                }
317
                                                                output.write("\n")
318

    
319
                                                                vForm = "";
320
                                                                break;
321

    
322
                                                        case "form":
323
                                                                flagForm = false;
324
                                                                break;
325

    
326
                                                        case "ana":
327
                                                                anahash.put(anaType, vAna);
328
                                                                vAna = "";
329
                                                                flagAna = false;
330
                                                                break;
331
                                                }
332
                                                break;
333

    
334
                                        case XMLStreamConstants.CHARACTERS:
335
                                                if(flagForm)
336
                                                        vForm += parser.getText().trim();
337
                                                if (flagAna) {
338
                                                        vAna += parser.getText().trim()
339
                                                }
340
                                                break;
341
                                }
342
                        }
343
                        output.close();
344
                        if (parser != null) parser.close();
345
                if (inputData != null) inputData.close();
346
                }
347
                catch (Exception ex) {
348
                        System.out.println("Exception while parsing " + inputData);
349
                        if (parser != null) parser.close();
350
                        if (inputData != null) inputData.close();
351
                        return false;
352
                }
353

    
354
                return true;
355
        }
356

    
357
        /**
358
         * Sets the alignment.
359
         *
360
         * @param structure the structure
361
         * @param attribute the attribute
362
         */
363
        public void setAlignment(String structure, String attribute)
364
        {
365
                doAlign = true;
366
                this.alignStructure = structure;
367
                this.alignAttribute = attribute;
368
        }
369

    
370
        /**
371
         * Gets the tu props.
372
         *
373
         * @param files the files
374
         * @return the tu props
375
         */
376
        public List<String> getTuProps(List<File> files)
377
        {
378
                Set<String> tuprops = new HashSet<String>();
379
                for (File f : files) {
380
                        def inputData = f.toURI().toURL().openStream();
381
                        def factory = XMLInputFactory.newInstance();
382
                        def parser = factory.createXMLStreamReader(inputData);
383
                        for (int event = parser.next(); event != XMLStreamConstants.END_DOCUMENT; event = parser.next())
384
                        {
385
                                switch (event) {
386
                                        case XMLStreamConstants.START_ELEMENT:
387
                                                switch (parser.getLocalName()) {
388
                                                        case "tu":
389
                                                        for ( int i = 0 ; i < parser.getAttributeCount() ; i++) {
390
                                                                tuprops.add(parser.getAttributeLocalName(i));
391
                                                        }
392
                                                        break;
393
                                                }
394
                                }
395
                        }
396
                        if (parser != null) parser.close();
397
                        if (inputData != null) inputData.close();
398
                }
399
                return new ArrayList<String>(tuprops);
400
        }
401

    
402
        public static HashMap<String, String> langs;
403
        public void setLangs(HashMap<String, String> langs)
404
        {
405
                this.langs = langs;
406
        }
407

    
408
        public static HashMap<Integer, ArrayList<String>> langGroups;
409
        public void setLangGroups(HashMap<Integer, ArrayList<String>> groups)
410
        {
411
                this.langGroups = groups;
412
        }
413
        
414
        public static HashMap<Integer, ArrayList<String>> corpusIDS;
415
        public void setCorpusIDS(HashMap<Integer, ArrayList<String>> corpusIDS)
416
        {
417
                this.corpusIDS = corpusIDS;
418
        }
419
        
420
        /**
421
         * Run.
422
         *
423
         * @param rootDirFile the root dir file
424
         * @param basename the basename
425
         * @param textAttributes the text attributes
426
         * @return true, if successful
427
         */
428
        public boolean run(Project project, File binDir, File txmDir, String basename)
429
        {
430
                sattrsListener = null; // reset SAttribute Listener for each new import
431
                String rootDir = binDir.getAbsolutePath();
432
                seg_id=1;
433
                
434
                if (!(CwbEncode.isExecutableAvailable() && CwbMakeAll.isExecutableAvailable())) {
435
                        println ("Error: CWB executables not well set.")
436
                        return false;
437
                }
438
                
439
                new File(binDir,"cqp").mkdirs()
440
                new File(binDir,"data").mkdirs()
441
                new File(binDir,"registry").mkdirs()
442

    
443
                String textid="";
444
                int counttext =0;
445
                List<File> files = txmDir.listFiles();
446

    
447
                //0- get all tu props
448
                //List<String> tuprops = getTuProps(files);
449

    
450
                if (corpusIDS == null || corpusIDS.size() == 0) {
451
                        corpusIDS = [:];
452
                        for (int group : langGroups.keySet()) {
453
                                String lang = langs.get(langGroups.get(group)[0]);
454
                                if (lang ==null) {
455
                                        println "ERROR: no lang defined for group $group . Aborting."
456
                                }
457
                                corpusIDS[group] = lang+group
458
                        }
459
                }
460
                println "Using corpus ID: $corpusIDS"
461
                
462
                String cqpName;
463
                for (int group : langGroups.keySet()) {
464
                        String lang = langs.get(langGroups.get(group)[0]);
465
                        segs_id.put(group, 0);
466
                        cqpName = basename+"_"+corpusIDS.get(group);
467
                        createOutput(rootDir+"/cqp", "${cqpName}.cqp");
468
                        output.write("<txmcorpus id=\"${cqpName}\" lang=\""+lang.toLowerCase()+"\">\n")
469
                        output.close();
470

    
471
                        //create txmDirs
472
                        new File(rootDir, "txm/"+cqpName.toUpperCase()).mkdir();
473
                }
474

    
475
                //1- Transform into CQP file and build a corpus per file
476
                Collections.sort(files);
477
                def anaTypesPerCqp = [:];
478
                def builder = null;
479
                for (int group : langGroups.keySet()) {
480
                        //String lang = langs.get(langGroups.get(group)[0]);
481
                        cqpName = basename+"_"+corpusIDS.get(group);
482
                        
483
                CorpusBuild corpus = project.getCorpusBuild(project.getName(), MainCorpus.class);
484
                if (corpus != null) {
485
                        if (project.getDoUpdate()) {
486
                                corpus.clean(); // remove old files
487
                        } else {
488
                                corpus.delete(); // remove old files and TXMResult children
489
                        }
490
                } else {
491
                        corpus = new MainCorpus(project);
492
                        corpus.setID(project.getName());
493
                        corpus.setName(project.getName());
494
                }
495
                        corpus.setDescription("Built with the TMX import module");
496
                        
497
                        File cqpFile = new File(binDir,"cqp/"+cqpName+".cqp");
498
                        
499
                        def filenames = langGroups.get(group);
500
                        filenames.sort()
501
                        //println("Process group no $group of files "+filenames)
502
                        for (String filename : filenames) {
503
                                File f = new File(txmDir, filename);
504
                                print "."
505
                                if (!f.exists()) {
506
                                        println("COMPILER: file "+f+ " does not exists -> stop")
507
                                        return false;
508
                                }
509

    
510
                                filename = filename.substring(0, filename.length()-4);
511
                                counttext++;
512

    
513
                                String txtname = f.getName();
514
                                txtname = txtname.substring(0, txtname.lastIndexOf(".xml"));
515
                                seg_id = segs_id.get(group);
516
                                builder = new compiler(f.toURI().toURL(), txtname, basename, "default", tuprops);
517
                                builder.transfomFileCqp(rootDir+"/cqp",cqpName+".cqp");
518
                                anaTypesPerCqp[cqpName] = builder.getAnaTypes();
519
                                segs_id.put(group, seg_id);
520

    
521
                                // move xml-txm file
522
                                File txmCorpusDir = new File(rootDir, "txm/"+cqpName.toUpperCase())
523
                                f.renameTo(new File(txmCorpusDir, f.getName()));
524
                        }
525
                }
526
                println ""
527
                
528
                for (int group : langGroups.keySet()) {
529
                        //String lang = langs.get(langGroups.get(group)[0]);
530
                        createOutput(rootDir+"/cqp", basename+"_"+corpusIDS.get(group)+".cqp");
531
                        output.write("</txmcorpus>")
532
                        output.close();
533
                }
534

    
535
                if(builder == null) {
536
                        System.out.println("No TXM files to process Stop import");
537
                        return false;
538
                }
539
                //2- Import into CWB
540
                def outDir = rootDir;
541
                def outDirTxm = rootDir;
542

    
543
                def cqpFiles = [:]
544
                for (File cqpfile : new File(rootDir, "cqp").listFiles()) {
545
                        String corpusname = cqpfile.getName();
546
                        
547
                        corpusname = corpusname.substring(0, corpusname.length()-4);
548
                        def corpusAnaTypes = anaTypesPerCqp[corpusname];
549
                        
550
                        CwbEncode cwbEn = new CwbEncode();
551
                        cwbEn.setDebug(debug);
552
                        CwbMakeAll cwbMa = new CwbMakeAll();
553
                        cwbMa.setDebug(debug);
554

    
555
                        def pAttrs = ["id", "ref"];
556
                        for(String type : corpusAnaTypes) {
557
                                int i = 2;
558
                                while (pAttrs.contains(type))
559
                                        type = type+(i++);
560
                                pAttrs.add(type);
561
                        }
562

    
563
                        structs = sattrsListener.getStructs();
564
                        structsProf = sattrsListener.getProfs();
565
                        // add structures+properties found in sources
566
                        List<String> sargs = new ArrayList<String>();
567

    
568
                        for (String name : structs.keySet()) {
569
                                if (name == "header") continue;
570
                                //if ( name == "text") continue; // added after
571
                                //if ( name == "q") continue; // added after
572
                                //if ( name == "foreign") continue; // added after
573
                                String concat = name+":"+structsProf.get(name); // append the depth
574
                                for (String value : structs.get(name)) // append the attributes
575
                                        concat += "+"+value;
576
                                if ((name == "text") &&
577
                                !(concat.endsWith("+id") || concat.contains("+id+")))
578
                                        concat += "+id"
579
                                if ((name == "text") &&
580
                                !(concat.endsWith("+base") || concat.contains("+base+")))
581
                                        concat += "+base"
582
                                if ((name == "text") &&
583
                                !(concat.endsWith("+project") || concat.contains("+project+")))
584
                                        concat += "+project"
585
                                sargs.add(concat);
586
                        }
587

    
588
                        sargs.add("txmcorpus:0+id+lang")
589
                        sargs.sort();
590

    
591
                        String[] sAttributes = sargs;
592
                        String[] pAttributes = pAttrs;
593
                        println "P-attributes: "+pAttrs
594
                        println "S-attributes: "+sargs
595

    
596
                        try {
597
                                cqpFiles[corpusname.toLowerCase()] = outDir + "/cqp/"+cqpfile.getName();
598
                                String regPath = outDirTxm + "/registry/"+corpusname.toLowerCase()
599
                                cwbEn.run(outDirTxm + "/data/"+corpusname.toUpperCase()+"/", outDir + "/cqp/"+cqpfile.getName(), regPath, pAttributes, sAttributes);
600
                                if (!new File(regPath).exists()) {
601
                                        println "Error: The registry file was not created: $regPath. See https://groupes.renater.fr/wiki/txm-users/public/faq"
602
                                        return false;
603
                                }
604
                                cwbMa.run(corpusname.toUpperCase(), outDirTxm + "/registry");
605
                        } catch (Exception ex) {System.out.println(ex); return false;}
606
                }
607

    
608
                // 3- do alignement
609
                if (doAlign) {
610
                        File registryDirectory = new File(rootDir,"registry");
611
                        def registryFiles = registryDirectory.listFiles();
612
                        for (File corpusName : registryFiles) {
613
                                for (File targetName : registryFiles) {
614
                                        if (!corpusName.equals(targetName)) {
615
                                                try {
616
                                                        PatchCwbRegistry.patchAlignment(new File(registryDirectory, corpusName.getName()), targetName.getName());
617
                                                        
618
                                                        File cqpFile1 = new File(cqpFiles[corpusName.getName()]);
619
                                                        File cqpFile2 = new File(cqpFiles[targetName.getName()]);
620
                                                        File alignOutFile = new File(outDir, "align.out");
621
                                                        
622
                                                        BuildAlignOut bao = new BuildAlignOut(cqpFile1, cqpFile2);
623
                                                        if (!bao.process(alignOutFile, "seg", "id")) {
624
                                                                println "Error while creating alignement file of $corpusName. Aborting."
625
                                                                return false;
626
                                                        }
627
                                                        
628
                                                        CwbAlign tt = new CwbAlign();
629
                                                        // ./cwb-align-encode -D -r ~/TXM/corpora/tmxtest/registry/ -v out.align
630
                                                        tt.setD();
631
                                                        tt.setv();
632
                                                        tt.setr(new File(rootDir,"registry").getAbsolutePath());
633
                                                        tt.cwbalignencode(alignOutFile.getAbsolutePath());
634
                                                } catch (IOException e) {
635
                                                        Log.severe("Error while calling TreeTagger: "+e.getLocalizedMessage());
636
                                                        return false;
637
                                                }
638
                                        }
639
                                }
640
                        }
641
                }
642

    
643
                return true;
644
        }
645

    
646
        /**
647
         * Gets the corpora names.
648
         *
649
         * @return the corpora names
650
         */
651
        public List<String> getCorporaNames()
652
        {
653
                return corporanames;
654
        }
655

    
656
        /**
657
         * Sets the debug.
658
         */
659
        public void setDebug()
660
        {
661
                this.debug = true;
662
        }
663

    
664
        /**
665
         * The main method.
666
         *
667
         * @param args the arguments
668
         */
669
        public static void main(String[] args)
670
        {
671
                File dir = new File("~/xml/geo");
672
                def c = new compiler();
673
                c.setDebug();
674
                c.setCwbPath("~/TXM/cwb/bin");
675
                c.run(dir,"geo");
676
        }
677
}