Index: /issm/trunk-jpl/jenkins/javascript/karma/karma.conf.js
===================================================================
--- /issm/trunk-jpl/jenkins/javascript/karma/karma.conf.js	(revision 20793)
+++ /issm/trunk-jpl/jenkins/javascript/karma/karma.conf.js	(revision 20794)
@@ -22,6 +22,9 @@
       'lib/bin/levelset.js',
       'lib/bin/mask.js',
+      'lib/bin/geometry.js',
+      'lib/bin/project3d.js',
       'lib/bin/model.js',
-      'scripts/specs/issm.spec.js'
+      'scripts/specs/temp.spec.js'
+      //'scripts/specs/3.spec.js'
     ],
 
@@ -65,4 +68,5 @@
     // start these browsers
     // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+    //browsers: ['Chrome'],
     browsers: ['Chrome'],
 
Index: /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/geometry.js
===================================================================
--- /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/geometry.js	(revision 20794)
+++ /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/geometry.js	(revision 20794)
@@ -0,0 +1,67 @@
+//GEOMETRY class definition
+//
+//   Usage:
+//      geometry=geometry();
+
+function geometry(){
+	//methods 
+		this.setdefaultparameters = function (){ //{{{
+		}// }}}
+		this.disp = function () { //{{{
+			console.log(sprintf("   Geometry parameters:"));
+
+			fielddisplay(this,'surface','ice upper surface elevation [m]');
+			fielddisplay(this,'thickness','ice thickness [m]');
+			fielddisplay(this,'base','ice base elevation [m]');
+			fielddisplay(this,'bed','bed elevation [m]');
+		} //}}}
+        this.extrude = function(md) {//{{{
+            this.surface=project3d(md,'vector',this.surface,'type','node');
+            this.thickness=project3d(md,'vector',this.thickness,'type','node');
+            this.hydrostatic_ratio=project3d(md,'vector',this.hydrostatic_ratio,'type','node');
+            this.base=project3d(md,'vector',this.base,'type','node');
+            this.bed=project3d(md,'vector',this.bed,'type','node');
+        }//}}}
+		this.classname = function () { //{{{
+			return 'geometry';
+		} //}}}
+		this.checkconsistency = function(md,solution,analyses) { //{{{
+
+			if ((solution==TransientSolutionEnum() & md.trans.isgia) | (solution==GiaSolutionEnum())){
+				checkfield(md,'fieldname','geometry.thickness','timeseries',1,'NaN',1,'Inf',1,'>=',0);
+			}
+			else{
+				checkfield(md,'fieldname','geometry.surface'  ,'NaN',1,'Inf',1,'size',[md.mesh.numberofvertices, 1]);
+				checkfield(md,'fieldname','geometry.base'      ,'NaN',1,'Inf',1,'size',[md.mesh.numberofvertices, 1]);
+				checkfield(md,'fieldname','geometry.thickness','NaN',1,'Inf',1,'size',[md.mesh.numberofvertices, 1],'>',0);
+				for(var i=0;i<md.mesh.numberofvertices;i++){
+					if (Math.abs(md.geometry.thickness.thickness-md.geometry.surface+md.geometry.base)>Math.pow(10,9)){
+						md = checkmessage(md,'equality thickness=surface-base violated');
+						break;
+					}
+				}
+				if (solution==TransientSolutionEnum() & md.trans.isgroundingline){
+					checkfield(md,'fieldname','geometry.bed','NaN',1,'Inf',1,'size',[md.mesh.numberofvertices, 1]);
+				}
+			}
+		} // }}}
+		this.marshall=function(md,prefix,fid) { //{{{
+			WriteData(fid,prefix,'object',this,'fieldname','surface','format','DoubleMat','mattype',1);
+			WriteData(fid,prefix,'object',this,'fieldname','thickness','format','DoubleMat','mattype',1,'timeserieslength',md.mesh.numberofvertices+1);
+			WriteData(fid,prefix,'object',this,'fieldname','base','format','DoubleMat','mattype',1);
+			WriteData(fid,prefix,'object',this,'fieldname','bed','format','DoubleMat','mattype',1);
+			WriteData(fid,prefix,'object',this,'fieldname','hydrostatic_ratio','format','DoubleMat','mattype',1);
+		}//}}}
+		this.fix=function() { //{{{
+			this.hydrostatic_ratio=NullFix(this.hydrostatic_ratio,NaN);
+		}//}}}
+	//properties 
+	// {{{
+		this.surface           = NaN;
+		this.thickness         = NaN;
+		this.base              = NaN;
+		this.bed               = NaN;
+		this.hydrostatic_ratio = NaN;
+		this.setdefaultparameters();
+		//}}}
+}
Index: /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/model.js
===================================================================
--- /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/model.js	(revision 20793)
+++ /issm/trunk-jpl/jenkins/javascript/karma/lib/bin/model.js	(revision 20794)
@@ -336,5 +336,5 @@
             md.mesh.long=project3d(md,'vector',md.mesh.long,'type','node');
 
