diff --git a/extra/4DNav/4DNav-docs.factor b/extra/4DNav/4DNav-docs.factor
new file mode 100755
index 0000000000..d4bf1db87d
--- /dev/null
+++ b/extra/4DNav/4DNav-docs.factor
@@ -0,0 +1,400 @@
+! Copyright (C) 2008 Jean-Fran�ois Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel quotations strings ;
+IN: 4DNav
+
+HELP: (mvt-4D)
+{ $values
+     { "quot" quotation }
+}
+{ $description "" } ;
+
+HELP: 4D-Rxw
+{ $values
+     { "angle" null }
+     { "Rz" null }
+}
+{ $description "" } ;
+
+HELP: 4D-Rxy
+{ $values
+     { "angle" null }
+     { "Rx" null }
+}
+{ $description "" } ;
+
+HELP: 4D-Rxz
+{ $values
+     { "angle" null }
+     { "Ry" null }
+}
+{ $description "" } ;
+
+HELP: 4D-Ryw
+{ $values
+     { "angle" null }
+     { "Ry" null }
+}
+{ $description "" } ;
+
+HELP: 4D-Ryz
+{ $values
+     { "angle" null }
+     { "Rx" null }
+}
+{ $description "" } ;
+
+HELP: 4D-Rzw
+{ $values
+     { "angle" null }
+     { "Rz" null }
+}
+{ $description "" } ;
+
+HELP: 4DNav
+{ $description "" } ;
+
+HELP: >observer3d
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: >present-space
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+
+HELP: >view1
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: >view2
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: >view3
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: >view4
+{ $values
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: add-keyboard-delegate
+{ $values
+     { "obj" object }
+     { "obj" object }
+}
+{ $description "" } ;
+
+HELP: button*
+{ $values
+     { "string" string } { "quot" quotation }
+     { "button" null }
+}
+{ $description "" } ;
+
+HELP: camera-action
+{ $values
+     { "quot" quotation }
+     { "quot" quotation }
+}
+{ $description "" } ;
+
+HELP: camera-button
+{ $values
+     { "string" string } { "quot" quotation }
+     { "button" null }
+}
+{ $description "" } ;
+
+HELP: controller-window*
+{ $values
+     { "gadget" "a gadget" } 
+}
+{ $description "" } ;
+
+
+HELP: init-models
+{ $description "" } ;
+
+HELP: init-variables
+{ $description "" } ;
+
+HELP: menu-3D
+{ $values
+     { "gadget" null }
+}
+{ $description "The menu dedicated to 3D movements of the camera" } ;
+
+HELP: menu-4D
+{ $values
+    
+     { "gadget" null }
+}
+{ $description "The menu dedicated to 4D movements of space" } ;
+
+HELP: menu-bar
+{ $values
+    
+     { "gadget" null }
+}
+{ $description "return gadget containing menu buttons" } ;
+
+HELP: model-projection
+{ $values
+     { "x" null }
+     { "space" null }
+}
+{ $description "Project space following coordinate x" } ;
+
+HELP: mvt-3D-1
+{ $values
+    
+     { "quot" quotation }
+}
+{ $description "return a quotation to orientate space to see it from first point of view" } ;
+
+HELP: mvt-3D-2
+{ $values
+    
+     { "quot" quotation }
+}
+{ $description "return a quotation to orientate space to see it from second point of view" } ;
+
+HELP: mvt-3D-3
+{ $values
+    
+     { "quot" quotation }
+}
+{ $description "return a quotation to orientate space to see it from third point of view" } ;
+
+HELP: mvt-3D-4
+{ $values
+    
+     { "quot" quotation }
+}
+{ $description "return a quotation to orientate space to see it from first point of view" } ;
+
+HELP: observer3d
+{ $description "" } ;
+
+HELP: observer3d>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: present-space
+{ $description "" } ;
+
+HELP: present-space>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: load-model-file
+{ $description "load space from file" } ;
+
+HELP: rotation-4D
+{ $values
+     { "m" "a rotation matrix" }
+}
+{ $description "Apply a 4D rotation matrix" } ;
+
+HELP: translation-4D
+{ $values
+     { "v" null }
+}
+{ $description "" } ;
+
+HELP: update-model-projections
+{ $description "" } ;
+
+HELP: update-observer-projections
+{ $description "" } ;
+
+HELP: view1
+{ $description "" } ;
+
+HELP: view1>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: view2
+{ $description "" } ;
+
+HELP: view2>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: view3
+{ $description "" } ;
+
+HELP: view3>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: view4
+{ $description "" } ;
+
+HELP: view4>
+{ $values
+    
+     { "value" null }
+}
+{ $description "" } ;
+
+HELP: viewer-windows*
+{ $description "" } ;
+
+HELP: win3D
+{ $values
+     { "text" null } { "gadget" null }
+}
+{ $description "" } ;
+
+HELP: windows
+{ $description "" } ;
+
+ARTICLE: "Space file" "Create a new space file"
+"\nTo build a new space, create an XML file using " { $vocab-link "adsoda" } " model description. \nAn example is:"
+$nl
+
+"\n<model>"
+"\n<space>"
+"\n <dimension>4</dimension>"
+"\n <solid>"
+"\n     <name>4cube1</name>"
+"\n     <dimension>4</dimension>"
+"\n     <face>1,0,0,0,100</face>"
+"\n     <face>-1,0,0,0,-150</face>"
+"\n     <face>0,1,0,0,100</face>"
+"\n     <face>0,-1,0,0,-150</face>"
+"\n     <face>0,0,1,0,100</face>"
+"\n     <face>0,0,-1,0,-150</face>"
+"\n     <face>0,0,0,1,100</face>"
+"\n     <face>0,0,0,-1,-150</face>"
+"\n     <color>1,0,0</color>"
+"\n </solid>"
+"\n <solid>"
+"\n     <name>4triancube</name>"
+"\n     <dimension>4</dimension>"
+"\n     <face>1,0,0,0,160</face>"
+"\n     <face>-0.4999999999999998,-0.8660254037844387,0,0,-130</face>"
+"\n     <face>-0.5000000000000004,0.8660254037844384,0,0,-130</face>"
+"\n     <face>0,0,1,0,140</face>"
+"\n     <face>0,0,-1,0,-180</face>"
+"\n     <face>0,0,0,1,110</face>"
+"\n     <face>0,0,0,-1,-180</face>"
+"\n     <color>0,1,0</color>"
+"\n </solid>"
+"\n <solid>"
+"\n     <name>triangone</name>"
+"\n     <dimension>4</dimension>"
+"\n     <face>1,0,0,0,60</face>"
+"\n     <face>0.5,0.8660254037844386,0,0,60</face>"
+"\n     <face>-0.5,0.8660254037844387,0,0,-20</face>"
+"\n     <face>-1.0,0,0,0,-100</face>"
+"\n     <face>-0.5,-0.8660254037844384,0,0,-100</face>"
+"\n     <face>0.5,-0.8660254037844387,0,0,-20</face>"
+"\n     <face>0,0,1,0,120</face>"
+"\n     <face>0,0,-0.4999999999999998,-0.8660254037844387,-120</face>"
+"\n     <face>0,0,-0.5000000000000004,0.8660254037844384,-120</face>"
+"\n     <color>0,1,1</color>"
+"\n </solid>"
+"\n <light>"
+"\n     <direction>1,1,1,1</direction>"
+"\n     <color>0.2,0.2,0.6</color>"
+"\n </light>"
+"\n <color>0.8,0.9,0.9</color>"
+"\n</space>"
+"\n</model>"
+
+
+;
+
+ARTICLE: "TODO" "Todo"
+{ $list 
+    "A file chooser"
+    "A vocab to initialize parameters"
+    "an editor mode" 
+        { $list "add a face to a solid"
+                "add a solid to the space"
+                "move a face"
+                "move a solid"
+                "select a solid in a list"
+                "select a face"
+                "display selected face"
+                "edit a solid color"
+                "add a light"
+                "edit a light color"
+                "move a light"
+                }
+    "add a tool wich give an hyperplane normal vector with enought points. Will use adsoda.intersect-hyperplanes with { { 0 } { 0 } { 1 } } "
+    "decorrelate 3D camera and activate them with select buttons"
+
+
+
+} ;
+
+
+ARTICLE: "4DNav" "4DNav"
+{ $vocab-link "4DNav" }
+$nl
+{ $heading "4D Navigator" }
+"4DNav is a simple tool to visualize 4 dimensionnal objects."
+"\n"
+"It uses " { $vocab-link "adsoda" } " library to display a 4D space and navigate thru it."
+
+"It will display:"
+{ $list
+    { "a menu window" }
+    {  "4 visualization windows" }
+}
+"Each window represents the projection of the 4D space on a particular 3D space."
+$nl
+
+{ $heading "Initialization" }
+"put the space file " { $strong "space-exemple.xml" } "  in temp directory"
+" and then type:" { $code "\"4DNav\" run" } 
+{ $heading "Navigation" }
+"4D submenu move the space in translations and rotation."
+"\n3D submenu move the camera in 3D space. Cameras in every 3D spaces are manipulated as a single one"
+$nl
+
+
+
+
+{ $heading "Links" }
+{ $subsection "Space file" }
+
+{ $subsection "TODO" }
+
+
+;
+
+ABOUT: "4DNav"
diff --git a/extra/4DNav/4DNav.factor b/extra/4DNav/4DNav.factor
new file mode 100755
index 0000000000..745259bd29
--- /dev/null
+++ b/extra/4DNav/4DNav.factor
@@ -0,0 +1,524 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel 
+namespaces
+accessors
+make
+math
+math.functions
+math.trig
+math.parser
+hashtables
+sequences
+combinators
+continuations
+colors
+prettyprint
+vars
+quotations
+io
+io.directories
+io.pathnames
+help.markup
+io.files
+ui.gadgets.panes
+ ui
+       ui.gadgets
+       ui.traverse
+       ui.gadgets.borders
+       ui.gadgets.handler
+       ui.gadgets.slate
+       ui.gadgets.theme
+       ui.gadgets.frames
+       ui.gadgets.tracks
+       ui.gadgets.labels
+       ui.gadgets.labelled       
+       ui.gadgets.lists
+       ui.gadgets.buttons
+       ui.gadgets.packs
+       ui.gadgets.grids
+       ui.gestures
+       ui.tools.workspace
+       ui.gadgets.scrollers
+splitting
+vectors
+math.vectors
+rewrite-closures
+self
+values
+4DNav.turtle
+4DNav.window3D
+4DNav.deep
+4DNav.space-file-decoder
+models
+fry
+adsoda
+adsoda.tools
+;
+
+IN: 4DNav
+VALUE: selected-file
+VALUE: translation-step
+VALUE: rotation-step
+
+3 to: translation-step 
+5 to: rotation-step
+
+VAR: selected-file-model
+VAR: observer3d 
+VAR: view1 
+VAR: view2
+VAR: view3
+VAR: view4
+VAR: present-space
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! replacement of namespaces.lib
+    
+: make* ( seq -- seq ) [ dup quotation? [ call ] [ ] if ] map ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! waiting for deep-cleave-quots
+
+: 4D-Rxy ( angle -- Rx ) deg>rad
+[ 1.0 , 0.0 , 0.0       , 0.0 ,
+  0.0 , 1.0 , 0.0       , 0.0 ,
+  0.0 , 0.0 , dup cos  , dup sin neg  ,
+  0.0 , 0.0 , dup sin  , dup cos  ,  ] 4 make-matrix nip ;
+
+: 4D-Rxz ( angle -- Ry ) deg>rad
+[ 1.0 , 0.0       , 0.0 , 0.0 ,
+  0.0 , dup cos  , 0.0 , dup sin neg  ,
+  0.0 , 0.0       , 1.0 , 0.0 ,
+  0.0 , dup sin  , 0.0 , dup cos  ,  ] 4 make-matrix nip ;
+
+: 4D-Rxw ( angle -- Rz ) deg>rad
+[ 1.0 , 0.0       , 0.0           , 0.0 ,
+  0.0 , dup cos  , dup sin neg  , 0.0 ,
+  0.0 , dup sin  , dup cos     , 0.0 ,
+  0.0 , 0.0       , 0.0           , 1.0 , ] 4 make-matrix nip ;
+
+: 4D-Ryz ( angle -- Rx ) deg>rad
+[ dup cos  , 0.0 , 0.0 , dup sin neg  ,
+  0.0       , 1.0 , 0.0 , 0.0 ,
+  0.0       , 0.0 , 1.0 , 0.0 ,
+  dup sin  , 0.0 , 0.0 , dup cos  ,   ] 4 make-matrix nip ;
+
+: 4D-Ryw ( angle -- Ry ) deg>rad
+[ dup cos  , 0.0 , dup sin neg  , 0.0 ,
+  0.0       , 1.0 , 0.0           , 0.0 ,
+  dup sin  , 0.0 , dup cos     , 0.0 ,
+  0.0       , 0.0 , 0.0           , 1.0 ,  ] 4 make-matrix nip ;
+
+: 4D-Rzw ( angle -- Rz ) deg>rad
+[ dup cos  , dup sin neg  , 0.0 , 0.0 ,
+  dup sin  , dup cos     , 0.0 , 0.0 ,
+  0.0       , 0.0           , 1.0 , 0.0 ,
+  0.0       , 0.0           , 0.0 , 1.0 ,  ] 4 make-matrix nip ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! UI
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: button* ( string quot -- button ) closed-quot <repeat-button>  ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! 
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: model-projection-chooser ( -- gadget )
+   observer3d> projection-mode>>
+   { { 1 "perspective" } { 0 "orthogonal" }  } <toggle-buttons> ;
+
+: collision-detection-chooser ( -- gadget )
+   observer3d> collision-mode>>
+   { { t "on" } { f "off" }  } <toggle-buttons>
+;
+
+: model-projection ( x -- space ) present-space>  swap space-project ;
+
+: update-observer-projections (  -- )
+    view1> relayout-1 
+    view2> relayout-1 
+    view3> relayout-1 
+    view4> relayout-1 ;
+
+: update-model-projections (  -- )
+    0 model-projection <model> view1> (>>model)
+    1 model-projection <model> view2> (>>model)
+    2 model-projection <model> view3> (>>model)
+    3 model-projection <model> view4> (>>model) ;
+
+: camera-action ( quot -- quot ) 
+    [ drop [ ] observer3d>  with-self update-observer-projections ] 
+    make* closed-quot ;
+
+: win3D ( text gadget -- ) "navigateur 4D : " rot append open-window ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! 4D object manipulation
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: (mvt-4D) ( quot -- )   
+    present-space>  
+        swap call space-ensure-solids 
+    >present-space 
+    update-model-projections 
+    update-observer-projections ;
+
+: rotation-4D ( m -- ) 
+    '[ _ [ [ middle-of-space dup vneg ] keep swap space-translate ] dip
+         space-transform 
+         swap space-translate
+    ] (mvt-4D) ;
+
+: translation-4D ( v -- ) '[ _ space-translate ] (mvt-4D) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! menu
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: menu-rotations-4D ( -- gadget )
+    <frame>
+         <pile> 1 >>fill
+          "XY +" [ drop rotation-step 4D-Rxy rotation-4D ] button* add-gadget
+          "XY -" [ drop rotation-step neg 4D-Rxy rotation-4D ] button* add-gadget 
+       @top-left grid-add    
+        <pile> 1 >>fill
+          "XZ +" [ drop rotation-step 4D-Rxz rotation-4D ] button* add-gadget
+          "XZ -" [ drop rotation-step neg 4D-Rxz rotation-4D ] button* add-gadget 
+       @top grid-add    
+        <pile> 1 >>fill
+          "YZ +" [ drop rotation-step 4D-Ryz rotation-4D ] button* add-gadget
+          "YZ -" [ drop rotation-step neg 4D-Ryz rotation-4D ] button* add-gadget 
+        @center grid-add
+         <pile> 1 >>fill
+          "XW +" [ drop rotation-step 4D-Rxw rotation-4D ] button* add-gadget
+          "XW -" [ drop rotation-step neg 4D-Rxw rotation-4D ] button* add-gadget 
+        @top-right grid-add   
+         <pile> 1 >>fill
+          "YW +" [ drop rotation-step 4D-Ryw rotation-4D ] button* add-gadget
+          "YW -" [ drop rotation-step neg 4D-Ryw rotation-4D ] button* add-gadget 
+       @right grid-add    
+         <pile> 1 >>fill
+          "ZW +" [ drop rotation-step 4D-Rzw rotation-4D ] button* add-gadget
+          "ZW -" [ drop rotation-step neg 4D-Rzw rotation-4D ] button* add-gadget 
+       @bottom-right grid-add    
+;
+
+: menu-translations-4D ( -- gadget )
+    <frame> 
+        <pile> 1 >>fill
+            <shelf> 1 >>fill  
+                "X+" [ drop {  1 0 0 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget
+                "X-" [ drop { -1 0 0 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget 
+            add-gadget
+            "YZW" <label> add-gadget
+         @bottom-right grid-add
+         <pile> 1 >>fill
+            "XZW" <label> add-gadget
+            <shelf> 1 >>fill
+                "Y+" [ drop  { 0  1 0 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget
+                "Y-" [ drop  { 0 -1 0 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget 
+                add-gadget
+         @top-right grid-add
+         <pile> 1 >>fill
+            "XYW" <label> add-gadget
+            <shelf> 1 >>fill
+                "Z+" [ drop { 0 0  1 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget
+                "Z-" [ drop { 0 0 -1 0 } translation-step v*n translation-4D ] 
+                    button* add-gadget 
+                add-gadget                 
+        @top-left grid-add     
+        <pile> 1 >>fill
+            <shelf> 1 >>fill
+                "W+" [ drop { 0 0 0 1  } translation-step v*n translation-4D ] 
+                    button* add-gadget
+                "W-" [ drop { 0 0 0 -1 } translation-step v*n translation-4D ] 
+                    button* add-gadget 
+                add-gadget
+            "XYZ" <label> add-gadget
+        @bottom-left grid-add 
+        "X" <label> @center grid-add
+;
+
+: menu-4D ( -- gadget )  
+    <shelf> 
+        "rotations" <label>     add-gadget
+        menu-rotations-4D       add-gadget
+        "translations" <label>  add-gadget
+        menu-translations-4D    add-gadget
+        0.5 >>align
+        { 0 10 } >>gap
+;
+
+
+! ------------------------------------------------------
+
+: redraw-model ( space -- )
+    >present-space 
+    update-model-projections 
+    update-observer-projections ;
+
+: load-model-file ( -- )
+  selected-file dup selected-file-model> set-model read-model-file 
+  redraw-model ;
+
+: mvt-3D-X ( turn pitch -- quot )
+    '[ turtle-pos> norm neg reset-turtle 
+        _ turn-left 
+        _ pitch-up 
+        step-turtle ] ;
+
+: mvt-3D-1 ( -- quot )      90  0 mvt-3D-X ; inline
+: mvt-3D-2 ( -- quot )      0  90 mvt-3D-X ; inline
+: mvt-3D-3 ( -- quot )      0   0 mvt-3D-X ; inline
+: mvt-3D-4 ( -- quot )      45 45 mvt-3D-X ; inline
+
+: camera-button ( string quot -- button ) 
+    [ <label>  ] dip camera-action <repeat-button> ;
+
+! ----------------------------------------------------------
+! file chooser
+! ----------------------------------------------------------
+: <run-file-button> ( file-name -- button )
+  dup '[ drop  _  \ selected-file set-value load-model-file 
+   ] 
+ closed-quot  <roll-button> { 0 0 } >>align ;
+
+: <list-runner> ( -- gadget )
+    "extra/4DNav" 
+  <pile> 1 >>fill 
+    over dup directory-files  
+    [ ".xml" tail? ] filter 
+    [ append-path ] with map
+    [ <run-file-button> add-gadget ] each
+    swap <labelled-gadget> ;
+
+! -----------------------------------------------------
+
+: menu-rotations-3D ( -- gadget )
+    <frame>
+        "Turn\n left"  [ rotation-step  turn-left  ] camera-button      
+            @left grid-add     
+        "Turn\n right" [ rotation-step turn-right ] camera-button      
+            @right grid-add     
+        "Pitch down"   [ rotation-step  pitch-down ] camera-button      
+            @bottom grid-add     
+        "Pitch up"     [ rotation-step  pitch-up   ] camera-button      
+            @top grid-add     
+        <shelf>  1 >>fill
+            "Roll left\n (ctl)"  [ rotation-step  roll-left  ] camera-button
+                add-gadget  
+            "Roll right\n(ctl)"  [ rotation-step  roll-right ] camera-button 
+                add-gadget  
+        @center grid-add 
+;
+
+: menu-translations-3D ( -- gadget )
+    <frame>
+        "left\n(alt)"          [ translation-step  strafe-left  ] camera-button
+            @left grid-add  
+        "right\n(alt)"         [ translation-step  strafe-right ] camera-button
+            @right grid-add     
+        "Strafe up \n (alt)"   [ translation-step strafe-up    ] camera-button
+            @top grid-add
+        "Strafe down \n (alt)" [ translation-step strafe-down  ] camera-button
+            @bottom grid-add    
+        <pile>  1 >>fill
+            "Forward (ctl)"  [  translation-step step-turtle ] camera-button
+                add-gadget
+            "Backward (ctl)" [ translation-step neg step-turtle ] camera-button
+                add-gadget
+        @center grid-add
+;
+
+: menu-quick-views ( -- gadget )
+    <shelf>
+        "View 1 (1)" mvt-3D-1 camera-button   add-gadget
+        "View 2 (2)" mvt-3D-2 camera-button   add-gadget
+        "View 3 (3)" mvt-3D-3 camera-button   add-gadget 
+        "View 4 (4)" mvt-3D-4 camera-button   add-gadget 
+;
+
+: menu-3D ( -- gadget ) 
+    <pile>
+        <shelf>   
+            menu-rotations-3D    add-gadget
+            menu-translations-3D add-gadget
+            0.5 >>align
+            { 0 10 } >>gap
+        add-gadget
+        menu-quick-views add-gadget ; 
+
+: add-keyboard-delegate ( obj -- obj )
+ <handler>
+{
+        { T{ key-down f f "LEFT" }  
+            [ [ rotation-step turn-left ] camera-action ] }
+        { T{ key-down f f "RIGHT" } 
+            [ [ rotation-step turn-right ] camera-action ] }
+        { T{ key-down f f "UP" }    
+            [ [ rotation-step pitch-down ] camera-action ] }
+        { T{ key-down f f "DOWN" }  
+            [ [ rotation-step pitch-up ] camera-action ] }
+
+        { T{ key-down f { C+ } "UP" } 
+            [ [ translation-step step-turtle ] camera-action ] }
+        { T{ key-down f { C+ } "DOWN" } 
+            [ [ translation-step neg step-turtle ] camera-action ] }
+        { T{ key-down f { C+ } "LEFT" } 
+            [ [ rotation-step roll-left ] camera-action ] }
+        { T{ key-down f { C+ } "RIGHT" } 
+            [ [ rotation-step roll-right ] camera-action ] }
+
+        { T{ key-down f { A+ } "LEFT" }  
+            [ [ translation-step strafe-left ] camera-action ] }
+        { T{ key-down f { A+ } "RIGHT" } 
+            [ [ translation-step strafe-right ] camera-action ] }
+        { T{ key-down f { A+ } "UP" }    
+            [ [ translation-step strafe-up ] camera-action ] }
+        { T{ key-down f { A+ } "DOWN" }  
+            [ [ translation-step strafe-down ] camera-action ] }
+
+
+        { T{ key-down f f "1" } [ mvt-3D-1 camera-action ] }
+        { T{ key-down f f "2" } [ mvt-3D-2 camera-action ] }
+        { T{ key-down f f "3" } [ mvt-3D-3  camera-action ] }
+        { T{ key-down f f "4" } [ mvt-3D-4  camera-action ] }
+
+    } [ make* ] map >hashtable >>table
+    ;    
+
+! --------------------------------------------
+! print elements 
+! --------------------------------------------
+! print-content
+
+GENERIC: adsoda-display-model ( x -- ) 
+
+M: light adsoda-display-model 
+"\n light : " .
+     { 
+        [ direction>> "direction : " pprint . ] 
+        [ color>> "color : " pprint . ]
+    }   cleave
+    ;
+
+M: face adsoda-display-model 
+     {
+        [ halfspace>> "halfspace : " pprint . ] 
+        [ touching-corners>> "touching corners : " pprint . ]
+    }   cleave
+    ;
+M: solid adsoda-display-model 
+     {
+        [ name>> "solid called : " pprint . ] 
+        [ color>> "color : " pprint . ]
+        [ dimension>> "dimension : " pprint . ]
+        [ faces>> "composed of faces : " pprint [ adsoda-display-model ] each ]
+    }   cleave
+    ;
+M: space adsoda-display-model 
+     {
+        [ dimension>> "dimension : " pprint . ] 
+        [ ambient-color>> "ambient-color : " pprint . ]
+        [ solids>> "composed of solids : " pprint [ adsoda-display-model ] each ]
+        [ lights>> "composed of lights : " pprint [ adsoda-display-model ] each ] 
+    }   cleave
+    ;
+
+! ----------------------------------------------
+: menu-bar ( -- gadget )
+       <shelf>
+             "reinit" [ drop load-model-file ] button* add-gadget
+             selected-file-model> <label-control> add-gadget
+    ;
+
+
+: controller-window* ( -- gadget )
+    { 0 1 } <track>
+        menu-bar f track-add
+        <list-runner>  
+            <limited-scroller>  
+            { 200 400 } >>max-dim
+        f track-add
+        <shelf>
+            "Projection mode : " <label> add-gadget
+            model-projection-chooser add-gadget
+        f track-add
+        <shelf>
+            "Collision detection (slow and buggy ) : " <label> add-gadget
+            collision-detection-chooser add-gadget
+        f track-add
+        <pile>
+            0.5 >>align    
+            menu-4D add-gadget 
+            light-purple solid-interior
+            "4D movements" <labelled-gadget>
+        f track-add
+        <pile>
+            0.5 >>align
+            { 2 2 } >>gap
+            menu-3D add-gadget
+            light-purple solid-interior 
+            "Camera 3D" <labelled-gadget>
+        f track-add      
+        gray solid-interior
+ ;
+ 
+: viewer-windows* ( --  )
+    "YZW" view1> win3D 
+    "XZW" view2> win3D 
+    "XYW" view3> win3D 
+    "XYZ" view4> win3D   
+;
+
+: navigator-window* ( -- )
+    controller-window*
+    viewer-windows*   
+    add-keyboard-delegate
+    "navigateur 4D" open-window
+;
+
+: windows ( -- ) [ [ navigator-window* ] with-scope ] with-ui ;
+
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: init-variables ( -- )
+    "choose a file" <model> >selected-file-model  
+    <observer> >observer3d
+    [ observer3d> >self
+      reset-turtle 
+      45 turn-left 
+      45 pitch-up 
+      -300 step-turtle 
+    ] with-scope
+    
+;
+
+
+: init-models ( -- )
+    0 model-projection observer3d> <window3D> >view1
+    1 model-projection observer3d> <window3D> >view2
+    2 model-projection observer3d> <window3D> >view3
+    3 model-projection observer3d> <window3D> >view4
+;
+
+: 4DNav ( -- ) 
+    init-variables
+    selected-file read-model-file >present-space
+    init-models
+    windows
+;
+
+MAIN: 4DNav
+
+
diff --git a/extra/4DNav/authors.txt b/extra/4DNav/authors.txt
new file mode 100755
index 0000000000..a6a96933f4
--- /dev/null
+++ b/extra/4DNav/authors.txt
@@ -0,0 +1 @@
+Jeff Bigot
\ No newline at end of file
diff --git a/extra/4DNav/camera/authors.txt b/extra/4DNav/camera/authors.txt
new file mode 100755
index 0000000000..bbc876e7b6
--- /dev/null
+++ b/extra/4DNav/camera/authors.txt
@@ -0,0 +1 @@
+Adam Wendt
diff --git a/extra/4DNav/camera/camera-docs.factor b/extra/4DNav/camera/camera-docs.factor
new file mode 100755
index 0000000000..422148aebe
--- /dev/null
+++ b/extra/4DNav/camera/camera-docs.factor
@@ -0,0 +1,88 @@
+! Copyright (C) 2008 Jean-François Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel ;
+IN: 4DNav.camera
+
+HELP: camera-eye
+{ $values
+    
+     { "point" null }
+}
+{ $description "return the position of the camera" } ;
+
+HELP: camera-focus
+{ $values
+    
+     { "point" null }
+}
+{ $description "return the point the camera looks at" } ;
+
+HELP: camera-up
+{ $values
+    
+     { "dirvec" null }
+}
+{ $description "In order to precise the roling position of camera give an upward vector" } ;
+
+HELP: do-look-at
+{ $values
+     { "camera" null }
+}
+{ $description "Word to use in replacement of gl-look-at when using a camera" } ;
+
+ARTICLE: "4DNav.camera" "4DNav.camera"
+{ $vocab-link "4DNav.camera" }
+"\n"
+"A camera is defined by:"
+{ $list
+{ "a position (" { $link camera-eye } ")" }
+{ "a focus direction (" { $link camera-focus } ")\n" }
+{ "an attitude information (" { $link camera-up } ")\n" }
+}
+"\nUse " { $link do-look-at } " in opengl statement in placement of gl-look-at"
+"\n\n"
+"A camera is a " { $vocab-link "4DNav.turtle" } " object. Its a special vocab to handle mouvements of a 3D object:"
+{ $list
+{ "To define a camera"
+{
+    $unchecked-example
+    
+"VAR: my-camera"
+": init-my-camera ( -- )"
+"    <turtle> >my-camera"
+"    [ my-camera> >self"
+"      reset-turtle "
+"    ] with-scope ;"
+} }
+{ "To move it"
+{
+    $unchecked-example
+
+"    [ my-camera> >self"
+"      45 pitch-up "
+"      5 step-turtle" 
+"    ] with-scope "
+} }
+{ "or"
+{
+    $unchecked-example
+
+"    [ my-camera> >self"
+"      5 strafe-left"
+"    ] with-scope "
+}
+}
+{
+"to use it in an opengl statement"
+{
+    $unchecked-example
+  "my-camera> do-look-at"
+
+}
+}
+}
+
+
+;
+
+ABOUT: "4DNav.camera"
diff --git a/extra/4DNav/camera/camera.factor b/extra/4DNav/camera/camera.factor
new file mode 100755
index 0000000000..93e8271f1b
--- /dev/null
+++ b/extra/4DNav/camera/camera.factor
@@ -0,0 +1,15 @@
+USING: kernel namespaces math.vectors opengl 4DNav.turtle self ;
+
+IN: 4DNav.camera
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: camera-eye ( -- point ) turtle-pos> ;
+
+: camera-focus ( -- point ) [ 1 step-turtle turtle-pos> ] save-self ;
+
+: camera-up ( -- dirvec )
+[ 90 pitch-up turtle-pos> 1 step-turtle turtle-pos> swap v- ] save-self ;
+
+: do-look-at ( camera -- )
+[ >self camera-eye camera-focus camera-up gl-look-at ] with-scope ;
diff --git a/extra/4DNav/deep/deep-docs.factor b/extra/4DNav/deep/deep-docs.factor
new file mode 100755
index 0000000000..0332f77e66
--- /dev/null
+++ b/extra/4DNav/deep/deep-docs.factor
@@ -0,0 +1,31 @@
+! Copyright (C) 2008 Jean-Fran�ois Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel quotations sequences ;
+IN: 4DNav.deep
+
+! HELP: deep-cleave-quots
+! { $values
+!     { "seq" sequence }
+!     { "quot" quotation }
+! }
+! { $description "A word to build a soquence from a sequence of quotation" }
+! 
+! { $examples
+! "It is useful to build matrix"
+! { $example "USING: math math.trig ; "
+!     " 30 deg>rad "
+!    "  {  { [ cos ] [ sin neg ]   0 } "
+!    "     { [ sin ] [ cos ]       0 } "
+!    "     {   0       0           1 } "
+!    "  } deep-cleave-quots " 
+!     " "
+! 
+! 
+! } }
+! ;
+
+ARTICLE: "4DNav.deep" "4DNav.deep"
+{ $vocab-link "4DNav.deep" }
+;
+
+ABOUT: "4DNav.deep"
diff --git a/extra/4DNav/deep/deep.factor b/extra/4DNav/deep/deep.factor
new file mode 100755
index 0000000000..65e15180bc
--- /dev/null
+++ b/extra/4DNav/deep/deep.factor
@@ -0,0 +1,11 @@
+USING: macros quotations math math.functions math.trig sequences.deep kernel make fry combinators grouping ;
+IN: 4DNav.deep
+
+! USING: bake ;
+! MACRO: deep-cleave-quots ( seq -- quot )
+!    [ [ quotation? ] deep-filter ]
+!    [ [ dup quotation? [ drop , ] when ] deep-map ]
+!    bi '[ _ cleave _ bake ] ;
+
+: make-matrix ( quot width -- matrix ) [ { } make ] dip group ; inline
+
diff --git a/extra/4DNav/deploy.factor b/extra/4DNav/deploy.factor
new file mode 100755
index 0000000000..e39f91acf6
--- /dev/null
+++ b/extra/4DNav/deploy.factor
@@ -0,0 +1,15 @@
+USING: tools.deploy.config ;
+H{
+    { deploy-c-types? t }
+    { deploy-word-props? t }
+    { deploy-name "4DNav" }
+    { deploy-ui? t }
+    { deploy-math? t }
+    { deploy-threads? t }
+    { deploy-reflection 3 }
+    { deploy-compiler? t }
+    { deploy-unicode? t }
+    { deploy-io 3 }
+    { "stop-after-last-window?" t }
+    { deploy-word-defs? t }
+}
diff --git a/extra/4DNav/file-chooser/authors.txt b/extra/4DNav/file-chooser/authors.txt
new file mode 100755
index 0000000000..a6a96933f4
--- /dev/null
+++ b/extra/4DNav/file-chooser/authors.txt
@@ -0,0 +1 @@
+Jeff Bigot
\ No newline at end of file
diff --git a/extra/4DNav/file-chooser/file-chooser.factor b/extra/4DNav/file-chooser/file-chooser.factor
new file mode 100755
index 0000000000..2915a093ed
--- /dev/null
+++ b/extra/4DNav/file-chooser/file-chooser.factor
@@ -0,0 +1,142 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING:
+kernel
+io.files
+io.backend
+sequences
+models
+strings
+ui
+ui.operations
+ui.commands
+ui.gestures
+ui.gadgets
+ui.gadgets.buttons
+ui.gadgets.lists
+ui.gadgets.labels
+ui.gadgets.tracks
+ui.gadgets.packs
+ui.gadgets.panes
+ui.gadgets.scrollers
+prettyprint
+combinators
+rewrite-closures
+accessors
+namespaces.lib
+values
+tools.walker
+fry
+;
+IN: 4DNav.file-chooser
+
+TUPLE: file-chooser < track 
+    path
+    extension 
+    selected-file
+    presenter
+    hook  
+    list
+    ;
+
+: find-file-list ( gadget -- list )
+    [ file-chooser? ] find-parent list>> ;
+
+file-chooser H{
+    { T{ key-down f f "UP" } [ find-file-list select-previous ] }
+    { T{ key-down f f "DOWN" } [ find-file-list select-next ] }
+    { T{ key-down f f "PAGE_UP" } [ find-file-list list-page-up ] }
+    { T{ key-down f f "PAGE_DOWN" } [ find-file-list list-page-down ] }
+    { T{ key-down f f "RET" } [ find-file-list invoke-value-action ] }
+    { T{ button-down } request-focus }
+    { T{ button-down f 1 } [ find-file-list invoke-value-action ]  }
+} set-gestures
+
+: list-of-files ( file-chooser -- seq )
+     [ path>> value>> directory-entries ] [ extension>> ] bi
+     '[ [ name>> _ [ tail? ] with contains? ] [ directory? ] bi or ]  filter
+;
+
+: update-filelist-model ( file-chooser -- file-chooser )
+    [ list-of-files ] [ model>> ] bi set-model ;
+
+: init-filelist-model ( file-chooser -- file-chooser )
+    dup list-of-files <model> >>model ; 
+
+: (fc-go) ( file-chooser quot -- )
+    [ [ file-chooser? ] find-parent dup path>> ] dip
+    call
+    normalize-path swap set-model
+    update-filelist-model
+    drop ;
+
+: fc-go-parent ( file-chooser -- )
+    [ dup value>> parent-directory ] (fc-go) ;
+
+: fc-go-home ( file-chooser -- )
+    [ home ] (fc-go) ;
+
+: fc-change-directory ( file-chooser file -- file-chooser )
+    dupd [ path>> value>> normalize-path ] [ name>> ] bi* 
+    append-path over path>> set-model    
+    update-filelist-model
+;
+
+: fc-load-file ( file-chooser file -- )
+  dupd [ selected-file>> ] [ name>> ] bi* swap set-model 
+  [ path>> value>> ] 
+  [ selected-file>> value>> append ] 
+  [ hook>> ] tri
+  call
+; inline
+
+! : fc-ok-action ( file-chooser -- quot )
+!  dup selected-file>> value>>  "" =
+!    [ drop [ drop ] ] [    
+!            [ path>> value>> ] 
+!            [ selected-file>> value>> append ] 
+!            [ hook>> prefix ] tri
+!        [ drop ] prepend
+!    ]  if ; 
+
+: line-selected-action ( file-chooser -- )
+     dup list>> list-value
+     dup directory? 
+     [ fc-change-directory ] [ fc-load-file ] if ;
+
+: present-dir-element ( element -- string )
+    [ name>> ] [ directory? ] bi   [ "-> " prepend ] when ;
+
+: <file-list> ( file-chooser -- list )
+  dup [ nip line-selected-action ] curry 
+  [ present-dir-element ] rot model>> <list> ;
+
+: <file-chooser> ( hook path extension -- gadget )
+    { 0 1 } file-chooser new-track
+    swap >>extension
+    swap <model> >>path
+    "" <model> >>selected-file
+    swap >>hook
+    init-filelist-model
+    dup <file-list> >>list
+    "choose a file in directory " <label> f track-add
+    dup path>> <label-control> f track-add
+    dup extension>> ", " join "limited to : " prepend <label> f track-add
+    <shelf> 
+        "selected file : " <label> add-gadget
+        over selected-file>> <label-control> add-gadget
+    f track-add
+    <shelf> 
+        over [  swap fc-go-parent ] curry  "go up" swap <bevel-button> add-gadget
+        over [  swap fc-go-home ] curry  "go home" swap <bevel-button> add-gadget
+    !    over [ swap fc-ok-action ] curry "OK" swap <bevel-button> add-gadget
+    !    [ drop ]  "Cancel" swap <bevel-button> add-gadget
+    f track-add
+    dup list>> <scroller> 1 track-add
+;
+
+M: file-chooser pref-dim* drop { 400 200 } ;
+
+: file-chooser-window ( -- )
+[ . ] home { "xml" "txt" }   <file-chooser> "Choose a file" open-window ;
+
diff --git a/extra/4DNav/hypercube.xml b/extra/4DNav/hypercube.xml
new file mode 100755
index 0000000000..0d46e3b315
--- /dev/null
+++ b/extra/4DNav/hypercube.xml
@@ -0,0 +1,37 @@
+<model>
+<space>
+	<name>hypercube</name>
+	<dimension>4</dimension>
+	<solid>
+		<name>4cube1</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,100</face>
+		<face>-1,0,0,0,-150</face>
+		<face>0,1,0,0,100</face>
+		<face>0,-1,0,0,-150</face>
+		<face>0,0,1,0,100</face>
+		<face>0,0,-1,0,-150</face>
+		<face>0,0,0,1,100</face>
+		<face>0,0,0,-1,-150</face>
+		<color>1,0,0</color>
+	</solid>
+	<solid>
+		<name>4cube1</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,100</face>
+		<face>-1,0,0,0,-150</face>
+		<face>0,1,0,0,100</face>
+		<face>0,-1,0,0,-150</face>
+		<face>0,0,1,0,100</face>
+		<face>0,0,-1,0,-150</face>
+		<face>0,0,0,1,100</face>
+		<face>0,0,0,-1,-150</face>
+		<color>1,0,0</color>
+	</solid>
+	<light>
+		<direction>1,1,1,1</direction>
+		<color>0.2,0.2,0.6</color>
+	</light>
+	<color>0.8,0.9,0.9</color>
+</space>
+</model>
diff --git a/extra/4DNav/light_test.xml b/extra/4DNav/light_test.xml
new file mode 100755
index 0000000000..b7d750ddaa
--- /dev/null
+++ b/extra/4DNav/light_test.xml
@@ -0,0 +1,62 @@
+<model>
+<space>
+	<name>multi solids</name>
+	<dimension>4</dimension>
+	<solid>
+		<name>4cube1</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,100</face>
+		<face>-1,0,0,0,-150</face>
+		<face>0,1,0,0,100</face>
+		<face>0,-1,0,0,-150</face>
+		<face>0,0,1,0,100</face>
+		<face>0,0,-1,0,-150</face>
+		<face>0,0,0,1,100</face>
+		<face>0,0,0,-1,-150</face>
+		<color>1,1,1</color>
+	</solid>
+	<solid>
+		<name>4triancube</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,160</face>
+        	<face>-0.4999999999999998,-0.8660254037844387,0,0,-130</face>
+		<face>-0.5000000000000004,0.8660254037844384,0,0,-130</face>
+		<face>0,0,1,0,140</face>
+		<face>0,0,-1,0,-180</face>
+		<face>0,0,0,1,110</face>
+		<face>0,0,0,-1,-180</face>
+		<color>1,1,1</color>
+	</solid>
+	<solid>
+		<name>triangone</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,60</face>
+		<face>0.5,0.8660254037844386,0,0,60</face>
+		<face>-0.5,0.8660254037844387,0,0,-20</face>
+		<face>-1.0,0,0,0,-100</face>
+		<face>-0.5,-0.8660254037844384,0,0,-100</face>
+		<face>0.5,-0.8660254037844387,0,0,-20</face>
+		<face>0,0,1,0,120</face>
+        	<face>0,0,-0.4999999999999998,-0.8660254037844387,-120</face>
+		<face>0,0,-0.5000000000000004,0.8660254037844384,-120</face>
+		<color>1,1,1</color>
+	</solid>
+	<light>
+		<direction>1,0,0,0</direction>
+		<color>0,0,0,0.6</color>
+	</light>
+	<light>
+		<direction>0,1,0,0</direction>
+		<color>0,0.6,0,0</color>
+	</light>
+	<light>
+		<direction>0,0,1,0</direction>
+		<color>0,0,0.6,0</color>
+	</light>
+	<light>
+		<direction>0,0,0,1</direction>
+		<color>0.6,0.6,0.6</color>
+	</light>
+	<color>0.99,0.99,0.99</color>
+</space>
+</model>
diff --git a/extra/4DNav/multi solids.xml b/extra/4DNav/multi solids.xml
new file mode 100755
index 0000000000..b401e988b9
--- /dev/null
+++ b/extra/4DNav/multi solids.xml	
@@ -0,0 +1,50 @@
+<model>
+<space>
+	<name>multi solids</name>
+	<dimension>4</dimension>
+	<solid>
+		<name>4cube1</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,100</face>
+		<face>-1,0,0,0,-150</face>
+		<face>0,1,0,0,100</face>
+		<face>0,-1,0,0,-150</face>
+		<face>0,0,1,0,100</face>
+		<face>0,0,-1,0,-150</face>
+		<face>0,0,0,1,100</face>
+		<face>0,0,0,-1,-150</face>
+		<color>1,0,0</color>
+	</solid>
+	<solid>
+		<name>4triancube</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,160</face>
+        	<face>-0.4999999999999998,-0.8660254037844387,0,0,-130</face>
+		<face>-0.5000000000000004,0.8660254037844384,0,0,-130</face>
+		<face>0,0,1,0,140</face>
+		<face>0,0,-1,0,-180</face>
+		<face>0,0,0,1,110</face>
+		<face>0,0,0,-1,-180</face>
+		<color>0,1,0</color>
+	</solid>
+	<solid>
+		<name>triangone</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,60</face>
+		<face>0.5,0.8660254037844386,0,0,60</face>
+		<face>-0.5,0.8660254037844387,0,0,-20</face>
+		<face>-1.0,0,0,0,-100</face>
+		<face>-0.5,-0.8660254037844384,0,0,-100</face>
+		<face>0.5,-0.8660254037844387,0,0,-20</face>
+		<face>0,0,1,0,120</face>
+        	<face>0,0,-0.4999999999999998,-0.8660254037844387,-120</face>
+		<face>0,0,-0.5000000000000004,0.8660254037844384,-120</face>
+		<color>0,1,1</color>
+	</solid>
+	<light>
+		<direction>1,1,1,1</direction>
+		<color>0.2,0.2,0.6</color>
+	</light>
+	<color>0.8,0.9,0.9</color>
+</space>
+</model>
diff --git a/extra/4DNav/prismetriagone.xml b/extra/4DNav/prismetriagone.xml
new file mode 100755
index 0000000000..cbdc071f97
--- /dev/null
+++ b/extra/4DNav/prismetriagone.xml
@@ -0,0 +1,25 @@
+<model>
+<space>
+	<name>Prismetragone</name>		
+	<dimension>4</dimension>
+	<solid>
+		<name>triangone</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,60</face>
+		<face>0.5,0.8660254037844386,0,0,60</face>
+		<face>-0.5,0.8660254037844387,0,0,-20</face>
+		<face>-1.0,0,0,0,-100</face>
+		<face>-0.5,-0.8660254037844384,0,0,-100</face>
+		<face>0.5,-0.8660254037844387,0,0,-20</face>
+		<face>0,0,1,0,120</face>
+        	<face>0,0,-0.4999999999999998,-0.8660254037844387,-120</face>
+		<face>0,0,-0.5000000000000004,0.8660254037844384,-120</face>
+		<color>0,1,1</color>
+	</solid>
+	<light>
+		<direction>1,1,1,1</direction>
+		<color>0.2,0.2,0.6</color>
+	</light>
+	<color>0.8,0.9,0.9</color>
+</space>
+</model>
diff --git a/extra/4DNav/space-file-decoder/authors.txt b/extra/4DNav/space-file-decoder/authors.txt
new file mode 100755
index 0000000000..a6a96933f4
--- /dev/null
+++ b/extra/4DNav/space-file-decoder/authors.txt
@@ -0,0 +1 @@
+Jeff Bigot
\ No newline at end of file
diff --git a/extra/4DNav/space-file-decoder/space-file-decoder-docs.factor b/extra/4DNav/space-file-decoder/space-file-decoder-docs.factor
new file mode 100755
index 0000000000..ce66375759
--- /dev/null
+++ b/extra/4DNav/space-file-decoder/space-file-decoder-docs.factor
@@ -0,0 +1,31 @@
+! Copyright (C) 2008 Jean-François Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel ;
+IN: 4DNav.space-file-decoder
+
+HELP: adsoda-read-model
+{ $values
+     { "tag" null }
+}
+{ $description "" } ;
+
+HELP: decode-number-array
+{ $values
+     { "x" null }
+     { "y" null }
+}
+{ $description "" } ;
+
+HELP: read-model-file
+{ $values
+    
+     { "path" "path to the file to read" }
+     { "x" null }
+}
+{ $description "" } ;
+
+ARTICLE: "4DNav.space-file-decoder" "4DNav.space-file-decoder"
+{ $vocab-link "4DNav.space-file-decoder" }
+;
+
+ABOUT: "4DNav.space-file-decoder"
diff --git a/extra/4DNav/space-file-decoder/space-file-decoder.factor b/extra/4DNav/space-file-decoder/space-file-decoder.factor
new file mode 100755
index 0000000000..158917ca3e
--- /dev/null
+++ b/extra/4DNav/space-file-decoder/space-file-decoder.factor
@@ -0,0 +1,65 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: adsoda
+xml
+xml.utilities
+accessors
+combinators
+sequences
+math.parser
+kernel
+splitting
+values
+continuations
+;
+IN: 4DNav.space-file-decoder
+
+: decode-number-array ( x -- y )  "," split [ string>number ] map ;
+
+PROCESS: adsoda-read-model ( tag -- )
+
+TAG: dimension adsoda-read-model children>> first string>number ;
+TAG: direction adsoda-read-model children>> first decode-number-array ;
+TAG: color     adsoda-read-model children>> first decode-number-array ;
+TAG: name      adsoda-read-model children>> first ;
+TAG: face      adsoda-read-model children>> first decode-number-array ;
+
+TAG: solid adsoda-read-model 
+    <solid> swap  
+    { 
+        [ "dimension" tag-named adsoda-read-model >>dimension ] 
+        [ "name"      tag-named adsoda-read-model >>name ] 
+        [ "color"     tag-named adsoda-read-model >>color ] 
+        [ "face"      tags-named [ adsoda-read-model cut-solid ] each ] 
+    } cleave
+    ensure-adjacencies
+;
+
+TAG: light adsoda-read-model 
+   <light> swap  
+    { 
+        [ "direction" tag-named adsoda-read-model >>direction ] 
+        [ "color"     tag-named adsoda-read-model >>color ] 
+    } cleave
+;
+
+TAG: space adsoda-read-model 
+    <space> swap  
+    { 
+        [ "dimension" tag-named adsoda-read-model >>dimension ] 
+        [ "name"      tag-named adsoda-read-model >>name ] 
+        [ "color"     tag-named adsoda-read-model >>ambient-color ] 
+        [ "solid"     tags-named [ adsoda-read-model suffix-solids ] each ] 
+        [ "light"     tags-named [ adsoda-read-model suffix-lights ] each ]         
+    } cleave
+;
+
+: read-model-file ( path -- x )
+  dup
+  [
+    [ file>xml "space" tags-named first adsoda-read-model ] 
+    [ drop <space> ] recover 
+  ] [  drop <space> ] if 
+
+;
+
diff --git a/extra/4DNav/summary.txt b/extra/4DNav/summary.txt
new file mode 100755
index 0000000000..5b5a452cde
--- /dev/null
+++ b/extra/4DNav/summary.txt
@@ -0,0 +1 @@
+4DNav : simmple tool to navigate thru a 4D space view as projections on 4 3D spaces.
\ No newline at end of file
diff --git a/extra/4DNav/tags.txt b/extra/4DNav/tags.txt
new file mode 100755
index 0000000000..0c63a72fc9
--- /dev/null
+++ b/extra/4DNav/tags.txt
@@ -0,0 +1 @@
+4D viewer
\ No newline at end of file
diff --git a/extra/4DNav/triancube.xml b/extra/4DNav/triancube.xml
new file mode 100755
index 0000000000..8551bed24c
--- /dev/null
+++ b/extra/4DNav/triancube.xml
@@ -0,0 +1,23 @@
+<model>
+<space>
+	<name>triancube</name>		
+	<dimension>4</dimension>
+	<solid>
+		<name>triancube</name>
+		<dimension>4</dimension>
+		<face>1,0,0,0,160</face>
+        	<face>-0.4999999999999998,-0.8660254037844387,0,0,-130</face>
+		<face>-0.5000000000000004,0.8660254037844384,0,0,-130</face>
+		<face>0,0,1,0,140</face>
+		<face>0,0,-1,0,-180</face>
+		<face>0,0,0,1,110</face>
+		<face>0,0,0,-1,-180</face>
+		<color>0,1,0</color>
+	</solid>
+	<light>
+		<direction>1,1,1,1</direction>
+		<color>0.2,0.2,0.6</color>
+	</light>
+	<color>0.8,0.9,0.9</color>
+</space>
+</model>
diff --git a/extra/4DNav/turtle/authors.txt b/extra/4DNav/turtle/authors.txt
new file mode 100755
index 0000000000..6cfd5da273
--- /dev/null
+++ b/extra/4DNav/turtle/authors.txt
@@ -0,0 +1 @@
+Eduardo Cavazos
diff --git a/extra/4DNav/turtle/turtle-docs.factor b/extra/4DNav/turtle/turtle-docs.factor
new file mode 100755
index 0000000000..e6f57972b9
--- /dev/null
+++ b/extra/4DNav/turtle/turtle-docs.factor
@@ -0,0 +1,229 @@
+! Copyright (C) 2008 Jean-François Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays help.markup help.syntax kernel sequences ;
+IN: 4DNav.turtle
+
+HELP: <turtle>
+{ $values
+    
+     { "turtle" null }
+}
+{ $description "" } ;
+
+HELP: >turtle-ori
+{ $values
+     { "val" null }
+}
+{ $description "" } ;
+
+HELP: >turtle-pos
+{ $values
+     { "val" null }
+}
+{ $description "" } ;
+
+HELP: Rx
+{ $values
+     { "angle" null }
+     { "Rz" null }
+}
+{ $description "" } ;
+
+HELP: Ry
+{ $values
+     { "angle" null }
+     { "Ry" null }
+}
+{ $description "" } ;
+
+HELP: Rz
+{ $values
+     { "angle" null }
+     { "Rx" null }
+}
+{ $description "" } ;
+
+HELP: V
+{ $values
+    
+     { "V" null }
+}
+{ $description "" } ;
+
+HELP: X
+{ $values
+    
+     { "3array" null }
+}
+{ $description "" } ;
+
+HELP: Y
+{ $values
+    
+     { "3array" null }
+}
+{ $description "" } ;
+
+HELP: Z
+{ $values
+    
+     { "3array" null }
+}
+{ $description "" } ;
+
+HELP: apply-rotation
+{ $values
+     { "rotation" null }
+}
+{ $description "" } ;
+
+HELP: distance
+{ $values
+     { "turtle" null } { "turtle" null }
+     { "n" null }
+}
+{ $description "" } ;
+
+HELP: move-by
+{ $values
+     { "point" null }
+}
+{ $description "" } ;
+
+HELP: pitch-down
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: pitch-up
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: reset-turtle
+{ $description "" } ;
+
+HELP: roll-left
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: roll-right
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: roll-until-horizontal
+{ $description "" } ;
+
+HELP: rotate-x
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: rotate-y
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: rotate-z
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: set-X
+{ $values
+     { "seq" sequence }
+}
+{ $description "" } ;
+
+HELP: set-Y
+{ $values
+     { "seq" sequence }
+}
+{ $description "" } ;
+
+HELP: set-Z
+{ $values
+     { "seq" sequence }
+}
+{ $description "" } ;
+
+HELP: step-turtle
+{ $values
+     { "length" null }
+}
+{ $description "" } ;
+
+HELP: step-vector
+{ $values
+     { "length" null }
+     { "array" array }
+}
+{ $description "" } ;
+
+HELP: strafe-down
+{ $values
+     { "length" null }
+}
+{ $description "" } ;
+
+HELP: strafe-left
+{ $values
+     { "length" null }
+}
+{ $description "" } ;
+
+HELP: strafe-right
+{ $values
+     { "length" null }
+}
+{ $description "" } ;
+
+HELP: strafe-up
+{ $values
+     { "length" null }
+}
+{ $description "" } ;
+
+HELP: turn-left
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: turn-right
+{ $values
+     { "angle" null }
+}
+{ $description "" } ;
+
+HELP: turtle
+{ $description "" } ;
+
+HELP: turtle-ori>
+{ $values
+    
+     { "val" null }
+}
+{ $description "" } ;
+
+HELP: turtle-pos>
+{ $values
+    
+     { "val" null }
+}
+{ $description "" } ;
+
+ARTICLE: "4DNav.turtle" "4DNav.turtle"
+{ $vocab-link "4DNav.turtle" }
+;
+
+ABOUT: "4DNav.turtle"
diff --git a/extra/4DNav/turtle/turtle.factor b/extra/4DNav/turtle/turtle.factor
new file mode 100755
index 0000000000..72a2e58e9b
--- /dev/null
+++ b/extra/4DNav/turtle/turtle.factor
@@ -0,0 +1,152 @@
+USING: kernel math arrays math.vectors math.matrices
+namespaces make
+math.constants math.functions
+math.vectors
+splitting grouping self math.trig
+  sequences accessors 4DNav.deep models ;
+IN: 4DNav.turtle
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: turtle pos ori ;
+
+: <turtle> ( -- turtle )
+    turtle new
+    { 0 0 0 } clone >>pos
+    3 identity-matrix >>ori
+;
+
+
+TUPLE: observer < turtle projection-mode collision-mode ;
+
+: <observer> ( -- object ) 
+     observer new
+    0 <model> >>projection-mode 
+    f <model> >>collision-mode
+    ;
+
+
+: turtle-pos> ( -- val ) self> pos>> ;
+: >turtle-pos ( val -- ) self> (>>pos) ;
+
+: turtle-ori> ( -- val ) self> ori>> ;
+: >turtle-ori ( val -- ) self> (>>ori) ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+! These rotation matrices are from
+! `Computer Graphics: Principles and Practice'
+
+
+! waiting for deep-cleave-quots  
+
+! : Rz ( angle -- Rx ) deg>rad
+!    {   { [ cos ] [ sin neg ]   0 }
+!        { [ sin ] [ cos ]      0  }
+!        {   0       0           1 } 
+!    } deep-cleave-quots  ;
+
+! : Ry ( angle -- Ry ) deg>rad
+!    {   { [ cos ]      0 [ sin ] }
+!        {   0          1 0       }
+!        { [  sin neg ] 0 [ cos ] }
+!    } deep-cleave-quots  ;
+  
+! : Rx ( angle -- Rz ) deg>rad
+!   {   { 1     0        0        }
+!        { 0   [ cos ] [ sin neg ] }
+!        { 0   [ sin ] [ cos ]     }
+!    } deep-cleave-quots ;
+
+: Rz ( angle -- Rx ) deg>rad
+[ dup cos ,     dup sin neg ,   0 ,
+  dup sin ,     dup cos ,       0 ,
+  0 ,           0 ,             1 , ] 3 make-matrix nip ;
+
+: Ry ( angle -- Ry ) deg>rad
+[ dup cos ,     0 ,             dup sin ,
+  0 ,           1 ,             0 ,
+  dup sin neg , 0 ,             dup cos , ] 3 make-matrix nip ;
+
+: Rx ( angle -- Rz ) deg>rad
+[ 1 ,           0 ,             0 ,
+  0 ,           dup cos ,       dup sin neg ,
+  0 ,           dup sin ,       dup cos , ] 3 make-matrix nip ;
+
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: apply-rotation ( rotation -- ) turtle-ori> swap m. >turtle-ori ;
+
+: rotate-x ( angle -- ) Rx apply-rotation ;
+: rotate-y ( angle -- ) Ry apply-rotation ;
+: rotate-z ( angle -- ) Rz apply-rotation ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: pitch-up   ( angle -- ) neg rotate-x ;
+: pitch-down ( angle -- )     rotate-x ;
+
+: turn-left ( angle -- )      rotate-y ;
+: turn-right ( angle -- ) neg rotate-y ;
+
+: roll-left  ( angle -- ) neg rotate-z ;
+: roll-right ( angle -- )     rotate-z ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! roll-until-horizontal
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: V ( -- V ) { 0 1 0 } ;
+
+: X ( -- 3array ) turtle-ori> [ first  ] map ;
+: Y ( -- 3array ) turtle-ori> [ second ] map ;
+: Z ( -- 3array ) turtle-ori> [ third  ] map ;
+
+: set-X ( seq -- ) turtle-ori> [ set-first ] 2each ;
+: set-Y ( seq -- ) turtle-ori> [ set-second ] 2each ;
+: set-Z ( seq -- ) turtle-ori> [ set-third ] 2each ;
+
+: roll-until-horizontal ( -- )
+    V Z cross normalize set-X
+    Z X cross normalize set-Y ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: distance ( turtle turtle -- n ) pos>> swap pos>> v- [ sq ] map sum sqrt ;
+
+: move-by ( point -- ) turtle-pos> v+ >turtle-pos ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: reset-turtle ( -- ) 
+    { 0 0 0 } clone >turtle-pos 3 identity-matrix >turtle-ori ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: step-vector ( length -- array ) { 0 0 1 } n*v ;
+
+: step-turtle ( length -- ) 
+    step-vector turtle-ori> swap m.v turtle-pos> v+ >turtle-pos ;
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+: strafe-up ( length -- )
+    90 pitch-up
+    step-turtle
+    90 pitch-down ;
+
+: strafe-down ( length -- )
+    90 pitch-down
+    step-turtle
+    90 pitch-up ;
+
+: strafe-left ( length -- )
+    90 turn-left
+    step-turtle
+    90 turn-right ;
+
+: strafe-right ( length -- )
+    90 turn-right
+    step-turtle
+    90 turn-left ;
diff --git a/extra/4DNav/window3D/authors.txt b/extra/4DNav/window3D/authors.txt
new file mode 100755
index 0000000000..a6a96933f4
--- /dev/null
+++ b/extra/4DNav/window3D/authors.txt
@@ -0,0 +1 @@
+Jeff Bigot
\ No newline at end of file
diff --git a/extra/4DNav/window3D/window3D-docs.factor b/extra/4DNav/window3D/window3D-docs.factor
new file mode 100755
index 0000000000..d57df6a8d8
--- /dev/null
+++ b/extra/4DNav/window3D/window3D-docs.factor
@@ -0,0 +1,20 @@
+! Copyright (C) 2008 Jean-François Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax kernel ;
+IN: 4DNav.window3D
+
+HELP: <window3D>
+{ $values
+     { "model" null } { "observer" null }
+     { "gadget" null }
+}
+{ $description "" } ;
+
+HELP: window3D
+{ $description "" } ;
+
+ARTICLE: "4DNav.window3D" "4DNav.window3D"
+{ $vocab-link "4DNav.window3D" }
+;
+
+ABOUT: "4DNav.window3D"
diff --git a/extra/4DNav/window3D/window3D.factor b/extra/4DNav/window3D/window3D.factor
new file mode 100755
index 0000000000..6db5d7c2f5
--- /dev/null
+++ b/extra/4DNav/window3D/window3D.factor
@@ -0,0 +1,82 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel 
+ui.gadgets
+ui.render
+opengl
+opengl.gl
+opengl.glu
+4DNav.camera
+4DNav.turtle
+math
+values
+alien.c-types
+accessors
+namespaces
+adsoda 
+models
+accessors
+prettyprint
+;
+
+IN: 4DNav.window3D
+
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! drawing functions 
+! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+TUPLE: window3D  < gadget observer ; 
+
+: <window3D>  ( model observer -- gadget )
+    window3D  new-gadget 
+    swap 2dup 
+    projection-mode>> add-connection
+    2dup 
+    collision-mode>> add-connection
+    >>observer 
+    swap <model> >>model 
+    t >>root?
+;
+
+M: window3D pref-dim* ( gadget -- dim )  drop { 300 300 } ;
+
+M: window3D draw-gadget* ( gadget -- )
+
+    GL_PROJECTION glMatrixMode
+        glLoadIdentity
+        0.6 0.6 0.6 .9 glClearColor
+        dup observer>> projection-mode>> value>> 1 =    
+        [ 60.0 1.0 0.1 3000.0 gluPerspective ]
+        [ -400.0 400.0 -400.0 400.0 0.0 4000.0 glOrtho ] if
+        dup observer>> collision-mode>> value>> 
+        \ remove-hidden-solids?   
+        set-value
+        dup  observer>> do-look-at
+        GL_MODELVIEW glMatrixMode
+            glLoadIdentity  
+            0.9 0.9 0.9 1.0 glClearColor
+            1.0 glClearDepth
+            GL_LINE_SMOOTH glEnable
+            GL_BLEND glEnable
+            GL_DEPTH_TEST glEnable       
+            GL_LEQUAL glDepthFunc
+            GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA glBlendFunc
+            GL_LINE_SMOOTH_HINT GL_NICEST glHint
+            1.25 glLineWidth
+            GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT bitor glClear
+            glLoadIdentity
+            GL_LIGHTING glEnable
+            GL_LIGHT0 glEnable
+            GL_COLOR_MATERIAL glEnable
+            GL_FRONT GL_AMBIENT_AND_DIFFUSE glColorMaterial
+            ! *************************
+            
+            model>> value>> 
+            [ space->GL ] when*
+
+            ! *************************
+;
+
+M: window3D graft* drop ;
+
+M: window3D model-changed nip relayout ; 
diff --git a/extra/adsoda/adsoda-docs.factor b/extra/adsoda/adsoda-docs.factor
new file mode 100755
index 0000000000..d90beb7c7b
--- /dev/null
+++ b/extra/adsoda/adsoda-docs.factor
@@ -0,0 +1,300 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: help.markup help.syntax ;
+
+IN: adsoda
+
+
+
+! --------------------------------------------------------------
+! faces
+! --------------------------------------------------------------
+ARTICLE: "face-page" "face in ADSODA"
+"explanation of faces"
+$nl
+"link to functions"
+"what is an halfspace"
+"halfspace touching-corners adjacent-faces"
+"touching-corners list of pointers to the corners which touch this face\n"
+
+"adjacent-faces list of pointers to the faces which touch this face\n"
+{ $subsection face }
+{ $subsection <face> }
+"test relative position"
+{ $subsection point-inside-or-on-face? } 
+{ $subsection point-inside-face? }
+"handling face"
+{ $subsection flip-face }
+{ $subsection face-translate  }
+{ $subsection  face-transform }
+
+;
+
+HELP: face
+{ $class-description "a face is defined by"
+{ $list "halfspace equation" }
+{ $list "list of touching corners" }
+{ $list "list of adjacent faces" }
+$nl
+"Touching corners and adjacent faces are defined by algorithm thanks to other faces of the solid"
+}
+
+
+;
+HELP: <face> 
+{ $values { "v" "an halfspace equation" } { "tuple" "a face" }  }   ;
+HELP: flip-face 
+{ $values { "face" "a face" } { "face" "flipped face" } }
+{ $description "change the orientation of a face" }
+;
+
+HELP: face-translate 
+{ $values { "face" "a face" } { "v" "a vector" } }
+{ $description 
+"translate a face following a vector"
+$nl
+"a translation of an halfspace doesn't change the normal vector. this word just compute the new constant term" }
+
+ 
+ ;
+HELP: face-transform 
+{ $values { "face" "a face" } { "m" "a transformation matrix" } }
+{ $description  "compute the transformation of a face using a transformation matrix" }
+ 
+ ;
+! --------------------------------
+! solid
+! --------------------------------------------------------------
+ARTICLE: "solid-page" "solid in ADSODA"
+"explanation of solids"
+$nl
+"link to functions"
+{ $subsection solid }
+{ $subsection <solid> }
+"test relative position"
+{ $subsection point-inside-solid? }
+{ $subsection point-inside-or-on-solid? }
+"playing with faces and solids"
+{ $subsection add-face }
+{ $subsection cut-solid }
+{ $subsection slice-solid }
+"solid handling"
+{ $subsection solid-project }
+{ $subsection solid-translate }
+{ $subsection solid-transform }
+{ $subsection subtract }
+
+{ $subsection get-silhouette  }
+
+{ $subsection  solid= }
+
+
+;
+
+HELP: solid 
+{ $class-description "dimension" $nl "silhouettes" $nl "faces" $nl "corners" $nl "adjacencies-valid" $nl "color" $nl "name" 
+}
+;
+
+HELP: add-face 
+{ $values { "solid" "a solid" } { "face" "a face" } }
+{ $description "reshape a solid with a face. The face truncate the solid." } ;
+
+HELP: cut-solid
+{ $values { "solid" "a solid" } { "halfspace" "an halfspace" } }
+{ $description "like add-face but just with halfspace equation" } ;
+
+HELP: slice-solid
+{ $values { "solid" "a solid" } { "face" "a face" } { "solid1" "the outer part of the former solid" } { "solid2" "the inner part of the former solid" } }
+{ $description "cut a solid into two parts. The face acts like a knife"
+}  ;
+
+
+HELP: solid-project
+{ $values { "lights" "lights" } { "ambient" "ambient" } { "solid" "solid" } { "solids" "projection of solid" } }
+{ $description "Project the solid using pv vector" 
+$nl
+"TODO: explain how to use lights"
+} ;
+
+HELP: solid-translate 
+{ $values { "solid" "a solid" } { "v" "translating vector" } }
+{ $description "Translate a solid using a vector" 
+$nl
+"v and solid must have the same dimension "
+} ;
+
+HELP: solid-transform 
+{ $values { "solid" "a solid" } { "m" "transformation matrix" } }
+{ $description "Transform a solid using a matrix"
+$nl
+"v and solid must have the same dimension "
+} ;
+
+HELP: subtract 
+{ $values { "solid1" "initial shape" } { "solid2" "shape to remove" } { "solids" "resulting shape" } }
+{ $description  " " } ;
+
+
+! --------------------------------------------------------------
+! space 
+! --------------------------------------------------------------
+ARTICLE: "space-page" "space in ADSODA"
+"A space is a collection of solids and lights."
+$nl
+"link to functions"
+$nl
+"Defining words"
+{ $subsection space }
+{ $subsection <space> } 
+{ $subsection suffix-solids  }
+{ $subsection suffix-lights }
+{ $subsection clear-space-solids  }
+{ $subsection describe-space }
+
+
+"Handling space"
+{ $subsection space-ensure-solids }
+{ $subsection eliminate-empty-solids  }
+{ $subsection space-transform }
+{ $subsection space-translate }
+{ $subsection remove-hidden-solids }
+{ $subsection space-project }
+
+
+;
+
+HELP: space 
+{ $class-description 
+"dimension" $nl " solids" $nl " ambient-color" $nl "lights" 
+}
+;
+
+HELP: suffix-solids 
+"( space solid -- space )"
+{ $values { "space" "a space" } { "solid" "a solid to add" } }
+{ $description "Add solid to space definition" } ;
+
+HELP: suffix-lights 
+"( space light -- space ) "
+{ $values { "space" "a space" } { "light" "a light to add" } }
+{ $description "Add a light to space definition" } ;
+
+HELP: clear-space-solids 
+"( space -- space )"   
+{ $values { "space" "a space" } }
+{ $description "remove all solids in space" } ;
+
+HELP: space-ensure-solids 
+{ $values { "space" "a space" } }
+{ $description "rebuild corners of all solids in space" } ;
+
+
+
+HELP: space-transform 
+" ( space m -- space )" 
+{ $values { "space" "a space" } { "m" "a matrix" } }
+{ $description "Transform a space using a matrix" } ;
+
+HELP: space-translate 
+{ $values { "space" "a space" } { "v" "a vector" } }
+{ $description "Translate a space following a vector" } ;
+
+HELP: describe-space " ( space -- )"
+{ $values { "space" "a space" } }
+{ $description "return a description of space" } ;
+
+HELP: space-project 
+{ $values { "space" "a space" } { "i" "an integer" } }
+{ $description "Project a space along ith coordinate" } ;
+
+! --------------------------------------------------------------
+! 3D rendering
+! --------------------------------------------------------------
+ARTICLE: "3D-rendering-page" "3D rendering in ADSODA"
+"explanation of 3D rendering"
+$nl
+"link to functions"
+{ $subsection face->GL }
+{ $subsection solid->GL }
+{ $subsection space->GL }
+
+;
+
+HELP: face->GL 
+{ $values { "face" "a face" } { "color" "3 3 values array" } }
+{ $description "" } ;
+
+HELP: solid->GL 
+{ $values { "solid" "a solid" } }
+{ $description "" } ;
+
+HELP: space->GL 
+{ $values { "space" "a space" } }
+{ $description "" } ;
+
+! --------------------------------------------------------------
+! light
+! --------------------------------------------------------------
+
+ARTICLE: "light-page" "light in ADSODA"
+"explanation of light"
+$nl
+"link to functions"
+;
+
+ARTICLE: { "adsoda" "light" } "ADSODA : lights"
+"! HELP: light position color" 
+"! <light> ( -- tuple ) light new ;"
+
+"! light est un vecteur avec 3 variables pour les couleurs\n"
+
+" void Light::Apply(Vector& normal, double &cRed, double &cGreen, double &cBlue)\n"
+" { \n"
+"   // Dot the light direction with the normalized normal of Face."
+"   register double intensity = -(normal * (*this));"
+
+"   // Face is a backface, from light's perspective"
+"   if (intensity < 0)"
+"     return;"
+"   "
+"   // Add the intensity componentwise"
+"   cRed += red * intensity;"
+"   cGreen += green * intensity;"
+"   cBlue += blue * intensity;"
+
+"   // Clip to unit range"
+"  if (cRed > 1.0) cRed = 1.0;"
+"   if (cGreen > 1.0) cGreen = 1.0;"
+"   if (cBlue > 1.0) cBlue = 1.0;"
+
+
+;
+
+
+
+ARTICLE: { "adsoda" "halfspace" } "ADSODA : halfspace"
+"! demi espace d�fini par un vecteur normal et une constante"
+" defined by the concatenation of the normal vector and a constant"  
+ ;
+
+
+
+ARTICLE:  "adsoda-main-page"  "ADSODA : Arbitrary-Dimensional Solid Object Display Algorithm"
+"multidimensional handler :" 
+$nl
+"design a solid using face delimitations. Only works on convex shapes"
+$nl
+{ $emphasis "written in C++ by Greg Ferrar" }
+$nl
+"full explanation on adsoda page at " { $url "http://www.flowerfire.com/ADSODA/" }
+$nl
+"Useful words are describe on the following pages: "
+{ $subsection "face-page" }
+{ $subsection "solid-page" }
+{ $subsection "space-page" }
+{ $subsection "light-page" }
+{ $subsection "3D-rendering-page" }
+ ;
+
+ABOUT: "adsoda-main-page"
diff --git a/extra/adsoda/adsoda-tests.factor b/extra/adsoda/adsoda-tests.factor
new file mode 100755
index 0000000000..f8881dfebb
--- /dev/null
+++ b/extra/adsoda/adsoda-tests.factor
@@ -0,0 +1,310 @@
+USING: adsoda
+kernel
+math
+accessors
+sequences
+    adsoda.solution2
+    fry
+    tools.test 
+    arrays ;
+
+IN: adsoda.tests
+
+
+
+: s1 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "s1" >>name
+    { 1 1 1 } >>color
+    { 1 -1 -5 } cut-solid 
+    { -1 -1 -21 } cut-solid 
+    { -1 0 -12 } cut-solid 
+    { 1 2 16 } cut-solid
+;
+: solid1 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "solid1" >>name
+    { 1 -1 -5 } cut-solid 
+    { -1 -1 -21 } cut-solid 
+    { -1 0 -12 } cut-solid 
+    { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+;
+: solid2 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "solid2" >>name
+    { -1 1 -10 } cut-solid 
+    { -1 -1 -28 } cut-solid 
+    { 1 0 13 } cut-solid 
+ !   { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+;
+
+: solid3 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid3" >>name
+    { 1 1 1 } >>color
+    { 1 0 16 } cut-solid 
+    { -1 0 -36 } cut-solid 
+    { 0 1 1 } cut-solid 
+    { 0 -1  -17 } cut-solid 
+ !   { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+
+;
+
+: solid4 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid4" >>name
+    { 1 1 1 } >>color
+    { 1 0 21 } cut-solid 
+    { -1 0 -36 } cut-solid 
+    { 0 1 1 } cut-solid 
+    { 0 -1  -17 } cut-solid 
+    ensure-adjacencies
+    
+;
+
+: solid5 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid5" >>name
+    { 1 1 1 } >>color
+    { 1 0 6 } cut-solid 
+    { -1 0 -17 } cut-solid 
+    { 0 1 17 } cut-solid 
+    { 0 -1  -19 } cut-solid 
+    ensure-adjacencies
+    
+;
+
+: solid7 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid7" >>name
+    { 1 1 1 } >>color
+    { 1 0 38 } cut-solid 
+    { 1 -5 -66 } cut-solid 
+    { -2 1 -75 } cut-solid
+    ensure-adjacencies
+    
+;
+
+: solid6s ( -- seq )
+  solid3 clone solid2 clone subtract
+;
+
+: space1 ( -- space )
+    <space>
+        2 >>dimension
+     !    solid3 suffix-solids
+        solid1 suffix-solids
+        solid2 suffix-solids
+    !   solid6s [ suffix-solids ] each 
+        solid4 suffix-solids
+     !   solid5 suffix-solids
+        solid7 suffix-solids
+        { 1 1 1 } >>ambient-color
+            <light>
+        { -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+;
+
+: space2 ( -- space )
+    <space>
+        4 >>dimension
+       ! 4cube suffix-solids
+        { 1 1 1 } >>ambient-color
+            <light>
+        { -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+
+       ;
+
+
+
+! {
+!        { 1 0 0 0 }
+!        { 0 1 0 0 }
+!        { 0 0 0.984807753012208 -0.1736481776669303 }
+!        { 0 0 0.1736481776669303 0.984807753012208 }
+!    }
+
+! ------------------------------------------------------------
+! constant+
+[ { 1 2 5 } ] [ { 1 2 3 } 2 constant+ ] unit-test
+
+! ------------------------------------------------------------
+! translate
+[ { 1 -1 0 } ] [ { 1 -1 -5 } { 3 -2 } translate ] unit-test
+
+! ------------------------------------------------------------
+! transform
+[ { -1 -1 -5 21.0 } ] [ { -1 -1 -5 21 }
+  { { 1 0 0 }
+    { 0 1 0 }
+    { 0 0 1 }
+    } transform  
+] unit-test
+
+! ------------------------------------------------------------
+! compare-nleft-to-identity-matrix
+[ t ] [ 
+    { 
+        { 1 0 0 1232 } 
+        { 0 1 0 0 321 } 
+        { 0 0 1 0 } } 
+        3 compare-nleft-to-identity-matrix 
+]  unit-test
+
+[ f ] [ 
+    { { 1 0 0 } { 0 1 0 } { 0 0 0 } } 
+    3 compare-nleft-to-identity-matrix 
+] unit-test
+
+[ f ] [ 
+    { { 2 0 0 } { 0 1 0 } { 0 0 1 } } 
+    3 compare-nleft-to-identity-matrix 
+] unit-test
+! ------------------------------------------------------------
+[ t ] [ 
+  { { 1 0 0 }
+    { 0 1 0 }
+    { 0 0 1 } } 3 valid-solution? 
+] unit-test
+
+[ f ] [ 
+  { { 1 0 0 1 }
+    { 0 0 0 1 }
+    { 0 0 1 0 } } 3 valid-solution? 
+] unit-test
+
+[ f ] [ 
+  { { 1 0 0 1 }
+    { 0 0 0 1 } } 3 valid-solution? 
+] unit-test
+
+[ f ] [ 
+  { { 1 0 0 1 }
+    { 0 0 0 1 }
+    { 0 0 1 0 } } 2 valid-solution? 
+] unit-test
+
+! ------------------------------------------------------------
+[ 3 ] [ { 1 2 3 } last ] unit-test 
+
+[ { 1 2 5 } ] [ { 1 2 3 } dup [ 2 + ] change-last ] unit-test 
+
+! ------------------------------------------------------------
+! position-point 
+[ 0 ] [ 
+    { 1 -1 -5 } { 2 7 } position-point 
+] unit-test
+
+! ------------------------------------------------------------
+
+! transform
+! TODO construire un exemple
+
+
+! ------------------------------------------------------------
+! slice-solid 
+
+! ------------------------------------------------------------
+! solve-equation 
+! deux cas de tests, avec solution et sans solution
+
+[ { 2 7 } ] 
+[ { { 1 -1 -5 } { 1 2 16 } } intersect-hyperplanes ] 
+unit-test
+
+[ f ] 
+[ { { 1 -1 -5 } { 1 2 16 } { -1 -1 -21 } } intersect-hyperplanes  ]
+unit-test
+
+[ f ] 
+[ { { 1 0 -5 } { 1 0 16 }  } intersect-hyperplanes  ]
+unit-test
+
+! ------------------------------------------------------------
+! point-inside-halfspace
+[ t ] [ { 1 -1 -5 } { 0 0 }  point-inside-halfspace? ] 
+unit-test
+[ f ] [ { 1 -1 -5 } { 8 13 }  point-inside-halfspace? ] 
+unit-test
+[ t ] [ { 1 -1 -5 } { 8 13 }  point-inside-or-on-halfspace? ] 
+unit-test
+
+
+! ------------------------------
+! order solid
+
+[  1 ] [ 0 >pv solid1 solid2 order-solid ] unit-test
+[ -1 ] [ 0 >pv solid2 solid1 order-solid ] unit-test
+[  f ] [ 1 >pv solid1 solid2 order-solid ] unit-test
+[  f ] [ 1 >pv solid2 solid1 order-solid ] unit-test
+
+
+! clip-solid
+[ { { 13 15 } { 15 13 } { 13 13 } } ]
+    [ 0 >pv solid2 solid1 clip-solid first corners>> ] unit-test
+
+solid1 corners>> '[ _ ]
+    [ 0 >pv solid1 solid1 clip-solid first corners>> ] unit-test
+
+solid1 corners>> '[ _ ]
+    [ 0 >pv solid1 solid2 clip-solid first corners>> ] unit-test
+
+solid1 corners>> '[ _ ]
+    [ 1 >pv solid1 solid2 clip-solid first corners>> ] unit-test
+solid2 corners>> '[ _ ]
+    [ 1 >pv solid2 solid1 clip-solid first corners>> ] unit-test
+
+!
+[
+    {
+        { { 13 15 } { 15 13 } { 13 13 } }
+        { { 16 17 } { 16 13 } { 36 17 } { 36 13 } }
+        { { 16 1 } { 16 2 } { 36 1 } { 36 2 } }
+    }
+] [     0 >pv solid2 solid3  2array 
+        solid1 (solids-silhouette-subtract) 
+        [ corners>> ] map
+  ] unit-test
+
+
+[
+{
+    { { 8 13 } { 2 7 } { 12 9 } { 12 2 } }
+    { { 13 15 } { 15 13 } { 13 13 } }
+    { { 16 17 } { 16 15 } { 36 17 } { 36 15 } }
+    { { 16 1 } { 16 2 } { 36 1 } { 36 2 } }
+}
+] [ 
+    0 >pv  <space> solid1 suffix-solids 
+        solid2 suffix-solids 
+        solid3 suffix-solids
+     remove-hidden-solids
+    solids>> [ corners>> ] map
+] unit-test
+
+! { }
+! { }
+! <light> { 0.2 0.3 0.4 } >>color { 1 -1 1 } >>direction     suffix
+! <light> { 0.4 0.3 0.1 } >>color { -1 -1 -1 } >>direction   suffix
+! suffix 
+! { 0.1 0.1 0.1 } suffix ! ambient color
+! { 0.23 0.32 0.17 } suffix ! solid color
+! solid3 faces>> first 
+
+! enlight-projection
diff --git a/extra/adsoda/adsoda.factor b/extra/adsoda/adsoda.factor
new file mode 100755
index 0000000000..e586087e48
--- /dev/null
+++ b/extra/adsoda/adsoda.factor
@@ -0,0 +1,543 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: accessors
+arrays 
+assocs
+combinators
+kernel 
+fry
+math 
+math.constants
+math.functions
+math.libm
+math.order
+math.vectors 
+math.matrices 
+math.parser
+namespaces
+prettyprint
+sequences
+sequences.deep
+sets
+slots
+sorting
+tools.time
+vars
+continuations
+words
+opengl
+opengl.gl
+colors
+adsoda.solution2
+adsoda.combinators
+opengl.demo-support
+values
+tools.walker
+;
+
+IN: adsoda
+
+DEFER: combinations
+VAR: pv
+
+
+! ---------------------------------------------------------------------
+! global values
+VALUE: remove-hidden-solids?
+VALUE: VERY-SMALL-NUM
+VALUE: ZERO-VALUE
+VALUE: MAX-FACE-PER-CORNER
+
+t to: remove-hidden-solids?
+0.0000001 to: VERY-SMALL-NUM
+0.0000001 to: ZERO-VALUE
+4 to: MAX-FACE-PER-CORNER
+! ---------------------------------------------------------------------
+! sequence complement
+
+: with-pv ( i quot -- ) [ swap >pv call ] with-scope  ; inline
+
+: dimension ( array -- x )      length 1- ; inline 
+: last ( seq -- x )             [ dimension ] [ nth ] bi ; inline
+: change-last ( seq quot --  )  [ [ dimension ] keep ] dip change-nth  ; 
+
+! --------------------------------------------------------------
+! light
+! --------------------------------------------------------------
+
+TUPLE: light name { direction array } color ;
+: <light> ( -- tuple ) light new ;
+
+! -----------------------------------------------------------------------
+! halfspace manipulation
+! -----------------------------------------------------------------------
+
+: constant+ ( v x -- w )  '[ [ _ + ] change-last ] keep ;
+: translate ( u v -- w )   dupd     v* sum     constant+ ; 
+
+: transform ( u matrix -- w )
+    [ swap m.v ] 2keep ! compute new normal vector    
+    [
+        [ [ abs ZERO-VALUE > ] find ] keep ! find a point on the frontier
+        ! be sure it's not null vector
+        last ! get constant
+        swap /f neg swap ! intercept value
+    ] dip  
+    flip 
+    nth
+    [ * ] with map ! apply intercep value
+    over v*
+    sum  neg
+    suffix ! add value as constant at the end of equation
+;
+
+: position-point ( halfspace v -- x ) 
+    -1 suffix v* sum  ; inline
+: point-inside-halfspace? ( halfspace v -- ? )       
+    position-point VERY-SMALL-NUM  > ; 
+: point-inside-or-on-halfspace? ( halfspace v -- ? ) 
+    position-point VERY-SMALL-NUM neg > ;
+: project-vector (  seq -- seq )     pv> [ head ] [ 1+  tail ] 2bi append ; 
+: get-intersection ( matrice -- seq )     [ 1 tail* ] map     flip first ;
+
+: islenght=? ( seq n -- seq n ? ) 2dup [ length ] [ = ] bi*  ;
+
+: compare-nleft-to-identity-matrix ( seq n -- ? ) 
+    [ [ head ] curry map ] keep  identity-matrix m- 
+    flatten
+    [ abs ZERO-VALUE < ] all?
+;
+
+: valid-solution? ( matrice n -- ? )
+    islenght=?
+    [ compare-nleft-to-identity-matrix ]  
+    [ 2drop f ] if ; inline
+
+: intersect-hyperplanes ( matrice -- seq )
+    [ solution dup ] [ first dimension ] bi
+    valid-solution?     [ get-intersection ] [ drop f ] if ;
+
+! --------------------------------------------------------------
+! faces
+! --------------------------------------------------------------
+
+TUPLE: face { halfspace array } touching-corners adjacent-faces ;
+: <face> ( v -- tuple )       face new swap >>halfspace ;
+: flip-face ( face -- face ) [ vneg ] change-halfspace ;
+: erase-face-touching-corners ( face -- face ) f >>touching-corners ;
+: erase-face-adjacent-faces ( face -- face )   f >>adjacent-faces ;
+: faces-intersection ( faces -- v )  
+    [ halfspace>> ] map intersect-hyperplanes ;
+: face-translate ( face v -- face ) 
+    [ translate ] curry change-halfspace ; inline
+: face-transform ( face m -- face )
+    [ transform ] curry change-halfspace ; inline
+: face-orientation ( face -- x )  pv> swap halfspace>> nth sgn ;
+: backface? ( face -- face ? )      dup face-orientation 0 <= ;
+: pv-factor ( face -- f face )     
+    halfspace>> [ pv> swap nth [ * ] curry ] keep ; inline
+: suffix-touching-corner ( face corner -- face ) 
+    [ suffix ] curry   change-touching-corners ; inline
+: real-face? ( face -- ? )
+    [ touching-corners>> length ] [ halfspace>> dimension ] bi >= ;
+
+: (add-to-adjacent-faces) ( face face -- face )
+    over adjacent-faces>> 2dup member?
+    [ 2drop ] [ swap suffix >>adjacent-faces ] if ;
+
+: add-to-adjacent-faces ( face face -- face )
+    2dup =   [ drop ] [ (add-to-adjacent-faces) ] if ;
+
+: update-adjacent-faces ( faces corner -- )
+   '[ [ _ suffix-touching-corner drop ] each ] keep 
+    2 among [ 
+        [ first ] keep second  
+        [ add-to-adjacent-faces drop ] 2keep 
+        swap add-to-adjacent-faces drop  
+    ] each ; inline
+
+: face-project-dim ( face -- x )  halfspace>> length 2 -  ;
+
+: apply-light ( color light normal -- u )
+    over direction>>  v. 
+    neg dup 0 > 
+    [ 
+        [ color>> swap ] dip 
+        [ * ] curry map v+ 
+        [ 1 min ] map 
+    ] 
+    [ 2drop ] 
+    if
+;
+
+: enlight-projection ( array face -- color )
+    ! array = lights + ambient color
+    [ [ third ] [ second ] [ first ] tri ]
+    [ halfspace>> project-vector normalize ] bi*
+    [ apply-light ] curry each
+    v*
+;
+
+: (intersection-into-face) ( face-init face-adja quot -- face )
+    [
+    [  [ pv-factor ] bi@ 
+        roll 
+        [ map ] 2bi@
+        v-
+    ] 2keep
+    [ touching-corners>> ] bi@
+    [ swap  [ = ] curry find  nip f = ] curry find nip
+    ] dip  over
+     [
+        call
+        dupd
+        point-inside-halfspace? [ vneg ] unless 
+        <face> 
+     ] [ 3drop f ] if 
+    ; inline
+
+: intersection-into-face ( face-init face-adja -- face )
+    [ [ project-vector ] bi@ ]     (intersection-into-face) ;
+
+: intersection-into-silhouette-face ( face-init face-adja -- face )
+    [ ] (intersection-into-face) ;
+
+: intersections-into-faces ( face -- faces )
+    clone dup  adjacent-faces>> [ intersection-into-face ] with map 
+    [ ] filter ;
+
+: (face-silhouette) ( face -- faces )
+    clone dup adjacent-faces>>
+    [   backface?
+        [ intersection-into-silhouette-face ] [ 2drop f ]  if  
+    ] with map 
+    [ ] filter
+; inline
+
+: face-silhouette ( face -- faces )     
+    backface? [ drop f ] [ (face-silhouette) ] if ;
+
+! --------------------------------
+! solid
+! --------------------------------------------------------------
+TUPLE: solid dimension silhouettes faces corners adjacencies-valid color name ;
+
+: <solid> ( -- tuple ) solid new ;
+
+: suffix-silhouettes ( solid silhouette -- solid )  
+    [ suffix ] curry change-silhouettes ;
+
+: suffix-face ( solid face -- solid )     [ suffix ] curry change-faces ;
+
+: suffix-corner ( solid corner -- solid ) [ suffix ] curry change-corners ; 
+
+: erase-solid-corners ( solid -- solid )  f >>corners ;
+
+: erase-silhouettes ( solid -- solid ) dup dimension>> f <array> >>silhouettes ;
+
+: filter-real-faces ( solid -- solid ) [ [ real-face? ] filter ] change-faces ;
+
+: initiate-solid-from-face ( face -- solid ) 
+    face-project-dim  <solid> swap >>dimension ;
+
+: erase-old-adjacencies ( solid -- solid )
+    erase-solid-corners
+    [ dup [ erase-face-touching-corners erase-face-adjacent-faces drop ] each ]
+    change-faces ;
+
+: point-inside-or-on-face? ( face v -- ? ) 
+    [ halfspace>> ] dip point-inside-or-on-halfspace?  ;
+
+: point-inside-face? ( face v -- ? ) 
+    [ halfspace>> ] dip  point-inside-halfspace? ;
+
+: point-inside-solid? ( solid point -- ? )
+    [ faces>> ] dip [ point-inside-face? ] curry  all?   ; inline
+
+: point-inside-or-on-solid? ( solid point -- ? )
+    [ faces>> ] dip [ point-inside-or-on-face? ] curry  all?   ; inline
+
+: unvalid-adjacencies ( solid -- solid )  
+    erase-old-adjacencies f >>adjacencies-valid erase-silhouettes ;
+
+: add-face ( solid face -- solid ) 
+    suffix-face unvalid-adjacencies ; 
+
+: cut-solid ( solid halfspace -- solid )    <face> add-face ; 
+
+: slice-solid ( solid face  -- solid1 solid2 )
+    [ [ clone ] bi@ flip-face add-face 
+    [ "/outer/" append ] change-name  ] 2keep
+    add-face [ "/inner/" append ] change-name ;
+
+! -------------
+
+
+: add-silhouette ( solid  -- solid )
+   dup 
+   ! find-adjacencies 
+   faces>> { } 
+   [ face-silhouette append ] reduce
+   [ ] filter 
+   <solid> 
+        swap >>faces
+        over dimension>> >>dimension 
+        over name>> " silhouette " append 
+                 pv> number>string append 
+        >>name
+     !   ensure-adjacencies
+   suffix-silhouettes ; inline
+
+: find-silhouettes ( solid -- solid )
+    { } >>silhouettes 
+    dup dimension>> [ [ add-silhouette ] with-pv ] each ;
+
+: ensure-silhouettes ( solid  -- solid )
+    dup  silhouettes>>  [ f = ] all?
+    [ find-silhouettes  ]  when ; 
+
+! ------------
+
+: corner-added? ( solid corner -- ? ) 
+    ! add corner to solid if it is inside solid
+    [ ] 
+    [ point-inside-or-on-solid? ] 
+    [ swap corners>> member? not ] 
+    2tri and
+    [ suffix-corner drop t ] [ 2drop f ] if ;
+
+: process-corner ( solid faces corner -- )
+    swapd 
+    [ corner-added? ] keep swap ! test if corner is inside solid
+    [ update-adjacent-faces ] 
+    [ 2drop ]
+    if ;
+
+: compute-intersection ( solid faces -- )
+    dup faces-intersection
+    dup f = [ 3drop ] [ process-corner ]  if ;
+
+: test-faces-combinaisons ( solid n -- )
+    [ dup faces>> ] dip among   
+    [ compute-intersection ] with each ;
+
+: compute-adjacencies ( solid -- solid )
+    dup dimension>> [ >= ] curry 
+    [ keep swap ] curry MAX-FACE-PER-CORNER swap
+    [ [ test-faces-combinaisons ] 2keep 1- ] [ ] while drop ;
+
+: find-adjacencies ( solid -- solid ) 
+    erase-old-adjacencies   
+    compute-adjacencies
+    filter-real-faces 
+    t >>adjacencies-valid ;
+
+: ensure-adjacencies ( solid -- solid ) 
+    dup adjacencies-valid>> 
+    [ find-adjacencies ] unless 
+    ensure-silhouettes
+    ;
+
+: (non-empty-solid?) ( solid -- ? ) [ dimension>> ] [ corners>> length ] bi < ;
+: non-empty-solid? ( solid -- ? )   ensure-adjacencies (non-empty-solid?) ;
+
+: compare-corners-roughly ( corner corner -- ? )
+    2drop t ;
+! : remove-inner-faces ( -- ) ;
+: face-project ( array face -- seq )
+    backface? 
+  [ 2drop f ]
+    [   [ enlight-projection ] 
+        [ initiate-solid-from-face ]
+        [ intersections-into-faces ]  tri
+        >>faces
+        swap >>color        
+    ]    if ;
+
+: solid-project ( lights ambient solid -- solids )
+  ensure-adjacencies
+    [ color>> ] [ faces>> ] bi [ 3array  ] dip
+    [ face-project ] with map 
+    [ ] filter 
+    [ ensure-adjacencies ] map
+;
+
+: (solid-move) ( solid v move -- solid ) 
+   curry [ map ] curry 
+   [ dup faces>> ] dip call drop  
+   unvalid-adjacencies ; inline
+
+: solid-translate ( solid v -- solid ) [ face-translate ] (solid-move) ; 
+: solid-transform ( solid m -- solid ) [ face-transform ] (solid-move) ; 
+
+: find-corner-in-silhouette ( s1 s2 -- elt bool )
+    pv> swap silhouettes>> nth     
+    swap corners>>
+    [ point-inside-solid? ] with find swap ;
+
+: valid-face-for-order ( solid point -- face )
+    [ point-inside-face? not ] 
+    [ drop face-orientation  0 = not ] 2bi and ;
+
+: check-orientation ( s1 s2 pt -- int )
+    [ nip faces>> ] dip
+    [ valid-face-for-order ] curry find swap
+    [ face-orientation ] [ drop f ] if ;
+
+: (order-solid) ( s1 s2 -- int )
+    2dup find-corner-in-silhouette
+    [ check-orientation ] [ 3drop f ] if ;
+
+: order-solid ( solid solid  -- i ) 
+    2dup (order-solid)
+    [ 2nip ]
+    [   swap (order-solid)
+        [ neg ] [ f ] if*
+    ] if* ;
+
+: subtract ( solid1 solid2 -- solids )
+    faces>> swap clone ensure-adjacencies ensure-silhouettes  
+    [ swap slice-solid drop ]  curry map
+    [ non-empty-solid? ] filter
+    [ ensure-adjacencies ] map
+; inline
+
+! --------------------------------------------------------------
+! space 
+! --------------------------------------------------------------
+TUPLE: space name dimension solids ambient-color lights ;
+: <space> ( -- space )      space new ;
+: suffix-solids ( space solid -- space ) [ suffix ] curry change-solids ; inline
+: suffix-lights ( space light -- space ) [ suffix ] curry change-lights ; inline
+: clear-space-solids ( space -- space )     f >>solids ;
+
+: space-ensure-solids ( space -- space ) 
+    [ [ ensure-adjacencies ] map ] change-solids ;
+: eliminate-empty-solids ( space -- space ) 
+    [ [ non-empty-solid? ] filter ] change-solids ;
+
+: projected-space ( space solids -- space ) 
+   swap dimension>> 1-  <space>    swap >>dimension    swap  >>solids ;
+
+: get-silhouette ( solid -- silhouette )    silhouettes>> pv> swap nth ;
+: solid= ( solid solid -- ? )               [ corners>> ]  bi@ = ;
+
+: space-apply ( space m quot -- space ) 
+        curry [ map ] curry [ dup solids>> ] dip
+        [ call ] [ drop ] recover drop ;
+: space-transform ( space m -- space ) [ solid-transform ] space-apply ;
+: space-translate ( space v -- space ) [ solid-translate ] space-apply ; 
+
+: describe-space ( space -- ) 
+    solids>>  [  [ corners>>  [ pprint ] each ] [ name>> . ] bi ] each ;
+
+: clip-solid ( solid solid -- solids )
+    [ ]
+    [ solid= not ]
+    [ order-solid -1 = ] 2tri 
+    and
+    [ get-silhouette subtract ] 
+    [  drop 1array ] 
+    if 
+    
+    ;
+
+: (solids-silhouette-subtract) ( solids solid -- solids ) 
+     [  clip-solid append ] curry { } -rot each ; inline
+
+: solids-silhouette-subtract ( solids i solid -- solids )
+! solids is an array of 1 solid arrays
+      [ (solids-silhouette-subtract) ] curry map-but 
+; inline 
+
+: remove-hidden-solids ( space -- space ) 
+! We must include each solid in a sequence because during substration 
+! a solid can be divided in more than on solid
+    [ 
+        [ [ 1array ] map ] 
+        [ length ] 
+        [ ] 
+        tri     
+        [ solids-silhouette-subtract ] 2each
+        { } [ append ] reduce 
+    ] change-solids
+    eliminate-empty-solids ! TODO include into change-solids
+;
+
+: space-project ( space i -- space )
+  [
+  [ clone  
+    remove-hidden-solids? [ remove-hidden-solids ] when
+    dup 
+        [ solids>> ] 
+        [ lights>> ] 
+        [ ambient-color>> ]  tri 
+        [ rot solid-project ] 2curry 
+        map 
+        [ append ] { } -rot each 
+        ! TODO project lights
+        projected-space 
+      ! remove-inner-faces 
+      ! 
+      eliminate-empty-solids
+    ] with-pv 
+    ] [ 3drop <space> ] recover
+    ; inline
+
+: middle-of-space ( space -- point )
+    solids>> [ corners>> ] map concat
+    [ [ ] [ v+ ] map-reduce ] [ length ] bi v/n
+;
+
+! --------------------------------------------------------------
+! 3D rendering
+! --------------------------------------------------------------
+
+: face-reference ( face -- halfspace point vect )
+       [ halfspace>> ] 
+       [ touching-corners>> first ] 
+       [ touching-corners>> second ] tri 
+       over v-
+;
+
+: theta ( v halfspace point vect -- v x )
+   [ [ over ] dip v- ] dip    
+   [ cross dup norm >float ]
+   [ v. >float ]  
+   2bi 
+   fatan2
+   -rot v. 
+   0 < [ neg ] when
+;
+
+: ordered-face-points ( face -- corners )  
+    [ touching-corners>> 1 head ] 
+    [ touching-corners>> 1 tail ] 
+    [ face-reference [ theta ] 3curry ]         tri
+    { } map>assoc    sort-values keys 
+    append
+    ; inline
+
+: point->GL  ( point -- )   gl-vertex ;
+: points->GL ( array -- )   do-cycle [ point->GL ] each ;
+
+: face->GL ( face color -- )
+   [ ordered-face-points ] dip
+   [ first3 1.0 glColor4d GL_POLYGON [ [ point->GL  ] each ] do-state ] curry
+   [  0 0 0 1 glColor4d GL_LINE_LOOP [ [ point->GL  ] each ] do-state ]
+   bi
+   ; inline
+
+: solid->GL ( solid -- )    
+    [ faces>> ]    
+    [ color>> ] bi
+    [ face->GL ] curry each ; inline
+
+: space->GL ( space -- )
+    solids>>
+    [ solid->GL ] each ;
+
+
+
+
+
diff --git a/extra/adsoda/adsoda.tests b/extra/adsoda/adsoda.tests
new file mode 100755
index 0000000000..f0b0c54953
--- /dev/null
+++ b/extra/adsoda/adsoda.tests
@@ -0,0 +1,147 @@
+! : init-4D-demo ( -- space )
+! OK
+! espace de dimension 4 et de couleur 0,3 0.3 0.3
+<space> 
+    4 >>dimension
+    { 0.3 0.3 0.3 } >>ambient-color
+    { 100 150 100  150 100 150 100 150 } "4cube1" 4cube suffix-solids
+   { 160 180  160 180 160 180 160 180 } "4cube2" 4cube suffix-solids
+    <light>
+        { -100 -100 -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+! ;
+! : init-3D-demo ( -- space )
+! OK
+! espace de dimension 4 et de couleur 0,3 0.3 0.3
+<space> 
+    3 >>dimension
+    { 0.3 0.3 0.3 } >>ambient-color
+    { 100 150 100  150 100 150 } "3cube1" 3cube suffix-solids
+  !  { -150 -10  -150 -10 -150 -10 -150 -10 } "4cube2" 4cube suffix-solids
+    <light>
+        { -100 -100 -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+! ;
+
+
+: s1 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "s1" >>name
+    { 1 1 1 } >>color
+    { 1 -1 -5 } cut-solid 
+    { -1 -1 -21 } cut-solid 
+    { -1 0 -12 } cut-solid 
+    { 1 2 16 } cut-solid
+;
+: solid1 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "solid1" >>name
+    { 1 -1 -5 } cut-solid 
+    { -1 -1 -21 } cut-solid 
+    { -1 0 -12 } cut-solid 
+    { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+;
+: solid2 ( -- solid )
+    <solid> 
+    2 >>dimension
+    "solid2" >>name
+    { -1 1 -10 } cut-solid 
+    { -1 -1 -28 } cut-solid 
+    { 1 0 13 } cut-solid 
+ !   { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+;
+
+: solid3 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid3" >>name
+    { 1 1 1 } >>color
+    { 1 0 16 } cut-solid 
+    { -1 0 -36 } cut-solid 
+    { 0 1 1 } cut-solid 
+    { 0 -1  -17 } cut-solid 
+ !   { 1 2 16 } cut-solid
+    ensure-adjacencies
+    
+
+;
+
+: solid4 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid4" >>name
+    { 1 1 1 } >>color
+    { 1 0 21 } cut-solid 
+    { -1 0 -36 } cut-solid 
+    { 0 1 1 } cut-solid 
+    { 0 -1  -17 } cut-solid 
+    ensure-adjacencies
+    
+;
+
+: solid5 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid5" >>name
+    { 1 1 1 } >>color
+    { 1 0 6 } cut-solid 
+    { -1 0 -17 } cut-solid 
+    { 0 1 17 } cut-solid 
+    { 0 -1  -19 } cut-solid 
+    ensure-adjacencies
+    
+;
+
+: solid7 ( -- solid )
+      <solid> 
+    2 >>dimension
+    "solid7" >>name
+    { 1 1 1 } >>color
+    { 1 0 38 } cut-solid 
+    { 1 -5 -66 } cut-solid 
+    { -2 1 -75 } cut-solid
+    ensure-adjacencies
+    
+;
+
+: solid6s ( -- seq )
+  solid3 clone solid2 clone subtract
+;
+
+: space1 ( -- space )
+    <space>
+        2 >>dimension
+     !    solid3 suffix-solids
+        solid1 suffix-solids
+        solid2 suffix-solids
+    !   solid6s [ suffix-solids ] each 
+        solid4 suffix-solids
+     !   solid5 suffix-solids
+        solid7 suffix-solids
+        { 1 1 1 } >>ambient-color
+            <light>
+        { -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+;
+
+: space2 ( -- space )
+    <space>
+        4 >>dimension
+       ! 4cube suffix-solids
+        { 1 1 1 } >>ambient-color
+            <light>
+        { -100 -100 } >>position
+        { 0.2 0.7 0.1 } >>color
+        suffix-lights
+
+       ;
+
diff --git a/extra/adsoda/authors.txt b/extra/adsoda/authors.txt
new file mode 100755
index 0000000000..856f3b05fc
--- /dev/null
+++ b/extra/adsoda/authors.txt
@@ -0,0 +1,2 @@
+Jeff Bigot
+Greg Ferrar
\ No newline at end of file
diff --git a/extra/adsoda/combinators/authors.txt b/extra/adsoda/combinators/authors.txt
new file mode 100755
index 0000000000..e7f4cdeb7c
--- /dev/null
+++ b/extra/adsoda/combinators/authors.txt
@@ -0,0 +1 @@
+JF Bigot, after Greg Ferrar
\ No newline at end of file
diff --git a/extra/adsoda/combinators/combinators-docs.factor b/extra/adsoda/combinators/combinators-docs.factor
new file mode 100755
index 0000000000..e6bb52ac24
--- /dev/null
+++ b/extra/adsoda/combinators/combinators-docs.factor
@@ -0,0 +1,39 @@
+! Copyright (C) 2008 Your name.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays help.markup help.syntax kernel sequences ;
+IN: adsoda.combinators
+
+HELP: among
+{ $values
+     { "array" array } { "n" null }
+     { "array" array }
+}
+{ $description "returns an array containings every possibilities of n choices among a given sequence" } ;
+
+HELP: columnize
+{ $values
+     { "array" array }
+     { "array" array }
+}
+{ $description "flip a sequence into a sequence of 1 element sequences" } ;
+
+HELP: concat-nth
+{ $values
+     { "seq1" sequence } { "seq2" sequence }
+     { "seq" sequence }
+}
+{ $description "merges 2 sequences of sequences appending corresponding elements" } ;
+
+HELP: do-cycle
+{ $values
+     { "array" array }
+     { "array" array }
+}
+{ $description "Copy the first element at the end of the sequence in order to close the cycle." } ;
+
+
+ARTICLE: "adsoda.combinators" "adsoda.combinators"
+{ $vocab-link "adsoda.combinators" }
+;
+
+ABOUT: "adsoda.combinators"
diff --git a/extra/adsoda/combinators/combinators-tests.factor b/extra/adsoda/combinators/combinators-tests.factor
new file mode 100755
index 0000000000..6796929a74
--- /dev/null
+++ b/extra/adsoda/combinators/combinators-tests.factor
@@ -0,0 +1,11 @@
+USING: adsoda.combinators
+sequences
+    tools.test 
+ ;
+
+IN: adsoda.combinators.tests
+
+
+[ { "atoto" "b" "ctoto" } ] [ { "a" "b" "c" } 1 [ "toto" append ] map-but ] 
+    unit-test
+
diff --git a/extra/adsoda/combinators/combinators.factor b/extra/adsoda/combinators/combinators.factor
new file mode 100755
index 0000000000..5838c30698
--- /dev/null
+++ b/extra/adsoda/combinators/combinators.factor
@@ -0,0 +1,44 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: kernel arrays sequences fry math combinators ;
+
+IN: adsoda.combinators
+
+! : (combinations) ( seq -- seq ) [ 1 tail ] dip combinations ; 
+
+! : prefix-each [ prefix ] curry map ; inline
+
+! : combinations ( seq n -- seqs )
+!    {
+!        { [ dup 0 = ] [ 2drop { { } } ] }
+!        { [ over empty? ] [ 2drop { } ] }
+!        { [ t ] [ 
+!            [ [ 1- (combinations) ] [ drop first ] 2bi prefix-each ]
+!            [ (combinations) ] 2bi append
+!        ] }
+!    } cond ;
+
+: columnize ( array -- array ) [ 1array ] map ; inline
+
+: among ( array n -- array )
+    2dup swap length 
+    {
+        { [ over 1 = ] [ 3drop columnize ] }
+        { [ over 0 = ] [ 2drop 2drop { } ] }
+        { [ 2dup < ] [ 2drop [ 1 cut ] dip  
+                         [ 1- among [ append ] with map  ] 
+                         [ among append ] 2bi
+                       ] }
+        { [ 2dup = ] [ 3drop 1array ] }
+        { [ 2dup > ] [ 2drop 2drop {  } ] } 
+    } cond
+;
+
+: concat-nth ( seq1 seq2 -- seq )  [ nth append ] curry map-index ;
+
+: do-cycle   ( array -- array )   dup first suffix ;
+
+: map-but ( seq i quot -- seq )
+    ! quot : ( seq x -- seq )
+    '[ _ = [ @ ] unless ] map-index ; inline
+
diff --git a/extra/adsoda/solution2/solution2.factor b/extra/adsoda/solution2/solution2.factor
new file mode 100755
index 0000000000..3e0648128d
--- /dev/null
+++ b/extra/adsoda/solution2/solution2.factor
@@ -0,0 +1,126 @@
+USING: kernel
+sequences
+namespaces
+
+math
+math.vectors
+math.matrices
+;
+IN: adsoda.solution2
+
+! -------------------
+! correctif solution
+! ---------------
+SYMBOL: matrix
+: MIN-VAL-adsoda ( -- x ) 0.00000001
+! 0.000000000001 
+;
+
+: zero? ( x -- ? ) 
+    abs MIN-VAL-adsoda <
+;
+
+! [ number>string string>number ] map 
+
+: with-matrix ( matrix quot -- )
+    [ swap matrix set call matrix get ] with-scope ; inline
+
+: nth-row ( row# -- seq ) matrix get nth ;
+
+: change-row ( row# quot -- seq ) ! row# quot -- | quot: seq -- seq )
+    matrix get swap change-nth ; inline
+
+: exchange-rows ( row# row# -- ) matrix get exchange ;
+
+: rows ( -- n ) matrix get length ;
+
+: cols ( -- n ) 0 nth-row length ;
+
+: skip ( i seq quot -- n )
+    over [ find-from drop ] dip length or ; inline
+
+: first-col ( row# -- n )
+    #! First non-zero column
+    0 swap nth-row [ zero? not ] skip ;
+
+: clear-scale ( col# pivot-row i-row -- n )
+    [ over ] dip nth dup zero? [
+        3drop 0
+    ] [
+        [ nth dup zero? ] dip swap [
+            2drop 0
+        ] [
+            swap / neg
+        ] if
+    ] if ;
+
+: (clear-col) ( col# pivot-row i -- )
+    [ [ clear-scale ] 2keep [ n*v ] dip v+ ] change-row ;
+
+: rows-from ( row# -- slice )
+    rows dup <slice> ;
+
+: clear-col ( col# row# rows -- )
+    [ nth-row ] dip [ [ 2dup ] dip (clear-col) ] each 2drop ;
+
+: do-row ( exchange-with row# -- )
+    [ exchange-rows ] keep
+    [ first-col ] keep
+    dup 1+ rows-from clear-col ;
+
+: find-row ( row# quot -- i elt )
+    [ rows-from ] dip find ; inline
+
+: pivot-row ( col# row# -- n )
+    [ dupd nth-row nth zero? not ] find-row 2nip ;
+
+: (echelon) ( col# row# -- )
+    over cols < over rows < and [
+        2dup pivot-row [ over do-row 1+ ] when*
+        [ 1+ ] dip (echelon)
+    ] [
+        2drop
+    ] if ;
+
+: echelon ( matrix -- matrix' )
+    [ 0 0 (echelon) ] with-matrix ;
+
+: nonzero-rows ( matrix -- matrix' )
+    [ [ zero? ] all? not ] filter ;
+
+: null/rank ( matrix -- null rank )
+    echelon dup length swap nonzero-rows length [ - ] keep ;
+
+: leading ( seq -- n elt ) [ zero? not ] find ;
+
+: reduced ( matrix' -- matrix'' )
+    [
+        rows <reversed> [
+            dup nth-row leading drop
+            dup [ swap dup clear-col ] [ 2drop ] if
+        ] each
+    ] with-matrix ;
+
+: basis-vector ( row col# -- )
+    [ clone ] dip
+    [ swap nth neg recip ] 2keep
+    [ 0 spin set-nth ] 2keep
+    [ n*v ] dip
+    matrix get set-nth ;
+
+: nullspace ( matrix -- seq )
+    echelon reduced dup empty? [
+        dup first length identity-matrix [
+            [
+                dup leading drop
+                dup [ basis-vector ] [ 2drop ] if
+            ] each
+        ] with-matrix flip nonzero-rows
+    ] unless ;
+
+: 1-pivots ( matrix -- matrix )
+    [ dup leading nip [ recip v*n ] when* ] map ;
+
+: solution ( matrix -- matrix )
+    echelon nonzero-rows reduced 1-pivots ;
+
diff --git a/extra/adsoda/solution2/summary.txt b/extra/adsoda/solution2/summary.txt
new file mode 100755
index 0000000000..a25a451f3c
--- /dev/null
+++ b/extra/adsoda/solution2/summary.txt
@@ -0,0 +1 @@
+A modification of solution to approximate solutions
\ No newline at end of file
diff --git a/extra/adsoda/summary.txt b/extra/adsoda/summary.txt
new file mode 100755
index 0000000000..ee666bc787
--- /dev/null
+++ b/extra/adsoda/summary.txt
@@ -0,0 +1 @@
+ADSODA : Arbitrary-Dimensional Solid Object Display Algorithm
\ No newline at end of file
diff --git a/extra/adsoda/tags.txt b/extra/adsoda/tags.txt
new file mode 100755
index 0000000000..6e25b2f44b
--- /dev/null
+++ b/extra/adsoda/tags.txt
@@ -0,0 +1 @@
+adsoda 4D viewer
\ No newline at end of file
diff --git a/extra/adsoda/tools/authors.txt b/extra/adsoda/tools/authors.txt
new file mode 100755
index 0000000000..a6a96933f4
--- /dev/null
+++ b/extra/adsoda/tools/authors.txt
@@ -0,0 +1 @@
+Jeff Bigot
\ No newline at end of file
diff --git a/extra/adsoda/tools/tools-docs.factor b/extra/adsoda/tools/tools-docs.factor
new file mode 100755
index 0000000000..6fb617a0c4
--- /dev/null
+++ b/extra/adsoda/tools/tools-docs.factor
@@ -0,0 +1,76 @@
+! Copyright (C) 2008 Jeff Bigot.
+! See http://factorcode.org/license.txt for BSD license.
+USING: arrays help.markup help.syntax kernel sequences ;
+IN: adsoda.tools
+
+HELP: 3cube
+{ $values 
+    { "array" "array" } { "name" "name" } 
+    { "solid" "solid" } 
+}
+{ $description "array : xmin xmax ymin ymax zmin zmax" 
+"\n returns a 3D solid with given limits"
+} ;
+
+HELP: 4cube
+{ $values 
+    { "array" "array" } { "name" "name" } 
+    { "solid" "solid" } 
+}
+{ $description "array : xmin xmax ymin ymax zmin zmax wmin wmax"  
+"\n returns a 4D solid with given limits"
+} ;
+
+
+HELP: coord-max
+{ $values
+     { "x" null } { "array" array }
+     { "array" array }
+}
+{ $description "" } ;
+
+HELP: coord-min
+{ $values
+     { "x" null } { "array" array }
+     { "array" array }
+}
+{ $description "" } ;
+
+HELP: equation-system-for-normal
+{ $values
+     { "points" "a list of n points" }
+     { "matrix" "matrix" }
+}
+{ $description "From a list of points, return the matrix" 
+"to solve in order to find the vector normal to the plan defined by the points" } 
+;
+
+HELP: normal-vector
+{ $values
+     { "points" "a list of n points" }
+     { "v" "a vector" }
+}
+{ $description "From a list of points, returns the vector normal to the plan defined by the points" 
+"\nWith n points, creates n-1 vectors and then find a vector orthogonal to every others"
+"\n returns { f } if a normal vector can not be found" } 
+;
+
+HELP: points-to-hyperplane
+{ $values
+     { "points" "a list of n points" }
+     { "hyperplane" "an hyperplane equation" }
+}
+{ $description "From a list of points, returns the equation of the hyperplan"
+"\n Finds a normal vector and then translate it so that it includes one of the points"
+
+} 
+;
+
+ARTICLE: "adsoda.tools" "adsoda.tools"
+{ $vocab-link "adsoda.tools" }
+"\nTools to help in building an " { $vocab-link "adsoda" } "-space"
+;
+
+ABOUT: "adsoda.tools"
+
+
diff --git a/extra/adsoda/tools/tools-tests.factor b/extra/adsoda/tools/tools-tests.factor
new file mode 100755
index 0000000000..bb5419417c
--- /dev/null
+++ b/extra/adsoda/tools/tools-tests.factor
@@ -0,0 +1,14 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: 
+adsoda.tools
+tools.test
+;
+
+IN: adsoda.tools.tests
+
+
+ [ { 1 0 } ] [ { { 0 0 } { 0 1 } }  normal-vector    ] unit-test
+ [ f ] [ { { 0 0 } { 0 0 } }  normal-vector    ] unit-test
+
+ [  { 1/2 1/2 1+1/2 }  ] [ { { 1 2 } { 2 1 } }  points-to-hyperplane ] unit-test
diff --git a/extra/adsoda/tools/tools.factor b/extra/adsoda/tools/tools.factor
new file mode 100755
index 0000000000..efa3a55013
--- /dev/null
+++ b/extra/adsoda/tools/tools.factor
@@ -0,0 +1,145 @@
+! Copyright (C) 2008 Jeff Bigot
+! See http://factorcode.org/license.txt for BSD license.
+USING: 
+kernel
+sequences
+math
+accessors
+adsoda
+math.vectors 
+math.matrices
+bunny.model
+io.encodings.ascii
+io.files
+sequences.deep
+combinators
+adsoda.combinators
+fry
+io.files.temp
+grouping
+;
+
+IN: adsoda.tools
+
+
+
+
+
+! ---------------------------------
+: coord-min ( x array -- array )  swap suffix  ;
+: coord-max ( x array -- array )  swap neg suffix ;
+
+: 4cube ( array name -- solid )
+! array : xmin xmax ymin ymax zmin zmax wmin wmax
+    <solid> 
+    4 >>dimension
+    swap >>name
+    swap
+    { 
+       [ { 1 0 0 0 } coord-min ] [ { -1 0 0 0 } coord-max ] 
+       [ { 0 1 0 0 } coord-min ] [ { 0 -1 0 0 } coord-max ]
+       [ { 0 0 1 0 } coord-min ] [ { 0 0 -1 0 } coord-max ] 
+       [ { 0 0 0 1 } coord-min ] [ { 0 0 0 -1 } coord-max ]
+    }
+    [ curry call ] 2map 
+    [ cut-solid ] each 
+    ensure-adjacencies
+    
+; inline
+
+: 3cube ( array name -- solid )
+! array : xmin xmax ymin ymax zmin zmax wmin wmax
+    <solid> 
+    3 >>dimension
+    swap >>name
+    swap
+    { 
+       [ { 1 0 0 } coord-min ] [ { -1 0 0 } coord-max ] 
+       [ { 0 1 0 } coord-min ] [ { 0 -1 0 } coord-max ]
+       [ { 0 0 1 } coord-min ] [ { 0 0 -1 } coord-max ] 
+    }
+    [ curry call ] 2map 
+    [ cut-solid ] each 
+    ensure-adjacencies
+    
+; inline
+
+
+: equation-system-for-normal ( points -- matrix )
+    unclip [ v- 0 suffix ] curry map
+    dup first [ drop 1 ] map     suffix
+;
+
+: normal-vector ( points -- v ) 
+    equation-system-for-normal
+    intersect-hyperplanes ;
+
+: points-to-hyperplane ( points -- hyperplane )
+    [ normal-vector 0 suffix ] [ first ] bi
+    translate ;
+
+: refs-to-points ( points faces -- faces )
+   [ swap [ nth 10 v*n { 100 100 100 } v+ ] curry map    ] with map
+;
+! V{ { 0.1 0.2 } { 1.1 1.3 } } V{ { 1 0 } { 0 1 } }
+! V{ { { 1.1 1.3 } { 0.1 0.2 } } { { 0.1 0.2 } { 1.1 1.3 } } }
+
+: ply-model-path ( -- path )
+
+! "bun_zipper.ply" 
+"screw2.ply"
+temp-file 
+;
+
+: read-bunny-model ( -- v )
+ply-model-path ascii [  parse-model ] with-file-reader
+
+refs-to-points
+;
+
+: 3points-to-normal ( seq -- v )
+    unclip [ v- ] curry map first2 cross normalize
+;
+: 2-faces-to-prism ( seq seq -- seq )
+  2dup
+    [ do-cycle 2 clump ] bi@ concat-nth  !  3 faces rectangulaires
+    swap prefix
+    swap prefix
+;    
+
+: Xpoints-to-prisme ( seq height -- cube )
+    ! from 3 points gives a list of faces representing a cube of height "height"
+    ! and of based on the three points
+    ! a face is a group of 3 or mode points.   
+    [ dup dup  3points-to-normal ] dip 
+    v*n [ v+ ] curry map ! 2 eme face triangulaire 
+    2-faces-to-prism  
+
+! [ dup number? [ 1 + ] when ] deep-map
+! dup keep 
+;
+
+
+: Xpoints-to-plane4D ( seq x y -- 4Dplane )
+    ! from 3 points gives a list of faces representing a cube in 4th dim
+    ! from x to y (height = y-x)
+    ! and of based on the X points
+    ! a face is a group of 3 or mode points.   
+    '[ [ [ _ suffix ] map ] [ [ _ suffix ] map ] bi ] call
+    2-faces-to-prism
+;
+
+: 3pointsfaces-to-3Dsolidfaces ( seq -- seq )
+    [ 1 Xpoints-to-prisme [ 100 110 Xpoints-to-plane4D ] map concat ] map 
+
+;
+
+: test-figure ( -- solid )
+    <solid> 
+    2 >>dimension
+    { 1 -1 -5 } cut-solid 
+    { -1 -1 -21 } cut-solid 
+    { -1 0 -12 } cut-solid 
+    { 1 2 16 } cut-solid
+;
+