1 
  2 
  3 _parsePath = function() {
  4     var dbpath = "";
  5     for( var i = 0; i < arguments.length; ++i )
  6         if ( arguments[ i ] == "--dbpath" )
  7             dbpath = arguments[ i + 1 ];
  8 
  9     if ( dbpath == "" )
 10         throw "No dbpath specified";
 11 
 12     return dbpath;
 13 }
 14 
 15 _parsePort = function() {
 16     var port = "";
 17     for( var i = 0; i < arguments.length; ++i )
 18         if ( arguments[ i ] == "--port" )
 19             port = arguments[ i + 1 ];
 20 
 21     if ( port == "" )
 22         throw "No port specified";
 23     return port;
 24 }
 25 
 26 createMongoArgs = function( binaryName , args ){
 27     var fullArgs = [ binaryName ];
 28 
 29     if ( args.length == 1 && isObject( args[0] ) ){
 30         var o = args[0];
 31         for ( var k in o ){
 32             if ( k == "v" && isNumber( o[k] ) ){
 33                 var n = o[k];
 34                 if ( n > 0 ){
 35                     if ( n > 10 ) n = 10;
 36                     var temp = "-";
 37                     while ( n-- > 0 ) temp += "v";
 38                     fullArgs.push( temp );
 39                 }
 40             }
 41             else {
 42                 fullArgs.push( "--" + k );
 43                 if ( o[k] != "" )
 44                     fullArgs.push( "" + o[k] );
 45             }
 46         }
 47     }
 48     else {
 49         for ( var i=0; i<args.length; i++ )
 50             fullArgs.push( args[i] )
 51     }
 52 
 53     return fullArgs;
 54 }
 55 
 56 __nextPort = 27000;
 57 startMongodTest = function (port, dirname, restart) {
 58     if (!port)
 59         port = __nextPort++;
 60     var f = startMongodEmpty;
 61     if (restart)
 62         f = startMongodNoReset;
 63     if (!dirname)
 64         dirname = "" + port; // e.g., data/db/27000
 65     var conn = f.apply(null, [
 66         {
 67             port: port,
 68             dbpath: "/data/db/" + dirname,
 69             noprealloc: "",
 70             smallfiles: "",
 71             oplogSize: "2",
 72             nohttpinterface: ""
 73         }
 74     ]
 75     );
 76     conn.name = "localhost:" + port;
 77     return conn;
 78 }
 79 
 80 // Start a mongod instance and return a 'Mongo' object connected to it.
 81 // This function's arguments are passed as command line arguments to mongod.
 82 // The specified 'dbpath' is cleared if it exists, created if not.
 83 startMongodEmpty = function () {
 84     var args = createMongoArgs("mongod", arguments);
 85 
 86     var dbpath = _parsePath.apply(null, args);
 87     resetDbpath(dbpath);
 88 
 89     return startMongoProgram.apply(null, args);
 90 }
 91 startMongod = function () {
 92     print("WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING RENAME YOUR INVOCATION");
 93     return startMongodEmpty.apply(null, arguments);
 94 }
 95 startMongodNoReset = function(){
 96     var args = createMongoArgs( "mongod" , arguments );
 97     return startMongoProgram.apply( null, args );
 98 }
 99 