-            md.geometry=extrude(md.geometry,md);
+            md.geometry=md.geometry.extrude(md);
                 md.friction  = extrude(md.friction,md);
                 md.inversion = extrude(md.inversion,md);
Index: /issm/trunk-jpl/jenkins/javascript/karma/package.json
===================================================================
--- /issm/trunk-jpl/jenkins/javascript/karma/package.json	(revision 20793)
+++ /issm/trunk-jpl/jenkins/javascript/karma/package.json	(revision 20794)
@@ -4,4 +4,5 @@
     "karma": "^0.13.22",
     "karma-chrome-launcher": "^1.0.1",
+    "karma-firefox-launcher": "^1.0.0",
     "karma-jasmine": "^1.0.2",
     "karma-jasmine-jquery": "^0.1.1",
Index: /issm/trunk-jpl/jenkins/javascript/karma/scripts/m2js.sh
===================================================================
--- /issm/trunk-jpl/jenkins/javascript/karma/scripts/m2js.sh	(revision 20793)
+++ /issm/trunk-jpl/jenkins/javascript/karma/scripts/m2js.sh	(revision 20794)
@@ -11,4 +11,7 @@
     fi
 
+    if [[ $OUTFILE == test*.js ]]; then
+        sed -i '2s/^/var md = new model();\n/' $OUTFILE # initialize the model
+    fi
 
     OUTFILE=$(dirname $INFILE)/$(basename $INFILE .m).js
@@ -24,8 +27,4 @@
     fi
 
-    if [[ $OUTFILE == test*.js ]]; then
-        sed -i '2s/^/var md = new model();\n/' $OUTFILE # initialize the model
-    fi
-
 
     sed -i 's/.*setmask\(.*\)/setmask\1/' $OUTFILE # setmask
@@ -37,5 +36,5 @@
 
     sed -i 's/.*parameterize.*/parameterize(md);/' $OUTFILE # parameterize
-    sed -i 's/^\s*\(extrude\)\(.*\)/md\.\1\2/' $OUTFILE # extrude
+    sed -i 's/^.*\(extrude\)\(.*\)/md\.\1\2/' $OUTFILE # extrude
 
     sed -i '/.*solve.*/! s/^md\s*=\s*//' $OUTFILE # remove md= unless it calls solve
@@ -59,5 +58,5 @@
 
     if grep 'zeros(.*)' $OUTFILE; then
-        sed -i '2s/^/function zeros(...args) {\n\tvar array = [];\n\tfor (var i = 0; i < args[0]; ++i) {\n\t\tarray.push(args.length == 1 ? 0 : zeros(args.slice(1)));\n\t}\n\treturn array;\n}\n/' $OUTFILE
+        sed -i '2s/^/function zeros(...args) {\n\tvar array = [];\n\tfor (var i = 0; i < args[0]; ++i) {\n\t\tarray.push(args.length == 1 ? 0 : zeros(args.slice(1)));\n\t}\n\treturn array;\n}\nvar md = new model();\n/' $OUTFILE
     fi # include zeros function to generate matrices of zeros
 
Index: /issm/trunk-jpl/src/m/classes/geometry.js
===================================================================
--- /issm/trunk-jpl/src/m/classes/geometry.js	(revision 20793)
+++ /issm/trunk-jpl/src/m/classes/geometry.js	(revision 20794)
@@ -16,4 +16,11 @@
 			fielddisplay(this,'bed','bed elevation [m]');
 		} //}}}
+        this.extrude = function(md) {//{{{
+            this.surface=project3d(md,'vector',this.surface,'type','node');
+            this.thickness=project3d(md,'vector',this.thickness,'type','node');
+            this.hydrostatic_ratio=project3d(md,'vector',this.hydrostatic_ratio,'type','node');
+            this.base=project3d(md,'vector',this.base,'type','node');
+            this.bed=project3d(md,'vector',this.bed,'type','node');
+        }//}}}
 		this.classname = function () { //{{{
 			return 'geometry';