100 startMongos = function(){
101     return startMongoProgram.apply( null, createMongoArgs( "mongos" , arguments ) );
102 }
103 
104 /* Start mongod or mongos and return a Mongo() object connected to there.
105   This function's first argument is "mongod" or "mongos" program name, \
106   and subsequent arguments to this function are passed as
107   command line arguments to the program.
108 */
109 startMongoProgram = function(){
110     var port = _parsePort.apply( null, arguments );
111 
112     _startMongoProgram.apply( null, arguments );
113 
114     var m;
115     assert.soon
116     ( function() {
117         try {
118             m = new Mongo( "127.0.0.1:" + port );
119             return true;
120         } catch( e ) {
121         }
122         return false;
123     }, "unable to connect to mongo program on port " + port, 60000 );
124 
125     return m;
126 }
127 
128 // Start a mongo program instance.  This function's first argument is the
129 // program name, and subsequent arguments to this function are passed as
130 // command line arguments to the program.  Returns pid of the spawned program.
131 startMongoProgramNoConnect = function() {
132     return _startMongoProgram.apply( null, arguments );
133 }
134 
135 myPort = function() {
136     var m = db.getMongo();
137     if ( m.host.match( /:/ ) )
138         return m.host.match( /:(.*)/ )[ 1 ];
139     else
140         return 27017;
141 }
142 
143 ShardingTest = function( testName , numShards , verboseLevel , numMongos , otherParams ){
144     if ( ! otherParams )
145         otherParams = {}
146     this._connections = [];
147     
148     if ( otherParams.sync && numShards < 3 )
149         throw "if you want sync, you need at least 3 servers";
150 
151     for ( var i=0; i<numShards; i++){
152         var conn = startMongodTest( 30000 + i , testName + i );
153         this._connections.push( conn );
154     }
155 
156     if ( otherParams.sync ){
157         this._configDB = "localhost:30000,localhost:30001,localhost:30002";
158         this._configConnection = new Mongo( this._configDB );
159         this._configConnection.getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );        
160     }
161     else {
162         this._configDB = "localhost:30000";
163         this._connections[0].getDB( "config" ).settings.insert( { _id : "chunksize" , value : otherParams.chunksize || 50 } );
164     }
165 
166     this._mongos = [];
167     var startMongosPort = 31000;
168     for ( var i=0; i<(numMongos||1); i++ ){
169         var myPort =  startMongosPort - i;
170         var conn = startMongos( { port : startMongosPort - i , v : verboseLevel || 0 , configdb : this._configDB }  );
171         conn.name = "localhost:" + myPort;
172         this._mongos.push( conn );
173         if ( i == 0 )
174             this.s = conn;
175     }
176 
177     var admin = this.admin = this.s.getDB( "admin" );
178     this.config = this.s.getDB( "config" );
179 
180     if ( ! otherParams.manualAddShard ){
181         this._connections.forEach(
182             function(z){
183                 admin.runCommand( { addshard : z.name , allowLocal : true } );
184             }
185         );
186     }
187 }
188 
189 ShardingTest.prototype.getDB = function( name ){
190     return this.s.getDB( name );
191 }
192 
193 ShardingTest.prototype.getServerName = function( dbname ){
194     var x = this.config.databases.findOne( { _id : dbname } );
195     if ( x )
196         return x.primary;
197     this.config.databases.find().forEach( printjson );
198     throw "couldn't find dbname: " + dbname + " total: " + this.config.databases.count();
199 }
200 
201 ShardingTest.prototype.getConnNames = function(){
202     var names = [];
203     for ( var i=0; i<this._connections.length; i++ ){
204         names.push( this._connections[i].name );
205     }
206     return names; 
207 }
208 
209 ShardingTest.prototype.getServer = function( dbname ){
210     var name = this.getServerName( dbname );
211 
212     var x = this.config.shards.findOne( { _id : name } );
213     if ( x )
214         name = x.host;
215 
216     for ( var i=0; i<this._connections.length; i++ ){
217         var c = this._connections[i];
218         if ( name == c.name )
219             return c;
220     }
221 
222     throw "can't find server for: " + dbname + " name:" + name;
223 
224 }
225 
226 ShardingTest.prototype.normalize = function( x ){
227     var z = this.config.shards.findOne( { host : x } );
228     if ( z )
229         return z._id;
230     return x;
231 }
232 
233 ShardingTest.prototype.getOther = function( one ){
234     if ( this._connections.length != 2 )
235         throw "getOther only works with 2 servers";
236 
237     if ( this._connections[0] == one )
238         return this._connections[1];
239     return this._connections[0];
240 }
241 
242 ShardingTest.prototype.getFirstOther = function( one ){
243     for ( var i=0; i<this._connections.length; i++ ){
244         if ( this._connections[i] != one )
245         return this._connections[i];
246     }
247     throw "impossible";
248 }
249 
250 ShardingTest.prototype.stop = function(){
251     for ( var i=0; i<this._mongos.length; i++ ){
252         stopMongoProgram( 31000 - i );
253     }
254     for ( var i=0; i<this._connections.length; i++){
255         stopMongod( 30000 + i );
256     }
257 }
258 
259 ShardingTest.prototype.adminCommand = function(cmd){
260     var res = this.admin.runCommand( cmd );
261     if ( res && res.ok == 1 )
262         return true;
263 
264     throw "command " + tojson( cmd ) + " failed: " + tojson( res );
265 }
266 
267 ShardingTest.prototype.getChunksString = function( ns ){
268     var q = {}
269     if ( ns )
270         q.ns = ns;
271     return Array.tojson( this.config.chunks.find( q ).toArray() , "\n" );
272 }
273 
274 ShardingTest.prototype.printChunks = function( ns ){
275     print( this.getChunksString( ns ) );
276 }
277 
278 ShardingTest.prototype.printShardingStatus = function(){
279     printShardingStatus( this.config );
280 }
281 
282 ShardingTest.prototype.printCollectionInfo = function( ns , msg ){
283     var out = "";
284     if ( msg )
285         out += msg + "\n";
286     out += "sharding collection info: " + ns + "\n";
287     for ( var i=0; i<this._connections.length; i++ ){
288         var c = this._connections[i];
289         out += "  mongod " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n";
290     }
291     for ( var i=0; i<this._mongos.length; i++ ){
292         var c = this._mongos[i];
293         out += "  mongos " + c + " " + tojson( c.getCollection( ns ).getShardVersion() , " " , true ) + "\n";
294     }
295     
296     print( out );
297 }
298 
299 printShardingStatus = function( configDB ){
300     if (configDB === undefined)
301         configDB = db.getSisterDB('config')
302     
303     var version = configDB.getCollection( "version" ).findOne();
304     if ( version == null ){
305         print( "not a shard db!" );
306         return;
307     }
308     
309     var raw = "";
310     var output = function(s){
311         raw += s + "\n";
312     }
313     output( "--- Sharding Status --- " );
314     output( "  sharding version: " + tojson( configDB.getCollection( "version" ).findOne() ) );
315     
316     output( "  shards:" );
317     configDB.shards.find().forEach( 
318         function(z){
319             output( "      " + tojson(z) );
320         }
321     );
322 
323     output( "  databases:" );
324     configDB.databases.find().sort( { name : 1 } ).forEach( 
325         function(db){
326             output( "\t" + tojson(db,"",true) );
327         
328             if (db.partitioned){
329                 for (ns in db.sharded){
330                     output("\t\t" + ns + " chunks:");
331                     configDB.chunks.find( { "ns" : ns } ).sort( { min : 1 } ).forEach( 
332                         function(chunk){
333                             output( "\t\t\t" + tojson( chunk.min ) + " -->> " + tojson( chunk.max ) + 
334                                    " on : " + chunk.shard + " " + tojson( chunk.lastmod ) );
335                         }
336                     );
337                 }
338             }
339         }
340     );
341     
342     print( raw );
343 }
344 
345 ShardingTest.prototype.sync = function(){
346     this.adminCommand( "connpoolsync" );
347 }
348 
349 ShardingTest.prototype.onNumShards = function( collName , dbName ){
350     this.sync(); // we should sync since we're going directly to mongod here
351     dbName = dbName || "test";
352     var num=0;
353     for ( var i=0; i<this._connections.length; i++ )
354         if ( this._connections[i].getDB( dbName ).getCollection( collName ).count() > 0 )
355             num++;
356     return num;
357 }
358 
359 ShardingTest.prototype.shardGo = function( collName , key , split , move , dbName ){
360     split = split || key;
361     move = move || split;
362     dbName = dbName || "test";
363 
364     var c = dbName + "." + collName;
365 
366     s.adminCommand( { shardcollection : c , key : key } );
367     s.adminCommand( { split : c , middle : split } );
368     s.adminCommand( { movechunk : c , find : move , to : this.getOther( s.getServer( dbName ) ).name } );
369     
370 }
371 
372 MongodRunner = function( port, dbpath, peer, arbiter, extraArgs ) {
373     this.port_ = port;
374     this.dbpath_ = dbpath;
375     this.peer_ = peer;
376     this.arbiter_ = arbiter;
377     this.extraArgs_ = extraArgs;
378 }
379 
380 MongodRunner.prototype.start = function( reuseData ) {
381     var args = [];
382     if ( reuseData ) {
383         args.push( "mongod" );
384     }
385     args.push( "--port" );
386     args.push( this.port_ );
387     args.push( "--dbpath" );
388     args.push( this.dbpath_ );
389     if ( this.peer_ && this.arbiter_ ) {
390         args.push( "--pairwith" );
391         args.push( this.peer_ );
392         args.push( "--arbiter" );
393         args.push( this.arbiter_ );
394         args.push( "--oplogSize" );
395         // small oplog by default so startup fast
396         args.push( "1" );
397     }
398     args.push( "--nohttpinterface" );
399     args.push( "--noprealloc" );
400     args.push( "--smallfiles" );
401     args.push( "--bind_ip" );
402     args.push( "127.0.0.1" );
403     if ( this.extraArgs_ ) {
404         args = args.concat( this.extraArgs_ );
405     }
406     removeFile( this.dbpath_ + "/mongod.lock" );
407     if ( reuseData ) {
408         return startMongoProgram.apply( null, args );
409     } else {
410         return startMongod.apply( null, args );
411     }
412 }
413 
414 MongodRunner.prototype.port = function() { return this.port_; }
415 
416 MongodRunner.prototype.toString = function() { return [ this.port_, this.dbpath_, this.peer_, this.arbiter_ ].toString(); }
417 
418 ReplPair = function( left, right, arbiter ) {
419     this.left_ = left;
420     this.leftC_ = null;
421     this.right_ = right;
422     this.rightC_ = null;
423     this.arbiter_ = arbiter;
424     this.arbiterC_ = null;
425     this.master_ = null;
426     this.slave_ = null;
427 }
428 
429 ReplPair.prototype.start = function( reuseData ) {
430     if ( this.arbiterC_ == null ) {
431         this.arbiterC_ = this.arbiter_.start();
432     }
433     if ( this.leftC_ == null ) {
434         this.leftC_ = this.left_.start( reuseData );
435     }
436     if ( this.rightC_ == null ) {
437         this.rightC_ = this.right_.start( reuseData );
438     }
439 }
440 
441 ReplPair.prototype.isMaster = function( mongo, debug ) {
442     var im = mongo.getDB( "admin" ).runCommand( { ismaster : 1 } );
443     assert( im && im.ok, "command ismaster failed" );
444     if ( debug ) {
445         printjson( im );
446     }
447     return im.ismaster;
448 }
449 
450 ReplPair.prototype.isInitialSyncComplete = function( mongo, debug ) {
451     var isc = mongo.getDB( "admin" ).runCommand( { isinitialsynccomplete : 1 } );
452     assert( isc && isc.ok, "command isinitialsynccomplete failed" );
453     if ( debug ) {
454         printjson( isc );
455     }
456     return isc.initialsynccomplete;
457 }
458 
459 ReplPair.prototype.checkSteadyState = function( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ) {
460     leftValues = leftValues || {};
461     rightValues = rightValues || {};
462 
463     var lm = null;
464     var lisc = null;
465     if ( this.leftC_ != null ) {
466         lm = this.isMaster( this.leftC_, debug );
467         leftValues[ lm ] = true;
468         lisc = this.isInitialSyncComplete( this.leftC_, debug );
469     }
470     var rm = null;
471     var risc = null;
472     if ( this.rightC_ != null ) {
473         rm = this.isMaster( this.rightC_, debug );
474         rightValues[ rm ] = true;
475         risc = this.isInitialSyncComplete( this.rightC_, debug );
476     }
477 
478     var stateSet = {}
479     state.forEach( function( i ) { stateSet[ i ] = true; } );
480     if ( !( 1 in stateSet ) || ( ( risc || risc == null ) && ( lisc || lisc == null ) ) ) {
481         if ( rm == 1 && lm != 1 ) {
482             assert( twoMasterOk || !( 1 in leftValues ) );
483             this.master_ = this.rightC_;
484             this.slave_ = this.leftC_;
485         } else if ( lm == 1 && rm != 1 ) {
486             assert( twoMasterOk || !( 1 in rightValues ) );
487             this.master_ = this.leftC_;
488             this.slave_ = this.rightC_;
489         }
490         if ( !twoMasterOk ) {
491             assert( lm != 1 || rm != 1, "two masters" );
492         }
493         // check for expected state
494         if ( state.sort().toString() == [ lm, rm ].sort().toString() ) {
495             if ( expectedMasterHost != null ) {
496                 if( expectedMasterHost == this.master_.host ) {
497                     return true;
498                 }
499             } else {
500                 return true;
501             }
502         }
503     }
504 
505     this.master_ = null;
506     this.slave_ = null;
507     return false;
508 }
509 
510 ReplPair.prototype.waitForSteadyState = function( state, expectedMasterHost, twoMasterOk, debug ) {
511     state = state || [ 1, 0 ];
512     twoMasterOk = twoMasterOk || false;
513     var rp = this;
514     var leftValues = {};
515     var rightValues = {};
516     assert.soon( function() { return rp.checkSteadyState( state, expectedMasterHost, twoMasterOk, leftValues, rightValues, debug ); },
517                 "rp (" + rp + ") failed to reach expected steady state (" + state + ")" );
518 }
519 
520 ReplPair.prototype.master = function() { return this.master_; }
521 ReplPair.prototype.slave = function() { return this.slave_; }
522 ReplPair.prototype.right = function() { return this.rightC_; }
523 ReplPair.prototype.left = function() { return this.leftC_; }
524 ReplPair.prototype.arbiter = function() { return this.arbiterC_; }
525 
526 ReplPair.prototype.killNode = function( mongo, signal ) {
527     signal = signal || 15;
528     if ( this.leftC_ != null && this.leftC_.host == mongo.host ) {
529         stopMongod( this.left_.port_ );
530         this.leftC_ = null;
531     }
532     if ( this.rightC_ != null && this.rightC_.host == mongo.host ) {
533         stopMongod( this.right_.port_ );
534         this.rightC_ = null;
535     }
536     if ( this.arbiterC_ != null && this.arbiterC_.host == mongo.host ) {
537         stopMongod( this.arbiter_.port_ );
538         this.arbiterC_ = null;
539     }
540 }
541 
542 ReplPair.prototype._annotatedNode = function( mongo ) {
543     var ret = "";
544     if ( mongo != null ) {
545         ret += " (connected)";
546         if ( this.master_ != null && mongo.host == this.master_.host ) {
547             ret += "(master)";
548         }
549         if ( this.slave_ != null && mongo.host == this.slave_.host ) {
550             ret += "(slave)";
551         }
552     }
553     return ret;
554 }
555 
556 ReplPair.prototype.toString = function() {
557     var ret = "";
558     ret += "left: " + this.left_;
559     ret += " " + this._annotatedNode( this.leftC_ );
560     ret += " right: " + this.right_;
561     ret += " " + this._annotatedNode( this.rightC_ );
562     return ret;
563 }
564 
565 
566 ToolTest = function( name ){
567     this.name = name;
568     this.port = allocatePorts(1)[0];
569     this.baseName = "jstests_tool_" + name;
570     this.root = "/data/db/" + this.baseName;
571     this.dbpath = this.root + "/";
572     this.ext = this.root + "_external/";
573     this.extFile = this.root + "_external/a";
574     resetDbpath( this.dbpath );
575 }
576 
577 ToolTest.prototype.startDB = function( coll ){
578     assert( ! this.m , "db already running" );
579  
580     this.m = startMongoProgram( "mongod" , "--port", this.port , "--dbpath" , this.dbpath , "--nohttpinterface", "--noprealloc" , "--smallfiles" , "--bind_ip", "127.0.0.1" );
581     this.db = this.m.getDB( this.baseName );
582     if ( coll )
583         return this.db.getCollection( coll );
584     return this.db;
585 }
586 
587 ToolTest.prototype.stop = function(){
588     if ( ! this.m )
589         return;
590     stopMongod( this.port );
591     this.m = null;
592     this.db = null;
593 }
594 
595 ToolTest.prototype.runTool = function(){
596     var a = [ "mongo" + arguments[0] ];
597 
598     var hasdbpath = false;
599     
600     for ( var i=1; i<arguments.length; i++ ){
601         a.push( arguments[i] );
602         if ( arguments[i] == "--dbpath" )
603             hasdbpath = true;
604     }
605 
606     if ( ! hasdbpath ){
607         a.push( "--host" );
608         a.push( "127.0.0.1:" + this.port );
609     }
610 
611     runMongoProgram.apply( null , a );
612 }
613 
614 ReplTest = function( name, ports ){
615     this.name = name;
616     this.ports = ports || allocatePorts( 2 );
617 }
618 
619 ReplTest.prototype.getPort = function( master ){
620     if ( master )
621         return this.ports[ 0 ];
622     return this.ports[ 1 ]
623 }
624 
625 ReplTest.prototype.getPath = function( master ){
626     var p = "/data/db/" + this.name + "-";
627     if ( master )
628         p += "master";
629     else
630         p += "slave"
631     return p;
632 }
633 
634 ReplTest.prototype.getOptions = function( master , extra , putBinaryFirst, norepl ){
635 
636     if ( ! extra )
637         extra = {};
638 
639     if ( ! extra.oplogSize )
640         extra.oplogSize = "1";
641         
642     var a = []
643     if ( putBinaryFirst )
644         a.push( "mongod" )
645     a.push( "--nohttpinterface", "--noprealloc", "--bind_ip" , "127.0.0.1" , "--smallfiles" );
646 
647     a.push( "--port" );
648     a.push( this.getPort( master ) );
649 
650     a.push( "--dbpath" );
651     a.push( this.getPath( master ) );
652     
653 
654     if ( !norepl ) {
655         if ( master ){
656             a.push( "--master" );
657         }
658         else {
659             a.push( "--slave" );
660             a.push( "--source" );
661             a.push( "127.0.0.1:" + this.ports[0] );
662         }
663     }
664     
665     for ( var k in extra ){
666         var v = extra[k];
667         a.push( "--" + k );
668         if ( v != null )
669             a.push( v );                    
670     }
671 
672     return a;
673 }
674 
675 ReplTest.prototype.start = function( master , options , restart, norepl ){
676     var lockFile = this.getPath( master ) + "/mongod.lock";
677     removeFile( lockFile );
678     var o = this.getOptions( master , options , restart, norepl );
679     if ( restart )
680         return startMongoProgram.apply( null , o );
681     else
682         return startMongod.apply( null , o );
683 }
684 
685 ReplTest.prototype.stop = function( master , signal ){
686     if ( arguments.length == 0 ){
687         this.stop( true );
688         this.stop( false );
689         return;
690     }
691     return stopMongod( this.getPort( master ) , signal || 15 );
692 }
693 
694 allocatePorts = function( n ) {
695     var ret = [];
696     for( var i = 31000; i < 31000 + n; ++i )
697         ret.push( i );
698     return ret;
699 }
700 
701 
702 SyncCCTest = function( testName ){
703     this._testName = testName;
704     this._connections = [];
705     
706     for ( var i=0; i<3; i++ ){
707         this._connections.push( startMongodTest( 30000 + i , testName + i ) );
708     }
709     
710     this.url = this._connections.map( function(z){ return z.name; } ).join( "," );
711     this.conn = new Mongo( this.url );
712 }
713 
714 SyncCCTest.prototype.stop = function(){
715     for ( var i=0; i<this._connections.length; i++){
716         stopMongod( 30000 + i );
717     }
718 }
719 
720 SyncCCTest.prototype.checkHashes = function( dbname , msg ){
721     var hashes = this._connections.map(
722         function(z){
723             return z.getDB( dbname ).runCommand( "dbhash" );
724         }
725     );
726 
727     for ( var i=1; i<hashes.length; i++ ){
728         assert.eq( hashes[0].md5 , hashes[i].md5 , "checkHash on " + dbname + " " + msg + "\n" + tojson( hashes ) )
729     }
730 }
731 
732 SyncCCTest.prototype.tempKill = function( num ){
733     num = num || 0;
734     stopMongod( 30000 + num );
735 }
736 
737 SyncCCTest.prototype.tempStart = function( num ){
738     num = num || 0;
739     this._connections[num] = startMongodTest( 30000 + num , this._testName + num , true );
740 }
741 
742 
743 function startParallelShell( jsCode ){
744     var x = startMongoProgramNoConnect( "mongo" , "--eval" , jsCode , db ? db.getMongo().host : null );
745     return function(){
746         waitProgram( x );
747     };
748 }
749 
750 var testingReplication = false;
751 
752 function skipIfTestingReplication(){
753     if (testingReplication) {
754 	print( "skipping" );
755 	quit(0);
756     }
757 }
758