changeset 0:bf79fb79ee13

Initial Mercurial check in.
author samer
date Tue, 17 Jan 2012 17:50:20 +0000
parents
children 5df24c91468d
files COPYING INSTALL LICENSE README TODO archive/jslab-scheme-1.1.tar.gz archive/jslab-src-1.1.tar.gz build.xml build/samer/applet/ButtonsApplet.class build/samer/applet/ConsoleApplet.class build/samer/applet/JApplet$1$1.class build/samer/applet/JApplet$1.class build/samer/applet/JApplet.class build/samer/applet/JAppletShell$VContainer.class build/samer/applet/JAppletShell.class build/samer/applet/Sierpinski$1.class build/samer/applet/Sierpinski.class build/samer/applet/WindowApplet.class build/samer/audio/AudioSink$Util.class build/samer/audio/AudioSink.class build/samer/audio/AudioSource$Util.class build/samer/audio/AudioSource.class build/samer/audio/FileSink$1.class build/samer/audio/FileSink$2.class build/samer/audio/FileSink.class build/samer/audio/FileSource$1.class build/samer/audio/FileSource$2.class build/samer/audio/FileSource$3.class build/samer/audio/FileSource$FileSourceViewer.class build/samer/audio/FileSource.class build/samer/audio/LineSink$1.class build/samer/audio/LineSink$2.class build/samer/audio/LineSink$Writer.class build/samer/audio/LineSink.class build/samer/audio/LineSource$1.class build/samer/audio/LineSource$2.class build/samer/audio/LineSource$Reader.class build/samer/audio/LineSource.class build/samer/audio/VLine$LineViewer.class build/samer/audio/VLine.class build/samer/core/Agent$Registry.class build/samer/core/Agent.class build/samer/core/CompoundAgent.class build/samer/core/DefaultShell.class build/samer/core/DoubleFormat.class build/samer/core/Environment$1.class build/samer/core/Environment$2$1.class build/samer/core/Environment$2.class build/samer/core/Environment$Autocoder.class build/samer/core/Environment$Binding.class build/samer/core/Environment$Codec.class build/samer/core/Environment$CompoundIterator.class build/samer/core/Environment$Datum.class build/samer/core/Environment$Iterator.class build/samer/core/Environment.class build/samer/core/Node.class build/samer/core/NumberSink.class build/samer/core/NumberViewer.class build/samer/core/Registry.class build/samer/core/Saveable.class build/samer/core/Saver.class build/samer/core/Shell$1.class build/samer/core/Shell$2.class build/samer/core/Shell$3.class build/samer/core/Shell$Dialog.class build/samer/core/Shell$Interface.class build/samer/core/Shell$Interpreter.class build/samer/core/Shell$ViewerWindowListener$1.class build/samer/core/Shell$ViewerWindowListener.class build/samer/core/Shell$Window.class build/samer/core/Shell.class build/samer/core/Variable.class build/samer/core/Viewable$1.class build/samer/core/Viewable$Vector.class build/samer/core/Viewable.class build/samer/core/Viewer.class build/samer/core/X$1.class build/samer/core/X$2.class build/samer/core/X$3.class build/samer/core/X$4.class build/samer/core/X$5.class build/samer/core/X$6.class build/samer/core/X$7.class build/samer/core/X$BaseCodec.class build/samer/core/X.class build/samer/core/shells/AWTShell$VContainer.class build/samer/core/shells/AWTShell.class build/samer/core/shells/BevelWindow.class build/samer/core/shells/DesktopShell$1.class build/samer/core/shells/DesktopShell$VContainer.class build/samer/core/shells/DesktopShell.class build/samer/core/shells/SwingShell$1.class build/samer/core/shells/SwingShell$VContainer.class build/samer/core/shells/SwingShell.class build/samer/core/types/DoubleModel.class build/samer/core/types/VBoolean.class build/samer/core/types/VColor.class build/samer/core/types/VDouble.class build/samer/core/types/VFile.class build/samer/core/types/VInteger.class build/samer/core/types/VParameter.class build/samer/core/types/VRectangle.class build/samer/core/types/VString.class build/samer/core/util/AgentAdapter.class build/samer/core/util/BaseViewer.class build/samer/core/util/ConsoleEnvironment$Texton.class build/samer/core/util/ConsoleEnvironment.class build/samer/core/util/DefaultViewer.class build/samer/core/util/FileFilter.class build/samer/core/util/FilteredEnvironment.class build/samer/core/util/HashMap$1.class build/samer/core/util/HashMap$Entry.class build/samer/core/util/HashMap.class build/samer/core/util/IMap.class build/samer/core/util/LinearMap.class build/samer/core/util/LogMap.class build/samer/core/util/MouseRetarget.class build/samer/core/util/Properties$1.class build/samer/core/util/Properties$Property.class build/samer/core/util/Properties.class build/samer/core/util/StackLayout.class build/samer/core/util/Tools.class build/samer/core/util/UserEnvironment$1.class build/samer/core/util/UserEnvironment$2.class build/samer/core/util/UserEnvironment$3.class build/samer/core/util/UserEnvironment$4.class build/samer/core/util/UserEnvironment$5.class build/samer/core/util/UserEnvironment$Gluon.class build/samer/core/util/UserEnvironment$Thingy.class build/samer/core/util/UserEnvironment.class build/samer/core/util/VLayout.class build/samer/core/util/VMap$Adjuster.class build/samer/core/util/VMap.class build/samer/core/util/VariableViewer.class build/samer/core/util/heavy/Border$1.class build/samer/core/util/heavy/Border$Base.class build/samer/core/util/heavy/Border$BevelInfo.class build/samer/core/util/heavy/Border$Empty.class build/samer/core/util/heavy/Border$In.class build/samer/core/util/heavy/Border$Interface.class build/samer/core/util/heavy/Border$Null.class build/samer/core/util/heavy/Border$Out.class build/samer/core/util/heavy/Border.class build/samer/core/util/heavy/Borders$AbstractBorder.class build/samer/core/util/heavy/Borders$CompoundBorder.class build/samer/core/util/heavy/Borders$EllipticalBorder.class build/samer/core/util/heavy/Borders$EmptyBorder.class build/samer/core/util/heavy/Borders$LoweredBevelBorder.class build/samer/core/util/heavy/Borders$ParentBgBorder.class build/samer/core/util/heavy/Borders$RaisedBevelBorder.class build/samer/core/util/heavy/Borders$RoundedBorder.class build/samer/core/util/heavy/Borders$SimpleBorder.class build/samer/core/util/heavy/Borders.class build/samer/core/util/heavy/ButtonBar.class build/samer/core/util/heavy/CommandField$Handler.class build/samer/core/util/heavy/CommandField.class build/samer/core/util/heavy/Console$OutputStream.class build/samer/core/util/heavy/Console$Writer.class build/samer/core/util/heavy/Console.class build/samer/core/util/heavy/Dialog$1.class build/samer/core/util/heavy/Dialog.class build/samer/core/util/heavy/Frame.class build/samer/core/util/heavy/JPanel.class build/samer/core/util/heavy/MenuBuilder.class build/samer/core/util/heavy/Meter$1.class build/samer/core/util/heavy/Meter.class build/samer/core/util/heavy/PopupHandler.class build/samer/core/util/heavy/TextualNumberViewer.class build/samer/core/util/heavy/VCanvas$1.class build/samer/core/util/heavy/VCanvas.class build/samer/core/util/heavy/VPanel.class build/samer/core/util/shell/AgentManager$1.class build/samer/core/util/shell/AgentManager.class build/samer/core/util/shell/AppShellBase.class build/samer/core/util/shell/ViewableManager$1.class build/samer/core/util/shell/ViewableManager$2.class build/samer/core/util/shell/ViewableManager$3.class build/samer/core/util/shell/ViewableManager$VblEntry.class build/samer/core/util/shell/ViewableManager$ViewerContainer.class build/samer/core/util/shell/ViewableManager$VwrEntry.class build/samer/core/util/shell/ViewableManager.class build/samer/core/util/swing/ButtonBar.class build/samer/core/util/swing/CommandField$Handler.class build/samer/core/util/swing/CommandField.class build/samer/core/util/swing/Console$OutputStream.class build/samer/core/util/swing/Console$Writer.class build/samer/core/util/swing/Console.class build/samer/core/util/swing/DarkMetalTheme.class build/samer/core/util/swing/Dialog.class build/samer/core/util/swing/DynamicPopupHandler.class build/samer/core/util/swing/Frame.class build/samer/core/util/swing/InternalFrame$1.class build/samer/core/util/swing/InternalFrame.class build/samer/core/util/swing/LED.class build/samer/core/util/swing/MenuBuilder.class build/samer/core/util/swing/Meter$1.class build/samer/core/util/swing/Meter.class build/samer/core/util/swing/PopupHandler.class build/samer/core/util/swing/SilkyMetalTheme.class build/samer/core/util/swing/TextualNumberViewer.class build/samer/core/util/swing/VCanvas$1.class build/samer/core/util/swing/VCanvas.class build/samer/core/util/swing/VContainerBase.class build/samer/core/util/swing/VPanel.class build/samer/core/viewers/BooleanViewer.class build/samer/core/viewers/ColorButton.class build/samer/core/viewers/ColorSwatch.class build/samer/core/viewers/ColorViewer.class build/samer/core/viewers/DoubleViewer.class build/samer/core/viewers/FileViewer.class build/samer/core/viewers/IntegerViewer.class build/samer/core/viewers/NumberViewer.class build/samer/core/viewers/ParameterViewer.class build/samer/core/viewers/StringViewer.class build/samer/core/viewers/swing/BooleanViewer.class build/samer/core/viewers/swing/ColorButton.class build/samer/core/viewers/swing/ColorChooserViewer$ColorModelAdapter.class build/samer/core/viewers/swing/ColorChooserViewer.class build/samer/core/viewers/swing/ColorSwatch.class build/samer/core/viewers/swing/ColorViewer.class build/samer/core/viewers/swing/DoubleViewer$1.class build/samer/core/viewers/swing/DoubleViewer.class build/samer/core/viewers/swing/FileChooserViewer.class build/samer/core/viewers/swing/FileViewer.class build/samer/core/viewers/swing/IntegerViewer.class build/samer/core/viewers/swing/NumberViewer.class build/samer/core/viewers/swing/ParameterViewer.class build/samer/core/viewers/swing/StringViewer.class build/samer/core/viewers/swing/Swatch.class build/samer/functions/Abs.class build/samer/functions/Add.class build/samer/functions/Atanh.class build/samer/functions/BiLaplacian$1.class build/samer/functions/BiLaplacian.class build/samer/functions/BiLaplacianBlend$1.class build/samer/functions/BiLaplacianBlend.class build/samer/functions/CauchyInfomax.class build/samer/functions/CompoundFunction$1.class build/samer/functions/CompoundFunction$2.class build/samer/functions/CompoundFunction.class build/samer/functions/Exp.class build/samer/functions/ExponentialSquashing.class build/samer/functions/Gamma.class build/samer/functions/HalfSquare.class build/samer/functions/Hamming.class build/samer/functions/Hanning.class build/samer/functions/HybridFunction.class build/samer/functions/Log.class build/samer/functions/LogAbs.class build/samer/functions/LogCauchy.class build/samer/functions/LogCosh$1.class build/samer/functions/LogCosh.class build/samer/functions/LogGenCosh$1.class build/samer/functions/LogGenCosh.class build/samer/functions/LogGenExp$1.class build/samer/functions/LogGenExp$2.class build/samer/functions/LogGenExp.class build/samer/functions/LogGenExp2$1.class build/samer/functions/LogGenExp2$2.class build/samer/functions/LogGenExp2$3.class build/samer/functions/LogGenExp2.class build/samer/functions/LogisiticInfomax.class build/samer/functions/LogisticHyperplane.class build/samer/functions/Negate.class build/samer/functions/Power.class build/samer/functions/Quadratic.class build/samer/functions/RaleighLogPrior$1.class build/samer/functions/RaleighLogPrior.class build/samer/functions/Reciprocal.class build/samer/functions/Scale.class build/samer/functions/ScaledFunction.class build/samer/functions/Sgn.class build/samer/functions/SparseExponential$1.class build/samer/functions/SparseExponential.class build/samer/functions/Sqrt.class build/samer/functions/Square.class build/samer/functions/Step.class build/samer/functions/Tanh$1.class build/samer/functions/Tanh.class build/samer/functions/ThresholdLog.class build/samer/functions/WinnerTakeAll.class build/samer/j3d/Axes.class build/samer/j3d/FPS.class build/samer/j3d/ImmediateRenderer.class build/samer/j3d/MatrixPointArray$1.class build/samer/j3d/MatrixPointArray.class build/samer/j3d/MatrixPointArrayAlpha$1.class build/samer/j3d/MatrixPointArrayAlpha.class build/samer/j3d/MatrixPointArrayRef$1.class build/samer/j3d/MatrixPointArrayRef.class build/samer/j3d/MatrixPoints4D$1.class build/samer/j3d/MatrixPoints4D.class build/samer/j3d/MonoView.class build/samer/j3d/MorphPoints$MorphBehavior.class build/samer/j3d/MorphPoints.class build/samer/j3d/PatchArray$1.class build/samer/j3d/PatchArray.class build/samer/j3d/PatchArrayAlpha$1.class build/samer/j3d/PatchArrayAlpha.class build/samer/j3d/Patches$1.class build/samer/j3d/Patches.class build/samer/j3d/PatchesAlpha$1.class build/samer/j3d/PatchesAlpha.class build/samer/j3d/Points3D$1.class build/samer/j3d/Points3D.class build/samer/j3d/Points3DAlpha$1.class build/samer/j3d/Points3DAlpha.class build/samer/j3d/Points3DRef$1.class build/samer/j3d/Points3DRef.class build/samer/j3d/Points4D$1.class build/samer/j3d/Points4D.class build/samer/j3d/Root.class build/samer/j3d/StereoView.class build/samer/j3d/Util.class build/samer/j3d/ViewBase.class build/samer/j3d/ViewGroup.class build/samer/maths/ClippedDivide.class build/samer/maths/ComplexVector.class build/samer/maths/Constant.class build/samer/maths/Difference.class build/samer/maths/Function.class build/samer/maths/FunctionMap.class build/samer/maths/FunctionOfGenerator.class build/samer/maths/FunctionOfVector.class build/samer/maths/FunctionPlotter$1.class build/samer/maths/FunctionPlotter$FunctionIterator.class build/samer/maths/FunctionPlotter.class build/samer/maths/Generator.class build/samer/maths/Identity.class build/samer/maths/IntArrayEditor.class build/samer/maths/IteratorImageSource.class build/samer/maths/LineTrace.class build/samer/maths/Linear.class build/samer/maths/Mat.class build/samer/maths/MatEditor.class build/samer/maths/Mathx.class build/samer/maths/Matrix$1$1.class build/samer/maths/Matrix$1$2.class build/samer/maths/Matrix$1.class build/samer/maths/Matrix$Column$1.class build/samer/maths/Matrix$Column.class build/samer/maths/Matrix$Row$1.class build/samer/maths/Matrix$Row.class build/samer/maths/Matrix$Slice.class build/samer/maths/Matrix$Vbl.class build/samer/maths/Matrix.class build/samer/maths/MatrixAgent.class build/samer/maths/MatrixImage.class build/samer/maths/MatrixImageSource.class build/samer/maths/MatrixImageSourceF.class build/samer/maths/MatrixPanel$Field.class build/samer/maths/MatrixPanel.class build/samer/maths/MatrixPlotter$1.class build/samer/maths/MatrixPlotter.class build/samer/maths/MatrixTImageSource.class build/samer/maths/MatrixTImageSourceF.class build/samer/maths/MatrixTimesVector.class build/samer/maths/MatrixTransposeTimesVector.class build/samer/maths/Neg.class build/samer/maths/Ops$1.class build/samer/maths/Ops$2.class build/samer/maths/Ops$3.class build/samer/maths/Ops$4.class build/samer/maths/Ops$5.class build/samer/maths/Ops$6.class build/samer/maths/Ops$7.class build/samer/maths/Ops$8.class build/samer/maths/Ops$9.class build/samer/maths/Ops$ArrayCopy.class build/samer/maths/Ops$IteratorCopy.class build/samer/maths/Ops.class build/samer/maths/Parameter.class build/samer/maths/Probe.class build/samer/maths/Product.class build/samer/maths/RowColumn.class build/samer/maths/SparseMatrix.class build/samer/maths/Sum.class build/samer/maths/VFunction$1.class build/samer/maths/VFunction$2.class build/samer/maths/VFunction.class build/samer/maths/VGenerator$UI.class build/samer/maths/VGenerator.class build/samer/maths/VVector$1.class build/samer/maths/VVector$2.class build/samer/maths/VVector.class build/samer/maths/Vec$ForArray$InputIterator.class build/samer/maths/Vec$ForArray$Iterator.class build/samer/maths/Vec$ForArray.class build/samer/maths/Vec$InputIterator.class build/samer/maths/Vec$Iterator.class build/samer/maths/Vec.class build/samer/maths/VectorEditor.class build/samer/maths/VectorFunctionOfVector.class build/samer/maths/VectorPlotter.class build/samer/maths/VectorPlusEqualsVector.class build/samer/maths/VectorTimesEqualsScalar.class build/samer/maths/VectorTrace.class build/samer/maths/VectorTraceObs.class build/samer/maths/Zero.class build/samer/maths/opt/AbsXFConvergence.class build/samer/maths/opt/Condition.class build/samer/maths/opt/ConjGrad.class build/samer/maths/opt/ConstrainedConjGrad.class build/samer/maths/opt/ConstrainedGillMurray.class build/samer/maths/opt/ConstrainedMinimiser.class build/samer/maths/opt/Constraints$Factory.class build/samer/maths/opt/Constraints.class build/samer/maths/opt/CubicLineSearch.class build/samer/maths/opt/Datum.class build/samer/maths/opt/Functionx.class build/samer/maths/opt/GConvergence.class build/samer/maths/opt/GillMurray.class build/samer/maths/opt/MinimiserBase$1.class build/samer/maths/opt/MinimiserBase$2.class build/samer/maths/opt/MinimiserBase$3.class build/samer/maths/opt/MinimiserBase$4.class build/samer/maths/opt/MinimiserBase$5.class build/samer/maths/opt/MinimiserBase$LSCondition$1.class build/samer/maths/opt/MinimiserBase$LSCondition.class build/samer/maths/opt/MinimiserBase.class build/samer/maths/opt/PolynomialLineSearch.class build/samer/maths/opt/Positivity$1.class build/samer/maths/opt/Positivity$2.class build/samer/maths/opt/Positivity.class build/samer/maths/opt/State.class build/samer/maths/opt/SubspaceFunctionx.class build/samer/maths/opt/UnconstrainedConjGrad$1.class build/samer/maths/opt/UnconstrainedConjGrad.class build/samer/maths/opt/UnconstrainedMinimiser.class build/samer/maths/opt/Util.class build/samer/maths/opt/XFConvergence.class build/samer/maths/opt/ZeroCrossingSparsity$1.class build/samer/maths/opt/ZeroCrossingSparsity$2.class build/samer/maths/opt/ZeroCrossingSparsity$3.class build/samer/maths/opt/ZeroCrossingSparsity$4.class build/samer/maths/opt/ZeroCrossingSparsity.class build/samer/maths/random/BaseRandom.class build/samer/maths/random/Binary.class build/samer/maths/random/BinaryVec.class build/samer/maths/random/BipolarUniform.class build/samer/maths/random/BoundedHyperbolic.class build/samer/maths/random/BoundedUniform.class build/samer/maths/random/Brownian.class build/samer/maths/random/Cauchy.class build/samer/maths/random/Exponential.class build/samer/maths/random/Gaussian.class build/samer/maths/random/GeneralisedExponential.class build/samer/maths/random/GeneralisedLaplacian.class build/samer/maths/random/Laplacian.class build/samer/maths/random/Logistic.class build/samer/maths/random/Mixture.class build/samer/maths/random/MixtureVec.class build/samer/maths/random/NormalisedGaussian.class build/samer/maths/random/PosteriorSampler.class build/samer/maths/random/PowerLaw.class build/samer/maths/random/Raleigh.class build/samer/maths/random/RectifiedCauchy.class build/samer/maths/random/RectifiedGaussian.class build/samer/maths/random/RectifiedLogistic.class build/samer/maths/random/SparseMixture.class build/samer/maths/random/Ternary.class build/samer/maths/random/Uniform.class build/samer/mds/CorrelationTask.class build/samer/mds/CovarianceTask.class build/samer/mds/DistanceTask.class build/samer/mds/Euclidean.class build/samer/mds/GeometricFilter.class build/samer/mds/MDS$Metric.class build/samer/mds/MDS$SamerStress.class build/samer/mds/MDS$Stress.class build/samer/mds/MDS.class build/samer/mds/MDSBase.class build/samer/mds/Manhatten.class build/samer/mds/MatrixPointViewer2.class build/samer/mds/Minkowski.class build/samer/mds/NewMDS$Laplacian.class build/samer/mds/NewMDS$Stress.class build/samer/mds/NewMDS.class build/samer/mds/ProximityFilter.class build/samer/midi/MidiRecorder.class build/samer/midi/MidiRecorderBase.class build/samer/midi/MidiSynth$1.class build/samer/midi/MidiSynth$Editor.class build/samer/midi/MidiSynth.class build/samer/midi/MidiWithAftertouch.class build/samer/models/AlignedGaussian$1.class build/samer/models/AlignedGaussian.class build/samer/models/BatchedTrainer.class build/samer/models/Covariance.class build/samer/models/DiffScaler$1.class build/samer/models/DiffScaler$OffsetTrainer.class build/samer/models/DiffScaler$ScaleTrainer.class build/samer/models/DiffScaler$TensionedTrainer.class build/samer/models/DiffScaler$Trainer.class build/samer/models/DiffScaler.class build/samer/models/Edge.class build/samer/models/GaussianStats.class build/samer/models/GaussianStatsOnline.class build/samer/models/GeneralisedExponential$1.class build/samer/models/GeneralisedExponential$Trainer.class build/samer/models/GeneralisedExponential.class build/samer/models/ICA$1.class build/samer/models/ICA$NewtonTrainer.class build/samer/models/ICA$ON2DecayWhenActive.class build/samer/models/ICA$ON2Trainer.class build/samer/models/ICA$ON3Trainer.class build/samer/models/ICA.class build/samer/models/ICAScalerSync.class build/samer/models/ICAWithScaler$DifferentialTrainer.class build/samer/models/ICAWithScaler$ScalerTrainer.class build/samer/models/ICAWithScaler.class build/samer/models/IIDPrior$1.class build/samer/models/IIDPrior.class build/samer/models/JointHistogramBase.class build/samer/models/MOGModel$1.class build/samer/models/MOGModel$2.class build/samer/models/MOGModel.class build/samer/models/MOGVector$1.class build/samer/models/MOGVector$2.class build/samer/models/MOGVector$PDF.class build/samer/models/MOGVector.class build/samer/models/MatrixTrainer.class build/samer/models/Mixture$Trainer.class build/samer/models/Mixture.class build/samer/models/Model$Trainer.class build/samer/models/Model.class build/samer/models/NoisyICA$1.class build/samer/models/NoisyICA$2.class build/samer/models/NoisyICA$3.class build/samer/models/NoisyICA.class build/samer/models/Scaler$1.class build/samer/models/Scaler$OffsetTrainer.class build/samer/models/Scaler$ScaleTrainer.class build/samer/models/Scaler$Trainer.class build/samer/models/Scaler.class build/samer/models/SignalHistogram.class build/samer/models/SmoothGeneralisedExponential$1.class build/samer/models/SmoothGeneralisedExponential.class build/samer/models/SparseICA$ON2Trainer.class build/samer/models/SparseICA$ON3Trainer.class build/samer/models/SparseICA.class build/samer/models/VarianceICA$1.class build/samer/models/VarianceICA$2.class build/samer/models/VarianceICA$3.class build/samer/models/VarianceICA.class build/samer/silk/JavaProcedure.class build/samer/silk/SchemeList$Iterator.class build/samer/silk/SchemeList.class build/samer/silk/SilkCompleter.class build/samer/silk/SilkFunction.class build/samer/silk/SilkObserver.class build/samer/silk/SilkTask.class build/samer/silk/Terminal$Transfer.class build/samer/silk/Terminal.class build/samer/tools/AnonymousTask.class build/samer/tools/ArrayImageSource.class build/samer/tools/ArrayVImageSource.class build/samer/tools/ColorRamp.class build/samer/tools/CompoundTask$Iterator.class build/samer/tools/CompoundTask$TaskLink.class build/samer/tools/CompoundTask.class build/samer/tools/ImageSourceBase.class build/samer/tools/ImageTrace.class build/samer/tools/ImageTraceBase.class build/samer/tools/ImageVTrace.class build/samer/tools/ImageViewer$1.class build/samer/tools/ImageViewer.class build/samer/tools/NamedTask.class build/samer/tools/NullTask.class build/samer/tools/Plotter$Pen.class build/samer/tools/Plotter.class build/samer/tools/RThread$Kill.class build/samer/tools/RThread$UI.class build/samer/tools/RThread.class build/samer/tools/RateSchedule.class build/samer/tools/Renderer$Fill.class build/samer/tools/Renderer$Fill3D.class build/samer/tools/Renderer$Line.class build/samer/tools/Renderer$Steps.class build/samer/tools/Renderer.class build/samer/tools/SafeTask.class build/samer/tools/ScatterPlot.class build/samer/tools/SignalTrace.class build/samer/tools/SubrateTask.class build/samer/tools/SwitchTask.class build/samer/tools/Task.class build/samer/tools/Trace.class build/samer/tools/vec2.class build/samer/units/Clicker.class build/samer/units/DoubleToStream.class build/samer/units/DoubleWriter.class build/samer/units/EnergyOperator.class build/samer/units/FFT.class build/samer/units/FFTVector$1.class build/samer/units/FFTVector$2.class build/samer/units/FFTVector$3.class build/samer/units/FFTVector$4.class build/samer/units/FFTVector.class build/samer/units/FIRFilter.class build/samer/units/Filter.class build/samer/units/FilterVector.class build/samer/units/FilteredGenerator.class build/samer/units/GenerateDouble.class build/samer/units/GenerateVector.class build/samer/units/Histogram$Equaliser.class build/samer/units/Histogram.class build/samer/units/IIRFilter.class build/samer/units/JointHistogram.class build/samer/units/Latch.class build/samer/units/LineIn.class build/samer/units/LineOut.class build/samer/units/Matrices.class build/samer/units/MousePosition.class build/samer/units/NoisyLinearSource.class build/samer/units/OnsetMap.class build/samer/units/Oscillator$1.class build/samer/units/Oscillator.class build/samer/units/OverlapAndAdd.class build/samer/units/RescaledIFT.class build/samer/units/SignalWindow$1.class build/samer/units/SignalWindow.class build/samer/units/SpectralFIR.class build/samer/units/Stacker.class build/samer/units/Stacker2.class build/samer/units/StreamToDouble.class build/samer/units/StreamToVec.class build/samer/units/SumFnVec.class build/samer/units/Trigger.class build/samer/units/VecToDouble.class build/samer/units/VecToStream$ArrayObjectWriter.class build/samer/units/VecToStream$IteratorFloatWriter.class build/samer/units/VecToStream.class build/samer/units/VecWriter.class build/samer/units/Wavetable.class examples/README examples/sockets/args examples/sockets/obj examples/sockets/ostream.scm examples/sockets/recv.silk examples/sound/midi/4notes.mat examples/sound/midi/args examples/sound/midi/args.alt examples/sound/midi/args.audio examples/sound/midi/args.old examples/sound/midi/basis.mat examples/sound/midi/diatonic.mat examples/sound/midi/midisynth examples/sound/midi/midisynth0 examples/sound/midi/midisynth1 examples/sound/midi/midisynth2 examples/sound/midi/midisynth4 examples/sound/midi/nice.mat examples/sound/midi/nice2.mat examples/sound/midi/pentatonic.mat examples/sound/midi/plinky.args examples/sound/midi/plinky.scm examples/sound/midi/plinky.silk examples/sound/midi/scale2.mat examples/sound/midi/scale3.mat examples/sound/midi/scale4.mat examples/sound/midi/synth.scm examples/sound/midi/thirds-2.mat examples/sound/midi/thirds.mat examples/sound/midi/walking_zither2 examples/sound/midi/walking_zither3 examples/sound/midi/walking_zither4 examples/sound/sampled/ICABundle.java examples/sound/sampled/Spectro.java examples/sound/sampled/args examples/sound/sampled/args.alt examples/sound/sampled/args.old examples/sound/sampled/audio-player/args examples/sound/sampled/audio-player/args.old examples/sound/sampled/audio-player/diffScaler.genexp.alpha examples/sound/sampled/audio-player/diffScaler.w examples/sound/sampled/audio-player/test.scm examples/sound/sampled/audioio.scm examples/sound/sampled/diffscaler.w examples/sound/sampled/firfilter.scm examples/sound/sampled/lineio.scm examples/sound/sampled/modulate.scm examples/sound/sampled/osc.scm examples/sound/sampled/play.scm examples/sound/sampled/play2.scm examples/sound/sampled/powspec.scm examples/sound/sampled/rec.scm examples/sound/sampled/record.scm examples/sound/sampled/specfilter.scm examples/sound/sampled/stacker.scm examples/sound/sampled/stacker2.scm examples/util/Cat.java examples/util/ClassInfo.java examples/util/DumpProperties.java examples/util/FontInfo.java lib/JScheme-license.txt lib/README lib/Tritonus-license.txt lib/libreadline-java-README local/javacc local/schemerc.scm local/silk local/swing local/swingrc.scm local/user.props src/samer/applet/ButtonsApplet.java src/samer/applet/CVS/Entries src/samer/applet/CVS/Repository src/samer/applet/CVS/Root src/samer/applet/CVS/Template src/samer/applet/ConsoleApplet.java src/samer/applet/JApplet.java src/samer/applet/JAppletShell.java src/samer/applet/Sierpinski.java src/samer/applet/WindowApplet.java src/samer/audio/AudioSink.java src/samer/audio/AudioSource.java src/samer/audio/CVS/Entries src/samer/audio/CVS/Repository src/samer/audio/CVS/Root src/samer/audio/CVS/Template src/samer/audio/FileSink.java src/samer/audio/FileSource.java src/samer/audio/LineSink.java src/samer/audio/LineSource.java src/samer/audio/VLine.java src/samer/core_/Agent.java src/samer/core_/CVS/Entries src/samer/core_/CVS/Repository src/samer/core_/CVS/Root src/samer/core_/CVS/Template src/samer/core_/CompoundAgent.java src/samer/core_/DoubleFormat.java src/samer/core_/Environment.java src/samer/core_/Node.java src/samer/core_/NumberSink.java src/samer/core_/NumberViewer.java src/samer/core_/Registry.java src/samer/core_/Saveable.java src/samer/core_/Saver.java src/samer/core_/Shell.java src/samer/core_/Variable.java src/samer/core_/Viewable.java src/samer/core_/Viewer.java src/samer/core_/X.java src/samer/core_/shells/AWTShell.java src/samer/core_/shells/CVS/Entries src/samer/core_/shells/CVS/Repository src/samer/core_/shells/CVS/Root src/samer/core_/shells/CVS/Template src/samer/core_/shells/DesktopShell.java src/samer/core_/shells/SwingShell.java src/samer/core_/types/CVS/Entries src/samer/core_/types/CVS/Repository src/samer/core_/types/CVS/Root src/samer/core_/types/CVS/Template src/samer/core_/types/DoubleModel.java src/samer/core_/types/VBoolean.java src/samer/core_/types/VColor.java src/samer/core_/types/VDouble.java src/samer/core_/types/VFile.java src/samer/core_/types/VInteger.java src/samer/core_/types/VParameter.java src/samer/core_/types/VRectangle.java src/samer/core_/types/VString.java src/samer/core_/util/AgentAdapter.java src/samer/core_/util/BaseViewer.java src/samer/core_/util/CVS/Entries src/samer/core_/util/CVS/Repository src/samer/core_/util/CVS/Root src/samer/core_/util/CVS/Template src/samer/core_/util/ConsoleEnvironment.java src/samer/core_/util/DefaultViewer.java src/samer/core_/util/FileFilter.java src/samer/core_/util/FilteredEnvironment.java src/samer/core_/util/HashMap.java src/samer/core_/util/IMap.java src/samer/core_/util/LinearMap.java src/samer/core_/util/LogMap.java src/samer/core_/util/MouseRetarget.java src/samer/core_/util/Properties.java src/samer/core_/util/StackLayout.java src/samer/core_/util/Tools.java src/samer/core_/util/UserEnvironment.java src/samer/core_/util/VLayout.java src/samer/core_/util/VMap.java src/samer/core_/util/VariableViewer.java src/samer/core_/util/heavy/Border.java src/samer/core_/util/heavy/Borders.java src/samer/core_/util/heavy/ButtonBar.java src/samer/core_/util/heavy/CVS/Entries src/samer/core_/util/heavy/CVS/Repository src/samer/core_/util/heavy/CVS/Root src/samer/core_/util/heavy/CVS/Template src/samer/core_/util/heavy/CommandField.java src/samer/core_/util/heavy/Console.java src/samer/core_/util/heavy/Dialog.java src/samer/core_/util/heavy/Frame.java src/samer/core_/util/heavy/JPanel.java src/samer/core_/util/heavy/MenuBuilder.java src/samer/core_/util/heavy/Meter.java src/samer/core_/util/heavy/NumberViewer.java.not src/samer/core_/util/heavy/PopupHandler.java src/samer/core_/util/heavy/TextualNumberViewer.java src/samer/core_/util/heavy/VCanvas.java src/samer/core_/util/heavy/VPanel.java src/samer/core_/util/shell/AgentManager.java src/samer/core_/util/shell/AppShellBase.java src/samer/core_/util/shell/CVS/Entries src/samer/core_/util/shell/CVS/Repository src/samer/core_/util/shell/CVS/Root src/samer/core_/util/shell/CVS/Template src/samer/core_/util/shell/ViewableManager.java src/samer/core_/util/swing/ButtonBar.java src/samer/core_/util/swing/CVS/Entries src/samer/core_/util/swing/CVS/Repository src/samer/core_/util/swing/CVS/Root src/samer/core_/util/swing/CVS/Template src/samer/core_/util/swing/CommandField.java src/samer/core_/util/swing/Console.java src/samer/core_/util/swing/DarkMetalTheme.java src/samer/core_/util/swing/Dialog.java src/samer/core_/util/swing/DynamicPopupHandler.java src/samer/core_/util/swing/Frame.java src/samer/core_/util/swing/InternalFrame.java src/samer/core_/util/swing/LED.java src/samer/core_/util/swing/MenuBuilder.java src/samer/core_/util/swing/Meter.java src/samer/core_/util/swing/PopupHandler.java src/samer/core_/util/swing/SilkyMetalTheme.java src/samer/core_/util/swing/TextualNumberViewer.java src/samer/core_/util/swing/VCanvas.java src/samer/core_/util/swing/VContainerBase.java src/samer/core_/util/swing/VPanel.java src/samer/core_/viewers/BooleanViewer.java src/samer/core_/viewers/CVS/Entries src/samer/core_/viewers/CVS/Repository src/samer/core_/viewers/CVS/Root src/samer/core_/viewers/CVS/Template src/samer/core_/viewers/ColorButton.java src/samer/core_/viewers/ColorSwatch.java src/samer/core_/viewers/ColorViewer.java src/samer/core_/viewers/DoubleViewer.java src/samer/core_/viewers/FileViewer.java src/samer/core_/viewers/IntegerViewer.java src/samer/core_/viewers/NumberViewer.java src/samer/core_/viewers/ParameterViewer.java src/samer/core_/viewers/StringViewer.java src/samer/core_/viewers/swing/BooleanViewer.java src/samer/core_/viewers/swing/CVS/Entries src/samer/core_/viewers/swing/CVS/Repository src/samer/core_/viewers/swing/CVS/Root src/samer/core_/viewers/swing/CVS/Template src/samer/core_/viewers/swing/ColorButton.java src/samer/core_/viewers/swing/ColorChooserViewer.java src/samer/core_/viewers/swing/ColorViewer.java src/samer/core_/viewers/swing/DoubleViewer.java src/samer/core_/viewers/swing/FileChooserViewer.java src/samer/core_/viewers/swing/FileViewer.java src/samer/core_/viewers/swing/IntegerViewer.java src/samer/core_/viewers/swing/NumberViewer.java src/samer/core_/viewers/swing/ParameterViewer.java src/samer/core_/viewers/swing/StringViewer.java src/samer/functions/Abs.java src/samer/functions/Add.java src/samer/functions/Atanh.java src/samer/functions/BiLaplacian.java src/samer/functions/BiLaplacianBlend.java src/samer/functions/CVS/Entries src/samer/functions/CVS/Repository src/samer/functions/CVS/Root src/samer/functions/CVS/Template src/samer/functions/CauchyInfomax.java src/samer/functions/CompoundFunction.java src/samer/functions/Exp.java src/samer/functions/ExponentialSquashing.java src/samer/functions/Gamma.java src/samer/functions/HalfSquare.java src/samer/functions/Hamming.java src/samer/functions/Hanning.java src/samer/functions/HybridFunction.java src/samer/functions/Log.java src/samer/functions/LogAbs.java src/samer/functions/LogCauchy.java src/samer/functions/LogCosh.java src/samer/functions/LogGenCosh.java src/samer/functions/LogGenExp.java src/samer/functions/LogGenExp2.java src/samer/functions/LogisiticInfomax.java src/samer/functions/LogisticHyperplane.java src/samer/functions/Negate.java src/samer/functions/Power.java src/samer/functions/Quadratic.java src/samer/functions/RaleighLogPrior.java src/samer/functions/Reciprocal.java src/samer/functions/Scale.java src/samer/functions/ScaledFunction.java src/samer/functions/Sgn.java src/samer/functions/SparseExponential.java src/samer/functions/Sqrt.java src/samer/functions/Square.java src/samer/functions/Step.java src/samer/functions/Tanh.java src/samer/functions/ThresholdLog.java src/samer/functions/WinnerTakeAll.java src/samer/j3d/Axes.java src/samer/j3d/CVS/Entries src/samer/j3d/CVS/Repository src/samer/j3d/CVS/Root src/samer/j3d/CVS/Template src/samer/j3d/FPS.java src/samer/j3d/ImmediateRenderer.java src/samer/j3d/J3DViewer.java.not src/samer/j3d/J3DViewerImmediate.java.not src/samer/j3d/J3DViewerMorph.java.not src/samer/j3d/MatrixPointArray.java src/samer/j3d/MatrixPointArrayAlpha.java src/samer/j3d/MatrixPointArrayRef.java src/samer/j3d/MatrixPoints4D.java src/samer/j3d/MonoView.java src/samer/j3d/MorphPoints.java src/samer/j3d/PatchArray.java src/samer/j3d/PatchArrayAlpha.java src/samer/j3d/Patches.java src/samer/j3d/PatchesAlpha.java src/samer/j3d/Points3D.java src/samer/j3d/Points3DAlpha.java src/samer/j3d/Points3DRef.java src/samer/j3d/Points4D.java src/samer/j3d/Root.java src/samer/j3d/StereoView.java src/samer/j3d/Util.java src/samer/j3d/ViewBase.java src/samer/j3d/ViewGroup.java src/samer/maths/CVS/Entries src/samer/maths/CVS/Repository src/samer/maths/CVS/Root src/samer/maths/CVS/Template src/samer/maths/ClippedDivide.java src/samer/maths/ComplexVector.java src/samer/maths/Constant.java src/samer/maths/Difference.java src/samer/maths/Function.java src/samer/maths/FunctionMap.java src/samer/maths/FunctionOfGenerator.java src/samer/maths/FunctionOfVector.java src/samer/maths/FunctionPlotter.java src/samer/maths/Generator.java src/samer/maths/Identity.java src/samer/maths/IntArrayEditor.java src/samer/maths/IteratorImageSource.java src/samer/maths/LineTrace.java src/samer/maths/Linear.java src/samer/maths/Mat.java src/samer/maths/MatEditor.java src/samer/maths/Mathx.java src/samer/maths/Matrix.java src/samer/maths/MatrixAgent.java src/samer/maths/MatrixImage.java src/samer/maths/MatrixImageSource.java src/samer/maths/MatrixImageSourceF.java src/samer/maths/MatrixPanel.java src/samer/maths/MatrixPlotter.java src/samer/maths/MatrixTImageSource.java src/samer/maths/MatrixTImageSourceF.java src/samer/maths/MatrixTimesVector.java src/samer/maths/MatrixTransposeTimesVector.java src/samer/maths/Neg.java src/samer/maths/Ops.java src/samer/maths/Parameter.java src/samer/maths/Probe.java src/samer/maths/Product.java src/samer/maths/RowColumn.java src/samer/maths/SparseMatrix.java src/samer/maths/Sum.java src/samer/maths/VFunction.java src/samer/maths/VGenerator.java src/samer/maths/VVector.java src/samer/maths/Vec.java src/samer/maths/VectorEditor.java src/samer/maths/VectorFunctionOfVector.java src/samer/maths/VectorPlotter.java src/samer/maths/VectorPlusEqualsVector.java src/samer/maths/VectorTimesEqualsScalar.java src/samer/maths/VectorTrace.java src/samer/maths/Zero.java src/samer/maths/opt/AbsXFConvergence.java src/samer/maths/opt/CVS/Entries src/samer/maths/opt/CVS/Repository src/samer/maths/opt/CVS/Root src/samer/maths/opt/CVS/Template src/samer/maths/opt/Condition.java src/samer/maths/opt/ConjGrad.java src/samer/maths/opt/ConstrainedConjGrad.java src/samer/maths/opt/ConstrainedGillMurray.java src/samer/maths/opt/ConstrainedMinimiser.java src/samer/maths/opt/Constraints.java src/samer/maths/opt/CubicLineSearch.java src/samer/maths/opt/Datum.java src/samer/maths/opt/Functionx.java src/samer/maths/opt/GConvergence.java src/samer/maths/opt/GillMurray.java src/samer/maths/opt/MinimiserBase.java src/samer/maths/opt/PolynomialLineSearch.java src/samer/maths/opt/Positivity.java src/samer/maths/opt/State.java src/samer/maths/opt/SubspaceFunctionx.java src/samer/maths/opt/UnconstrainedConjGrad.java src/samer/maths/opt/UnconstrainedMinimiser.java src/samer/maths/opt/Util.java src/samer/maths/opt/XFConvergence.java src/samer/maths/opt/ZeroCrossingSparsity.java src/samer/maths/random/BaseRandom.java src/samer/maths/random/Binary.java src/samer/maths/random/BinaryVec.java src/samer/maths/random/BipolarUniform.java src/samer/maths/random/BoundedHyperbolic.java src/samer/maths/random/BoundedUniform.java src/samer/maths/random/Brownian.java src/samer/maths/random/CVS/Entries src/samer/maths/random/CVS/Repository src/samer/maths/random/CVS/Root src/samer/maths/random/CVS/Template src/samer/maths/random/Cauchy.java src/samer/maths/random/Exponential.java src/samer/maths/random/Gaussian.java src/samer/maths/random/GeneralisedExponential.java src/samer/maths/random/GeneralisedLaplacian.java src/samer/maths/random/Laplacian.java src/samer/maths/random/Logistic.java src/samer/maths/random/Mixture.java src/samer/maths/random/MixtureVec.java src/samer/maths/random/NormalisedGaussian.java src/samer/maths/random/PosteriorSampler.java src/samer/maths/random/PowerLaw.java src/samer/maths/random/Raleigh.java src/samer/maths/random/RectifiedCauchy.java src/samer/maths/random/RectifiedGaussian.java src/samer/maths/random/RectifiedLogistic.java src/samer/maths/random/SparseMixture.java src/samer/maths/random/Ternary.java src/samer/maths/random/Uniform.java src/samer/mds/CVS/Entries src/samer/mds/CVS/Repository src/samer/mds/CVS/Root src/samer/mds/CVS/Template src/samer/mds/CorrelationTask.java src/samer/mds/CovarianceTask.java src/samer/mds/DistanceTask.java src/samer/mds/Euclidean.java src/samer/mds/GeometricFilter.java src/samer/mds/MDS.java src/samer/mds/MDSBase.java src/samer/mds/Manhatten.java src/samer/mds/MatrixBall.java.not src/samer/mds/MatrixPointViewer2.java src/samer/mds/Minkowski.java src/samer/mds/NewMDS.java src/samer/mds/ProximityFilter.java src/samer/midi/CVS/Entries src/samer/midi/CVS/Repository src/samer/midi/CVS/Root src/samer/midi/CVS/Template src/samer/midi/MidiRecorder.java src/samer/midi/MidiRecorderBase.java src/samer/midi/MidiSynth.java src/samer/midi/MidiWithAftertouch.java src/samer/models/#Model.java# src/samer/models/AlignedGaussian.java src/samer/models/BatchedTrainer.java src/samer/models/CVS/Entries src/samer/models/CVS/Repository src/samer/models/CVS/Root src/samer/models/CVS/Template src/samer/models/Covariance.java src/samer/models/DiffScaler.java src/samer/models/GaussianStats.java src/samer/models/GaussianStatsOnline.java src/samer/models/GeneralisedExponential.java src/samer/models/ICA.java src/samer/models/ICAScalerSync.java src/samer/models/ICAWithScaler.java src/samer/models/IIDPrior.java src/samer/models/JointHistogramBase.java src/samer/models/MOGModel.java src/samer/models/MOGVector.java src/samer/models/MatrixTrainer.java src/samer/models/Mixture.java src/samer/models/Model.java src/samer/models/NoisyICA.java src/samer/models/Scaler.java src/samer/models/SignalHistogram.java src/samer/models/SmoothGeneralisedExponential.java src/samer/models/SparseICA.java src/samer/models/VarianceICA.java src/samer/models/notyet/CVS/Entries src/samer/models/notyet/CVS/Repository src/samer/models/notyet/CVS/Root src/samer/models/notyet/CVS/Template src/samer/models/notyet/ModelGraph.java src/samer/models/notyet/PCA.java src/samer/silk/CVS/Entries src/samer/silk/CVS/Repository src/samer/silk/CVS/Root src/samer/silk/CVS/Template src/samer/silk/JavaProcedure.java src/samer/silk/SchemeList.java src/samer/silk/SilkCompleter.java src/samer/silk/SilkFunction.java src/samer/silk/SilkObserver.java src/samer/silk/SilkTask.java src/samer/silk/Terminal.java src/samer/tools/AnonymousTask.java src/samer/tools/ArrayImageSource.java src/samer/tools/ArrayVImageSource.java src/samer/tools/CVS/Entries src/samer/tools/CVS/Repository src/samer/tools/CVS/Root src/samer/tools/CVS/Template src/samer/tools/ColorRamp.java src/samer/tools/CompoundTask.java src/samer/tools/ImageSourceBase.java src/samer/tools/ImageTrace.java src/samer/tools/ImageTraceBase.java src/samer/tools/ImageVTrace.java src/samer/tools/ImageViewer.java src/samer/tools/NamedTask.java src/samer/tools/NullTask.java src/samer/tools/Plotter.java src/samer/tools/RThread.java src/samer/tools/RateSchedule.java src/samer/tools/Renderer.java src/samer/tools/SafeTask.java src/samer/tools/ScatterPlot.java src/samer/tools/SignalTrace.java src/samer/tools/SubrateTask.java src/samer/tools/SwitchTask.java src/samer/tools/Task.java src/samer/tools/TaskTrigger.java.not src/samer/tools/Trace.java src/samer/tools/vec2.java src/samer/units/CVS/Entries src/samer/units/CVS/Repository src/samer/units/CVS/Root src/samer/units/CVS/Template src/samer/units/Clicker.java src/samer/units/DoubleToStream.java src/samer/units/DoubleWriter.java src/samer/units/EnergyOperator.java src/samer/units/FFT.java src/samer/units/FFTVector.java src/samer/units/FIRFilter.java src/samer/units/Filter.java src/samer/units/FilterVector.java src/samer/units/FilteredGenerator.java src/samer/units/GenerateDouble.java src/samer/units/GenerateVector.java src/samer/units/Histogram.java src/samer/units/IIRFilter.java src/samer/units/JointHistogram.java src/samer/units/Latch.java src/samer/units/LineIn.java src/samer/units/LineOut.java src/samer/units/Matrices.java src/samer/units/MousePosition.java src/samer/units/NoisyLinearSource.java src/samer/units/OnsetMap.java src/samer/units/Oscillator.java src/samer/units/OverlapAndAdd.java src/samer/units/RescaledIFT.java src/samer/units/SignalWindow.java src/samer/units/SpectralFIR.java src/samer/units/Stacker.java src/samer/units/Stacker2.java src/samer/units/StreamToDouble.java src/samer/units/StreamToVec.java src/samer/units/SumFnVec.java src/samer/units/Trigger.java src/samer/units/VecToDouble.java src/samer/units/VecToStream.java src/samer/units/VecWriter.java src/samer/units/Wavetable.java src/scheme/analysis.scm src/scheme/audio.scm src/scheme/color.scm src/scheme/filelist.scm src/scheme/filter.scm src/scheme/functions.scm src/scheme/genfilter.scm src/scheme/genmodel.scm src/scheme/ica/args src/scheme/ica/run.scm src/scheme/ica/train.scm src/scheme/joints.scm src/scheme/lineout.scm src/scheme/midi.scm src/scheme/modelbase.scm src/scheme/models.scm src/scheme/newica.scm src/scheme/old/audio.scm src/scheme/old/genfilter.scm src/scheme/old/lineout.scm src/scheme/old/shell.scm src/scheme/old/synthesis.scm src/scheme/props.scm src/scheme/readline.scm src/scheme/scheme-client.scm src/scheme/scheme-server.scm src/scheme/shell.scm src/scheme/signals.scm src/scheme/sockets.scm src/scheme/spectro.scm src/scheme/streams.scm src/scheme/synthesis.scm src/scheme/task.scm src/scheme/tools.scm src/scheme/view3d.scm src/scheme/viewables.scm src/scheme/weird.scm
diffstat 1195 files changed, 36009 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/INSTALL	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,146 @@
+I'm afraid the build and install process is not
+very automated as there are a lot of external
+dependencies, and the details will depend on how
+your machine is set up.
+
+In everything that follows, ~ denotes the 
+directory created when you unpack the source
+distribution. It should contain several directories
+including src/ scheme/ and examples/
+
+Building
+--------
+
+There should be a prebuilt samer.jar in ~/lib.
+
+Currently using Ant to manage the build process.
+If you use Ant, make sure you set the ANT_HOME
+and JAVA_HOME environment variables correctly.
+Also, note that the build file build.xml uses
+JIKES and not JAVAC as the compiler as its about
+a million times faster. If you don't have JIKES
+I suggest you get it.
+Otherwise, you will have to comment out that line
+in build.xml.
+anyway, do
+	ant compile
+to complile everything
+	ant docs
+to compile javadocs
+	ant dist
+to make a jar file of all the classes
+
+If you don't want to (or can't) use Ant, then
+you will have to devise some other way of getting
+all the java compiled. You might want to import
+it into whatever IDE you like to use.
+
+Dependencies
+------------
+You need these these packages on your system to
+be able to compile and run everything:
+	JScheme 	- A Scheme interpreter in Java (essential)
+	JAMA		- A matrix package (essential)
+	Java3D	- For 3D graphics (to compile/use samer.j3d package)
+	libreadline-java - much better command line for JScheme (unix only)
+	tritonus - For writing wave files (samer.core.FileSink)
+			and for reading encoding audio like MP3, OGG. May also
+			need javalayer/jogg/jorbis packages too.
+
+This is a summary of jars and what they are needed for
+
+-- minimal to build everything
+		jama.jar
+	-- to build samer.j3d.* package
+		j3daudio.jar
+		j3dcore.jar
+		j3dutils.jar
+		vecmath.jar
+	-- to build samer.silk.* package
+		jscheme.jar
+		libreadline-java.jar
+	-- to build samer.audio.FileSink class
+		tritonus_aos.jar
+		tritonus_share.jar
+-- extra required to read encoded audio at run time
+		javalayer.jar
+		jogg-0.0.5.jar
+		jorbis-0.0.12.jar
+		tritonus_dsp.jar
+		tritonus_jorbis.jar
+		tritonus_mp3.jar
+		tritonus_remaining.jar
+		tritonus_vorbis.jar
+
+These jars or links to these jars need to be in ~/lib
+if you use the supplied build.xml with Ant. They can be
+anywhere if you are prepared to hack around and set up
+your own classpath.
+
+Note that libreadline-java needs a supporting native library
+which you will have to install if you want to use it.
+
+Installing
+----------
+
+This is where the fun starts.
+The first order of business is to decide what the
+CLASSPATH will be. You need the jars as described above,
+and you also need to include either the ~/build
+directory that is populated when everything is
+compiled 'ant compile', or the ~/dist/lib/samer-xxxxxx.jar that is
+produced if you 'ant dist'.
+Or the ~/lib/samer.jar that comes with the distribution.
+
+Then you need to go and look in the ~/local directory.
+There are two executable scripts called silk and swing
+in there (silk.bat and swing.bat for those of you using
+Windows. There are
+also two scheme scripts called silkrc.scm and swingrc.scm.
+The 'silk' script needs to set up the class path and invoke
+JScheme on the 'silkrc.scm' script. You fix up the paths.
+Then link or copy silk to wherever you want to keep it.
+When you run it, you should get a nice Scheme interpreter
+but not much else.
+
+The swingrc.scm script sets up a working environment for
+using the rest of the library, including creating a
+samer.core.shells.SwingShell. You can also decide on various
+things like what Look-and-feel to use, and whether you want
+antialiased graphics. Other properties are loaded
+from ~/local/user.props, but in order to find this file,
+you need to make sure the variable jhome is correctly set
+in silkrc.scm
+
+	
+_____________________________________________________
+Note for windows users:
+
+	Unix file names go like this: ~/something or /usr/local/something/else
+	Paths are colon separated, eg ~/java/lib:/usr/local/java/lib
+	under windows, change / to \ and : to ; eg
+	c:\this\is\a\path;c:\this\is\another
+
+
+Useful References
+-----------------
+
+JScheme (formerly SILK)
+	Current project page: jscheme.sourceforge.net
+	Old version: www.norvig.com/jscheme.html
+
+JAMA: Jama Matrix library
+	http://math.nist.gov/javanumerics/jama/
+
+Java Readline
+
+Javasound
+
+Tritonus (Java sound implementation)
+
+Java3D
+
+Java graphics
+	http://java.sun.com/products/jfc/tsc/articles/painting/index.html
+
+Ant: A build tool (replacement for make)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,5 @@
+This software (jslab-0.1) is distributed under the GNU Public Licence (GPL)
+which is included in the file COPYING, included in the distribution.
+
+The source files still bear a copyright notice from 2000, but this
+will be updated to the new GPL in a subsequent release. 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,65 @@
+*** JSLAB version 0.4
+*** Copyright 2000,2004: Dr. Samer Abdallah 
+*** samer.abdallah@elec.qmul.ac.uk
+
+
+This is a Java class library and a bunch of
+scheme scripts which provide an interactive,
+interpreted environment for doing mathematical
+and signal processing experiments. 
+
+It doesn't really have a name yet - JSLAB just
+stands for Java Scheme Lab (not too catchy eh?)
+and also the top level is still eponymously named.
+It will be changed eventually but that requires 
+changes to nearly every source file and so is
+deferred till the next version.
+
+The core classes can run with or without a GUI. 
+Many (those deriving from samer.core.Viewable)
+can generate a GUI on demand. Generally, if
+you type
+	(expose)
+at the scheme prompt, you will get a window
+containing all the currently registered 
+Viewable objects.
+
+Signal flow is usually handled by a main
+loop managed by an RThread object (see
+samer.tools.RThread and samer.tools.Task)
+In order to build the loop, you register
+Task objects with it (see task.scm). These
+are then run as part of the loop, which can
+be controlled either from the GUI or from
+the scheme prompt. The main Scheme commands
+for this are
+	(addtask <newtask>)	; add a task
+	(pr-tasks)				; list current tasks
+	(start)					; start main loop
+	(stop)					; etc...
+	(task-ref 3)			; get 4th task in list
+	(remove (task-ref 2)); remove 3rd task
+
+Most of the high level stuff is in Scheme, so
+it's best to look in the scheme subdirectory
+for more info.
+
+There are some examples in the examples directory,
+but the only ones likely to work are in
+examples/sound/sampled/
+Even then, you may have some issues to do with
+which mixer (ie sound card) the program tries
+to grab, as I haven't really sorted out a general
+way of allowing the user to decide which mixer
+to use.
+
+
+INSTALLATION:
+See INSTALL.
+There is a pre-built jar in lib/samer.jar
+
+Note: The packages samer.core.* are in a directory
+called 'core_' instead of 'core', because CVS ignores
+any file/directory called 'core'.
+
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TODO	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,168 @@
+Java Framework Wishlist
+=======================
+
+TaskLoop utilities: indefinite, finite 
+	with or without checkpoint()
+	with or without regulation
+
+help facility using a help-map
+
+more flexible REPLs: prompt control etc. (check readline)
+
+Hierarchical viewable namespace. Infact, consolidate viewables
+namespace with Environments. Then have a browser which views an
+Environment. Make Environment viewable?
+
+Similar viewer for tasks: CompoundTask, SubrateTask
+
+Beans?
+Info classes for Units/Models
+
+JBuilder project, debugger
+
+Drag and drop
+
+Tree view of viewables / root environment
+
+Node namespace vs environments
+Special `directories' contain links: Tasks, Viewables, Agents
+
+BeanContext idea
+
+Viewer hints: eg rdonly/rw
+	In object
+	In registry
+
+Allow interpreter to be registered with shell and then used to
+decode commands, string properties etc.
+
+Sort out border usage: get default borders from environment
+(or UIDefaults?) Remove my Border classes.
+
+FileSource GUI for playlist
+
+
+Core
+----
+
+	- individually addressable agents (by name?)
+	- agents container
+	- viewable groups:
+		o grouped by creation time?
+		o by heirarchichal name space?
+	- tree view of name space: viewables, agents etc
+	  tree view or different containers (cf folder view)
+	- consolidate name spaces: Node and Space. (Add Agents?, Tasks?)
+	- viewables attached to or contained within other viewables
+	- Agents attached to viewables: automatically exposed
+	- VDouble viewers: dial, slider
+	- concept of readonly vs editable viewable -> viewer/editor
+	- text readouts on tool tips in many places eg
+		o	text readout of numbers on graphical viewers
+		o	row/column numbers on matrix viewers
+	- cleanup Variable.Model ~ Property ~ DoubleModel
+	- pause mechanism: wait for kerpress in a certain window,
+	  or put up dialog box and wait for ok/cancel
+	- get cancel to work on Variable editors dialogs or
+	  arg input
+	- dialog boxes for messages, questions
+	- fix dialog ownership
+	- combo box type controls: what kind of viewable needs this
+	- Applet shell
+	- control over default viewers chosen by shell
+	- mousepad editor for 2d viewable parameter
+	- Use reflection to build an Agent for any supplied object.
+	  Easy for methods, but what about member objects?
+	- standardise object factories:
+		o parameter passing: name space vs stack vs method parameters
+		o constructor or static factory method
+		o viewers for viewables: what parameters?
+		  where does viewer go: separate window or existing container
+		o creating named objects: put into namespace (Node or Space?)
+
+	- Agent interface: use an object (like an Action) to report commands.
+		This will be a concrete class that provides some or all of
+		o name
+		o description/help (eg for tool-tip)
+		o icon
+		o boolean viewable for toggles
+		o call-back/ runnable for actions? hmm...
+
+
+	StackLayout -> BoxLayout
+	compare Viewables and Views with Models and Views in Swing:
+		Model					Controller						View
+
+		Model					ViewableRepresentaive		Viewer
+	(no defined interface)		(object)					(interface)
+
+Tools
+-----
+
+	- Task management:
+		o Task viewables
+		o Task containers
+		o task name space
+		o task creation, addition to task list
+		o task list as container of tasks ~ draggable?
+	- Tasks in multiple lists: use better container class
+	- colour map editor
+	- JMap/MapAgent ~ review?
+	- synchronised multirate system: several task lists
+	  going at different rates but with properly maintained
+	  synchrony. eg, fastest list is 'master', others are
+	  'slaves' and go at integer submultiples of master rate.
+
+
+
+Maths
+-----
+
+	- viewer/agent for random Generator ~ parser for creation?
+	- Oscilloscope signal viewer
+	- Polytrace viewer: several viewers in one plotter
+	- suites of elementwise operators:
+		zero
+		identity
+		randomise
+
+		shift, reflect
+		transpose
+		addnoise
+		plus, minus, times
+		determinant, norm, trace, min/max
+		elementwise function
+	- signal filters
+	- matrix image source: on the fly reflection / diagonal flip
+	- virtual matrix image source, eg sparse matrix
+	- interactive spline function
+	- Function factory with expression parser
+	- better text based vector/matrix editor ~ not millions of cells
+	- better graphics matrix editor : image editor with selection
+	  and selection operations like move, copy, multiply, flip etc.
+	  also draw line, block, other primitives. (clipboard?)
+	- set vector from function using some map for element to ordinate
+
+
+
+
+	- socket connection: viewable at one end changes, its
+		peer/shadow/mirror receives and update
+	- use for remote vector for connection between units
+	- possible direct connection? unit reads input from stream?
+	- think about streams for connecting units
+	- control over FFT windows
+
+
+Audio
+-----
+	- MidiSynth viewable/viewer: controls program changes
+	  possible note/channel mappings
+	- event based midi driver: define mappings from small
+	  number of triggerable events to channel, note number etc
+	- wave/midi streams: file, sound card, socket etc
+	- wave format conversion objects
+
+
+
+
Binary file archive/jslab-scheme-1.1.tar.gz has changed
Binary file archive/jslab-src-1.1.tar.gz has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/build.xml	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+<project name="samer" default="compile">
+	<property name="src" value="src/"/>
+	<property name="build" value="build/"/>
+	<property name="dist" value="dist/"/>
+	<property name="home" value="/Users/samer"/>
+	<property name="build.sysclasspath" value="ignore"/>
+	<!--
+	<property name="build.compiler" value="jikes"/>
+	-->
+
+	<path id="cp">
+		<fileset dir="${home}/lib/java">
+			<include name="jama.jar"/>
+			<include name="jscheme.jar"/>
+			<include name="libreadline-java.jar"/>
+			<include name="tritonus_aos.jar"/>
+			<include name="tritonus_share.jar"/>
+		</fileset>
+	</path>
+
+	<target name="init">
+		<tstamp/>
+		<mkdir dir="${build}"/>
+	</target>
+	
+	<target name="compile" depends="init">
+		<mkdir dir="${build}"/>
+		<javac srcdir="${src}" destdir="${build}" deprecation="on">
+			<exclude name="samer/models/notyet/**"/>
+			<exclude name="scheme/**"/>
+			<classpath>
+				<path refid="cp"/>
+			</classpath>
+		</javac>
+	</target>
+
+	<target name="dist" depends="compile">
+		<mkdir dir="${dist}/lib"/>
+		<jar jarfile="${dist}/lib/samer-${DSTAMP}.jar" basedir="${build}"/>
+	</target>
+
+	<target name="doc">
+		<mkdir dir="doc/api"/>
+		<javadoc 
+			packagenames="samer.*"
+			excludepackagenames="samer.models.notyet"
+			sourcepath="${src}" destdir="doc/api"
+			author="true" version="true" use="true"
+		/>
+	</target>
+		
+	<target name="clean">
+		<delete dir="${build}"/>
+		<delete dir="${dist}"/>
+		<delete dir="doc/api"/>
+	</target>
+</project>
Binary file build/samer/applet/ButtonsApplet.class has changed
Binary file build/samer/applet/ConsoleApplet.class has changed
Binary file build/samer/applet/JApplet$1$1.class has changed
Binary file build/samer/applet/JApplet$1.class has changed
Binary file build/samer/applet/JApplet.class has changed
Binary file build/samer/applet/JAppletShell$VContainer.class has changed
Binary file build/samer/applet/JAppletShell.class has changed
Binary file build/samer/applet/Sierpinski$1.class has changed
Binary file build/samer/applet/Sierpinski.class has changed
Binary file build/samer/applet/WindowApplet.class has changed
Binary file build/samer/audio/AudioSink$Util.class has changed
Binary file build/samer/audio/AudioSink.class has changed
Binary file build/samer/audio/AudioSource$Util.class has changed
Binary file build/samer/audio/AudioSource.class has changed
Binary file build/samer/audio/FileSink$1.class has changed
Binary file build/samer/audio/FileSink$2.class has changed
Binary file build/samer/audio/FileSink.class has changed
Binary file build/samer/audio/FileSource$1.class has changed
Binary file build/samer/audio/FileSource$2.class has changed
Binary file build/samer/audio/FileSource$3.class has changed
Binary file build/samer/audio/FileSource$FileSourceViewer.class has changed
Binary file build/samer/audio/FileSource.class has changed
Binary file build/samer/audio/LineSink$1.class has changed
Binary file build/samer/audio/LineSink$2.class has changed
Binary file build/samer/audio/LineSink$Writer.class has changed
Binary file build/samer/audio/LineSink.class has changed
Binary file build/samer/audio/LineSource$1.class has changed
Binary file build/samer/audio/LineSource$2.class has changed
Binary file build/samer/audio/LineSource$Reader.class has changed
Binary file build/samer/audio/LineSource.class has changed
Binary file build/samer/audio/VLine$LineViewer.class has changed
Binary file build/samer/audio/VLine.class has changed
Binary file build/samer/core/Agent$Registry.class has changed
Binary file build/samer/core/Agent.class has changed
Binary file build/samer/core/CompoundAgent.class has changed
Binary file build/samer/core/DefaultShell.class has changed
Binary file build/samer/core/DoubleFormat.class has changed
Binary file build/samer/core/Environment$1.class has changed
Binary file build/samer/core/Environment$2$1.class has changed
Binary file build/samer/core/Environment$2.class has changed
Binary file build/samer/core/Environment$Autocoder.class has changed
Binary file build/samer/core/Environment$Binding.class has changed
Binary file build/samer/core/Environment$Codec.class has changed
Binary file build/samer/core/Environment$CompoundIterator.class has changed
Binary file build/samer/core/Environment$Datum.class has changed
Binary file build/samer/core/Environment$Iterator.class has changed
Binary file build/samer/core/Environment.class has changed
Binary file build/samer/core/Node.class has changed
Binary file build/samer/core/NumberSink.class has changed
Binary file build/samer/core/NumberViewer.class has changed
Binary file build/samer/core/Registry.class has changed
Binary file build/samer/core/Saveable.class has changed
Binary file build/samer/core/Saver.class has changed
Binary file build/samer/core/Shell$1.class has changed
Binary file build/samer/core/Shell$2.class has changed
Binary file build/samer/core/Shell$3.class has changed
Binary file build/samer/core/Shell$Dialog.class has changed
Binary file build/samer/core/Shell$Interface.class has changed
Binary file build/samer/core/Shell$Interpreter.class has changed
Binary file build/samer/core/Shell$ViewerWindowListener$1.class has changed
Binary file build/samer/core/Shell$ViewerWindowListener.class has changed
Binary file build/samer/core/Shell$Window.class has changed
Binary file build/samer/core/Shell.class has changed
Binary file build/samer/core/Variable.class has changed
Binary file build/samer/core/Viewable$1.class has changed
Binary file build/samer/core/Viewable$Vector.class has changed
Binary file build/samer/core/Viewable.class has changed
Binary file build/samer/core/Viewer.class has changed
Binary file build/samer/core/X$1.class has changed
Binary file build/samer/core/X$2.class has changed
Binary file build/samer/core/X$3.class has changed
Binary file build/samer/core/X$4.class has changed
Binary file build/samer/core/X$5.class has changed
Binary file build/samer/core/X$6.class has changed
Binary file build/samer/core/X$7.class has changed
Binary file build/samer/core/X$BaseCodec.class has changed
Binary file build/samer/core/X.class has changed
Binary file build/samer/core/shells/AWTShell$VContainer.class has changed
Binary file build/samer/core/shells/AWTShell.class has changed
Binary file build/samer/core/shells/BevelWindow.class has changed
Binary file build/samer/core/shells/DesktopShell$1.class has changed
Binary file build/samer/core/shells/DesktopShell$VContainer.class has changed
Binary file build/samer/core/shells/DesktopShell.class has changed
Binary file build/samer/core/shells/SwingShell$1.class has changed
Binary file build/samer/core/shells/SwingShell$VContainer.class has changed
Binary file build/samer/core/shells/SwingShell.class has changed
Binary file build/samer/core/types/DoubleModel.class has changed
Binary file build/samer/core/types/VBoolean.class has changed
Binary file build/samer/core/types/VColor.class has changed
Binary file build/samer/core/types/VDouble.class has changed
Binary file build/samer/core/types/VFile.class has changed
Binary file build/samer/core/types/VInteger.class has changed
Binary file build/samer/core/types/VParameter.class has changed
Binary file build/samer/core/types/VRectangle.class has changed
Binary file build/samer/core/types/VString.class has changed
Binary file build/samer/core/util/AgentAdapter.class has changed
Binary file build/samer/core/util/BaseViewer.class has changed
Binary file build/samer/core/util/ConsoleEnvironment$Texton.class has changed
Binary file build/samer/core/util/ConsoleEnvironment.class has changed
Binary file build/samer/core/util/DefaultViewer.class has changed
Binary file build/samer/core/util/FileFilter.class has changed
Binary file build/samer/core/util/FilteredEnvironment.class has changed
Binary file build/samer/core/util/HashMap$1.class has changed
Binary file build/samer/core/util/HashMap$Entry.class has changed
Binary file build/samer/core/util/HashMap.class has changed
Binary file build/samer/core/util/IMap.class has changed
Binary file build/samer/core/util/LinearMap.class has changed
Binary file build/samer/core/util/LogMap.class has changed
Binary file build/samer/core/util/MouseRetarget.class has changed
Binary file build/samer/core/util/Properties$1.class has changed
Binary file build/samer/core/util/Properties$Property.class has changed
Binary file build/samer/core/util/Properties.class has changed
Binary file build/samer/core/util/StackLayout.class has changed
Binary file build/samer/core/util/Tools.class has changed
Binary file build/samer/core/util/UserEnvironment$1.class has changed
Binary file build/samer/core/util/UserEnvironment$2.class has changed
Binary file build/samer/core/util/UserEnvironment$3.class has changed
Binary file build/samer/core/util/UserEnvironment$4.class has changed
Binary file build/samer/core/util/UserEnvironment$5.class has changed
Binary file build/samer/core/util/UserEnvironment$Gluon.class has changed
Binary file build/samer/core/util/UserEnvironment$Thingy.class has changed
Binary file build/samer/core/util/UserEnvironment.class has changed
Binary file build/samer/core/util/VLayout.class has changed
Binary file build/samer/core/util/VMap$Adjuster.class has changed
Binary file build/samer/core/util/VMap.class has changed
Binary file build/samer/core/util/VariableViewer.class has changed
Binary file build/samer/core/util/heavy/Border$1.class has changed
Binary file build/samer/core/util/heavy/Border$Base.class has changed
Binary file build/samer/core/util/heavy/Border$BevelInfo.class has changed
Binary file build/samer/core/util/heavy/Border$Empty.class has changed
Binary file build/samer/core/util/heavy/Border$In.class has changed
Binary file build/samer/core/util/heavy/Border$Interface.class has changed
Binary file build/samer/core/util/heavy/Border$Null.class has changed
Binary file build/samer/core/util/heavy/Border$Out.class has changed
Binary file build/samer/core/util/heavy/Border.class has changed
Binary file build/samer/core/util/heavy/Borders$AbstractBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$CompoundBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$EllipticalBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$EmptyBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$LoweredBevelBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$ParentBgBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$RaisedBevelBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$RoundedBorder.class has changed
Binary file build/samer/core/util/heavy/Borders$SimpleBorder.class has changed
Binary file build/samer/core/util/heavy/Borders.class has changed
Binary file build/samer/core/util/heavy/ButtonBar.class has changed
Binary file build/samer/core/util/heavy/CommandField$Handler.class has changed
Binary file build/samer/core/util/heavy/CommandField.class has changed
Binary file build/samer/core/util/heavy/Console$OutputStream.class has changed
Binary file build/samer/core/util/heavy/Console$Writer.class has changed
Binary file build/samer/core/util/heavy/Console.class has changed
Binary file build/samer/core/util/heavy/Dialog$1.class has changed
Binary file build/samer/core/util/heavy/Dialog.class has changed
Binary file build/samer/core/util/heavy/Frame.class has changed
Binary file build/samer/core/util/heavy/JPanel.class has changed
Binary file build/samer/core/util/heavy/MenuBuilder.class has changed
Binary file build/samer/core/util/heavy/Meter$1.class has changed
Binary file build/samer/core/util/heavy/Meter.class has changed
Binary file build/samer/core/util/heavy/PopupHandler.class has changed
Binary file build/samer/core/util/heavy/TextualNumberViewer.class has changed
Binary file build/samer/core/util/heavy/VCanvas$1.class has changed
Binary file build/samer/core/util/heavy/VCanvas.class has changed
Binary file build/samer/core/util/heavy/VPanel.class has changed
Binary file build/samer/core/util/shell/AgentManager$1.class has changed
Binary file build/samer/core/util/shell/AgentManager.class has changed
Binary file build/samer/core/util/shell/AppShellBase.class has changed
Binary file build/samer/core/util/shell/ViewableManager$1.class has changed
Binary file build/samer/core/util/shell/ViewableManager$2.class has changed
Binary file build/samer/core/util/shell/ViewableManager$3.class has changed
Binary file build/samer/core/util/shell/ViewableManager$VblEntry.class has changed
Binary file build/samer/core/util/shell/ViewableManager$ViewerContainer.class has changed
Binary file build/samer/core/util/shell/ViewableManager$VwrEntry.class has changed
Binary file build/samer/core/util/shell/ViewableManager.class has changed
Binary file build/samer/core/util/swing/ButtonBar.class has changed
Binary file build/samer/core/util/swing/CommandField$Handler.class has changed
Binary file build/samer/core/util/swing/CommandField.class has changed
Binary file build/samer/core/util/swing/Console$OutputStream.class has changed
Binary file build/samer/core/util/swing/Console$Writer.class has changed
Binary file build/samer/core/util/swing/Console.class has changed
Binary file build/samer/core/util/swing/DarkMetalTheme.class has changed
Binary file build/samer/core/util/swing/Dialog.class has changed
Binary file build/samer/core/util/swing/DynamicPopupHandler.class has changed
Binary file build/samer/core/util/swing/Frame.class has changed
Binary file build/samer/core/util/swing/InternalFrame$1.class has changed
Binary file build/samer/core/util/swing/InternalFrame.class has changed
Binary file build/samer/core/util/swing/LED.class has changed
Binary file build/samer/core/util/swing/MenuBuilder.class has changed
Binary file build/samer/core/util/swing/Meter$1.class has changed
Binary file build/samer/core/util/swing/Meter.class has changed
Binary file build/samer/core/util/swing/PopupHandler.class has changed
Binary file build/samer/core/util/swing/SilkyMetalTheme.class has changed
Binary file build/samer/core/util/swing/TextualNumberViewer.class has changed
Binary file build/samer/core/util/swing/VCanvas$1.class has changed
Binary file build/samer/core/util/swing/VCanvas.class has changed
Binary file build/samer/core/util/swing/VContainerBase.class has changed
Binary file build/samer/core/util/swing/VPanel.class has changed
Binary file build/samer/core/viewers/BooleanViewer.class has changed
Binary file build/samer/core/viewers/ColorButton.class has changed
Binary file build/samer/core/viewers/ColorSwatch.class has changed
Binary file build/samer/core/viewers/ColorViewer.class has changed
Binary file build/samer/core/viewers/DoubleViewer.class has changed
Binary file build/samer/core/viewers/FileViewer.class has changed
Binary file build/samer/core/viewers/IntegerViewer.class has changed
Binary file build/samer/core/viewers/NumberViewer.class has changed
Binary file build/samer/core/viewers/ParameterViewer.class has changed
Binary file build/samer/core/viewers/StringViewer.class has changed
Binary file build/samer/core/viewers/swing/BooleanViewer.class has changed
Binary file build/samer/core/viewers/swing/ColorButton.class has changed
Binary file build/samer/core/viewers/swing/ColorChooserViewer$ColorModelAdapter.class has changed
Binary file build/samer/core/viewers/swing/ColorChooserViewer.class has changed
Binary file build/samer/core/viewers/swing/ColorSwatch.class has changed
Binary file build/samer/core/viewers/swing/ColorViewer.class has changed
Binary file build/samer/core/viewers/swing/DoubleViewer$1.class has changed
Binary file build/samer/core/viewers/swing/DoubleViewer.class has changed
Binary file build/samer/core/viewers/swing/FileChooserViewer.class has changed
Binary file build/samer/core/viewers/swing/FileViewer.class has changed
Binary file build/samer/core/viewers/swing/IntegerViewer.class has changed
Binary file build/samer/core/viewers/swing/NumberViewer.class has changed
Binary file build/samer/core/viewers/swing/ParameterViewer.class has changed
Binary file build/samer/core/viewers/swing/StringViewer.class has changed
Binary file build/samer/core/viewers/swing/Swatch.class has changed
Binary file build/samer/functions/Abs.class has changed
Binary file build/samer/functions/Add.class has changed
Binary file build/samer/functions/Atanh.class has changed
Binary file build/samer/functions/BiLaplacian$1.class has changed
Binary file build/samer/functions/BiLaplacian.class has changed
Binary file build/samer/functions/BiLaplacianBlend$1.class has changed
Binary file build/samer/functions/BiLaplacianBlend.class has changed
Binary file build/samer/functions/CauchyInfomax.class has changed
Binary file build/samer/functions/CompoundFunction$1.class has changed
Binary file build/samer/functions/CompoundFunction$2.class has changed
Binary file build/samer/functions/CompoundFunction.class has changed
Binary file build/samer/functions/Exp.class has changed
Binary file build/samer/functions/ExponentialSquashing.class has changed
Binary file build/samer/functions/Gamma.class has changed
Binary file build/samer/functions/HalfSquare.class has changed
Binary file build/samer/functions/Hamming.class has changed
Binary file build/samer/functions/Hanning.class has changed
Binary file build/samer/functions/HybridFunction.class has changed
Binary file build/samer/functions/Log.class has changed
Binary file build/samer/functions/LogAbs.class has changed
Binary file build/samer/functions/LogCauchy.class has changed
Binary file build/samer/functions/LogCosh$1.class has changed
Binary file build/samer/functions/LogCosh.class has changed
Binary file build/samer/functions/LogGenCosh$1.class has changed
Binary file build/samer/functions/LogGenCosh.class has changed
Binary file build/samer/functions/LogGenExp$1.class has changed
Binary file build/samer/functions/LogGenExp$2.class has changed
Binary file build/samer/functions/LogGenExp.class has changed
Binary file build/samer/functions/LogGenExp2$1.class has changed
Binary file build/samer/functions/LogGenExp2$2.class has changed
Binary file build/samer/functions/LogGenExp2$3.class has changed
Binary file build/samer/functions/LogGenExp2.class has changed
Binary file build/samer/functions/LogisiticInfomax.class has changed
Binary file build/samer/functions/LogisticHyperplane.class has changed
Binary file build/samer/functions/Negate.class has changed
Binary file build/samer/functions/Power.class has changed
Binary file build/samer/functions/Quadratic.class has changed
Binary file build/samer/functions/RaleighLogPrior$1.class has changed
Binary file build/samer/functions/RaleighLogPrior.class has changed
Binary file build/samer/functions/Reciprocal.class has changed
Binary file build/samer/functions/Scale.class has changed
Binary file build/samer/functions/ScaledFunction.class has changed
Binary file build/samer/functions/Sgn.class has changed
Binary file build/samer/functions/SparseExponential$1.class has changed
Binary file build/samer/functions/SparseExponential.class has changed
Binary file build/samer/functions/Sqrt.class has changed
Binary file build/samer/functions/Square.class has changed
Binary file build/samer/functions/Step.class has changed
Binary file build/samer/functions/Tanh$1.class has changed
Binary file build/samer/functions/Tanh.class has changed
Binary file build/samer/functions/ThresholdLog.class has changed
Binary file build/samer/functions/WinnerTakeAll.class has changed
Binary file build/samer/j3d/Axes.class has changed
Binary file build/samer/j3d/FPS.class has changed
Binary file build/samer/j3d/ImmediateRenderer.class has changed
Binary file build/samer/j3d/MatrixPointArray$1.class has changed
Binary file build/samer/j3d/MatrixPointArray.class has changed
Binary file build/samer/j3d/MatrixPointArrayAlpha$1.class has changed
Binary file build/samer/j3d/MatrixPointArrayAlpha.class has changed
Binary file build/samer/j3d/MatrixPointArrayRef$1.class has changed
Binary file build/samer/j3d/MatrixPointArrayRef.class has changed
Binary file build/samer/j3d/MatrixPoints4D$1.class has changed
Binary file build/samer/j3d/MatrixPoints4D.class has changed
Binary file build/samer/j3d/MonoView.class has changed
Binary file build/samer/j3d/MorphPoints$MorphBehavior.class has changed
Binary file build/samer/j3d/MorphPoints.class has changed
Binary file build/samer/j3d/PatchArray$1.class has changed
Binary file build/samer/j3d/PatchArray.class has changed
Binary file build/samer/j3d/PatchArrayAlpha$1.class has changed
Binary file build/samer/j3d/PatchArrayAlpha.class has changed
Binary file build/samer/j3d/Patches$1.class has changed
Binary file build/samer/j3d/Patches.class has changed
Binary file build/samer/j3d/PatchesAlpha$1.class has changed
Binary file build/samer/j3d/PatchesAlpha.class has changed
Binary file build/samer/j3d/Points3D$1.class has changed
Binary file build/samer/j3d/Points3D.class has changed
Binary file build/samer/j3d/Points3DAlpha$1.class has changed
Binary file build/samer/j3d/Points3DAlpha.class has changed
Binary file build/samer/j3d/Points3DRef$1.class has changed
Binary file build/samer/j3d/Points3DRef.class has changed
Binary file build/samer/j3d/Points4D$1.class has changed
Binary file build/samer/j3d/Points4D.class has changed
Binary file build/samer/j3d/Root.class has changed
Binary file build/samer/j3d/StereoView.class has changed
Binary file build/samer/j3d/Util.class has changed
Binary file build/samer/j3d/ViewBase.class has changed
Binary file build/samer/j3d/ViewGroup.class has changed
Binary file build/samer/maths/ClippedDivide.class has changed
Binary file build/samer/maths/ComplexVector.class has changed
Binary file build/samer/maths/Constant.class has changed
Binary file build/samer/maths/Difference.class has changed
Binary file build/samer/maths/Function.class has changed
Binary file build/samer/maths/FunctionMap.class has changed
Binary file build/samer/maths/FunctionOfGenerator.class has changed
Binary file build/samer/maths/FunctionOfVector.class has changed
Binary file build/samer/maths/FunctionPlotter$1.class has changed
Binary file build/samer/maths/FunctionPlotter$FunctionIterator.class has changed
Binary file build/samer/maths/FunctionPlotter.class has changed
Binary file build/samer/maths/Generator.class has changed
Binary file build/samer/maths/Identity.class has changed
Binary file build/samer/maths/IntArrayEditor.class has changed
Binary file build/samer/maths/IteratorImageSource.class has changed
Binary file build/samer/maths/LineTrace.class has changed
Binary file build/samer/maths/Linear.class has changed
Binary file build/samer/maths/Mat.class has changed
Binary file build/samer/maths/MatEditor.class has changed
Binary file build/samer/maths/Mathx.class has changed
Binary file build/samer/maths/Matrix$1$1.class has changed
Binary file build/samer/maths/Matrix$1$2.class has changed
Binary file build/samer/maths/Matrix$1.class has changed
Binary file build/samer/maths/Matrix$Column$1.class has changed
Binary file build/samer/maths/Matrix$Column.class has changed
Binary file build/samer/maths/Matrix$Row$1.class has changed
Binary file build/samer/maths/Matrix$Row.class has changed
Binary file build/samer/maths/Matrix$Slice.class has changed
Binary file build/samer/maths/Matrix$Vbl.class has changed
Binary file build/samer/maths/Matrix.class has changed
Binary file build/samer/maths/MatrixAgent.class has changed
Binary file build/samer/maths/MatrixImage.class has changed
Binary file build/samer/maths/MatrixImageSource.class has changed
Binary file build/samer/maths/MatrixImageSourceF.class has changed
Binary file build/samer/maths/MatrixPanel$Field.class has changed
Binary file build/samer/maths/MatrixPanel.class has changed
Binary file build/samer/maths/MatrixPlotter$1.class has changed
Binary file build/samer/maths/MatrixPlotter.class has changed
Binary file build/samer/maths/MatrixTImageSource.class has changed
Binary file build/samer/maths/MatrixTImageSourceF.class has changed
Binary file build/samer/maths/MatrixTimesVector.class has changed
Binary file build/samer/maths/MatrixTransposeTimesVector.class has changed
Binary file build/samer/maths/Neg.class has changed
Binary file build/samer/maths/Ops$1.class has changed
Binary file build/samer/maths/Ops$2.class has changed
Binary file build/samer/maths/Ops$3.class has changed
Binary file build/samer/maths/Ops$4.class has changed
Binary file build/samer/maths/Ops$5.class has changed
Binary file build/samer/maths/Ops$6.class has changed
Binary file build/samer/maths/Ops$7.class has changed
Binary file build/samer/maths/Ops$8.class has changed
Binary file build/samer/maths/Ops$9.class has changed
Binary file build/samer/maths/Ops$ArrayCopy.class has changed
Binary file build/samer/maths/Ops$IteratorCopy.class has changed
Binary file build/samer/maths/Ops.class has changed
Binary file build/samer/maths/Parameter.class has changed
Binary file build/samer/maths/Probe.class has changed
Binary file build/samer/maths/Product.class has changed
Binary file build/samer/maths/RowColumn.class has changed
Binary file build/samer/maths/SparseMatrix.class has changed
Binary file build/samer/maths/Sum.class has changed
Binary file build/samer/maths/VFunction$1.class has changed
Binary file build/samer/maths/VFunction$2.class has changed
Binary file build/samer/maths/VFunction.class has changed
Binary file build/samer/maths/VGenerator$UI.class has changed
Binary file build/samer/maths/VGenerator.class has changed
Binary file build/samer/maths/VVector$1.class has changed
Binary file build/samer/maths/VVector$2.class has changed
Binary file build/samer/maths/VVector.class has changed
Binary file build/samer/maths/Vec$ForArray$InputIterator.class has changed
Binary file build/samer/maths/Vec$ForArray$Iterator.class has changed
Binary file build/samer/maths/Vec$ForArray.class has changed
Binary file build/samer/maths/Vec$InputIterator.class has changed
Binary file build/samer/maths/Vec$Iterator.class has changed
Binary file build/samer/maths/Vec.class has changed
Binary file build/samer/maths/VectorEditor.class has changed
Binary file build/samer/maths/VectorFunctionOfVector.class has changed
Binary file build/samer/maths/VectorPlotter.class has changed
Binary file build/samer/maths/VectorPlusEqualsVector.class has changed
Binary file build/samer/maths/VectorTimesEqualsScalar.class has changed
Binary file build/samer/maths/VectorTrace.class has changed
Binary file build/samer/maths/VectorTraceObs.class has changed
Binary file build/samer/maths/Zero.class has changed
Binary file build/samer/maths/opt/AbsXFConvergence.class has changed
Binary file build/samer/maths/opt/Condition.class has changed
Binary file build/samer/maths/opt/ConjGrad.class has changed
Binary file build/samer/maths/opt/ConstrainedConjGrad.class has changed
Binary file build/samer/maths/opt/ConstrainedGillMurray.class has changed
Binary file build/samer/maths/opt/ConstrainedMinimiser.class has changed
Binary file build/samer/maths/opt/Constraints$Factory.class has changed
Binary file build/samer/maths/opt/Constraints.class has changed
Binary file build/samer/maths/opt/CubicLineSearch.class has changed
Binary file build/samer/maths/opt/Datum.class has changed
Binary file build/samer/maths/opt/Functionx.class has changed
Binary file build/samer/maths/opt/GConvergence.class has changed
Binary file build/samer/maths/opt/GillMurray.class has changed
Binary file build/samer/maths/opt/MinimiserBase$1.class has changed
Binary file build/samer/maths/opt/MinimiserBase$2.class has changed
Binary file build/samer/maths/opt/MinimiserBase$3.class has changed
Binary file build/samer/maths/opt/MinimiserBase$4.class has changed
Binary file build/samer/maths/opt/MinimiserBase$5.class has changed
Binary file build/samer/maths/opt/MinimiserBase$LSCondition$1.class has changed
Binary file build/samer/maths/opt/MinimiserBase$LSCondition.class has changed
Binary file build/samer/maths/opt/MinimiserBase.class has changed
Binary file build/samer/maths/opt/PolynomialLineSearch.class has changed
Binary file build/samer/maths/opt/Positivity$1.class has changed
Binary file build/samer/maths/opt/Positivity$2.class has changed
Binary file build/samer/maths/opt/Positivity.class has changed
Binary file build/samer/maths/opt/State.class has changed
Binary file build/samer/maths/opt/SubspaceFunctionx.class has changed
Binary file build/samer/maths/opt/UnconstrainedConjGrad$1.class has changed
Binary file build/samer/maths/opt/UnconstrainedConjGrad.class has changed
Binary file build/samer/maths/opt/UnconstrainedMinimiser.class has changed
Binary file build/samer/maths/opt/Util.class has changed
Binary file build/samer/maths/opt/XFConvergence.class has changed
Binary file build/samer/maths/opt/ZeroCrossingSparsity$1.class has changed
Binary file build/samer/maths/opt/ZeroCrossingSparsity$2.class has changed
Binary file build/samer/maths/opt/ZeroCrossingSparsity$3.class has changed
Binary file build/samer/maths/opt/ZeroCrossingSparsity$4.class has changed
Binary file build/samer/maths/opt/ZeroCrossingSparsity.class has changed
Binary file build/samer/maths/random/BaseRandom.class has changed
Binary file build/samer/maths/random/Binary.class has changed
Binary file build/samer/maths/random/BinaryVec.class has changed
Binary file build/samer/maths/random/BipolarUniform.class has changed
Binary file build/samer/maths/random/BoundedHyperbolic.class has changed
Binary file build/samer/maths/random/BoundedUniform.class has changed
Binary file build/samer/maths/random/Brownian.class has changed
Binary file build/samer/maths/random/Cauchy.class has changed
Binary file build/samer/maths/random/Exponential.class has changed
Binary file build/samer/maths/random/Gaussian.class has changed
Binary file build/samer/maths/random/GeneralisedExponential.class has changed
Binary file build/samer/maths/random/GeneralisedLaplacian.class has changed
Binary file build/samer/maths/random/Laplacian.class has changed
Binary file build/samer/maths/random/Logistic.class has changed
Binary file build/samer/maths/random/Mixture.class has changed
Binary file build/samer/maths/random/MixtureVec.class has changed
Binary file build/samer/maths/random/NormalisedGaussian.class has changed
Binary file build/samer/maths/random/PosteriorSampler.class has changed
Binary file build/samer/maths/random/PowerLaw.class has changed
Binary file build/samer/maths/random/Raleigh.class has changed
Binary file build/samer/maths/random/RectifiedCauchy.class has changed
Binary file build/samer/maths/random/RectifiedGaussian.class has changed
Binary file build/samer/maths/random/RectifiedLogistic.class has changed
Binary file build/samer/maths/random/SparseMixture.class has changed
Binary file build/samer/maths/random/Ternary.class has changed
Binary file build/samer/maths/random/Uniform.class has changed
Binary file build/samer/mds/CorrelationTask.class has changed
Binary file build/samer/mds/CovarianceTask.class has changed
Binary file build/samer/mds/DistanceTask.class has changed
Binary file build/samer/mds/Euclidean.class has changed
Binary file build/samer/mds/GeometricFilter.class has changed
Binary file build/samer/mds/MDS$Metric.class has changed
Binary file build/samer/mds/MDS$SamerStress.class has changed
Binary file build/samer/mds/MDS$Stress.class has changed
Binary file build/samer/mds/MDS.class has changed
Binary file build/samer/mds/MDSBase.class has changed
Binary file build/samer/mds/Manhatten.class has changed
Binary file build/samer/mds/MatrixPointViewer2.class has changed
Binary file build/samer/mds/Minkowski.class has changed
Binary file build/samer/mds/NewMDS$Laplacian.class has changed
Binary file build/samer/mds/NewMDS$Stress.class has changed
Binary file build/samer/mds/NewMDS.class has changed
Binary file build/samer/mds/ProximityFilter.class has changed
Binary file build/samer/midi/MidiRecorder.class has changed
Binary file build/samer/midi/MidiRecorderBase.class has changed
Binary file build/samer/midi/MidiSynth$1.class has changed
Binary file build/samer/midi/MidiSynth$Editor.class has changed
Binary file build/samer/midi/MidiSynth.class has changed
Binary file build/samer/midi/MidiWithAftertouch.class has changed
Binary file build/samer/models/AlignedGaussian$1.class has changed
Binary file build/samer/models/AlignedGaussian.class has changed
Binary file build/samer/models/BatchedTrainer.class has changed
Binary file build/samer/models/Covariance.class has changed
Binary file build/samer/models/DiffScaler$1.class has changed
Binary file build/samer/models/DiffScaler$OffsetTrainer.class has changed
Binary file build/samer/models/DiffScaler$ScaleTrainer.class has changed
Binary file build/samer/models/DiffScaler$TensionedTrainer.class has changed
Binary file build/samer/models/DiffScaler$Trainer.class has changed
Binary file build/samer/models/DiffScaler.class has changed
Binary file build/samer/models/Edge.class has changed
Binary file build/samer/models/GaussianStats.class has changed
Binary file build/samer/models/GaussianStatsOnline.class has changed
Binary file build/samer/models/GeneralisedExponential$1.class has changed
Binary file build/samer/models/GeneralisedExponential$Trainer.class has changed
Binary file build/samer/models/GeneralisedExponential.class has changed
Binary file build/samer/models/ICA$1.class has changed
Binary file build/samer/models/ICA$NewtonTrainer.class has changed
Binary file build/samer/models/ICA$ON2DecayWhenActive.class has changed
Binary file build/samer/models/ICA$ON2Trainer.class has changed
Binary file build/samer/models/ICA$ON3Trainer.class has changed
Binary file build/samer/models/ICA.class has changed
Binary file build/samer/models/ICAScalerSync.class has changed
Binary file build/samer/models/ICAWithScaler$DifferentialTrainer.class has changed
Binary file build/samer/models/ICAWithScaler$ScalerTrainer.class has changed
Binary file build/samer/models/ICAWithScaler.class has changed
Binary file build/samer/models/IIDPrior$1.class has changed
Binary file build/samer/models/IIDPrior.class has changed
Binary file build/samer/models/JointHistogramBase.class has changed
Binary file build/samer/models/MOGModel$1.class has changed
Binary file build/samer/models/MOGModel$2.class has changed
Binary file build/samer/models/MOGModel.class has changed
Binary file build/samer/models/MOGVector$1.class has changed
Binary file build/samer/models/MOGVector$2.class has changed
Binary file build/samer/models/MOGVector$PDF.class has changed
Binary file build/samer/models/MOGVector.class has changed
Binary file build/samer/models/MatrixTrainer.class has changed
Binary file build/samer/models/Mixture$Trainer.class has changed
Binary file build/samer/models/Mixture.class has changed
Binary file build/samer/models/Model$Trainer.class has changed
Binary file build/samer/models/Model.class has changed
Binary file build/samer/models/NoisyICA$1.class has changed
Binary file build/samer/models/NoisyICA$2.class has changed
Binary file build/samer/models/NoisyICA$3.class has changed
Binary file build/samer/models/NoisyICA.class has changed
Binary file build/samer/models/Scaler$1.class has changed
Binary file build/samer/models/Scaler$OffsetTrainer.class has changed
Binary file build/samer/models/Scaler$ScaleTrainer.class has changed
Binary file build/samer/models/Scaler$Trainer.class has changed
Binary file build/samer/models/Scaler.class has changed
Binary file build/samer/models/SignalHistogram.class has changed
Binary file build/samer/models/SmoothGeneralisedExponential$1.class has changed
Binary file build/samer/models/SmoothGeneralisedExponential.class has changed
Binary file build/samer/models/SparseICA$ON2Trainer.class has changed
Binary file build/samer/models/SparseICA$ON3Trainer.class has changed
Binary file build/samer/models/SparseICA.class has changed
Binary file build/samer/models/VarianceICA$1.class has changed
Binary file build/samer/models/VarianceICA$2.class has changed
Binary file build/samer/models/VarianceICA$3.class has changed
Binary file build/samer/models/VarianceICA.class has changed
Binary file build/samer/silk/JavaProcedure.class has changed
Binary file build/samer/silk/SchemeList$Iterator.class has changed
Binary file build/samer/silk/SchemeList.class has changed
Binary file build/samer/silk/SilkCompleter.class has changed
Binary file build/samer/silk/SilkFunction.class has changed
Binary file build/samer/silk/SilkObserver.class has changed
Binary file build/samer/silk/SilkTask.class has changed
Binary file build/samer/silk/Terminal$Transfer.class has changed
Binary file build/samer/silk/Terminal.class has changed
Binary file build/samer/tools/AnonymousTask.class has changed
Binary file build/samer/tools/ArrayImageSource.class has changed
Binary file build/samer/tools/ArrayVImageSource.class has changed
Binary file build/samer/tools/ColorRamp.class has changed
Binary file build/samer/tools/CompoundTask$Iterator.class has changed
Binary file build/samer/tools/CompoundTask$TaskLink.class has changed
Binary file build/samer/tools/CompoundTask.class has changed
Binary file build/samer/tools/ImageSourceBase.class has changed
Binary file build/samer/tools/ImageTrace.class has changed
Binary file build/samer/tools/ImageTraceBase.class has changed
Binary file build/samer/tools/ImageVTrace.class has changed
Binary file build/samer/tools/ImageViewer$1.class has changed
Binary file build/samer/tools/ImageViewer.class has changed
Binary file build/samer/tools/NamedTask.class has changed
Binary file build/samer/tools/NullTask.class has changed
Binary file build/samer/tools/Plotter$Pen.class has changed
Binary file build/samer/tools/Plotter.class has changed
Binary file build/samer/tools/RThread$Kill.class has changed
Binary file build/samer/tools/RThread$UI.class has changed
Binary file build/samer/tools/RThread.class has changed
Binary file build/samer/tools/RateSchedule.class has changed
Binary file build/samer/tools/Renderer$Fill.class has changed
Binary file build/samer/tools/Renderer$Fill3D.class has changed
Binary file build/samer/tools/Renderer$Line.class has changed
Binary file build/samer/tools/Renderer$Steps.class has changed
Binary file build/samer/tools/Renderer.class has changed
Binary file build/samer/tools/SafeTask.class has changed
Binary file build/samer/tools/ScatterPlot.class has changed
Binary file build/samer/tools/SignalTrace.class has changed
Binary file build/samer/tools/SubrateTask.class has changed
Binary file build/samer/tools/SwitchTask.class has changed
Binary file build/samer/tools/Task.class has changed
Binary file build/samer/tools/Trace.class has changed
Binary file build/samer/tools/vec2.class has changed
Binary file build/samer/units/Clicker.class has changed
Binary file build/samer/units/DoubleToStream.class has changed
Binary file build/samer/units/DoubleWriter.class has changed
Binary file build/samer/units/EnergyOperator.class has changed
Binary file build/samer/units/FFT.class has changed
Binary file build/samer/units/FFTVector$1.class has changed
Binary file build/samer/units/FFTVector$2.class has changed
Binary file build/samer/units/FFTVector$3.class has changed
Binary file build/samer/units/FFTVector$4.class has changed
Binary file build/samer/units/FFTVector.class has changed
Binary file build/samer/units/FIRFilter.class has changed
Binary file build/samer/units/Filter.class has changed
Binary file build/samer/units/FilterVector.class has changed
Binary file build/samer/units/FilteredGenerator.class has changed
Binary file build/samer/units/GenerateDouble.class has changed
Binary file build/samer/units/GenerateVector.class has changed
Binary file build/samer/units/Histogram$Equaliser.class has changed
Binary file build/samer/units/Histogram.class has changed
Binary file build/samer/units/IIRFilter.class has changed
Binary file build/samer/units/JointHistogram.class has changed
Binary file build/samer/units/Latch.class has changed
Binary file build/samer/units/LineIn.class has changed
Binary file build/samer/units/LineOut.class has changed
Binary file build/samer/units/Matrices.class has changed
Binary file build/samer/units/MousePosition.class has changed
Binary file build/samer/units/NoisyLinearSource.class has changed
Binary file build/samer/units/OnsetMap.class has changed
Binary file build/samer/units/Oscillator$1.class has changed
Binary file build/samer/units/Oscillator.class has changed
Binary file build/samer/units/OverlapAndAdd.class has changed
Binary file build/samer/units/RescaledIFT.class has changed
Binary file build/samer/units/SignalWindow$1.class has changed
Binary file build/samer/units/SignalWindow.class has changed
Binary file build/samer/units/SpectralFIR.class has changed
Binary file build/samer/units/Stacker.class has changed
Binary file build/samer/units/Stacker2.class has changed
Binary file build/samer/units/StreamToDouble.class has changed
Binary file build/samer/units/StreamToVec.class has changed
Binary file build/samer/units/SumFnVec.class has changed
Binary file build/samer/units/Trigger.class has changed
Binary file build/samer/units/VecToDouble.class has changed
Binary file build/samer/units/VecToStream$ArrayObjectWriter.class has changed
Binary file build/samer/units/VecToStream$IteratorFloatWriter.class has changed
Binary file build/samer/units/VecToStream.class has changed
Binary file build/samer/units/VecWriter.class has changed
Binary file build/samer/units/Wavetable.class has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/README	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,2 @@
+Chances of these examples working immediately
+are pretty slim. Especially the audio ones.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sockets/args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,12 @@
+#properties
+#Thu Apr 24 22:40:45 BST 2003
+playlist.files='()
+x.trace.window.bounds=(754,28,256,534)
+s.plotter.window.bounds=(508,576,512,118)
+v.plotter.window.bounds=(266,25,394,104)
+normaliser.rate=0.001
+Tasks.bounds=(257,142,210,152)
+s.trace.window.bounds=(495,22,256,534)
+violin1='("/Users/samer/Music/Partita2-1a.wav" "/Users/samer/Music/Partita2-1b.wav" "/Users/samer/Music/Partita2-2.WAV" "/Users/samer/Music/Partita3-5.WAV" "/Users/samer/Music/Sonata1-1a.wav" "/Users/samer/Music/Sonata1-1b.wav" "/Users/samer/Music/Sonata2-1.wav")
+x.plotter.window.bounds=(133,404,512,118)
+exposed.bounds=(49,144,98,79)
Binary file examples/sockets/obj has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sockets/ostream.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+(load "sockets.scm")
+
+;;; get a random vector
+(define v (VVector. "v" 8))
+(.next (samer.maths.random.NormalisedGaussian.) (.array v))
+
+;;; write object to a file
+(define o (oostream (ofstream "obj")))
+(.writeObject o v)
+(.close o)
+
+;;; read object back
+(define i (iostream (ifstream "obj")))
+(define w (.readObject i))
+(.close i)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sockets/recv.silk	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,13 @@
+(load "sockets.scm")
+(load "sources.scm")
+
+(define S (make-server))
+(define x (norm (linein (filesource))))
+(define s (VVector. "s" 512))
+(expose)
+(define sk (accept S))
+(addtask (send-vec sk x))
+
+(define th2 (RThread.))
+(.addTask th2 (recv-vec sk s)) 
+
Binary file examples/sound/midi/4notes.mat has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+#properties
+#Thu Jul 14 14:56:13 BST 2011
+p.slider.map.maximum=0.001
+decay.slider.map.maximum=0.700
+Tasks.bounds=(290,499,225,145)
+matrix.file=walking_zither2
+spam.bounds=(660,114,266,204)
+MidiSynth.bounds=(1,24,345,140)
+midisynth.file=midisynth
+matrix.rowcolumn.trace.window.bounds=(557,374,256,86)
+regulated=true
+matrix.rowcolumn.plotter.window.bounds=(264,345,242,115)
+out.plotter.window.bounds=(4,22,128,118)
+MidiSynthEditor.bounds=(281,201,308,231)
+matrix.rowcolumn.image.window.bounds=(514,242,229,78)
+p=2.0E-5
+plotter.type=2
+midisynth.offset=32
+matrix.rowcolumn.editor.image.window.bounds=(377,604,505,69)
+midisynth.bounds=(281,22,232,176)
+out.image.window.bounds=(396,586,390,88)
+regulator.target=35.0
+midisynth.offset.bounds=(283,23,204,57)
+matrix.editor.window.bounds=(603,22,551,549)
+p.slider.map.minimum=2.357E-7
+decay.slider.map.minimum=0.001
+exposed.bounds=(3,22,276,590)
+matrix.image.window.bounds=(255,51,161,202)
+decay=0.01
+midisynth.factor=80.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/args.alt	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,166 @@
+#AppShellBase
+#Thu Mar 22 11:32:49 GMT+00:00 2001
+spectrum.image.map.log=true
+coder.y.trace.map.maximum=40.0
+coder.A.plotter.window.bounds=(965,54,291,146)
+coder.e.image.window.bounds=(634,86,353,74)
+coder.u.histogram.bins.plotter.window.bounds=(383,665,362,256)
+audio.buffer=11025
+x.plotter.window.bounds=(951,117,273,88)
+coder.z.plotter.window.bounds=(524,320,338,148)
+batch=128
+coder.z.trace.window.bounds=(628,313,444,295)
+likelihood.map.maximum=4000.0
+coder.e.plotter.window.bounds=(947,333,267,102)
+y.image.map.minimum=0.0
+likelihood.likelihood.bounds=(783,4,492,332)
+B.rowcolumn.image.window.bounds=(823,745,162,195)
+coder.y.trace.window.bounds=(625,169,630,267)
+VState.x2.plotter.window.bounds=(990,118,269,106)
+source.class2=samer.maths.ops.Zero
+nonlin=sparseLaplacian
+DELTA=1.0E-4
+y.trace.window.bounds=(568,351,526,307)
+y.plotter.window.bounds=(673,18,281,95)
+likelihood.rate=0.5
+e.plotter.map.maximum=0.15
+Synth.editor.window.bounds=(318,207,453,486)
+midisynth.thresh=0.1
+y.trace.cellsize=4
+source.x.plotter.window.bounds=(378,694,371,135)
+y.image.map.maximum=2.0
+rowcolumn.image.window.bounds=(837,622,162,174)
+y.editplot.window.bounds=(614,213,328,127)
+cellsize=1
+coder.e.image.map.maximum=0.3
+normaliser.signal.plotter.map.maximum=6.0
+coder.C.plotter.window.bounds=(342,659,498,238)
+numpoints=128
+XEPS=1.0E-6
+coder.e.rowcolumn.image.window.bounds=(824,628,162,174)
+B.editor.window.bounds=(761,100,275,312)
+spectrum.image.window.bounds=(639,327,355,78)
+qnopt.VState.TestRig.bounds=(355,-1,304,561)
+map.symmetric=false
+MidiSynthEditor.bounds=(921,348,312,253)
+exposed.bounds=(308,3,261,549)
+spectrum.image.map.minimum=5.0E-5
+coder.A.rowcolumn.plotter.window.bounds=(308,350,309,222)
+regulator.target=7.5
+B.image.window.title=Basis
+size=512
+spectrum.plotter.window.bounds=(679,333,569,147)
+z.plotter.window.bounds=(885,234,371,173)
+logprior.derivative.y.map.maximum=4.0
+console.bounds=(271,650,500,297)
+Harry.editor.window.bounds=(0,0,321,332)
+coder.A.editor.window.bounds=(-5,-5,1290,1034)
+sout.plotter.window.bounds=(341,57,306,129)
+e.plotter.window.bounds=(338,24,363,132)
+x.map.maximum=2.0
+MidiSynth.bounds=(911,5,342,254)
+x.map.symmetric=true
+coder.A.file=learned.mat
+B.image.window.bounds=(967,389,270,295)
+logprior.strength=8.0
+source.type=mixture
+regulated=true
+step=512
+y.editor.window.bounds=(614,330,325,130)
+coder.z.trace.map.maximum=0.0020
+gamma=2.0
+ZETA=0.125
+B.plotter.window.bounds=(0,0,176,181)
+sout.image.window.bounds=(319,647,454,82)
+coder.y.rowcolumn.image.window.bounds=(828,703,162,174)
+coder.A.image.window.bounds=(625,437,646,290)
+y.MidiSynthEditor.bounds=(907,292,320,253)
+A.image.window.bounds=(555,14,270,295)
+normaliser.map.maximum=2000.0
+source.A.plotter.window.bounds=(31,338,510,257)
+ping.Ping.bounds=(339,477,162,80)
+mixtures=64
+normaliser.loudness.bounds=(262,3,378,173)
+noise.variance=0.0
+normaliser.rate=0.01
+VState.beta=1.0
+z.image.window.bounds=(934,395,165,185)
+randomiser.variance=0.1
+waveform.plotter.window.bounds=(0,0,526,124)
+spectrogram.cellsize=1
+andy.image.window.bounds=(889,547,269,67)
+coder.learn.rate=0.0010
+spectrum.editor.window.bounds=(0,0,526,80)
+GEPS=2.0E-5
+y.image.window.bounds=(503,554,268,78)
+coder.Basis.bounds=(328,41,270,298)
+spectrum.trace.map.minimum=5.0E-5
+z.image.map.maximum=2.0
+coder.A.plotter.rowcolumn.image.window.bounds=(1110,211,164,200)
+Synth.file=synth.mat
+coder.z.image.window.bounds=(935,440,162,182)
+image.height=8
+midisynth.count_thresh=1
+B.MidiSynthEditor.bounds=(568,356,306,109)
+VState.map.symmetric=false
+coder.A.image.rowcolumn.image.window.bounds=(816,640,162,174)
+x.image.window.bounds=(614,116,271,63)
+y.image.ETA=0.75
+coder.y.image.window.bounds=(517,890,647,95)
+coder.y.plotter.map.minimum=-1.0
+histogram.bins=128
+Synth.image.window.bounds=(215,108,512,295)
+trace.map.symmetric=false
+logprior.y.map.maximum=4.0
+trace.colormap=trace
+plotter.bounds=(914,311,254,159)
+xtol=1.0E-5
+spectrum.trace.map.maximum=0.0050
+A.rowcolumn.image.colormap=grey
+spectrum.trace.window.bounds=(628,15,445,295)
+B.file=scale2.mat
+coder.y.image.map.maximum=8.0
+image.width=8
+source.A.map.maximum=1.0
+coder.sigma=8.0E-5
+source.mixture.p=0.05
+logprior.beta=0.06
+y.plotter.map.maximum=3.0
+ftol=1.0E-10
+audio.rate=11025
+logprior.plotter.bounds=(676,70,258,163)
+Harry.image.window.bounds=(887,258,270,288)
+coder.u.histogram.bins.image.window.bounds=(345,465,178,170)
+x.image.map.maximum=2.0
+coder.A.image.map.minimum=7.474249728000009E-10
+VState.TestRig.bounds=(317,-1,291,545)
+sources=64
+midisynth.offset=50
+source.class=samer.maths.random.Uniform
+x.plotter.map.maximum=4.0
+VState.g1.plotter.window.bounds=(958,228,269,106)
+coder.y.plotter.window.bounds=(864,322,297,126)
+spectrum.trace.map.log=true
+B.plotter.rowcolumn.image.window.bounds=(384,123,168,228)
+colormap=hotAsymmetric
+normaliser.signal.plotter.window.bounds=(345,253,445,160)
+ETA=0.75
+B.factor=1.0
+randomiseMatrix=basisMatrix
+coder.A.image.map.maximum=1.0240000000000013E-4
+maxiter=400
+likelihood.map.minimum=-4000.0
+VState.g2.plotter.window.bounds=(977,337,271,124)
+H.image.window.bounds=(634,320,206,231)
+e.image.window.bounds=(1097,439,164,182)
+spectrogram.Spectrogram.bounds=(350,0,911,569)
+outputs=96
+VState.h.plotter.window.bounds=(964,545,270,116)
+e.editplot.window.bounds=(591,209,290,145)
+sout.trace.window.bounds=(317,-14,280,381)
+A.image.colormap=hotAsymmetric
+trace.cellsize=1
+coder.Coder.bounds=(76,9,270,295)
+VState.map.maximum=400.0
+gtol=1.0E-4
+coder.A.rowcolumn.image.window.bounds=(481,562,291,87)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/args.audio	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,120 @@
+#AppShell
+#Fri Apr 28 12:10:43 GMT 2000
+source.p=0.1
+audio.buffer=11025
+signal.histogram.bins.plotter.window.bounds=(803,579,436,180)
+waveform.plotter.window.bounds=(351,502,754,133)
+beta=1.017
+trace.colormap=trace
+scroll=false
+stretch=false
+normaliser.signal.histogram.bins.plotter.window.bounds=(383,597,436,180)
+size=1024
+normaliser.signal.plotter.map.minimum=-6.0
+waveform.image.window.bounds=(91,619,1038,52)
+saamah=01223 333585
+spectrogram.map.log=true
+source=line
+normaliser.loudness.bounds=(5,876,355,132)
+spectrum.histogram.map.maximum=1000
+B.file=diatonic.mat
+exposed.bounds=(971,74,301,490)
+noise.class=samer.maths.ops.Zero
+histogram.bins.plotter.map.maximum=6000
+normaliser.signal.plotter.map.maximum=6.0
+regulated=false
+audio.bits=16
+spectrum.histogram.bins.image.map.minimum=0.0
+spectrum.histogram.bins.file=spectrum.histogram.mat
+power.rate=0.02
+function.foreground=#a05080
+waveform.histogram.map.minimum=-10000.0
+font.size=14
+waveform.histogram.bins.plotter.window.bounds=(373,584,380,204)
+audio.signed=true
+power.window.title=Signal Strength
+waveform.editor.window.bounds=(86,292,880,125)
+spectrum.histogram.bins.plotter.map.minimum=3.0
+spectrum.histogram.bins.plotter.map.maximum=1000.0
+normaliser.signal.histogram.bins.file=normaliser.signal.histogram.mat
+spectrum.trace.window.bounds=(11,6,323,553)
+spectrum.image.map.log=true
+audio.offset=-410.0
+midi.output=10
+power.Signal=Power.bounds=(408,423,445,295)
+spectrum.image.map.minimum=5.0E-5
+normaliser.signal.plotter.window.bounds=(520,-3,527,141)
+waveform.image.map.maximum=7073.223999999999
+spectrum.trace.map.minimum=1.0E-5
+plotter.foreground=#8080ff
+waveform.plotter.map.minimum=-18850.125158400006
+waveform.plotter.map.maximum=18850.125158400006
+signal.image.window.bounds=(0,0,1038,50)
+waveform.trace.map.maximum=10000.0
+spectrum.image.map.maximum=0.008700000000000006
+spectrogram.Spectrogram.bounds=(12,7,405,551)
+window=hamming
+spectrum.plotter.window.bounds=(653,771,632,169)
+spectrum.trace.map.log=true
+outputs=64
+spectrum.trace.map.maximum=0.01
+spectrum.image.window.bounds=(-6,-2,526,86)
+type=0
+B.editor.window.bounds=(649,178,288,818)
+B.image.window.bounds=(531,362,270,295)
+W.map.symmetric=true
+Spectrum.bounds=(106,693,614,62)
+colormap=trace
+spectrogram.map.minimum=7.999999999999997E-5
+normaliser.rate=0.01
+midi.input=Yoke NT:  1
+normaliser.map.maximum=4000.0
+spectrum.histogram.bins.image.window.bounds=(322,10,178,518)
+spectrum.histogram.bins.Image.window.bounds=(43,93,178,554)
+signal.plotter.window.bounds=(414,555,755,142)
+spectrum.histogram.map.minimum=9.999999999999994E-8
+spectrogram.map.maximum=0.01
+plotter.background=000000
+histogram.bins.plotter.maximum=4000
+waveform.plotter.window.title=Waveform
+histogram.bin.plotter.minimum=3
+waveform.histogram.bins.plotter.map.maximum=9940.000000000022
+waveform.histogram.bins.plotter.map.minimum=3.0
+normaliser.map.minimum=0.0
+console.scrollBars=true
+audio.bigEndian=false
+rate=22050
+class2=samer.maths.ops.Zero
+regulator.target=8.0
+power.map.minimum=0.0
+step=256
+mixtures=128
+source.mixture.p=0.05
+B.MidiSynthEditor.bounds=(2,199,323,253)
+histogram.bins=128
+histogram.bin.plotter.maximum=4000
+source.class=samer.maths.random.Uniform
+y.image.window.bounds=(327,82,460,77)
+normalise=true
+cellsize=1
+spectrum.histogram.bins.image.map.maximum=2921.0
+power.window.bounds=(141,558,502,159)
+power.map.maximum=4000.0
+waveform.histogram.map.maximum=10000.0
+spectrum.plotter.map.minimum=-6.0
+spectrum.plotter.map.maximum=6.0
+histogram.map.minimum=-18.0
+sources=128
+noise.type=simple
+waveform.histogram.bins.file=waveform.histogram.mat
+source.type=mixture
+histogram.map.maximum=10.0
+audio.rate=11025
+spectrum.histogram.bins.plotter.window.bounds=(365,589,518,258)
+waveform.trace.window.bounds=(327,-14,270,1038)
+gamma=1.0
+spectrum.image.window.title=Power Spectrum
+MidiSynth.bounds=(0,0,308,186)
+audio.channels=1
+normaliser.signal.image.window.bounds=(0,0,880,79)
+console.bounds=(539,689,428,325)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/args.old	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+#properties
+#Thu Jul 14 14:56:12 BST 2011
+p.slider.map.maximum=0.001
+decay.slider.map.maximum=0.700
+Tasks.bounds=(290,499,225,145)
+matrix.file=walking_zither2
+spam.bounds=(660,114,266,204)
+MidiSynth.bounds=(1,24,345,140)
+midisynth.file=midisynth
+matrix.rowcolumn.trace.window.bounds=(557,374,256,86)
+regulated=true
+matrix.rowcolumn.plotter.window.bounds=(264,345,242,115)
+out.plotter.window.bounds=(4,22,128,118)
+MidiSynthEditor.bounds=(281,201,308,231)
+matrix.rowcolumn.image.window.bounds=(514,242,229,78)
+p=2.0E-5
+plotter.type=2
+midisynth.offset=32
+matrix.rowcolumn.editor.image.window.bounds=(377,604,505,69)
+midisynth.bounds=(281,22,232,176)
+out.image.window.bounds=(396,586,390,88)
+regulator.target=35.0
+midisynth.offset.bounds=(283,23,204,57)
+matrix.editor.window.bounds=(603,22,551,549)
+p.slider.map.minimum=2.357E-7
+decay.slider.map.minimum=0.001
+exposed.bounds=(3,22,276,590)
+matrix.image.window.bounds=(255,51,161,202)
+decay=0.01
+midisynth.factor=80.0
Binary file examples/sound/midi/basis.mat has changed
Binary file examples/sound/midi/diatonic.mat has changed
Binary file examples/sound/midi/midisynth has changed
Binary file examples/sound/midi/midisynth0 has changed
Binary file examples/sound/midi/midisynth1 has changed
Binary file examples/sound/midi/midisynth2 has changed
Binary file examples/sound/midi/midisynth4 has changed
Binary file examples/sound/midi/nice.mat has changed
Binary file examples/sound/midi/nice2.mat has changed
Binary file examples/sound/midi/pentatonic.mat has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/plinky.args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+#properties
+#Sat May 18 20:02:12 BST 2002
+regulated=true
+p=2.0E-5
+decay=0.996
+MidiSynthEditor.bounds=(0,537,290,176)
+matrix.rowcolumn.editor.image.window.bounds=(248,412,247,78)
+midisynth.offset=32
+Tasks.bounds=(290,499,225,145)
+matrix.editor.window.bounds=(248,137,247,271)
+regulator.target=35.0
+MidiSynth.bounds=(0,0,413,133)
+exposed.bounds=(0,137,248,396)
+midisynth.factor=80.0
+matrix.file=walking_zither2
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/plinky.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+(load "midi.scm")
+(import "samer.maths.random.*")
+
+(put "regulated" #t)
+(put "colormap" (redgreen))
+(put "symmetric" #t)
+
+(tasks)
+
+(define N 64)
+(define M 64)
+
+(define matrix	(Matrix. "matrix" M N))
+(define out   	(VVector. "out" N))
+(define vgen  	(VGenerator. "gen"))
+(define rowcol	(RowColumn. matrix))
+(define decay 	(VDouble. "decay" 0.002))
+
+(.setGenerator vgen (Binary.))
+
+
+; program 46 is cool!
+; so are 10, 12, 111
+(define midiin (VVector. "midiin" 64))
+(define synth (MidiSynth. midiin))
+(define m 0)
+
+(addtasks
+	(sub 4 (task
+		(.timesEquals matrix (- 1 (.get decay)))
+		(.add matrix vgen)
+		(.changed matrix)
+	))
+
+	(Ops.transfer rowcol midiin)
+	(Ops.update midiin)
+	synth
+	(task
+		(.setRow rowcol m)
+		(set! m (if (< m (- M 1)) (+ m 1) 0))
+	)
+)
+
+(define (load-file fn)
+	(let ((f (istream fn)))
+		(.load matrix f)
+		(.close f)))
+
+(define (f1) (load-file "walking_zither2"))
+(define (f2) (load-file "walking_zither3"))
+(define (f3) (load-file "walking_zither4"))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/plinky.silk	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+(import "samer.maths.random.*")
+(load "color.silk")
+
+(put "regulated" #t)
+(put "colormap" (redgreen))
+(put "symmetric" #t)
+
+(tasks)
+
+(define N 64)
+(define M 64)
+
+(define matrix	(Matrix. "matrix" M N))
+(define out   	(VVector. "out" N))
+(define vgen  	(VGenerator. "gen"))
+(define rowcol	(RowColumn. matrix))
+(define decay 	(VDouble. "decay" 0.998))
+
+(.setGenerator vgen (Binary.))
+
+
+; program 46 is cool!
+; so are 10, 12, 111
+(define midiin (VVector. "midiin" 64))
+(define synth (MidiSynth. midiin))
+(define m 0)
+
+(addtasks
+	(sub 4 (task
+		(.timesEquals matrix (.value$ decay))
+		(.add matrix vgen)
+		(.changed matrix)
+	))
+
+	(Ops.transfer rowcol midiin)
+	(Ops.update midiin)
+	synth
+	(task
+		(.setRow rowcol m)
+		(set! m (if (< m (- M 1)) (+ m 1) 0))
+	)
+)
+
+
+(define (load-file fn) 
+	(let ((f (istream fn)))
+		(.load matrix f)
+		(.close f)))
+
+(define (f1) (load-file "walking_zither2"))		
+(define (f2) (load-file "walking_zither3"))		
+(define (f3) (load-file "walking_zither4"))		
+
+
+
+
Binary file examples/sound/midi/scale2.mat has changed
Binary file examples/sound/midi/scale3.mat has changed
Binary file examples/sound/midi/scale4.mat has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/midi/synth.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,10 @@
+(import "javax.sound.midi.*")
+
+(define synth (MidiSystem.getSynthesizer))
+(define c0 (vector-ref (.getChannels synth) 0))
+(define (open) (.open synth))
+(define (close) (.close synth))
+(define (on pitch) (.noteOn c0 pitch 80))
+(define (off pitch) (.noteOff c0 pitch 0))
+
+(open)
Binary file examples/sound/midi/thirds-2.mat has changed
Binary file examples/sound/midi/thirds.mat has changed
Binary file examples/sound/midi/walking_zither2 has changed
Binary file examples/sound/midi/walking_zither3 has changed
Binary file examples/sound/midi/walking_zither4 has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/ICABundle.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+package samer.models;
+import samer.tools.*;
+import samer.core.*;
+import samer.maths.*;
+
+
+public class ICABundle extends AnonymousTask
+{
+	public ICA					ica;
+	public DiffScaler			scaler;
+	public GeneralisedExponential	genexp;
+	public BatchedTrainer	tscaler, tica, tgenexp;
+
+	public ICABundle(Vec x) {
+		ica=new ICA(x);
+		scaler=new DiffScaler(ica.output());
+		genexp=new GeneralisedExponential(scaler.output());
+
+		ica.setOutputModel(scaler);
+		scaler.setOutputModel(genexp);
+
+		tscaler=new BatchedTrainer(scaler.getScaleTrainer(),4);
+		tgenexp=new BatchedTrainer(genexp.getTrainer(),256);
+		tica   =new BatchedTrainer(ica.getTrainer(),x.size());
+	}
+
+	public void setFlushTask(Task t) { tica.setFlushTask(t); }
+	
+	public Task getSyncTask() {
+		return new AnonymousTask() {
+			ICAScalerSync sync=new ICAScalerSync(ica,scaler);
+			public void run() {
+				sync.run();
+				ica.execute("basis",Shell.env());
+			}
+		};
+	}
+
+	public void run() throws Exception {
+		ica.infer(); 
+		scaler.infer();
+		genexp.compute(); 
+		scaler.compute();
+		tgenexp.run(); 
+		tscaler.run(); 
+		tica.run();
+	}
+
+	public void dispose() {
+		tica.dispose();
+		tscaler.dispose();
+		tgenexp.dispose();
+		genexp.dispose();
+		scaler.dispose();
+		ica.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/Spectro.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,55 @@
+import samer.core.*;
+import samer.tools.*;
+import samer.maths.*;
+import samer.audio.*;
+import samer.units.*;
+import samer.functions.*;
+import samer.models.*;
+
+
+public class Spectro {
+	public static void main(String [] args) throws Exception {
+		new samer.core.shells.SwingShell();
+
+		CompoundTask	tasks=new CompoundTask();
+		RThread 			thread=new RThread(tasks);
+		AudioSource		source=new FileSource();
+		LineIn				linein=new LineIn(source,1024,512);
+		Scaler				scaler=new Scaler(linein.output());
+		IIDPrior			prior=new IIDPrior(scaler.output(),new Abs());
+		FFTVector		fft=new FFTVector(scaler.output());
+		VVector			y=new VVector("ft-magnitude",fft.size()/2);
+
+		scaler.setOutputModel(prior);		
+		tasks.addTask(linein);
+		tasks.addTask(scaler);
+		tasks.addTask(prior);
+		tasks.addTask(new BatchedTrainer(scaler.getTrainer(),4));
+		tasks.addTask(fft.calcTask());
+		tasks.addTask(fft.getFnPower(new Sqrt(),y));
+
+		/*  this shows how to put some defaults in the environment
+			they will affect any trace viewers for the ft-magnitude vector */
+		Shell.push(y.getNode());
+		Shell.put("trace.map.log","true");
+		Shell.put("trace.map.maxmimum",new Double(10));
+		Shell.put("trace.map.minimum",new Double(0.01));
+		Shell.pop();
+
+		y.getAgent().execute("trace",Shell.env());
+
+		{
+			Object [] commands = { "expose", "exit" };
+
+			Shell.interpret("expose");
+			Shell.exposeCommands(commands);
+			Shell.exposeCommands(thread);
+		}
+	}
+
+	public static void lineout() {
+		Shell.put("audio.scale",new Integer(1));
+		Shell.put("audio.rate",new Integer(22050));
+		// could create LineOut object to play stuff coming from linein
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,359 @@
+#properties
+#Thu Jul 14 14:15:19 BST 2011
+function.derivative.plotter.window.bounds=(375,357,426,239)
+sqrt.plotter.window.bounds=(0,0,208,122)
+waveform.image.cell.size=1
+joint.histogram.map.minimum=20.000
+stacker.output.reshaped.image.map.minimum=0.1
+editor.plotter.type=4
+mog.weights.learn.rate=1.2E-4
+coder.A.editor.window.bounds=(562,376,211,247)
+vodka.jelly=woozy
+scaler.offset=-451.602
+decay=0.995
+mog.sigmas.image.window.bounds=(301,388,219,108)
+coeff.editor.plotter.window.bounds=(0,0,214,494)
+filter.waveform.scaler.scale=0.080
+mog.means.rowcolumn.editor.plotter.window.bounds=(617,334,265,114)
+logprior.beta=0.01
+vector.editor.plotter.window.bounds=(20,218,362,178)
+shortspec.trace.window.bounds=(0,0,264,278)
+normaliser.signal.plotter.map.maximum=6.0
+director.bounds=(704,182,444,278)
+ft.mag.plotter.window.bounds=(382,298,264,120)
+ETA=0.75
+spectrum.stats.covariance.image.window.bounds=(523,366,256,278)
+basis.subrate.factor=10
+ft.power.diffScaler.output.image.window.bounds=(200,141,1078,105)
+x.editor.image.window.bounds=(0,0,230,59)
+filter.ft.mag.trace.window.bounds=(334,0,264,280)
+phi.plotter.window.bounds=(0,0,520,118)
+mog.weight.editor.window.bounds=(302,548,504,116)
+stacker.target.reshaped.image.map.minimum=5.0E-4
+ica.s.image.window.bounds=(876,426,264,49)
+v2.y.image.window.bounds=(559,525,221,65)
+signal.map.minimum=-1.0
+normaliser.signal.plotter.window.bounds=(505,372,512,113)
+function.derivative.plotter.y.map.minimum=-1.28
+sig.trace.map.symmetric=false
+z.plotter.window.bounds=(0,0,214,138)
+spectrum.trace.map.symmetric=false
+xtol=0.001
+mog.likelihood.map.symmetric=false
+ica.E(x).trace.window.bounds=(876,336,264,86)
+out.image.window.bounds=(497,548,268,67)
+midiin.editor.image.window.bounds=(309,502,444,71)
+scaler.scale.trace.map.minimum=-0.0
+mog.weights.editor.plotter.map.symmetric=false
+matrix.file=walking_zither2
+thread.priority=-0.1
+mog.means.editor.plotter.window.bounds=(300,313,224,178)
+spoon=58
+B.editor.window.bounds=(209,223,199,249)
+file=walking_zither2
+mog.likelihood.trace.window.bounds=(309,725,428,178)
+mixture.gauss2.variance=0.8
+sig.trace.map.maximum=2.999
+signalBlock.trace.window.bounds=(373,457,264,49)
+E.trace.map.minimum=0.0
+batch=512
+buffer(Product(filter(sqrt(filter(wavetable))),Gaussian)).plotter.window.bounds=(416,491,264,120)
+mog.p.editor.plotter.window.bounds=(0,0,214,138)
+mog.weights.editor.image.window.bounds=(25,172,333,118)
+normaliser.level.trace.map.minimum=15.999
+MidiSynthEditor.bounds=(-8,226,391,230)
+waveform.scaler.batch=4
+B.image.window.bounds=(0,0,146,54)
+joint.histogram.likelihood.trace.window.bounds=(84,573,293,96)
+matrix.editor.window.bounds=(660,438,186,213)
+XEPS=1.0E-6
+spoons=true
+mog.sigmas.editor.image.window.bounds=(238,1,270,125)
+ft.power.trace.window.bounds=(297,22,272,778)
+z.trace.window.bounds=(5,696,1036,292)
+function.plotter.y.map.maximum=1.099
+signal.trace.window.bounds=(21,69,290,147)
+ica.<phi(s)s'>.image.window.bounds=(264,0,264,278)
+waveform.trace.window.bounds=(1010,234,264,534)
+waveform.scaler.output.plotter.window.bounds=(627,566,264,75)
+sig1.trace.window.bounds=(400,408,287,145)
+coder.L.trace.window.bounds=(0,0,264,86)
+filter.waveform.scaler.offset=-0.010
+scaleNormaliser.output.trace.window.bounds=(272,281,264,278)
+filter.ft.mag.plotter.window.bounds=(382,298,264,120)
+z.histogram.bins.plotter.window.bounds=(607,461,214,138)
+filter.ft.mag.diffScaler.output.plotter.window.bounds=(352,166,520,120)
+plotter.type=0
+spectrum.stats.cov.image.window.bounds=(9,449,256,278)
+filter.mean.image.window.bounds=(765,605,146,59)
+scaleNormaliser.output.plotter.window.bounds=(0,0,264,118)
+ft.power.diffScaler.mu.plotter.window.bounds=(297,165,1025,118)
+loudness.plotter.window.bounds=(387,18,146,150)
+ft.power.diffScaler.w.plotter.window.bounds=(204,22,548,207)
+ftol=1.0E-6
+waveform.scaler.offset=1.554E-4
+image.width=256
+playlist.bounds=(0,0,415,185)
+genexp.plotter.window.bounds=(0,12,617,307)
+matrix.editor.button1=2.0
+learn.G.image.window.bounds=(264,0,264,278)
+g.plotter.window.bounds=(627,645,524,88)
+signalBlock.plotter.window.bounds=(669,409,149,145)
+x.editor.plotter.window.bounds=(360,621,268,91)
+vector.editor.image.button1=0.1
+x.plotter.window.bounds=(471,759,419,126)
+normaliser.mean.trace.window.bounds=(891,156,265,70)
+console.frame.bounds=(128,657,301,51)
+spectrum.trace.map.maximum=153.6
+stacker.output.image.map.minimum=0.089
+out.plotter.window.bounds=(20,124,623,115)
+function.derivative.plotter.x.map.maximum=4.0
+file.bounds=(111,141,520,341)
+mog.p.plotter.window.bounds=(0,0,235,98)
+Likelihood.trace.window.bounds=(310,509,423,213)
+color.title=Color
+filter.residual.image.window.bounds=(878,524,146,63)
+v2.A.editor.window.bounds=(0,0,243,306)
+ft.mag.diffScaler.w.file=diffscaler.w
+MidiSynth.bounds=(2,61,455,148)
+plotter.y.map.symmetric=false
+signalBlock.image.window.bounds=(700,431,86,49)
+phi(x).plotter.window.bounds=(360,522,264,118)
+flush.subrate.factor=1000
+genexp.derivative.plotter.window.bounds=(91,334,444,320)
+ica.W.rowcolumn.plotter.window.bounds=(104,451,510,118)
+waveform.linetrace.window.bounds=(268,358,227,284)
+matrix.rowcolumn.trace.window.bounds=(176,395,241,294)
+coeffs.editor.image.window.bounds=(530,731,273,103)
+filter.waveform.scaler.output.plotter.window.bounds=(627,566,264,175)
+v1.y.image.window.bounds=(558,454,223,67)
+ft.mag.diffScaler.output.stacker.output.reshaped.image.map.maximum=200.0
+ft.mag.diffScaler.batch=16
+cell.size=1
+scaler.output.trace.window.bounds=(0,461,264,278)
+function.plotter.window.bounds=(375,90,416,263)
+ft.power.image.window.bounds=(256,22,1025,37)
+sqrt.trace.window.bounds=(0,0,264,534)
+z.image.window.bounds=(479,637,268,40)
+vector.plotter.window.bounds=(498,531,302,121)
+audio.rate=22050
+waveform.image.window.bounds=(103,503,1038,58)
+midisynth.offset=32
+ZETA=0.125
+ica.rate=0.04
+matrix.plotter.window.bounds=(0,0,212,136)
+ft.mag.diffScaler.w.plotter.window.bounds=(304,298,264,120)
+stacker.output.reshaped.image.window.bounds=(303,249,264,49)
+outbuf.plotter.window.bounds=(202,728,242,141)
+mouse.exposed.bounds=(860,192,188,120)
+v2.x.image.window.bounds=(625,587,236,63)
+coder.W.image.window.bounds=(0,90,264,278)
+scaler.scale.trace.window.bounds=(0,-1,264,86)
+mog.means.image.window.bounds=(301,283,224,103)
+gtol=0.01
+mog.-log\ p(s).trace.window.bounds=(310,291,423,216)
+mog.weight.image.window.bounds=(412,259,221,103)
+ica.g.plotter.window.bounds=(360,278,264,118)
+waveform.scaler.offsetRate=3.2E-6
+jelly.bounds=(369,132,270,294)
+waveform.plotter.map.symmetric=true
+e.plotter.window.bounds=(34,408,520,118)
+mog.sigmas.editor.plotter.map.symmetric=false
+lineout.scale.bounds=(307,0,199,57)
+mog.sigmas.learn.rate=2.0E-4
+normaliser.level=693.855
+E.trace.window.bounds=(0,371,264,86)
+mog.means.learn.rate=0.001
+filter.waveform.scaler.batch=16
+matrix.plotter.rowcolumn.image.window.bounds=(318,43,268,40)
+joint.histogram.map.maximum=10000.0
+stacker.output.reshaped.image.map.maximum=100.0
+Image\ Viewer.bounds=(759,485,243,264)
+ica.C.rowcolumn.plotter.window.bounds=(521,856,525,118)
+energy.trace.window.bounds=(575,749,584,178)
+spectrum.editor.plotter.window.bounds=(282,31,583,169)
+ica.W.file=wave-256-ica
+matrix.rowcolumn.image.window.bounds=(417,470,266,55)
+GEPS=0.001
+x.histogram.bins.image.window.bounds=(693,378,146,115)
+ft.power.diffScaler.output.plotter.window.bounds=(320,440,520,120)
+sqrt.image.window.bounds=(250,621,520,49)
+ica.W.image.window.bounds=(780,524,264,278)
+writer.enable=false
+ica.L.trace.map.maximum=2000.0
+audio.buffer=8192
+buffer(oscillator).plotter.window.bounds=(303,0,520,120)
+filter.waveform.scaler.offsetRate=3.2E-6
+ica.G.plotter.window.bounds=(318,173,264,118)
+lineout.scale=1.0
+Tasks.bounds=(19,571,206,152)
+vector.editor.window.bounds=(497,165,268,87)
+stacker.target.reshaped.image.map.maximum=5.0
+FIR.coefficients.plotter.window.bounds=(397,315,475,142)
+mog.state.image.window.bounds=(470,885,419,91)
+signal.map.maximum=1.0
+spectrum.editor.image.window.bounds=(126,215,823,135)
+ica.learn.G.image.window.bounds=(916,91,264,278)
+scaler.scaleRate=-0.010
+subrate.factor=1
+mog.-log\ p(s).image.window.bounds=(0,0,146,39)
+spectrum.histogram.bins.rowcolumn.plotter.window.bounds=(948,487,208,122)
+ft.mag.diffScaler.stretch=0.001
+logprior.derivative.plotter.window.bounds=(0,0,254,158)
+E(x).trace.window.bounds=(891,246,264,86)
+test.spam=true
+sig.trace.window.bounds=(85,678,434,95)
+mixture.gauss2.mean=0.2
+waveform.scaler.scaleRate=0.01
+scaler.offset.trace.window.bounds=(360,196,264,86)
+energy.plotter.window.bounds=(0,0,206,134)
+matrix.image.window.bounds=(420,169,268,292)
+normaliser.signal.image.window.bounds=(505,350,513,51)
+output.plotter.window.bounds=(352,166,520,120)
+signal.trace.map.maximum=1.0
+playlist.files='("/Users/samer/Music/Bach/inv2part.wav" "/Users/samer/Music/Bach/inv3part.wav")
+mixture.gauss1.variance=0.1
+matrix.rowcolumn.editor.image.window.bounds=(394,259,409,95)
+mog.means.editor.window.bounds=(304,433,505,113)
+E.trace.map.maximum=1280.0
+ft-magnitude.trace.window.bounds=(4,22,256,534)
+ica.L.trace.window.bounds=(876,336,264,86)
+normaliser.level.trace.map.maximum=6399.999
+histogram.likelihood.trace.window.bounds=(891,336,264,278)
+regulated=true
+mog.p(s|x).image.window.bounds=(189,455,146,212)
+ica.learn.rate=0.012
+normaliser.level.trace.window.bounds=(891,85,266,67)
+y.image.window.bounds=(562,306,180,71)
+playlist.current=/mnt/sauce/music/Bach/wav/inv3part.wav
+w1.color.bounds=(365,495,381,382)
+mog.means.plotter.window.bounds=(0,0,214,138)
+filter.residual.histogram.bins.image.window.bounds=(690,367,166,130)
+directory=/mnt/sauce/music/Bach/wav
+mog.p.editor.image.window.bounds=(0,0,297,100)
+size=1024
+linebuf.plotter.window.bounds=(39,125,798,142)
+coder.learn.deltas.image.window.bounds=(264,90,264,278)
+bits.image.window.bounds=(248,688,117,49)
+v1.e.image.window.bounds=(0,0,146,47)
+scaleNormaliser.scale.plotter.window.bounds=(0,0,264,118)
+pdf.plotter.window.bounds=(591,692,254,158)
+mog.sigmas.editor.window.bounds=(304,304,503,129)
+trace.scrollStep=1
+buffer(filter(wavetable)).plotter.window.bounds=(4,22,520,120)
+x^2.plotter.window.bounds=(0,0,418,134)
+mouse.y.trace.window.bounds=(536,252,260,164)
+midiin.image.window.bounds=(444,540,270,58)
+histogram.bins.rowcolumn.plotter.window.bounds=(891,618,208,122)
+logprior.strength=0.0
+audio.exposed.bounds=(980,190,229,372)
+ica.s.plotter.window.bounds=(151,296,264,118)
+exposed.bounds=(1,22,296,778)
+noise=(Gaussian.)
+audio.offset=-507.6
+step=384
+sig.trace.map.minimum=0.002
+e(x).plotter.window.bounds=(360,644,264,118)
+table.editor.plotter.window.bounds=(237,265,423,246)
+directory.bounds=(698,81,443,295)
+normaliser.signal.trace.window.bounds=(891,336,264,278)
+mog.likelihood.map.minimum=-0.0
+Desktop.bounds=(206,3,1014,862)
+buffer(Product(filter(filter(wavetable)),Gaussian)).plotter.window.bounds=(403,470,264,120)
+stacker.target.reshaped.image.window.bounds=(460,564,308,64)
+v2.e.image.window.bounds=(0,0,146,39)
+spectrum.image.window.bounds=(504,404,517,46)
+coder.C.image.window.bounds=(264,90,264,278)
+canvas.bounds=(0,0,630,520)
+function.plotter.y.map.minimum=-0.099
+filter.playlist.current=/home/music/wav/22kmono/bach/sonata2/grave.wav
+waveform.scaler.scale=0.011
+map.symmetric=true
+stacker.output.image.window.bounds=(0,688,1280,49)
+vector.trace.window.bounds=(717,546,339,176)
+mog.weights.plotter.window.bounds=(641,632,214,138)
+x.trace.window.bounds=(570,433,270,111)
+mogpdf.plotter.window.bounds=(661,822,254,95)
+coeffs.editor.plotter.map.maximum=2.0
+smoothness=5.0
+ica.<phi(s)s'>.plotter.window.bounds=(0,0,264,118)
+Plotter.bounds=(356,62,408,395)
+filter.ft.mag.diffScaler.w.plotter.window.bounds=(437,433,264,120)
+tasklist.bounds=(887,0,245,185)
+trace.bounds=(10,821,290,99)
+vector.histogram.bins.image.window.bounds=(325,41,144,292)
+spectrum.histogram.likelihood.trace.window.bounds=(273,283,173,534)
+mixture.p=0.5
+waveform.plotter.map.maximum=36000.0
+russian.vodka.jelly=snoozy
+spectrum.trace.map.minimum=3.2E-5
+scaleNormaliser.scale.editor.plotter.window.bounds=(282,629,264,118)
+coder.learn.rate=0.16
+mat.image.window.bounds=(0,0,264,278)
+e.trace.window.bounds=(0,89,264,278)
+normaliser.mean=-444.473
+vector.editor.button1=0.1
+test.file=test3.silk
+scaler.E.trace.window.bounds=(360,376,264,86)
+p=1.0E-5
+ica.C.image.window.bounds=(516,524,264,278)
+scaler.output.plotter.window.bounds=(627,566,264,75)
+v1.B.editor.window.bounds=(0,0,187,201)
+wavewriter.scale.bounds=(305,57,199,57)
+midisynth.factor=120.0
+v1.B.image.window.bounds=(0,0,146,54)
+factor=58
+ft.mag.diffScaler.output.stacker.output.reshaped.image.window.bounds=(303,249,264,49)
+image.height=16
+ica.learn.G.rowcolumn.plotter.window.bounds=(166,816,937,118)
+matrix.plotter.rowcolumn.plotter.window.bounds=(5,159,212,136)
+histogram.likelihood.plotter.window.bounds=(891,383,264,100)
+VState.Optimiser.bounds=(0,0,287,592)
+matrix.rowcolumn.plotter.window.bounds=(0,0,212,136)
+scaler.NlogK.trace.window.bounds=(0,551,264,86)
+joint.histogram.bins.image.window.bounds=(701,314,163,193)
+w1.scale=0.01
+ft.mag.diffScaler.output.stacker.output.reshaped.image.map.minimum=1.0
+spectrum.trace.window.bounds=(284,206,256,294)
+normaliser.rate=0.004
+jelly=wobbly
+vector.reshaped.image.window.bounds=(0,0,146,294)
+mog.weights.editor.plotter.window.bounds=(300,492,225,127)
+mog.-log\ p(s).plotter.window.bounds=(469,627,427,129)
+generator=(oscillator "osc1" 0.1)
+stacker.output.reshaped.image.map.symmetric=false
+waveform.plotter.window.bounds=(364,356,512,118)
+scaler.scale=4715.263
+mog.sigmas.editor.plotter.window.bounds=(300,196,224,117)
+scaler.offsetRate=3.200E-6
+filter.mean.plotter.window.bounds=(637,652,214,138)
+regulator.target=46.733
+source=line
+matrix.rowcolumn.editor.plotter.window.bounds=(613,573,367,148)
+ft.power.diffScaler.output.trace.window.bounds=(301,22,272,778)
+coder.sigma=0.001
+trace.map.symmetric=false
+coeffs.editor.plotter.window.bounds=(283,22,584,177)
+ft.mag.diffScaler.scale=0.01
+ica.s.trace.window.bounds=(0,89,264,278)
+filter.waveform.scaler.scaleRate=0.01
+infile=/mnt/sauce/music/projwav/beethoven/piano/fm-1.wav
+ica.e(x).trace.window.bounds=(876,54,264,278)
+histogram.bins.image.window.bounds=(162,599,86,278)
+function.plotter.x.map.maximum=4.0
+vector.image.window.bounds=(113,544,404,72)
+ica.log\ |W|=-580.779
+x.image.window.bounds=(373,381,265,83)
+ica.W.rowcolumn.image.window.bounds=(248,190,264,49)
+spectrum.plotter.window.bounds=(76,580,813,116)
+ica.G.image.window.bounds=(283,0,264,278)
+vector.editor.image.window.bounds=(371,114,292,102)
+histogram.sumL.trace.window.bounds=(891,156,264,86)
+spectrum.histogram.bins.image.window.bounds=(451,284,104,534)
+test.color=\#465f90
+out.trace.window.bounds=(13,401,1036,292)
+mog.sigmas.rowcolumn.editor.plotter.window.bounds=(623,452,236,138)
+w1.color=\#817a9b
+ica.e(x).plotter.window.bounds=(333,471,264,118)
+spectrum.histogram.sumL.trace.window.bounds=(297,845,272,83)
+histogram.bins=96
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/args.alt	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,4 @@
+#properties
+#Mon Jun 09 17:53:39 BST 2003
+exposed.bounds=(9,78,453,167)
+console.frame.bounds=(4,22,220,51)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/args.old	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,352 @@
+#properties
+#Thu Jul 14 12:56:51 BST 2011
+function.derivative.plotter.window.bounds=(375,357,426,239)
+sqrt.plotter.window.bounds=(0,0,208,122)
+waveform.image.cell.size=1
+joint.histogram.map.minimum=20.000
+stacker.output.reshaped.image.map.minimum=0.1
+editor.plotter.type=4
+mog.weights.learn.rate=1.2E-4
+coder.A.editor.window.bounds=(562,376,211,247)
+vodka.jelly=woozy
+scaler.offset=-451.602
+decay=0.995
+mog.sigmas.image.window.bounds=(301,388,219,108)
+coeff.editor.plotter.window.bounds=(0,0,214,494)
+filter.waveform.scaler.scale=0.080
+mog.means.rowcolumn.editor.plotter.window.bounds=(617,334,265,114)
+logprior.beta=0.01
+vector.editor.plotter.window.bounds=(20,218,362,178)
+shortspec.trace.window.bounds=(0,0,264,278)
+normaliser.signal.plotter.map.maximum=6.0
+director.bounds=(704,182,444,278)
+ft.mag.plotter.window.bounds=(382,298,264,120)
+ETA=0.75
+spectrum.stats.covariance.image.window.bounds=(523,366,256,278)
+basis.subrate.factor=10
+x.editor.image.window.bounds=(0,0,230,59)
+filter.ft.mag.trace.window.bounds=(334,0,264,280)
+phi.plotter.window.bounds=(0,0,520,118)
+mog.weight.editor.window.bounds=(302,548,504,116)
+stacker.target.reshaped.image.map.minimum=5.0E-4
+ica.s.image.window.bounds=(876,426,264,49)
+v2.y.image.window.bounds=(559,525,221,65)
+signal.map.minimum=-1.0
+normaliser.signal.plotter.window.bounds=(505,372,512,113)
+function.derivative.plotter.y.map.minimum=-1.28
+sig.trace.map.symmetric=false
+z.plotter.window.bounds=(0,0,214,138)
+spectrum.trace.map.symmetric=false
+xtol=0.001
+mog.likelihood.map.symmetric=false
+ica.E(x).trace.window.bounds=(876,336,264,86)
+out.image.window.bounds=(497,548,268,67)
+midiin.editor.image.window.bounds=(309,502,444,71)
+scaler.scale.trace.map.minimum=-0.0
+mog.weights.editor.plotter.map.symmetric=false
+matrix.file=walking_zither2
+thread.priority=-0.1
+mog.means.editor.plotter.window.bounds=(300,313,224,178)
+spoon=58
+B.editor.window.bounds=(209,223,199,249)
+file=walking_zither2
+mog.likelihood.trace.window.bounds=(309,725,428,178)
+mixture.gauss2.variance=0.8
+sig.trace.map.maximum=2.999
+signalBlock.trace.window.bounds=(373,457,264,49)
+E.trace.map.minimum=0.0
+batch=512
+buffer(Product(filter(sqrt(filter(wavetable))),Gaussian)).plotter.window.bounds=(416,491,264,120)
+mog.p.editor.plotter.window.bounds=(0,0,214,138)
+mog.weights.editor.image.window.bounds=(25,172,333,118)
+normaliser.level.trace.map.minimum=15.999
+MidiSynthEditor.bounds=(-8,226,391,230)
+waveform.scaler.batch=8
+B.image.window.bounds=(0,0,146,54)
+joint.histogram.likelihood.trace.window.bounds=(84,573,293,96)
+matrix.editor.window.bounds=(660,438,186,213)
+XEPS=1.0E-6
+spoons=true
+mog.sigmas.editor.image.window.bounds=(238,1,270,125)
+z.trace.window.bounds=(5,696,1036,292)
+function.plotter.y.map.maximum=1.099
+signal.trace.window.bounds=(21,69,290,147)
+ica.<phi(s)s'>.image.window.bounds=(264,0,264,278)
+waveform.trace.window.bounds=(1010,234,264,534)
+waveform.scaler.output.plotter.window.bounds=(627,566,264,75)
+sig1.trace.window.bounds=(400,408,287,145)
+coder.L.trace.window.bounds=(0,0,264,86)
+filter.waveform.scaler.offset=-0.010
+scaleNormaliser.output.trace.window.bounds=(272,281,264,278)
+filter.ft.mag.plotter.window.bounds=(382,298,264,120)
+z.histogram.bins.plotter.window.bounds=(607,461,214,138)
+filter.ft.mag.diffScaler.output.plotter.window.bounds=(352,166,520,120)
+plotter.type=0
+spectrum.stats.cov.image.window.bounds=(9,449,256,278)
+filter.mean.image.window.bounds=(765,605,146,59)
+scaleNormaliser.output.plotter.window.bounds=(0,0,264,118)
+loudness.plotter.window.bounds=(387,18,146,150)
+ftol=1.0E-6
+waveform.scaler.offset=1.554E-4
+image.width=256
+playlist.bounds=(0,0,415,185)
+genexp.plotter.window.bounds=(0,12,617,307)
+matrix.editor.button1=2.0
+learn.G.image.window.bounds=(264,0,264,278)
+g.plotter.window.bounds=(627,645,524,88)
+signalBlock.plotter.window.bounds=(669,409,149,145)
+x.editor.plotter.window.bounds=(360,621,268,91)
+vector.editor.image.button1=0.1
+x.plotter.window.bounds=(471,759,419,126)
+normaliser.mean.trace.window.bounds=(891,156,265,70)
+console.frame.bounds=(128,657,301,51)
+spectrum.trace.map.maximum=153.6
+stacker.output.image.map.minimum=0.089
+out.plotter.window.bounds=(20,124,623,115)
+function.derivative.plotter.x.map.maximum=4.0
+file.bounds=(111,141,520,341)
+mog.p.plotter.window.bounds=(0,0,235,98)
+Likelihood.trace.window.bounds=(310,509,423,213)
+color.title=Color
+filter.residual.image.window.bounds=(878,524,146,63)
+v2.A.editor.window.bounds=(0,0,243,306)
+ft.mag.diffScaler.w.file=diffscaler.w
+MidiSynth.bounds=(2,61,455,148)
+plotter.y.map.symmetric=false
+signalBlock.image.window.bounds=(700,431,86,49)
+phi(x).plotter.window.bounds=(360,522,264,118)
+flush.subrate.factor=1000
+genexp.derivative.plotter.window.bounds=(91,334,444,320)
+ica.W.rowcolumn.plotter.window.bounds=(104,451,510,118)
+waveform.linetrace.window.bounds=(268,358,227,284)
+matrix.rowcolumn.trace.window.bounds=(176,395,241,294)
+coeffs.editor.image.window.bounds=(530,731,273,103)
+filter.waveform.scaler.output.plotter.window.bounds=(627,566,264,175)
+v1.y.image.window.bounds=(558,454,223,67)
+ft.mag.diffScaler.output.stacker.output.reshaped.image.map.maximum=200.0
+ft.mag.diffScaler.batch=16
+cell.size=1
+scaler.output.trace.window.bounds=(0,461,264,278)
+function.plotter.window.bounds=(375,90,416,263)
+sqrt.trace.window.bounds=(0,0,264,534)
+z.image.window.bounds=(479,637,268,40)
+vector.plotter.window.bounds=(498,531,302,121)
+audio.rate=22050
+waveform.image.window.bounds=(103,503,1038,58)
+midisynth.offset=32
+ZETA=0.125
+ica.rate=0.04
+matrix.plotter.window.bounds=(0,0,212,136)
+ft.mag.diffScaler.w.plotter.window.bounds=(304,298,264,120)
+stacker.output.reshaped.image.window.bounds=(303,249,264,49)
+outbuf.plotter.window.bounds=(202,728,242,141)
+mouse.exposed.bounds=(860,192,188,120)
+v2.x.image.window.bounds=(625,587,236,63)
+coder.W.image.window.bounds=(0,90,264,278)
+scaler.scale.trace.window.bounds=(0,-1,264,86)
+mog.means.image.window.bounds=(301,283,224,103)
+gtol=0.01
+mog.-log\ p(s).trace.window.bounds=(310,291,423,216)
+mog.weight.image.window.bounds=(412,259,221,103)
+ica.g.plotter.window.bounds=(360,278,264,118)
+waveform.scaler.offsetRate=3.2E-6
+jelly.bounds=(369,132,270,294)
+waveform.plotter.map.symmetric=true
+e.plotter.window.bounds=(34,408,520,118)
+mog.sigmas.editor.plotter.map.symmetric=false
+lineout.scale.bounds=(307,0,199,57)
+mog.sigmas.learn.rate=2.0E-4
+normaliser.level=693.855
+E.trace.window.bounds=(0,371,264,86)
+mog.means.learn.rate=0.001
+filter.waveform.scaler.batch=16
+matrix.plotter.rowcolumn.image.window.bounds=(318,43,268,40)
+joint.histogram.map.maximum=10000.0
+stacker.output.reshaped.image.map.maximum=100.0
+Image\ Viewer.bounds=(759,485,243,264)
+ica.C.rowcolumn.plotter.window.bounds=(521,856,525,118)
+energy.trace.window.bounds=(575,749,584,178)
+spectrum.editor.plotter.window.bounds=(282,31,583,169)
+ica.W.file=wave-256-ica
+matrix.rowcolumn.image.window.bounds=(417,470,266,55)
+GEPS=0.001
+x.histogram.bins.image.window.bounds=(693,378,146,115)
+sqrt.image.window.bounds=(250,621,520,49)
+ica.W.image.window.bounds=(780,524,264,278)
+writer.enable=false
+ica.L.trace.map.maximum=2000.0
+audio.buffer=8192
+buffer(oscillator).plotter.window.bounds=(303,0,520,120)
+filter.waveform.scaler.offsetRate=3.2E-6
+ica.G.plotter.window.bounds=(318,173,264,118)
+lineout.scale=1.0
+Tasks.bounds=(19,571,206,152)
+vector.editor.window.bounds=(497,165,268,87)
+stacker.target.reshaped.image.map.maximum=5.0
+FIR.coefficients.plotter.window.bounds=(397,315,475,142)
+mog.state.image.window.bounds=(470,885,419,91)
+signal.map.maximum=1.0
+spectrum.editor.image.window.bounds=(126,215,823,135)
+ica.learn.G.image.window.bounds=(916,91,264,278)
+scaler.scaleRate=-0.010
+subrate.factor=1
+mog.-log\ p(s).image.window.bounds=(0,0,146,39)
+spectrum.histogram.bins.rowcolumn.plotter.window.bounds=(948,487,208,122)
+ft.mag.diffScaler.stretch=0.001
+logprior.derivative.plotter.window.bounds=(0,0,254,158)
+E(x).trace.window.bounds=(891,246,264,86)
+test.spam=true
+sig.trace.window.bounds=(85,678,434,95)
+mixture.gauss2.mean=0.2
+waveform.scaler.scaleRate=0.01
+scaler.offset.trace.window.bounds=(360,196,264,86)
+energy.plotter.window.bounds=(0,0,206,134)
+matrix.image.window.bounds=(420,169,268,292)
+normaliser.signal.image.window.bounds=(505,350,513,51)
+output.plotter.window.bounds=(352,166,520,120)
+signal.trace.map.maximum=1.0
+playlist.files='("/Users/samer/Music/Bach/inv2part.wav" "/Users/samer/Music/Bach/inv3part.wav")
+mixture.gauss1.variance=0.1
+matrix.rowcolumn.editor.image.window.bounds=(394,259,409,95)
+mog.means.editor.window.bounds=(304,433,505,113)
+E.trace.map.maximum=1280.0
+ft-magnitude.trace.window.bounds=(4,22,256,534)
+ica.L.trace.window.bounds=(876,336,264,86)
+normaliser.level.trace.map.maximum=6399.999
+histogram.likelihood.trace.window.bounds=(891,336,264,278)
+regulated=true
+mog.p(s|x).image.window.bounds=(189,455,146,212)
+ica.learn.rate=0.012
+normaliser.level.trace.window.bounds=(891,85,266,67)
+y.image.window.bounds=(562,306,180,71)
+playlist.current=/mnt/sauce/music/Bach/wav/inv3part.wav
+w1.color.bounds=(365,495,381,382)
+mog.means.plotter.window.bounds=(0,0,214,138)
+filter.residual.histogram.bins.image.window.bounds=(690,367,166,130)
+directory=/mnt/sauce/music/Bach/wav
+mog.p.editor.image.window.bounds=(0,0,297,100)
+size=1024
+linebuf.plotter.window.bounds=(39,125,798,142)
+coder.learn.deltas.image.window.bounds=(264,90,264,278)
+bits.image.window.bounds=(248,688,117,49)
+v1.e.image.window.bounds=(0,0,146,47)
+scaleNormaliser.scale.plotter.window.bounds=(0,0,264,118)
+pdf.plotter.window.bounds=(591,692,254,158)
+mog.sigmas.editor.window.bounds=(304,304,503,129)
+trace.scrollStep=1
+buffer(filter(wavetable)).plotter.window.bounds=(4,22,520,120)
+x^2.plotter.window.bounds=(0,0,418,134)
+mouse.y.trace.window.bounds=(536,252,260,164)
+midiin.image.window.bounds=(444,540,270,58)
+histogram.bins.rowcolumn.plotter.window.bounds=(891,618,208,122)
+logprior.strength=0.0
+audio.exposed.bounds=(980,190,229,372)
+ica.s.plotter.window.bounds=(151,296,264,118)
+exposed.bounds=(4,22,302,778)
+noise=(Gaussian.)
+audio.offset=-507.6
+step=384
+sig.trace.map.minimum=0.002
+e(x).plotter.window.bounds=(360,644,264,118)
+table.editor.plotter.window.bounds=(237,265,423,246)
+directory.bounds=(698,81,443,295)
+normaliser.signal.trace.window.bounds=(891,336,264,278)
+mog.likelihood.map.minimum=-0.0
+Desktop.bounds=(206,3,1014,862)
+buffer(Product(filter(filter(wavetable)),Gaussian)).plotter.window.bounds=(403,470,264,120)
+stacker.target.reshaped.image.window.bounds=(460,564,308,64)
+v2.e.image.window.bounds=(0,0,146,39)
+spectrum.image.window.bounds=(504,404,517,46)
+coder.C.image.window.bounds=(264,90,264,278)
+canvas.bounds=(0,0,630,520)
+function.plotter.y.map.minimum=-0.099
+filter.playlist.current=/home/music/wav/22kmono/bach/sonata2/grave.wav
+waveform.scaler.scale=0.011
+map.symmetric=true
+stacker.output.image.window.bounds=(0,688,1280,49)
+vector.trace.window.bounds=(717,546,339,176)
+mog.weights.plotter.window.bounds=(641,632,214,138)
+x.trace.window.bounds=(570,433,270,111)
+mogpdf.plotter.window.bounds=(661,822,254,95)
+coeffs.editor.plotter.map.maximum=2.0
+smoothness=5.0
+ica.<phi(s)s'>.plotter.window.bounds=(0,0,264,118)
+Plotter.bounds=(356,62,408,395)
+filter.ft.mag.diffScaler.w.plotter.window.bounds=(437,433,264,120)
+tasklist.bounds=(887,0,245,185)
+trace.bounds=(10,821,290,99)
+vector.histogram.bins.image.window.bounds=(325,41,144,292)
+spectrum.histogram.likelihood.trace.window.bounds=(273,283,173,534)
+mixture.p=0.5
+waveform.plotter.map.maximum=36000.0
+russian.vodka.jelly=snoozy
+spectrum.trace.map.minimum=3.2E-5
+scaleNormaliser.scale.editor.plotter.window.bounds=(282,629,264,118)
+coder.learn.rate=0.16
+mat.image.window.bounds=(0,0,264,278)
+e.trace.window.bounds=(0,89,264,278)
+normaliser.mean=-444.473
+vector.editor.button1=0.1
+scaler.E.trace.window.bounds=(360,376,264,86)
+test.file=test3.silk
+p=1.0E-5
+ica.C.image.window.bounds=(516,524,264,278)
+scaler.output.plotter.window.bounds=(627,566,264,75)
+wavewriter.scale.bounds=(305,57,199,57)
+v1.B.editor.window.bounds=(0,0,187,201)
+midisynth.factor=120.0
+factor=58
+v1.B.image.window.bounds=(0,0,146,54)
+ft.mag.diffScaler.output.stacker.output.reshaped.image.window.bounds=(303,249,264,49)
+image.height=16
+ica.learn.G.rowcolumn.plotter.window.bounds=(166,816,937,118)
+matrix.plotter.rowcolumn.plotter.window.bounds=(5,159,212,136)
+histogram.likelihood.plotter.window.bounds=(891,383,264,100)
+matrix.rowcolumn.plotter.window.bounds=(0,0,212,136)
+VState.Optimiser.bounds=(0,0,287,592)
+scaler.NlogK.trace.window.bounds=(0,551,264,86)
+w1.scale=0.01
+joint.histogram.bins.image.window.bounds=(701,314,163,193)
+ft.mag.diffScaler.output.stacker.output.reshaped.image.map.minimum=1.0
+spectrum.trace.window.bounds=(284,206,256,294)
+jelly=wobbly
+normaliser.rate=0.004
+vector.reshaped.image.window.bounds=(0,0,146,294)
+mog.-log\ p(s).plotter.window.bounds=(469,627,427,129)
+mog.weights.editor.plotter.window.bounds=(300,492,225,127)
+generator=(oscillator "osc1" 0.1)
+stacker.output.reshaped.image.map.symmetric=false
+waveform.plotter.window.bounds=(364,356,512,118)
+scaler.offsetRate=3.200E-6
+mog.sigmas.editor.plotter.window.bounds=(300,196,224,117)
+scaler.scale=4715.263
+filter.mean.plotter.window.bounds=(637,652,214,138)
+regulator.target=46.733
+source=line
+matrix.rowcolumn.editor.plotter.window.bounds=(613,573,367,148)
+coder.sigma=0.001
+trace.map.symmetric=false
+coeffs.editor.plotter.window.bounds=(283,22,584,177)
+ft.mag.diffScaler.scale=0.01
+ica.s.trace.window.bounds=(0,89,264,278)
+filter.waveform.scaler.scaleRate=0.01
+infile=/mnt/sauce/music/projwav/beethoven/piano/fm-1.wav
+ica.e(x).trace.window.bounds=(876,54,264,278)
+histogram.bins.image.window.bounds=(162,599,86,278)
+vector.image.window.bounds=(113,544,404,72)
+function.plotter.x.map.maximum=4.0
+x.image.window.bounds=(373,381,265,83)
+ica.log\ |W|=-580.779
+ica.W.rowcolumn.image.window.bounds=(248,190,264,49)
+spectrum.plotter.window.bounds=(76,580,813,116)
+ica.G.image.window.bounds=(283,0,264,278)
+vector.editor.image.window.bounds=(371,114,292,102)
+spectrum.histogram.bins.image.window.bounds=(451,284,104,534)
+histogram.sumL.trace.window.bounds=(891,156,264,86)
+out.trace.window.bounds=(13,401,1036,292)
+test.color=\#465f90
+mog.sigmas.rowcolumn.editor.plotter.window.bounds=(623,452,236,138)
+ica.e(x).plotter.window.bounds=(333,471,264,118)
+w1.color=\#817a9b
+spectrum.histogram.sumL.trace.window.bounds=(297,845,272,83)
+histogram.bins=96
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/audio-player/args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+#properties
+#Wed Jul 20 00:03:42 BST 2011
+ft.power.diffScaler.tension=200.0
+ft.power.diffScaler.output.plotter.window.bounds=(782,22,513,118)
+ft.power.diffScaler.mu.plotter.window.bounds=(753,243,513,118)
+ft.power.diffScaler.genexp.rate=1.0E-5
+waveform.scaler.scale.trace.window.bounds=(563,151,256,86)
+ft.power.diffScaler.output.trace.window.bounds=(295,143,263,535)
+ft.power.diffScaler.genexp.e.trace.map.minimum=0.001
+ft.power.diffScaler.w.plotter.map.minimum=0.100
+ft.power.diffScaler.genexp.e.trace.window.bounds=(561,141,256,535)
+ft.power.diffScaler.genexp.alpha.file=diffScaler.genexp.alpha
+waveform.scaler.scaleRate=0.01
+ft.power.diffScaler.genexp.e.plotter.window.bounds=(4,22,513,118)
+ft.power.diffScaler.genexp.alpha.plotter.window.bounds=(764,22,513,118)
+waveform.plotter.window.bounds=(4,22,1024,118)
+ft.power.diffScaler.genexp.e.trace.map.maximum=20.0
+ft.power.diffScaler.w.plotter.map.maximum=39999.999
+ft.power.diffScaler.output.image.window.bounds=(518,22,517,87)
+ft.power.diffScaler.w.file=diffScaler.w
+ft.power.trace.window.bounds=(307,164,256,535)
+ft.power.diffScaler.scaleRate=0.01
+ft.power.diffScaler.w.plotter.window.bounds=(296,22,513,118)
+ft.power.diffScaler.output.trace.map.minimum=0.100
+exposed.bounds=(6,22,325,772)
+ft.power.diffScaler.output.trace.map.maximum=5000.0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/audio-player/args.old	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+#properties
+#Tue Jul 19 22:56:16 BST 2011
+waveform.scaler.scale.trace.window.bounds=(563,151,256,86)
+ft.power.diffScaler.tension=200.0
+ft.power.diffScaler.w.plotter.window.bounds=(296,22,513,118)
+ft.power.diffScaler.scaleRate=0.01
+ft.power.diffScaler.output.trace.map.maximum=3999.999
+ft.power.diffScaler.output.trace.window.bounds=(311,162,434,535)
+ft.power.diffScaler.output.plotter.window.bounds=(782,22,513,118)
+ft.power.diffScaler.output.trace.map.minimum=0.100
+waveform.plotter.window.bounds=(4,22,1024,118)
+ft.power.trace.window.bounds=(307,164,256,535)
+ft.power.diffScaler.output.image.window.bounds=(518,22,517,87)
+ft.power.diffScaler.mu.plotter.window.bounds=(563,264,513,118)
+exposed.bounds=(6,141,303,653)
+waveform.scaler.scaleRate=0.01
Binary file examples/sound/sampled/audio-player/diffScaler.genexp.alpha has changed
Binary file examples/sound/sampled/audio-player/diffScaler.w has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/audio-player/test.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+(load "audio.scm")
+(load "filelist.scm")
+(load "lineout.scm")
+(load "functions.scm")
+(load "models.scm")
+
+(define hop 512)
+(define fs  22050)
+
+(put "regulator.target" (* 1.04 (/ fs hop)))
+(put "regulator.regulated" "true")
+(put "trace.map.symmetric" #f)
+(put "trace.map.log" #t)
+(put "trace.scroll" #t)
+(put "ft.power.trace.map.maximum" 60)
+(put "ft.power.trace.map.minimum" 0.005)
+(put "diffScaler.offsetRate" 0)
+(put "diffScaler.scaleRate" 0.01)
+(put "scaler.scaleRate" 0.01)
+
+(define f (mono fs))
+(define s (filesource f))
+(define lin (linein s 1024 hop))
+(define lou (lineout (linesnk-buf f 1024) lin hop))
+(exec lin "plotter")
+
+(set-playlist (map File. '(
+		"Tesri-A.mp3"
+		"Tesri-B.mp3"
+		"The Amateur View-A.mp3"
+		"The Amateur View-B.mp3"
+		"HotelMorgen-A.ogg"
+		"HotelMorgen-B.ogg"))) 
+
+(define x (norm lin))
+(define y (ft-power (ft-vec x)))
+(define z (smoothscale y genexp-spec))
+(exec z "trace")
+
+(exec (viewable "ft.power.diffScaler.w") "load")
+(exec (viewable "ft.power.diffScaler.genexp.alpha") "load")
+(expose)
+
+;(start)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/audioio.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,41 @@
+;;; Simple program that streams audio input to audio output
+;;; and a WAV file called out.wav.
+;;; Uses raw LineSource and LineSink, not LineIn and LineOut objects
+;;; (see lineio.scm)
+
+(load "audio.scm")
+
+
+(tasks)
+(define fmt (mono 44100))	; see audio.scm for other options
+
+; this is set up to read audio from one mixer and write out to
+; another. This is because my main mixer, though it does full
+; duplex, ends up feeding back because tritonus alsa mixer is
+; mixing all the input channels on the sound card, rather than
+; letting me choose just the line input.
+(define in (linesrc (mixer-n 1) fmt))
+(define out (linesnk (mixer-n 2) fmt)) 
+(define wav (filesnk "out.wav" fmt))
+
+
+(define N 1024)	; frame size for audio transfers
+(define x (VVector. "x" N))	; frame of audio data
+
+; this sets up the tasks to run in the main loop, but
+; nothing happens until the loop is started
+(addtasks
+	(.reader in (.array x) 0 N)	; read N samples into x
+	(Ops.update x)						; to update GUI
+	; the switches mean that the tasks can be switched in
+	; and out of the main loop on the fly through the GUI
+	(node "writer" (switch (.writer wav (.array x) 0 N)))
+	(node "lineout" (switch (.writer out (.array x) 0 N)))
+)
+
+(expose)							; show GUI
+(expose (.getScale out))	; show GUI for lineout scaling
+(expose (.getScale wav))	; ditto for file out scaling
+
+(display "Type (start) or press start button to start main loop.\n")
+
Binary file examples/sound/sampled/diffscaler.w has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/firfilter.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+; Take audio from line in,
+; apply FIR filter defined in the frequency domain,
+; and send out
+(load "audio.scm")
+(load "synthesis.scm")
+
+(put "regulated" #f)
+(put "map.symmetric" #t)
+
+(tasks)
+(define fmt (mono 22050))
+(define N 512)
+
+
+; update filter whenever spectrum changes
+
+(lineout (linesnk fmt)
+	(gen->vector N (filter-gen 
+		(fir-filter (spectral-fir 64 (VVector. "spectrum" 33)))
+		(Wavetable. (linein (linesrc fmt) N N)))))
+
+(expose)
+(set "editor.plotter.type" 4)
+(exec (viewable "coeffs") "plotter editor")
+(exec (viewable "spectrum") "plotter editor")
+
+;; the viewable "spectrum" is actually the vector created a few lines up
+;; the plotter-editor allows the user to draw the desired frequency
+;; response, which is then translated into the appropriate FIR filter.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/lineio.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,8 @@
+(load "audio.scm")
+(load "lineout.scm")
+
+; audio input with a frame size of 1024 and a hop size of 512
+; is routed directly to audio output, which must also be informed
+; that hop size is 512.
+(lineout (linesnk) (linein (linesrc) 1024 512) 512)
+(expose)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/modulate.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,25 @@
+;;; Modulate noise or sine wave with short-term energy of input audio signal
+
+(load "audio.scm")
+(load "lineout.scm")
+(load "synthesis.scm")
+
+
+(put "regulated" #f)	; main loop will not be regulated, run as fast as possible.
+
+(tasks)	; creates regulator and main loop Task
+
+(define N 256) ; frame size for audio input, output, and hop size
+(lineout (default-linesnk) 
+	(gen->vector N (Product.	; generate N sample vector as product of two 
+;		(NormalisedGaussian.)	; signal generators:
+		(oscillator 0.5)			; a sinusoidal oscillator at 0.5 radians/sample
+		(FunctionOfGenerator. (Sqrt.)	; and the square root of
+			(filter-gen 					; a filtered signal
+				(fir-filter (VVector. "coeffs" 32))	; filter is fir with 32 taps
+				(filter-gen (EnergyOperator.) 		; signal is energy
+					(Wavetable. (linein (default-linesrc) N N)))))))) ; of audio in
+
+(expose)	; shows GUI
+(set "editor.plotter.type" 4)	; vector editors like bar chart rather than line
+(exec (viewable "coeffs") "plotter editor")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/osc.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,11 @@
+; shows how to generate a signal using an oscillator, buffer it,
+; and send it to the sound card
+(load "audio.scm")
+(load "lineout.scm")
+(load "synthesis.scm")
+
+; this uses the default linesnk, which will be a lineout returned
+; by the AudioSystem. Could easily choose a different lineout or
+; even a file sink. (eg see record.scm)
+(lineout (linesnk (mono 44100)) (gen->vector 512 (oscillator 0.1)))
+(expose)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/play.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+;;; This script reads audio from standard input and presents
+;;; an interface for playing it. Program exits when playback
+;;; thread is killed.
+
+(load "audio.scm")
+(load "filelist.scm")
+(load "lineout.scm")
+
+(tasks)
+(put "playlist.current" null)
+(define in (filesource))
+(.open in System.in$)
+
+(lineout (linein in 2048 2048))
+(expose)
+(start)
+(.join (thread))
+(exit)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/play2.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+(load "audio.scm")
+
+(define fmt (stereo 44100))	; see audio.scm for other options
+
+(define in (linesrc fmt))
+(define out (linesnk fmt)) 
+(define N 2048)	; frame size for audio transfers
+(define x (VVector. "x" N))	; frame of audio data
+
+; this sets up the tasks to run in the main loop, but
+; nothing happens until the loop is started
+(addtasks
+	(.reader in (.array x) 0 N)	; read N samples into x
+	(switch (.writer out (.array x) 0 N))
+)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/powspec.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,15 @@
+(load "audio.scm")
+(load "functions.scm")
+(load "models.scm")
+
+(define fmt (mono 22050))
+(define size 2048)
+(define hop 512)
+; get low latency input line with a buffer size of 4096
+(define X (ft-power (ft-vec (norm (linein (linesrc-buf fmt 4096) size hop)))))
+(define Y (diffscale X cauchy-spec))
+
+(exec Y "trace")
+
+(expose)
+(start)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/rec.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,9 @@
+; shows how to record from audio input to standard output in WAV format
+(load "audio.scm")
+(load "lineout.scm")
+
+(put "regulated" #f)
+(define fmt (mono 44100))
+(lineout (filesnk System.out$ fmt) (linein (linesrc fmt) 2048 2048))
+(expose)
+(start)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/record.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,9 @@
+; shows how to record from audio input a wav file
+(load "audio.scm")
+(load "lineout.scm")
+
+(put "regulated" #f)
+(define fmt (mono 44100))
+(lineout (filesnk "out.wav" fmt) (linein (linesrc fmt) 1024 1024))
+(expose)
+(start)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/specfilter.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,48 @@
+;;; Example of some more complicated spectral processing. 
+;;; We read two audio inputs: one from the sound card and one
+;;; from a file.  Then we filter one by the spectrum of the
+;;; other.
+
+(load "functions.scm")
+(load "models.scm")
+(load "lineout.scm")
+(load "audio.scm")
+(load "synthesis.scm")
+(load "filelist.scm")
+
+(define size 512)			; size of STFT frames
+(define hop 128)			; hops size
+(define fmt (mono 22050))
+(tasks)
+
+;; X is an object or unit which manages the FT of live input.
+;; Y is an object or unit which manages the FT of the file input.
+;; f is the normalised magnitude spectrum of the file input.
+;; z is the magnitude spectrum of the live input
+(define X (ft-vec (norm (linein (linesrc (default-mixer) fmt) size hop))))
+(define Y (node "filter" (ft-vec (norm (linein (filesource) size hop)))))
+(define f (diffscale (ft-mag Y) cauchy-spec))
+(define z (ft-mag X))
+; (define f (VVector. "filter" (.size z)))
+
+; at this point, the task list has a lot of stuff in it: everything
+; required to generate f and z when the main loop is run.
+
+(put "lineout.scale" 1.0e-5)	; get a lot of clipping if this is too large
+(.setWindow X (Constant. 1.0))	; override Hanning window in STFT default
+
+; this adds a task to multiply z (in place) by f
+(addtasks (task (Mathx.mul (.array z) (.array f)))) 
+
+; invert FT wih new magnitudes from z
+; then overlap-and-add output to audio output
+(overlap-and-add (linesnk (mixer-n 2) fmt)
+	(rescaled-ift Y z hop))
+
+(expose)
+
+; at this point the task list is ready and the whole
+; is started by calling (start) or pressing the start button
+; on the Regulator GUI.:w
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/stacker.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+(load "audio.scm")
+(load "functions.scm")
+(load "models.scm")
+
+(put "image.width" 256)
+(put "image.height" 16)
+(put "image.map.log" true)
+
+
+(define audioTasks (seq))
+(with-tasks audioTasks
+	(define x (ft-mag (ft-vec (norm 
+		(linein (linesrc (mono 11025)) 512 256))))))
+
+(addtasks (Stacker. x audioTasks 16 1))
+(expose)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/sound/sampled/stacker2.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+;;; Example of how to use Stacker2, which buffers several
+;;; vectors into one big vector.
+
+(load "audio.scm")
+(load "functions.scm")
+(load "models.scm")
+
+
+;;; Buffers the last n vectors from x. Adds the appropriate
+;;; task and returns the big composite vector.
+(define (stack n x)
+	(define stacker (node (.getNode x) (Stacker2. x n)))
+	(addtasks stacker)
+	(.output stacker))
+
+
+(stack 16 
+	(diffscale 
+		(ft-mag (ft-vec (norm (linein (linesrc (mono 11025)) 512 256))))
+		cauchy-spec))
+
+(expose)
+
+(put "image.width" 256)
+(put "image.height" 16)
+(put "image.map.log" true)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/util/Cat.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+package eg.util;
+import  samer.core.*;
+import  java.io.*;
+
+public class Cat
+{
+	public static void main( String args[]) 
+	{ 
+		// set up message window
+		new samer.core.shells.AppShell();
+
+		BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
+                
+		try { 
+			String s;
+			for (;;) {
+				s=d.readLine();
+				if (s==null) break; 
+				Shell.print(s); 
+			}
+		} catch (IOException e) { Shell.print("---- error ----");}
+
+		String term="\n---------------------------\nclose window to exit";
+		if (args.length==0) { Shell.print(term); }
+		else {
+			if (!args[0].equals("-q")) Shell.print(term);
+			else { Shell.exit(); }
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/util/ClassInfo.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,97 @@
+package eg.util;
+import  samer.core.*;
+import  samer.core.shells.*;
+import  samer.core.types.*;
+import  samer.core.Agent.*;
+import  java.lang.reflect.*;
+import  java.util.*;
+
+public class ClassInfo implements Agent, Observer
+{
+	VString	clname = new VString("class");
+	VBoolean	all = new VBoolean("all",false);;
+	Class		cl;
+
+	public ClassInfo()
+	{
+		clname.addObserver(this);
+		all.addObserver(this);
+		Shell.register(this); 
+		Shell.exposeCommands(this); 
+	}
+
+	public void getCommands(Registry r) { 
+		r.add("class").add("interfaces")
+			.add("methods").add("fields").add("superclass")
+			.add("verbose", all.value);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{ 
+		if (cmd.equals("class")) {
+			clname.value = X.string(env.datum(),clname.value);
+			clname.changed();
+		} else if (cmd.equals("methods")) {
+			Method		mths[];
+
+			if (all.value) mths = cl.getMethods();
+			else				mths = cl.getDeclaredMethods();
+				
+			Shell.print("Methods: ");
+			for (int i=0;i<mths.length; i++) {
+				Shell.print("\t"+mths[i]);
+			}
+
+		} else if (cmd.equals("fields")) {
+			Field		flds[];
+
+			if (all.value) flds = cl.getFields();
+			else				flds = cl.getDeclaredFields();
+
+			Shell.print("Fields: ");
+			for (int i=0;i<flds.length; i++) {
+				Shell.print("\t"+flds[i]);
+			}
+		} else if (cmd.equals("interfaces")) {
+			Class		ifaces[] = cl.getInterfaces();
+			Shell.print("Interfaces: ");
+			for (int i=0;i<ifaces.length; i++) {
+				Shell.print("\t"+ifaces[i]);
+			}
+		} else if (cmd.equals("superclass")) {
+			setClass(cl.getSuperclass());
+		} else if (cmd.equals("verbose")) {
+			all.value = X._bool(env.datum(),!all.value);
+			all.changed();
+		}
+	}
+
+	public void update(Observable o, Object src)
+	{
+		if (clname.equals(o) && src!=this) { // &&&
+			try { setClass(clname.value); }
+			catch (Exception ex) {}
+		}
+	}
+
+	private void setClass(String n) throws Exception {
+		setClass(Class.forName(n));
+	}
+
+	private void setClass(Class c) throws Exception
+	{
+		clname.value = c.getName();
+		clname.changed(this);
+		cl = c; 
+
+		Constructor cons[] = cl.getConstructors();
+
+		Shell.print("\nClass: "+cl);
+		Shell.print("\textends "+cl.getSuperclass());
+		Shell.print("constructors");
+		for (int i=0;i<cons.length; i++) {
+			Shell.print("\t"+cons[i]);
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/util/DumpProperties.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,38 @@
+package eg.util;
+
+import java.util.Properties;
+import java.util.Enumeration;
+
+import java.net.InetAddress;
+
+public class DumpProperties
+	{
+	public static void main(String[] args)
+		{
+		Properties props = System.getProperties();
+		Enumeration enum = props.propertyNames();
+
+		System.out.println("System Properties");
+		while( enum.hasMoreElements() )
+			{
+			String key   = (String)enum.nextElement();
+			String value = props.getProperty(key);
+			System.out.println(key + "\t" + value);
+			}
+
+		try 
+			{
+			InetAddress host = InetAddress.getLocalHost();
+			String name = host.getHostName();
+			String addr = host.getHostAddress();
+
+			System.out.println("hostname = " + name);
+			System.out.println("address  = " + addr);
+			}
+		catch ( Exception e )
+			{
+			System.err.println("Exception looking up local host name");
+			e.printStackTrace();
+			}
+		}
+	}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/util/FontInfo.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,34 @@
+package eg.util;
+import  samer.core.*;
+import  java.awt.*;
+
+public class FontInfo implements Agent
+{
+	public FontInfo() 
+	{ 
+		Shell.registerAgent(this); 
+		Shell.exposeCommands(this); 
+	}
+
+	public void getCommands(Registry r) { 
+		r.add("list1").add("list2").add("setfont");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("list1")) {
+			String [] fonts=Toolkit.getDefaultToolkit().getFontList();
+			Shell.print("fonts via Toolkit");
+			for (int i=0; i<fonts.length; i++) {
+				Shell.print("   "+fonts[i]);
+			}
+		} else if (cmd.equals("list2")) {
+			String [] fonts=GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
+			Shell.print("fonts via GraphicsEnvironment");
+			for (int i=0; i<fonts.length; i++) {
+				Shell.print("   "+fonts[i]);
+			}
+		} 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/JScheme-license.txt	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,28 @@
+                The Jscheme Language and Implementation
+Copyright (c) 2002 Ken R. Anderson, Timothy J. Hickey, Peter Norvig
+
+This system is licensed under the following 
+zlib/libpng open-source license.
+
+This software is provided 'as-is', without any express or
+implied warranty.
+
+In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any
+purpose, including commercial applications, and to alter it
+and redistribute it freely, subject to the following
+restrictions:
+
+1. The origin of this software must not be misrepresented; you
+   must not claim that you wrote the original software. If you
+   use this software in a product, an acknowledgment in the
+   product documentation would be appreciated but is not
+   required.
+
+2. Altered source versions must be plainly marked as such, and
+   must not be misrepresented as being the original software.
+
+3. This notice may not be removed or altered from any source
+   distribution.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/README	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,3 @@
+This would contain some 3rd party libraries, but
+I would rather not bundle them -- better to have
+them installed separately in a sharable way.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/Tritonus-license.txt	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,5 @@
+Tritonus is distrubuted under the Lesser GNU Public License (LGPL).
+See 
+	http://www.tritonus.org/
+	http://www.gnu.org/copyleft/lesser.html
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/libreadline-java-README	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,93 @@
+*** This was extracted from the libjavareadline 0.7.3 distribution.
+*** The jar will not work unless the correct native libraries are
+*** present, so the best thing is to install libreadline-java independently.
+***
+*** Samer Abdallah 20/8/04 (jslab v 0.1) 
+***
+
+This is my "port" of GNU-Readline to Java. Actually, it is a crude wrapper 
+using the Java Native Interface (JNI).
+
+Starting from version 0.6, alternative libraries are supported. Currently
+only Editline is implemented, but adding support for other implementations
+should be easy. 
+From 0.6 on, JavaReadline also has a fallback solution (System.in) for
+platforms without Readline or Editline support, making your programs portable
+again.
+
+This version implements basic readline functionality like line editing and
+filename completion, which should be just enough for normal use. Not all
+functionality is available with all implementations.
+
+Various people contributed code (see the file NEWS for details).
+Since I changed some of the code, all bugs are my fault and bugreports
+should be adressed to me.
+
+The binary distribution contains the API documentation, a JAR with the
+Readline class and the shared libraries libJavaReadline.so and 
+libJavaEditline.so. It was compiled running Linux 2.2.18 with glibc 2.2.
+
+The source distribution contains all the source (I hope this doesn't surprise
+you ;-) and a system of makefiles. You need the JDK to compile it.
+
+
+LICENSING ISSUES
+================
+
+Although JavaReadline is distributed under the LGPL, the underlying
+Readline library is GPL code. The consequence is, that any program
+linking with JavaReadline+Readline, will fall under the GPL.
+
+There is a Readline replacement called Editline with a more liberal
+license. Use that library if you want to distribute your program
+under the LGPL instead of the GPL.
+
+You can fetch the Editline stuff at http://packages.debian.org. You
+need libedit2 and libedit-dev. Source code is also available, although
+I must admit I did not succeed in compiling it on my non-BSD and
+non-Debian system :-(
+
+
+COMPILATION
+===========
+
+Compilation should be no problem. Try "make". You should set the
+variable JAVA_HOME (or edit the makefile). Also, if you don't use jikes,
+you should change the variables JAVAC and JAVAC_OPT in the makefile. A better
+alternative is to install jikes, it will speed up your development by
+a factor of 2-3.
+
+If you don't have the Editline libraries installed, use 
+"make T_LIBS=JavaReadline" (the default creates both JavaReadline and
+JavaEditline).
+
+
+INSTALLATION
+============
+
+Copy the files libJava*.so to one of your library directories or add
+the directory where you put libJava*.so to LD_LIBARY_PATH. Also, add
+java_readline.jar to your CLASSPATH. After building the jar and the shared
+library, you can run a program with something like:
+
+LD_LIBRARY_PATH=/usr/lib java -cp java_readline.jar org.foo.bar.MyClass
+
+assuming that you put libJava*.so into /usr/lib.
+
+
+DEBIAN
+======
+
+Thanks to Ben Burton, Debian-packages for JavaReadline are available!
+
+
+SUPPORT
+=======
+
+If you think you found a bug or want to contribute some code please drop 
+me a note.
+
+Bernhard Bablok
+mail@bablokb.de
+http://www.bablokb.de
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/javacc	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,7 @@
+#!/bin/sh
+jlib=~/lib/java
+#j3djars=$jlib/vecmath.jar:$jlib/j3dcore.jar:$jlib/j3dutils.jar:$jlib/j3daudio.jar
+base=$jlib/jscheme-7.2.jar:$jlib/jama.jar
+mlctrl=$jlib/matlabcontrol.jar
+export CLASSPATH=$jlib:$base:$mlctrl:$CLASSPATH
+javac "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/schemerc.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,11 @@
+;#! java jscheme.Shebang
+			 
+(define eval-string jscheme.JS.eval)
+(define lib "/Users/samer/lib")
+(define load-roots (list
+	(string-append lib "/jslab/scheme")
+	(string-append lib "/jslab/local")
+))
+(load "elf/load.scm")
+(load "readline.scm")
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/silk	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,8 @@
+#!/bin/sh
+jlib=~/lib/java
+silkrc=~/lib/jslab/local/schemerc.scm
+base=$jlib/jscheme.jar:$jlib/libreadline-java.jar:$jlib/jama.jar
+JAVA_HOME=/opt/local/share/java/openjdk6
+#JAVA_HOME="/Library/Java/JavaVirtualMachines/JDK 1.7.0 Developer Preview.jdk/Contents/Home"
+export CLASSPATH=$jlib:$base:$CLASSPATH
+exec "$JAVA_HOME/bin/java" -Dawt.useSystemAAFontSettings=lcd -Dswing.aatext=true -Xdock:name="JSLab" jscheme.REPL $silkrc "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/swing	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,2 @@
+#!/bin/sh
+exec silk '(load "swingrc.scm")' "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/swingrc.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+;;; Mac OS X only
+;;;
+; Properties documented here:
+; http://developer.apple.com/library/mac/#documentation/Java/Reference/Java_PropertiesRef/Articles/JavaSystemProperties.html
+(let ((sp System.setProperty))
+	(sp "apple.laf.useScreenMenuBar" "true")
+	;(sp "apple.awt.brushMetalLook" "true")
+	;(sp "apple.awt.antialiasing" "off")
+	;(sp "apple.awt.textantialiasing" "on")
+	(sp "apple.awt.rendering" "speed")  ; speed quality
+	;(sp "apple.awt.interpolation" "bicubic");  nearestneighbor bilinear bicubic
+	;(sp "apple.awt.graphics.UseQuartz" "false")	
+	;(sp "apple.awt.showGrowBox" "true")
+
+	;;; older options, not working as of Java 6
+	;(sp "com.apple.mrj.application.apple.menu.about.name" "JSLab")
+	;(sp "com.apple.mrj.application.growbox.intrudes" "false")
+	;(sp "com.apple.mrj.application.live-resize" "false")
+	;(sp "com.apple.macosx.AntialiasedGraphicsOn" "false")
+	;(sp "com.apple.macos.useScreenMenuBar" "true")
+	;(sp "com.apple.hwaccel" "true")
+)
+		
+(samer.core.shells.SwingShell. (string-append lib "/jslab/local/user.props"))
+
+;; This is a theme for people using the Metal look and feel.
+(define (mytheme)
+	(display "setting Metal theme\n")
+	(javax.swing.plaf.metal.MetalLookAndFeel.setCurrentTheme
+		(samer.core.util.swing.SilkyMetalTheme.
+			(X.font (Shell.datum "swing.font") "Dialog")
+			(java.awt.Color.decode "#e4e1e4")	0.64))
+	(javax.swing.UIManager.setLookAndFeel
+		(javax.swing.plaf.metal.MetalLookAndFeel.)
+	)
+)
+
+;; this is a theme for Mac users using the native Aqua look-and-feel
+(define (osxtheme)
+	(define f	(X.font (Shell.datum "swing.font") "Dialog"))
+	(display "Setting OS X theme defaults\n")
+	(for-each (lambda (x) (javax.swing.UIManager.put (string-append x ".font") f))
+		'("Label" "TextField" "CheckBox" "CheckBoxMenuItem" "Button" "List" "Tree" "MenuItem"))
+	(javax.swing.UIManager.put "TitledBorder.font" 
+		(.deriveFont f java.awt.Font.BOLD$))
+)
+
+(import "samer.tools.*")
+
+(load "shell.scm")
+(load "task.scm")
+(load "color.scm")
+
+(import "samer.maths.*")
+(import "samer.functions.*")
+(import "samer.units.*")
+
+(samer.core.util.Tools.setAntialias #t)
+(osxtheme)	; I'm using a Mac
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/local/user.props	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+#properties=props
+canvas.antialias=true
+console.background=#000000
+console.foreground=(200 180 240)
+#console.font=Courier-PLAIN-12
+#input.console.foreground=(230 210 255)
+border.inset=2
+console.scrollbars=true
+console.frame.title=Console
+exposed.title=Viewables
+swing.output.console.background=~default
+swing.input.console.background=~default
+swing.output.console.foreground=~default
+swing.input.console.foreground=~default
+#plotter.type=0
+meter.background=(255 255 255)
+#meter.foreground=(100 100 160)
+meter.foreground=(142 153 166)
+#meter.background=(184 198 220)
+trace.axesColor=(0 100 0)
+trace.background=(255 255 255)
+trace.foreground=(0 0 0)
+trace.scroll=false
+trace.scrollStep=1
+field.width=5
+plotter.background=(255 255 255)
+plotter.axesColor=(160 80 120)
+plotter.foreground=(0 0 0)
+cell.size=1
+map.symmetric=true
+slider.map.symmetric=false
+meter.map.symmetric=false
+#boolean.iconDirectory=/Users/samer/java/src/buttons
+histogram.map.symmetric=false
+histogram.bins.image.map.symmetric=false
+histogram.bins.image.map.log=true
+histogram.bins.image.colormap=grey.colormap
+histogram.bins.image.map.minimum=1
+histogram.bins.image.map.maximum=10000
+histogram.bins.rowcolumn.rowwise=true
+histogram.bins.rowcolumn.plotter.map.symmetric=false
+histogram.bins.rowcolumn.plotter.map.log=true
+histogram.bins.rowcolumn.plotter.map.minimum=1
+histogram.bins.rowcolumn.plotter.map.maximum=10000
+swing.font=Verdana-PLAIN-11
+swing.boldfont=Verdana-BOLD-11
+ft.window=hanning
+E.trace.map.symmetric=false
+E.trace.map.symmetric.minimum=0
+E.trace.map.symmetric.maximum=2000
+regulator.regulated=false
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/ButtonsApplet.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,41 @@
+/*
+ *	ButtonsApplet.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.applet;
+import  java.awt.*;
+
+
+public class ButtonsApplet extends JApplet
+{
+	public void init()
+	{
+		super.init();
+
+		JAppletShell.instance.registerButtons(this);
+
+		// set layout here
+		String dir=getParameter("layout");
+		if ("vertical".equals(dir)) 
+			setLayout(new GridLayout(0,1,8,8));
+		else {
+			String grid=getParameter("grid");
+
+			if ("true".equals(grid)) setLayout(new GridLayout(1,0,8,8));
+			else      setLayout(new FlowLayout(FlowLayout.LEFT,4,4));
+		}
+	}
+
+	public void destroy()
+	{
+		JAppletShell.instance.deregisterButtons(this);
+		super.destroy();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,7 @@
+/ButtonsApplet.java/1.1.1.1/Fri Dec 10 03:29:24 2004//
+/ConsoleApplet.java/1.1.1.1/Fri Dec 10 03:29:24 2004//
+/JApplet.java/1.1.1.1/Fri Dec 10 03:29:24 2004//
+/JAppletShell.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Sierpinski.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/WindowApplet.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/applet
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/ConsoleApplet.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+/*
+ *	ConsoleApplet.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.applet;
+import  samer.core.*;
+
+public class ConsoleApplet extends JApplet
+{
+	public void init()
+	{
+		super.init();
+
+		// Shell.push(this); // push AppletEnvironment?
+		JAppletShell.instance.setConsoleContainer(this);
+		// Shell.pop();
+	}
+
+	public void destroy()
+	{
+		JAppletShell.instance.releaseConsoleContainer(this);
+		super.destroy();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/JApplet.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,142 @@
+/*
+ *	JApplet.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.applet;
+import  samer.core.*;
+import  samer.core.util.heavy.*;
+import  java.applet.*;
+import  java.awt.*;
+import  java.net.*;
+import  java.io.*;
+
+
+/** Base class for applets that work with the JAppletShell framework.
+	Manages a border and scripts to run on create, destroy, init and term
+*/
+
+public class JApplet extends Applet
+{
+	private Border.Interface	border;
+	protected String			name, ondestroy;
+
+
+	public void setBorder( Border.Interface b) { border=b; }
+	public Border.Interface getBorder() { return border; }
+
+	public void init() 
+	{
+		JAppletShell.initialise(this);
+		name = getParameter("name");
+		if (name!=null && name.length()==0) name=null;
+
+		String args = getParameter("args");
+		if (args!=null && args.length()>0) {
+			try {
+				JAppletShell.instance.loadargs(new URL(getDocumentBase(), args));
+			}
+			catch (Exception ex) {
+				Shell.trace("JApplet: error loading "+args);
+			}
+		}
+
+		Shell.trace("JApplet init "+name); 
+		ondestroy=getParameter("ondestroy");
+		setup();
+	}
+
+	public void setup()
+	{
+		// create a new environment based on Shell top level
+		// with name equal to Applet name, using this applet
+		// as a Dictionary (String -> String mapping)
+
+		if (name!=null) { /* what? */ }
+		Node node= (name==null ? Shell.env().node() : new Node(name));
+		Environment env=new Environment(Shell.env(),node) {
+			public Datum datum(final String nm) {
+				final String vl=getParameter(nm);
+				if (vl==null) return parent.datum(nm);
+				return new Datum() {
+					public String name() { return nm; }
+					public int    score() { return 0; }
+					public Object get(Codec c, Object def) { return c.decode(vl); }
+					public void   get(Autocoder obj) { obj.decode(vl); }
+				};
+			}
+		};
+		// can't push global Environment because 
+		// applets may load mutli-threadedly.
+
+
+		// set up colours and fonts from properties
+		Color pageColour = X.color(env.datum("pagebg"), getBackground());
+		getParent().setBackground( pageColour);
+		setBackground( X.color(env.datum("background"), pageColour));
+		setForeground( X.color(env.datum("foreground"), getForeground()));
+		setFont((Font)(env.datum("font").get(X.FontCodec,"Helvetica-PLAIN-12")));
+
+		// create border using parameters from this applet
+
+		setBorder( Borders.createBorder(new Environment(env,"border")));
+
+		// "export" means  we should make this applets
+		// parameters globally visible as Shell properties 
+		synchronized (JAppletShell.instance) {
+			String export=getParameter("export"); // local search only!
+			if ("true".equals(export)) {
+				Shell.trace("Applet: "+name+" exporting properties");
+				Shell.push(env);
+				// ?? what happens when this applet goes away? 
+				// maybe implement Peers environement, consisting of
+				// a list (rather than a stack) of other environments
+			}
+		}
+	}
+
+	public void onStart() 
+	{
+		String oncreate=getParameter("oncreate");
+		if (oncreate!=null) {
+			Shell.trace("oncreate: "+oncreate);
+			Shell.interpret(new StringReader(oncreate));
+		}
+	}
+
+	public void onDestroy() 
+	{
+		if (ondestroy!=null) {
+			Shell.trace("ondestroy: "+ondestroy);
+			Shell.interpret(new StringReader(ondestroy));
+		}
+	}
+
+	public Insets getInsets() { 
+		if (border!=null) return border.getBorderInsets(this); 
+		else return new Insets(0,0,0,0);
+	}
+
+	public void paint(Graphics g)
+	{
+		// should paint border first, incase border erases bg
+		Dimension d=getSize();
+		border.paintBorder(this,g,0,0,d.width,d.height);
+		g.setColor( getForeground());
+	}
+
+	public void   setProperty(String nm,String vl) {}
+	public String getProperty(String nm) { return getParameter(nm); }
+
+	public void start() { Shell.trace("JApplet start"); onStart(); }
+	public void stop() { Shell.trace("JApplet stop"); }
+	public void destroy() { Shell.trace("JApplet destroy"); onDestroy(); }
+
+	protected void finalize() { Shell.trace("JApplet finalizing "+name); } 
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/JAppletShell.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,364 @@
+/*
+ *	JAppletShell.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.applet;
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.net.*;
+import java.io.*;
+
+import samer.core.*;
+import samer.core.util.heavy.*;
+import samer.core.util.shell.*;
+import samer.core.util.*;
+import samer.core.Shell.*;
+
+import samer.core.util.heavy.Frame;
+import samer.core.util.heavy.Dialog;
+import samer.core.util.Properties;
+import samer.core.NumberViewer;
+import samer.core.viewers.*;
+import samer.core.types.*;
+
+import samer.core.util.heavy.Console;
+import java.util.Hashtable;
+
+	/*
+		To do:
+o		2 - Create optional output window
+		3 - display commands in menu on Applet OR
+		4 - commands on button bar in applet
+
+		6 - create Viewer to use Tools
+		7 - manage agents
+		8 - manage viewables
+	*/
+
+/**
+	This is a Shell that uses Applets to form a GUI. The basic idea is that
+	each applet that gets created on a web page registers itself with shell
+	as an available window, or perhaps as a special window like a console
+	or viewables container. Then, whenever a script or something asks for
+	a window, it gets to use one of the applets.
+ */
+
+public class JAppletShell implements Shell.Interface, Agent
+{
+	static JAppletShell instance=null;
+	private static Object mutex=new Object(); // to serialise Shell creation
+
+	private AgentManager		am;
+	private ViewableManager	vm;
+	private Properties			props;
+	private URL					documentBase;
+	private Container			confr=null;
+	private Console				console=null;
+	private ButtonBar			buttonBar=null;
+	private Vector				windows=new Vector();
+	private java.awt.Frame	dialogOwner=null;
+	private Hashtable			winmap=new Hashtable();
+
+	protected JAppletShell()
+	{
+		vm = new ViewableManager();
+		am = new AgentManager();
+		am.registerAgent(am);
+		am.registerAgent(this);
+
+		props = new Properties(Shell.env());
+		
+		put(VDouble.class,DoubleViewer.class);
+		put(VInteger.class,IntegerViewer.class);
+		put(VBoolean.class,BooleanViewer.class);
+		put(VString.class,StringViewer.class);
+		put(VParameter.class,ParameterViewer.class);
+		put(VFile.class,FileViewer.class);
+		put(VColor.class,ColorButton.class);
+		put(Variable.class,StringViewer.class);
+		put(Viewable.class,DefaultViewer.class);
+	}
+
+	public static void initialise(Applet applet)
+	{
+		System.out.println("Initialising JAppletShell...\n");
+		synchronized(mutex) {
+			if (instance==null) {
+				Shell.setShell(instance=new JAppletShell());
+			}
+			instance.documentBase=applet.getDocumentBase();
+		}
+	}
+
+	public void getCommands(Agent.Registry r) { 
+		r.add("load").add("save").add("run").add("expose"); 
+	}	
+
+	public void execute(String cmd, Environment env) throws Exception 
+	{
+		if (cmd.equals("load")) {
+			loadargs(new URL(documentBase, X.string(env.datum(),"args")));
+		} else if (cmd.equals("save")) {
+			saveargs(new URL(documentBase, X.string(env.datum(),"args")));
+		} else if (cmd.equals("run")) {
+			String scr=X.string(env.datum("script"));
+			runscript(new URL(documentBase, scr));
+		} else if (cmd.equals("expose")) {
+			exposeViewables();
+		} else if (cmd.equals("exit")) {
+			Shell.trace("Shell: exit");
+		}
+	}
+	
+	public void exit() {}
+	
+	public synchronized void loadargs(URL url) throws Exception
+	{
+		Shell.print("loading args from "+url);
+		InputStream in=url.openConnection().getInputStream();
+		try { props.load(new BufferedInputStream(in)); }
+		finally { in.close(); }
+	}
+
+	public synchronized void saveargs(URL url) throws Exception
+	{
+		URLConnection con=url.openConnection();
+		con.setDoOutput(true);
+
+		OutputStream out=con.getOutputStream();
+		try { 
+			Shell.print("saving args to "+url);
+			props.save(out); 
+			Shell.print("-- saved");
+		} finally { out.close(); }
+	}
+
+	public void runscript(URL url) throws Exception
+	{
+		InputStream in=url.openStream();
+		try { Shell.interpret(new BufferedReader(new InputStreamReader(in))); }
+		finally { in.close(); }
+	}
+
+	protected void put(Class a, Class b) { samer.core.Registry.put(a,b); }
+	
+	// ----------- Window registry ----------
+
+	public static void registerWindow(Shell.Window win, String name)
+	{
+		if (name!=null) {
+			Shell.trace("registering named window: "+name);
+			instance.winmap.put(name,win);
+		} else { 
+			Shell.trace("registering anonymous window: "+win);
+			instance.windows.addElement(win);
+		}
+	}
+
+	public static void deregisterWindow(Shell.Window win, String name) 
+	{
+		Shell.trace("deregistering window "+name);
+		if (name!=null) {
+			Object o=instance.winmap.get(name);
+			if (win==o) instance.winmap.remove(name);
+		} else instance.windows.removeElement(win);
+	}
+
+	public static java.awt.Frame dummyFrame() 
+	{ 
+		if (instance.dialogOwner==null) {
+			instance.dialogOwner=new java.awt.Frame("DialogOwner");
+		}
+		return instance.dialogOwner; 
+	}
+
+	public Shell.Dialog getDialog(String title) { 
+		return new Dialog(dummyFrame(),title,true); 
+	}
+
+	public Shell.Window getWindow(String title)
+	{
+		Object win=instance.winmap.remove(title);
+
+		if (win==null) {
+			// named window not found -- return first anonymous window
+			if (windows.size()>0) {
+				Shell.trace("looking for anonymous window");
+				win=windows.firstElement();
+				windows.removeElementAt(0);
+				Shell.trace("returning anonymous window");
+			}
+		} else Shell.trace("returning named window: "+title);
+
+		// if all else fails, create a new Frame window
+		if (win==null) win=new Frame(title);
+			
+		return (Shell.Window)win;
+	}
+
+	public Viewer getViewerFor(Viewable v) { return null; }
+
+	// different types of message
+	public void status(String msg) { print(msg); }
+	public void trace(String msg) { System.err.println(msg); } 
+	public void print(String msg) 
+	{ 
+		if (console!=null) console.write(msg+"\n");
+		else System.out.println(msg);
+	}
+
+	public PrintWriter	getPrintWriter() { 
+		if (console!=null) return new PrintWriter(console.getWriter(),true);
+		else return new PrintWriter(System.out); 
+	}
+
+	// agents and viewables
+	public void registerAgent(Agent a) { am.registerAgent(a); }
+	public void deregisterAgent(Agent a) { am.deregisterAgent(a); }
+	public void registerViewable(Viewable v) { vm.registerViewable(v); }
+	public void deregisterViewable(Viewable v) { vm.deregisterViewable(v); }
+
+	public void registerButtons(Container c)	{
+		buttonBar = new ButtonBar(c);
+		buttonBar.setBroadcaster(am.getBroadcaster());
+	}
+
+	public void deregisterButtons(Container c)	{
+		if (buttonBar.container()==c) buttonBar=null;
+	}
+
+	public Viewer createViewerPanel(Viewer vwr) { return new VPanel(vwr); }
+	public Component createLabel(String txt) {
+		Label l=new Label(txt);
+		l.addMouseListener(MouseRetarget.listener);
+		return l;
+	}
+
+	public Container createButtonsFor(Agent agent)
+	{
+		ButtonBar bbar=new ButtonBar();
+		bbar.setTarget(agent);
+		agent.getCommands(bbar);
+		return bbar.container();
+	}
+
+	public NumberViewer createNumberViewer(String label, int flags, NumberSink s) {
+		return new TextualNumberViewer(label,flags,s);
+	}
+
+	public void exposeCommands( Agent agent)
+	{
+		// what happens if button container goes away?
+
+		if (buttonBar!=null) {
+			buttonBar.setTarget(agent); // ?? or broadcast?
+			agent.getCommands(buttonBar);
+			buttonBar.container().getParent().validate();
+		}
+
+		// should we put buttons on console if no button bar?
+	}
+
+	// ----------- Viewables management --------------
+
+	public static void expose() { instance.exposeViewables(); }
+
+	public void exposeViewables()
+	{
+		if (!vm.hasViewerContainer()) {
+			// try to find window called "exposed"
+			Shell.Window win=(Shell.Window)instance.winmap.remove("exposed");
+			if (win==null) {
+				// window not found-use new frame window
+				vm.exposeViewables(new VContainer(new Frame("exposed")));
+			} else {
+				// use named window
+				vm.exposeViewables(new VContainer(win));
+			}
+		}
+	}
+
+	class VContainer extends WindowAdapter implements ViewableManager.ViewerContainer
+	{ 
+		Shell.Window	win;
+		Frame			frame;
+
+		VContainer(Frame frame) { this((Shell.Window)frame); this.frame=frame; }
+		VContainer(Shell.Window win)
+		{
+			frame=null;
+
+			this.win=win;
+			// let applet control this?
+			win.container().setLayout( new StackLayout()); 
+			win.expose(); // redundant for applets
+			win.addWindowListener(this); // also redundant!
+		}
+
+		public void add(java.util.Iterator components) 
+		{
+			Shell.trace("VContainer: adding stuff");
+			Container c=win.container();
+			while (components.hasNext()) {
+				c.add((Component)(components.next()));
+			}
+			c.validate();
+			if (frame!=null) frame.pack();
+		}
+
+		public void removeAll() { win.container().removeAll(); }
+		public void windowClosing(WindowEvent e) {
+			vm.releaseViewerContainer();
+			win.dispose();
+		}	
+	}
+
+	// --------------- Console management -------------
+
+	public void releaseConsoleContainer(Container c)
+	{
+		// if we're using this console container...
+		if (confr==c) {
+			confr.removeAll();
+			confr=null;
+
+			// should we destroy the console too?
+			// what about any outstanding PrintWriters?
+		}
+	}
+
+	public void setConsoleContainer(Container c)
+	{ 
+		// we have a console container - don't need a new one
+		if (confr!=null) return;
+		confr = c;
+
+		// create console if necessary
+		if (console==null) console = new Console();
+
+		// add console, command field and button bar according
+		// to current property set.
+
+		confr.setLayout( new BorderLayout(3,3));
+		confr.add(console, "Center");
+		if (Shell.getBoolean("console.commandField",false)) {
+			confr.add( new CommandField(20), "South"); 
+		}
+
+		// add button bar if buttons not already showing.
+		if (buttonBar!=null && !buttonBar.container().isShowing()) {
+			confr.add( buttonBar.container(), "North");
+			confr.validate();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/Sierpinski.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,71 @@
+package samer.applet;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.Random;
+import samer.core.*;
+import samer.core.util.heavy.VCanvas;
+import samer.tools.*;
+
+public class Sierpinski extends VCanvas implements Task, Agent
+{
+	Random		rnd=new Random();
+	RThread		rthread;
+	int			x=0, y=0, w=0, h=0;
+
+	public Sierpinski()
+	{
+		Shell.trace("creating RThread");
+		rthread = new RThread(this);
+
+		Shell.trace("obtaining window");
+		Shell.Window win=Shell.getWindow("Sierpinski");
+		win.container().setLayout(new BorderLayout());
+		win.container().add(this,"Center");
+		win.expose();
+		win.addWindowListener( new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+				Shell.print("Sierpinski terminating");
+				// how can I destroy the RThread?
+				// exposing commands creates actionListeners
+				// which refer to the Agent, thus stopping the
+				// Agent from being garbage-collected
+				dispose();
+			}
+		} );
+
+		Shell.trace("exposing commands");
+		exposeCommands(rthread);
+		exposeCommands(this);
+		Shell.registerAgent(this);
+		Shell.exposeCommands(rthread);
+		Shell.exposeCommands(this);
+	}
+
+	public void dispose()
+	{
+		Shell.deregisterAgent(this);
+		rthread.dispose();
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("clear"); }
+	public void execute(String cmd, Environment env) throws Exception{
+		if (cmd.equals("clear")) repaint();
+	}
+
+	public void run() throws Exception
+	{
+		int    j=Math.abs(rnd.nextInt())%3;
+
+		if (j==0)      { x=x/2; y=y/2; }
+		else if (j==1) { x=x/2; y=h+y/2; }
+		else           { x=w+x/2; y=y/2; }
+
+		graphics.fillRect( x, y, 1, 1);
+	}
+
+ 	public void stopping() { Shell.print("stopping"); }
+	public void starting() { Shell.print("starting"); }
+	public void realized() { Shell.print("realized"); sized(); }
+	public void sized() { w=width/2; h=height/2; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/applet/WindowApplet.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,114 @@
+/*
+ *	WindowApplet.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.applet;
+
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.Random;
+import  java.net.*;
+import  samer.core.*;
+import  samer.core.util.*;
+import  samer.core.util.heavy.*;
+import  samer.tools.*;
+
+//import  samer.core.util.common.Tools;
+
+public class WindowApplet extends JApplet implements Shell.Window, ActionListener
+{
+	private	WindowListener	wl=null;
+
+	public void init()
+	{
+		super.init();
+
+		JAppletShell.registerWindow(this,name);
+
+		PopupMenu p=new PopupMenu( "Frame");
+		p.addActionListener(this);
+		p.add("recycle");
+		add(p);
+		// addContainerListener(this); check for empty? see AppShell
+		addMouseListener(new PopupHandler(p,true));
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		if (e.getActionCommand().equals("recycle")) {
+			// simulate window closing behaviour by
+			// calling listeners - this REQUESTS that
+			// the window be released gracefully
+			if (wl!=null) {
+				Shell.trace("firing windowClosing event");
+				wl.windowClosing(new WindowEvent(
+					JAppletShell.dummyFrame(),
+					WindowEvent.WINDOW_CLOSING));
+			}
+		}
+	}
+	
+	public void start()
+	{
+		super.start();
+
+		if (name!=null) {
+			if (name.equals("exposed")) JAppletShell.expose();
+		}
+
+		// if we need to have access to private properties:
+		// Manager props = new Manager(this);
+	}
+
+	private boolean destroying=false;
+
+	public void destroy() 
+	{ 
+		destroying=true;
+
+		if (wl!=null) {
+			Shell.trace("firing windowClosing event");
+
+			// this may precipitate component removals or a window dispose
+			// we should ignore any dispose requests we get - that's
+			// why we set destroying=true;
+			wl.windowClosing(new WindowEvent(
+				JAppletShell.dummyFrame(),
+				WindowEvent.WINDOW_CLOSING));
+		}
+
+		wl=null; // forget about window listeners
+
+		// window is no longer available for use
+		JAppletShell.deregisterWindow(this,name);
+
+		// after this, if components are removed, this may
+		// precipitate a call to dispose if any container
+		// listeners are registered - we leave destroying=true
+		// so that nothing happens.
+		super.destroy();
+	}
+
+	public Container container() { return this; }
+	public synchronized void addWindowListener(WindowListener l) {
+		Shell.trace("adding window listener");
+		wl = AWTEventMulticaster.add(wl,l);     
+	}
+
+	public void expose() { validate(); }
+	public void dispose() { 
+		if (!destroying) {
+			removeAll();
+			wl=null; // forget about listeners
+
+			// window is now available for reuse
+			JAppletShell.registerWindow(this,name);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/AudioSink.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,72 @@
+/*
+ *	AudioSink.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+import samer.tools.*;
+
+/**
+	General interface for objects that accept a stream of
+	samples.
+*/
+
+public interface AudioSink
+{
+	boolean isOpen();
+	void open() throws Exception;
+	void close();
+	void dispose();
+
+	/** Return a task which takes samples from the given buffer
+	 *  The idea is that the audio sink can choose the right
+	 *  kind of writer depending on the format of the audio stream,
+	 *  and then handle any conversions automatically.
+	 */
+	Task writer(double buf[], int off, int len);
+	Task writer(float buf[], int off, int len);
+
+	public static class Util {
+		public static void doubleToShort(double[] src, byte [] dst, int off, int n, double k) {
+			k*=32768;
+			for (int i=0, j=off; j<n+off; j++) {
+		 		int y = (int)(k*src[j]);
+				dst[i++] = (byte)(y&0xff);
+				dst[i++] = (byte)(y>>8);
+			}
+		}
+
+		public static void doubletoByte(double [] src, byte[] dst, int off, int n, double k) {
+			k*=128;
+			for (int i=0, j=off; j<n+off; j++) {
+		 		int y = (int)(k*src[j]) + 128;
+				dst[i++] = (byte)(y&0xff);
+			}
+		}
+
+		public static void floatToShort(float [] src, byte [] dst, int off, int n, float k) {
+			k*=32768;
+			for (int i=0, j=off; j<n+off; j++) {
+		 		int y = (int)(k*src[j]);
+				dst[i++] = (byte)(y&0xff);
+				dst[i++] = (byte)(y>>8);
+			}
+		}
+
+		public static void floatToByte(float [] src, byte [] dst, int off, int n, float k) {
+			k*=128;
+			for (int i=0, j=off; j<n+off; j++) {
+		 		int y = (int)(128.0*src[j]) + 128;
+				dst[i++] = (byte)(y&0xff);
+			}
+		}
+
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/AudioSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,88 @@
+/*
+ *	AudioSource.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+import samer.tools.*;
+
+/**
+	General interface for objects that can supply an
+	audio stream.
+*/
+
+public interface AudioSource
+{
+	boolean  isOpen();
+	void open() throws Exception;
+	void close();
+	void dispose();
+
+	/** return a task which reads samples into the given buffer
+	 *  The idea is that the audio source can choose the right
+	 *  kind of reader depending on the format of the audio stream,
+	 *  and then handle the conversion to doubles automatically
+	 */
+	Task reader(double buf[], int off, int len);
+	Task reader(float buf[], int off, int len);
+
+	public static class Util {
+		/* NB. These copying functions allow NEGATIVE offset (off<0). The semantics 
+		 * of this is are that n values are copied from source to destination, writing 
+		 * into the destination starting at the negative offset, but that values before
+		 * index 0 will never be accessed, hence, they are not actually copied. Only
+		 * the last n-off values will be available in dst starting from index 0.
+		 * This is useful as it allows block-wise audio input where the block lenght
+		 * is smaller than the step length.
+		 */
+
+		public static void shortToDoubleMixDown(byte [] src, double [] dst, int off, int n, int m) {
+			double a = (1.0/(m*32768.0)); // scaling factor including division by mixdown factor m
+			int skip = off<0 ? -off : 0;
+			for (int i=2*m*skip, j=off+skip; j<n+off; j++) {
+				dst[j] = 0;
+				for (int k=0; k<m; k++) dst[j] += a*((src[i++]&0xff) | src[i++]<<8);
+			}
+		}
+
+		public static void shortToDouble(byte [] src, double [] dst, int off, int n) {
+			int i, j;
+			if (off<0) { i= 2*(-off); j=0; } else { i=0; j=off; }
+			while (j<n+off) dst[j++] = (1.0/32768.0)*((src[i++]&0xff) | src[i++]<<8);
+		}
+
+		public static void byteToDouble(byte [] src, double [] dst, int off, int n) {
+			int i, j;
+			if (off<0) { i= -off; j=0; } else { i=0; j=off; }
+			while (j<n+off) dst[j++] = (1.0/256.0)*(src[i++]&0xff)-128.0;
+		}
+
+		public static void shortToFloatMixDown(byte [] src, float [] dst, int off, int n, int m) {
+			int skip = off<0 ? -off : 0;
+			float a = (1F/(m*32768F)); // scaling factor including division by mixdown factor m
+			for (int i=2*m*skip, j=off+skip; j<n+off; j++) {
+				dst[j] = 0;
+				for (int k=0; k<m; k++) dst[j] += a*((src[i++]&0xff) | src[i++]<<8);
+			}
+		}
+
+		public static void shortToFloat(byte [] src, float [] dst, int off, int n) {
+			int i, j;
+			if (off<0) { i= -2*off; j=0; } else { i=0; j=off; }
+			while (j<n+off) dst[j++] = (1F/32768F)*((src[i++]&0xff) | src[i++]<<8);
+		}
+
+		public static void byteToFloat(byte [] src, float [] dst, int off, int n) {
+			int i, j;
+			if (off<0) { i= -off; j=0; } else { i=0; j=off; }
+			while (j<n+off) dst[j++] = (1F/256F)*(src[i++]&0xff)-128F;
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,9 @@
+/AudioSink.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/AudioSource.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/FileSource.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/LineSource.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/StreamSource.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/VLine.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/LineSink.java/1.2/Mon Oct  9 21:16:16 2006//
+/FileSink.java/1.2/Wed Oct 11 13:02:09 2006//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/audio
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/FileSink.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,150 @@
+/*
+ *	FileSink.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.tools.*;
+import  javax.sound.sampled.*;
+import  java.io.*;
+
+import  org.tritonus.share.sampled.AudioSystemShadow;
+import  org.tritonus.share.sampled.file.AudioOutputStream;
+
+/**
+	An AudioSink that writes to a wav file.
+	Viewable name: "wavewriter"<br>
+	Properties read from current environment:
+	<dl>
+	<dt>filesink.current
+		<dd>Current file (String)
+	<dt>filesink.scale
+		<dd>scale factor for converting floats/doubles (Double)
+	</dl>
+*/
+
+public class FileSink extends Viewable implements AudioSink, Agent
+{
+	VFile					file;
+	AudioOutputStream	out=null;
+	AudioFormat			format;
+	VDouble				scale;
+
+	public FileSink(String filename, AudioFormat fmt) throws Exception {
+		this(fmt); file.setFile(new File(filename)); 
+	}
+
+	public FileSink(AudioFormat fmt)
+	{
+		super("filessink");
+
+		Shell.push(node);
+		file=new VFile("file","",0);
+		scale=new VDouble("scale",1.0,0);
+		Shell.push("audio");
+		format=fmt;
+		Shell.pop();
+		Shell.pop();
+
+		setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public void dispose() {
+		close();
+		Shell.deregisterViewable(this);
+		file.dispose();
+	}
+
+	public VDouble getScale() { return scale; }
+	public void setFormat(AudioFormat f) { format=f; }
+
+	public boolean isOpen() { return out!=null; }
+	public void open() throws Exception { open(file.getFile()); }
+	public synchronized  void open(File file) throws Exception
+	{
+		Shell.trace("wave writer opening "+file+" as "+format);
+
+		out=AudioSystemShadow.getAudioOutputStream(
+			AudioFileFormat.Type.WAVE,format,AudioSystem.NOT_SPECIFIED,
+				new BufferedOutputStream(
+					new FileOutputStream(file)));
+		this.file.setFile(file);
+	}
+
+	public synchronized void close() {
+		try { if (out!=null) out.close(); out=null; }
+		catch (IOException ex) { Shell.trace("*** Error closing: "+ex); }
+	}
+
+	public Task writer(final double [] dbuf, final int off, final int len) {
+		return new AnonymousTask() {
+			byte [] bbuf = new byte[2*len];
+
+			public void write(double dbuf[], int off, int len) throws Exception {
+				synchronized (FileSink.this) {
+					Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
+					writeBytes(bbuf, 2*len);
+				}
+			}
+			public void run() throws Exception {
+				synchronized (FileSink.this) {
+					Util.doubleToShort(dbuf,bbuf,off,len,scale.value);
+					writeBytes(bbuf, bbuf.length);
+				}
+			}
+		};
+	}
+
+	public Task writer(final float [] dbuf, final int off, final int len) {
+		return new AnonymousTask() {
+			byte [] bbuf = new byte[2*len];
+
+			public void write(float dbuf[], int off, int len) throws Exception {
+				synchronized (FileSink.this) {
+					Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
+					writeBytes(bbuf, 2*len);
+				}
+			}
+			public void run() throws Exception {
+				synchronized (FileSink.this) {
+					Util.floatToShort(dbuf,bbuf,off,len,(float)scale.value);
+					writeBytes(bbuf, bbuf.length);
+				}
+			}
+		};
+	}
+
+	private void writeBytes(byte [] buf,int len) throws Exception {
+		int count = out.write(buf, 0, len);
+		for (int n=count; n<len; n+=count) {
+			count = out.write(buf, n, len - n);
+			if (count<=0) throw new Exception("Write failed");
+		}
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("open").add("close").add("set scale"); }
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("open")) {close(); open(); }
+		else if (cmd.equals("close")) close();
+		else if (cmd.equals("set scale")) { env.datum().get(scale); }
+	}
+
+	// Viewable
+	public Viewer getViewer() {
+		DefaultViewer vwr=new DefaultViewer(this);
+		vwr.add(file);
+		vwr.add(Shell.createButtonsFor(this));
+		return vwr;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/FileSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,346 @@
+/*
+ *	FileSource.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.tools.*;
+import  javax.sound.sampled.*;
+import  javax.swing.*;
+import  java.io.*;
+import  java.util.*;
+
+/**
+	An AudioSource that read from multiple audio files. Can read any
+	format for which the appropriate JavaSound plug-in is installed on
+	your system, eg WAV, AU, MP3, OGG. The implementation of 
+	AudioSource.reader() returns a Task which gets samples from the audio 
+	files, going through the play list one by one. If the loop flag
+	is true, then samples are returned indefinitely by looping through the
+	playlist; otherwise, an EOFException is thrown if an attempt is made
+	to read beyond the end of the last file.
+	
+	FileSource is a Viewable called "playlist", and an Agent with commands
+	next, prev, reopen, view, select, loop.
+	
+	Properties read from current environment:
+	<dl>
+		<dt>current<dd>Current file (String)
+		<dt>loop<dd>Loop playlist? (Boolean) [true]
+	</dl>
+					
+*/
+
+public class FileSource extends Viewable implements AudioSource, Agent
+{
+	List<File>				list=null;
+	ListIterator<File>	it=null;
+	boolean			loop;
+	int				channelsToMix;
+	VFile				curFile;
+	InputStream		in=null;
+	AudioFormat		format=null;
+	byte[]  			byte_buf=null;
+	int				chunk=0;
+
+	/**
+	 * Construct a FileSource initialised with current file and loop initialised
+	 * from the current Environment. No exception is thrown if the current file
+	 * cannot be opened, however, you must be sure to set it to a valid file
+	 * (or to set a playlist) before trying to read any samples.
+	 */
+	public FileSource()
+	{
+		super("playlist");
+
+		Shell.push(node);
+		curFile=new VFile("current","",0);
+		loop=Shell.getBoolean("loop",true);
+		Shell.pop();
+
+		setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public void dispose() {
+		close();
+		Shell.deregisterViewable(this);
+		curFile.dispose();
+	}
+
+	/** Returns current file */
+	public File getFile() { return curFile.getFile(); }
+	public void setTargetFormat(AudioFormat f) { format=f; }
+
+	/** If true then loop playlist, otherwise, an Exception will be thrown
+	 * when the end of the playlist is reached. If there is no playlist, then
+	 * looping applies to the current file only. */
+	public void setLoop(boolean f) { loop=f; }
+
+	/** Set playlist to all WAV files in given directory */
+	public void setDirectory(File dir, String ext) {
+		setPlaylist(Arrays.asList(dir.listFiles(getFileFilter(ext)))); 
+	}
+
+	public synchronized List<File> getPlaylist() { return list; }
+	public synchronized void setPlaylist(List<File> l) { list=l; it=list.listIterator(); }
+	private synchronized void setFile(File f) { curFile.setFile(f); }
+
+	/** Go back to start of playlist. Next block of samples will be from head
+	 *  of first file in playlist. Will throw an exception if there is no playlist */
+	public synchronized void rewind() throws Exception {
+		it=list.listIterator(); next();
+	}
+
+	/** Move to head of next file in playlist */
+	public synchronized void next() throws Exception
+	{
+		boolean wasOpen=isOpen();
+
+		if (wasOpen) close();
+		if (!it.hasNext()) {
+			if (!loop) throw new EOFException();
+			it=list.listIterator();
+			if (!it.hasNext()) throw new Exception("no files in playlist");
+		}
+		setFile(it.next());
+		if (wasOpen) openCurrent();
+	}
+
+	/** Move to head of previous file in playlist */
+	public synchronized void prev() throws Exception
+	{
+		boolean wasOpen=isOpen();
+		if (wasOpen) close();
+		if (!it.hasPrevious()) {
+			if (!loop) throw new EOFException();
+			it=list.listIterator(list.size());
+			if (!it.hasPrevious()) throw new Exception("no files in playlist");
+		}
+		setFile(it.previous());
+		if (wasOpen) openCurrent();
+	}
+
+	public boolean isOpen() { return in!=null; }
+
+	/** Closes current input stream */
+	public synchronized void close() {
+		try { 
+			if (in!=null) {
+				Shell.trace("Closing audio stream...");
+				in.close(); in=null; byte_buf=null; 
+			}
+		}
+		catch (IOException ex) {}
+	}
+
+	/** Opens the playlist starting with the first file.  */
+	public synchronized void open() throws Exception { rewind(); if (!isOpen()) openCurrent(); }
+
+	/** Opens the current file. Next read will returns samples
+	 *  from head of given file. If setFormat() was called previously, then
+	 *  we will attempt to do format conversion. */
+	private synchronized void openCurrent() throws Exception
+	{
+		File file=curFile.getFile();
+		Shell.trace("\nOpening audio file: "+file);
+
+		AudioInputStream		s=AudioSystem.getAudioInputStream(file);
+		AudioFormat				af=s.getFormat();
+		long						frames=file.length()/af.getFrameSize();
+
+		Shell.trace("  format: "+af);
+		Shell.trace("  duration: "+(long)(frames/af.getFrameRate())+" s");
+
+		// convert to target format if required
+		if (format!=null) {
+			if (!format.equals(af)) {
+				Shell.trace("  converting to "+format);
+				if (af.getChannels()>format.getChannels()) {
+					Shell.trace("  channels mix down required.");
+					AudioFormat fmt1 = new AudioFormat( format.getEncoding(), format.getSampleRate(), 
+								format.getSampleSizeInBits(), 
+								af.getChannels(), format.getFrameSize(), format.getFrameRate(), format.isBigEndian());
+
+					channelsToMix = af.getChannels();
+					s=convertFormat(s,af,fmt1);
+				} else {
+					channelsToMix = 0;
+					s=convertFormat(s,af,format);
+				}
+			}
+		}
+
+		// If we have a reader task, then update the byte buffer
+		if (chunk>0) setByteBuffer();
+
+		// Shell.trace("stream format: "+s.getFormat());
+		in = new BufferedInputStream(s,16*1024);
+	}
+
+	/** Returns number of bytes available in current file */
+	public int available() throws Exception { return in.available(); }
+
+	/** Reopen current file, so that next read will be from head of file. */
+	public synchronized void reopen() throws Exception { close(); openCurrent(); }
+
+	private void setChunkSize(int s) { chunk=s; }
+	private void setByteBuffer() {
+		byte_buf = new byte[2*chunk*(channelsToMix>0 ? channelsToMix : 1)];
+	}
+
+	/** Returns a Task which copies samples as doubles into the given
+	 *  buffer between the given positions. */
+	public Task reader(final double [] dbuf, final int off, final int len) {
+		setChunkSize(len);
+		if (in!=null) setByteBuffer();
+
+		return new AnonymousTask() {
+			public void run() throws Exception {
+				int n = 0;
+
+				synchronized (FileSource.this) {
+					int blen = byte_buf.length;
+					while (n < blen) {
+						int count = in.read(byte_buf, n, blen - n);
+						if (count > 0) n+=count;
+						else if (it!=null) next();
+						else if (!loop) throw new EOFException();
+						else reopen();
+					}
+				}
+				if (channelsToMix>0) Util.shortToDoubleMixDown(byte_buf,dbuf,off,len,channelsToMix);
+				else Util.shortToDouble(byte_buf,dbuf,off,len);
+			}
+		};
+	}
+
+	/** Returns a Task which copies samples as floats into the given
+	 *  buffer between the given positions. */
+	public Task reader(final float [] dbuf, final int off, final int len) {
+		setChunkSize(len);
+		if (in!=null) setByteBuffer();
+
+		return new AnonymousTask() {
+			public synchronized void run() throws Exception {
+				int n = 0;
+
+				synchronized (FileSource.this) {
+					int blen = byte_buf.length;
+					while (n < blen) {
+						int count = in.read(byte_buf, n, blen - n);
+						if (count > 0) n+=count;
+						else if (it!=null) next();
+						else if (!loop) throw new EOFException();
+						else reopen();
+					}
+				}
+				if (channelsToMix>0) Util.shortToFloatMixDown(byte_buf,dbuf,off,len,channelsToMix);
+				else Util.shortToFloat(byte_buf,dbuf,off,len);
+			}
+		};
+	}
+
+	// Agent
+	public void getCommands(Agent.Registry r) {
+		r.add("prev").add("reopen").add("next").add("view")
+		 .add("select").add("loop",loop);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("next")) next();
+		else if (cmd.equals("prev")) prev();
+		else if (cmd.equals("reopen")) reopen();
+		else if (cmd.equals("view")) {
+			if (list!=null) {
+				Shell.expose(
+					new JScrollPane(new JList(list.toArray())),
+					"playlist");
+			}
+		} else if (cmd.equals("select")) {
+			JFileChooser dlg = new JFileChooser(".");
+
+			dlg.setMultiSelectionEnabled(true);
+			dlg.setFileSelectionMode(dlg.FILES_AND_DIRECTORIES);
+			if (list!=null && !list.isEmpty()) {
+				dlg.setCurrentDirectory(list.get(0));
+				dlg.setSelectedFiles(list.toArray(new File[0]));
+			}
+			dlg.setDialogTitle("Select audio files");
+			if (dlg.showDialog(null, "OK")==JFileChooser.APPROVE_OPTION) {
+				File first=dlg.getSelectedFile();
+				if (first.isDirectory())
+					setDirectory(first,".wav");
+				else
+					setPlaylist(Arrays.asList(dlg.getSelectedFiles()));
+			}
+		} 	else if (cmd.equals("loop")) {
+			loop=X._bool(env.datum(),!loop);
+		}
+	}
+
+	// Viewable
+	public Viewer getViewer() { return new FileSourceViewer(); }
+	class FileSourceViewer extends DefaultViewer implements Agent {
+		public FileSourceViewer() {
+			super(FileSource.this);
+			add(curFile);
+			add(Shell.createButtonsFor(this));
+		}
+
+		public void getCommands(Agent.Registry r) {
+			r.add("prev").add("reopen").add("next").add("view").add("select");
+		}
+		public void execute(String cmd, Environment env) throws Exception {
+			FileSource.this.execute(cmd,env);
+		}
+	};
+
+	private static java.io.FileFilter getFileFilter(final String ext) { 
+		return new java.io.FileFilter() {
+			public boolean accept(File file) {
+				return file.getName().toLowerCase().endsWith(ext);
+			}
+		};
+	}
+
+
+
+	private static AudioInputStream convertFormat(AudioInputStream sin, AudioFormat fin, AudioFormat fout) throws Exception
+	{
+		if (fin==fout) return sin;
+		else if (fin.getEncoding()==AudioFormat.Encoding.PCM_SIGNED) {
+			try { return AudioSystem.getAudioInputStream(fout,sin); }
+			catch (IllegalArgumentException ex) { Shell.trace("Direct conversion failed"); }
+
+			AudioFormat fint = new AudioFormat(  // PCM
+				fout.getSampleRate(), fout.getSampleSizeInBits(),
+				fin.getChannels(), true, fout.isBigEndian());
+			Shell.trace("Trying PCM conversion via "+fint.toString());
+			return AudioSystem.getAudioInputStream(fout,AudioSystem.getAudioInputStream(fint,sin));
+		} else {
+		// First, check for MP3 - if so, cannot convert number of channels
+			if (fin.getChannels()==fout.getChannels() && fin.getSampleRate()==fout.getSampleRate()) {
+				Shell.trace("Trying direct decoding from "+fin.getEncoding().toString());
+				return AudioSystem.getAudioInputStream(fout,sin);
+			} else {
+				AudioFormat fint = new AudioFormat( 
+					fin.getSampleRate(), fout.getSampleSizeInBits(),
+					fin.getChannels(), true, fout.isBigEndian());
+				Shell.trace("Trying conversion via "+fint.toString());
+				return convertFormat(AudioSystem.getAudioInputStream(fint,sin),fint,fout);
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/LineSink.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,129 @@
+/*
+ *	LineSink.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  java.io.*;
+import  javax.sound.sampled.*;
+
+/**
+	An AudioSink that sends samples to a Java Sound SourceDataLine.
+	Audio format can be determined in several ways (see below).
+	<p> Object is a Viewable, and is called "lineout".
+	Reads property "scale" from current environment, but scale
+	can be adjusted afterwards.
+	@see samer.audio.AudioSink
+*/
+
+public class LineSink extends VLine implements AudioSink
+{
+	private SourceDataLine	line;
+	private AudioFormat	   fmt;
+	private int             bufsize=0;
+	private VDouble			scale;
+
+	/** Create LineSink reading from given TargetDataLine */
+	public LineSink(SourceDataLine l, AudioFormat f) throws Exception {
+		super("lineout"); 
+		line=l; fmt=f;
+		Shell.push(getNode());
+		scale=new VDouble("scale",1.0,0);
+		Shell.pop();
+	}
+
+	public DataLine getLine() { return line; }
+	public boolean isOpen() { return line.isOpen(); }
+	public void setBufferSize(int b) { bufsize=b; }
+
+	/**
+	 * Returns the object used to store the scale factor for conversion from
+	 * doubles/floats to shorts/bytes. This is multiplied by 128 for conversion
+	 * to 8 bit audio, or 32768 for conversion to 16 bit audio.
+	*/
+	public VDouble getScale() { return scale; }
+
+	public void dispose() { scale.dispose(); super.dispose(); }
+
+	/** Open the line using either the current format or the line's default format if
+	*	none has been set.
+	*/
+	public void openImpl() throws Exception {
+		if (bufsize==0) line.open(fmt); else line.open(fmt,bufsize);
+	}
+
+	public void closeImpl() throws Exception { line.close(); }
+
+	/** Commands are :"set scale". */
+	public void getCommands(Registry r) {
+		r.add("set scale").group();
+		super.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("set scale")) { env.datum().get(scale); }
+		else super.execute(cmd,env);
+	}
+
+	public Task writer(final double dbuf[], final int off, final int len) {
+		return new Writer(2*len) {
+			public void write(double dbuf[], int off, int len) throws Exception {
+				Util.doubleToShort(dbuf,buf,off,len,scale.value);
+				super.write(2*len);
+			}
+			public void run() throws Exception {
+				super.run();	Util.doubleToShort(dbuf,buf,off,len,scale.value);
+			}
+		};
+	}
+
+	public Task writer(final float dbuf[], final int off, final int len) {
+		return new Writer(2*len) {
+			public void write(float dbuf[], int off, int len) throws Exception {
+				Util.floatToShort(dbuf,buf,off,len,(float)scale.value);
+				super.write(2*len);
+			}
+			public void run() throws Exception {
+				super.run();	Util.floatToShort(dbuf,buf,off,len,(float)scale.value);
+			}
+		};
+	}
+
+	protected class Writer implements Task {
+		byte buf[];
+		int		size;
+
+		public Writer(int bufsize) { size=bufsize; buf=new byte[size]; }
+
+		public void starting() { start(); }
+		public void stopping() { stop(); }
+		public void dispose() {}
+		public void run() throws Exception {
+			if (line.write(buf,0,size)<=0) throw new EOFException();
+			changed();
+		}
+
+		public void write(int size) throws Exception {
+			if (line.write(buf,0,size)<=0) throw new EOFException();
+			changed();
+		}
+	}
+
+	public static DataLine.Info lineInfo(AudioFormat fmt) {
+		return new DataLine.Info( SourceDataLine.class, fmt); 
+	}
+
+	public static DataLine.Info lineInfo(AudioFormat fmt, int bufsize) {
+		return new DataLine.Info( SourceDataLine.class, fmt, bufsize); 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/LineSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,93 @@
+/*
+ *	LineSource.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+import  samer.core.*;
+import  samer.tools.*;
+import  java.io.*;
+import  javax.sound.sampled.*;
+
+/**
+	An AudioSource that reads from the sound card in real time.
+	Uses a standard JavaSound TargetDataLine to get data.
+	However, an alternative DataLine can be supplied instead.
+	Audio format is determined by current environment--see
+	VLine.
+	<p> Object is a Viewable, and is called "linein". Node is
+	created in current context, ie with a parent determined by
+	current Environment.
+	@see samer.core.AudioSource
+*/
+
+public class LineSource extends VLine implements AudioSource
+{
+	private TargetDataLine	line;
+	private AudioFormat	fmt;
+	private int          bufsize=0;
+
+	/** Create LineSource reading from given TargetDataLine */
+	public LineSource(TargetDataLine l,AudioFormat f) throws Exception {
+		super("linein"); line=l; fmt=f;
+	}
+
+	public void setBufferSize(int b) { bufsize=b; }
+
+	public DataLine getLine() { return line; }
+	public boolean  isOpen() { return line.isOpen(); }
+
+	/** Open using default format */
+	public void openImpl() throws Exception {
+		if (bufsize==0) line.open(fmt); else line.open(fmt,bufsize);
+	}
+
+	public void closeImpl() throws Exception { line.close(); }
+
+	public Task reader(final double dbuf[], final int off, final int len) {
+		return new Reader(2*len) {
+			public void run() throws Exception {
+				super.run();	Util.shortToDouble(buf,dbuf,off,len);
+			}
+		};
+	}
+
+	public Task reader(final float dbuf[], final int off, final int len) {
+		return new Reader(2*len) {
+			public void run() throws Exception {
+				super.run();	Util.shortToFloat(buf,dbuf,off,len);
+			}
+		};
+	}
+
+
+	protected class Reader implements Task {
+		byte buf[];
+		int		size;
+
+		public Reader(int bufsize) { size=bufsize; buf=new byte[size]; }
+
+		public void starting() { start(); }
+		public void stopping() { stop(); }
+		public void dispose() {}
+		public void run() throws Exception {
+			if (line.read(buf,0,size)<=0) throw new EOFException();
+			changed();
+		}
+	}
+
+	public static DataLine.Info lineInfo(AudioFormat fmt) {
+		return new DataLine.Info( TargetDataLine.class, fmt); 
+	}
+
+	public static DataLine.Info lineInfo(AudioFormat fmt, int bufsize) {
+		return new DataLine.Info( TargetDataLine.class, fmt, bufsize); 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/audio/VLine.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,122 @@
+/*
+ *	VLine.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.audio;
+
+import javax.sound.sampled.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.util.swing.Meter;
+import samer.core.types.*;
+
+/**
+	A Viewable for exposing a Javasound DataLine object.
+	The Agent responds to these commands: "open", "close", "info"
+	"start", "stop", "drain" and "flush".
+
+	Changes:
+	16/6/03: removed ClipAgent class. Don't care about clips.
+		Also removed line members from agent classes: they now use
+		local variables in the execute method instead.
+*/
+
+public abstract class VLine extends Viewable implements Agent
+{
+	public VLine(String name) {
+		super(name); 
+		setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	abstract DataLine getLine();
+	abstract void openImpl() throws Exception;
+	abstract void closeImpl() throws Exception;
+
+	/** Open the line using its default format */
+	public void open() throws Exception { openImpl(); }
+
+	/** Close the line */
+	public void close() {
+		try{ closeImpl(); }
+		catch (Exception ex) {
+			Shell.trace("line failed to close: "+ex);
+		}
+	}
+
+	public void start() {
+		Shell.status("starting line");
+		getLine().start();
+		Shell.status("line started");
+	}
+
+	public void stop() {
+		Shell.status("stopping line");
+		getLine().stop();
+		Shell.status("line stopped");
+	}
+
+	public void dispose() { close(); super.dispose(); }
+
+	public Viewer getViewer() { return new LineViewer(getLine()); }
+
+	public void getCommands(Agent.Registry r) {
+		r.add("start").add("stop").add("flush");
+		r.add("open").add("close").add("info");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("start")) start();
+		else if (cmd.equals("stop")) stop();
+		else if (cmd.equals("drain")) { getLine().drain(); changed(); }
+		else if (cmd.equals("flush")) { getLine().flush(); changed(); }
+		else if (cmd.equals("open")) open();
+		else if (cmd.equals("close")) close();
+		else if (cmd.equals("info")) {
+			Shell.print("Line information: "+getLabel());
+			Shell.print(getLine().getLineInfo().toString());
+			Shell.print("Format: "+getLine().getFormat());
+			Shell.print("Buffer size: "+getLine().getBufferSize());
+		}
+	}
+
+	public String toString() { return super.toString()+"="+getLine().getFormat(); }
+
+	class LineViewer extends BaseViewer
+	{
+		Meter			meter=null;
+		DataLine		line;
+
+		public LineViewer(DataLine line) {
+			super(VLine.this);
+			setLayout( new VLayout(1,4));
+			setText(getLabel());
+
+			if (Shell.getBoolean("meter",true)) {
+				Shell.push("meter");
+				meter = new Meter();
+				meter.getMap().setDomain(0,line.getBufferSize());
+				Shell.pop();
+				add(meter);
+			}
+			Shell.pop();
+		}
+
+		public void update(Observable o, Object src) {
+			if (src==Viewable.DISPOSING) super.update(o,src);
+			else if (meter!=null) meter.next(line.available());
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Agent.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *	Agent.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+
+/**
+	An Agent is something that can handle commands.
+	It can also optionally report which commands it
+	can handle so that they can be exposed in some
+	way, eg buttons or a menu.
+ */
+
+public interface Agent
+{
+	/**
+		Bad interface name, I know, but a Registry is
+		supplied to an agent so that it can report
+		which commands it handles. The implementation
+		of the Registry can do whatever it likes with
+		the names: compile a list, create buttons or a
+		menu, or just ignore them.
+
+		<p>May eventually want to be able to supply
+		more information abdut a command, so that we
+		can, eg, put an icon on a toolbar or have a
+		tool tip
+	 */
+
+	public interface Registry {
+		Registry add( String name);
+
+		/**
+			The second form of add, with a boolean
+			second argument suggests that the command expects
+			a boolean argument and can thus be associated
+			with a checkbox or check menu item.
+		 */
+
+		Registry add( String name, boolean initialValue);
+
+		/** 
+			This means that the following commands reported
+			to add() are to be directed to a different Agent
+		 */
+
+		void     setTarget(Agent a);
+
+		/** this means start a new group */
+		void group(); 
+	}
+
+	/** Implementations can use the Registry to report which
+		commands they respond to */
+	void getCommands(Registry r);
+
+	/** This must do what the named command says using the given Environment
+		for parameters or supplimentary data. */
+	void execute( String name, Environment env) throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/Agent.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/CompoundAgent.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/DoubleFormat.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Environment.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Node.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/NumberSink.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/NumberViewer.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Registry.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Saveable.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Saver.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Shell.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Variable.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Viewable.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/Viewer.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/X.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+D/shells////
+D/types////
+D/util////
+D/viewers////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/CompoundAgent.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+/*
+ *	CompoundAgent.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+
+/** An Agent that is a composition of two given Agents. */
+public class CompoundAgent implements Agent
+{
+	Agent a1, a2;
+
+	public CompoundAgent(Agent a1,Agent a2) { this.a1=a1; this.a2=a2; }
+
+	/** This reports the commands from both the child agents. Duplicate
+		commands are not removed. */
+	public void getCommands(Registry r) { a1.getCommands(r); r.group(); a2.getCommands(r); }
+
+	/** Forwards the the command on to BOTH child agents in the order specified
+		in the constructor. */
+	public void execute( String name, Environment env) throws Exception {
+		a1.execute(name,env);
+		a2.execute(name,env);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/DoubleFormat.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,69 @@
+/*
+ *	DoubleFormat.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+import  java.text.*;
+
+public class DoubleFormat extends NumberFormat
+{
+	int nfix=2;
+
+	public DoubleFormat(int n) { setDecimals(n); }
+
+	public void   setDecimals(int n) { nfix=n; }
+	public String _format(double x) { return format(x,nfix); }
+	public double _parse(String s) { return Double.valueOf(s).doubleValue(); }
+
+
+	public StringBuffer format( long n, StringBuffer buf, FieldPosition fp) {
+		buf.append(n);
+		return buf;
+	}
+	public StringBuffer format( double x, StringBuffer buf, FieldPosition fp) {
+		buf.append(x);
+		return buf;
+	}
+
+	public Number parse(String s, java.text.ParsePosition pp) {
+		return Double.valueOf(s);
+	}
+	// ...............................................
+
+	public static String format( double x, int nfix)
+	{
+		int nfixPlus1=nfix+1;
+		// quick and dirty hack!
+		String s=Double.toString(x);
+		int	point = s.indexOf('.');
+
+		// no decimals: return as is
+		if (point==-1) return s;
+
+		// look for exponent
+		int	exp = s.indexOf('E',point);
+
+		if (exp==-1) {
+			// no exponent: count decimals
+			if (s.length()-point <= nfixPlus1) return s;
+			else {
+				// chop off excess precision
+				return s.substring(0,point+nfixPlus1);
+			}
+		} else {
+			// count digits up to exponent
+			if (exp-point < nfixPlus1) return s;
+			else {
+				// return truncated mantissa and exponent
+				return s.substring(0,point+nfixPlus1) + s.substring(exp);
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Environment.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,247 @@
+/*
+ *	Environment.java
+ *
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+
+/**
+	An Environment is a way of managing named values.
+	The names form a heirarchical system using dot (.) as
+	a seperator. (See Node class)
+
+	Each Environment has a parent Environment, except for the
+	singleton top level Environment.
+
+	Each Environment has a Node which serves as a 'current
+	directory'. Environments form a chain: if one
+	Environment cannot satisfy a request for a named
+	binding, it should ask its parent.
+
+	@see samer.core.Node
+	@see samer.core.X
+ */
+
+public class Environment
+{
+	protected Environment	parent;
+	protected Node			base;
+
+	/** Construct a new Environment with the given parent
+		and base node */
+	public Environment(Environment parent, Node base) { this.parent=parent; this.base=base; }
+
+	/** Construct a new Environment with the given parent
+		and a base node relative to the parent Environment.
+	  	That is, <code>node = new Node(name, parent.node());</code>
+	*/
+	public Environment(Environment parent, String name) {
+		this(parent,new Node(name,parent.base));
+	}
+
+	/** Return this environment's parent, or null of top level */
+	public final Environment parent() { return parent; }
+
+	/** Return this environment's associated node */
+	public final Node node() { return base; }
+
+	/*
+	 *	these methods form the main implementation of the Environment and
+	 * are meant to be overridden by subclasses.
+	 */
+
+	 /** Add and return a new named binding */
+	public Binding	add(String nm, Object o)      { return parent.add(abs(nm),o); }
+
+	 /** Add anonymous datum */
+	public void		add(Object obj)               { parent.add(obj); }
+
+	public void		store(String nm, Autocoder o) { parent.store(abs(nm),o); }
+	public void		store(String nm, Object o, Codec c) { parent.store(abs(nm),o,c); }
+
+	/** Return next anonymous datum */
+	public Datum	datum()            { return parent.datum(); }
+
+	/** Return Datum that best matches given name */
+	public Datum	datum(String name) { return parent.datum(abs(name)); }
+
+	/** Return Binding that best matches given name */
+	public Binding	binding(String name) { return parent.binding(abs(name)); }
+
+	/** Return an Iterator that will step through all data in this
+		Environment and it's ancestors */
+	public Iterator data() { return parent.data(); }
+
+	// ... Interfaces ....................................................
+
+	/**
+		Basic interface for getting at a particular stored object or
+		value.
+		There is no concept of returning the value as-is: it must
+		be translated in to an object of some desired class.
+		Value can be extracted in one of two ways:
+		a Codec, which is an object which knows how to convert
+		between stored data and some desired class of object.
+		The other way is via an Autocoder, which is basically
+		an object with it's own Codec built in.
+	*/
+
+	public interface Datum {
+
+		/** the stored name of this Datum */
+		String	name();
+
+		/** goodness of name matching procedure used to find this Datum */
+		int		score();
+
+//		Object	get() throws Exception;					// return intrinsic class ??
+//		Object	get(Codec c) throws Exception; 		// no default supplied
+
+		/** return object as decoded by Codec c. If this Datum is a
+			null Datum, ie contains no data, return def */
+		Object	get(Codec c, Object def); // ?? copy semantics?	 exception?
+
+		/** decode value in to Autocoder obj */
+		void get(Autocoder obj) throws Exception;
+
+	}
+
+	/**
+		A Binding is a Datum in which the value is an accessible Object,
+		ie one that doesn't need decoding. Unlike a Datum, this value
+		can be set or removed from the Environment.
+	*/
+	public interface Binding extends Datum {
+		Object	get() throws Exception;
+		void		set(Object obj);
+		void		remove();
+	}
+
+	/**
+		A null Binding that has no data.
+		All attempts to read value throw an Exception, except get()
+		with a default supplied.
+		*/
+	public final static Binding Null = new Binding() {
+		public String	name()  { return "null"; }
+		public int		score() { return 1000000000; } // Mr. Billion
+
+		public Object	get() throws Exception { throw new Exception(); }
+		public Object	get(Codec c, Object def) { return def==null ? def : c.decode(def); } // ??
+		// public void		get(Autocoder obj) throws Exception { throw new Exception(); }
+		public void		get(Autocoder obj) {}
+
+		public void		set(Object obj) { throw new RuntimeException(); }
+		public void		remove() { throw new RuntimeException(); }
+	};
+
+	/** This is an object which knows how to code and decode itself. */
+	public interface Autocoder
+	{
+		/** return this object as a string */
+		String string(); 		// as string
+
+		/** return this object as any object of a convenient class.
+			Strictly speaking, should return an <i>immutable</i>
+			representation of the object.
+		*/
+		Object object();
+
+		/** set this object by decoding supplied object, which may be
+			a string. This method can be as smart as you like, behaving
+			differently for different classes of supplied object.
+		*/
+		void   decode(Object o);
+	}
+
+	/** This is an object which knows how to code and decode on behalf
+		of some other class which represents the actual data. */
+	public interface Codec {
+		/** return Class of object that this Codec deals with */
+		Class  targetClass();
+
+		// methods for encoding object for storage
+		String string(Object o); // convert object to string
+		Object object(Object o); // convert object to another object
+		Object decode(Object o); // convert other object to target class
+	}
+
+	/** For iterating through data in environment,
+		returning a Datum for each item
+	*/
+	public interface Iterator {
+		boolean	hasNext();
+		Datum		next();
+	}
+
+	/** Steps through two iterators consecutively */
+	protected static class CompoundIterator implements Iterator {
+		Iterator i1, i2;
+		public CompoundIterator(Iterator a, Iterator b) { i1=a; i2=b; }
+		public boolean hasNext() {
+			if (i1.hasNext()) return true;
+			if (i2==null) return false;
+			i1=i2; i2=null; return i1.hasNext();
+		}
+		public Datum next() {
+			if (i1.hasNext())	return i1.next();
+			i1=i2; i2=null; return i1.next();
+		}
+	}
+
+	// ...................................................................
+
+	/** Return absolute node path for given name. If name begins
+		with '.', then it is already an absolute name. Otherwise, the
+		base node for this Environment is prepended.
+	*/
+	public final String abs(String name) {
+		return Node.isAbsolute(name) ? name : base.fullNameFor(name);
+	}
+
+	/** Return node name relative to this Environment's node.
+		Throws an Exception if the supplied name is absolute and
+		NOT a child of this Environment's node.
+	*/
+	public final String rel(String name) {
+		if (!Node.isAbsolute(name)) return name;
+		String fullbase=base.fullName();
+		if (!name.startsWith(fullbase)) throw new Error("nonlocal node name:" + name);
+		return name.substring(fullbase.length()+1); // miss out dot!
+	}
+
+	/** Returns true if the given name is a subnode of this environment's node,
+		ie, if it can belong in this environment
+		*/
+	protected boolean belongs(String name) { return base.isSubnode(name); }
+	
+	/** Return a top level environment */
+	public  static Environment top() { 
+		return new Environment(null,Node.root()) {
+			public Binding	add(String n, Object o) { throw error(); }
+			public void		add(Object o)				{ throw error(); }
+			public void		store(String nm, Object o, Codec c) { throw error(); }
+			public void		store(String nm, Autocoder o)       { throw error(); }
+	
+			public Datum	datum()            { return Null; }
+			public Datum	datum(String name) { return Null; }
+			public Binding binding(String name) { return Null; }
+	
+			public Iterator data() {
+				return new Iterator() {
+					public boolean	hasNext() { return false; }
+					public Datum	next() { return Null; }
+				};
+			}
+	
+			RuntimeException error() { return new RuntimeException("Environment.top"); }
+		};													 
+	}
+}													 
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Node.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,99 @@
+/*
+ *	Node.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *	Change history:
+ *
+ *	Removed all references to parent nodes - each node now
+ *	stores its full name. Uses more memory but simpler in the
+ *	long run, I think.
+ */
+
+package samer.core;
+import java.util.*;
+
+/**
+	<p> A Node is essentially a path in a hierarchical
+	name space. Each node is an independent object. 
+	A Node can be constructed either with an explicit
+	parent Node, or with an absolute path, or as a child
+	of the current Node maintained by the current Shell.
+	Names are constructed in parts, concatenated with 
+	dots, eg,
+	<code>
+		Node A=new Node("top",null);
+		Node B=new Node("middle",A);
+		Node C=new Node("bottom",B);
+	</code>
+	Then node A is "top", node B is "top.middle" and node
+	C is "top.middle.bottom"
+
+	<p>The top level Environment (see Environment)
+	actually uses a nameless top level node: "", so that
+	all fully specified node paths begin with ".", eg
+	".antelope.gibbon.firebucket"
+	This is so that names that <I>don't</I> start with a
+ 	dot are treated as relative to the current Environment's node.
+ */
+
+public class Node implements java.io.Serializable
+{
+	private final String	name;
+
+	/** Construct new Node with given name as a child of the
+		current Environment's base node, ie
+		<code>Shell.env().node()</code>
+	 */
+	public Node(String name) {
+		if (name==null || name.equals(""))
+			throw new Error("Node with empty name");
+
+		if (isAbsolute(name)) this.name=name;
+		else this.name=Shell.env().node().fullNameFor(name);
+	}
+
+
+	private Node() { name=""; }
+
+	/** Construct new Node with given name and parent
+		If parent is null, a top level node is created
+	*/
+	public Node(String name, Node parent) { this.name = parent.fullName()+"."+name; }
+
+	/** Returns parent Node, or null if no parent */
+	public Node   getParent()	{ return new Node(name.substring(0,name.lastIndexOf('.'))); }
+	public static String lastPart(String str) { return str.substring(1+str.lastIndexOf('.')); }
+	public String fullName() { return name; }
+	public String shortName() { return lastPart(name); }
+
+	/** Return full name of hypothetical Node with given name
+		as a child of this Node, ie, this node's full name + "."+ nm.
+	*/
+	public String fullNameFor(String nm) { return name+"."+nm; }
+
+	/** Absolute names start with a . This is only true of the top
+		level Node has an empty name!
+	*/
+	public static boolean isAbsolute(String nm) { return (nm.charAt(0)=='.'); }
+
+	/** Returns true if and only if the given name is a child of this one.
+		This is trivially true if the given name is relative (ie doesn't start
+		with a dot). If it does, then the initial substrings must match.
+	*/
+	public boolean isSubnode(String nm) {
+		if (!isAbsolute(nm)) return true;
+		return nm.startsWith(name);
+	}
+
+	/** Returns the full name of this node. */
+	public String toString() { return name; }
+
+	/** Returns a NEW top-level node each time it is called. */
+	public static Node root() { return new Node(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/NumberSink.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,9 @@
+package samer.core;
+
+/** Trivial interface for something that has a settable number,
+	integer or floating point. */
+public interface NumberSink
+{
+	void set(int n);
+	void set(double n);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/NumberViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,12 @@
+package samer.core;
+
+/** Interface for something something which is a Viewer and
+	has a settable number. */
+public interface NumberViewer extends Viewer, NumberSink
+{
+	// creation flags
+	final static int SLIDER=0x01;
+	final static int TEXT=0x02;
+	final static int INTEGER=0x04;
+	final static int BOUNDED=0x08;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Registry.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,49 @@
+package samer.core;
+import  java.util.Hashtable;
+
+/**
+	The Registry stores Object class - Viewer class pairs.
+	Associations can be added as Class objects or Class names (Strings).
+	When creating a Viewer for a given object, matching is done on the
+	basis that an exact Class matches is preferred, but failing that, parent
+	Class matches are attempted up the Class heirarchy until a match is
+	found.
+*/
+
+public class Registry
+{
+	static { Shell.trace("initialising Registry"); }
+	private static Hashtable map=new Hashtable();
+
+	/** register viewer as a Viewer class for objects of class obj */
+	public static void put(Class obj, Class viewer) { map.put(obj.getName(),viewer); }
+
+	/** Registering by class name saves loading the class itself
+		until it is actually needed. */
+	public static void put(String obj, String viewer) { map.put(obj,viewer); }
+
+	/** Create and return a Viewer for the supplied object */
+	public static Viewer createViewer(Object obj)
+	{
+		Class cl=obj.getClass();
+
+		// lookup by class NAME
+		Object vwr=map.get(cl.getName());
+		while (vwr==null) {
+			cl=cl.getSuperclass();
+			if (cl==null) return null;
+			vwr=map.get(cl.getName());
+		}
+
+		Class [] types = { cl };
+		Object [] parms = { obj };
+
+		try {
+			if (vwr instanceof String) vwr=Class.forName((String)vwr);
+			return (Viewer)((Class)vwr).getConstructor(types).newInstance(parms);
+		} catch (Exception ex) {
+			Shell.trace(ex.toString());
+			return null;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Saveable.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,15 @@
+package samer.core;
+
+import java.io.*;
+
+/** Interface for objects that can be saved in
+	binary or text format. Don't need to implement all
+	methods, eg if no binary format. Just throw an exception
+	instead. */
+
+public interface Saveable {
+	void load(InputStream in) throws Exception;
+	void save(OutputStream out)  throws Exception;
+	void read(Reader rdr)  throws Exception;
+	void write(Writer wr)  throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Saver.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,76 @@
+package samer.core;
+
+import samer.core.types.*;
+import java.io.*;
+
+/** An Agent that manages saving and loading of a Saveable object */
+
+public class Saver implements Agent {
+	Saveable	obj;
+	VFile			file, txtfile;
+
+	public Saver(Saveable obj) { init(obj); }
+	public Saver(Saveable obj, Node node) {
+		Shell.push(node); init(obj); Shell.pop();
+	}
+
+	public void setName(String n) { file.setFile(new File(n)); }
+	public File 	getFile() { return file.getFile(); }
+
+	private void init(Saveable obj) {
+		this.obj=obj;
+		file = new VFile("file","",0);
+		txtfile = new VFile("text file","",0);
+	}
+
+	public void load() throws Exception {
+		Shell.print("loading "+obj+" from "+file);
+		FileInputStream f=new FileInputStream(file.getFile());
+		try { obj.load(new BufferedInputStream(f)); } finally { f.close(); }
+	}
+
+	public void save() throws Exception {
+		Shell.print("saving "+obj+" to "+file);
+		OutputStream f=new BufferedOutputStream( new FileOutputStream(file.getFile()));
+		try { obj.save(f); } finally { f.close(); }
+	}
+
+	public void read() throws Exception {
+		Shell.print("loading "+obj+" as text from "+txtfile);
+		FileReader f=new FileReader(txtfile.getFile());
+		try { obj.read(f); } finally { f.close(); }
+	}
+
+	public void write() throws Exception {
+		Shell.print("saving "+obj+" as text to "+txtfile);
+		Writer w=new BufferedWriter(new FileWriter(txtfile.getFile()));
+		try { obj.write(w); } finally { w.close(); }
+	}
+
+	public void getCommands(Registry r)
+	{
+		r.add("load").add("load text");
+		r.group();
+		r.add("save as").add("save").add("save text");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("load")) {
+			try { 	env.datum().get(file); load(); }
+			catch (Exception x) { Shell.print("Error loading: "+x); }
+		} else if (cmd.equals("save as")) {
+			try { 	env.datum().get(file); txtfile.decode(file.string()+".txt"); save(); }
+			catch (Exception x) { Shell.print("Error saving: "+x); }
+		} else if (cmd.equals("save")) {
+			try { 	save(); }
+			catch (Exception x) { Shell.print("Error saving: "+x); }
+		} else if (cmd.equals("load text")) {
+			try { env.datum().get(txtfile); read(); }
+			catch (Exception x) { Shell.print("Error reading: "+x); }
+		} else if (cmd.equals("save text")) {
+			try { env.datum().get(txtfile); write(); }
+			catch (Exception x) { Shell.print("Error writing: "+x); }
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Shell.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,464 @@
+/*
+ *	Shell.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+import java.io.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+import samer.core.Environment.Datum;
+import samer.core.Environment.Binding;
+import samer.core.Environment.Autocoder;
+
+
+
+/**
+	This class provides a set of static methods for
+	some useful services. The actual implementation is 
+	provided by some object that implements the
+	Shell.Interface interface.
+  */
+
+public class Shell
+{
+	/** All shells must implement this interface. It provides service that
+	  *   are generally useful but can be implemented in different ways, such
+	  *   as printing messages and getting usable windows. */
+
+	public interface Interface
+	{	
+		// different types of message
+		void print(String msg); 
+		void status(String msg); 
+		void trace(String msg); 
+
+		// factory methods
+		PrintWriter	getPrintWriter();
+		Window		getWindow(String title);
+		Dialog			getDialog(String title); 
+
+		Container		createButtonsFor(Agent agent);
+		Viewer		createViewerPanel(Viewer vwr);
+		Component	createLabel(String nm);
+
+		NumberViewer createNumberViewer( String label, int flags, NumberSink s);
+
+		// agents and viewables
+		void registerViewable(Viewable v);
+		void deregisterViewable(Viewable v);
+		void registerAgent(Agent a);
+		void deregisterAgent(Agent a);
+		void exposeCommands(Agent agent);
+		void exit();
+	}
+
+
+	/**
+		Interface returned by the getWindow method of the
+		Shell.Interface interface. The window is not necessarily
+		visible on return -- use the <code>expose()</code>
+		method to make it so.
+		NB: distinct from java.awt.Window.
+	 */
+
+	public interface Window {
+		/** Make window visible */
+		void expose();
+
+		/** Hide and destroy window */
+		void dispose();
+
+		/** Should behave just like in <code>java.awt.Window</code> */
+		void addWindowListener(WindowListener wl);
+
+		/** Returns the AWT container for this window, in to
+			which components can be added in the normal way */
+		Container container();
+	}
+
+	/**
+		Interface returned by the getDialog method of the
+		Shell.Interface interface. The dialog is not necessarily
+		visible on return -- use the <code>expose()</code>
+		method to make it so.
+		<p>A dialog is distinct from a window in that it
+		is modal, and is dismissed by one of a set of buttons.
+		<p>NB: distinct from java.awt.Dialog
+	 */
+
+	public interface Dialog {
+		/** Make dialog visible */
+		void expose();
+
+		/** Hide and destroy dialog */
+		void dispose();
+
+		/** Typically, the dialog will add a new button with the
+			given label. */
+		void      addAction(String cmd);
+
+		/** Returns the text of the button used to dismiss the dialog */
+		String    result();
+
+		/** Returns the AWT container for this window, in to
+			which components can be added in the normal way */
+		Container container();
+	}
+
+
+
+	// .......................................................
+
+	/** Sets the static current shell to point to the given shell */
+	public static void setShell(Interface sh) { current=sh; }
+
+	public static void print(String msg) { current.print(msg); }
+	public static void status(String msg) { current.status(msg); }
+	public static void trace(String msg) { current.trace(msg); }
+
+	public static PrintWriter getPrintWriter() { return current.getPrintWriter(); }
+	public static Window	getWindow(String title) { return current.getWindow(title); }
+	public static Dialog	getDialog(String title) { return current.getDialog(title); }
+
+	/** Create and return a new Panel containing the given Viewer */
+	public static Viewer	createViewerPanel(Viewer v ) {
+		return current.createViewerPanel(v);
+	}
+
+	/** Return an AWT Container containing buttons for each the
+		commands reported by the given Agent */
+	public static Container createButtonsFor(Agent a) {
+		return current.createButtonsFor(a);
+	}
+
+	/** Return a label component. Can be AWT, Swing, or whatever */
+	public static Component createLabel(String txt) {
+		return current.createLabel(txt);
+	}
+
+	public static NumberViewer createNumberViewer( String l, int f, NumberSink dm) {
+		return current.createNumberViewer(l,f,dm);
+	}
+
+	public static NumberViewer createNumberViewer( String l, int f) {
+		return current.createNumberViewer(l,f,null);
+	}
+
+	// .......................................................
+	private static boolean reg=true;
+
+	/** If false, subsequent calls to <code>registerViewable()</code>
+		 are ignored */
+	public static boolean setAutoRegister(boolean f) { boolean old=reg; reg=f; return old; }
+	public static void registerAgent(Agent a) { current.registerAgent(a); }
+	public static void deregisterAgent(Agent a) {  current.deregisterAgent(a); }
+	public static void registerViewable(Viewable v) { if (reg) current.registerViewable(v); }
+	public static void deregisterViewable(Viewable v) { current.deregisterViewable(v); }
+	public static void exposeCommands(Agent a) { current.exposeCommands(a); }
+	public static void exit() { current.exit(); }
+
+	// .......................................................
+	// these two are for handling commands
+
+	/** The interface for any kind of string interpreter */
+	public interface Interpreter {
+		/** Do something with no return value */
+		void execute(Reader txt);
+
+		/** Evaluate something and return a value
+			(perhaps we should require with no side-effects?) */
+		Object evaluate(Reader txt);
+	}
+
+	private static Interpreter interp=new Interpreter() {
+		public void execute(Reader txt) { Shell.print("Sorry - don't know how"); }
+		public Object evaluate(Reader txt) { throw new Error("no interpreter"); }
+	};
+
+
+	/** Set the current interpreter that is statically available */
+	public static void setInterpreter(Interpreter i) { interp=i; }
+
+	/** Use the current interepreter to interpret the given String */
+	public static void interpret(String cmd) { interp.execute(new StringReader(cmd)); }
+	/** Use the current interepreter to interpret commands from the Reader */
+	public static void interpret(Reader in) { interp.execute(in); }
+
+
+
+	// .......................................................
+	// Environments
+
+	private static Stack			stack=new Stack();		// environment stack
+	private static Environment	_env=Environment.top();  		// current environment
+	private static Interface		current=new DefaultShell();	// current shell
+
+	/** Pops the top of the Environment stack. The one below
+		becomes the new current environment. */
+	public static void pop() { _env=(Environment)stack.pop(); }
+
+	/** Push given Environment on top of stack. It becomes
+		the new current environment. */
+	public static void push(Environment e) { stack.push(_env); _env=e; }
+
+	/** Pushes a new environment which contains no data but
+		has the given base node. Used to establish a new node context */
+	public static void push(Node n) { push(new Environment(_env,n)); }
+
+	/** The same as <code>push(new Node(nm)) </code> ie, uses
+		base node of current environment as a parent */
+	public static void push(String nm) { push(new Environment(_env,nm)); }
+
+	/** Return current node, the one at the top of the stack (without removing it)  */
+	public static Environment env() { return _env; }
+
+	// -------------------------------------------------------
+
+	/** Get a double value from the current environment. Name
+		can be absolute or relative to current base node. Returns def
+		if no matching value is found */
+	public static double getDouble(String nm, double def)    {
+		return X._double(datum(nm),def);
+	}
+
+	/** See description for getDouble() */
+	public static int		getInt(String nm, int def)          {
+		return X._int(datum(nm),def);
+	}
+
+	/** See description for getDouble() */
+	public static boolean getBoolean(String nm, boolean def) {
+		return X._bool(datum(nm),def);
+	}
+
+	/** See description for getDouble() */
+	public static String getString(String nm, String def)    {
+		return X.string(datum(nm),def);
+	}
+
+	/** Get a String from current environment, throwing an Exception
+		if no value is found. */
+	public static String getString(String nm) throws Exception {
+		return X.string(datum(nm));
+	}
+
+	public static Color	getColor(String nm, Color def)      {
+		return X.color(datum(nm),def);
+	}
+
+	/** Search for named Datum in current Environment. */
+	public static Datum   datum(String nm) { return _env.datum(nm); }
+
+	/** Add and return new binding to current environment. */
+	public static Binding put(String nm, Object o) { return _env.add(nm,o); }
+
+	/** Search for and return object bound to given name. */
+	public static Object  get(String nm) throws Exception {
+		return _env.binding(nm).get();
+	}
+
+	/** Search for and return object bound to given name. */
+	public static Object  get(String nm,Object def) {
+		try { return _env.binding(nm).get();}
+		catch (Exception ex) { return def; }
+	}
+
+	/** Remove named binding from current environment, ONLY if it
+		is bound to the given object. */
+	public static void remove(String nm, Object vl) {
+		Binding v=_env.binding(nm);
+		try { if (v.get()==vl) v.remove(); }
+		catch (Exception ex) { Shell.trace("Shell.remove error: "+ex); }
+	}
+
+
+	public static void exposeCommands(final Object[] cmds)
+	{
+		// create a temporary Agent to manage the array of command names
+		exposeCommands( new Agent() {
+			public void getCommands(Agent.Registry r) {
+				r.setTarget(null);
+				for (int i=0; i<cmds.length; i++) r.add((String)cmds[i]);
+			}
+			public void execute(String cmd, Environment env) {}
+		} );
+	}
+
+	// .......................................................
+	// helper functions for creating windows and dialogs
+
+
+	/** Creates and shows a dialog containing the given component
+		and "ok" and "cancel" buttons. Returns "ok" or "cancel"
+		depending on which button was pressed. */
+
+	public static String showDialogFor(Component comp, String name)
+	{
+		Dialog	dlg = Shell.getDialog(name);
+
+		dlg.container().add(comp);
+		dlg.addAction("cancel");
+		dlg.addAction("ok");
+		dlg.expose();
+		dlg.dispose();
+
+		return dlg.result();
+	}
+
+
+
+	/**
+		Expose the given Viewer. Uses the Shell.getWindow() to get
+		some screen space, and adds the Viewer's component into the
+		Shell.Window's container.
+	  */
+
+	public static Window showViewer( Viewer vwr, String name) {
+		return expose(vwr.getComponent(),name);
+	}
+
+	/** same as showViewer() */
+	public static Window expose( Viewer vwr, String name) {
+		return expose(vwr.getComponent(),name);
+	}
+
+	
+	/**
+		Expose the given AWT Component. Uses the Shell.getWindow() to get
+		some screen space, and adds the component into the
+		Shell.Window's container. The window is given the supplied name.
+	  */
+
+	public static Window expose( Component c, String name) {
+		Component [] cs = {c};
+		return expose(cs,name);
+	}
+
+	/**
+		Expose a bunch of Components in one window with the given name.
+		The layout is the default one determined by the current shell's implementation
+		of getWindow().
+	  */
+	public static Window expose( Component[] cs, String name)
+	{
+		Window win = Shell.getWindow(name);
+		ViewerWindowListener l=new ViewerWindowListener(win,null); // vwr);
+
+		//win.container().setLayout(new BoxLayout());
+		//win.container().setLayout(new BorderLayout());
+		// win.container().add(c,BorderLayout.CENTER);
+		if (cs!=null) for (int i=0; i<cs.length; i++) win.container().add(cs[i]);
+		win.container().addContainerListener(l);
+		win.addWindowListener(l);
+		win.expose();
+		return win;
+	}
+
+
+	/**
+		Completely removes all trace of the given viewer. Works by calling
+		its detach() method	to relinquish any resources and drop
+		references to itself, and removing it from its parent container
+		if it has one.
+	  */
+
+	public static void releaseViewer(Viewer vwr)
+	{
+		vwr.detach();
+		Component c=vwr.getComponent();
+		Container p=c.getParent();
+		if (p!=null) p.remove(c);
+	}
+
+
+
+	/**
+		A singleton WindowListener that, when attached to a Window, calls
+		Shell.exit() when the window is closed.
+	 */
+
+	public static WindowListener exitListener() { return exitter; }
+	private static WindowListener exitter = new WindowAdapter() {
+		public void windowClosing(WindowEvent e) { Shell.exit(); }
+	};
+
+
+
+	// Private listener class for handling a window containing a viewer
+
+	public static WindowListener closeListener(Window w) { return new ViewerWindowListener(w,null); }
+	private static class ViewerWindowListener extends WindowAdapter implements ContainerListener
+	{
+		Viewer	vwr;
+		Window	win;
+		public ViewerWindowListener(Window w, Viewer v) { win=w; vwr=v; }
+		public void windowClosing(WindowEvent e) { if (vwr!=null) vwr.detach(); win.dispose(); }
+		public void componentAdded(ContainerEvent e) {}
+		public void componentRemoved(ContainerEvent e) {
+			if (win.container().getComponentCount()>0) win.container().validate();
+			else EventQueue.invokeLater( new Runnable() { public void run() { win.dispose(); }});
+		}
+	}
+}
+
+
+
+
+/**
+	A fairly minimal implementation of Shell.Interface
+	Much of the functionality is missing:
+	<ul>
+	<li>Implementations of print, status
+	and trace go directly to System.out, System.out and System.err respectively,
+	hence usually to stdout and stderr.
+
+	<li> Window, dialog, button, label, Viewer creation functions all return null.
+	<li> Register agent or viewable does nothing.
+	<lI> exit() exits the JVM by calling System.exit()
+	</ul>
+ */
+
+class DefaultShell implements Shell.Interface
+{
+	private PrintWriter writer=null;
+	private PrintWriter stdout=new PrintWriter(System.out,true); // with autoflush
+	private PrintWriter stderr=new PrintWriter(System.err); // without autoflush
+
+	//	DefaultShell() { trace("creating DefaultShell"); }
+
+	// Different types of message
+	public void print(String string) { stdout.println(string); }
+	public void status(String string) { stdout.println(string); }
+	public void trace(String string) {	stderr.println(string); }
+
+	public PrintWriter getPrintWriter()
+	{
+		if (writer==null)
+			writer = new PrintWriter( new OutputStreamWriter(System.out));
+		return writer;
+	};
+
+	public Shell.Dialog getDialog(String title) { return null; }
+	public Shell.Window getWindow(String title) { return null; }
+	public Container	createButtonsFor(Agent agent) { return null; }
+	public Viewer		createViewerPanel(Viewer vwr) { return null; }
+	public Component	createLabel(String nm) { return null; }
+	public NumberViewer createNumberViewer( String l, int f, NumberSink s) { return null; }
+
+	// registry
+	public void registerAgent(Agent a) {}
+	public void deregisterAgent(Agent a) {}
+	public void registerViewable(Viewable v) {}
+	public void deregisterViewable(Viewable v) {}
+	public void exposeCommands(Agent agent) {}
+	public void exit() { System.exit(0); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Variable.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,66 @@
+/*
+ *	Variable.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core;
+import	samer.core.Environment.Autocoder;
+import	java.io.*;
+
+/**
+	A Variable is a Viewable with an associated mutable data 
+	model (that implements the Autocoder interface). The data
+	model handles conversion of data to and from a small number of
+	recognised interchange formats (String, character stream).
+	This means that the data can be stored in a Binding.
+
+	The init() method handles registration of the Viewable
+	and initialisation of the data value from a Shell property.
+
+ */
+
+public class Variable extends Viewable // implement Environment.Autocoder
+{
+	/** Means do not automatically load value from current
+		environment on construction. */
+	public final static int	NOINIT	= 1;
+
+	/** Means register this Viewable automatically on construction. */
+	public final static int	REGISTER	= 2;
+
+	  /** Not currently used. */
+	public final static int	NODEFAULT= 8;
+
+	public Variable(Node node) { super(node); }
+	public Variable(String nm) { this(new Node(nm)); }
+	public Variable(String nm, Autocoder m, int flags) { this(nm); init(m,flags); }
+
+	/** Store this variable's data in the given environment */
+	public void save(Environment env) { env.store(node.fullName(), model); }
+
+	/** Restore this variable's data from the given environment */
+	public void load(Environment env) throws Exception {
+		env.datum(node.fullName()).get(model);
+		changed();
+	}
+
+	public String toString() { return super.toString()+"="+model.string(); }
+	
+	public void init(Autocoder m, int flags) { model=m; init(flags); }
+	public void init(int flags)
+	{
+		if ((flags&NOINIT)==0)   try { load(Shell.env()); } catch (Exception ex) {} // ??
+		if ((flags&REGISTER)!=0) Shell.registerViewable(this);
+		// what if no value found at this point?
+	}
+
+	public  Autocoder	getModel()	{ return model; }
+	private Autocoder	model;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Viewable.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,118 @@
+/*
+ *	Viewable.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core;
+import	java.util.*;
+
+
+/**
+		<p>
+		A Viewable is a named Observable object, for which
+		can be created a Viewer. A Viewer is meant to allow user
+		interaction with the object. The name is managed
+		by a Node object, so they can form a heirarchy.
+		A Viewable can also have an associated Agent, so that
+		Viewers can automatically expose commands
+		for the Agent.
+  */
+
+
+public class Viewable extends Observable
+{
+	/** sent to Obervable.update() when Viewable is
+	  * being disposed of.
+	  */
+	public final static Object DISPOSING = new Object();
+
+	public final Node getNode() { return node; }
+	public final void setNode(Node n) { node=n; }
+	public Agent getAgent() { return agent; }
+	public void setAgent(Agent a) { agent=a; }
+	public void addAgent(Agent a) { setAgent(new CompoundAgent(agent,a)); }
+
+	public String getLabel() {
+		String str = Shell.getString(node.fullNameFor("label"),null);
+		return str==null ? node.fullName().substring(1)	: str;
+	}
+
+	/**	<p>Should leave the Viewable in such a state that the
+	  *	garbage collector can get it as soon as any direct
+	  *	references go out of scope. In particular, any attached
+	  *	Viewers or Observers should drop their references to
+	  *	this Viewable, and if necessary, dispose of themselves.
+	  *	<p>
+	  *	The default implementation deregisters the Viewable,
+	  *	notifies Obervers and detaches the node.
+	  */
+
+	public void dispose()
+	{
+		Shell.deregisterViewable(this);
+		changed(DISPOSING);
+	}
+
+	/** This should return a suitable Viewer for this object.
+		Default implementation asks the <code>samer.core.Registry</code>
+		to create one. */
+	public Viewer  getViewer() { return Registry.createViewer(this); }
+
+	protected Viewable(String nm) { node = new Node(nm); }
+	protected Viewable(Node nd) { node = nd; }
+	protected Viewable() {}
+
+	protected Node		node;
+	protected Agent		agent=null;
+	// protected Vector	agents=new Vector();
+
+	public String toString() {
+		return Node.lastPart(getClass().getName())+":"+getLabel();
+	}
+	
+	public void finalize() { Shell.trace("Viewable finalizing: "+toString()); }
+
+	/* ------- override implementation of Observable here -----------*/
+	
+	private static class Vector extends java.util.Vector {
+		public Object[] getArray() { return elementData; }
+	}
+
+	private Vector observers=new Vector();
+
+	public synchronized void addObserver(Observer o) {
+		if (!observers.contains(o)) observers.addElement(o);
+   }
+
+	public synchronized void deleteObserver(Observer o) {
+		observers.removeElement(o);
+	}
+
+	public synchronized void deleteObservers() {
+		observers.removeAllElements();
+	}
+
+	public  void notifyObservers(Object arg)
+	{
+		Object [] arr=observers.getArray();
+
+		for (int i=observers.size()-1; i>=0; i--) {
+			((Observer)arr[i]).update(this, arg);
+		}
+	}
+
+	/** This will notify all observers that this object may have changed
+		The second argument to Observer.update() will be null */
+	public final void changed() { notifyObservers(null); }
+
+	/** This will notify all observers that this object may have changed.
+		The second argument to Observer.update() will be the given object */
+	public final void changed(Object o)	{ notifyObservers(o); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/Viewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,28 @@
+/*
+ *	Viewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core;
+import	java.util.*;
+import   java.awt.*;
+
+/**
+	A Viewer is essentially an AWT component with an
+	associated menu, intended to be (but not necessarily)
+	associated with a Viewable 
+ */
+
+public interface Viewer
+{
+	Component	getComponent();
+	void			exposeCommands(Agent agent);
+	void			detach();
+	void			attach();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/X.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,317 @@
+/*
+ *	X.java	
+ *
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core;
+import  java.io.StringWriter;
+import  java.util.StringTokenizer;
+import  java.awt.Font;
+import  java.awt.Rectangle;
+import  java.awt.Color;
+import  java.awt.SystemColor;
+
+import  samer.core.Environment.Datum;
+import  samer.core.Environment.Codec;
+import  samer.core.Environment.Autocoder;
+
+/**
+	Static methods for converting objects and extracting correctly typed
+	values from Environments. Short name
+	because of expected frequent use! Also, contains
+	several Codec classes.
+	@see samer.core.Environment
+	@see samer.core.Environment.Datum
+	@see samer.core.Environment.Autocoder
+ */
+
+public class X
+{
+	/** Tries to extract an Object from the given Datum, throws Exception in failure */
+	public static Object object(Datum b) throws Exception {
+		Object ret=b.get(ObjectCodec,null);
+		if (ret==null) throw new Exception("no data");
+		return ret;
+	}
+
+	/** Tries to extract a String given Datum */
+	public static String string(Datum b) throws Exception {
+		String ret=(String)b.get(StringCodec,null);
+		if (ret==null) throw new Exception("datum has no value");
+		return ret;
+	}
+
+	/** Tries to extract a Font given Datum. If this fails, tries
+		to decode def using FontCodec. def can be a Font or a String. */
+	public static Font font(Datum b, Object def) {
+		return (Font)b.get(FontCodec,def);
+	}
+
+	/** Tries to extract a Rectangle from given Datum. If this fails, tries
+		to decode def as a rectangle. */
+	public static Rectangle rect(Datum b, Rectangle def) {
+		return (Rectangle)b.get(RectangleCodec,def);
+	}
+
+	/** Get String from Datum, returning def if this fails */
+	public static String string(Datum b,String def) {
+		return (String)b.get(StringCodec,def);
+	}
+
+	/** Get Color from Datum, decoding def if this fails. def can
+		be a Color or a String. See ColorCodec. */
+	public static Color	color(Datum b, Object def) {
+		return (Color)b.get(ColorCodec,def);
+	}
+
+	/** Extract int from Datum */
+	public static int _int(Datum b,int def) {
+		return ((Integer)b.get(IntegerCodec,new Integer(def))).intValue();
+	}
+	/** Extract double from Datum */
+	public static double _double(Datum b,double def) {
+		return ((Double)b.get(DoubleCodec,new Double(def))).doubleValue();
+	}
+	/** Extract boolean from Datum */
+	public static boolean _bool(Datum b,boolean def) {
+		return ((Boolean)b.get(BooleanCodec,new Boolean(def))).booleanValue();
+	}
+
+	/** store given object to current environment */
+	public static void store(String name, Object value) {
+		Shell.env().store(name,value,codec(value));
+	}
+
+	/** Extracts an integer array from a string. Valid strings are, eg
+		"(1,2,3)", "(4 5 6)", "7 8 9", "10, 11, 12" */
+	public static int[] parseIntArray(String s, int n)
+	{
+		StringTokenizer token = new StringTokenizer(s,"(), ");
+		int[] a=new int[n];
+
+		for (int i=0; i<n; i++) {
+			a[i]=Integer.parseInt(token.nextToken());
+		}
+		return a;
+	}
+
+	/** @see samer.core.X.parseIntArray */
+	public static double[] doubleArray(String s, int n)
+	{
+		StringTokenizer token = new StringTokenizer(s,"(), ");
+		double[] a=new double[n];
+
+		for (int i=0; i<n; i++) {
+			a[i]=parseDouble(token.nextToken());
+		}
+		return a;
+	}
+
+	/** Sets each integer in the int array to the numeric value of the corresponding
+		Objects in the Object array (they have to be subclasses of Numbe).
+	 */
+	public static void setIntArray(int[] a, Object[] b) {
+		for (int i=0; i<a.length; i++)
+			a[i]=((Number)b[i]).intValue();
+	}
+
+	/** Base class for objects that can convert some type to and from String or
+		Object. @see samer.core.Environment.Codec */
+	public static class BaseCodec implements Codec
+	{
+		public Class targetClass() { return Object.class; }
+
+		/** convert to string using object's toString() method (a reasonable default) */
+		public String string(Object o) { return o.toString(); }
+
+		/** Convert to object by returning original object. This might be OK for
+		 *  immutable objects, but should be overriden for mutable ones, perhaps
+		 *	returning a clone of the original or an object of a different class altogether.
+		 */
+		public Object object(Object o) { return o; }
+
+		/** Decode given object to by return it the given object itself. */
+		public Object decode(Object o) {	return o; }
+	};
+
+	public static Codec ObjectCodec = new BaseCodec();
+
+	/** Can decode numbers in Integer, Number, or String form */
+	public static Codec IntegerCodec = new BaseCodec()
+	{
+		public Class targetClass() { return Integer.class; }
+
+		/** If given object is any subclass of java.lang.Number, then its
+			numerical value is returned as an Integer. If it is a string,
+			the string is parsed to extract an integer value. Any other
+			class will probably cause this function to barf.
+		*/
+		
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof Integer) return o;
+			if (o instanceof String)  return Integer.decode(o.toString());
+			return new Integer(((Number)o).intValue());
+		}
+	};
+
+	private static DoubleFormat fmt=new DoubleFormat(3);
+
+	/** Convert double to string using the (private) current DoubleFormat object */
+	public static String string(double v) { return fmt._format(v); }
+
+	/** Convert string to double */
+	public static double parseDouble(String s) {
+		return Double.valueOf(s).doubleValue();
+	}
+
+	/** Can decode numbers in Double, Number, or String form */
+	public static Codec DoubleCodec = new BaseCodec()
+	{
+		public Class targetClass() { return Double.class; }
+
+		public String string(Object o) { return fmt._format(((Number)o).doubleValue()); }
+
+		/** Can decode String or any subclass of Number */
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof Double) return o;
+			if (o instanceof String) return Double.valueOf(o.toString());
+			return new Double(((Number)o).doubleValue());
+		}
+
+	};
+
+	/** Can decode Boolean or String ("true" or "false") form */
+	public static Codec BooleanCodec = new BaseCodec()
+	{
+		public Class  targetClass() { return Boolean.class; }
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof Boolean) return o;
+			return Boolean.valueOf(o.toString());
+		}
+	};
+
+	public static Codec StringCodec = new BaseCodec()
+	{
+		public Class  targetClass() { return String.class; }
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof String) return o;
+			else return o.toString();
+		}
+	};
+
+
+	/** Can decode Color or String form
+		String can be "#rrggbb" where rrggbb are hex,
+		or "(r,g,b)" or "(r g b)" where r, g, b are integers,
+		or "$bg", which evaluates to SystemColor.control, the
+		default background color for components,
+		or "$fg", which evaluates to SystemColor.controlText,
+		the default foreground color.
+	*/
+
+	public static Codec ColorCodec = new Codec()
+	{
+		public Class  targetClass() { return Color.class; }
+		public Object object(Object o) { return o; }
+		public String string(Object o) {
+			StringBuffer buf=new StringBuffer("#");
+			buf.append(Integer.toHexString(((Color)o).getRGB() & 0xffffff));
+			return buf.toString();
+		}
+		public Object decode(Object o) {	
+//			if (o==null) return null;
+			if (o instanceof Color) return o;
+
+			String s=o.toString();
+			if (s.startsWith("(")) {
+				int[] a=parseIntArray(s,3);
+				return new Color(a[0],a[1],a[2]);
+			}
+			if (s.equals("$bg"))	return SystemColor.control;
+			if (s.equals("$fg"))	return SystemColor.controlText;
+			return Color.decode(s);
+		}
+	};
+
+	/** Can decode Font or String, using Font.decode(),
+		eg "Helvetica-PLAIN-12" */
+	public static Codec FontCodec = new Codec()
+	{
+		public Class  targetClass() { return Font.class; }
+		public Object object(Object o) { return o; }
+		public String string(Object o) { return o.toString(); }
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof Font)   return o;
+			return Font.decode(o.toString());
+		}
+	};
+
+	public static Codec RectangleCodec = new Codec()
+	{
+		public Class  targetClass() { return Font.class; }
+		public Object object(Object o) { return o; }
+		public String string(Object o) {
+			Rectangle      r=(Rectangle)o;
+			StringBuffer	buf=new StringBuffer();
+
+			buf.append('(');
+			buf.append(String.valueOf(r.x));			buf.append(',');
+			buf.append(String.valueOf(r.y));			buf.append(',');
+			buf.append(String.valueOf(r.width));	buf.append(',');
+			buf.append(String.valueOf(r.height));
+			buf.append(')');
+			return buf.toString();
+		}
+
+		public Object decode(Object o) {
+//			if (o==null) return null;
+			if (o instanceof Rectangle) return o;
+
+			int[] a=parseIntArray(o.toString(),4);
+			return new Rectangle(a[0],a[1],a[2],a[3]);
+		}
+	};
+
+	public static Codec codec(Object o) { return codec(o.getClass()); }
+	public static Codec codec(Class c)
+	{
+		for (int i=classes.length-1; i>0; i--) {
+			if (classes[i].isAssignableFrom(c)) return codecs[i];
+		}
+		return codecs[0];
+	}
+
+	private static Class[] classes = {
+		Object.class,
+		Font.class,
+		Rectangle.class,
+		Color.class,
+		String.class,
+		Boolean.class,
+		Integer.class,
+		Double.class
+	};
+
+	private static Codec[] codecs = {
+		ObjectCodec,
+		FontCodec,
+		RectangleCodec,
+		ColorCodec,
+		StringCodec,
+		BooleanCodec,
+		IntegerCodec,
+		DoubleCodec
+	};
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/AWTShell.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,188 @@
+/*
+ *	AWTShell.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.shells;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.util.shell.*;
+import samer.core.util.heavy.*;
+import samer.core.util.heavy.Console;
+import samer.core.util.heavy.Frame;
+import samer.core.util.heavy.Dialog;
+import samer.core.NumberViewer;
+import samer.core.viewers.*;
+import samer.core.types.*;
+
+public class AWTShell extends AppShellBase
+{
+	public AWTShell() { this(getDefaultPropertiesFile()); }
+	public AWTShell(String propsFile) 
+	{
+		super(propsFile);
+		currentFrame = new java.awt.Frame("dummy"); // temporary dialog owner
+
+		Shell.setShell(this);
+
+		// going to cache font and menu font
+		Font font=X.font(Shell.datum("font"),null);
+		Font menufont=X.font(Shell.datum("menu.font"),null);
+		if (font!=null) Shell.put("font", font);
+		if (menufont!=null) Shell.put("menu.font", menufont);
+
+		con   = new Console(); 
+		confr = new Frame("console.frame");
+		confr.setLayout( new BorderLayout(3,3));
+		confr.add(con);
+		confr.add( new CommandField(20), "South"); 
+		confr.addWindowListener( Shell.exitListener());
+		confr.expose();
+		// currentFrame=confr;
+
+		Shell.registerAgent(this);
+		Shell.registerAgent(con);
+
+		put(VDouble.class,DoubleViewer.class);
+		put(VInteger.class,IntegerViewer.class);
+		put(VBoolean.class,BooleanViewer.class);
+		put(VString.class,StringViewer.class);
+		put(VParameter.class,ParameterViewer.class);
+		put(VFile.class,FileViewer.class);
+		put(VColor.class,ColorButton.class);
+		put(Variable.class,StringViewer.class);
+		put(Viewable.class,DefaultViewer.class);
+
+		try { execute("run",Shell.env()); }
+		catch (Exception ex) { Shell.trace(ex.toString()); }
+	}
+
+	class VContainer extends WindowAdapter implements ViewableManager.ViewerContainer
+	{
+		Frame	frame;
+
+		VContainer()
+		{
+			frame = new Frame("exposed");
+			frame.setLayout( new StackLayout());
+			frame.expose();
+			frame.addWindowListener(this);
+		}
+
+		public void add(java.util.Iterator components)
+		{
+			Container c=frame.container();
+			while (components.hasNext()) {
+				c.add((Component)(components.next()));
+			}
+			c.validate();
+			frame.pack();
+		}
+
+		public void removeAll() {
+			frame.setVisible(false);
+			frame.container().removeAll();
+		}
+
+		public void windowClosing(WindowEvent e) {
+			vm.releaseViewerContainer();
+			frame.dispose();
+		}
+	}
+
+	public ViewableManager.ViewerContainer getViewerContainer() {
+		return new VContainer();
+	}
+
+	public Shell.Dialog getDialog(String title) { return new Dialog(currentFrame,title,true); }
+	public Shell.Window getWindow(String title) { return new BevelWindow(title); }
+	public Viewer createViewerPanel(Viewer vwr) { return new VPanel(vwr); }
+	public Container createButtonsFor(Agent agent)
+	{
+		ButtonBar bbar=new ButtonBar();
+		bbar.setTarget(agent);
+		agent.getCommands(bbar);
+		return bbar.container();
+	}
+
+	public NumberViewer createNumberViewer(String label, int flags, NumberSink s) {
+		return new TextualNumberViewer(label,flags,s);
+	}
+
+	public void exposeCommands( Agent agent)
+	{
+		if (buttonBar==null) {
+			buttonBar = new ButtonBar();
+			buttonBar.setBroadcaster(am.getBroadcaster());
+			confr.add( buttonBar.container(), "North");
+		}
+
+		buttonBar.setTarget(agent);
+		agent.getCommands(buttonBar);
+		confr.validate();
+	}
+
+	public Component createLabel(String txt) { 
+		Label l=new Label(txt);
+		l.addMouseListener(MouseRetarget.listener); 
+		return l;
+	}
+
+	// .......... Message printing .............. 
+
+	public PrintWriter getPrintWriter() { 
+		return new PrintWriter(con.getWriter(),true);
+	}
+
+	public void print(String msg) { con.write(msg); con.write("\n"); }
+	public void status(String msg) { con.write(msg); con.write("\n"); }
+
+
+	// ............... Private bits .............
+
+	private java.awt.Frame	currentFrame=null;
+
+	private Frame		confr=null;
+	private Console	con=null;
+	private ButtonBar	buttonBar=null;
+
+	public static void main( String args[]) { new AWTShell(); }
+
+}
+
+
+
+class BevelWindow extends Frame implements Shell.Window
+{
+	JPanel panel; 
+
+	public BevelWindow(String name) 
+	{	
+		super(name); 
+		Shell.push(getNode());
+
+		panel = new JPanel( Border.create(
+			Border.NONE, Shell.getInt("borderWidth",2)
+		));
+
+		boolean bw = Shell.getBoolean("bevelChildren",false);
+		if (bw) panel.setChildBorder(Border.create(Border.IN,0));
+
+		Shell.pop();
+		add(panel); 
+	}
+
+	public Container container() { return panel; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,4 @@
+/AWTShell.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/DesktopShell.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+/SwingShell.java/1.1.1.1/Fri Dec 10 03:29:25 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/shells
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/DesktopShell.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,196 @@
+/*
+ *	AppShell.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.shells;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+
+import samer.core.*;
+import samer.core.util.shell.*;
+import samer.core.util.*;
+import samer.core.util.swing.*;
+import samer.core.util.swing.Frame;
+import samer.core.util.swing.Console;
+import samer.core.util.swing.Dialog;
+import samer.core.NumberViewer;
+import samer.core.viewers.swing.*;
+import samer.core.types.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+public class DesktopShell extends AppShellBase
+{
+	public DesktopShell() { this(getDefaultPropertiesFile());	}
+	public DesktopShell(String props) {
+		super(props);
+		Shell.setShell(this);
+
+		desktop = new JDesktopPane();
+		desktop.setDragMode(JDesktopPane.LIVE_DRAG_MODE);
+		mainFrame = new Frame("Desktop");
+		mainFrame.container().setLayout(new BorderLayout());
+		mainFrame.container().add(desktop);
+		mainFrame.expose();
+		mainFrame.addWindowListener( new WindowAdapter() {
+			public void windowClosing(WindowEvent e) { Shell.exit(); }
+		} );
+
+		InternalFrame.setDesktop(desktop);
+
+//		con   = new Console();
+//		confr = new InternalFrame("console.frame");
+//		JScrollPane scroller = new JScrollPane(con);
+
+//		JComponent jc=new javax.swing.JPanel();
+//		jc.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
+//		jc.setLayout( new BorderLayout(4,5));
+//		jc.add(scroller);
+//		jc.add(new CommandField(20), "South");
+		//confr.container().add(jc);
+//		confr.setContentPane(jc);
+//		confr.pack();
+//		confr.expose();
+
+		Shell.registerAgent(this);
+//		Shell.registerAgent(con);
+
+		// javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+
+		put(VDouble.class,DoubleViewer.class);
+		put(VInteger.class,IntegerViewer.class);
+		put(VBoolean.class,BooleanViewer.class);
+		put(VString.class,StringViewer.class);
+		put(VParameter.class,ParameterViewer.class);
+		put(VFile.class,FileViewer.class);
+		put(VColor.class,ColorButton.class);
+		put(Variable.class,StringViewer.class);
+		put(Viewable.class,DefaultViewer.class);
+
+		try { execute("run",Shell.env()); }
+		catch (Exception ex) { Shell.trace(ex.toString()); }
+	}
+
+	class VContainer extends InternalFrameAdapter implements ViewableManager.ViewerContainer
+	{
+		InternalFrame	frame;
+		Box				box;
+		Component		glue;
+
+		VContainer()
+		{
+			frame = new InternalFrame("exposed");
+			box   = Box.createVerticalBox();
+			glue  = Box.createVerticalGlue();
+
+			JScrollPane scr=new JScrollPane(box);
+			scr.setBorder(null);
+
+			box.add(glue);
+			frame.container().add(scr);
+			frame.pack();
+			frame.expose();
+			frame.setClosable(true);
+			frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+			frame.addInternalFrameListener(this);
+		}
+
+		public void removeAll() { box.removeAll(); }
+		public void add(java.util.Iterator components)
+		{
+			box.remove(glue);
+			while (components.hasNext()) {
+				box.add((Component)(components.next()));
+			}
+			box.add(glue);
+			box.validate();
+			frame.pack();
+		}
+
+		public void internalFrameClosing(InternalFrameEvent e) {
+			Shell.print("internal frame closing");
+			vm.releaseViewerContainer();
+			frame.dispose();
+		}
+	}
+
+	public ViewableManager.ViewerContainer getViewerContainer() {
+		return new VContainer();
+	}
+
+	// ............. Factory methods ............
+
+	public Shell.Window getWindow(String title) { return new InternalFrame(title); }
+	public Shell.Dialog getDialog(String title) { return new Dialog(mainFrame,title,true); }
+
+	public Component createLabel(String txt) { return new JLabel(txt); }
+	public Viewer    createViewerPanel(Viewer vwr) { return new VPanel(vwr); }
+	public Container createButtonsFor(Agent agent)
+	{
+		ButtonBar bbar=new ButtonBar();
+		bbar.setTarget(agent);
+		agent.getCommands( bbar);
+		return bbar;
+	}
+
+	public NumberViewer createNumberViewer(String label, int flags, NumberSink s) {
+		return new TextualNumberViewer(label);
+	}
+
+	public void exposeCommands( Agent agent)
+	{
+		if (buttonBar==null) {
+			buttonBar = new ButtonBar();
+			buttonBar.setBroadcaster(am.getBroadcaster());
+			mainFrame.container().add( buttonBar, "North");
+		}
+
+		buttonBar.setTarget(agent);
+		agent.getCommands(buttonBar);
+		mainFrame.validate();
+	}
+
+	// .......... Message printing ..............
+
+	public void print(String msg) { System.out.println(msg); }
+	public void status(String msg) { System.out.println(msg); }
+
+	private PrintWriter writer=null;
+	public PrintWriter getPrintWriter()
+	{
+		if (writer==null)
+			writer = new PrintWriter( new OutputStreamWriter(System.out));
+		return writer;
+	};
+/*
+	public PrintWriter getPrintWriter() {
+		return new PrintWriter(con.getWriter(),true);
+	}
+
+	public void print(String msg) { con.write(msg); con.write("\n"); }
+	public void status(String msg) { con.write(msg); con.write("\n"); }
+ */
+
+	// ............... Private bits .............
+
+	private Frame			mainFrame;
+	private JDesktopPane	desktop;
+	private InternalFrame	confr=null;
+	private Console			con=null;
+	private ButtonBar		buttonBar=null;
+	private Component		glue;
+
+	public static void main( String args[]) { new DesktopShell(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/shells/SwingShell.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,181 @@
+/*
+ *	AppShell.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.shells;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.util.shell.*;
+import samer.core.util.swing.*;
+import samer.core.util.swing.Frame;
+import samer.core.util.swing.Console;
+import samer.core.util.swing.Dialog;
+import samer.core.NumberViewer;
+import samer.core.viewers.swing.*;
+import samer.core.types.*;
+
+
+public class SwingShell extends AppShellBase
+{
+	public SwingShell() { this(getDefaultPropertiesFile());	}
+	public SwingShell(String props)
+	{
+		super(props);
+		Shell.trace("SwingShell constructor");
+		Shell.setShell(this);
+		Shell.registerAgent(this);
+
+//		Shell.trace("creating console");
+//		con   = new Console();
+//		JScrollPane scroller = new JScrollPane(con);
+//		JComponent jc = (JComponent)(confr.getContentPane());
+//		jc.setBorder(BorderFactory.createEmptyBorder(1,1,1,1));
+//		Shell.registerAgent(con);
+
+//		confr.container().setLayout( new BorderLayout(4,5));
+//		confr.container().add(scroller);
+//		confr.container().add( new CommandField(20), "South");
+//		confr.expose();
+
+		javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled(false);
+
+
+		Shell.trace("registering viewer classes");
+		mput("VDouble","DoubleViewer");
+		mput("VInteger","IntegerViewer");
+		mput("VBoolean","BooleanViewer");
+		mput("VString","StringViewer");
+		mput("VParameter","ParameterViewer");
+		mput("VFile","FileViewer");
+		mput("VColor","ColorButton");
+		put(Variable.class,StringViewer.class);
+		put(Viewable.class,DefaultViewer.class);
+
+		try { execute("run",Shell.env()); }
+		catch (Exception ex) { Shell.trace(ex.toString()); }
+	}
+
+	private static void mput(String cl, String vwr) {
+		samer.core.Registry.put("samer.core.types."+cl, "samer.core.viewers.swing."+vwr);
+	}
+
+	class VContainer extends VContainerBase implements ViewableManager.ViewerContainer
+	{
+		VContainer() { super("exposed"); box.add(buttonBar); }
+
+		public void add(java.util.Iterator components)
+		{
+			adding=true;
+			box.remove(glue); box.remove(buttonBar);
+			while (components.hasNext()) {
+				box.add((Component)(components.next()));
+			}
+			box.add(glue); box.add(buttonBar);
+			box.validate();
+			if (noScrollBars() || frame.getBounds().isEmpty()) frame.pack();
+			else frame.validate();
+			adding=false;
+		}
+
+		public void windowClosing(WindowEvent e) {
+			vm.releaseViewerContainer();
+			super.windowClosing(e);
+		}
+	}
+
+	public ViewableManager.ViewerContainer getViewerContainer() {
+		if (buttonBar==null) {
+			buttonBar = new ButtonBar();
+			buttonBar.setBroadcaster(am.getBroadcaster());
+			buttonBar.setTarget(this);
+			buttonBar.add("set").add("get").add("load").add("save").add("exit");
+		}
+		return new VContainer();
+	}
+
+
+	// ............. Factory methods ............
+
+	public Shell.Window getWindow(String title) { return new Frame(title); }
+	public Shell.Dialog getDialog(String title) {
+		// if (currentFrame==null) currentFrame=new JFrame("dialog owner");
+		// return new Dialog(currentFrame,title,true);
+		return new Dialog(title,true);
+	}
+
+	public Component createLabel(String txt) {
+		JLabel l=new JLabel(Node.lastPart(txt)) {
+			public void setName(String txt) {
+				super.setName(txt);
+				setText(Node.lastPart(txt));
+				setToolTipText(txt);
+			}
+		};
+		l.setToolTipText(txt);
+		MouseRetarget.mouseInvisibilityFor(l);
+		return l;
+	}
+	public Viewer    createViewerPanel(Viewer vwr) { return new VPanel(vwr); }
+
+	public Container createButtonsFor(Agent agent)
+	{
+		ButtonBar bbar=new ButtonBar();
+		bbar.setTarget(agent);
+		agent.getCommands( bbar);
+		return bbar;
+	}
+
+	public NumberViewer createNumberViewer(String label, int flags, NumberSink s) {
+		return new TextualNumberViewer(label);
+	}
+
+	public void exposeCommands( Agent agent) {
+		buttonBar.setTarget(agent);
+		agent.getCommands(buttonBar);
+	}
+
+	// .......... Message printing ..............
+	public void print(String msg) { System.out.println(msg); }
+	public void status(String msg) { System.out.println(msg); }
+
+	private PrintWriter writer=null;
+	public PrintWriter getPrintWriter()
+	{
+		if (writer==null)
+			writer = new PrintWriter( new OutputStreamWriter(System.out));
+		return writer;
+	};
+
+//	public PrintWriter getPrintWriter() {
+//		return new PrintWriter(con.getWriter(),true);
+//	}
+
+//	public void print(String msg) { con.write(msg); con.write("\n"); }
+//	public void status(String msg) { con.write(msg); con.write("\n"); }
+
+
+	// ............... Private bits .............
+
+//	private JFrame	currentFrame=null;
+	private JFrame	confr=null;
+	private Console	con=null;
+	private ButtonBar	buttonBar=null;
+	private Component	glue;
+
+	public static void main( String args[]) { new SwingShell(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,10 @@
+/DoubleModel.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VBoolean.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VColor.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VDouble.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VFile.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VInteger.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VParameter.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VRectangle.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VString.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/types
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/DoubleModel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ *	DoubleModel.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+
+public interface DoubleModel
+{
+	public void set(double t);
+	public double get();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VBoolean.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+/*
+ *	VBoolean.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+public class VBoolean extends Variable implements Environment.Autocoder
+{
+	public boolean value;
+
+	public VBoolean( String nm, boolean vl) { this(nm,vl,REGISTER); }
+	public VBoolean( String nm, boolean vl, int flags) { 
+		super(nm); value=vl; init(this,flags);
+	}
+
+	public String string()			{ return String.valueOf(value); }
+	public Object object()			{ return new Boolean(value); }
+	public void   decode(Object o)	{ value=((Boolean)X.BooleanCodec.decode(o)).booleanValue(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VColor.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+/*
+ *	VColor.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.awt.*;
+import  java.io.*;
+
+public class VColor extends Variable implements Environment.Autocoder
+{
+	public int	r, g, b;
+
+	public VColor( String nm) { this(nm,Variable.REGISTER); }
+	public VColor( String nm, Color c) { this(nm,c,Variable.REGISTER); }
+
+	public VColor( String nm, int flags) { 
+		super(nm); init(this,flags|Variable.NODEFAULT); 
+	}
+
+	public VColor( String nm, Color c, int flags) { 
+		super(nm); setColor(c); init(this,flags); 
+	}
+
+	public Color getColor() { return new Color(r,g,b); }
+	public Color getColorWithAlpha(int a) { return new Color(r,g,b,a); }
+	public Color getColorWithAlpha(double a) { return new Color(r,g,b,(int)(255*a)); }
+	public void  setColor(Color c) { 
+		r=c.getRed();
+		g=c.getGreen();
+		b=c.getBlue();
+	}
+
+	public String string() { return X.ColorCodec.string(getColor()); }
+	public Object object() { return X.ColorCodec.object(getColor()); }
+	public void   decode(Object o) { setColor((Color)X.ColorCodec.decode(o)); }
+	
+	public static Color withAlpha(Color c, int alpha) {
+		return new Color(c.getRed(),c.getGreen(),c.getBlue(),alpha);
+	}
+	public static Color withAlpha(Color c, double alpha) {
+		return new Color(c.getRed(),c.getGreen(),c.getBlue(),alpha>=1?255:(int)(256*alpha));
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VDouble.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *	VDouble.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+
+public class VDouble extends Variable implements Environment.Autocoder, DoubleModel
+{
+	public double	value;
+	public int		flags;
+
+	// public VDouble( double n) { this("", n, NOINIT); }
+
+	public VDouble( String nm) { this(nm,0.0,SIGNAL); }
+	public VDouble( String nm, int flags) { this(nm,0.0,flags|SIGNAL); }
+	public VDouble( String nm, double n) { this(nm,n, REGISTER); }
+	public VDouble( String nm, double n, int flags)	{
+		super(nm); value = n; this.flags=flags; init(this,flags); 
+	}
+
+	public String string() { return X.string(value); }
+	public Object object() { return new Double(value); }
+	public void   decode(Object o) { value=((Double)X.DoubleCodec.decode(o)).doubleValue(); }
+
+	public void set(double x) { value=x; changed(); }
+	public double get() { return value; }
+
+	/* these are flags are hints for viewer creation */
+	public static int METER=16;
+	public static int NOSLIDER=32;
+	public static int NOENTRY=64;
+	public static int SIGNAL=REGISTER | NOSLIDER | NOENTRY;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VFile.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+public class VFile extends Variable implements Environment.Autocoder
+{
+	private File value;
+
+	public VFile( String nm) { this(nm,"",REGISTER); }
+	public VFile( String nm, String val, int flags) { 
+		super(nm); value = new File(val); init(this,flags);
+	}
+
+	public File   getFile() { return value; }
+	public void	  setFile(File f) { value=f; changed(); }
+
+	public String string() { 
+		// return relative path if possible
+		String current=System.getProperty("user.dir");
+		String fullpath=value.getPath();
+		if (fullpath.equals(current))
+			return ".";
+		else if (fullpath.startsWith(current)) 
+			return fullpath.substring(current.length()+1);
+		else 
+			return value.getPath(); 
+	}
+	public Object object() { return value; }
+	public void   decode(String s) { value=new File(s); }
+	public void   decode(Object o) {
+		if (o instanceof File) value=(File)o;
+		else value=new File(o.toString());
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VInteger.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,43 @@
+/*
+ *	VInteger.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+
+public class VInteger extends Variable implements Environment.Autocoder
+{
+	public	int	value;
+	private	int	min, max;
+	public static Object NEW_RANGE=new Object();
+
+	public VInteger( String nm, int n) { this(nm,n,REGISTER); }
+	public VInteger( String nm, int n, int flags) 
+	{ 
+		super(nm);
+
+		value = n; 
+		min = 0;	max = 2*value;
+		init(this,flags); 
+		max = 2*value;
+	}
+
+	public void	setRange( int mn, int mx) { min=mn; max=mx; changed(NEW_RANGE); }
+	public int  getMin() { return min; }
+	public int  getMax() { return max; }
+	public void set(int x) { value=x; changed(); }
+
+	public String string() { return String.valueOf(value); }
+	public Object object() { return new Integer(value); }
+	public void   decode(Object o) { value=((Integer)X.IntegerCodec.decode(o)).intValue(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VParameter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,36 @@
+/*
+ *	VParameter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+
+public class VParameter extends Variable implements Environment.Autocoder, DoubleModel
+{
+	public DoubleModel iface;
+
+	public VParameter( DoubleModel iface) { this("",iface,NOINIT); }
+	public VParameter( String nm, DoubleModel iface) { this (nm,iface,REGISTER); }
+	public VParameter( String nm, DoubleModel iface, int flags)	{
+		super(nm);
+		this.iface=iface;
+		init(this,flags);
+	}
+
+	public String string() { return X.string(iface.get()); }
+	public Object object() { return new Double(iface.get()); }
+	public void   decode(Object o) { iface.set(((Double)X.DoubleCodec.decode(o)).doubleValue()); }
+
+	public double get() { return iface.get(); }
+	public void set(double t) { iface.set(t); changed(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VRectangle.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *	VRectangle.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.awt.*;
+import  java.io.*;
+
+public class VRectangle extends Variable implements Environment.Autocoder
+{
+	public Rectangle rect;
+
+	public VRectangle( String nm) { this(nm,REGISTER); }
+	public VRectangle( String nm, int flags) { super(nm); init(this,flags|NODEFAULT); }
+
+	public String string() { return X.RectangleCodec.string(rect); }
+	public Object object() { return X.RectangleCodec.object(rect); }
+	public void   decode(Object o) { 
+		rect=(Rectangle)X.RectangleCodec.decode(o);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/types/VString.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *	VString.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.types;
+import  samer.core.*;
+import  java.io.*;
+
+public class VString extends Variable implements Environment.Autocoder
+{
+	public String value;
+
+	public VString( String nm) { this(nm,"",REGISTER); }
+	public VString( String nm, String val) { this(nm,val,REGISTER); }
+	public VString( String nm, String val, int flags) { 
+		super(nm); value = val; init(this,flags);
+	}
+
+	public String string() { return value; }
+	public Object object() { return value; }
+	public void	  decode(Object o) { value=(String)X.StringCodec.decode(o); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/AgentAdapter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,63 @@
+/*
+ *	AgentAdapter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+/**
+	This converts action events and item state
+	events (eg from buttons, menus, or check box
+	items) into Agent commands.
+  */
+
+public class AgentAdapter implements ActionListener, ItemListener
+{
+	private Agent		agent;
+
+	public AgentAdapter(Agent a) { agent=a; }
+
+	public Agent getAgent() { return agent; }
+	
+	public void actionPerformed(ActionEvent e) {
+		try {	agent.execute(e.getActionCommand(), new UserEnvironment(Shell.env())); }
+		catch (Exception ex) {
+			Shell.print("*** error in agent action: "+agent);
+			Shell.print("*** exception: "+ex);
+			ex.printStackTrace();
+		}
+	}
+
+	/**
+		This sends provides a boolean argument to the command
+		The value comes from the new state of the item.
+	  */
+
+	public void itemStateChanged(ItemEvent e)	
+	{
+		Object	obj=e.getItem();
+		String	cmd;
+
+		if (obj instanceof String) cmd = (String)obj;
+		else if (obj instanceof Component) cmd = ((Component)obj).getName();
+		else return;
+		if (cmd==null) return;
+
+		boolean	state = (e.getStateChange()==ItemEvent.SELECTED);
+		try { agent.execute(cmd,new UserEnvironment(Shell.env(),state)); }
+		catch (Exception ex) {
+			Shell.print("*** error in agent action: "+agent);
+			Shell.print("*** exception: "+ex);
+			ex.printStackTrace();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/BaseViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,131 @@
+/*
+ *	BaseViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import  samer.core.*;
+import  java.util.*;
+import  java.awt.*;
+
+/**
+	Basic Viewer that appears as panel with an optional
+	label. It is actually an envelope class for the real Viewer
+	provided by Shell.createViewerPanel(), but in addition, it:
+	- handles a reference to an Observable.
+	- handles attach() and detach() in response to 
+	  underlying panel's visibility.
+	- responds to DISPOSE message from Observable by attempting
+	  to destroy itself using Shell.releaseViewer()
+  */
+
+public class BaseViewer implements Observer, Viewer
+{
+	private		Container	panel;
+	private		Viewer		viewer;
+	protected	Observable	obs;
+	private		Component label;
+
+	/** Construct a BaseViewer for the given Viewable. If the Viewable
+		has an Agent (ie returns something from getAgent() ) then
+		the Agent's commands are exposed on the Viewer using
+		this.exposeCommmands()
+	*/
+	public BaseViewer(Viewable v) {
+		this((Observable)v);
+		Agent a=v.getAgent();
+		if (a!=null) exposeCommands(a);
+	}
+
+	/** Construct a BaseViewer for the given Observable. The only difference
+		between this constructor and the BaseViewer(Viewable) constructor
+		is that no agent is exposed.
+	*/
+	public BaseViewer(Observable o) {
+		obs=o;
+		viewer=Shell.createViewerPanel(this);
+		panel=(Container)viewer.getComponent();
+	}
+
+	/** Returns the Container to which Components can be added to
+		be exposed in this Viewer.
+	*/
+	public Container panel() { return panel; }
+
+	/** Attempts to display a label or name for this viewer.
+		<ul>
+			<li>If no label exists, then one is created via Shell.createLabel()
+			<li>If a label exists, it's text is changed to match the <code>txt</code>
+			<li>If <code>txt==null</code> then any label is removed
+		</ul>
+	*/
+	public void setText(String txt) {
+		if (txt==null) {
+			if (label!=null) panel.remove(label);
+			label=null;
+		} else if (label==null) {
+			panel.add(label=Shell.createLabel(txt));
+		} else {
+			label.setName(txt);
+		}
+	}
+
+	/** Equivalent to panel().setLayout(layout) - See java.awt.Container.setLayout()	*/
+	public void setLayout(LayoutManager l) { panel.setLayout(l); }
+
+	/** Equivalent to panel().add(component) - See java.awt.Container.add()	*/
+	public void add(Component c) { panel.add(c); }
+
+	/** Add a default viewer for the given Viewable
+		Equivalent to panel().add(vbl.getViewer().getComponent())
+		See java.awt.Container.add()
+	*/
+	public void add(Viewable vbl) { panel.add(vbl.getViewer().getComponent()); }
+
+	/**	Implementation of Viewer.getComponent(): returns the
+		AWT Component for this Viewer.	*/
+	public Component getComponent() { return panel; }
+
+	/** Delegated to viewer returned frp, Shell.createViewerPanel() -
+		Generally, this will add an Agent's commands to a right-click popup menu */
+	public void	exposeCommands(Agent agent) { viewer.exposeCommands(agent); }
+
+	/**  A call to this means that the Viewer should begin observing and
+		reflecting changes in its Viewable */
+	public void attach() { obs.addObserver(this); }
+
+	/** This ought to be the reverse of attach(). Not entirely clear who
+		should be dropping references to whom here. Mainly, the Viewer
+		should become disposable, so Viewer should arrange for any references
+		to it (esp from the Viewable) to be dropped. This implementation
+		deletes this Viewer (Observer) from the Viewable (Observable),
+		but does not drop the Viewer's reference to the Observable incase
+		it needs to reattach. This will be a problem for Viewers that
+		observe more than one Viewable, so let's assume that BaseViewer
+		is specifically a monogamous Viewer!
+	 */
+	public void detach() { obs.deleteObserver(this); } // obs=null;
+
+	/** Respond to changes in Observable. This implementation tests
+		to see if the Observable is being destroyed and if so, attempts to
+		destroy the Viewer.
+	*/
+	public void update(Observable o, Object arg) { disposeFilter(o,arg); }
+
+	/** implementation of update method is here so that it can be called
+		easily by sub-classes more than one generation removed. */
+	protected final boolean disposeFilter(Observable o, Object arg)
+	{
+		if (obs.equals(o) && Viewable.DISPOSING==arg) {
+			Shell.releaseViewer(this);
+			return true;
+		}
+		return false;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,22 @@
+/AgentAdapter.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/BaseViewer.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/ConsoleEnvironment.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/DefaultViewer.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/FileFilter.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/FilteredEnvironment.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/HashMap.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/IMap.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/LinearMap.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/LogMap.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/MouseRetarget.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/StackLayout.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Tools.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/UserEnvironment.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VLayout.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VMap.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VariableViewer.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+D/heavy////
+D/light////
+D/shell////
+D/swing////
+/Properties.java/1.2/Mon Oct  9 21:16:17 2006//
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/util
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/ConsoleEnvironment.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,85 @@
+/*
+ *	ConsoleEnvironment.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import  samer.core.*;
+import  java.io.*;
+
+/**	
+  *	Environment which provides access to the user
+  *	using the standard input and output
+  */
+
+public class ConsoleEnvironment extends Environment
+{
+	BufferedReader	in;
+
+	public ConsoleEnvironment(Environment parent) {
+		super(parent,parent.node());
+		in=new BufferedReader(new InputStreamReader(System.in));
+	}
+
+	public Datum datum() { return new Texton("",Null); } // ??
+	public Datum datum(String name) {
+		// should check if use is willing to supply value
+		// if not return Null (or bad score)
+		return new Texton(rel(name),parent.datum(abs(name))); 
+	}
+
+	private class Texton implements Datum 
+	{
+		String	name;			// name of this Binding
+		Datum		inherited;	// parent's binding
+
+		public Texton(String nm, Datum inh) { name=nm; inherited=inh; }
+
+		public String name()  { return this.name; }
+		public int	  score() { return 32; } // less than perfect match
+
+		public Object get(Codec c, Object def)
+		{
+			if (def==null) def=inherited.get(c,def);
+
+			Shell.push(parent);
+			try {
+				System.out.println("Enter value for "+name);
+				if (def!=null) {
+					System.out.println("Default value is: " + def);
+				}
+				String instring=in.readLine();
+
+				if (instring.equals(".")) {
+					System.out.println("returning: "+def);
+					return def;
+				}
+				return c.decode(instring);
+			} catch (Exception ex) { 
+				Shell.trace(ex.toString());
+				throw new Error("get "+name);
+			} finally { Shell.pop(); }
+		}
+
+		public void get(Autocoder obj)
+		{
+			Shell.push(parent);
+			try {
+				System.out.println("Enter value for "+name);
+				System.out.println("Current value is: " + obj.string());
+				String instring=in.readLine();
+				if (!instring.equals(".")) obj.decode(instring);
+			} catch (Exception ex) { 
+				Shell.trace(ex.toString());
+				throw new Error("get "+name);
+			} finally { Shell.pop(); }
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/DefaultViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,10 @@
+package samer.core.util;
+import  samer.core.*;
+
+public class DefaultViewer extends BaseViewer {
+	public DefaultViewer(Viewable v) {
+		super(v);
+		panel().setName(v.getLabel());
+		panel().setLayout(new StackLayout(2));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/FileFilter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,23 @@
+package samer.core.util;
+
+import java.io.*;
+
+public class FileFilter 
+	implements java.io.FileFilter, java.io.FilenameFilter {
+
+	String	extension;
+
+	public FileFilter() { this(""); }
+	public FileFilter(String ext) { setExtension(ext); }
+
+	public boolean accept(File file) { return test(file.getName()); }
+	public boolean accept(File dir, String filename) {
+		return test(filename);
+	}
+
+	private boolean test(String fn) { 
+		return fn.toLowerCase().endsWith(extension); 
+	}
+
+	public void setExtension(String ext) { extension=ext.toLowerCase(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/FilteredEnvironment.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,46 @@
+/*
+ *	Properties.java	
+ *
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.util;
+import	samer.core.*;
+import	java.io.*;
+
+public class FilteredEnvironment extends Environment
+{
+	Environment env;
+	String		filter;
+
+	public FilteredEnvironment(Environment env, String filter) { 
+		super(env.parent(),env.node()); this.env=env; this.filter=filter;
+	}
+
+	public void store(String nm, Autocoder o) {
+		if (nm.endsWith(filter)) env.store(nm,o);
+		else parent.store(nm,o);
+	}
+
+	public void store(String nm, Object o, Codec c) {
+		if (nm.endsWith(filter)) env.store(nm,o,c);
+		else parent.store(nm,o,c);
+	}
+
+	public void		add(Object obj) { env.add(obj); } 
+	public Binding	add(String nm, Object o){
+		if (nm.endsWith(filter)) return env.add(nm,o);
+		else return parent.add(abs(nm),o); 
+	}
+
+	public Datum datum() { return env.datum(); }
+	public Datum datum(String name) { return env.datum(name); }
+	public Binding binding(String name) { return env.binding(name); }
+	public Iterator data() { return env.data(); }
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/HashMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,94 @@
+package	samer.core.util;
+import	samer.core.*;
+
+
+public class HashMap extends Environment
+{
+	java.util.HashMap	map=new java.util.HashMap();
+
+	public HashMap(Environment parent) { super(parent,parent.node()); }
+	public HashMap(Environment parent, String name) {
+		super(parent,new Node(name,parent.node()));
+	}	
+
+	protected class Entry implements Binding
+	{
+		String	nm;
+		Object	vl;
+		int		sc;
+
+		Entry(String n, Object v, int s) { nm=n; vl=v; sc=s; }
+
+		public String  name() { return abs(nm); } 
+		public int		score() { return sc; }
+
+		public Object	get() { return vl; }
+		public Object	get(Codec c, Object def) { return c.decode(vl); }
+		public void		get(Autocoder obj) { obj.decode(vl); }
+
+		public void		set(Object obj) { map.put(nm,obj); }
+		public void		remove() { map.remove(nm); }
+	}
+
+	public Binding add(String name, Object value) 
+	{
+		// check for existing value??
+		if (belongs(name)) {
+			String key=rel(name);
+			map.put(key,value);
+			return new Entry(key,value,0);
+		} else return super.add(name,value);
+	}
+
+	public Datum datum(String name) 
+	{
+		Binding local=localFind(rel(name)); // localised name
+		if (local.score()>0) { 
+			// if match is less than perfect, get parent's best match
+			Datum inherited=parent.datum(abs(name));
+			if (inherited.score()<local.score()) return inherited;
+		}
+		return local;
+	}
+
+	public Binding binding(String name) 
+	{
+		Binding local=localFind(rel(name)); // localised name
+
+		if (local.score()>0) { 
+			// if match is less than perfect, get parent's best match
+			Binding inherited=parent.binding(abs(name));
+			if (inherited.score()<local.score()) return inherited;
+		}
+		return local;
+	}
+
+	public Iterator data()
+	{
+		return new CompoundIterator(
+			new Iterator() {
+				java.util.Iterator it=map.entrySet().iterator();
+				public boolean hasNext() { return it.hasNext(); }
+				public Datum   next() {
+					java.util.Map.Entry entry=(java.util.Map.Entry)it.next();
+					return new Entry((String)entry.getKey(),entry.getValue(),0);
+				}
+			},
+			parent.data()
+		);
+	}
+	
+	protected Binding localFind(String key) 
+	{
+		String	pname = '.'+key;
+
+		for (int i=0, s=0; i>=0; s++) {
+			pname = pname.substring(i+1);
+			Object val=map.get(pname); 
+			if (val!=null) return new Entry(pname,val,s);
+			i = pname.indexOf('.');
+		}
+		return Null;
+	}
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/IMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+
+/**
+	Integer map:
+	This class maps a given interval of real numbers
+	to the interval [0,1], returning either the real
+	number, or converting it to an integer between 0
+	and a given value (defaults to 256). 
+ */
+
+public class IMap
+{
+	double	a, b;
+	double	ia, ib;
+	int		maxi;
+	double	c;
+	boolean  clipped;
+
+	public IMap copy() { try { return (IMap)this.clone(); } catch (Exception ex) {} return null; }
+
+	public String toString() { return "["+getDomainMin()+","+getDomainMax()+")->{0.."+(maxi-1)+"}"; }
+	public double getDomainMin() { return b/a; }
+	public double getDomainMax() { return (1+b)/a; }
+	public void setDomain( double t1, double t2)
+	{
+		a	= 1/(t2-t1);
+		b	= a*t1;
+		ia  = c*a;
+		ib  = c*b;
+	}
+
+	public int	getIntRange() { return maxi+1; }
+	public void setIntRange( int m)
+	{ 
+		maxi= m-1; 
+		c   = m;
+		ia  = c*a;
+		ib  = c*b;
+	}
+
+	public double map( double t) { return a*t-b; }
+	public int clipInt( double t)
+	{
+		double x=ia*t-ib;
+		if (x<0)	return 0;
+		if (x>=c)	return maxi;
+		return (int)x;
+	}
+
+	// sets a flag if clipped
+	public int toInt( double t)
+	{
+		double x=ia*t-ib;
+		clipped = (x<0 || x>=c);
+		return (int)x;
+	}
+
+	// inverse mapping
+	public double inverse(double y) { return (y+b)/a; }
+	public double inverseFromInt(int y) { return (y+ib)/ia; }
+
+	public boolean wasClipped() { return clipped; }
+	protected IMap() {}
+}
+
+
+
+
+
+	
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/LinearMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+
+/**
+	This class maps a given interval of real numbers
+	to the interval [0,1], returning either the real
+	number, or converting it to an integer between 0
+	and a given value (defaults to 256). 
+ */
+
+public class LinearMap extends IMap
+{
+	public LinearMap() { this(0.0,1.0,256); }
+	public LinearMap(int m) { this(0.0,1.0,m); }
+	public LinearMap(double t1, double t2) { this(t1,t2,256); }
+	public LinearMap(double t1, double t2, int m) { setDomain(t1,t2); setIntRange(m); }
+}
+
+
+
+
+
+	
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/LogMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,47 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+
+/**
+	This class maps a given interval of real numbers
+	to the interval [0,1], returning either the real
+	number, or converting it to an integer between 0
+	and a given value (defaults to 256). 
+ */
+
+public class LogMap extends IMap
+{
+	public LogMap() { this(0.001,1.0,256); }
+	public LogMap(int m) { this(0.001,1.0,m); }
+	public LogMap(double t1, double t2) { this(t1,t2,256); }
+	public LogMap(double t1, double t2, int m) { setDomain(t1,t2); setIntRange(m); }
+
+	public double getDomainMin() { return Math.exp(super.getDomainMin()); }
+	public double getDomainMax() { return Math.exp(super.getDomainMax()); }
+	public void setDomain( double t1, double t2)	{
+		if (t1<0 || t2<0) throw new Error("Bad domain for log map");
+		super.setDomain( Math.log(t1), Math.log(t2));
+	}
+
+	private static double log(double t) { return t>0 ? Math.log(t) : Double.NEGATIVE_INFINITY; }
+	public final double map( double t) { return super.map(log(t)); }
+	public final int clipInt( double t) { return super.clipInt(log(t)); }
+	public final int toInt( double t) { return super.toInt(log(t)); }
+	public double inverse(double t) { return Math.exp(super.inverse(t)); }
+	public double inverseFromInt(int i) { return Math.exp(super.inverseFromInt(i)); }
+}
+
+
+
+
+
+	
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/MouseRetarget.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *	MouseRetarget.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import  java.awt.*;
+import  java.awt.event.*;
+
+
+/**
+		This is a mouse event handler that makes
+		a component effectively invisible to
+		mouse clicks by routing a events through
+		to the parent container. 
+ */
+		
+public class MouseRetarget extends MouseAdapter
+{
+	private void retarget(MouseEvent e)
+	{
+		if (!e.isConsumed()) { // no point otherwise
+			Component c=e.getComponent();
+			Component parent=c.getParent();
+
+			if (parent!=null) {
+				Point origin=c.getLocation();
+		
+				// Must make new event look as if it
+				// was generated by parent
+
+				MouseEvent ee = new MouseEvent(
+					parent,
+					e.getID(),	
+					e.getWhen(), 
+					e.getModifiers(),
+					e.getX() + origin.x,
+					e.getY() + origin.y,
+					e.getClickCount(),                  
+					e.isPopupTrigger());
+
+				parent.dispatchEvent(ee);
+			}
+		}
+	}
+
+	public void mouseClicked(MouseEvent e) { retarget(e); }
+	public void mousePressed(MouseEvent e) { retarget(e); }
+	public void mouseReleased(MouseEvent e) { retarget(e); }
+
+	// This one static object can handle all the mouse
+	// event redirection for everyone
+
+	public static final MouseListener listener=new MouseRetarget();
+	public static void mouseInvisibilityFor(Component c) {
+		c.addMouseListener(listener);
+	}
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/Properties.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,115 @@
+/*
+ *	Properties.java	
+ *
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.util;
+import	samer.core.*;
+import	java.io.*;
+
+public class Properties extends Environment
+{
+	protected java.util.Properties	props;
+	protected boolean	writable;
+
+	public Properties(Environment parent) { 
+		this(parent,parent.node(),new java.util.Properties());
+	}
+	public Properties(Environment parent, java.util.Properties pr) {
+		this(parent,parent.node(),pr);
+	}
+	public Properties(Environment parent, Node n) {
+		this(parent,n,new java.util.Properties());
+	}
+	public Properties(Environment parent, Node n, java.util.Properties pr) {
+		super(parent,n); props=pr; writable=true;
+	}
+
+	public void save(OutputStream out) throws Exception { props.store(out,"properties"); }
+	public void load(InputStream in) throws Exception { props.load(in); }
+	public void setWritable(boolean f) { writable=f; }
+	protected class Property implements Binding
+	{
+		String	nm;
+		String	vl;
+		int		sc;
+
+		Property(String n, String v, int s) { 
+			nm=n; sc=s;
+			vl = v.equals("~default") ? null : v;
+		}
+
+		public String	name() { return abs(nm); }		
+		public int		score() { return sc; }
+
+		public Object	get() { return vl; }
+		public Object	get(Codec c, Object def) { return c.decode(vl==null?def:vl); }
+		public void		get(Autocoder obj) { obj.decode(vl); }
+
+		public void		set(Object obj) { props.put(nm,(String)obj); }
+		public void		remove() { props.remove(nm); }
+	}
+
+	public void store(String name, Autocoder o) {
+		if (writable && belongs(name)) props.put(rel(name),o.string());
+		else parent.store(name,o);
+	}
+	public void store(String name, Object o, Codec c) {
+		if (writable && belongs(name)) props.put(rel(name),c.string(o));
+		else parent.store(name,o,c);
+	}
+
+	public Datum datum(String name) 
+	{
+		Datum local=localFind(rel(name)); // localised name
+
+		if (local.score()>0) { 
+			// if match is less than perfect, get parent's best match
+			Datum inherited=parent.datum(abs(name));
+			if (inherited.score()<local.score()) return inherited;
+		}
+		return local;
+	}
+
+	public Binding binding(String name) 
+	{
+		Binding local=localFind(rel(name)); // localised name
+
+		if (local.score()>0) { 
+			Binding inherited=parent.binding(abs(name));
+			if (inherited.score()<local.score()) return inherited;
+		}
+		return local;
+	}
+
+	public Iterator data()
+	{
+		return new CompoundIterator( new Iterator() {
+			java.util.Enumeration enu=props.keys();
+			public boolean hasNext() { return enu.hasMoreElements(); }
+			public Datum next() {
+				String key=(String)enu.nextElement();
+				return new Property(key,props.getProperty(key),0);
+		} }, parent.data() );
+	}
+
+	public Binding localFind(String key) 
+	{
+		String	val, pname = '.'+key;
+
+		for (int i=0, s=0; i>=0; s++) {
+			pname = pname.substring(i+1);
+			val=props.getProperty(pname); 
+			if (val!=null) return new Property(pname,val,s);
+			i = pname.indexOf('.');
+		}
+		return Null;
+	}
+}
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/StackLayout.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,95 @@
+/*
+ *	StackLayout.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import java.awt.*;
+
+/**
+	This layout manager stacks everything up vertically
+	letting each component assume it's preferred height,
+	but stretching them all out to fill the width available.
+	The preferred width is the height of the widest
+	component
+ */
+
+public class StackLayout implements LayoutManager, java.io.Serializable
+{
+	private int		gap;
+
+	public StackLayout() { gap=0; }
+	public StackLayout(int a) { gap=a; }
+	public void setGap(int a) { gap=a; }
+	public int  getGap(int a) { return gap; }
+
+	public void addLayoutComponent(String name, Component comp) {}
+	public void removeLayoutComponent(Component comp) {}
+
+	public Dimension preferredLayoutSize(Container parent)
+	{
+		Component[] c=parent.getComponents();
+		Dimension	d1=new Dimension(0,0), d2;
+
+		int	n=c.length;
+		for (int i=0; i<n; i++) {
+			d2 = c[i].getPreferredSize();
+			d1.height += d2.height;
+			d1.width  = Math.max(d1.width,d2.width);
+		}
+
+		if (n>1) d1.height += (n-1)*gap;
+
+		Insets		insets=parent.getInsets();
+		d1.width  += insets.left + insets.right;
+		d1.height += insets.top + insets.bottom;
+
+		return d1;
+	}
+
+	public Dimension minimumLayoutSize(Container parent) 
+	{
+		Component[] c=parent.getComponents();
+		Dimension	d1=new Dimension(0,0), d2;
+
+		int	n=c.length;
+		for (int i=0; i<n; i++) {
+			d2 = c[i].getMinimumSize();
+			d1.height += d2.height;
+			d1.width  = Math.max(d1.width,d2.width);
+		}
+
+		if (n>1) d1.height += (n-1)*gap;
+
+		Insets		insets=parent.getInsets();
+		d1.width  += insets.left + insets.right;
+		d1.height += insets.top + insets.bottom;
+
+		return d1;
+	}
+
+	public void layoutContainer(Container parent)
+	{
+		Component[] c=parent.getComponents();
+		Insets		insets=parent.getInsets();
+		int			x, y, w;
+		Dimension	p=parent.getSize(), d;
+
+		w = p.width - (insets.left+insets.right);
+		x = insets.left;
+		y = insets.top;
+
+		int	n=c.length;
+		for (int i=0; i<n; i++) {
+			d = c[i].getPreferredSize();
+			c[i].setBounds(x,y,w,d.height);
+			y += d.height + gap;
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/Tools.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+/*
+ *	Tools.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+
+import  java.awt.*;
+import  java.io.*;
+import  java.util.*;
+import  java.awt.*;
+import  java.lang.reflect.*;
+import  samer.core.*;
+
+public class Tools
+{
+	// for scheme to use - a bit clunky!
+
+	public static double[] doubleArray(int n) { return new double[n]; }
+	public static double   doubleArray(double[] x, int i) { return x[i]; }
+	public static double   doubleArray(double[] x, int i, double y) { return x[i]=y; }
+	public static double[] doubleArray(double[] x, Object[] y) {
+		for (int i=0; i<y.length; i++)
+			x[i]=((Double)X.DoubleCodec.decode(y[i])).doubleValue();
+		return x;
+	}
+	public static double[] doubleArray(Object [] y) {
+		double [] x=new double[y.length];
+		return doubleArray(x,y);
+	}
+
+	private static Object aa=RenderingHints.VALUE_ANTIALIAS_OFF;
+
+	public static void setAntialias(boolean f) {
+		aa= f ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF;
+	}
+
+	public static Graphics initGraphics( Graphics g)
+	{
+		Graphics2D	g2=(Graphics2D)g;
+		g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED);
+		//g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, aa);
+		return g;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/UserEnvironment.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,172 @@
+/*
+ *	UserEnvironment.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import  samer.core.types.*;
+import  samer.core.*;
+import  java.util.Hashtable;
+import  java.awt.Color;
+
+/**	
+  *	Environment which provides access to the user
+  *	using a GUI
+  */
+
+public class UserEnvironment extends Environment
+{
+	boolean toggleBoolean=false;
+	boolean state;
+
+	public UserEnvironment(Environment parent) {	super(parent,parent.node()); }
+	public UserEnvironment(Environment parent, boolean bool) { 
+		super(parent,parent.node()); toggleBoolean=true; state=bool;
+	}
+
+	private static Hashtable reg=new Hashtable();
+
+	public interface Thingy {
+		Viewable viewable(String name, Object obj);
+		Object	decode(Viewable vbl);
+	}
+
+	static {
+		reg.put( Boolean.class, new Thingy() {
+			public Object decode(Viewable vbl) { return new Boolean(((VBoolean)vbl).value); }
+			public Viewable viewable(String name, Object obj) {
+				return new VBoolean(name,((Boolean)obj).booleanValue(),Variable.NOINIT);
+			}
+		} );
+
+		reg.put( Integer.class, new Thingy() {
+			public Object decode(Viewable vbl) { return new Integer(((VInteger)vbl).value); }
+			public Viewable viewable(String name, Object obj) {
+				return new VInteger(name,((Number)obj).intValue(),Variable.NOINIT);
+			}
+		} );
+
+		reg.put( Double.class, new Thingy() {
+			public Object decode(Viewable vbl) { return new Double(((VDouble)vbl).value); }
+			public Viewable viewable(String name, Object obj) {
+				return new VDouble(name,((Number)obj).doubleValue(),Variable.NOINIT);
+			}
+		} );
+
+		reg.put( String.class, new Thingy() {
+			public Object decode(Viewable vbl) { return ((VString)vbl).value; }
+			public Viewable viewable(String name, Object obj) {
+				return new VString(name,obj==null ? "" : (String)obj,Variable.NOINIT);
+			}
+		} );
+
+		reg.put( Color.class, new Thingy() {
+			public Object decode(Viewable vbl) { return ((VColor)vbl).getColor(); }
+			public Viewable viewable(String name, Object obj) {
+				return obj!=null ?
+						new VColor(name,(Color)obj,Variable.NOINIT)
+					:	new VColor(name,Variable.NOINIT);
+			}
+		} );
+	}
+
+	public void add(Object o) { Shell.print(X.codec(o).string(o)); }
+	public Binding add(String n, Object o) {
+		Shell.print(n+"="+X.codec(o).string(o));
+		return super.add(n,o);
+	}
+
+	public Datum datum() { return new Gluon(".",Null); } // ??
+	public Datum datum(String name) {
+		return new Gluon(rel(name),parent.datum(abs(name)));
+	}
+
+	private class Gluon implements Datum
+	{
+		String	name;			// name of this Binding
+		Datum		inherited;	// parent's binding
+
+		public Gluon(String nm, Datum inh) { name=nm; inherited=inh; }
+
+		public String name()  { return this.name; }
+		public int	  score() { return 0; } // ie perfect match
+
+		public Object get(Codec c, Object def)
+		{
+			if (toggleBoolean) {
+				if (c.targetClass()==Boolean.class) return new Boolean(state);
+			}
+
+			if (def==null) def=inherited.get(c,def);
+			else def=c.decode(def); // ??
+
+			Thingy thing=(Thingy)reg.get(c.targetClass());
+
+			if (thing==null) {
+				Object strdef=(def==null?null:c.string(def));
+				Object result=get(X.StringCodec,strdef);
+				return (result==strdef ? def : c.decode(result));
+			}
+
+			// what if def is still null??
+
+			Shell.push(parent);
+			try {
+				// create, decode, and dispose of dialog with user
+				Viewable vbl=thing.viewable(name,def);
+				String	rc=showdlg(vbl.getViewer().getComponent());
+				if (rc.equals("ok")) def=thing.decode(vbl);
+				vbl.dispose();
+				check(rc);
+
+				return def;
+			} finally { Shell.pop(); }
+		}
+
+		public void get(Autocoder obj)
+		{
+			if (toggleBoolean) {
+				 if (obj instanceof VBoolean) obj.decode(new Boolean(state));
+			} else if (obj instanceof Viewable) {
+				Viewable vbl=(Viewable)obj;
+				Object	old=obj.object();
+
+				Shell.push(parent);
+				try {
+					Viewer	vwr=((Viewable)obj).getViewer();
+					String	rc=showdlg(vwr.getComponent());
+					if (rc.equals("default")) { obj.decode(old); vbl.changed(); }
+					vwr.detach();
+					check(rc);
+				}
+				finally { Shell.pop(); }
+			} else {
+				obj.decode(get(X.StringCodec,obj.string()));
+			}
+		}
+
+		private void check(String rc) {
+			if (rc.equals("cancel")) throw new Error("cancel");
+		}
+
+		private String showdlg(java.awt.Component c) {
+			Shell.Dialog	dlg = Shell.getDialog(name.endsWith(".") ? "Parameter entry" : name);
+
+			dlg.container().add(c);
+			dlg.addAction("default");
+			dlg.addAction("cancel");
+			dlg.addAction("ok");
+			dlg.expose();
+			dlg.dispose();
+
+			return dlg.result();
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/VLayout.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,124 @@
+/*
+ *	VLayout.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util;
+import java.awt.*;
+
+/**
+	Things are layed out horizontally. Everyone gets to
+	be their preferred size, except for the filler, which
+	is stretched horizontally (but not vertically) to fill
+	the space available. The whole thing is centered vertically.
+ */
+
+public class VLayout implements LayoutManager, java.io.Serializable
+{
+	private int		gap=4;
+	private int		filler=1; // index of filler component
+	private int		fillerHeight=10;
+
+	public VLayout( int f, int g) { gap=g; filler=f; }
+	public VLayout( int f) { gap=0; filler=f; }
+
+	public void setGap(int a) { gap=a; }
+	public int  getGap() { return gap; }
+	public void setFiller(int f) { filler=f; }
+	public int  getFiller() { return filler; }
+	public void addLayoutComponent(String name, Component comp) {}
+	public void removeLayoutComponent(Component comp) {}
+
+	public Dimension preferredLayoutSize(Container parent)
+	{
+		Component[] c=parent.getComponents();
+		Dimension	d1=new Dimension(0,0), d2;
+
+		int	n=c.length;
+		for (int i=0; i<n; i++) {
+			d2 = c[i].getPreferredSize();
+			d1.width += d2.width;
+			d1.height = Math.max(d1.height,d2.height);
+		}
+
+		if (n>1) d1.width += (n-1)*gap;
+
+		Insets		insets=parent.getInsets();
+		d1.width  += insets.left + insets.right;
+		d1.height += insets.top + insets.bottom;
+
+		return d1;
+	}
+
+	public Dimension minimumLayoutSize(Container parent) 
+	{
+		Component[] c=parent.getComponents();
+		Dimension	d1=new Dimension(0,0), d2;
+
+		int	n=c.length;
+		for (int i=0; i<n; i++) {
+			d2 = c[i].getMinimumSize();
+			d1.width += d2.width;
+			d1.height = Math.max(d1.height,d2.height);
+		}
+
+		if (n>1) d1.width += (n-1)*gap;
+
+		Insets		insets=parent.getInsets();
+		d1.width  += insets.left + insets.right;
+		d1.height += insets.top + insets.bottom;
+
+		return d1;
+	}
+
+	public void layoutContainer(Container parent)
+	{
+		Component[] c=parent.getComponents();
+		Insets		insets=parent.getInsets();
+		int			xl, xr, y, havail, h;
+		Dimension	p=parent.getSize(), d;
+
+		havail = p.height - (insets.top+insets.bottom);
+
+		int	n=c.length;
+
+		// first layout components left of filler
+
+		xl = insets.left;
+		for (int i=0; i<filler && i<n; i++) {
+			d = c[i].getPreferredSize();
+			if (d.height>havail) { h=havail; y=insets.bottom; }
+			else				 { h=d.height; y=(p.height-h)/2; }
+			c[i].setBounds(xl,y,d.width,h);
+			xl += d.width + gap;
+		}
+		// xl is now position of left hand edge of filler
+
+		// next, layout components right of filler
+		// x is now position of RIGHTHAND edge
+
+		xr = p.width-insets.right; 
+		for (int i=n-1; i>filler && i>=0; i--) {
+			d = c[i].getPreferredSize();
+			if (d.height>havail) { h=havail; y=insets.bottom; }
+			else				 { h=d.height; y=(p.height-h)/2; }
+			c[i].setBounds(xr-d.width,y,d.width,h);
+			xr -= d.width + gap;
+		}
+		// xr is now position of right hand edge of filler
+
+		// now we can position the filler component
+		if (filler>=0 && filler<n) {
+			d = c[filler].getPreferredSize();
+			if (d.height>havail) { h=havail; y=insets.bottom; }
+			else				 { h=d.height; y=(p.height-h)/2; }
+			c[filler].setBounds(xl,y,xr-xl,h);
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/VMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,188 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.util;
+
+import   samer.core.*;
+import	samer.core.types.*;
+import	java.util.*;
+import	java.awt.*;
+
+/**
+	An Agent and Viewable that manages a IMap object - provides
+	a user interface for adjusting the domain.
+ */
+
+public class VMap extends Viewable implements Agent
+{
+	IMap		map;
+	boolean	symmetric;
+
+	public static final Object NEW_MAP = new Object();
+
+	public VMap(IMap m) { this(m,true); }
+	public VMap(IMap m, Node node) { this(m,true,node); }
+	public VMap(IMap m, boolean init) { this(m,init,new Node("map")); }
+
+	/** Construct a VMap from a given IMap and node. The boolean init flag specifies
+		whether or not the VMap should reinitialise the IMap from the current Environment
+	*/
+	
+	public VMap(IMap m, boolean init, Node node)
+	{
+		super(node);
+		setAgent(this);
+
+		map = m;
+		symmetric = false;
+
+		if (init) {
+			Shell.push(getNode());
+			try {
+				boolean logmap = Shell.getBoolean("log", false);
+
+				if (logmap) { map=new LogMap(); symmetric=false; }
+				else symmetric = Shell.getBoolean( "symmetric", symmetric);
+
+				setDomain(
+					Shell.getDouble("minimum",map.getDomainMin()),
+					Shell.getDouble("maximum",map.getDomainMax())
+				);
+			} finally { Shell.pop(); }
+		}
+	}
+
+	public void setMap( IMap m) { map=m; changed(NEW_MAP); }
+	public IMap getMap() { return map; }
+
+	public String toString() { return super.toString()+"="+map.toString(); }
+	
+	// ........... Viewable bits ................
+
+	public void dispose()
+	{
+		Shell.deregisterAgent(this);
+		super.dispose();
+	}
+
+	public Viewer	getViewer() { return new Adjuster(); }
+
+	// ........... Agent Bits ...................
+
+	public void getCommands(Agent.Registry r) {
+		r.add("domain").add("symmetric",symmetric);
+		r.add("linear").add("log");
+		r.group();
+		r.add("put").add("get");
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if (c.equals("domain"))	{
+			Shell.showDialogFor(getViewer().getComponent(),Node.lastPart(node.fullName()));
+		} else if (c.equals("symmetric")) {
+			symmetric = X._bool(env.datum(),!symmetric);
+			setDomain( map.getDomainMin(), map.getDomainMax());
+			changed();
+		} else if (c.equals("linear")) {
+			IMap newmap = new LinearMap( );
+			newmap.setDomain( map.getDomainMin(), map.getDomainMax());
+			newmap.setIntRange( map.getIntRange());
+			setMap(newmap);
+		} else if (c.equals("log")) {
+			double min=map.getDomainMin();
+			double max=map.getDomainMax();
+
+			if (min<=0) min=max/1000; // default dynamic range
+			symmetric=false;
+			setMap(new LogMap(min,max,map.getIntRange()));
+		} else if (c.equals("put")) Shell.put("map",this);
+		else if (c.equals("get")) setMap(((VMap)Shell.get("map")).getMap().copy());
+		/* or
+			} else if (c.equals("put")) Shell.put("map",this.getMap().copy());
+			else if (c.equals("get")) setMap((IMap)Shell.get("map"));
+		*/
+	}
+
+	public void setSymmetric(boolean f) { symmetric=f; }
+	public void setDomain( double min, double max)
+	{
+		if (map instanceof LogMap) {
+			if (min<=0) min=max/1000;
+		} else {
+			if (symmetric) { max=Math.max(max,-min); min=-max; }
+		}
+		// Shell.trace("new domain=["+min+","+max+")");
+		map.setDomain(min,max);
+	}
+
+	class Adjuster extends BaseViewer
+	{
+		VBoolean		sym;
+		VDouble		t1, t2;
+
+		Adjuster()
+		{
+			super(VMap.this);
+			panel().setName(getLabel());
+			Shell.push(getNode());
+
+			setLayout( new StackLayout());
+
+			t1 = new VDouble("maximum",map.getDomainMax(),Variable.NOINIT);
+			t2 = new VDouble("minimum",map.getDomainMin(),Variable.NOINIT);
+			sym= new VBoolean("symmetric",symmetric,Variable.NOINIT);
+			t1.addObserver(this);
+			t2.addObserver(this);
+			sym.addObserver(this);
+
+			add(t1.getViewer().getComponent());
+			add(t2.getViewer().getComponent());
+			add(sym.getViewer().getComponent());
+
+			Shell.pop();
+		}
+
+		public void update(Observable o, Object src)
+		{
+			if (src==this) return; // &&&
+			if (VMap.this.equals(o)) {
+				// means someone has changed the map ...
+				// ... and if it wasn't us...
+				t1.value=map.getDomainMax(); t1.changed(this);
+				t2.value=map.getDomainMin(); t2.changed(this);
+				if (sym.value!=symmetric) {
+					sym.value=symmetric; sym.changed(this);
+				}
+			} else {
+				// Widget adjusted
+				// user has adjusted controls...
+				// must set map and notify any observers
+				if (sym==o) {
+					if (symmetric=sym.value) {
+						double max=Math.max(t1.value,-t2.value);
+						t1.value=max; t2.value=-max;
+						t1.changed(this); t2.changed(this);
+					}
+				} else {
+					if (symmetric) {
+						if (t1==o)      { t2.value=-t1.value; t2.changed(this); }
+						else if (t2==o) {	t1.value=-t2.value; t1.changed(this); }
+					}
+				}
+				map.setDomain(t2.value,t1.value);
+				changed(this);
+				// else, WE adjusted the controls to
+				// reflect reality, so do nothing
+			}
+		}
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/VariableViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,53 @@
+/*
+ *	VariableViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.util;
+import	samer.core.*;
+import	java.util.*;
+
+/** A VariableViewer is a BaseViewer that provides Agent commands
+	for saving and restoring its Variable. It also sets the BaseViewer's
+	label using the name of the Variable.
+*/
+
+public class VariableViewer extends BaseViewer implements Agent
+{
+	protected Variable variable;
+
+	/** Construct a VariableViewer for the given Variable, setting the
+		viewer's label to the default provided by variable.getLabel().
+	 */
+	protected VariableViewer(Variable v) {
+		super(v); variable = v;
+		setText(v.getLabel());
+		exposeCommands(this);
+	}
+
+	// ............. Agent bits .................
+
+	/** Reports the following commands: "save" and "restore". */
+	public void getCommands(Agent.Registry r) { r.add("store").add("restore"); }
+
+	/** Handles the commands "save" and "restore" using
+		Variable.save() and Variable.load(). */
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if      (cmd.equals("store"))		{ variable.save(Shell.env()); }
+		else if (cmd.equals("restore"))	{ variable.load(Shell.env()); }
+		//else if (cmd.equals("full name")) {
+		//	env.add(variable.getNode().fullName());
+		//}
+	}
+
+	/** A utility layout manager provided for VariableViewers to use.
+		(See VLayout class) */
+	protected static final VLayout	layout = new VLayout(1,6);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Border.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,146 @@
+/*
+ *	Border.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+/**
+	A class for managing borders (eg bevelly borders).
+	Borders are actually implemented by the Border.Interface
+	interface. Vaguely based on javax.swing.border architecture - 
+	should be easy to move to swing borders eventually.
+  */
+
+public class Border 
+{
+	public interface Interface
+	{
+		void paintBorder(Component c, Graphics g, int x, int y, int w, int h);
+		Insets getBorderInsets(Component c);
+		boolean isBorderOpaque();
+	}
+
+	public final static int	OUT=-1;
+	public final static int	IN=1;
+	public final static int	NONE=0;
+
+	public static Interface create(int type, int inset)
+	{
+		Base b;
+		switch (type) {
+			case IN: b=new In(); break;
+			case OUT: b=new Out(); break;
+			default: b=new Empty(); break;
+		}
+		b.setInset(inset);
+		return b;
+	}
+
+	public static Interface createDefault() {
+		return create(defaultBevel,defaultInset);
+	}
+
+	public static Interface createWithInset(int inset) { 
+		return create(defaultBevel,inset);
+	}
+
+	public static Interface create(int type) { 
+		return create(type,defaultInset);
+	}
+
+	public static Interface createEmpty() {
+		return create(NONE,defaultInset);
+	}
+
+	public static void pushIn() { push(IN); }
+	public static void pushOut() { push(OUT); }
+	public static void pushNone() { push(NONE); }
+	public static void push( int f) { push(f,defaultInset); }
+	public static void push( int f, int ins)
+	{ 
+		bevelStack.push(new BevelInfo(defaultBevel,defaultInset));
+		defaultBevel=f; 
+		defaultInset=ins;
+	}
+
+	public static void pop()
+	{
+		BevelInfo bi = (BevelInfo)bevelStack.pop();
+		defaultBevel = bi.type;
+		defaultInset = bi.inset;
+	}
+
+	// ----------------------------------------------
+
+	public static class Null implements Interface
+	{
+		public void    paintBorder(Component c, Graphics g, int x, int y, int w, int h) {}
+		public Insets  getBorderInsets(Component c) { return new Insets(0,0,0,0); }
+		public boolean isBorderOpaque() { return false; }
+	}
+
+	private static abstract class Base implements Interface
+	{
+		protected int inset;
+
+		public boolean isBorderOpaque() { return false; }
+		public void    setInset(int ins) { inset=ins; }
+		public Insets  getBorderInsets(Component c)
+		{ 
+			int a = inset+2;
+			return new Insets(a,a,a,a); 
+		}
+	}
+
+	private static class In extends Base
+	{
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+		{
+			g.setColor( c.getParent().getBackground()); 
+			g.drawRect( x, y, w-1, h-1);
+			g.draw3DRect( x+1, y+1, w-3, h-3, false);
+		}
+	}
+
+	private static class Out extends Base
+	{
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+		{
+			g.setColor( c.getBackground());
+			g.draw3DRect( x+1, y+1, w-3, h-3, true);
+		}
+	}
+
+	private static class Empty extends Base
+	{
+		public Insets  getBorderInsets(Component c) { 
+			return new Insets(inset,inset,inset,inset); 
+		}
+
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {}
+	}
+
+
+	private static class BevelInfo {
+		int	type;
+		int	inset;
+
+		BevelInfo(int t,int i) { type=t; inset=i; }
+	}
+
+	private static int defaultBevel=Shell.getInt("border.bevel",NONE);
+	private static int defaultInset=Shell.getInt("border.inset",4);
+	private static Stack bevelStack=new Stack();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Borders.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,269 @@
+/*
+ *	AppletBorders.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+
+public class Borders 
+{
+	protected static void drawThickRect(Graphics g,int x, int y, int w, int h, int th)
+	{
+		g.fillRect(x,y,w,th);
+		g.fillRect(x,y+h-th,w,th);
+		g.fillRect(x,y+th,th,h-2*th);
+		g.fillRect(x+w-th,y+th,th,h-2*th);
+	}
+
+	private static abstract class AbstractBorder implements Border.Interface
+	{
+		protected Insets	insets;
+		protected AbstractBorder() {}
+		protected void setInset(int ins) { insets=new Insets(ins,ins,ins,ins); }
+		
+		public boolean isBorderOpaque() { return false; }
+		public Insets getBorderInsets(Component c) { return insets; }
+	}
+	
+	public static class EmptyBorder extends AbstractBorder
+	{
+		public EmptyBorder(int th) { insets=new Insets(th,th,th,th); }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {}
+	}
+
+	public static class SimpleBorder extends AbstractBorder
+	{
+		private Color	color;
+		private int		thickness;
+
+		public SimpleBorder(int th) { this(th,null); }
+		public SimpleBorder(int th, Color col) { color=col; thickness=th; setInset(th); }
+
+		public boolean isBorderOpaque() { return true; }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+		{
+			g.setColor(color==null ? getDefaultColor(c) : color);
+			drawThickRect(g,x,y,w,h,thickness);
+			// alternative is to fill while clipping out interior
+			// or to fill component background after filling border rect
+			// this requires that borders be drawn outside-in
+		}
+
+		protected Color getDefaultColor(Component c) { return c.getForeground(); }
+	}
+
+	public static class ParentBgBorder extends SimpleBorder
+	{
+		public ParentBgBorder(int th) { super(th,null); }
+
+		protected Color getDefaultColor(Component c) { return c.getParent().getBackground(); }
+	}
+
+	public static class RaisedBevelBorder extends AbstractBorder
+	{
+		private Color	color;
+		private Color	bgcolor;
+		private int		binset;
+
+		public RaisedBevelBorder() { this(1,0); }
+		public RaisedBevelBorder(int th) { this(th,0); }
+		public RaisedBevelBorder(int th, int ins) { setInset(th); binset=ins; }
+
+		public void setBackground(Color c) { bgcolor=c; }
+		public void setColor(Color c) { color=c; }
+
+		public boolean isBorderOpaque() { return true; }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) 
+		{
+			// draw background color outside 3d rect
+			if (binset!=0) {
+				g.setColor(bgcolor==null ? c.getParent().getBackground() : bgcolor);
+				drawThickRect(g,x,y,w,h,binset);
+			}
+
+			// draw 3d rect just inside
+			g.setColor(color==null ? c.getBackground() : color);
+			g.draw3DRect(x+binset,y+binset,w-2*binset-1,h-2*binset-1,true);
+			// g.fill3DRect(x+binset,y+binset,w-2*binset,h-2*binset,true);
+		}
+
+	}
+
+	public static class LoweredBevelBorder extends AbstractBorder
+	{
+		private Color	color;
+		private Color	bgcolor;
+		private int		binset;
+
+		public LoweredBevelBorder(int th) { this(th,0); }
+		public LoweredBevelBorder(int th, int ins) { setInset(th); binset=ins; }
+
+		public void setBackground(Color c) { bgcolor=c; }
+		public void setColor(Color c) { color=c; }
+
+		public boolean isBorderOpaque() { return true; }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) 
+		{
+			// draw background color outside 3d rect
+			g.setColor(bgcolor==null ? c.getParent().getBackground() : bgcolor);
+			drawThickRect(g,x,y,w,h,binset);
+
+			// draw 3d rect just inside
+			g.setColor(color==null ? c.getParent().getBackground() : color);
+			g.draw3DRect(x+binset,y+binset,w-2*binset-1,h-2*binset-1,false);
+			// g.fill3DRect(x+binset,y+binset,w-2*binset,h-2*binset,false);
+		}
+	}
+
+	public static class RoundedBorder extends AbstractBorder
+	{
+		private Color	color;
+		private Color	bgcolor;
+		private int		t, r, a;
+
+		public RoundedBorder( int t, int r) { this(t,r,t,null); }
+		public RoundedBorder( int t, int r, int i) { this(t,r,i,null); }
+		public RoundedBorder( int t, int r, int i, Color c) {
+			this.t=t; this.r=r;	this.a=r; color=c; setInset(i);
+		}
+
+		public boolean isBorderOpaque() { return true; }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+		{
+			// draw background color outside 3d rect
+			g.setColor(bgcolor==null ? c.getParent().getBackground() : bgcolor);
+			drawThickRect(g,x,y,w,h,a);
+	
+			if (t==1) {
+				g.setColor(c.getBackground());
+				g.fillRoundRect(x,y,w,h,r,r);
+				g.setColor(color==null ? getDefaultColor(c) : color);
+				g.drawRoundRect(x,y,w-1,h-1,r,r);
+			} else {
+				g.setColor(color==null ? getDefaultColor(c) : color);
+				g.fillRoundRect(x,y,w,h,r,r);
+				g.setColor(c.getBackground());
+				g.fillRoundRect(x+t,y+t,w-2*t,h-2*t,r-2*t, r-2*t);
+			}
+		}
+
+		protected Color getDefaultColor(Component c) { return c.getForeground(); }
+	}
+
+	public static class EllipticalBorder extends AbstractBorder
+	{
+		private Color	color;
+		private Color	bgcolor;
+		private int		t;
+
+		public EllipticalBorder( int t) { this(t,t); }
+		public EllipticalBorder( int t, int ins) { this.t=t; setInset(ins); }
+
+		public boolean isBorderOpaque() { return true; }
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h)
+		{
+			// draw background color outside 3d rect
+			g.setColor(bgcolor==null ? c.getParent().getBackground() : bgcolor);
+			g.fillRect(x,y,w,h);
+	
+			g.setColor(color==null ? getDefaultColor(c) : color);
+			g.fillOval(x,y,w,h);
+			g.setColor(c.getBackground());
+			g.fillOval(t,t,w-2*t,h-2*t);
+		}
+
+		protected Color getDefaultColor(Component c) { return c.getForeground(); }
+	}
+
+	public static class CompoundBorder extends AbstractBorder 
+	{
+		protected Border.Interface out;
+		protected Border.Interface in;
+
+		public CompoundBorder(Border.Interface out, Border.Interface in) 
+		{
+			this.out = out; this.in = in;
+		}	    
+
+		public boolean isBorderOpaque() { 
+			
+			return (out.isBorderOpaque() && in.isBorderOpaque());
+		}
+
+		public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) 
+		{
+			out.paintBorder(c, g, x, y, w, h);		
+
+			Insets  i=out.getBorderInsets(c);
+			x += i.left;
+			y += i.top;
+			w -= (i.right + i.left);
+			h -= (i.bottom + i.top);
+  			in.paintBorder(c, g, x, y, w, h);		
+		}
+     
+		/** 
+		 * Reinitialize the insets parameter with this Border's current Insets. 
+		 * @param c the component for which this border insets value applies
+		 * @param insets the object to be reinitialized
+		 */
+		public Insets getBorderInsets(Component c) 
+		{
+			Insets	ret=new Insets(0,0,0,0);
+
+			Insets  tmp=out.getBorderInsets(c);
+			ret.top += tmp.top;
+			ret.left += tmp.left;
+			ret.bottom += tmp.bottom;
+			ret.right += tmp.right;
+
+			tmp=in.getBorderInsets(c);
+			ret.top += tmp.top;
+			ret.left += tmp.left;
+			ret.bottom += tmp.bottom;
+			ret.right += tmp.right;
+
+			return ret;
+		}
+	}
+
+	public static Border.Interface createBorder() { 
+		return createBorder(Shell.env()); 
+	}
+
+	public static Border.Interface createBorder(Environment env)
+	{
+		Border.Interface border = null;
+
+		Color		col = X.color(env.datum("color"),null);
+		String	p   = X.string(env.datum("type"),"none");
+		int		bw  = X._int(env.datum("width"),0);
+
+		if (p.equals("none")) border = new Borders.EmptyBorder(0);
+		else if (p.equals("raised")) border = new Borders.RaisedBevelBorder(bw);
+		else if (p.equals("sunk"))  border = new Borders.LoweredBevelBorder(bw);
+		else if (p.equals("simple")) border = new Borders.SimpleBorder(bw,col);
+		else if (p.equals("rounded")) {
+			int	   rad = X._int(env.datum("radius"),0);
+			border = new Borders.RoundedBorder(bw,rad,bw,col);
+		}
+
+		// add external padding if necessary
+		int padding = X._int(env.datum("padding"),0);
+		if (padding>0) {
+			border = new Borders.CompoundBorder(
+				border,	new Borders.EmptyBorder(padding)
+			);
+		}
+
+		return border;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/ButtonBar.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,55 @@
+/*
+ *	ButtonBar.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+/**
+	Displays Agent commands as push button in a container.
+  */
+
+public class ButtonBar implements Agent.Registry 
+{
+	public ButtonBar(Container p) { panel=p; }
+	public ButtonBar() {
+		this(new JPanel(Border.create(Border.NONE)));
+		panel.setLayout( new FlowLayout(FlowLayout.LEFT,6,2));
+	}
+
+
+	public Agent.Registry add(String l) 
+	{ 
+		Button b = new Button(l);
+		b.addActionListener(handler);
+		panel.add(b);
+		return this;
+	}
+
+	public Agent.Registry add(String l, boolean state) { return add(l); }
+
+	public Container container() { return panel; }
+	public void setBroadcaster(ActionListener b) { broadcaster=b; }
+	public void setTarget(Agent a) { 
+		if (a!=null) handler=new AgentAdapter(a); 
+		else handler=broadcaster;
+		group();
+	}
+
+	public void group() {}
+
+	private	Container		panel;
+	private ActionListener	handler;
+	private ActionListener	broadcaster;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+/Border.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Borders.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/ButtonBar.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/CommandField.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Dialog.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Frame.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/JPanel.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/MenuBuilder.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Meter.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/NumberViewer.java.not/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/PopupHandler.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/TextualNumberViewer.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VCanvas.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/VPanel.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Console.java/1.2/Mon Oct  9 21:16:17 2006//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/util/heavy
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/CommandField.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,55 @@
+/*
+ *	CommandField.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.io.*;
+
+public class CommandField extends TextField
+{
+	public CommandField(int w) 
+	{ 
+		super(w); 
+
+		setBackground( Shell.getColor("awt.input.console.background", Color.black));
+		setForeground( Shell.getColor("awt.input.console.foreground", Color.orange));
+		try {	setFont(X.font(Shell.datum("awt.input.console.font"),null)); }
+		catch (Exception ex) { /* ok if no font specified */ }
+		addActionListener(h);
+		addKeyListener(h);
+	}
+
+	static Handler h = new Handler();
+	static class Handler extends KeyAdapter implements ActionListener, java.io.Serializable
+	{
+		String last;
+
+		public void actionPerformed(ActionEvent e) {
+			Object o = e.getSource();
+			TextComponent tc = ((TextComponent)o);			
+			last=tc.getText();
+			Shell.print("> "+last);
+			Shell.interpret(new StringReader(last)); 
+			tc.setText("");
+		}
+
+		public void keyPressed(KeyEvent e) {
+			if (e.getKeyCode()==KeyEvent.VK_UP) {
+				Object o = e.getSource();
+				TextComponent tc = ((TextComponent)o);			
+				tc.setText(last);
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Console.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,102 @@
+/*
+ *	Console.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+import  java.io.*;
+
+/**
+		<p>
+		A class which can display messages in a scrolling text
+		area, which can be put in another container or its own frame.
+		There is a static reference to the current Console so
+		that anyone can display messages without worrying about
+		who created the Console.
+
+		<p>
+		Associated with the Console are a Writer and an OutputStream
+		so that any method which writes to a Java IO stream can be
+		redirected to the current console.
+
+ */
+
+public class Console extends TextArea implements Agent
+{
+	private Writer			writer=null;
+	private OutputStream	ostream=null;
+
+	public Console()
+	{
+		super("",16,40, 
+			Shell.getBoolean("awt.output.console.scrollbars", false)
+				? TextArea.SCROLLBARS_VERTICAL_ONLY
+				: TextArea.SCROLLBARS_NONE
+		);
+
+		// setEditable(false);
+		setBackground( Shell.getColor("awt.output.console.background", Color.black));
+		setForeground( Shell.getColor("awt.output.console.foreground", Color.orange));
+		setFont(X.font(Shell.datum("awt.output.console.font"),null)); 
+	}
+
+	public void write( String s) { append(s); }
+	public void getCommands(Agent.Registry r) { r.add("clear").add("setfont"); }
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("clear")) setText("");
+		else if (cmd.equals("setfont")) 
+			setFont(X.font(env.datum("font"),null));
+	}
+
+	public String toString() { return "Console"; }
+
+	public Writer getWriter() {
+		if (writer==null) writer = new Writer();
+		return writer;
+	}
+
+	public OutputStream getStream() {
+		if (ostream==null) ostream = new OutputStream();
+		return ostream;
+	}
+
+	class Writer extends java.io.Writer
+	{
+		StringBuffer	str;
+
+		Writer() { str = new StringBuffer(); }
+
+		public void write( char buf[], int off, int len) {
+			str.append( buf, off, len); // indentation
+		}
+
+		public void flush() { 
+//			append( str.toString()); 
+			try { append( str.toString()); 
+			} catch(IOException ex) { /* eh? */}
+			str.setLength(0); 
+		}
+		public void close() { }
+	}
+	
+	class OutputStream extends java.io.OutputStream
+	{
+		StringBuffer	str;
+
+		OutputStream() { str = new StringBuffer(); }
+
+		public void write( int b) { str.append( (char)b); }		
+		public void flush()	{ append( str.toString()); str.setLength(0); }
+		public void close() { }
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Dialog.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,80 @@
+/*
+ *	Dialog.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+public class Dialog extends java.awt.Dialog implements ActionListener, Shell.Dialog
+{
+	String		result;
+	Container	panel;
+	Panel			buttons;
+
+	public Dialog( java.awt.Frame owner, String nm, boolean modal)
+	{
+		super(owner,nm,modal);
+
+		panel = new JPanel(Border.create(Border.NONE));
+		panel.setLayout(new GridLayout(0,1));
+		buttons=new Panel(); // JPanel(Border.create(Border.NONE));
+		buttons.setLayout( new FlowLayout(FlowLayout.RIGHT,6,2));
+
+		setFont(X.font(Shell.datum("dialog.font"),null));
+		setLayout( new BorderLayout());
+		add( panel, "Center");
+		add( buttons, "South");
+		addWindowListener( new WindowAdapter() {
+			public void windowClosing(WindowEvent e) { 
+				result = "close";
+				setVisible(false); 
+			}
+		} );
+	}
+
+	protected void finalize() { Shell.trace("Dialog finalizing"); }
+
+	public void actionPerformed(ActionEvent e)
+	{
+		result=e.getActionCommand();
+		setVisible(false);
+
+		//String cmd=e.getActionCommand();
+		//if	     (cmd=="ok")     { result=cmd; setVisible(false); }
+		//else if (cmd=="cancel") { result=cmd; setVisible(false); }
+	}
+
+	public Container container() { return panel; }
+	public String result() { return result; }
+	public void expose() { pack(); centre(); setVisible(true); toFront(); }
+
+	public void centre()
+	{
+		Dimension d=getSize();
+		setLocation( (SX-d.width)/2, (SY-d.height)/2);
+	}
+
+	public void addAction(String label)
+	{
+		Button btn=new Button(label);
+		btn.addActionListener(this);
+		buttons.add(btn);
+	}
+
+	private static int SX, SY; // screen width and height
+	static {
+		Dimension s=Toolkit.getDefaultToolkit().getScreenSize();
+		SX=s.width;
+		SY=s.height;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Frame.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,99 @@
+/*
+ *	Frame.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+/** 
+	<p>
+	This is a useful kind of framed window that uses 
+	the property set to get window size and position
+	and colours. It can also send window closing events
+	to the default command handler (see Agency) as
+	"exit" actions.
+
+	<p>
+	Addition: frame can dispose of itself when last component
+	is removed.
+ */
+
+public class Frame extends java.awt.Frame 
+	implements ComponentListener, ActionListener, Shell.Window
+{
+	Node node;
+
+	public Frame() { this("frame"); }
+	public Frame( String nm) { node=new Node(nm); init(); }
+
+	public Container container() { return this; }
+
+	public void	expose() {
+		// this makes sure we don't show a zero-sized window
+		if (getBounds().isEmpty()) pack();
+		setVisible(true);
+	}
+
+	public Node getNode() { return node; }
+
+	// ..... Event Listener bits .......
+
+	public void componentHidden(ComponentEvent e) {}
+	public void componentShown(ComponentEvent e) {}
+	public void componentMoved(ComponentEvent e) { savepos(); }
+	public void componentResized(ComponentEvent e) { savepos(); }
+	public void actionPerformed(ActionEvent e) {
+		if (e.getActionCommand().equals("pack")) pack();
+	}
+	
+
+	// ........... private bits ...............
+
+	private void savepos() { X.store(node.fullNameFor("bounds"),getBounds()); }
+
+	private void init()
+	{
+		Shell.push(node);
+		try {
+			String	tit = Shell.getString("title",null);
+			Color		bg  = Shell.getColor("background",SystemColor.control);
+			Color		fg  = Shell.getColor("foreground",SystemColor.controlText);
+			Rectangle pos = X.rect(Shell.datum("bounds"),null);
+			Font		font = X.font(Shell.datum("font"),null);
+
+			if (tit!=null) setTitle(tit);
+			else {
+					// remove "." from start of name
+				String n=node.fullName();
+				if (n.startsWith(".")) n=n.substring(1);
+				// remove ".window" from end of name
+				if (n.endsWith(".window")) n=n.substring(0,n.length()-7);
+				setTitle(n);
+		}
+
+			if (pos!=null) setBounds(pos);
+			if (font!=null) setFont(font);
+
+			setBackground(bg);
+			setForeground(fg);
+		} finally { Shell.pop(); }
+
+		PopupMenu p=new PopupMenu( "Frame");
+		p.addActionListener(this);
+		p.add("pack");
+		add(p);
+
+		addComponentListener(this);
+		addMouseListener(new PopupHandler(p,true));
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/JPanel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,74 @@
+/*
+ *	JPanel.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  samer.core.util.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+/**
+ *		This is a panel with an optional bevel border,
+ *		and a name label. It can also draw bevels
+ *		round its children
+ */
+
+
+public class JPanel extends Panel
+{
+	private Border.Interface	cborder=null;
+	private Border.Interface	border=null;
+
+	/** Constructors can specify bevel type, inset and name */
+
+	public JPanel() { this(Border.createDefault()); }
+	public JPanel(Border.Interface border)
+	{
+		setLayout(new FlowLayout(FlowLayout.LEFT,0,0));
+		addMouseListener(MouseRetarget.listener);
+		this.border = border;
+	}
+
+	public Insets getInsets() { return border.getBorderInsets(this); }
+
+	public void setBorder( Border.Interface b) { border=b; }
+	public void setChildBorder( Border.Interface b) { cborder=b; }
+
+	public void paint(Graphics g)
+	{
+		super.paint(g);
+
+		if (border!=null) {
+			Dimension d=getSize();
+			border.paintBorder(this,g,0,0,d.width,d.height);
+		}
+
+		if (cborder!=null) {
+			Component []	c=getComponents();
+			Insets	insets=cborder.getBorderInsets(this);
+			int		dx=insets.left, dy=insets.top;
+			int		dw=insets.left+insets.right;
+			int		dh=insets.top+insets.bottom;
+
+			for (int i=c.length-1; i>=0; i--) {
+				Rectangle r=c[i].getBounds();
+				if (!r.isEmpty()) {
+					cborder.paintBorder(
+						c[i], g, 
+						r.x-dx, r.y-dy,
+						r.width+dw, r.height+dh
+					);
+				}
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/MenuBuilder.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+/*
+ *	Tools.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+
+public class MenuBuilder implements Agent.Registry 
+{
+	Menu			menu;
+	AgentAdapter	ad;
+	Font	font=X.font(Shell.datum("menu.font"),null); 
+
+	public MenuBuilder(Menu m, AgentAdapter a) { menu=m; ad=a; }
+
+	public Agent.Registry add(String l) { 
+		MenuItem mi = new MenuItem(l);
+		mi.setFont(font);
+		mi.addActionListener(ad);
+		menu.add(mi);
+		return this;
+	}
+	public Agent.Registry add(String l, boolean state) {
+		CheckboxMenuItem mi = new CheckboxMenuItem(l, state);
+		mi.setFont(font);
+		mi.addItemListener(ad);
+		menu.add(mi);
+		return this;
+	}
+	public void setTarget(Agent a) { ad=new AgentAdapter(a); group(); }
+	public void group() { menu.add("-"); }
+
+	public static Menu showCommands( Agent agent, Component c, Menu menu)	
+	{
+		AgentAdapter	adapter=new AgentAdapter(agent);
+
+		if (menu==null) {
+			PopupMenu p=new PopupMenu(c.getName());
+
+			c.add(p);
+			c.removeMouseListener( MouseRetarget.listener);
+			c.addMouseListener( new PopupHandler(p));
+			c.addMouseListener( MouseRetarget.listener);
+			menu=p;
+		} else {
+			menu.add("-");
+		}
+
+		agent.getCommands( new MenuBuilder(menu,adapter));
+		return menu;
+	}
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/Meter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,70 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.util.*;
+
+public class Meter extends VCanvas
+{
+	IMap	map;
+	int		lasti, nexti;
+	double	x=0;
+
+	public Meter() { map = new LinearMap(0,1); lasti=0; }
+
+	public void exposeMap() { exposeMap(true); }
+	public void exposeMap(boolean reinit) {
+		final VMap	vmap=new VMap(map,reinit);
+		vmap.addObserver( new Observer() {
+			public void update(Observable o, Object args) {
+				if (args==VMap.NEW_MAP) setMap(vmap.getMap());
+				nexti=map.toInt(x); repaint(); 
+			}
+		} );
+		vmap.changed();
+		exposeCommands(vmap);
+	}
+	
+	public void paint(Graphics g)
+	{
+		lasti=nexti=map.toInt(x);
+		g.setColor(getBackground());
+		g.fillRect(lasti,0,width-lasti,height);
+		g.setColor(getForeground());
+		g.fillRect(0,0,lasti,height);
+	}
+
+	public void update(Graphics g)
+	{
+		if (nexti>lasti) {
+			g.setColor(getForeground());
+			g.fillRect(lasti,0,nexti-lasti,height);
+		} else if (nexti<lasti) {
+			g.setColor(getBackground());
+			g.fillRect(nexti,0,lasti-nexti,height);
+		}	
+		lasti=nexti;
+	}
+
+	protected void realized() {}
+	public void next( double x) { 
+		nexti=map.toInt(x); this.x=x;
+		if (nexti!=lasti) repaint(); 
+	}
+
+	public Dimension getPreferredSize() { return new Dimension(96,6); }
+	public Dimension getMinimumSize() { return new Dimension(32,4); }
+
+	public IMap getMap() { return map; }
+	public void setMap(IMap m) { map=m; lasti=0; repaint(); }
+	protected void sized() { map.setIntRange(width); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/NumberViewer.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,101 @@
+/*
+ *	NumberViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+import  samer.tools.VMap;
+
+public class NumberViewer extends VPanel implements
+	FocusListener, AdjustmentListener, ActionListener
+{
+	protected static final VLayout	layout = new VLayout(1,6);
+
+	DoubleModel	dm;
+	TextField	t;
+	Scrollbar	s;
+	VMap			map;
+
+	public detach() { dm=null; super.detach(); }
+
+	protected NumberViewer(Viewer vwr, String label, DoubleModel dm) 
+	{ 
+		super(vwr);
+		setLayout(layout); 
+		setName(label);
+
+		s = new Scrollbar( Scrollbar.HORIZONTAL, 0, 10, 0, map.getIntRange());
+		s.addAdjustmentListener(this);
+
+		t = new TextField(4); 
+		t.addFocusListener(this);
+		t.addActionListener(this);
+
+		add(s,"Center");
+		add(t,"East");
+
+		this.dm=dm;
+	}
+
+	public void set(int num) 
+	{ 
+		t.setText(String.valueOf(num));
+		s.setValue(num);
+	}
+
+	public void set(double num)
+	{
+		t.setText(X.string(num));
+		s.setValue(map.toInt(num));
+	}
+
+	public Dimension getMinimumSize() { return getPreferredSize(); }
+	public Dimension getPreferredSize()
+	{
+		Dimension d=super.getPreferredSize();
+		Dimension dl=l.getPreferredSize();
+		Dimension dt=t.getPreferredSize();
+
+		// Need to make room for scroll bar 
+		d.width = dl.width + dt.width + 96; // ??
+		return d;
+	}
+
+	// ----------- event handling -------------
+
+	private void textChanged() 
+	{
+		double n=X.parseDouble(t.getText());
+		s.setValue(map.toInt(num));
+		if (model!=null) model.set(n);
+	}
+
+	public void adjustmentValueChanged(AdjustmentEvent e) 
+	{
+		getSlider();
+		setText();
+		variable.changed(this);
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) {
+		if (e.getSource()==t) textChanged();
+	}
+
+	public void actionPerformed( ActionEvent e) {
+		if (e.getSource()==t) textChanged(); 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/PopupHandler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,55 @@
+/*
+ *	PopupHandler.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  java.awt.*;
+import  java.awt.event.*;
+
+public class PopupHandler extends MouseAdapter
+{
+	private PopupMenu	popup;
+	private boolean	backstop;
+
+	public PopupHandler(PopupMenu p) { this(p,false); }	
+	public PopupHandler(PopupMenu p, boolean bs) { popup=p; backstop=bs; }	
+
+	public void mousePressed( MouseEvent e)
+	{
+		if (isTrigger(e)) { 
+			popup.show( e.getComponent(), e.getX(), e.getY());
+			e.consume();
+		}
+		// could pass directly on to dispatcher here
+	}
+	public void mouseReleased( MouseEvent e)
+	{
+		if (isTrigger(e)) { 
+			popup.show( e.getComponent(), e.getX(), e.getY());
+			e.consume();
+		}
+		// could pass directly on to dispatcher here
+	}
+
+	boolean isTrigger(MouseEvent e)
+	{
+		if (!e.isPopupTrigger()) return false;		
+
+		// firstly, must have button 2 or 3 down
+		// if ( (f & (InputEvent.BUTTON3_MASK|InputEvent.BUTTON2_MASK))==0 ) return false; 
+
+		// next, if Popup is backstop menu, definitely show it
+		if (backstop) return true; 
+
+		// otherwise, must NOT have Alt or Ctl down
+		if (e.isShiftDown() || e.isControlDown()) return false; 
+		return true;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/TextualNumberViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,47 @@
+package samer.core.util.heavy;
+import samer.core.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public class TextualNumberViewer extends VPanel
+	 implements NumberViewer, FocusListener, ActionListener
+{
+	TextField	rt;
+	NumberSink	model;
+	boolean		real;
+
+	public TextualNumberViewer(String label, int flags, NumberSink model)
+	{
+		setLayout(new BorderLayout()); 
+		setName(label);
+
+		rt = new TextField(Shell.getInt("field.width",4));
+		rt.setBackground(Shell.getColor("field.background",null));
+		rt.setForeground(Shell.getColor("field.foreground",null));
+		add( rt,"East");
+
+		if (model!=null) {
+			this.model=model;
+			rt.addFocusListener(this);
+			rt.addActionListener(this);
+			real = ((flags & INTEGER)==0);
+		}
+	}
+
+	public void set(int num) {
+		rt.setText(String.valueOf(num));
+	}
+	public void set(double num) {
+		rt.setText(X.string(num));
+	}
+
+	private void textChanged() {
+		if (real) model.set(X.parseDouble(rt.getText())); 
+		else model.set(Integer.decode(rt.getText()).intValue());
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) {	textChanged();	}
+	public void actionPerformed( ActionEvent e) { textChanged(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/VCanvas.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,130 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.*;
+import  samer.core.util.Tools;
+import  samer.core.util.MouseRetarget;
+import  samer.core.util.swing.MenuBuilder;
+import  samer.core.util.swing.DynamicPopupHandler;
+import  java.awt.*;
+import  java.awt.event.*;
+
+/**
+		<p>
+		This is a Canvas which maintains a valid Graphics
+		object. The Graphics associated with the Canvas
+		becomes available only at a certain time (not
+		during construction) so we have to setup the
+		Graphics in response to some event. It seems that the 
+		only event a component reliably gets after being
+		realized is a size event. We use the first size
+		event to get a Graphics and notify any derived
+		classes through the <code>realized()</code>
+		method which is there to be overridden.
+	
+ */
+
+public class VCanvas extends Canvas implements Viewer
+{
+	public Graphics graphics=null;
+	public int		 width, height;
+
+	/**	<b><code>void realized()</code></b>
+	  *	This is called when the cached Graphics object
+	  *	(see GCanvas) is created. The component is probably still
+	  *	invisible at this point, but we can get off-screen
+	  *	Images and do other useful setting up things that
+	  *	don't seem to work in the constructor
+	  *
+	  */
+	protected void realized() {}
+	protected void sized() {}
+
+	public void clear() { clear(graphics); }
+	public void clear(Graphics g) {
+		g.setColor(getBackground());
+		g.fillRect(0,0,width,height);
+	}
+
+	private void cacheGraphics()
+	{
+		if (graphics!=null) graphics.dispose();
+		graphics=Tools.initGraphics(getGraphics());
+	}
+	
+	public void removeNotify()
+	{
+		detach();
+		// graphics=null; // this might cause a problem! synchronization?
+		super.removeNotify();
+	}
+
+	public void addNotify()
+	{
+		super.addNotify();
+		Dimension d = getSize();
+		width=d.width; height=d.height;
+		cacheGraphics();
+		attach(); realized(); // ??
+	}
+
+	public Dimension getMinimumSize() {
+		return new Dimension(0,0);
+	}
+
+	{	// initialisation code
+		addMouseListener(MouseRetarget.listener);
+		addComponentListener( new ComponentAdapter() {
+			public void componentResized(ComponentEvent e) {
+				Dimension d = getSize();
+				width=d.width; height=d.height;
+				cacheGraphics();
+				sized();
+			}
+		} );
+
+		setBackground(Shell.getColor("background",null));
+		setForeground(Shell.getColor("foreground",null));
+	}
+
+	/* this is v cunning (actually - not really) */
+	public Image createPixel() { return createPixel(1,1); }
+	public Image createPixel(Color c) { return createPixel(c,1,1); }
+	public Image createPixel(int w, int h) { return createPixel(getForeground(),w,h); }
+	public Image createPixel(Color c, int w, int h)
+	{
+		Image img=createImage(w,h);
+		Graphics g=img.getGraphics();
+		g.setColor(c);
+		g.fillRect(0,0,w,w);
+		g.dispose();
+		return img;
+	}
+
+	// ....... MenuAnchor bits .......................
+
+	private DynamicPopupHandler thing=null;
+	// private JPopupMenu thing=null;
+
+	public Component	getComponent() { return this; }
+	public void			attach() {}
+	public void			detach() {}
+	public void	exposeCommands(Agent agent) {
+		// menu=MenuBuilder.showCommands(agent,getComponent(),menu);
+		thing=MenuBuilder.showCommands(agent,getComponent(),thing);
+	}
+
+	protected void finalize() {
+		if (graphics!=null) graphics.dispose();
+	}
+
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/heavy/VPanel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,51 @@
+/*
+ *	VPanel.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.heavy;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+
+public class VPanel extends JPanel implements Viewer
+{
+	private Menu		menu=null;
+	private Viewer		vwr;
+	private Label		label;
+
+	public VPanel() { this(null); }
+	public VPanel(Viewer vwr) { super(); this.vwr=vwr; }
+
+	public void setName(String txt) {
+		if (txt==null) { if (label!=null) remove(label); return; }
+		super.setName(txt);
+		if (label!=null) label.setText(txt);
+		else {
+			label=new Label(txt);
+			label.addMouseListener(MouseRetarget.listener); 
+			add(label,0);
+		}
+	}
+
+	public Component getComponent() { return this; }
+	public void	attach() {}
+	public void	detach() {}
+	public void	exposeCommands(Agent agent) { 
+		menu=MenuBuilder.showCommands(agent,this,menu); 
+	}
+
+	public void addNotify() { super.addNotify(); if (vwr!=null) vwr.attach(); }
+	public void removeNotify() { if (vwr!=null) vwr.detach(); super.removeNotify(); }
+
+//	public void add(Component c) { super.add(c); }
+	public void add(Viewer v) { add(v.getComponent()); }
+	public void add(Viewable v) { add(v.getViewer()); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/AgentManager.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,92 @@
+/*
+ *	AgentManager.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.shell;
+import  samer.core.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+public class AgentManager implements Agent, ActionListener
+{
+	private Vector  agents=new Vector();
+	//private boolean exitOnReturn=false;
+
+	public AgentManager() { Shell.put("AgentManager",this); }
+
+	public ActionListener getBroadcaster() { return this; }
+
+	public void actionPerformed(ActionEvent e) {
+		dispatch(e.getActionCommand(),Shell.env());
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("help").add("agents"); }
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("agents")) {
+			Shell.print("registered agents:");
+			Enumeration i=agents.elements();
+			while(i.hasMoreElements()) {
+				Shell.print(i.nextElement().toString());
+			}
+		} else if (cmd.equals("help")) help();
+	}
+
+	//public void exitOnReturn() { Shell.trace("*** exit on return"); exitOnReturn=true; }
+
+	public void registerAgent(Agent a) {
+		Shell.trace("registering agent: "+a);
+		agents.addElement(a);
+	}
+
+	public void deregisterAgent(Agent a) {
+		Shell.trace("deregistering agent: "+a);
+		agents.removeElement(a);
+	}
+
+	public void dispatch(String cmd, Environment env)
+	{
+		Enumeration i=agents.elements();
+		while(i.hasMoreElements()) {
+			Agent agent=(Agent)i.nextElement();
+			try { agent.execute(cmd,env); }
+			catch (Exception ex) {
+				Shell.print("*** agent error in "+agent);
+				Shell.print("*** exception: "+ex);
+				ex.printStackTrace();
+			}
+		}
+		//if (exitOnReturn) System.exit(0);
+	}
+
+	public void help()
+	{
+		Shell.print("____________________________________");
+		Shell.print("Registered Agents and their commands");
+
+		Enumeration i=agents.elements();
+		Agent.Registry printer = new Agent.Registry() {
+			public void setTarget(Agent a) {}
+			public Registry add( String name) { Shell.print("\t"+name); return this; }
+			public Registry add( String name, boolean initialValue) {
+				Shell.print("\t"+name+" (boolean)"); return this;
+			}
+			public void group() { Shell.print("............"); }
+		};
+
+		while(i.hasMoreElements()) {
+			Agent a=(Agent)(i.nextElement());
+			Shell.print("");
+			Shell.print("---- "+a.getClass().getName());
+			a.getCommands(printer);
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/AppShellBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,145 @@
+/*
+ *	AppShell.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.shell;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.io.*;
+
+public abstract class AppShellBase extends Properties
+	implements Shell.Interface, Agent
+{
+	protected AgentManager		am;
+	protected ViewableManager	vm;
+	private   boolean registerAgents;
+	private   boolean registerViewables;
+
+	private static Environment baseEnvironment(String fname)
+	{
+		try {
+			Shell.trace("loading user properties from " +fname);
+			FileInputStream in=new FileInputStream(fname);
+
+			try {
+				Properties uprops=new Properties(Shell.env());
+				uprops.load(in);
+				uprops.setWritable(false);
+				Shell.push(uprops);
+				Shell.trace("user properties successfully loaded");
+			} finally { in.close(); }
+		} catch (Exception ex) {
+			Shell.trace("failed to load user properties: "+ex);
+		}
+		return Shell.env();
+	}
+
+	protected static String getDefaultPropertiesFile() {
+		return System.getProperty("user.home") + File.separator + "user.props";
+	}
+
+	protected AppShellBase() { this(getDefaultPropertiesFile());	}
+	protected AppShellBase(String userPropsFile)
+	{
+		super(baseEnvironment(userPropsFile));
+
+		try { execute("load",Shell.env()); }
+		catch (Exception ex) { Shell.trace("failed to load local properties"); }
+
+		Shell.push(this);
+//		Shell.push(new FilteredEnvironment(new Properties(this), "bounds"));
+		Shell.push(new HashMap(Shell.env()));
+
+		am = new AgentManager();		registerAgent(am);
+		vm = new ViewableManager();
+
+		registerAgents=true;
+		registerViewables=true;
+	}
+
+	public void enableAgentRegistry(boolean f) { registerAgents=f; }
+	public void enableViewableRegistry(boolean f) { registerViewables=f; }
+
+	public void getCommands(Agent.Registry r) {
+		// r.add("set").add("get")
+		r.add("load").add("save")
+		 .add("expose").add("exit");
+	}
+
+	public void exit() { am.dispatch("exit",Shell.env()); }
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("exit")) {
+			try { execute("save",this); }
+			catch (Exception ex) { Shell.trace(ex.toString()); }
+
+			// not any more. Just exit and be done.
+			// am.exitOnReturn(); // must let other agents respond before System.exit
+			System.exit(0);
+			
+		} else if (cmd.equals("expose")) {
+			if (!vm.hasViewerContainer()) {
+				vm.exposeViewables(getViewerContainer());
+			}
+
+		} else if (cmd.equals("get")) { // get property
+			String nm = X.string(env.datum());
+			Shell.print("name: "+nm);
+			try {
+				Object val=X.object(datum(nm));
+				Shell.print("value: "+val);
+				env.add(val);
+			} catch (Exception ex) { Shell.print("value: ** not bound **"); }
+
+		} else if (cmd.equals("set")) {
+			X.store(X.string(env.datum()),X.object(env.datum()));
+
+		} else if (cmd.equals("load")) {
+			String fname=X.string(env.datum("local.props"),"args");
+			Shell.trace("loading properties from "+fname);
+			InputStream in=new FileInputStream(fname);
+			try { props.load(in); }
+			finally { in.close(); }
+
+		} else if (cmd.equals("save")) {
+			String fname=X.string(env.datum("local.props"),"args");
+			Shell.trace("saving properties to "+fname);
+
+			try {
+				File file=new File(fname);
+				File old=new File(fname+".old");
+				try { old.delete(); }
+				catch (Exception ex) {}
+				file.renameTo(old);
+			} catch (Exception ex) {
+				Shell.trace(ex.toString());
+			}
+
+			OutputStream out=new FileOutputStream(fname);
+			try { props.store(out,"properties"); }
+			finally { out.close(); }
+		}
+	}
+
+	protected void put(Class a, Class b) { samer.core.Registry.put(a,b); }
+
+	public void trace(String msg) { System.err.println(msg); }
+//	public void trace(String string) {
+//		System.err.println(" "+(System.currentTimeMillis() % 8192L)+": "+string);
+//	}
+	public void registerAgent(Agent a) { if (registerAgents) am.registerAgent(a); }
+	public void deregisterAgent(Agent a) { am.deregisterAgent(a); }
+	public void deregisterViewable(Viewable v) { vm.deregisterViewable(v); }
+	public void registerViewable(Viewable v) { if (registerViewables) vm.registerViewable(v); }
+
+	protected abstract ViewableManager.ViewerContainer getViewerContainer();
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,4 @@
+/AgentManager.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/AppShellBase.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/ViewableManager.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/util/shell
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/shell/ViewableManager.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,203 @@
+/*
+ *	AppShell.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.shell;
+import  samer.core.util.*;
+import  samer.core.types.*;
+import  samer.core.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+
+public class ViewableManager
+{
+	private		Vector	viewables = new Vector();
+	protected	Vector	exposedViewers = new Vector();
+
+	public ViewableManager() {
+		Shell.put("ViewableManager", this);
+	}
+	protected static class VblEntry
+	{
+		public Viewable viewable;
+		public boolean	exposed=false;
+
+		public VblEntry(Viewable v) { viewable=v; }
+	}
+
+	protected static class VwrEntry
+	{
+		public Viewer	viewer;
+		public VblEntry	entry;
+		public VwrEntry(VblEntry ve, Viewer vwr) { entry=ve; viewer=vwr; }
+	}
+
+	public void listViewables() {
+		Shell.print("registered viewables:");
+		Iterator i=viewables.iterator();
+		while(i.hasNext()) {
+			Shell.print(((VblEntry)(i.next())).viewable.getNode().fullName()	);
+		}
+	}
+
+	public void registerViewable(Viewable v)
+	{
+		if (findEntry(v)==null)	{
+			// not already in list, so add
+			VblEntry vbl=new VblEntry(v);
+			viewables.addElement(vbl);
+
+			// if viewables currently exposed, then expose this one
+			if (vc!=null) {
+				final Viewer vwr=v.getViewer();
+				if (vwr!=null) {
+					// add via singleton enumeration
+					vc.add( new Iterator() {
+						boolean more=true;
+						public boolean hasNext() { return more; }
+						public Object next() { more=false; return vwr.getComponent(); }
+						public void remove() {}
+					} );
+				}
+			}
+		}
+	}
+
+	public void deregisterViewable(Viewable v)
+	{
+		VblEntry ve=findEntry(v);
+		if (ve!=null) viewables.removeElement(ve);
+		// ought to remove from vc but can't be bothered
+	}
+
+	public Viewable getViewable(String name)
+	{
+		Iterator i=viewables.iterator();
+		Viewable		best=null;
+		int			score=0;
+
+		while (i.hasNext()) {
+			VblEntry ve=(VblEntry)i.next();
+			String fullname=ve.viewable.getNode().fullName();
+			if (name.endsWith(fullname)) {
+				int ss=fullname.length();
+				if (ss>score) {
+					best=ve.viewable;
+					score=ss;
+				}
+			}
+		}
+		return best;
+	}
+
+	private VblEntry findEntry(Viewable v)
+	{
+		Iterator i=viewables.iterator();
+		while (i.hasNext()) {
+			VblEntry ve=(VblEntry)i.next();
+			if (ve.viewable==v) return ve;
+		}
+		return null;
+	}
+
+
+	public interface ViewerContainer {
+		// add(Viewer viewer);
+		void add(Iterator components);
+		void removeAll(); // redundant?
+	}
+
+	private ViewerContainer vc=null;
+
+	public Iterator getViewables() {
+		return new Iterator() {
+			Iterator vbls=viewables.iterator();
+			VblEntry	vbl;
+
+			public boolean hasNext() { return vbls.hasNext(); }
+			public Object next() 	{ return ((VblEntry)vbls.next()).viewable; }
+			public void remove() {}
+		};
+	}
+
+	/**
+		Register the supplied ViewerContainer and fill with
+		all currently registered exposable Viewables.
+		Any subsequently registered Viewables will be exposed
+		in this ViewerContainer.
+	  */
+
+	public void exposeViewables(ViewerContainer c)
+	{
+		Iterator viewers = new Iterator() {
+			Iterator vbls=viewables.iterator();
+			VblEntry	vbl;
+			Viewer		nextvwr;
+
+			{ prepareNext(); }
+
+			public void remove() {}
+			public boolean hasNext() { return nextvwr!=null; }
+			public Object next()
+			{
+				Component ret=nextvwr.getComponent();
+				exposedViewers.addElement(new VwrEntry(vbl,nextvwr));
+				vbl.exposed=true;
+				prepareNext();
+
+				return ret;
+			}
+
+			private void prepareNext()
+			{
+				while (vbls.hasNext()) {
+					vbl=(VblEntry)vbls.next();
+					if (!vbl.exposed) {
+						nextvwr=vbl.viewable.getViewer();
+						if (nextvwr!=null) return;
+					}
+				}
+				nextvwr=null;
+			}
+		};
+		c.add(viewers);
+		vc=c;
+	}
+
+	/**
+		Empties and deregisters the currently registered ViewerContainer.
+		All Viewers are detached, and removed, so they should be up
+		for garbage collection after this. The ViewableManager also
+		forgets about the ViewerContainer so that it can be disposed
+		of and subsequently registered Viewable will not be shown.
+	  */
+
+	public void releaseViewerContainer()
+	{
+		if (vc==null) return;
+
+		Shell.trace("releasing viewer container");
+		Iterator i=exposedViewers.iterator();
+		while (i.hasNext()) {
+			VwrEntry entry = (VwrEntry)i.next();
+			entry.viewer.detach();
+			entry.entry.exposed=false;
+		}
+		vc.removeAll();
+		vc=null;
+
+		return;
+	}
+
+	public boolean hasViewerContainer() { return vc!=null; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/ButtonBar.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,82 @@
+/*
+ *	ButtonBar.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.event.*;
+import  javax.swing.*;
+import  javax.swing.border.*;
+
+/**
+	Displays Agent commands as buttons in a JToolBar.
+  */
+
+public class ButtonBar extends JToolBar implements Agent.Registry
+{
+	private static java.awt.Insets ins = new java.awt.Insets(2,6,2,6);
+
+	private ActionListener handler=null;
+	private ActionListener broadcaster=null;
+	private ItemListener	  itemHandler=null;
+
+	public ButtonBar() {}
+
+	/** Set the target agent for subsequent buttons added via add() method.
+		If null, then subsequently added buttons will broadcast their command
+		using the ActionListener registered via setBroadcaster.
+	*/
+	public void setTarget(Agent a) {
+		if (a!=null) {
+			AgentAdapter adapter=new AgentAdapter(a);
+			itemHandler=adapter;
+			handler=adapter;
+		} else {
+			itemHandler=null;
+			handler=broadcaster;
+		}
+	}
+
+	/** Set the ActionListener to be used when no specific target agent
+		is specified for a button. */
+	public void setBroadcaster(ActionListener b) { broadcaster=b; }
+
+	/** Add a new button with the given text.  */
+	public Agent.Registry add(String l)
+	{
+		JButton b = new JButton(l);
+		// could try to get an icon and some tool tips here
+		b.setMargin(ins);
+		b.addActionListener(handler);
+		add(b);
+		return this;
+	}
+
+	/** Add a boolean state button */
+	public Agent.Registry add(String l, boolean state)
+	{
+		JToggleButton b = new JToggleButton(l);
+		b.setName(l);
+		b.setMargin(ins);
+
+		if (itemHandler!=null)
+			b.addItemListener(itemHandler);
+		else
+			b.addActionListener(handler);
+
+		add(b);
+		return this;
+	}
+
+	/** Make logical gap between previous buttons and ones to follow */
+	public void group() {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+/ButtonBar.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/CommandField.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/DarkMetalTheme.java/1.1.1.1/Fri Dec 10 03:29:26 2004//
+/Dialog.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/DynamicPopupHandler.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Frame.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/InternalFrame.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LED.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MenuBuilder.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Meter.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/PopupHandler.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/SilkyMetalTheme.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/TextualNumberViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/VPanel.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Console.java/1.2/Mon Oct  9 21:16:17 2006//
+/VCanvas.java/1.1.1.1/Mon Aug 15 18:36:19 2005//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/util/swing
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/CommandField.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	CommandField.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.io.*;
+import  javax.swing.*;
+
+public class CommandField extends JTextField
+{
+	public CommandField(int w) 
+	{ 
+		super(w); 
+
+		setBackground( X.color(Shell.datum("swing.input.console.background"), Color.white));
+		setForeground( X.color(Shell.datum("swing.input.console.foreground"), Color.black));
+		Font font=X.font(Shell.datum("swing.input.console.font"),null);
+		if (font!=null) setFont(font);
+		addActionListener(h);
+		addKeyListener(h);
+	}
+
+	static Handler h = new Handler();
+	static class Handler extends KeyAdapter implements ActionListener, java.io.Serializable
+	{
+		String last;
+
+		public void actionPerformed(ActionEvent e) {
+			Object o = e.getSource();
+			JTextField tc = ((JTextField)o);			
+			last=tc.getText();
+			Shell.print("> "+last);
+			Shell.interpret(new StringReader(last)); 
+			tc.setText("");
+		}
+
+		public void keyPressed(KeyEvent e) {
+			if (e.getKeyCode()==KeyEvent.VK_UP) {
+				Object o = e.getSource();
+				JTextField tc = ((JTextField)o);			
+				tc.setText(last);
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/Console.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,105 @@
+/*
+ *	Console.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  java.awt.*;
+import  java.io.*;
+import	javax.swing.*;
+
+/**
+		<p>
+		A class which can display messages in a scrolling text
+		area, which can be put in another container or its own frame.
+		There is a static reference to the current Console so
+		that anyone can display messages without worrying about
+		who created the Console.
+
+		<p>
+		Associated with the Console are a Writer and an OutputStream
+		so that any method which writes to a Java IO stream can be
+		redirected to the current console.
+
+ */
+
+public class Console extends JTextArea implements Agent
+{
+	private Writer			writer=null;
+	private OutputStream	ostream=null;
+
+	public Console() { this(true); }
+	public Console(boolean setAsDefault)
+	{
+		super("",16,40);
+
+		// setBackground( X.color(Shell.datum("swing.output.console.background"), getBackground()));
+		// setForeground( X.color(Shell.datum("swing.output.console.foreground"), getForeground()));
+		Font fnt=X.font(Shell.datum("swing.output.console.font"),null);
+		if (fnt!=null) setFont(fnt);
+
+		setEditable(false);
+		setLineWrap(true);
+
+		writer  = new Writer();
+		ostream = new OutputStream();
+	}
+
+	public String toString() { return "samer.core.util.swing.Console"; }
+	public void write( String s) { append(s); }
+	public void getCommands(Agent.Registry r) { r.add("clear").add("setfont"); }
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("clear")) setText("");
+		else if (cmd.equals("setfont")) 
+			setFont(X.font(env.datum("font"),null));
+	}
+
+	public Writer getWriter() {
+		if (writer==null) writer = new Writer();
+		return writer;
+	}
+
+	public OutputStream getStream() {
+		if (ostream==null) ostream = new OutputStream();
+		return ostream;
+	}
+
+	class Writer extends java.io.Writer
+	{
+		StringBuffer	str;
+
+		Writer() { str = new StringBuffer(); }
+
+		public void write( char buf[], int off, int len) {
+			str.append( buf, off, len); // indentation
+		}
+
+		public void flush() { 
+//			append( str.toString()); 
+			try { append( str.toString()); }
+			catch(IOException ex) { /* eh? */}
+			str.setLength(0); 
+		}
+		public void close() { }
+	}
+	
+	class OutputStream extends java.io.OutputStream
+	{
+		StringBuffer	str;
+
+		OutputStream() { str = new StringBuffer(); }
+
+		public void write( int b) { str.append( (char)b); }		
+		public void flush()	{ append( str.toString()); str.setLength(0); }
+		public void close() { }
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/DarkMetalTheme.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,103 @@
+package samer.core.util.swing;
+
+import javax.swing.plaf.*;
+import javax.swing.*;
+import java.awt.*;
+
+public class DarkMetalTheme extends javax.swing.plaf.metal.MetalTheme {
+
+	private ColorUIResource primary1;
+	private ColorUIResource primary2;
+	private ColorUIResource primary3;
+	private ColorUIResource red, blue, yellow, green, highlight;
+
+	private ColorUIResource secondary1;
+	private ColorUIResource secondary2;
+	private ColorUIResource secondary3;
+	private ColorUIResource white;
+
+	private FontUIResource plainFont;
+	private FontUIResource smallFont;
+	private FontUIResource boldFont;
+
+	public String getName() { return "Silk"; }
+
+	public DarkMetalTheme(Font font, Color bg, double hue, double sat)
+	{
+		System.err.println("Metal theme: base font is "+font);
+
+		plainFont = new FontUIResource(font);
+		smallFont = new FontUIResource(font.deriveFont(0.8f*font.getSize2D()));
+		boldFont = new FontUIResource(font.deriveFont(Font.BOLD));
+
+		primary3 = new ColorUIResource(Color.getHSBColor((float)hue,(float)sat,.5f));
+		primary2 =new ColorUIResource(Color.getHSBColor((float)hue,(float)sat,.3f));
+		primary1 =new ColorUIResource(Color.getHSBColor((float)hue,(float)sat,.1f));
+
+		secondary3 = new ColorUIResource(bg);
+		secondary2 = new ColorUIResource(bg.darker());
+		secondary1 = new ColorUIResource(bg.darker().darker());
+		highlight = new ColorUIResource(bg.brighter());
+
+
+		white=new ColorUIResource(Color.white.darker());
+		red=new ColorUIResource(Color.red);
+		blue=new ColorUIResource(Color.blue);
+		green=new ColorUIResource(Color.green);
+		yellow=new ColorUIResource(Color.yellow);
+	}
+
+	public void addCustomEntriesToTable(UIDefaults table)
+	{
+		table.put( "Button.font", boldFont);
+		table.put( "Label.foreground", getWhite());
+		table.put( "TextField.background", secondary2);
+		table.put( "TextField.foreground", getWhite());
+		table.put( "TitledBorder.font", boldFont);
+		table.put( "List.background", getBlack());
+		table.put( "List.foreground", getWhite());
+		table.put( "List.font", plainFont);
+  	}
+
+	public ColorUIResource getWhite() { return white; }
+	public ColorUIResource getPrimary1() { return primary1; }
+	public ColorUIResource getPrimary2() { return primary2; }
+	public ColorUIResource getPrimary3() { return primary3; }
+
+	public ColorUIResource getSecondary1() { return secondary1; }
+	public ColorUIResource getSecondary2() { return secondary2; }
+	public ColorUIResource getSecondary3() { return secondary3; }
+
+	public FontUIResource getControlTextFont() { return plainFont;}
+	public FontUIResource getSystemTextFont() { return plainFont;}
+	public FontUIResource getUserTextFont() { return plainFont;}
+	public FontUIResource getMenuTextFont() { return plainFont;}
+	public FontUIResource getWindowTitleFont() { return boldFont;}
+	public FontUIResource getSubTextFont() { return smallFont;}
+
+	public ColorUIResource getMenuForeground() { return getWhite(); }
+	public ColorUIResource getMenuSelectedForeground() { return getWhite(); }
+
+	// these are for tweaking
+
+	public ColorUIResource getDesktopColor() { return getPrimary1(); }
+
+	public ColorUIResource getControl() { return getSecondary3(); }
+	public ColorUIResource getControlShadow() { return getSecondary2(); }
+	public ColorUIResource getControlDarkShadow() { return getSecondary1(); }
+	public ColorUIResource getControlInfo() { return getWhite(); }
+	public ColorUIResource getControlHighlight() { return highlight; } // getWhite(); }
+//	public ColorUIResource getControlDisabled() { return getSecondary2(); }
+
+//	public ColorUIResource getPrimaryControl() { return getPrimary3(); }
+//	public ColorUIResource getPrimaryControlShadow() { return getPrimary2(); }
+//	public ColorUIResource getPrimaryControlDarkShadow() { return getPrimary1(); }
+	public ColorUIResource getPrimaryControlInfo() { return primary2; } // getWhite(); }
+	public ColorUIResource getPrimaryControlHighlight() { return primary3; } // getWhite(); }
+
+	public ColorUIResource getSystemTextColor() { return getWhite(); }
+//	public ColorUIResource getInactiveSystemTextColor() { return getSecondary2(); }
+
+	public ColorUIResource getSeparatorBackground() { return highlight; } // getWhite(); }
+	public ColorUIResource getSeparatorForeground() { return getSecondary2(); } // getPrimary1(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/Dialog.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *	Dialog.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  javax.swing.*;
+
+public class Dialog extends JDialog implements ActionListener, Shell.Dialog
+{
+	String	result;
+	Box	buttons;
+
+	public Dialog( java.awt.Frame owner, String nm, boolean modal)
+	{
+		super(owner,nm,modal);
+		buttons=new Box(BoxLayout.X_AXIS);
+		buttons.add( Box.createHorizontalGlue());
+		container().setLayout( new BorderLayout());
+		container().add( buttons, "South");
+		setDefaultCloseOperation(HIDE_ON_CLOSE);
+	}
+
+	public Dialog(String nm, boolean modal)
+	{
+		setModal(modal);
+		setTitle(nm);
+
+		buttons=new Box(BoxLayout.X_AXIS);
+		buttons.add( Box.createHorizontalGlue());
+		container().setLayout( new BorderLayout());
+		container().add( buttons, "South");
+		setDefaultCloseOperation(HIDE_ON_CLOSE);
+	}
+
+	protected void finalize() { Shell.trace("SDialog finalizing"); }
+
+	public void actionPerformed(ActionEvent e)
+	{
+		result=e.getActionCommand();
+		Shell.trace("closing dialog: "+result);
+		setVisible(false);
+	}
+
+	public void centre() { setLocationRelativeTo(null); }
+
+	public Container container() { return getContentPane(); }
+	public String	result() { return result; }
+	public void expose() { result="close"; pack(); centre(); setVisible(true); }
+
+	public void addAction(String label)
+	{
+		JButton btn=new JButton(label);
+		btn.addActionListener(this);
+		buttons.add(btn);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/DynamicPopupHandler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *	DynamicPopupHandler.java	
+ *
+ *	Copyright (c) 2003, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  samer.core.util.*;
+import  java.awt.event.*;
+import  javax.swing.*;
+
+/** This is a mouse click handler that builds a popup menu on
+	the fly from a list of Agents (actually, just one, possibly
+	compound agent.) The Agent can be changed so that
+	new menu items can be added.
+*/
+
+public class DynamicPopupHandler extends MouseAdapter
+{
+	private String			name;
+	private boolean			backstop;
+	private AgentAdapter	adapter=null;
+
+	public DynamicPopupHandler(String nm) { name=nm; }
+		
+	public void addAgent(Agent agent) {
+		adapter=new AgentAdapter( adapter==null ? agent
+			: new CompoundAgent(adapter.getAgent(),agent));
+	}
+	
+	public void setBackstop(boolean f) { backstop=f; }
+	public void mousePressed( MouseEvent e) { maybeShowMenu(e); }
+	public void mouseReleased( MouseEvent e) { maybeShowMenu(e); }
+
+	void maybeShowMenu(MouseEvent e)
+	{
+		if (!e.isPopupTrigger()) return;		
+		if (!backstop) {
+			// if not backstop, must NOT have Alt or Ctl down
+			// modified for Macs: need modifiers to get right mouse click!
+			if (e.isShiftDown()) return; 
+		}
+		JPopupMenu popup=new JPopupMenu(name);
+		adapter.getAgent().getCommands(new MenuBuilder(popup,adapter));
+		popup.show( e.getComponent(), e.getX(), e.getY());
+		e.consume();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/Frame.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,122 @@
+/*
+ *	Frame.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  javax.swing.*;
+
+/** 
+	<p>
+	This is a useful kind of framed window that uses 
+	the property set to get window size and position
+	and colours. It can also send window closing events
+	to the default command handler (see Agency) as
+	"exit" actions.
+
+	<p>
+	Addition: frame can dispose of itself when last component
+	is removed.
+ */
+
+public class Frame extends JFrame 
+	implements ComponentListener, ActionListener, Shell.Window
+{
+	Node node;
+
+	public Frame() { this("frame"); }
+	public Frame( String nm) {
+		// remove "." from start of name
+		if (nm.startsWith(".")) nm=nm.substring(1);
+		node=new Node(nm); init();
+	}
+
+	public Container container() { return getContentPane(); }
+	public void dispose() { super.dispose(); }
+
+	public void	expose() {
+		// this makes sure we don't show a zero-sized window
+		if (getBounds().isEmpty()) pack();
+		setVisible(true);
+	}
+
+	public Node getNode() { return node; }
+
+	// ..... Event Listener bits .......
+
+	public void componentHidden(ComponentEvent e) {}
+	public void componentShown(ComponentEvent e) {}
+	public void componentMoved(ComponentEvent e) { savepos(); }
+	public void componentResized(ComponentEvent e) { savepos(); }
+	public void actionPerformed(ActionEvent e) {
+		if (e.getActionCommand().equals("pack")) pack();
+	}
+
+	// override pack to stop window being bigger than screen
+	public void pack() {
+		super.pack();
+		
+		Dimension d=getToolkit().getScreenSize();
+		Rectangle b=getBounds();
+		boolean	f=false;
+		if (b.y+b.height>d.height) {
+			b.height=d.height-b.y;
+			b.width+=16; // this is to make room for vertical scroll bar (hack - sorry)
+			f=true;
+		}
+		if (b.x+b.width>d.width) { b.width=d.width-b.x; f=true; }
+		if (f) setBounds(b);
+	}	
+
+	// ........... private bits ...............
+
+	private void savepos() { X.store(node.fullNameFor("bounds"),getBounds()); }
+
+	private void init()
+	{
+		Shell.push(node);
+		try {
+			String	tit = Shell.getString("title",null);
+			Color		bg  = Shell.getColor("background",SystemColor.control);
+			Color		fg  = Shell.getColor("foreground",SystemColor.controlText);
+			Rectangle pos = X.rect(Shell.datum("bounds"),null);
+			// Font		font = X.font(Shell.datum("font"),null);
+
+			if (tit!=null) setTitle(tit);
+			else {
+				// remove "." from start of name
+				String n=node.fullName();
+				if (n.startsWith(".")) n=n.substring(1);
+				// remove ".window" from end of name
+				if (n.endsWith(".window")) n=n.substring(0,n.length()-7);
+				setTitle(n);
+			}
+
+			if (pos!=null) setBounds(pos);
+			// if (font!=null) setFont(font);
+
+			// setBackground(bg);
+			// setForeground(fg);
+		} finally { Shell.pop(); }
+
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+		JPopupMenu p=new JPopupMenu( "Frame");
+		p.add("pack").addActionListener(this);
+
+		addComponentListener(this);
+		MenuBuilder.addPopup(p,getContentPane()).setBackstop(true);
+	}
+
+	
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/InternalFrame.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,113 @@
+/*
+ *	Frame.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.*;
+import  javax.swing.*;
+import  javax.swing.event.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.io.*;
+
+/** 
+	<p>
+	This is a useful kind of framed window that uses 
+	the property set to get window size and position
+	and colours. It can also send window closing events
+	to the default command handler (see Agency) as
+	"exit" actions.
+
+	<p>
+	Addition: frame can dispose of itself when last component
+	is removed.
+ */
+
+public class InternalFrame extends JInternalFrame 
+	implements ComponentListener, ActionListener, Shell.Window
+{
+	Node node;
+
+	public InternalFrame( String nm) { 
+		super(nm,true,false,true,true);
+		setClosable(true);
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+		desktop.add(this);
+		node=new Node(nm); 
+		init(); 
+	}
+
+	public Container container() { return getContentPane(); }
+	public void dispose() { super.dispose(); }
+
+	public void	expose() {
+		// this makes sure we don't show a zero-sized window
+		if (getBounds().isEmpty()) pack();
+		setVisible(true);
+	}
+
+	public Node getNode() { return node; }
+
+	// ..... Event Listener bits .......
+
+	public void componentHidden(ComponentEvent e) {}
+	public void componentShown(ComponentEvent e) {}
+	public void componentMoved(ComponentEvent e) { savepos(); }
+	public void componentResized(ComponentEvent e) { savepos(); }
+	public void actionPerformed(ActionEvent e) {
+		if (e.getActionCommand().equals("pack")) pack();
+	}
+	
+
+	// ........... private bits ...............
+
+	private void savepos() { X.store(node.fullNameFor("bounds"),getBounds()); }
+
+	private void init()
+	{
+		Shell.push(node);
+		try {
+			String	tit = Shell.getString("title",null);
+			Color		bg  = Shell.getColor("background",SystemColor.control);
+			Color		fg  = Shell.getColor("foreground",SystemColor.controlText);
+			Rectangle pos = X.rect(Shell.datum("bounds"),null);
+			// Font		font = X.font(Shell.datum("font"),null);
+
+			if (tit!=null) setTitle(tit);
+			else setTitle(node.fullName());
+
+			if (pos!=null) setBounds(pos);
+			// if (font!=null) setFont(font);
+
+			setBackground(bg);
+			setForeground(fg);
+		} finally { Shell.pop(); }
+
+		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+		JPopupMenu p=new JPopupMenu( "Frame");
+		p.add("pack").addActionListener(this);
+
+		addComponentListener(this);
+		MenuBuilder.addPopup(p,getContentPane()).setBackstop(true);
+	}
+
+	public void addWindowListener(final WindowListener l) {
+		addInternalFrameListener( new InternalFrameAdapter() {
+			public void internalFrameClosing(InternalFrameEvent e) {
+				l.windowClosing(null);
+			}
+		} );
+	}
+
+	public static void setDesktop(Container c) { desktop=c; }
+	private static Container desktop;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/LED.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,36 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  javax.swing.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+public class LED extends JComponent
+{
+	boolean state=false;
+	
+	public LED(Color fg) { this(fg,fg.darker().darker()); }
+	public LED(Color fg, Color bg) { this(); setBackground(bg); setForeground(fg);	}
+	public LED() {}
+	
+	public void update(Graphics g) { paint(g); }
+	public void paint(Graphics g) {
+		g.setColor( state ? getForeground() : getBackground());
+		g.fillRect(0,0,getWidth(),getHeight());
+	}
+
+	public final void on() { set(true); }
+	public final void off() { set(false); }
+	public final void set( boolean state) { 
+		if (state!=this.state) { this.state=state; repaint(); }
+	}
+
+	public Dimension getPreferredSize() { return new Dimension(8,8); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/MenuBuilder.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,95 @@
+/*
+ *	MenuBuilder.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.util.*;
+import  samer.core.*;
+import  javax.swing.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+public class MenuBuilder implements Agent.Registry 
+{
+	JPopupMenu		menu;
+	AgentAdapter	ad;
+
+	public MenuBuilder(JPopupMenu m, AgentAdapter a) { menu=m; ad=a; }
+
+	public Agent.Registry add(String l) 
+	{ 
+		// could get icon here
+		JMenuItem mi = new JMenuItem(l);
+		mi.addActionListener(ad);
+		menu.add(mi);
+		return this;
+	}
+	public Agent.Registry add(String l, boolean state) 
+	{
+		// could get icon here
+		JCheckBoxMenuItem mi = new JCheckBoxMenuItem(l, state);
+		mi.setName(l);
+		mi.addItemListener(ad);
+		menu.add(mi);
+		return this;
+	}
+	public void group() { menu.addSeparator(); }
+
+	public void setTarget(Agent a) { ad=new AgentAdapter(a); group(); }
+
+	public static PopupHandler addPopup(JPopupMenu popup, Component c) {
+		PopupHandler h=new PopupHandler(popup); 
+		insertML(h,c); return h;
+	}
+	
+	private static void insertML(MouseListener l, Component c) {
+		// what if this listener isn't there?
+		c.removeMouseListener(MouseRetarget.listener);
+		c.addMouseListener(l);
+		c.addMouseListener(MouseRetarget.listener);
+	}
+
+	/** Add commands for given Agent to given menu, to be show in given component.
+		If menu is null, then a new menu is created and associated with the component
+		using a popup menu mouse handler. The popup will be shown when the user
+		right clicks in the component.
+	*/
+	
+	public static JPopupMenu showCommands( Agent agent, Component c, JPopupMenu menu)
+	{
+		if (menu==null) {
+			menu=new JPopupMenu(c.getName());
+			addPopup(menu, c);
+		} else {
+			menu.addSeparator();
+		}
+
+		agent.getCommands( new MenuBuilder(menu,new AgentAdapter(agent)));
+		return menu;
+	}
+
+	/** Add commands for given Agent to the given DynamicPopupHandler. This maintains
+		a list of agents, so when the handler is triggered by the user right-clicking in
+		the given component, a popup menu is built dynamically from the commands reported
+		by the Agents.
+		*/
+
+	public static DynamicPopupHandler showCommands( Agent agent, Component c, DynamicPopupHandler h)
+	{
+		if (h==null) {
+			h=new DynamicPopupHandler(c.getName());
+			insertML(h,c);
+		}
+		h.addAgent(agent);
+		return h;
+	}
+};
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/Meter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.util.*;
+import javax.swing.BorderFactory;
+
+public class Meter extends VCanvas
+{
+	IMap	map;
+	int		lasti, nexti;
+	double	x;
+
+	public Meter() { map = new LinearMap(0,1); lasti=0; }
+
+	public void exposeMap() { exposeMap(true); }
+	public void exposeMap(boolean reinit) {
+		final VMap	vmap=new VMap(map,reinit);
+		vmap.addObserver( new Observer() {
+			public void update(Observable o, Object args) {
+				if (args==VMap.NEW_MAP) setMap(vmap.getMap());
+				nexti=map.toInt(x); repaint();
+			}
+		} );
+		vmap.changed();
+		exposeCommands(vmap);
+	}
+
+	public void realized() {
+		setBorder(BorderFactory.createLineBorder(getForeground().darker().darker()));
+	}
+
+	protected void paintComponent(Graphics g) {
+		lasti=nexti;
+		g.setColor(getBackground());
+		g.fillRect(lasti,0,width-lasti,height);
+		g.setColor(getForeground());
+		g.fillRect(0,0,lasti,height);
+	}
+
+	public void next( double x) { 
+		nexti=map.toInt(x); this.x=x;
+		if (nexti!=lasti) repaint();
+	}
+
+	public Dimension getPreferredSize() { return new Dimension(96,6); }
+	public Dimension getMinimumSize() { return new Dimension(32,4); }
+
+	public IMap getMap() { return map; }
+	public void setMap(IMap m) { map=m; lasti=0; repaint(); }
+	protected void sized() { map.setIntRange(width); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/PopupHandler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,39 @@
+/*
+ *	PopupHandler.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  java.awt.event.*;
+import  javax.swing.*;
+
+public class PopupHandler extends MouseAdapter
+{
+	private JPopupMenu	popup;
+	private boolean		backstop;
+
+	public PopupHandler(JPopupMenu p) { this(p,false); }	
+	public PopupHandler(JPopupMenu p, boolean bs) { popup=p; backstop=bs; }	
+
+	public void setBackstop(boolean f) { backstop=f; }
+	public void mousePressed( MouseEvent e) { maybeShowMenu(e); }
+	public void mouseReleased( MouseEvent e) { maybeShowMenu(e); }
+
+	void maybeShowMenu(MouseEvent e)
+	{
+		if (!e.isPopupTrigger()) return;		
+		if (!backstop) {
+			// if not backstop, must NOT have Alt or Ctl down
+			// modified for Macs: need modifiers to get right mouse click!
+			if (e.isShiftDown()) return; 
+		}
+		popup.show( e.getComponent(), e.getX(), e.getY());
+		e.consume();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/SilkyMetalTheme.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,92 @@
+package samer.core.util.swing;
+
+import javax.swing.plaf.*;
+import javax.swing.*;
+import java.awt.*;
+
+public class SilkyMetalTheme extends javax.swing.plaf.metal.MetalTheme {
+
+	private ColorUIResource primary1;
+	private ColorUIResource primary2;
+	private ColorUIResource primary3;
+	private ColorUIResource red, blue, yellow, green, highlight;
+
+	private ColorUIResource secondary1;
+	private ColorUIResource secondary2;
+	private ColorUIResource secondary3;
+
+	private FontUIResource plainFont;
+	private FontUIResource smallFont;
+	private FontUIResource boldFont;
+
+	public String getName() { return "Silk"; }
+
+	public SilkyMetalTheme(Font font, Color bg, double hue)
+	{
+		System.err.println("Metal theme: base font is "+font);
+
+		plainFont = new FontUIResource(font);
+		smallFont = new FontUIResource(font.deriveFont(0.8f*font.getSize2D()));
+		boldFont = new FontUIResource(font.deriveFont(Font.BOLD));
+
+		primary3 = new ColorUIResource(Color.getHSBColor((float)hue,0.3f,1.0f));
+		primary2 =new ColorUIResource(Color.getHSBColor((float)hue,0.4f,.9f));
+		primary1 =new ColorUIResource(Color.getHSBColor((float)hue,0.3f,.3f));
+
+		secondary3 = new ColorUIResource(bg);
+		secondary2 = new ColorUIResource(bg.darker());
+		secondary1 = new ColorUIResource(bg.darker().darker());
+		highlight = new ColorUIResource(bg.brighter());
+
+		red=new ColorUIResource(Color.red);
+		blue=new ColorUIResource(Color.blue);
+		green=new ColorUIResource(Color.green);
+		yellow=new ColorUIResource(Color.yellow);
+	}
+
+	public void addCustomEntriesToTable(UIDefaults table)
+	{
+		table.put( "Button.font", boldFont);
+		table.put( "Label.foreground", getBlack());
+		table.put( "TitledBorder.font", boldFont);
+		table.put( "List.font", plainFont);
+  	}
+
+	public ColorUIResource getPrimary1() { return primary1; }
+	public ColorUIResource getPrimary2() { return primary2; }
+	public ColorUIResource getPrimary3() { return primary3; }
+
+	public ColorUIResource getSecondary1() { return secondary1; }
+	public ColorUIResource getSecondary2() { return secondary2; }
+	public ColorUIResource getSecondary3() { return secondary3; }
+
+	public FontUIResource getControlTextFont() { return plainFont;}
+	public FontUIResource getSystemTextFont() { return plainFont;}
+	public FontUIResource getUserTextFont() { return plainFont;}
+	public FontUIResource getMenuTextFont() { return plainFont;}
+	public FontUIResource getWindowTitleFont() { return boldFont;}
+	public FontUIResource getSubTextFont() { return smallFont;}
+
+	// these are fore tweaking
+
+	public ColorUIResource getDesktopColor() { return getPrimary1(); }
+
+	public ColorUIResource getControl() { return getSecondary3(); }
+	public ColorUIResource getControlShadow() { return getSecondary2(); }
+	public ColorUIResource getControlDarkShadow() { return getSecondary1(); }
+//	public ColorUIResource getControlInfo() { return getBlack(); }
+	public ColorUIResource getControlHighlight() { return highlight; } // getWhite(); }
+//	public ColorUIResource getControlDisabled() { return getSecondary2(); }
+
+//	public ColorUIResource getPrimaryControl() { return getPrimary3(); }
+//	public ColorUIResource getPrimaryControlShadow() { return getPrimary2(); }
+//	public ColorUIResource getPrimaryControlDarkShadow() { return getPrimary1(); }
+//	public ColorUIResource getPrimaryControlInfo() { return getBlack(); }
+	public ColorUIResource getPrimaryControlHighlight() { return highlight; } // getWhite(); }
+
+//	public ColorUIResource getSystemTextColor() { return getPrimary1(); }
+//	public ColorUIResource getInactiveSystemTextColor() { return getSecondary2(); }
+
+	public ColorUIResource getSeparatorBackground() { return highlight; } // getWhite(); }
+	public ColorUIResource getSeparatorForeground() { return getSecondary2(); } // getPrimary1(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/TextualNumberViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+package samer.core.util.swing;
+import  samer.core.*;
+import  javax.swing.*;
+
+public class TextualNumberViewer extends VPanel implements NumberViewer
+{
+	JTextField	rt;
+
+	public TextualNumberViewer(String label)
+	{
+		setLayout(new java.awt.BorderLayout(0,0));
+		setBorder(BorderFactory.createEmptyBorder(2,4,2,4));
+		add(new JLabel(label));
+
+		rt = new JTextField(Shell.getInt("field.width",4));
+		rt.setBackground(Shell.getColor("field.background",rt.getBackground()));
+		rt.setForeground(Shell.getColor("field.foreground",rt.getForeground()));
+		add(rt,java.awt.BorderLayout.EAST);
+	}
+
+	public void set(int num) {	rt.setText(String.valueOf(num)); }
+	public void set(double num) {	rt.setText(X.string(num));	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/VCanvas.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,76 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.util.swing;
+import	samer.core.util.*;
+import	samer.core.*;
+import	javax.swing.*;
+import	java.awt.*;
+import	java.awt.event.*;
+
+/** Basically a Viewer implemented as a bare JComponent.
+	Calls attach() on addNotify(). Also calls realized();
+	Calls sized() when sized.
+	Keeps track of its own width and height.
+	Can display popup menu.
+ */
+
+public class VCanvas extends JComponent implements Viewer
+{
+	public int		 width, height;
+
+	public VCanvas()
+	{
+		addMouseListener(MouseRetarget.listener);
+		addComponentListener( new ComponentAdapter() {
+			public void componentResized(ComponentEvent e) {
+				width=getWidth(); height=getHeight();
+				sized();
+			}
+		} );
+
+		setBackground(Shell.getColor("background",null));
+		setForeground(Shell.getColor("foreground",null));
+		setOpaque(true);
+	}
+
+	protected void realized() {}
+	protected void sized() {}
+
+	protected void paintComponent(Graphics g) { clear(g); }
+	public void clear(Graphics g) {
+		g.setColor(getBackground());
+		g.fillRect(0,0,width,height);
+	}
+
+	public void removeNotify() { detach(); super.removeNotify(); }
+	public void addNotify() {
+		super.addNotify();
+		width=getWidth(); height=getHeight();
+		attach(); realized(); // ??
+	}
+
+	public Dimension getMinimumSize() { return new Dimension(0,0); }
+
+	// ....... MenuAnchor bits .......................
+
+	public Component	getComponent() { return this; }
+	public void	attach() {} 
+	public void	detach() {}
+
+	// private javax.swing.JPopupMenu	menu=null;
+	private DynamicPopupHandler	popup=null;
+	
+	public void	exposeCommands(Agent agent) {
+		popup=MenuBuilder.showCommands(agent,this,popup);
+		// menu=MenuBuilder.showCommands(agent,getComponent(),menu);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/VContainerBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,76 @@
+/*
+ *	VContainerBase.java
+ *
+ *	Copyright (c) 2011, Samer Abdallah, Queen Mary, University of London
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.util.shell.*;
+import samer.core.util.swing.*;
+import samer.core.util.swing.Frame;
+import samer.core.util.swing.Console;
+import samer.core.util.swing.Dialog;
+import samer.core.NumberViewer;
+import samer.core.viewers.swing.*;
+import samer.core.types.*;
+
+
+public class VContainerBase extends WindowAdapter implements ContainerListener
+{
+	protected 	Frame			frame;
+	protected	Box			box;
+	protected	Component	glue;
+	protected	JScrollPane	scr;
+	protected	boolean		adding=false;
+
+	public VContainerBase(String name)
+	{
+		frame = new Frame(name);
+		box   = Box.createVerticalBox();
+		glue  = Box.createVerticalGlue();
+
+		scr=new JScrollPane(box);
+		scr.setBorder(null);
+		box.add(glue); // box.add(buttonBar);
+		box.addContainerListener(this);
+		box.getParent().setBackground(SystemColor.control);
+		frame.container().add(scr);
+		frame.expose();
+		frame.addWindowListener(this);
+	}
+
+	public void pack() { frame.pack(); }
+	public void validate() { box.validate(); frame.validate(); }
+	public void removeAll() { frame.setVisible(false); box.removeAll(); }
+	public void add(Component comp) { box.remove(glue); box.add(comp); box.add(glue); }
+	public void close() { frame.dispose(); }
+
+	public void windowClosing(WindowEvent e) { frame.dispose(); }
+
+	public void componentAdded(ContainerEvent e) {}
+	public void componentRemoved(ContainerEvent e) {
+		box.validate(); frame.validate();
+		if (!adding && noScrollBars()) frame.pack();
+		// else frame.validate();
+	}
+
+	protected boolean noScrollBars() {
+		JScrollBar sb=scr.getVerticalScrollBar();
+		if (sb==null) return true;
+		return !sb.isVisible();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/util/swing/VPanel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,103 @@
+/*
+ *	Tools.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.util.swing;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  javax.swing.*;
+import  javax.swing.border.*;
+
+/**
+ *		This is a panel with an optional bevel border,
+ *		and a name label. It can also draw bevels
+ *		round its children
+ */
+
+
+public class VPanel extends JPanel implements Viewer
+{
+	private	Border			cborder=null; // border for children
+	private 	Viewer			vwr;
+
+	/** Constructors can specify bevel type, inset and name */
+
+	public VPanel() { this(null); }
+	public VPanel(Viewer vwr)
+	{
+		super( new FlowLayout(FlowLayout.LEFT,0,0));
+
+		this.vwr=vwr;
+		// border=Border.createDefault(); // ??
+		// addMouseListener(MouseRetarget.listener);
+		setBorder(BorderFactory.createEmptyBorder(3,6,3,6));
+	}
+
+	public void setName(String txt) {
+		if (txt==null) {
+			setBorder(BorderFactory.createEmptyBorder(2,6,2,6));
+			return;
+		}
+		super.setName(txt);
+		setBorder(
+			BorderFactory.createCompoundBorder(
+				BorderFactory.createTitledBorder(
+					BorderFactory.createEmptyBorder(4,0,8,0),  // space top and bottom
+					txt, TitledBorder.LEADING, TitledBorder.BELOW_TOP),
+				BorderFactory.createEmptyBorder(0,12,0,0) // small indent
+			)
+		);
+	}
+
+	public void setChildBorder( Border b) { cborder=b; }
+
+	/*
+	public void paintChildren(Graphics g) {
+		if (cborder!=null) {
+			Component []	c=getComponents();
+			Insets	insets=cborder.getBorderInsets(this);
+			int		dx=insets.left, dy=insets.top;
+			int		dw=insets.left+insets.right;
+			int		dh=insets.top+insets.bottom;
+
+			for (int i=c.length-1; i>=0; i--) {
+				Rectangle r=c[i].getBounds();
+				if (!r.isEmpty()) {
+					cborder.paintBorder(
+						c[i], g,
+						r.x-dx, r.y-dy,
+						r.width+dw, r.height+dh
+					);
+				}
+			}
+		}
+		super.paintChildren();
+	}
+	*/
+
+
+	public Component getComponent() { return this; }
+	public void	attach() {}
+	public void	detach() {}
+
+	// private 	JPopupMenu		thing=null;
+	private	DynamicPopupHandler thing=null;
+	
+	public void	exposeCommands(Agent agent) {
+		thing=MenuBuilder.showCommands(agent,this,thing);
+	}
+
+	public void addNotify() { if (vwr!=null) vwr.attach(); super.addNotify(); }
+	public void removeNotify() { if (vwr!=null) vwr.detach(); super.removeNotify(); }
+
+//	public void add(Viewer v) { super.add(v.getComponent()); }
+	public void add(Viewable v) { add(v.getViewer().getComponent()); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/BooleanViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,50 @@
+/*
+ *	BooleanViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.util.*;
+import  java.awt.*;
+import  java.awt.event.*;
+
+public class BooleanViewer extends VariableViewer implements ItemListener
+{
+	VBoolean	vbool;
+	Checkbox	cb;
+
+	public BooleanViewer(Viewable v) { this((VBoolean)v); }
+	public BooleanViewer(VBoolean vbool) 
+	{ 
+		super(vbool);
+		this.vbool = vbool;
+
+		setText(null);
+		cb = new Checkbox(vbool.getLabel());
+		cb.addItemListener(this);
+		add(cb);
+		update(null,null);
+	}
+
+	public void update(Observable o, Object source) // &&&
+	{
+		if (source!=this) cb.setState(vbool.value);
+		super.update(o,source);
+	}
+
+	public void itemStateChanged(ItemEvent e)	
+	{
+		vbool.value = (e.getStateChange()==ItemEvent.SELECTED);
+		vbool.changed(this);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,11 @@
+/BooleanViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorButton.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorSwatch.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/DoubleViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/FileViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/IntegerViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/NumberViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ParameterViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/StringViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+D/swing////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/viewers
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/ColorButton.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,63 @@
+/*
+ *	ColorButton.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers;
+import	samer.core.util.*;
+import	samer.core.types.*;
+import	samer.core.*;
+import	java.util.*;
+import	java.awt.*;
+import	java.awt.event.*;
+
+public class ColorButton extends VariableViewer implements ActionListener
+{
+	VColor		vcolor;
+	Button		btn;
+	ColorSwatch	cp;
+
+	public ColorButton(VColor v) { 
+		super(v);
+		vcolor = v;
+		init(v);
+	}
+
+	private void init(Viewable v) 
+	{ 
+		setLayout(layout);
+
+		cp = new ColorSwatch();
+		cp.setColor(vcolor.getColor());
+		btn=new Button("...");
+		btn.addActionListener(this);
+
+		add(cp);
+		add(btn);
+		update(null,null);
+	}
+
+	public void actionPerformed(ActionEvent e)
+	{
+		// bring up color dialog
+		Viewer	vwr=new ColorViewer(vcolor);
+		Shell.expose(vwr,variable.getLabel());
+	}
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source==this) return;
+		if (o==vcolor) {
+			cp.setColor(vcolor.getColor());
+			super.update(o,source);
+		} 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/ColorSwatch.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+/*
+ *	ColorViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers;
+import	samer.core.util.heavy.*;
+import	java.awt.*;
+
+class ColorSwatch extends JPanel {
+	Color color;
+
+	ColorSwatch() { super(Border.create(Border.IN,0));}
+
+	public void setColor(Color c) {
+		color=c;
+		paintSwatch(getGraphics());
+	}
+
+	public Dimension getPreferredSize() { return new Dimension(24,24); }
+
+	private void paintSwatch(Graphics g)
+	{
+		if (g==null) return;
+		Dimension	d=getSize();
+		g.setColor(color);
+		g.fillRect(2,2,d.width-4,d.height-4);
+	}
+	public void paint(Graphics g) {
+		super.paint(g);
+		paintSwatch(g);
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/ColorViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,91 @@
+/*
+ *	ColorViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers;
+import	samer.core.util.*;
+import	samer.core.util.heavy.*;
+import	samer.core.types.*;
+import	samer.core.*;
+import	java.util.*;
+import	java.awt.*;
+
+public class ColorViewer extends VariableViewer
+{
+	VColor	vcolor;
+	VInteger	red, green, blue;
+	ColorSwatch	cp;
+
+	public ColorViewer(VColor v) { 
+		super(v); vcolor = v; init(v);
+	}
+
+	private void init(Viewable v) 
+	{ 
+		Shell.push(v.getNode());
+		red = new VInteger("red", vcolor.r, Variable.NOINIT);
+		green = new VInteger("green", vcolor.g, Variable.NOINIT);
+		blue = new VInteger("blue", vcolor.b, Variable.NOINIT);
+		Shell.pop();
+
+		red.setRange(0,255);
+		green.setRange(0,255);
+		blue.setRange(0,255);
+
+		setLayout(new StackLayout(4)); 
+		cp=new ColorSwatch();
+
+		Border.pushNone();
+
+		add(red.getViewer().getComponent());
+		add(green.getViewer().getComponent());
+		add(blue.getViewer().getComponent());
+		add(cp);
+
+		Border.pop();
+
+		red.addObserver(this);
+		green.addObserver(this);
+		blue.addObserver(this);
+		update(null,null);
+	}
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source==this) return; // &&&
+		if (o==vcolor) {
+			red.value	= vcolor.r;			
+			green.value = vcolor.g;			
+			blue.value	= vcolor.b;		
+			red.changed(this);	
+			green.changed(this);	
+			blue.changed(this);	
+			cp.setColor(vcolor.getColor());
+			super.update(o,source);
+		} else {
+			vcolor.r = red.value;
+			vcolor.g = green.value;
+			vcolor.b = blue.value;
+			vcolor.changed(this);
+			cp.setColor(vcolor.getColor());
+		}
+	}
+/*
+	public void detach()
+	{
+		red.dispose();
+		green.dispose();
+		blue.dispose();
+		super.detach();
+	}
+ */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/DoubleViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,63 @@
+/*
+ *	DoubleViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+
+public class DoubleViewer extends NumberViewer
+{
+	VDouble		model;
+	Scrollbar	s;
+	double		max;
+
+	public DoubleViewer(Viewable v) { this((VDouble)v); }
+	public DoubleViewer(VDouble model) 
+	{ 
+		super(model);
+		this.model = model;
+		this.max   = model.value*2;
+		init();
+	}
+
+	protected Component createSlider() {
+		s=new Scrollbar( Scrollbar.HORIZONTAL, 0, 10, 0, 110);
+		return s;
+	}
+
+	protected void setText()	{ t.setText(model.string()); }
+	protected void getText()   { model.decode(t.getText()); }
+	protected void setSlider() { s.setValue( (int)(100*(model.value/max))); }
+	protected void getSlider() { model.value = max*s.getValue()/100.0; }
+
+	public void getCommands(Agent.Registry r) {
+		r.add("print").add("set");
+		r.add("double range").add("halve range").add("negate range").add("calibrate");
+		r.group();
+		super.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("print")) Shell.print(model.toString());
+		else if (cmd.equals("set"))
+			model.set(X._double(env.datum(model.getNode().fullName()),model.get()));
+		else if (cmd.equals("double range"))	{ max*=2; setSlider();	}
+		else if (cmd.equals("halve range"))		{ max/=2; setSlider();	}
+		else if (cmd.equals("negate range"))	{ max=-max; setSlider(); }
+		else if (cmd.equals("calibrate")) { max=model.value*2; setSlider(); }
+		else super.execute(cmd,env);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/FileViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *	FileViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  samer.core.Agent.*;
+import  java.io.*;
+import  java.awt.*;
+
+public class FileViewer extends StringViewer
+{
+	VFile	vfile;
+
+	public FileViewer(Viewable v) { this((VFile)v); }
+	public FileViewer(VFile vfile) 
+	{ 
+		super(vfile); this.vfile=vfile; 
+		Button b=new Button("...");
+		b.addActionListener(new AgentAdapter(this));
+
+		panel().add(b,"East");
+	}
+
+	public void getCommands(Registry r) { r.add("select"); super.getCommands(r); }
+	public void	execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("select") || cmd.equals("...")) {
+
+			Container cont=panel().getParent();
+			while (cont!=null && !(cont instanceof Frame)) { cont=cont.getParent(); }
+			
+			FileDialog dlg = new FileDialog((Frame)cont, "Select file", FileDialog.LOAD);
+			dlg.setDirectory(vfile.getFile().getParent());
+			dlg.setFile(vfile.getFile().getName());
+			dlg.setVisible(true);
+			dlg.dispose();
+			// what if cancelled?
+
+			vfile.setFile(new File(dlg.getDirectory(),dlg.getFile()));
+			vfile.changed();
+		} else super.execute(cmd,env);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/IntegerViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *	IntegerViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+
+public class IntegerViewer extends NumberViewer
+{
+	VInteger		model;
+	Scrollbar	s;
+
+	public IntegerViewer(Viewable v) { this((VInteger)v); }
+	public IntegerViewer(VInteger model) 
+	{ 
+		super(model);
+		this.model = model;
+		init();
+	}
+
+	protected Component createSlider() {
+		s=new Scrollbar( Scrollbar.HORIZONTAL, 0, 1, model.getMin(), model.getMax()+1);
+		return s;
+	}
+
+	protected void setText()	{ t.setText(model.string()); }
+	protected void getText()   { model.decode(t.getText()); }
+	protected void setSlider() { s.setValue( model.value); }
+	protected void getSlider() { model.value = s.getValue(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/NumberViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,109 @@
+/*
+ *	NumberViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+
+abstract class NumberViewer extends VariableViewer implements
+	FocusListener, AdjustmentListener, ActionListener
+{
+	TextField	t;
+
+	protected NumberViewer(Variable v) 
+	{ 
+		super(v);
+		setLayout(layout); 
+	}
+
+	protected void init()
+	{
+		Component s = createSlider();
+		((Adjustable)s).addAdjustmentListener(this);
+
+		t = new TextField(4); 
+		t.addFocusListener(this);
+		t.addActionListener(this);
+
+		// panel().add(l,"West");
+		panel().add(s,"Center");
+		panel().add(t,"East");
+		update(null,null);
+	}
+
+	protected abstract Component createSlider();
+	protected abstract void getText() throws Exception;
+	protected abstract void setText();
+	protected abstract void getSlider();
+	protected abstract void setSlider();
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source!=this) { // &&&
+			setText();
+			setSlider();
+		}
+		super.update(o,source);
+	}
+
+/*
+	// ??
+	public Dimension getMinimumSize() { return getPreferredSize(); }
+	public Dimension getPreferredSize()
+	{
+		Dimension d=super.getPreferredSize();
+		Dimension dl=l.getPreferredSize();
+		Dimension dt=t.getPreferredSize();
+
+		// Need to make room for scroll bar 
+		d.width = dl.width + dt.width + 96; // ??
+		return d;
+	}
+   */
+
+	// ----------- event handling -------------
+
+	private void textChanged() 
+	{
+		// enter pressed in text field:
+		// read value from text, set slider and
+		// notify observers.
+		try { 
+			getText(); 
+			setSlider(); 
+			variable.changed(this); 
+		}
+		catch (Exception ex) { Shell.trace(ex.toString()); }
+	}
+
+	public void adjustmentValueChanged(AdjustmentEvent e) 
+	{
+		getSlider();
+		setText();
+		variable.changed(this);
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) {
+		if (e.getSource()==t) textChanged();
+	}
+
+	public void actionPerformed( ActionEvent e) {
+		if (e.getSource()==t) textChanged(); 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/ParameterViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+/*
+ *	ParameterViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+
+public class ParameterViewer extends NumberViewer
+{
+	DoubleModel iface;
+	Scrollbar	s;
+	double		max;
+
+	public ParameterViewer(VParameter v) 
+	{ 
+		super(v); 
+		this.iface = v.iface;
+		this.max   = 2*iface.get();
+		init();
+	}
+
+	protected Component createSlider() {
+		s=new Scrollbar( Scrollbar.HORIZONTAL, 0, 10, 0, 110);
+		return s;
+	}
+
+	protected void setText()	{ t.setText(X.string(iface.get())); }
+	protected void getText()   { iface.set(X.parseDouble(t.getText())); }
+	protected void setSlider() { s.setValue( (int)(100*(iface.get()/max))); }
+	protected void getSlider() { iface.set( max*s.getValue()/100.0); }
+
+	public void getCommands(Agent.Registry r) {
+		r.add("double").add("halve").add("negate").add("calibrate").group();
+		super.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if      (cmd.equals("double"))	{ max*=2; setSlider();	} 
+		else if (cmd.equals("halve"))		{ max/=2; setSlider();	} 
+		else if (cmd.equals("negate"))	{ max=-max; setSlider(); } 
+		else if (cmd.equals("calibrate")) { max=iface.get()*2; setSlider(); }
+		else super.execute(cmd,env);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/StringViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+/*
+ *	StringViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers;
+import	samer.core.util.*;
+import	samer.core.types.*;
+import	samer.core.*;
+import	java.awt.*;
+import	java.awt.event.*;
+import	java.util.*;
+
+public class StringViewer extends VariableViewer implements ActionListener, FocusListener
+{
+	TextField	t;
+
+	public StringViewer(VString v) { this((Variable)v); }
+	public StringViewer(Variable v) 
+	{ 
+		super(v); 
+
+		setLayout(layout);
+		t = new TextField(12); 
+		t.addFocusListener(this);
+		t.addActionListener(this);
+
+		panel().add(t,"Center");
+		update(null,null);
+
+	}
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source!=this) { // &&&
+			t.setText(variable.getModel().string());
+		}
+		super.update(o,source);
+	}
+
+	private void parseTextField()
+	{
+		variable.getModel().decode(t.getText()); 
+		variable.changed(this); 
+	}
+
+	public void actionPerformed( ActionEvent e)
+	{
+		// set value and slider
+		if (e.getSource()==t) parseTextField();
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) { parseTextField(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/BooleanViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,73 @@
+/*
+ *	BooleanViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+
+import  java.io.*;
+import  java.util.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  javax.swing.*;
+
+public class BooleanViewer extends VariableViewer implements ItemListener
+{
+	VBoolean	vbool;
+	JCheckBox	cb;
+
+	public BooleanViewer(Viewable v) { this((VBoolean)v); }
+	public BooleanViewer(VBoolean vbool) 
+	{ 
+		super(vbool);
+		this.vbool = vbool;
+
+		setLayout( new BoxLayout(panel(),BoxLayout.X_AXIS));
+		setText(null);
+
+		cb = new JCheckBox(vbool.getLabel());
+		cb.setFocusPainted(false);
+		cb.setMargin(new Insets(0,0,0,0));
+		cb.addItemListener(this);
+		setImageIcons(
+			Shell.getString("boolean.iconDirectory",
+			System.getProperty("user.home",".")+"/buttons"));
+		add(cb);
+		add(Box.createHorizontalGlue());
+		update(null,null);
+	}
+
+	private void setImageIcons(String dirname) {
+		File dir=new File(dirname);
+		if (dir.isDirectory()) {
+			Shell.trace("loading icons from "+dir); 
+			cb.setIcon(new ImageIcon(new File(dir,"rb.gif").getPath()));
+			cb.setPressedIcon(new ImageIcon(new File(dir,"rbr.gif").getPath()));
+			cb.setRolloverIcon(new ImageIcon(new File(dir,"rbp.gif").getPath()));
+			cb.setRolloverSelectedIcon(new ImageIcon(new File(dir,"rbrs.gif").getPath()));
+			cb.setSelectedIcon(new ImageIcon(new File(dir,"rbs.gif").getPath()));
+		}
+	}
+
+	public void update(Observable o, Object source) // &&&
+	{
+		if (source!=this) cb.setSelected(vbool.value);
+		super.update(o,source);
+	}
+
+	public void itemStateChanged(ItemEvent e)	
+	{
+		vbool.value = (e.getStateChange()==ItemEvent.SELECTED);
+		vbool.changed(this);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,12 @@
+/BooleanViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorButton.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorChooserViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ColorViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/DoubleViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/FileChooserViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/FileViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/IntegerViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/NumberViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ParameterViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/StringViewer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/core_/viewers/swing
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/ColorButton.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,80 @@
+/*
+ *	ColorViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers.swing;
+import	samer.core.util.*;
+import	samer.core.types.*;
+import	samer.core.*;
+
+import	java.util.*;
+import	java.awt.*;
+import	java.awt.event.*;
+import	javax.swing.*;
+
+public class ColorButton extends VariableViewer implements ActionListener
+{
+	VColor		vcolor;
+	JButton		btn;
+	ColorSwatch	cp;
+
+	public ColorButton(VColor v) { super(v); vcolor = v; init(v); }
+
+	private void init(Viewable v) 
+	{ 
+		setLayout(new BoxLayout(panel(),BoxLayout.X_AXIS)); 
+
+		cp = new ColorSwatch(vcolor.getColor());
+		btn=new JButton(cp);
+		btn.addActionListener(this);
+		btn.setMargin(null); // new Insets(0,0,0,0));
+
+		add(Box.createHorizontalGlue());
+		add(btn);
+		update(null,null);
+	}
+
+	public void actionPerformed(ActionEvent e)
+	{
+		// bring up color dialog
+		Viewer	vwr=new ColorChooserViewer(vcolor);
+		Shell.expose(vwr,variable.getLabel());
+		//Shell.showDialogFor(vwr.getComponent());
+		//vwr.detach();
+	}
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source==this) return;
+		if (o==obs) {
+			cp.setColor(vcolor.getColor());
+			btn.repaint();
+			super.update(o,source);
+		} 
+	}
+}
+
+class ColorSwatch implements Icon {
+	Color	col;
+
+	public ColorSwatch(Color c) { col=c; }
+	public void setColor(Color c) { col=c; }
+	public int getIconWidth() {	return 12; }
+	public int getIconHeight() { return 12; }
+
+	public void paintIcon(Component c, Graphics g, int x, int y) {
+		g.setColor(Color.black);
+		g.fillRect(x, y, getIconWidth(), getIconHeight());
+		g.setColor(col);
+		g.fillRect(x+2, y+2, getIconWidth()-4, getIconHeight()-4);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/ColorChooserViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,79 @@
+/*
+ *	ColorViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers.swing;
+import	samer.core.util.swing.*;
+import	samer.core.types.*;
+import	samer.core.util.*;
+import	samer.core.*;
+
+import	java.util.*;
+import	java.awt.*;
+import	javax.swing.*;
+import	javax.swing.event.*;
+import	javax.swing.colorchooser.*;
+import	javax.swing.border.*;
+
+public class ColorChooserViewer extends VariableViewer
+{
+	JColorChooser	chooser;
+	VColor			vcolor;
+
+	ColorModelAdapter cm;
+
+	public ColorChooserViewer(VColor  v) { 
+		super(v); vcolor = v; init(v);
+	}
+
+	private void init(Viewable v) 
+	{	
+		cm=new ColorModelAdapter();
+		chooser = new JColorChooser(cm); 
+/*
+		setBorder(
+			BorderFactory.createTitledBorder(
+				BorderFactory.createEmptyBorder(4,0,4,0),
+				variable.getLabel(),
+				TitledBorder.LEFT,
+				TitledBorder.BELOW_TOP
+			)
+		);
+	 */
+		setLayout(new BorderLayout());
+		add(chooser);
+	}
+
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source==this) return; // &&&
+		if (o==vcolor) {
+			// viewable has changed
+			cm.refresh();			
+			super.update(o,source);
+		} 
+	}
+
+	class ColorModelAdapter extends DefaultColorSelectionModel
+	{
+		public void refresh() { super.setSelectedColor(vcolor.getColor()); }
+
+		public Color getSelectedColor() { return vcolor.getColor(); }
+		public void setSelectedColor(Color c) {
+			vcolor.setColor(c); super.setSelectedColor(c);
+			if (vcolor!=null) vcolor.changed(this);
+		}
+
+		{ refresh(); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/ColorViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,115 @@
+/*
+ *	ColorViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers.swing;
+import	samer.core.util.swing.*;
+import	samer.core.util.*;
+import	samer.core.types.*;
+import	samer.core.*;
+import	java.util.*;
+import	java.awt.*;
+import	javax.swing.*;
+import	javax.swing.JPanel;
+
+public class ColorViewer extends VariableViewer
+{
+	VColor	vcolor;
+	VInteger	red, green, blue;
+	Swatch	cp;
+
+	public ColorViewer(Viewable v) { 
+		super((Variable)v);
+		vcolor = (VColor)v;
+		init(v);
+	}
+
+	private void init(Viewable v) 
+	{ 
+		Shell.push(v.getNode());
+		red = new VInteger("red", vcolor.r, Variable.NOINIT);
+		green = new VInteger("green", vcolor.g, Variable.NOINIT);
+		blue = new VInteger("blue", vcolor.b, Variable.NOINIT);
+		Shell.pop();
+
+		red.setRange(0,255);
+		green.setRange(0,255);
+		blue.setRange(0,255);
+
+		setLayout(new StackLayout(4)); 
+
+		cp = new Swatch();
+		JPanel pp=new JPanel();
+		pp.setBorder(BorderFactory.createLoweredBevelBorder());
+		pp.setLayout(new BorderLayout());
+		pp.add(cp);
+
+		// put default empty border
+		add(red.getViewer().getComponent());
+		add(green.getViewer().getComponent());
+		add(blue.getViewer().getComponent());
+		add(pp);
+		// restore previous default border
+
+		red.addObserver(this);
+		green.addObserver(this);
+		blue.addObserver(this);
+		update(null,null);
+	}
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source==this) return; // &&&
+		if (o==vcolor) {
+			red.value	= vcolor.r;			
+			green.value = vcolor.g;			
+			blue.value	= vcolor.b;		
+			red.changed(this);	
+			green.changed(this);	
+			blue.changed(this);	
+			cp.setColor(vcolor.getColor());
+			super.update(o,source);
+		} else {
+			vcolor.r = red.value;
+			vcolor.g = green.value;
+			vcolor.b = blue.value;
+			vcolor.changed(this);
+			cp.setColor(vcolor.getColor());
+		}
+	}
+/*
+	public void detach()
+	{
+		red.dispose();
+		green.dispose();
+		blue.dispose();
+		super.detach();
+	}
+  */
+}
+
+class Swatch extends Component {
+	public Dimension getPreferredSize() { return new Dimension(24,24); }
+
+	public void setColor(Color c) {
+		setBackground(c);
+		repaint();
+	}
+
+	public void paint(Graphics g)
+	{
+		Dimension	d=getSize();
+		g.setColor(getBackground());
+		g.fillRect(0,0,d.width,d.height);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/DoubleViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,125 @@
+/*
+ *	DoubleViewer.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.util.swing.Meter;
+import  samer.core.Agent.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.util.*;
+import  javax.swing.*;
+
+import samer.tools.SignalTrace;
+
+public class DoubleViewer extends NumberViewer
+{
+	VDouble		model;
+	JSlider			slider;
+	Meter			meter;
+	VMap				map;
+	int					flags;
+
+	public DoubleViewer(Viewable v) { this((VDouble)v); }
+	public DoubleViewer(VDouble model) { this(model,model.flags); }
+	public DoubleViewer(VDouble model, int flags)
+	{
+		super(model);
+		this.model = model;
+		this.flags = flags;
+		init((flags&VDouble.NOENTRY)==0);
+	}
+
+	protected JComponent createSlider() {
+		Shell.push(model.getNode());
+		try {
+			if ((flags&VDouble.NOSLIDER)==0) {
+				Shell.push("slider");
+				slider=new JSlider( JSlider.HORIZONTAL, 0, 100, 0);
+				slider.addChangeListener(this);
+				map=new VMap(new LinearMap(100),true);
+				map.addObserver( new Observer() {
+					public void update(Observable o, Object args) {
+						ignoreSliderChange=true; setSlider();
+						ignoreSliderChange=false;
+					}
+				} );
+				exposeCommands(map);
+	
+				Shell.pop();
+				return slider;
+			} else if (Shell.getBoolean("meter",(flags&VDouble.METER)!=0)) {
+				Shell.push("meter");
+				meter = new Meter();
+				meter.exposeMap();
+				meter.setMaximumSize(new Dimension(1000,6));
+				Shell.pop();
+				return meter;
+			} else return null;
+		} finally { Shell.pop(); }
+	}
+
+	protected void setText()	{ t.setText(X.string(model.get())); }
+	protected void getText()   { model.decode(t.getText()); }
+	protected void setSlider() {
+		if (meter!=null) {
+			meter.next(model.get());
+		} else if (slider!=null) {
+			IMap imap=this.map.getMap();
+			double value=model.get();
+			int k=imap.toInt(value);
+			if (imap.wasClipped()) {
+				double right=imap.getDomainMax(), left=imap.getDomainMin();
+				if (k<0) map.setDomain(2*value-right,right);
+				else map.setDomain(left,2*value-left);
+				map.changed();
+			} else 	slider.setValue(k);
+		}
+	}
+
+	protected void getSlider() {
+		if (slider!=null) model.value = map.getMap().inverseFromInt(slider.getValue());
+	}
+
+	public void getCommands(Registry r) {
+		// this gets called in VariableViewer constructor before this
+		// object is propery constructed. Hmmmph.
+		//if ((model.flags&VDouble.NOENTRY)==0) r.add("print").add("set");
+		//if (slider!=null || meter!=null) r.add("calibrate");
+		r.add("print").add("set");
+		r.add("calibrate");
+		r.add("trace");
+		r.group();
+		super.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("print")) Shell.print(model.toString());
+		else if (cmd.equals("set"))
+			model.set(X._double(env.datum(model.getNode().fullName()),model.get()));
+		else if (cmd.equals("calibrate")) {
+			if (slider!=null) {
+				map.setDomain(0,model.get()*2); setSlider();
+			} else if (meter!=null) 
+				meter.getMap().setDomain(0,2*model.get());
+		} else if (cmd.equals("trace")) {
+			Shell.push(new Node("trace", model.getNode()));
+			SignalTrace vwr = new SignalTrace(model);
+			Shell.expose((Viewer)vwr,"window");
+			model.addObserver(vwr);
+			Shell.pop();
+		} else super.execute(cmd,env);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/FileChooserViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,76 @@
+/*
+ *	FileViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+
+import  java.io.*;
+import  java.util.*;
+import  javax.swing.*;
+import  javax.swing.event.*;
+import  java.beans.*;
+
+public class FileChooserViewer extends VariableViewer
+	implements PropertyChangeListener
+{
+	JFileChooser	chooser;
+	VFile				vfile;
+
+	public FileChooserViewer(Viewable v) { this((VFile)v); }
+	public FileChooserViewer(VFile vfile) {
+		super(vfile); this.vfile=vfile;
+
+		setLayout(new BoxLayout(panel(),BoxLayout.Y_AXIS));
+		chooser = new JFileChooser(vfile.getFile());
+		chooser.setSelectedFile(vfile.getFile().getAbsoluteFile());
+		chooser.setControlButtonsAreShown(false);
+		chooser.addPropertyChangeListener(
+			JFileChooser.SELECTED_FILE_CHANGED_PROPERTY, this
+		);
+
+		try { if (vfile.getFile().isDirectory()) setDirectorySelection(); }
+		catch (Exception  ex) {}
+
+		add(chooser);
+	}
+
+	public void update(Observable o, Object source)
+	{
+		if (source!=this) {
+			chooser.setSelectedFile(vfile.getFile().getAbsoluteFile());
+		}
+		super.update(o,source);
+	}
+
+    public void propertyChange(PropertyChangeEvent e)
+	{
+		String prop = e.getPropertyName();
+		if(prop == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY) {
+			vfile.setFile(chooser.getSelectedFile());
+			vfile.changed();
+		}
+	}
+
+	public void setMultiSelectionEnabled(boolean f) {
+		chooser.setMultiSelectionEnabled(f);
+	}
+
+	public void setDirectorySelection() {
+		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+	}
+
+	public void setFileSelection() {
+		chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/FileViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,58 @@
+/*
+ *	FileViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.io.*;
+import  javax.swing.*;
+
+public class FileViewer extends StringViewer
+{
+	VFile	vfile;
+
+	public FileViewer(Viewable v) { this((VFile)v); }
+	public FileViewer(VFile vfile) 
+	{ 
+		super(vfile); this.vfile=vfile; 
+		JButton b=new JButton("...");
+		b.addActionListener(new AgentAdapter(this));
+		add(Box.createHorizontalStrut(4));
+		add(b);
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("select"); super.getCommands(r); }
+	public void	execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("select") || cmd.equals("...")) {
+
+			//Container cont=getParent();
+			//while (cont!=null && !(cont instanceof Frame)) { cont=cont.getParent(); }
+			
+			JFileChooser fc = new JFileChooser(vfile.getFile());
+			fc.setCurrentDirectory(vfile.getFile().getAbsoluteFile());
+			fc.setDialogTitle(vfile.getNode().fullName());
+
+			try {
+				if (vfile.getFile().isDirectory())
+					fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+			}
+			catch (Exception  ex) {}
+
+			if (fc.showDialog(panel(),"Select")==fc.APPROVE_OPTION) {
+				vfile.setFile(fc.getSelectedFile());
+				vfile.changed();
+			}
+		} else super.execute(cmd,env);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/IntegerViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	IntegerViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+import  javax.swing.*;
+
+public class IntegerViewer extends NumberViewer
+{
+	VInteger	model;
+	JSlider		s;
+	
+	public IntegerViewer(Viewable v) { this((VInteger)v); }
+	public IntegerViewer(VInteger model)
+	{
+		super(model);
+		this.model = model;
+		init();
+	}
+
+	protected JComponent createSlider() {
+		s=new JSlider( JSlider.HORIZONTAL, model.getMin(), model.getMax(),model.value);
+		s.addChangeListener(this);
+		return s;
+	}
+
+	protected void setText()	{ t.setText(model.string()); }
+	protected void getText()   { model.decode(t.getText()); }
+	protected void getSlider() { model.value = s.getValue(); }
+	protected void setSlider() {
+		if (model.value>s.getMaximum()) { s.setMaximum(model.value); }
+		else if (model.value<s.getMinimum()) { s.setMinimum(model.value); }
+		s.setValue( model.value);
+	}
+
+	public void update(Observable obs, Object arg)
+	{
+		if (arg==VInteger.NEW_RANGE) {
+			s.setMinimum(model.getMin());
+			s.setMaximum(model.getMax());
+		} else super.update(obs,arg);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/NumberViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,127 @@
+/*
+ *	NumberViewer.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.util.*;
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+import  javax.swing.*;
+import  javax.swing.event.*;
+
+
+abstract	class NumberViewer extends VariableViewer implements
+	FocusListener, ChangeListener, ActionListener
+{
+	JTextField	t=null;
+	volatile boolean ignoreTextChange=false, ignoreSliderChange=false;
+
+	protected NumberViewer(Variable v)
+	{
+		super(v);
+		setLayout(new BoxLayout(panel(),BoxLayout.X_AXIS));
+	}
+
+	protected void init() { init(true); }
+	protected void init(boolean entry)
+	{
+		Dimension	d;
+
+		JComponent	s = createSlider();
+
+
+		if (s!=null) {
+			d=s.getPreferredSize();
+			d.width=80;
+			s.setPreferredSize(d);
+			if (s instanceof JSlider) add(s);
+			else {
+				add(Box.createHorizontalStrut(4));	add(s);
+				add(Box.createHorizontalStrut(4));
+			}
+		} else {
+			add(Box.createHorizontalGlue());
+		}
+
+		if (entry) {
+			t = new JTextField(6);
+			d=t.getPreferredSize();
+			d.width *= 2;
+			t.setMaximumSize(d);
+			t.addFocusListener(this);
+			t.addActionListener(this);
+			add(t);
+		}
+
+		update(null,null);
+	}
+
+	protected abstract JComponent createSlider();
+	protected abstract void getText() throws Exception;
+	protected abstract void setText();
+	protected abstract void getSlider();
+	protected abstract void setSlider();
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source) // &&&
+	{
+		if (source!=this) {
+			ignoreTextChange=true;
+			ignoreSliderChange=true;
+			if (t!=null) setText();
+			setSlider();
+			ignoreTextChange=false;
+			ignoreSliderChange=false;
+		}
+		super.update(o,source);
+	}
+
+	// ----------- event handling -------------
+
+	private void textChanged()
+	{
+		if (ignoreTextChange) return;
+		// enter pressed in text field:
+		// read value from text, set slider and
+		// notify observers.
+		try {
+			getText();
+			ignoreSliderChange=true;
+			setSlider();
+			ignoreSliderChange=false;
+			variable.changed(this);
+		}
+		catch (Exception ex) { Shell.trace(ex.toString()); }
+	}
+
+	public void stateChanged(ChangeEvent e)
+	{
+		if (ignoreSliderChange) return;
+
+		getSlider();
+		ignoreTextChange=true;
+		if (t!=null) setText();
+		ignoreTextChange=false;
+		variable.changed(this);
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) {
+		if (e.getSource()==t) textChanged();
+	}
+
+	public void actionPerformed( ActionEvent e) {
+		if (e.getSource()==t) textChanged();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/ParameterViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,58 @@
+/*
+ *	ParameterViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.core.viewers.swing;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.core.*;
+import  javax.swing.*;
+
+public class ParameterViewer extends NumberViewer
+{
+	DoubleModel iface;
+	JSlider		s;
+	double		max;
+
+	public ParameterViewer(VParameter v) 
+	{ 
+		super(v); 
+		this.iface = v.iface;
+		this.max   = 2*iface.get();
+		init();
+	}
+
+	protected JComponent createSlider() {
+		s=new JSlider( JSlider.HORIZONTAL, 0, 100, 0);
+		s.addChangeListener(this);
+		return s;
+	}
+
+	protected void setText()	{ t.setText(X.string(iface.get())); }
+	protected void getText()   { iface.set(X.parseDouble(t.getText())); }
+	protected void setSlider() { s.setValue( (int)(100*(iface.get()/max))); }
+	protected void getSlider() { iface.set( max*s.getValue()/100.0); }
+
+	public void getCommands(Agent.Registry r) {
+		r.add("double").add("halve").add("negate").add("calibrate").group();
+		super.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if      (cmd.equals("double"))	{ max*=2; setSlider();	} 
+		else if (cmd.equals("halve"))		{ max/=2; setSlider();	} 
+		else if (cmd.equals("negate"))	{ max=-max; setSlider(); } 
+		else if (cmd.equals("calibrate")) { max=iface.get()*2; setSlider(); }
+		else super.execute(cmd,env);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/core_/viewers/swing/StringViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,71 @@
+/*
+ *	StringViewer.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.core.viewers.swing;
+import	samer.core.util.*;
+import	samer.core.types.*;
+import	samer.core.*;
+import	javax.swing.*;
+import	java.awt.event.*;
+import	java.util.*;
+
+public class StringViewer extends VariableViewer implements ActionListener, FocusListener
+{
+	JTextField	t;
+
+	public StringViewer(VString v) { this((Variable)v); }
+	public StringViewer(Variable v) 
+	{ 
+		super(v); 
+
+		// setLayout(new BoxLayout(panel(),BoxLayout.X_AXIS));
+		setLayout(layout);
+		t = new JTextField(4); 
+		t.addFocusListener(this);
+		t.addActionListener(this);
+
+		// add(Box.createHorizontalStrut(12));
+		add(t);
+		update(null,null);
+
+		JComponent jc=(JComponent)panel();
+		java.awt.Dimension  pr=jc.getPreferredSize();
+		java.awt.Dimension  mx=jc.getMaximumSize();
+		mx.height=pr.height;
+		jc.setMaximumSize(mx);
+	}
+
+	// ....... Viewer bits ...................................
+
+	public void update(Observable o, Object source)
+	{ 
+		if (source!=this) { // &&&
+			t.setText(variable.getModel().string());
+		}
+		super.update(o,source);
+	}
+
+	// ........ Functionality ................................
+	private void parseTextField()
+	{
+		variable.getModel().decode(t.getText()); 
+		variable.changed(this); 
+	}
+
+	public void actionPerformed( ActionEvent e)
+	{
+		// set value and slider
+		if (e.getSource()==t) parseTextField();
+	}
+
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) { parseTextField(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Abs.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/*
+ *	Abs.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Abs extends Function
+{	
+	public double apply(double t) { return Math.abs(t); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.abs(x[i]);
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.abs(x[i]);
+	}
+
+	public Function derivative() { return new Sgn(); }
+	public String format(String arg) { return "|"+arg+"|"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Add.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.core.types.*;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class Add extends Function implements DoubleModel
+{	
+	double k;
+
+	public Add(double k) { this.k=k; }
+
+	public void set(double k) { this.k=k; }
+	public double get() { return k; }
+	
+	public double apply(double t) { return t+k; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]+=k;
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=x[i]+k;
+	}
+	public String format(String arg) { return arg+"+"+X.string(k); }
+
+	public Function derivative() { return new Identity(); }
+	public Function inverse() { return new Add(-k); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Atanh.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,18 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Atanh extends Function
+{
+	public double apply(double t) { return Mathx.atanh(t); }
+	public Function inverse() { return new Tanh(); }
+	public String format(String arg) { return "atanh("+arg+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/BiLaplacian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/**
+Sparsified Laplacian, v1
+	Log prior for an laplacian distribution with
+	an extra mass at zero, eg a mixture of a laplacian
+	with another much narrower laplacian. The log prior is
+	basically an abs function with with a extra-deep pit at
+	zero.
+	Paramters control the width and depth of the pit.
+  */
+
+public class BiLaplacian extends Function
+{
+	double width=1, A=1, slope=2;
+
+	public void setWidth(double b) { width=b; slope=(width+A)/width; }
+	public void setStrength(double a) { A=a; slope=(width+A)/width; }
+	public double getJump() { return slope; }
+
+	public String format(String t) { return "BiLaplace("+t+")"; }
+
+	public final double apply(double t) { 
+		t = Math.abs(t);
+		if  (t<width) return -A+slope*t;
+		else return t;
+	}
+
+	public Function derivative() { 
+		return new Function() {
+			public String format(String t) { return "dBiLaplace("+t+")"; }
+			public final double apply(double t) { 
+				if (t>0) {
+					if  (t<width) return slope;
+					else return 1;
+				} else if (t<0) {
+					if  (t>-width) return -slope;
+					else return -1;
+				} else return 0;
+			}
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/BiLaplacianBlend.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,58 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/**
+	Log prior for an laplacian distribution with
+	an extra mass at zero, eg a mixture of a laplacian
+	with another much narrower laplacian. The log prior is
+	basically an abs function with with a extra-deep pit at
+	zero.
+	Paramters control the width and depth of the pit.
+
+	Two linear phases blended exponentially.
+  */
+
+public class BiLaplacianBlend extends Function
+{
+	double beta=1, A=1;
+
+	public void setExponent(double b) { beta=b; }
+	public void setStrength(double a) { A=a; }
+	public double getJump() { return 1+A*beta; }
+
+	public String format(String t) { return "SparseLaplacian("+t+")"; }
+
+	public final double apply(double t) { 
+		t = Math.abs(t);
+		double s=beta*t;
+		if  (s<24) return t-A*Math.exp(-s);
+		else return t;
+	}
+
+	public Function derivative() { 
+		return new Function() {
+			public final double apply(double t) { 
+				if (t>0) {
+					double s=beta*t;
+					if  (s>24) return 1;
+					else return 1+A*beta*Math.exp(-s);
+				} else if (t<0) {
+					double s=-beta*t;
+					if  (s>24) return -1;
+					else return -1-A*beta*Math.exp(-s);
+				} else return 0;
+			}
+			public String format(String t) { return "dBiLaplacian("+t+")"; }
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,39 @@
+/Abs.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Add.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Atanh.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/BiLaplacian.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/BiLaplacianBlend.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/CauchyInfomax.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/CompoundFunction.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Exp.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ExponentialSquashing.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Gamma.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/HalfSquare.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Hamming.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Hanning.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/HybridFunction.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Log.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogAbs.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogCauchy.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogCosh.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogGenCosh.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogGenExp.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogGenExp2.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogisiticInfomax.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/LogisticHyperplane.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Negate.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Power.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Quadratic.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/RaleighLogPrior.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Reciprocal.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Scale.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ScaledFunction.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Sgn.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/SparseExponential.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Sqrt.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Square.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Step.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Tanh.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ThresholdLog.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/WinnerTakeAll.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/functions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/CauchyInfomax.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/** cauchy distribution score function */
+public class CauchyInfomax extends Function
+{
+	public final double apply(double t) { return 2*t/(1+t*t); }
+	public final void   apply(double [] x) { apply(x,x); }
+	public final void   apply(double [] x, double [] y) { 
+		for (int i=0; i<x.length; i++) {
+			double t=x[i];
+			y[i]= 2*t/(1+t*t); 
+		}
+	}
+	public String format(String t) { return "dlogcauchy("+t+")"; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/CompoundFunction.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,72 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import	samer.maths.*;
+
+public class CompoundFunction extends Function
+{
+	Function f, g;
+
+	public CompoundFunction( Function f, Function g)	{
+		this.f=f; this.g=g;
+	}
+
+	public void dispose() {
+		f.dispose();
+		g.dispose();
+	}
+
+	public double apply(double t) { return f.apply(g.apply(t)); }
+
+	public Function inverse() 
+	{
+		return new Function() {
+			Function	finv=f.inverse();
+			Function ginv=g.inverse();
+
+			public void dispose()
+			{
+				finv.dispose();
+				ginv.dispose();
+			}
+
+			public double apply(double t) { return ginv.apply(finv.apply(t)); }
+			public Function inverse() { return new CompoundFunction(f,g); }
+			public String format(String arg) { return ginv.format(finv.format(arg)); }
+		};
+	}
+
+	public Function derivative()
+	{
+		final Function df=f.derivative();
+		final Function dg=g.derivative();
+
+		if (df instanceof Zero) return df;
+		if (df instanceof Constant) return new ScaledFunction(dg,df.apply(0));
+
+		return new Function() {
+
+			public void dispose()
+			{
+				df.dispose();
+				dg.dispose();
+			}
+
+			public double apply(double t) { 
+				return df.apply(g.apply(t))*dg.apply(t); 
+			}
+			public String format(String t) { 
+				return dg.format(t) + " " + df.format(g.format(t)); 
+			}
+		};
+	}
+
+	public String format(String arg) { return f.format(g.format(arg)); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Exp.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Exp extends Function
+{	
+	public double apply(double t) { return Math.exp(t); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.exp(x[i]);
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.exp(x[i]);
+	}
+
+	public Function derivative() { return new Exp(); }
+	public Function inverse() { return new Log(); }
+	public String format(String arg) { return "exp("+arg+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/ExponentialSquashing.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,34 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/** Zero for t<0, linear near 0, exponentially tending to 1 */
+
+public class ExponentialSquashing extends Function implements DoubleModel
+{	
+	private double	beta=1;
+	private VParameter betaParam;
+
+	public ExponentialSquashing() {
+		betaParam = new VParameter( "squash.beta", this);
+	}
+
+	public double get() { return beta; }
+	public void set(double t) { beta=t; }
+	public void dispose() { betaParam.dispose(); }
+
+	public double apply(double t) { 
+		if (t>0) return 1 - Math.exp(-beta*t);
+		else return 0;
+	}
+	public String format(String arg) { return "ExponentialSquashing("+arg+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Gamma.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,215 @@
+// JEM - Java tools for Experimental Mathematics
+// Copyright (C) 2001 JEM-Group
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+package samer.functions;
+
+/** 
+ * Implementation of the real (incomplete) Gamma function.
+ * <p>
+ * This class provides an implementaion of the real Gamma function
+ * <p align=center>
+ * <code>&Gamma;( z ) = &int;<sub>0</sub><sup>&infin;</sup> t<sup>z-1</sup>e<sup>-t</sup>dt</code>
+ * </p>
+ * and its sibling, the <i>incomplete</i> Gamma function:
+ * <p align=center>
+ * <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>x</sup>t<sup>a-1</sup>e<sup>-t</sup>dt</code>
+ * </p><p>
+ * The Implementation follows the ideas of C.Lanczos and their realizations
+ * presented in <em>Numerical Recipes in C</em>.
+ * </p><p> 
+ * Further reading:
+ * <table>
+ * <tr><td> - </td><td>C.Lanczos, 1964, SIAM Journal of Numerical Analysis, ser. B, vol. 1,
+ * pp. 86-96.</td></tr>
+ * <tr><td> - </td><td>W.H.Press, S.A.Teukolsky, W.T.Vetterling, B.P.Flannery.
+ * <em>Numerical Recipes in C</em>. Cambridge University Press, 1992. </td></tr>
+ * </table>
+ *</p>
+ */
+public class Gamma {
+
+    private static final double a = Math.sqrt( 2*Math.PI ) *    1.000000000190015;
+    private static final double b = Math.sqrt( 2*Math.PI ) *   76.18009172947146;
+    private static final double c = Math.sqrt( 2*Math.PI ) *  -86.50532032941677;
+    private static final double d = Math.sqrt( 2*Math.PI ) *   24.01409824083091;
+    private static final double e = Math.sqrt( 2*Math.PI ) *   -1.231739572450155;
+    private static final double f = Math.sqrt( 2*Math.PI ) *    0.1208650973866179e-2;
+    private static final double g = Math.sqrt( 2*Math.PI ) *   -0.5395239384953e-5;
+
+    private Gamma() {}
+
+    static double gamma_( double z ) {
+
+	if( z <= 0 )
+	    throw new IllegalArgumentException("argument must be positive");
+
+	double s = Math.exp( Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 ) );
+	
+	return s * ( a + 
+		     b/(z+1) + c/(z+2) + d/(z+3) + 
+		     e/(z+4) + f/(z+5) + g/(z+6)  ) / z;
+    }
+
+    /**
+     * Retunrs the gamma function at <code>z</code>.
+     * @param z a real number
+     * @return <code> &Gamma;( z ) = &int;<sub>0</sub><sup>&infin;</sup> 
+     * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
+     */
+    public static double gamma( double z ) {
+
+	return z <= 0.5 ? Math.PI / gamma_ ( 1 - z ) / Math.sin( Math.PI * z ) : gamma_ ( z );
+    }
+
+    static double logOfGamma_( double z ) {
+
+	if( z <= 0 )
+	    throw new IllegalArgumentException("argument must be positive");
+
+	double s = Math.log( z + 5.5 ) * ( z + 0.5 ) - ( z + 5.5 );
+	
+	return s + Math.log(  ( a + 
+				b/(z+1) + c/(z+2) + d/(z+3) + 
+				e/(z+4) + f/(z+5) + g/(z+6)  ) / z );
+    }
+
+
+    /**
+     * Retunrs the logarithm of the gamma function at <code>z</code>.
+     * @param z a real number
+     * @return <code>log( &Gamma;( z ) ) = log ( &int;<sub>0</sub><sup>&infin;</sup> 
+     * t<sup>z-1</sup>e<sup>-t</sup>dt )</code>
+     */
+    public static double logOfGamma( double z ) {
+
+	return z <= 0.5 
+	    ? Math.log( Math.PI / Math.sin( Math.PI * z ) ) - logOfGamma_ ( 1 - z )  
+	    : logOfGamma_ ( z );
+    
+    }
+
+
+    private static double gamma( double a, double x, double gammaOfA, boolean computeGammaOfA ) {
+
+	if( a<=0 )
+	    throw new IllegalArgumentException( "a is not positive" );
+
+	if( x<0 )
+	    throw new IllegalArgumentException( "x is negative" );
+
+	if( x < a + 1 ) {
+	    if( computeGammaOfA )
+		gammaOfA = gamma ( a );
+
+	    return computeViaSeries( a, x, gammaOfA );
+	
+	} else
+	    return computeViaContinuedFraction( a, x );
+    }
+
+    /**
+     * Returns the incomplete gamma function at <code>a, x</code>.
+     * The algorithms for the incomplete gamma function needs
+     * to compute <code>&Gamma;(a)</code>; providing this value
+     * will therefor lead to an optimization if you need
+     * this value also for a diffrent porpuse.
+     * @param a a positive real number
+     * @param x a real number greater than <code>a</code>
+     * @return <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>&infin;</sup> 
+     * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
+     */
+    public static double gamma( double a, double x, double gammaOfA ) {
+	return gamma ( a, x, gammaOfA, false );
+    }
+
+
+    /**
+     * Returns the incomplete gamma function at <code>a, x</code>.
+     * @param a a positive real number
+     * @param x a real number greater than <code>a</code>
+     * @return <code>&Gamma;( a, x ) = &int;<sub>0</sub><sup>&infin;</sup> 
+     * t<sup>z-1</sup>e<sup>-t</sup>dt</code>
+     */
+    public static double gamma( double a, double x ) {
+	return gamma ( a, x, 123, true );
+    }
+    
+    static int MAX_NUMBER_OF_ITERATIONS = 200;
+
+    static double EPS = 1e-16;
+
+    static double computeViaSeries( double a, double x, double gammaOfA ) {
+
+	double factor = a;
+	double delta  = 1 / a;
+	double sum    = delta;
+	
+	int counter   = 0;
+
+	while( Math.abs(delta) > Math.abs( sum ) * EPS ) {
+	    
+	    delta *= x/++factor;
+
+	    sum   += delta;
+
+	    if( counter > MAX_NUMBER_OF_ITERATIONS )
+		throw new RuntimeException( "exeeded max number of iterations="+
+					    MAX_NUMBER_OF_ITERATIONS );
+	}
+
+	return gammaOfA  - sum * Math.exp( a*Math.log( x ) - x );
+    }
+
+    static double MIN_DP = 1e-30;
+
+    static double computeViaContinuedFraction( double a, double x ) {
+
+	    double b = x + 1 - a;
+	    double c = 1/MIN_DP;
+	    double d = 1/b;
+	    double h = d;
+
+	    for( int i=1; i<MAX_NUMBER_OF_ITERATIONS; i++ ) {
+
+		double an = -i * (i-a);
+
+		b += 2;
+
+		d  = an*d + b;
+		c  = an/c + b;
+
+		if( Math.abs( c ) < MIN_DP )
+		    c = MIN_DP;
+		if( Math.abs( d ) < MIN_DP )
+		    d = MIN_DP;
+
+		d = 1 / d;
+
+		double delta = c * d;
+
+		h *= delta;
+
+		if( Math.abs( delta - 1 ) < EPS )
+		    return h * Math.exp( a * Math.log( x ) - x );
+	    }
+
+	    throw new RuntimeException( "exeeded max number of iterations="+
+					MAX_NUMBER_OF_ITERATIONS  );
+    }
+    
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/HalfSquare.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class HalfSquare extends Function
+{
+	public double apply(double t) { return t*t/2; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]*=x[i]/2;
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=x[i]*x[i]/2;
+	}
+
+	public String format(String arg) { return "sqr("+arg+")/2"; }
+	public Function inverse() { return new ScaledFunction(new Sqrt(),Math.sqrt(2)); }
+	public Function derivative() { return new Identity(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Hamming.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,6 @@
+package samer.functions;
+
+public class Hamming extends samer.maths.Function {
+	public double apply(double t) { return 0.54 - 0.46*Math.cos(2*Math.PI*t); }
+	public String format(String t) { return "Hamming("+t+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Hanning.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,6 @@
+package samer.functions;
+
+public class Hanning extends samer.maths.Function {
+	public double apply(double t) { return 0.5*(1 - Math.cos(2*Math.PI*t)); }
+	public String format(String t) { return "Hanning("+t+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/HybridFunction.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,50 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/**
+	Piecewise function made of two other functions, f and g.
+	If argument>threshold, return g(t), otherwise return f(t)
+	Implements double model for setting the threshold or
+	cross-over point, which defaults to zero.
+	*/
+
+public class HybridFunction extends Function implements DoubleModel
+{
+	double theta=0;
+	Function f, g;
+
+	public HybridFunction( Function f, Function g) { this(f,g,0); }
+	public HybridFunction( Function f, Function g, double th)
+	{
+		this.f=f;
+		this.g=g;
+		theta=th;
+	}
+
+	/** DoubleModel implementation: set crossover point */
+	public void set(double t) { theta=t; }
+
+	/** DoubleModel implementation: get crossover point */
+	public double get() { return theta; }
+
+	public void dispose() { f.dispose(); g.dispose(); }
+	public double apply(double t) { return t<0 ? f.apply(t) : g.apply(t); }
+
+	public Function derivative() {
+		return new HybridFunction(f.derivative(),g.derivative(),theta);
+	}
+
+	public String format(String arg) {
+		return "t>=0 ? "+g.format(arg)+" : " +f.format(arg);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Log.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Log extends Function
+{	
+	public double apply(double t) { return Math.log(t); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.log(x[i]);
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.log(x[i]);
+	}
+
+	public String format(String arg) { return "log "+arg; }
+	// public Function derivative() { return new Power(-1); }
+	public Function inverse() { return new Exp(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogAbs.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class LogAbs extends Function
+{	
+	public double apply(double t) { return Math.log(Math.abs(t)); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.log(Math.abs(x[i]));
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.log(Math.abs(x[i]));
+	}
+
+	public String format(String arg) { return "log |"+arg+"|"; }
+	// public Function derivative() { return new Power(-1); }
+	public Function inverse() { return new Exp(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogCauchy.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/** Cauchy distribution negative log prior */
+package samer.functions;
+import  samer.maths.*;
+
+public class LogCauchy extends Function
+{
+	public final double apply(double t) { return Math.log(1+t*t); }
+	public String format(String t) { return "log (1+"+t+"^2)"; }
+	public Function derivative() { return new CauchyInfomax(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogCosh.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,42 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/**
+	Actually 2 log cosh: - log prior of sech^2 disribution
+	like abs but with rounded bottom
+	Amount of rounding is adjustable */
+
+
+public class LogCosh extends Function {
+	double offset=-Math.log(2);
+
+	public String format(String t) { return "-2 log cosh "+t; }
+
+	public final double apply(double t) {
+		if  (t<-12) return offset-t;
+		else if (t>12) return offset+t;
+		else return Math.log(Mathx.cosh(t)); 
+	}
+
+	public Function derivative() { 
+		return new Function() {
+			public String format(String t) { return "tanh "+t; }
+			public final double apply(double t) { 
+				if  (t<-12) return -1;
+				else if (t>12) return 1;
+				else return Mathx.tanh(t); 
+			}
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogGenCosh.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,46 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/** Actually NEGATIVE log cosh: like abs but with rounded bottom
+	Amount of rounding is adjustable */
+
+
+public class LogGenCosh extends Function implements DoubleModel
+{
+	double beta=1, alpha=1, offset;
+
+	public LogGenCosh() {}
+	public LogGenCosh( double a) { set(a); }
+	
+	public double get() { return alpha; }
+	public void set(double n)  {
+		alpha=n; beta=1/n; offset=-alpha*Math.log(2);
+	}
+
+	public String format(String t) { return "log cosh "+t; }
+
+	public final double apply(double t) {
+		double s=beta*t;
+		if  (s<-16) return offset-t;
+		else if (s>16) return offset+t;
+		else return alpha*Math.log(Mathx.cosh(beta*t)); 
+	}
+
+	public Function derivative() { 
+		return new Function() {
+			public String format(String t) { return "tanh "+t; }
+			public final double apply(double t) { return Mathx.tanh(beta*t); }
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogGenExp.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,50 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/** Generalised exponential log prior
+	Blending to quadratic at zero */
+
+public class LogGenExp extends Function implements DoubleModel
+{
+	private double	alpha=1;
+	private double eps=1e-6;
+
+	public LogGenExp( double a, double e) { alpha=a; eps=e; }
+
+	public double get() { return alpha; }
+	public void set(double t) { alpha=t; }
+	public void dispose() { }
+
+	public DoubleModel getAlphaModel() { return this; }
+	public DoubleModel getEpsModel() {
+		return new DoubleModel() {
+			public double get() { return eps; }
+			public void set(double t) { eps=t; }
+		};
+	}
+
+	public double apply(double t) {
+		return (t*t)/(eps + Math.pow(Math.abs(t),2-alpha));
+	}
+	public String format(String arg) { return "|"+arg+"|^a"; }
+
+	public Function derivative() {
+		return new Function () {
+			public double apply(double t) {
+				// don't ask me why the 3 is there. it just is.
+				return (alpha*t)/(2*eps + Math.pow(Math.abs(t),2-alpha));
+			}
+			public String format(String arg) { return "a "+arg+"^(a-1)"; }
+		};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogGenExp2.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,59 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/** This version has a quadratic phase, a linear phase,
+and finally, a power law phase. */
+
+public class LogGenExp2 extends Function implements DoubleModel
+{
+	private double	alpha=1;
+	private double e2=1e-6;	// quadratic scale
+	private double e1=1e-1;	// linear scale
+   
+	public double get() { return alpha; }
+	public void set(double t) { alpha=t; }
+	public void dispose() { }
+
+	public DoubleModel getAlphaModel() { return this; }
+	public DoubleModel getQuadraticScale() { 
+		return new DoubleModel() {
+			public double get() { return e2; }
+			public void set(double t) { e2=t; }
+		};
+   }
+   
+	public DoubleModel getLinearScale() { 
+		return new DoubleModel() {
+			public double get() { return e1; }
+			public void set(double t) { e1=t; }
+		};
+	}
+		
+	public double apply(double t) {
+		t=Math.abs(t);      
+		return (t*t)/(e2 + t*(e1 + Math.pow(t,1-alpha)));
+	}
+	public String format(String arg) { return "|"+arg+"|^a"; }
+
+	public Function derivative() {
+		return new Function () {
+         public double apply(double t) {
+         	double at=Math.abs(t);
+            double q=Math.pow(at,2-alpha);
+            double r=e2+e1*at+q;
+            return t*(2*e2+e1*at+alpha*q)/(r*r);
+			}
+			public String format(String arg) { return "a "+arg+"^(a-1)"; }
+		};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogisiticInfomax.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class LogisiticInfomax extends ScaledFunction {
+	public LogisiticInfomax() { super( new Tanh(), 2); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/LogisticHyperplane.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+package samer.functions;
+
+import samer.maths.*;
+
+public class LogisticHyperplane extends FunctionOfVector {	
+	double[]		norm;
+	double		offset;
+	Function	fn;
+	
+	public LogisticHyperplane(int n) {
+		this(new double[n],0);
+	}
+	
+	public LogisticHyperplane(double [] norm, double offset) {
+		this.offset=offset;
+		this.norm=norm;
+		fn=new Step();
+	}	
+	
+	public void setFunction(Function f) { fn=f; }
+	public void setOffset(double r) { offset=r; }
+	public void setNormal(double [] n) { norm=n; }
+	public double getOffset() { return offset; }
+	public double[] getNormal() { return norm; }
+	
+	public double apply(double [] in) {
+		return fn.apply(Mathx.dot(in,norm)-offset);
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Negate.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import	samer.maths.*;
+
+public class Negate extends Function
+{	
+	public double apply(double t) { return -t;	}
+	public String format(String arg) { return "-"+arg; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Power.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.core.types.*;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class Power extends Function implements DoubleModel
+{	
+	double k;
+
+	public Power(double k) { this.k=k; }
+
+	public void set(double k) { this.k=k; }
+	public double get() { return k; }
+	
+	public double apply(double t) { return Math.pow(t,k); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.pow(x[i],k);
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.pow(x[i],k);
+	}
+	public String format(String arg) { return arg+"^"+X.string(k); }
+
+	public Function derivative() { 
+		if (k==3) return new Quadratic(3,0,0);
+		else if (k==2) return new Linear(2,0);
+		else if (k==1) return new Constant(1);
+		else return new ScaledFunction(new Power(k-1),k); 
+	}
+	public Function inverse() { return new Power(1/k); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Quadratic.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,41 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class Quadratic extends Function
+{	
+	double	a, b, c;
+
+	public Quadratic(double a, double b, double c) { 
+		this.a = a; this.b = b; this.c = c;
+	}
+
+	public double apply(double t) { return c+t*(b+a*t); }
+	public String format(String arg) { 
+		StringBuffer buf=new StringBuffer();
+		boolean f=false;
+		if (c!=0) { buf.append(X.string(c)); }
+		if (b!=0 || b<0) { 
+			if (f) { buf.append(b>0 ? " + " : " - "); f=true; }
+			if (b==1 || b==-1) buf.append(arg); 
+			else buf.append(X.string(Math.abs(b))).append(arg); 
+		}
+		if (a!=0) { 
+			if (f || a<0) { buf.append(a>0 ? " + " : " - "); f=true; }
+			if (a==1 || a==-1) buf.append(arg+"^2"); 
+			else buf.append(X.string(Math.abs(b))).append(arg+"^2"); 
+		}
+		return buf.toString();
+	}
+
+	public Function derivative() { return new Linear(2*a,b); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/RaleighLogPrior.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/**
+	Density is linear near zero, rising to a peak, decaying
+	with a Gaussian tail.
+*/
+
+public class RaleighLogPrior extends Function
+{
+	public final double apply(double t) { return 0.5*t*t - Math.log(t); }
+	public String format(String t) { return "LogRaleigh("+t+")"; }
+	public Function derivative() { 
+		return new Function() {
+			public String format(String t) { return "dLogRaleigh("+t+")"; }
+			public final double apply(double t) { return t-1/t; }
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Reciprocal.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,25 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Reciprocal extends Function
+{	
+	public double apply(double t) { return 1/t; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=1/x[i];
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=1/x[i];
+	}
+
+	public String format(String arg) { return "1/"+arg; }
+	public Function inverse() { return this; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Scale.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,36 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+
+public class Scale extends Function implements DoubleModel
+{	
+	private double	k;
+
+	public Scale(  double k) { this.k=k; }
+
+	public double get() { return k; }
+	public void set(double kk) { k=kk; }
+	
+	public void dispose() {}
+
+	public double apply(double t) { return k*t; }
+	public void apply(double [] x) { 	for (int i=0; i<x.length; i++) x[i]*=k; }
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<y.length; i++) y[i]=k*x[i];
+	}
+
+	public String format(String arg) { return X.string(k)+"*"+arg; }
+
+	public Function inverse() { return new Scale(1/k); }
+	public Function derivative() {	return new Constant(k); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/ScaledFunction.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+
+public class ScaledFunction extends Function implements DoubleModel
+{	
+	private double	k;
+	private Function f;
+
+	public ScaledFunction( Function f, double k)
+	{
+		this.f=f;
+		this.k=k;
+	}
+
+	public double get() { return k; }
+	public void set(double kk) { k=kk; }
+	
+	public void dispose() { f.dispose(); }
+
+	public double apply(double t) { return k*f.apply(t); }
+	public void apply(double [] x) {
+		f.apply(x);
+		for (int i=0; i<x.length; i++) x[i]*=k;
+	}
+	public void apply(double [] x, double [] y) {
+		f.apply(x,y);
+		for (int i=0; i<y.length; i++) y[i]*=k;
+	}
+
+	public String format(String arg) {
+		if (k==0) return "0";
+		if (k==1) return f.format(arg);
+		if (k==-1) return "-"+f.format(arg);
+		return X.string(k)+" "+f.format(arg); 
+	}
+
+	public Function inverse() { return new ScaledFunction(f,1/k); }
+	public Function derivative() {
+		return new ScaledFunction( f.derivative(), k);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Sgn.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import	samer.maths.*;
+
+public class Sgn extends Function
+{	
+	public double apply(double t) { 
+		if (t>0) return 1;
+		if (t<0) return -1;
+		return 0;
+	}
+	public String format(String arg) { return "sgn("+arg+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/SparseExponential.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/**
+	Single-sided (ie positive only) version of SparseLaplacian.
+	See that class for a description.
+  */
+
+public class SparseExponential extends Function
+{
+	double beta=1, A=1;
+
+	public void setExponent(double b) { beta=b; }
+	public void setStrength(double a) { A=a; }
+
+	public String format(String t) { return "SparseExp("+t+")"; }
+
+	public final double apply(double t) { 
+		double s=beta*t;
+		if  (s<24) return t-A*Math.exp(-s);
+		else return t;
+	}
+
+	public Function derivative() { 
+		return new Function() {
+			public String format(String t) { return "dSparseExp("+t+")"; }
+			public final double apply(double t) { 
+				double s=beta*t;
+				if  (s>24) return 1;
+				else return 1+A*beta*Math.exp(-s);
+			}
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Sqrt.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Sqrt extends Function
+{	
+	public double apply(double t) { return Math.sqrt(t); }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.sqrt(x[i]);
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=Math.sqrt(x[i]);
+	}
+
+	public String format(String arg) { return "sqrt("+arg+")"; }
+	public Function inverse() { return new Square(); }
+	public Function derivative() { 
+		return new ScaledFunction( 
+			new CompoundFunction( new Reciprocal(), new Sqrt()),
+			0.5
+		);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Square.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Square extends Function
+{	
+	public double apply(double t) { return t*t; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]*=x[i];
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=x[i]*x[i];
+	}
+
+	public String format(String arg) { return "sqr("+arg+")"; }
+	public Function inverse() { return new Sqrt(); }
+	public Function derivative() { return new Linear(2,0); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Step.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Step extends Function
+{	
+	public double apply(double t) { 
+		if (t>0) return 1;
+		return 0;
+	}
+	public String format(String arg) { return "H("+arg+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/Tanh.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,28 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+public class Tanh extends Function
+{
+	public double apply(double t) { return Mathx.tanh(t); } 
+	public String   format(String arg) { return "tanh("+arg+")"; }
+	public Function inverse() { return new Atanh(); }
+	public Function derivative() { 
+		return new Function() {
+			public double apply(double t) { 
+				double z=Math.exp(-t);
+				z=2/(z+1/z);
+				return z*z; 
+			}
+			public String format(String arg) { return "tanh'("+arg+")"; }
+		};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/ThresholdLog.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/** Log with lower cut-off, then constant */
+public class ThresholdLog extends Function implements DoubleModel
+{	
+	private double	thresh=1;
+	private VParameter param;
+
+	public ThresholdLog() {
+		param = new VParameter( "log.thresh", this);
+	}
+
+	public double get() { return thresh; }
+	public void set(double t) { thresh=t; }
+	public void dispose() { param.dispose(); }
+
+	public double apply(double t) { 
+		if (t>thresh) return Math.log(t/thresh);
+		else return 0;
+	}
+	public String format(String arg) { return "H(log "+arg+"/thresh)"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/functions/WinnerTakeAll.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.functions;
+import  samer.maths.*;
+
+/**
+	This is NOT and element-wise nonlinearity, but
+	rather a function of an entire vector.
+  */
+
+public class WinnerTakeAll extends VectorFunctionOfVector
+{
+	public void apply(double [] y) 
+	{		
+		int jmax=Mathx.argmax(y);
+		Mathx.zero(y);
+		y[jmax]=1;
+	}
+
+	public void apply(double [] y, double [] z) 
+	{		
+		Mathx.zero(z);
+		z[Mathx.argmax(y)]=1;
+	}
+}
+			
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Axes.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,119 @@
+/*
+ *      Axis.java 1.0 98/11/25
+ *
+ * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
+ * modify and redistribute this software in source and binary code form,
+ * provided that i) this copyright notice and license appear on all copies of
+ * the software; and ii) Licensee does not utilize the software in a manner
+ * which is disparaging to Sun.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
+ * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
+ * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
+ * LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
+ * LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
+ * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
+ * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
+ * OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * This software is not designed or intended for use in on-line control of
+ * aircraft, air traffic, aircraft navigation or aircraft communications; or in
+ * the design, construction, operation or maintenance of any nuclear
+ * facility. Licensee represents and warrants that it will not use or
+ * redistribute the Software for such purposes.
+ */
+
+/*
+ * Getting Started with the Java 3D API
+ * written in Java 3D
+ *
+ * This program demonstrates:
+ *   1. writing a visual object class
+ *      In this program, Axis class defines a visual object
+ *      This particular class extends Shape3D
+ *      See the text for a discussion.
+ *   2. Using LineArray to draw 3D lines.
+ */
+
+package samer.j3d;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+    public class Axes extends Shape3D{
+
+	////////////////////////////////////////////
+	//
+	// create axis visual object
+	//
+	public Axes() {
+	
+	    this.setGeometry(createGeometry());
+
+	}
+
+	private Geometry createGeometry(){
+	    // create line for X axis
+            IndexedLineArray axisLines = new IndexedLineArray(18, GeometryArray.COORDINATES, 30);
+
+	    axisLines.setCoordinate( 0, new Point3f(-1.0f, 0.0f, 0.0f));
+	    axisLines.setCoordinate( 1, new Point3f( 1.0f, 0.0f, 0.0f));
+	    axisLines.setCoordinate( 2, new Point3f( 0.9f, 0.1f, 0.1f));
+	    axisLines.setCoordinate( 3, new Point3f( 0.9f,-0.1f, 0.1f));
+	    axisLines.setCoordinate( 4, new Point3f( 0.9f, 0.1f,-0.1f));
+	    axisLines.setCoordinate( 5, new Point3f( 0.9f,-0.1f,-0.1f));
+	    axisLines.setCoordinate( 6, new Point3f( 0.0f,-1.0f, 0.0f));
+	    axisLines.setCoordinate( 7, new Point3f( 0.0f, 1.0f, 0.0f));
+	    axisLines.setCoordinate( 8, new Point3f( 0.1f, 0.9f, 0.1f));
+	    axisLines.setCoordinate( 9, new Point3f(-0.1f, 0.9f, 0.1f));
+	    axisLines.setCoordinate(10, new Point3f( 0.1f, 0.9f,-0.1f));
+	    axisLines.setCoordinate(11, new Point3f(-0.1f, 0.9f,-0.1f));
+	    axisLines.setCoordinate(12, new Point3f( 0.0f, 0.0f,-1.0f));
+	    axisLines.setCoordinate(13, new Point3f( 0.0f, 0.0f, 1.0f));
+	    axisLines.setCoordinate(14, new Point3f( 0.1f, 0.1f, 0.9f));
+	    axisLines.setCoordinate(15, new Point3f(-0.1f, 0.1f, 0.9f));
+	    axisLines.setCoordinate(16, new Point3f( 0.1f,-0.1f, 0.9f));
+	    axisLines.setCoordinate(17, new Point3f(-0.1f,-0.1f, 0.9f));
+
+            axisLines.setCoordinateIndex( 0, 0);
+            axisLines.setCoordinateIndex( 1, 1);
+            axisLines.setCoordinateIndex( 2, 2);
+            axisLines.setCoordinateIndex( 3, 1);
+            axisLines.setCoordinateIndex( 4, 3);
+            axisLines.setCoordinateIndex( 5, 1);
+            axisLines.setCoordinateIndex( 6, 4);
+            axisLines.setCoordinateIndex( 7, 1);
+            axisLines.setCoordinateIndex( 8, 5);
+            axisLines.setCoordinateIndex( 9, 1);
+            axisLines.setCoordinateIndex(10, 6);
+            axisLines.setCoordinateIndex(11, 7);
+            axisLines.setCoordinateIndex(12, 8);
+            axisLines.setCoordinateIndex(13, 7);
+            axisLines.setCoordinateIndex(14, 9);
+            axisLines.setCoordinateIndex(15, 7);
+            axisLines.setCoordinateIndex(16,10);
+            axisLines.setCoordinateIndex(17, 7);
+            axisLines.setCoordinateIndex(18,11);
+            axisLines.setCoordinateIndex(19, 7);
+            axisLines.setCoordinateIndex(20,12);
+            axisLines.setCoordinateIndex(21,13);
+            axisLines.setCoordinateIndex(22,14);
+            axisLines.setCoordinateIndex(23,13);
+            axisLines.setCoordinateIndex(24,15);
+            axisLines.setCoordinateIndex(25,13);
+            axisLines.setCoordinateIndex(26,16);
+            axisLines.setCoordinateIndex(27,13);
+            axisLines.setCoordinateIndex(28,17);
+            axisLines.setCoordinateIndex(29,13);
+
+            return axisLines;
+
+	} // end of Axis createGeometry()
+
+
+    } // end of class Axis
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/Axes.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/FPS.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ImmediateRenderer.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/J3DViewer.java.not/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/J3DViewerImmediate.java.not/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/J3DViewerMorph.java.not/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MatrixPointArray.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MatrixPointArrayAlpha.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MatrixPointArrayRef.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MatrixPoints4D.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MonoView.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/MorphPoints.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/PatchArray.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/PatchArrayAlpha.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Patches.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/PatchesAlpha.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Points3D.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Points3DAlpha.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Points3DRef.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Points4D.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Root.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/StereoView.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/Util.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ViewBase.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ViewGroup.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/j3d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/FPS.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,38 @@
+/* Credit: got this from Particles java 3d demo app
+   by Jeff White (jsw@cs.brown.edu)
+ */
+
+package samer.j3d;
+
+import javax.media.j3d.*;
+import javax.vecmath.*;
+import java.util.Enumeration;
+
+final class FPS extends Behavior {
+
+    protected int nFrames;
+    protected long startTime;
+    protected final WakeupCondition w;
+
+    public FPS(int nFrames){
+        this.nFrames=nFrames;
+        w=new WakeupOnElapsedFrames(nFrames);        
+    }
+
+    public FPS(){
+        this(100);
+    }
+
+    public void initialize(){
+        setSchedulingBounds(new BoundingSphere(new Point3d(),1000));
+        startTime=System.currentTimeMillis();
+        wakeupOn(w);
+    }
+
+    public void processStimulus(Enumeration criteria){
+        long time=System.currentTimeMillis();
+        System.err.println("fps: "+ 1000 * (double) nFrames / (double) (time-startTime));
+        startTime=time;
+        wakeupOn(w);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/ImmediateRenderer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,60 @@
+/*
+*/
+package samer.j3d;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.io.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+public class ImmediateRenderer extends Util implements Task
+{
+	Background	bg;
+	Geometry		geom;
+	Appearance	app;
+	
+	VDouble		speed, scale;
+	float				angle=0;
+				
+	Transform3D			mt=new Transform3D();
+	Canvas3D				canvas;
+	GraphicsContext3D	gc;
+	
+	
+	public ImmediateRenderer(Canvas3D c) throws Exception
+	{		
+		canvas=c;
+		canvas.stopRenderer();
+	
+		speed=new VDouble("speed",0.1);
+		scale=new VDouble("scale",1);
+	}
+
+	public void setGeometry(Geometry g) { geom=g; }
+	public void setAppearance(Appearance a) { app=a; }
+	public void setBackground(Background b) { bg=b; }
+	
+	public void dispose() { speed.dispose(); scale.dispose(); 
+	}
+	
+	public void stopping() { Shell.print("immediate renderer stopping"); }
+	public void starting() { 
+		Shell.print("immediate renderer starting"); 
+		if (gc==null) gc = canvas.getGraphicsContext3D();
+		if (app!=null) gc.setAppearance(app);
+		if (bg!=null) gc.setBackground(bg);
+	}
+
+	public void run() {
+		mt.rotY(angle+=speed.value);
+		mt.setScale(scale.value);
+		gc.setModelTransform(mt);
+		gc.clear();
+		gc.draw(geom);
+		canvas.swap();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/J3DViewer.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,73 @@
+/*
+*/
+package samer.j3d;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.io.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+public class J3DViewer extends Util
+{
+	Shape3D	shape;
+		
+	public J3DViewer(Root root, Matrix P, VVector A) throws Exception
+	{		
+		if (P==null) {
+			Shell.print("creating PointsMatrix");
+			P=new Matrix("PointsMatrix",A.size(),4);
+			new MatrixAgent(P).execute("load",Shell.env());
+		}
+		// create scene
+		{
+			int viewerType=Shell.getInt("viewerType",0);
+			Shape3D shape;
+
+			switch (viewerType) {
+				case 1:
+					shape=new Shape3D(new MatrixPointArrayAlpha(P,A), transparent(0,points()));
+					break;
+				case 2:
+					shape=new Shape3D(new MatrixPoints4D(P,A), transparent(0,points()));
+					break;
+				case 3:
+					Geometry geom=new PatchArrayAlpha(P,A);
+					shape=new Shape3D(geom, rndr(flat(transparent(0,patch())),false));
+					break;
+				default: 
+					shape=new Shape3D(new MatrixPointArray(P,A), points()); 
+					addBackground(root,new Background(new Color3f(0.26f,0.23f,0.35f)));
+					break;
+			}
+		}
+	}
+
+	public javax.media.j3d.Node getShape() { return rotaterise(shape); }
+	
+	private Appearance rndr(Appearance a, boolean ignore)
+	{
+		RenderingAttributes	ra=new RenderingAttributes();
+		ra.setDepthBufferEnable(false);
+		ra.setIgnoreVertexColors(ignore);
+		a.setRenderingAttributes(ra);
+		return a;
+	}
+
+
+	private static Group rotaterise(javax.media.j3d.Node n)
+	{
+		TransformGroup	tg = new TransformGroup();
+		TransformGroup tg2=new TransformGroup();
+
+		mouseRotate(tg);
+		mouseTranslate(tg);
+		mouseZoom(tg);
+		addRotator(tg2,Shell.getInt("rotation.period",10000));
+		tg.addChild(n);
+		tg2.addChild(tg);
+		return tg2;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/J3DViewerImmediate.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,90 @@
+/*
+*/
+package samer.j3d;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.io.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+public class J3DViewerImmediate extends Util implements Task
+{
+	Root			root=new Root();
+	Background	bg;
+	Geometry		geom;
+	Appearance	app;
+	Viewer		V;
+
+	TaskList		tasks;
+	VDouble		speed, scale;
+	GraphicsContext3D	gc;
+	Transform3D		mt=new Transform3D();
+	Canvas3D			canvas;
+	float				angle=0;
+				
+	public J3DViewerImmediate(Matrix P, VVector A) throws Exception
+	{		
+		if (P==null) {
+			Shell.print("creating PointsMatrix");
+			P=new Matrix("PointsMatrix",A.size(),3);
+			new MatrixAgent(P).execute("load",Shell.env());
+		}
+		// create scene
+		bg=new Background(new Color3f(0.26f,0.23f,0.35f));
+		// geom=new MatrixPointArrayAlpha(P,A);
+		// app=transparent(0,points(new Appearance()));
+		geom= // new MatrixPointArray(P,A);
+				new MatrixPoints4D(P,A); 
+		app=transparent(0,points());
+		V=new Viewer("particles");
+		// remember to stop canvas renderers
+	
+	
+		root.addChild(V);
+		root.compile();
+		root.golive();
+
+		// Shell.registerAgent(this);
+		// Shell.exposeCommands(this);
+
+
+		Shell.push(V.node);
+		speed=new VDouble("speed",0.1);
+		scale=new VDouble("scale",1);
+		Shell.pop();
+
+		canvas=V.V.canvas;
+		canvas.stopRenderer();
+
+		tasks=(TaskList)Shell.get("taskList");
+		tasks.addTask(this);
+	}
+
+	public void stopping() { Shell.print("view stopping"); }
+	public void starting() { 
+		Shell.print("view starting"); 
+		if (gc==null) gc = canvas.getGraphicsContext3D();
+		gc.setAppearance(app);
+		// gc.setBackground(bg);
+	}
+
+	public void run() {
+		mt.rotY(angle+=speed.value);
+		mt.setScale(scale.value);
+		gc.clear();
+		gc.setModelTransform(mt);
+		gc.draw(geom);
+		canvas.swap();
+	}
+
+	public void dispose()
+	{
+		// Shell.deregisterAgent(this);
+		tasks.removeTask(this);
+		V.dispose();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/J3DViewerMorph.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,152 @@
+/*
+		hello6.java
+
+		Construct universe without using SimpleUniverse 
+		utility class - this puts together the view
+		group explicitly.
+
+		Now has dynamically creatable views.
+		Have to construct views on BranchGroups so they
+		can be added while universe is live?	
+ */
+package samer.j3d;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.io.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+import java.util.Enumeration;
+
+public class J3DViewerMorph extends Util implements Agent
+{
+	Root			root=new Root();
+	Switch		switcher;
+	Morph			morph;
+	Viewer		V;
+	Matrix		P,P2;
+	Appearance	app=points(new Appearance());
+	Behavior		morpher;
+					
+	public J3DViewerMorph(VVector A) throws Exception
+	{		
+		Shell.print("creating PointsMatrix");
+
+		P=new Matrix("PointsMatrix",A.size(),3);
+		new MatrixAgent(P).execute("load",Shell.env());
+		P2=new Matrix("PointsMatrix2",A.size(),3);
+		new MatrixAgent(P2).execute("load",Shell.env());
+
+		// create scene
+		addBackground(root,new Background(new Color3f(0.26f,0.23f,0.35f)));
+
+		GeometryArray geoms[] = {
+			new MatrixPointArray(P2,A),
+			new MatrixPointArray(P,A)
+		};
+
+		morph=new Morph(geoms,app);
+		morph.setCapability(Morph.ALLOW_WEIGHTS_WRITE);
+		morpher=new MorphBehavior();
+		morpher.setSchedulingBounds(getBounds());
+
+		switcher=new Switch();
+		switcher.addChild(new Shape3D(geoms[1], app));
+		switcher.addChild(morph);
+		switcher.setCapability(Switch.ALLOW_SWITCH_WRITE);
+		switcher.setWhichChild(0);
+
+		// root.addChild(rotaterise(morph));
+		root.addChild(morpher);
+		root.addChild(rotaterise(switcher));
+
+		V=new Viewer("particles");
+	
+		root.addChild(V);
+		root.addChild(new FPS(200));
+		root.compile();
+		root.golive();
+
+		Shell.registerAgent(this);
+		Shell.exposeCommands(this);
+
+		V.V.startView();
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("switch").add("morph"); }
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("switch")) { 
+			switcher.setWhichChild(X._int(env.datum(),0));
+		} else if (cmd.equals("morph")) {
+		}
+	}
+	
+	public Task getTask() { return V.V; }
+	
+	private static Group rotaterise(javax.media.j3d.Node n)
+	{
+		TransformGroup	tg = new TransformGroup();
+//		TransformGroup tg2=new TransformGroup();
+
+		mouseRotate(tg);
+		mouseTranslate(tg);
+		mouseZoom(tg);
+//		addRotator(tg,Shell.getInt("rotation.period",10000));
+		tg.addChild(n);
+		// tg.addChild(tg2);
+		return tg;
+	}
+
+	public class MorphBehavior extends Behavior 
+	{
+		private WakeupCriterion nextframe;
+		private WakeupCriterion trigger;
+		private	double t, weights[];
+
+		public MorphBehavior() {
+			trigger = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
+			nextframe = new WakeupOnElapsedFrames(1);
+			weights = new double[2];
+		}
+
+		public void initialize() { 
+			Shell.print("behavior init");
+			t=0; this.wakeupOn(trigger); 
+		}
+
+		public void processStimulus(Enumeration criteria)
+		{
+			if (criteria.nextElement().equals(trigger)){
+				Shell.print("morphing");
+
+				t=0;
+				weights[0]=1;
+				weights[1]=0;
+				morph.setWeights(weights);
+				wakeupOn(nextframe);
+
+			} else { 
+				t += 0.01; 
+				if (t < 1){
+
+					weights[0]=1-t;
+					weights[1]=t;
+					morph.setWeights(weights);
+					wakeupOn(nextframe);
+
+				} else { 
+					weights[0]=0;
+					weights[1]=1;
+					morph.setWeights(weights);
+
+					Shell.print("finished morphing");
+					wakeupOn(trigger);
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MatrixPointArray.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,78 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class MatrixPointArray extends PointArray implements Observer
+{
+	int			N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public MatrixPointArray(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new float[3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double [] a=A.array();
+		double	  k=K.value;
+
+		for (int i=0, j=0; i<N; i++,j+=3) {
+			float ai=(float)(a[i]*k);
+			carray[j]=ai;
+			carray[j+1]=0.8f*ai;
+			carray[j+2]=0.4f*ai;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MatrixPointArrayAlpha.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,85 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class MatrixPointArrayAlpha extends PointArray implements Observer
+{
+	int			N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public MatrixPointArrayAlpha(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new float[4*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		{
+			double [] a=A.array();
+			for (int i=0; i<N; i++) {
+				a[i]=1;
+				carray[4*i]=1;
+				carray[4*i+1]=0.8f;
+				carray[4*i+2]=0.4f;
+			}
+		}
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double [] a=A.array();
+		double	  k=K.value;
+
+		for (int i=0, j=3; i<N; i++,j+=4) {
+			float ai=(float)(a[i]*k);
+			carray[j]=ai;
+		}
+		setColors(0,carray);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MatrixPointArrayRef.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,74 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class MatrixPointArrayRef extends PointArray implements Observer
+{
+	int			N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+
+	GeometryUpdater	updater;
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public MatrixPointArrayRef(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), BY_REFERENCE | COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new float[3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_REF_DATA_WRITE);
+
+		{
+			double [] a=A.array();
+			for (int i=0; i<N; i++) a[i]=1;
+		}
+
+		updater = new GeometryUpdater() {
+			public void updateData(Geometry g)
+			{
+				// load colours
+				double [] a=A.array();
+				double	  k=K.value;
+
+				for (int i=0, j=0; i<N; i++,j+=3) {
+					float ai=(float)(a[i]*k);
+					carray[j]=ai;
+					carray[j+1]=0.8f*ai;
+					carray[j+2]=0.4f*ai;
+				}
+			}
+		};
+
+		updater.updateData(this);
+
+		setColorRefFloat(carray);
+		setCoordRefDouble(P.getRowPackedCopy());
+
+		A.addObserver(this);
+/*
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+ */
+	}
+
+
+	public void update(Observable o, Object a) { updateData(updater); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MatrixPoints4D.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,80 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import java.awt.Color;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class MatrixPoints4D extends PointArray implements Observer
+{
+	int			N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+
+	Color4f		carray[];
+
+	public MatrixPoints4D(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new Color4f[N];
+		for (int i=0; i<N; i++) carray[i]=new Color4f();
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+
+			// choose color according to 4th dimension
+			carray[i].set(Color.getHSBColor((float)(row[3]*0.3)+0.16f,1f,1f));
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+			carray[i].w=ai;
+		}
+		setColors(0,carray);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MonoView.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+/**
+
+ */
+package samer.j3d;
+
+import samer.core.*;
+//import samer.core.util.swing.MenuBuilder;
+import javax.media.j3d.*;
+
+
+public class MonoView extends ViewBase
+{
+	Canvas3D		c;
+	Shell.Window	w;
+
+	public MonoView()
+	{
+		c=createCanvas();
+		c.setMonoscopicViewPolicy(CYCLOPEAN_EYE_VIEW);
+		w=createWindow(c,"centre");
+		// MenuBuilder.showCommands(this,c,null);
+	}
+
+	public void dispose() {
+		w.dispose();
+		super.dispose();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/MorphPoints.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,108 @@
+package samer.j3d;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.io.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+import java.util.Enumeration;
+
+public class MorphPoints extends Util implements Agent
+{
+	Switch		switcher;
+	Morph		morph;
+	Matrix		P1,P2;
+	Appearance	app=points();
+	Behavior		morpher;
+					
+	public MorphPoints(Root root, Matrix P1, Matrix P2, VVector A) throws Exception
+	{		
+		Shell.print("creating PointsMatrix");
+
+		this.P1=P1;
+		this.P2=P2;
+
+		GeometryArray geoms[] = {
+			new Points3D(P2,A),
+			new Points3D(P1,A)
+		};
+
+		morph=new Morph(geoms,app);
+		morph.setCapability(Morph.ALLOW_WEIGHTS_WRITE);
+		morpher=new MorphBehavior();
+		morpher.setSchedulingBounds(getBounds());
+
+		switcher=new Switch();
+		switcher.addChild(new Shape3D(geoms[1], app));
+		switcher.addChild(morph);
+		switcher.setCapability(Switch.ALLOW_SWITCH_WRITE);
+		switcher.setWhichChild(0);
+
+		// root.addChild(rotaterise(morph));
+		root.addChild(morpher);
+		root.addChild(switcher);
+
+		Shell.exposeCommands(this);
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("switch").add("morph"); }
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("switch")) { 
+			switcher.setWhichChild(X._int(env.datum(),0));
+		} else if (cmd.equals("morph")) {
+		}
+	}
+	
+	public class MorphBehavior extends Behavior 
+	{
+		private WakeupCriterion nextframe;
+		private WakeupCriterion trigger;
+		private	double t, weights[];
+
+		public MorphBehavior() {
+			trigger = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);
+			nextframe = new WakeupOnElapsedFrames(1);
+			weights = new double[2];
+		}
+
+		public void initialize() { 
+			Shell.print("behavior init");
+			t=0; this.wakeupOn(trigger); 
+		}
+
+		public void processStimulus(Enumeration criteria)
+		{
+			if (criteria.nextElement().equals(trigger)){
+				Shell.print("morphing");
+
+				t=0;
+				weights[0]=1;
+				weights[1]=0;
+				morph.setWeights(weights);
+				wakeupOn(nextframe);
+
+			} else { 
+				t += 0.01; 
+				if (t < 1){
+
+					weights[0]=1-t;
+					weights[1]=t;
+					morph.setWeights(weights);
+					wakeupOn(nextframe);
+
+				} else { 
+					weights[0]=0;
+					weights[1]=1;
+					morph.setWeights(weights);
+
+					Shell.print("finished morphing");
+					wakeupOn(trigger);
+				}
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/PatchArray.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,98 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class PatchArray extends QuadArray implements Observer
+{
+	int			N;	// number of patches
+	Matrix		P;	// positions and sizes of patches
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+	VDouble		L;  // scaling factor for sizes
+
+	float		carray[];	// array for holding colours
+
+	public PatchArray(Matrix points, VVector activities)
+	{
+		super(4*points.getRowDimension(), COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+		L=new VDouble("patch.size",1);
+
+		carray=new float[4*3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		L.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	private double quad[] = new double[12];
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		double		l=L.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			double x1=row[0]-l*row[1];
+			double x2=row[0]+l*row[1];
+			double y1=row[3]-l*row[4];
+			double y2=row[3]+l*row[4];
+
+			quad[0] = x1;	quad[1] = y1;	quad[2] = 0;
+			quad[3] = x1;	quad[4] = y2;	quad[5] = 0;
+			quad[6] = x2;	quad[7] = y2;	quad[8] = 0;
+			quad[9] = x2;	quad[10]= y1;	quad[11]= 0;
+
+			// set 4 vertices of quad
+			setCoordinates(j,quad,0,4); j+=4;
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/PatchArrayAlpha.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,102 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class PatchArrayAlpha extends QuadArray implements Observer
+{
+	int			N;	// number of patches
+	Matrix		P;	// positions and sizes of patches
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+	VDouble		L;  // scaling factor for sizes
+
+	Color4f		carray[];	// array for holding colours
+
+	public PatchArrayAlpha(Matrix points, VVector activities)
+	{
+		super(4*points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+		L=new VDouble("patch.size",1);
+
+		carray=new Color4f[4*N];
+		for (int i=0; i<4*N; i+=4) 
+			carray[i+3]=
+				carray[i+2]=
+				carray[i+1]=
+				carray[i]=new Color4f(1f,1f,1f,1f);
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		L.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	private double quad[] = new double[12];
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		double		l=L.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			double x1=row[0]-l*row[1];
+			double x2=row[0]+l*row[1];
+			double y1=row[3]-l*row[4];
+			double y2=row[3]+l*row[4];
+
+			quad[0] = x1;	quad[1] = y1;	quad[2] = 0;
+			quad[3] = x1;	quad[4] = y2;	quad[5] = 0;
+			quad[6] = x2;	quad[7] = y2;	quad[8] = 0;
+			quad[9] = x2;	quad[10]= y1;	quad[11]= 0;
+
+			// set 4 vertices of quad
+			setCoordinates(j,quad,0,4); j+=4;
+
+			// choose color according to energy?
+			// carray[i].set(Color.getHSBColor((float)(row[3]*0.3)+0.16f,1f,1f));
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+			carray[j].w = ai; j+=4;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Patches.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,98 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class Patches extends QuadArray implements Observer
+{
+	int			N;	// number of patches
+	Matrix		P;	// positions and sizes of patches
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+	VDouble		L;  // scaling factor for sizes
+
+	float		carray[];	// array for holding colours
+
+	public Patches(Matrix points, VVector activities)
+	{
+		super(4*points.getRowDimension(), COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+		L=new VDouble("patch.size",1);
+
+		carray=new float[4*3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		L.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	private double quad[] = new double[12];
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		double		l=L.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			double x1=row[0]-l*row[1];
+			double x2=row[0]+l*row[1];
+			double y1=row[3]-l*row[4];
+			double y2=row[3]+l*row[4];
+
+			quad[0] = x1;	quad[1] = y1;	quad[2] = 0;
+			quad[3] = x1;	quad[4] = y2;	quad[5] = 0;
+			quad[6] = x2;	quad[7] = y2;	quad[8] = 0;
+			quad[9] = x2;	quad[10]= y1;	quad[11]= 0;
+
+			// set 4 vertices of quad
+			setCoordinates(j,quad,0,4); j+=4;
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+			carray[j]=ai; carray[j+1]=ai;	carray[j+2]=ai; j+=3;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/PatchesAlpha.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,102 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class PatchesAlpha extends QuadArray implements Observer
+{
+	int				N;	// number of patches
+	Matrix		P;	// positions and sizes of patches
+	VVector		A;	// scalar activations
+	VDouble	K;  // scaling factor for activations
+	VDouble	L;  // scaling factor for sizes
+
+	Color4f		carray[];	// array for holding colours
+
+	public PatchesAlpha(Matrix points, VVector activities)
+	{
+		super(4*points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+		L=new VDouble("patch.size",1);
+
+		carray=new Color4f[4*N];
+		for (int i=0; i<4*N; i+=4) 
+			carray[i+3]=
+				carray[i+2]=
+				carray[i+1]=
+				carray[i]=new Color4f(1f,1f,1f,1f);
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		L.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	private double quad[] = new double[12];
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		double		l=L.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			double x1=row[0]-l*row[1];
+			double x2=row[0]+l*row[1];
+			double y1=row[3]-l*row[4];
+			double y2=row[3]+l*row[4];
+
+			quad[0] = x1;	quad[1] = y1;	quad[2] = 0;
+			quad[3] = x1;	quad[4] = y2;	quad[5] = 0;
+			quad[6] = x2;	quad[7] = y2;	quad[8] = 0;
+			quad[9] = x2;	quad[10]= y1;	quad[11]= 0;
+
+			// set 4 vertices of quad
+			setCoordinates(j,quad,0,4); j+=4;
+
+			// choose color according to energy?
+			// carray[i].set(Color.getHSBColor((float)(row[3]*0.3)+0.16f,1f,1f));
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+		int			j=0;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+			carray[j].w = ai; j+=4;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Points3D.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,78 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class Points3D extends PointArray implements Observer
+{
+	int				N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble	K;  // scaling factor for activations
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public Points3D(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1.0);
+
+		carray=new float[3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double [] a=A.array();
+		double	  k=K.value;
+
+		for (int i=0, j=0; i<N; i++,j+=3) {
+			float ai=(float)(a[i]*k);
+			carray[j]=ai;
+			carray[j+1]=0.8f*ai;
+			carray[j+2]=0.4f*ai;
+		}
+		setColors(0,carray);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Points3DAlpha.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,92 @@
+package	samer.j3d;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class Points3DAlpha extends PointArray implements Observer
+{
+	int				N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VMap			map; // from activity to intensity
+//	VDouble	K;  // scaling factor for activations
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public Points3DAlpha(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+//		K=new VDouble("scale",1.0);
+		map=new VMap(new LinearMap());	
+		Shell.registerViewable(map);
+
+		carray=new float[4*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		{
+			double [] a=A.array();
+			for (int i=0; i<N; i++) {
+				a[i]=1;
+				carray[4*i]=1;
+				carray[4*i+1]=1;
+				carray[4*i+2]=1;
+			}
+		}
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double [] a=A.array();
+		IMap		imap=map.getMap();
+//		double	  k=K.value;
+
+		for (int i=0, j=3; i<N; i++,j+=4) {
+//			float ai=(float)(a[i]*k);
+			float ai=(float)(imap.map(a[i]));
+			carray[j]=ai;
+		}
+		setColors(0,carray);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Points3DRef.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,74 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class Points3DRef extends PointArray implements Observer
+{
+	int				N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble	K;  // scaling factor for activations
+
+	GeometryUpdater	updater;
+
+	float		carray[];	// array for holding colours
+//	Color3f		carray[];
+
+	public Points3DRef(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), BY_REFERENCE | COORDINATES | COLOR_3);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new float[3*N];
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_REF_DATA_WRITE);
+
+		{
+			double [] a=A.array();
+			for (int i=0; i<N; i++) a[i]=1;
+		}
+
+		updater = new GeometryUpdater() {
+			public void updateData(Geometry g)
+			{
+				// load colours
+				double [] a=A.array();
+				double	  k=K.value;
+
+				for (int i=0, j=0; i<N; i++,j+=3) {
+					float ai=(float)(a[i]*k);
+					carray[j]=ai;
+					carray[j+1]=0.8f*ai;
+					carray[j+2]=0.4f*ai;
+				}
+			}
+		};
+
+		updater.updateData(this);
+
+		setColorRefFloat(carray);
+		setCoordRefDouble(P.getRowPackedCopy());
+
+		A.addObserver(this);
+/*
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+ */
+	}
+
+
+	public void update(Observable o, Object a) { updateData(updater); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Points4D.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,80 @@
+package	samer.j3d;
+
+import samer.core.types.*;
+import samer.maths.*;
+import java.util.*;
+import java.awt.Color;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class Points4D extends PointArray implements Observer
+{
+	int			N;	// number of points
+	Matrix		P;	// 3d positions of points
+	VVector		A;	// scalar activations
+	VDouble		K;  // scaling factor for activations
+
+	Color4f		carray[];
+
+	public Points4D(Matrix points, VVector activities)
+	{
+		super(points.getRowDimension(), COORDINATES | COLOR_4);
+
+		N=points.getRowDimension();
+		P=points;
+		A=activities;
+		K=new VDouble("scale",1);
+
+		carray=new Color4f[N];
+		for (int i=0; i<N; i++) carray[i]=new Color4f();
+
+		// set capabilities for subsequent updates
+		setCapability(ALLOW_COORDINATE_WRITE);
+		setCapability(ALLOW_COLOR_WRITE);
+
+		updatePoints();
+		updateActivities();
+
+		A.addObserver(this);
+		P.addObserver(new Observer () {
+			public void update(Observable o, Object a) {
+				updatePoints();
+			}
+		});
+	}
+
+
+	public void update(Observable o, Object a)
+	{
+		updateActivities();
+	}
+
+	public void updatePoints()
+	{
+		// load points into point array
+		double [][] PA=P.getArray();
+		double []	row;
+
+		for (int i=0; i<N; i++) {
+			row=PA[i];
+			setCoordinate(i,row);
+
+			// choose hue according to 4th dimension
+			carray[i].set(Color.getHSBColor((float)(row[3]*0.3)+0.16f,1f,1f));
+		}
+	}
+
+	public void updateActivities()
+	{
+		// load colours
+		double []	a=A.array();
+		double		k=K.value;
+
+		for (int i=0; i<N; i++) {
+			float ai=(float)(a[i]*k);
+			carray[i].w=ai;
+		}
+		setColors(0,carray);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Root.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,15 @@
+package samer.j3d;
+import	javax.media.j3d.*;
+
+public class Root extends BranchGroup
+{
+	protected VirtualUniverse	U=new VirtualUniverse();
+	protected Locale			L=new Locale(U);
+
+	public void activate() { L.addBranchGraph(this); }
+	// capabilities:
+	public Root() {
+		setCapability(ALLOW_CHILDREN_EXTEND);
+		setCapability(ALLOW_CHILDREN_WRITE);
+	}
+}		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/StereoView.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,36 @@
+/**
+
+ */
+package samer.j3d;
+
+import samer.core.*;
+//import samer.core.util.swing.MenuBuilder;
+import javax.media.j3d.*;
+
+
+public class StereoView extends ViewBase
+{
+	Canvas3D		c1, c2;
+	Shell.Window	w1, w2;
+
+	public StereoView()
+	{
+		c1=createCanvas();
+		c1.setMonoscopicViewPolicy(LEFT_EYE_VIEW);
+		w1=createWindow(c1,"left");
+
+		c2=createCanvas();
+		c2.setMonoscopicViewPolicy(RIGHT_EYE_VIEW);
+		w2=createWindow(c2,"right");
+
+		// MenuBuilder.showCommands(this,c1,null);
+		// MenuBuilder.showCommands(this,c2,null);
+	}
+
+	public void dispose() {
+		w1.dispose();
+		w2.dispose();
+		super.dispose();
+	}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/Util.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,225 @@
+package samer.j3d;
+
+import samer.core.*;
+import java.awt.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+import com.sun.j3d.utils.behaviors.keyboard.*;
+import com.sun.j3d.utils.behaviors.mouse.*;
+import com.sun.j3d.utils.geometry.*;
+
+public class Util
+{
+	private static Bounds bounds=new BoundingSphere(new Point3d(0,0,0),1000);
+	public static void setBounds(Bounds b) { bounds=b; }
+	public static Bounds getBounds() { return bounds; }
+
+
+	// -------------- TransformGroup behviours ------------------
+
+	public static TransformGroup mouseRotate(TransformGroup tg)
+	{
+        MouseRotate m = new MouseRotate(readwrite(tg));
+        m.setSchedulingBounds(bounds);
+        tg.addChild(m);
+		return tg;
+	}
+
+	public static TransformGroup mouseTranslate(TransformGroup tg)
+	{
+        MouseTranslate m = new MouseTranslate(readwrite(tg));
+        m.setSchedulingBounds(bounds);
+        tg.addChild(m);
+		return tg;
+	}
+
+	public static TransformGroup mouseZoom(TransformGroup tg)
+	{
+        MouseZoom m = new MouseZoom(readwrite(tg));
+        m.setSchedulingBounds(bounds);
+        tg.addChild(m);
+		return tg;
+	}
+
+	public static void addKeyNavigator(Group g, TransformGroup tg)
+	{
+		// readwrite(tg);
+        KeyNavigatorBehavior keynav = new KeyNavigatorBehavior(tg);
+        keynav.setSchedulingBounds(bounds);
+        g.addChild(keynav);
+	}
+
+	public static TransformGroup addRotator(int period, TransformGroup tg)
+	{
+		Alpha alpha = new Alpha(-1, period);
+		Behavior rotator = new RotationInterpolator(alpha, writable(tg));
+		rotator.setSchedulingBounds(bounds);
+		tg.addChild(rotator);
+		return tg;
+	}
+
+	// -------------- Lighting ------------------
+
+	public static Light color(Light l, Color3f c) { l.setColor(c); return l; }
+	public static Light directionalLight(double x, double y, double z)
+	{
+        DirectionalLight l = new DirectionalLight();
+		l.setDirection(-(float)x,-(float)y,-(float)z);
+        l.setInfluencingBounds(bounds);
+		return l;
+	}
+
+	public static Light ambientLight() 
+	{
+        AmbientLight a = new AmbientLight();
+        a.setInfluencingBounds(bounds);
+		return a;
+	}
+
+	public static Light pointLight(double x, double y, double z)
+	{
+        PointLight l = new PointLight();
+        l.setInfluencingBounds(bounds);
+		l.setPosition((float)x,(float)y,(float)z);
+		l.setAttenuation(0,0,1);
+		return l;
+	}
+
+	public static Background background(double r, double g, double b)
+	{
+		Background bg=new Background((float)r,(float)g,(float)b);
+		bg.setApplicationBounds(bounds);
+		return bg;
+	}
+
+
+	public static ViewPlatform	 writable(ViewPlatform vp) {
+        vp.setCapability(ViewPlatform.ALLOW_POLICY_WRITE); return vp; 
+	}
+	public static TransformGroup writable(TransformGroup tg) {
+        tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); return tg; 
+	}
+	public static TransformGroup readwrite(TransformGroup tg) {
+        tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); 
+        tg.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); 
+		return tg; 
+	}
+
+	// ----------------- Appearances ------------------
+
+	// basic appearances
+	
+	public static Appearance points()
+	{
+		Appearance a = new Appearance();
+		PolygonAttributes pa = new PolygonAttributes();
+		pa.setPolygonMode(PolygonAttributes.POLYGON_POINT);
+		pa.setCullFace(PolygonAttributes.CULL_NONE);
+		a.setPolygonAttributes(pa);
+		a.setPointAttributes(
+			new PointAttributes((float)Shell.getDouble("pointsize",3), false));
+		return a;
+	}
+
+	public static Appearance wireframe()
+	{
+		Appearance a = new Appearance();
+		PolygonAttributes polyAttrib = new PolygonAttributes();
+		polyAttrib.setPolygonMode(PolygonAttributes.POLYGON_LINE);
+		if (!Shell.getBoolean("backfacecull",false)) {
+			polyAttrib.setCullFace(PolygonAttributes.CULL_NONE);
+		}
+		a.setPolygonAttributes(polyAttrib);
+		a.setLineAttributes(
+			new LineAttributes((float)Shell.getDouble("linewidth",2),
+						LineAttributes.PATTERN_SOLID,true));
+
+		return a;
+    }
+
+    public static Appearance shadedwireframe() 
+	{
+        Appearance a = new Appearance();
+        PolygonAttributes polyAttrib = new PolygonAttributes();
+        polyAttrib.setPolygonMode(PolygonAttributes.POLYGON_LINE);
+        a.setPolygonAttributes(polyAttrib);
+		a.setLineAttributes(new LineAttributes(2f,LineAttributes.PATTERN_SOLID,false));
+
+        Material material = new Material();
+        material.setDiffuseColor(new Color3f(.7f, 0.6f, 0.9f));
+		material.setShininess(128);
+        a.setMaterial(material);
+        return a;
+    }
+
+	public static Appearance offsetPolygon() 
+	{		
+		Appearance a = new Appearance();
+		PolygonAttributes polyAttrib = new PolygonAttributes();
+		polyAttrib.setPolygonOffset(2f);
+		a.setPolygonAttributes(polyAttrib);
+
+		return a;
+	}
+	
+	public static Appearance patches()
+	{
+		Appearance a = new Appearance();
+		PolygonAttributes polyAttrib = new PolygonAttributes();
+		polyAttrib.setCullFace(PolygonAttributes.CULL_NONE);
+		a.setPolygonAttributes(polyAttrib);
+
+		// I think this is for transparent polygons
+		// see depthBufferFreezeTransparent in view
+		RenderingAttributes	ra=new RenderingAttributes();
+		ra.setDepthBufferEnable(false);
+		ra.setIgnoreVertexColors(false);
+		a.setRenderingAttributes(ra);
+		
+		return a;
+	}
+
+	// modifiers
+	
+	public static Appearance color(Color3f c, Appearance a)
+	{
+		ColoringAttributes colorAttrib=new ColoringAttributes();
+		colorAttrib.setColor(c);
+		a.setColoringAttributes(colorAttrib);
+		return a;
+	}
+
+	public static Appearance flat(Appearance a)
+	{
+		ColoringAttributes colorAttrib=new ColoringAttributes();
+		colorAttrib.setShadeModel(ColoringAttributes.SHADE_FLAT);
+		a.setColoringAttributes(colorAttrib);
+		return a;
+	}
+
+	public static Appearance flat(Color3f c, Appearance a)
+	{
+		ColoringAttributes colorAttrib=new ColoringAttributes();
+		colorAttrib.setShadeModel(ColoringAttributes.SHADE_FLAT);
+		colorAttrib.setColor(c);
+		a.setColoringAttributes(colorAttrib);
+		return a;
+	}
+
+	public static Appearance alpha(double t, Appearance a)
+	{
+		a.setTransparencyAttributes(
+			new TransparencyAttributes(TransparencyAttributes.BLENDED,(float)t));
+		return a;
+	}
+
+    public static Appearance material(Color3f diff, Color3f spec, int shin, Appearance a) 
+	{
+        Material material = new Material();
+        material.setDiffuseColor(diff);
+        material.setSpecularColor(spec);
+		material.setShininess(shin);
+        a.setMaterial(material);
+        return a;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/ViewBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,118 @@
+/**
+		ViewGroup.java
+
+		A View branch group containing a ViewPlatform
+		and associated Views, Canvas3Ds and Windows to
+		hold the canvases.  Can be added dynamically
+		to a live universe.
+
+		Parameters:
+			initial placement
+			autostart canvas?
+			autostart view?
+			keyboard navigator?
+			various view policies
+
+		Requirements:
+			must be placable (hence TransformGroup and ViewPlatform)
+			must be Node so addable to universe
+			renderable:
+				view.renderOnce()
+				view.startView()
+				view.stopView()
+				canvas.startRenderer()
+				canvas.stopRenderer()
+				... ?
+			disposable: cleans up properly
+			must have accessible View and Canvas objects
+			must manage multiple canvases for stereo
+
+ */
+package samer.j3d;
+
+import samer.core.*;
+import samer.tools.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class ViewBase extends javax.media.j3d.View implements Agent, WindowListener, Task
+{
+	public ViewBase()
+	{
+		stopView(); // seems  be started during constructor
+
+		PhysicalBody body=new PhysicalBody();
+		PhysicalEnvironment env=new PhysicalEnvironment();
+		double d=Shell.getDouble("eyeSeparation",0.01); // units??
+		body.setLeftEyePosition(new Point3d(-d,0,0));
+		body.setRightEyePosition(new Point3d(d,0,0));
+		body.setNominalEyeHeightFromGround(0);
+
+		// canvas.getStereoAvailable()
+		// canvas.setStereoEnable
+		// queryProperties
+
+		setPhysicalBody(body);
+		setPhysicalEnvironment(env);
+
+		setWindowEyepointPolicy(View.RELATIVE_TO_WINDOW);
+		//setWindowResizePolicy(View.VIRTUAL_WORLD);
+		//setLocalEyeLightingEnable(true);
+		//setWindowMovementPolicy(View.VIRTUAL_WORLD);
+		setFrontClipDistance(Shell.getDouble("front",0.5));
+		setBackClipDistance(Shell.getDouble("back",20));
+		setDepthBufferFreezeTransparent(true);
+		// Shell.registerAgent(this);
+	}
+
+	 
+	public Canvas3D createCanvas() {
+		GraphicsConfigTemplate tmp=new GraphicsConfigTemplate3D();
+		Shell.trace("Graphics configuration template: "+tmp);
+		
+		Canvas3D canvas=new Canvas3D(
+			GraphicsEnvironment.getLocalGraphicsEnvironment().
+				getDefaultScreenDevice().getBestConfiguration(tmp));
+		addCanvas3D(canvas);
+		return canvas;
+	}
+
+	public Shell.Window createWindow(Canvas3D canvas, String name) {
+		Shell.Window w=Shell.getWindow(name);
+		w.container().setLayout(new java.awt.BorderLayout());
+		w.container().add(canvas);
+		w.addWindowListener(this);
+		w.expose();
+		// expose commands for agent
+		return w;
+	}
+	
+	public void dispose() {
+		stopView();
+		// Shell.deregisterAgent(this);
+	}
+
+	public void getCommands(Agent.Registry r) {
+		r.add("start").add("stop").add("render");
+	}
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("render")) renderOnce();
+		else if (cmd.equals("start")) { Shell.trace("view staring"); startView(); }
+		else if (cmd.equals("stop")) { Shell.trace("view stopping"); stopView(); }
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() { if (!isViewRunning()) renderOnce(); }
+
+	public void windowOpened(WindowEvent e) {}
+	public void windowClosed(WindowEvent e) { }
+	public void windowClosing(WindowEvent e) { dispose(); }
+	public void windowActivated(WindowEvent e) {	}
+	public void windowDeactivated(WindowEvent e) {}
+	public void windowIconified(WindowEvent e) {}
+	public void windowDeiconified(WindowEvent e) {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/j3d/ViewGroup.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,70 @@
+/**
+		ViewGroup.java
+
+		A View branch group containing a ViewPlatform
+		and associated Views, Canvas3Ds and Windows to
+		hold the canvases.  Can be added dynamically
+		to a live universe.
+
+		Parameters:
+			initial placement
+			autostart canvas?
+			autostart view?
+			keyboard navigator?
+			various view policies
+
+		Requirements:
+			must be placable (hence TransformGroup and ViewPlatform)
+			must be Node so addable to universe
+			renderable:
+				view.renderOnce()
+				view.startView()
+				view.stopView()
+				canvas.startRenderer()
+				canvas.stopRenderer()
+				... ?
+			disposable: cleans up properly
+			must have accessible View and Canvas objects
+			must manage multiple canvases for stereo
+
+ */
+package samer.j3d;
+
+import samer.core.*;
+import javax.media.j3d.*;
+import javax.vecmath.*;
+
+
+public class ViewGroup extends BranchGroup
+{
+	TransformGroup	VT;
+	ViewPlatform		VP;
+	ViewBase			V;
+
+	public void lookFrom(Point3d eye, Vector3d up)
+	{
+		// view platform placement
+		Transform3D		t=new Transform3D();
+		t.lookAt(eye, new Point3d(0,0,0), up);
+		t.invert();
+		VT.setTransform(t);
+	}
+
+	public ViewGroup()
+	{
+		VT=new TransformGroup();
+		VP=new ViewPlatform();
+		lookFrom(
+			new Point3d(X.doubleArray(Shell.getString("lookfrom","(0,1,8)"),3)),
+			new Vector3d(0,1,0)
+		);
+		VT.addChild(VP);
+		addChild(VT);
+
+		// addChild(new FPS(200));
+		// setCapability(ALLOW_DETACH);
+		// setCapability(ALLOW_CHILDREN_WRITE);
+	}
+
+	public void attachView(View v) { v.attachViewPlatform(VP); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,50 @@
+/ClippedDivide.java/1.1.1.1/Fri Dec 10 03:29:27 2004//
+/ComplexVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Constant.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Difference.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Function.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/FunctionMap.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/FunctionOfGenerator.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/FunctionOfVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/FunctionPlotter.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Generator.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Identity.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/IntArrayEditor.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/IteratorImageSource.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/LineTrace.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Linear.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Mat.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatEditor.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Mathx.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Matrix.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixAgent.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixImage.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixImageSource.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixImageSourceF.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixPanel.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixPlotter.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixTImageSource.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixTImageSourceF.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixTimesVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MatrixTransposeTimesVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Neg.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Ops.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Parameter.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Probe.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Product.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/RowColumn.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/SparseMatrix.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Sum.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VFunction.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VGenerator.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Vec.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorEditor.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorFunctionOfVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorPlotter.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorPlusEqualsVector.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorTimesEqualsScalar.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/VectorTrace.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Zero.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+D/opt////
+D/random////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/maths
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/ClippedDivide.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,43 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  samer.tools.*;
+
+public class ClippedDivide extends AnonymousTask
+{
+	VVector		out;
+	double []	_top, _bot, _F;
+	int			l;
+
+	public ClippedDivide(VVector num, VVector denom) throws Exception 
+	{ 
+		l = num.size(); // length of input
+		out = new VVector("F",l); // output
+
+		// add task to compute the desired frequency response
+		_top = num.array();
+		_bot = denom.array();
+		_F   = out.array();
+	}
+
+	public VVector output() { return out; }
+
+	public void run() {
+		for (int i=0; i<l; i++) {
+			_F[i] = (_top[i]<_bot[i]) ? _top[i]/_bot[i] : 1;
+			// Weiner filter version would be
+			// t1=z[i]*z[i]; t2=x[i]-z[i];
+			// _F[i]=t1/(t1 + t2*t2); ??
+		}
+		out.changed(); 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/ComplexVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	ComplexVector.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class ComplexVector
+{
+	public double	real[];
+	public double	imag[];
+	public int		length;
+
+	public ComplexVector(int n) {
+		real = new double[n];
+		imag = new double[n];
+		length=n;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Constant.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+
+public class Constant extends Function implements Generator
+{
+	double k;
+
+	public Constant() { k=Shell.getInt("constant",1); }
+	public Constant(double k) { this.k=k; }
+	public void dispose() {}
+
+	// Generator
+	public double next() { return k; }
+	public void   next(double [] x) { for (int i=0; i<x.length; i++) x[i]=k; }
+
+	// Function
+	public double apply(double t) { return k; }
+	public Function derivative() { return new Zero(); }
+
+	public String toString() { return "Constant("+k+")"; }
+	public String format(String arg) { return X.string(k); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Difference.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Difference implements Generator
+{
+	Generator g1, g2;
+
+	public Difference( Generator g1, Generator g2) { this.g1=g1; this.g2=g2; }
+
+	public void   dispose() { g1.dispose(); g2.dispose(); }
+	public double next() { return g1.next()-g2.next(); }
+	public void   next(double [] x) { 
+		g1.next(x);
+		for (int i=0; i<x.length; i++) x[i]-=g2.next(); 
+	}
+
+	public String toString() { return g1.toString()+"-"+g2; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Function.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,38 @@
+/*
+ *	Function.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+  *		Defines a real-valued function of a single real variable.
+  *		
+  */
+
+public abstract class Function
+{
+	public abstract double apply(double in);
+
+	/** apply function to each element of in, placing result in out */
+	public void apply(double [] in, double [] out) {
+		for (int i=0; i<in.length; i++) out[i]=apply(in[i]);
+	}
+
+	/** apply function in place, to each element of inout */
+	public void apply(double [] inout) {
+		for (int i=0; i<inout.length; i++) inout[i]=apply(inout[i]);
+	}
+
+	public void dispose() {}
+
+	public Function inverse() { throw new Error("no inverse"); }
+	public Function derivative() { throw new Error("no derivative"); }
+	public abstract String format(String arg);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/FunctionMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import samer.core.util.*;
+
+/**
+	This class maps a given interval of real numbers
+	to the interval [0,1], returning either the real
+	number, or converting it to an integer between 0
+	and a given value (defaults to 256).
+ */
+
+public class FunctionMap extends IMap
+{
+	Function f, finv;
+
+	public FunctionMap(int m, Function fn) {
+		setIntRange(m);
+		f=fn; finv=fn.inverse();
+		setDomain(0,1);
+	}
+
+	public void setFunction(Function fn) {
+		double t1=getDomainMin();
+		double t2=getDomainMax();
+		f=fn; finv=fn.inverse();
+		setDomain(t1,t2);
+	}
+
+	public double getDomainMin() { return finv.apply(super.getDomainMin()); }
+	public double getDomainMax() { return finv.apply(super.getDomainMax()); }
+	public void setDomain( double t1, double t2)	{
+		super.setDomain( f.apply(t1), f.apply(t2));
+	}
+
+	public final double map( double t) { return super.map(f.apply(t)); }
+	public final int clipInt( double t) { return super.clipInt(f.apply(t)); }
+	public final int toInt( double t) { return super.toInt(f.apply(t)); }
+	public double inverse(double t) { return finv.apply(super.inverse(t)); }
+	public double inverseFromInt(int i) { return finv.apply(super.inverseFromInt(i)); }
+}
+
+
+
+
+
+	
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/FunctionOfGenerator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+package samer.maths;
+
+public class FunctionOfGenerator implements Generator
+{
+	Generator	g;
+	Function		f;	
+
+	public FunctionOfGenerator(Function f, Generator g) {
+		this.f=f; this.g=g;
+	}
+
+	public double next() { return f.apply(g.next()); }
+	public void next(double [] x) {
+		g.next(x);
+		f.apply(x);
+	}
+
+	public void dispose() { f.dispose(); g.dispose(); }
+	public String toString() { return f.format(g.toString()); }
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/FunctionOfVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/*
+ *	FunctionOfVector.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+  *		Defines a real-valued function of a vector
+  *		
+  */
+public abstract class FunctionOfVector
+{
+	public abstract double apply(double [] in);
+	public void dispose() {}
+
+	public VectorFunctionOfVector derivative() { return null; }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/FunctionPlotter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,220 @@
+/*
+ *	FunctionPlotter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import samer.maths.Vec.Iterator;
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.types.*;
+import samer.core.Agent.*;
+import samer.tools.*;
+import java.util.*;
+import java.awt.*;
+
+public class FunctionPlotter extends Plotter implements Agent, Observer
+{
+	private VFunction	vfunc;
+	private VMap		vmap, xvmap;
+	private boolean	autoscale=false;
+	private int			type;
+	private Pen			pen;
+	private int w, h;
+
+	Node		node=null;
+	int		numPoints;
+
+	public final static int LINE=0;
+	public final static int STEP=1;
+	public final static int FILL=2;
+	public final static int FILL3D=3;
+	public final static int CLOSED=4;
+	public final static int STEPS=5;
+											  
+	public FunctionPlotter(VFunction vf) 
+	{ 
+		vfunc=vf; 
+		node=Shell.env().node(); 
+
+		w = Shell.getInt("width",240);
+		h = Shell.getInt("height",120);
+		type = Shell.getInt("type", LINE);
+
+		setAxes( XAXIS|YAXIS); 
+		// pen = getPen();
+
+		Shell.push("y");
+		vmap=new VMap(ymap);
+		Shell.pop();
+
+		Shell.push("x");
+		xvmap=new VMap(xmap);
+		Shell.pop();
+
+		vmap.addObserver(this);
+		xvmap.addObserver(this);
+		ymap = vmap.getMap();
+		xmap = xvmap.getMap();
+
+		numPoints = Shell.getInt("numpoints",256);
+
+		// attach commands from this agent to this Viewer
+		exposeCommands( this);
+		exposeCommands( vmap);
+		exposeCommands( xvmap);
+		Shell.registerAgent(this);
+	}
+
+	protected void realized() 
+	{ 
+		super.realized();
+		vfunc.addObserver(this);
+	}
+
+	// .............. Viewer bits .............................
+
+	public void update(Observable o, Object s) 
+	{ 
+		if (s==this) return; // &&&
+		if (s==Viewable.DISPOSING) {
+			Shell.releaseViewer(this);
+		} else if (o==vmap) {	
+			if (s==VMap.NEW_MAP) ymap = vmap.getMap();
+			autoscale(); repaint();
+		} else if (o==xvmap) {	
+			if (s==VMap.NEW_MAP) xmap = xvmap.getMap();
+			autoscale(); repaint();
+		} else if (vfunc==o) {
+			autoscale(); repaint();
+		}
+	}
+ 
+	public void detach()
+	{
+		Shell.deregisterAgent(this);
+		if (node!=null) { node=null; }
+		if (vfunc!=null) { vfunc.deleteObserver(this); vfunc=null; }
+		super.detach();
+	}
+
+	// .............. Agent bits ..............................
+
+	public void getCommands(Registry r)
+	{	
+		r.add("update").add("points");
+		r.add("line").add("box").add("fill").add("fill3d").add("steps");
+		r.add("scale").add("autoscale",autoscale);
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if      (c.equals("points"))	{ numPoints=X._int(env.datum(),numPoints); repaint(); }
+		else if (c.equals("line"))		{ type=LINE; repaint(); }
+		else if (c.equals("box"))		{ type=CLOSED; repaint(); }
+		else if (c.equals("fill"))		{ type=FILL; repaint(); }
+		else if (c.equals("fill3d"))	{ type=FILL3D; repaint(); }
+		else if (c.equals("steps"))	{ type=STEPS; repaint(); }
+		else if (c.equals("scale"))	{ scale(); repaint(); }
+		else if (c.equals("autoscale")) {
+			autoscale = X._bool(env.datum(),!autoscale);
+			if (autoscale) { scale(); repaint(); }
+		}
+	}
+
+	private class FunctionIterator implements Iterator {
+		int i=0, n=numPoints;
+		double x=xmap.inverse(0);
+		double dx=(xmap.inverse(1)-x)/n;
+		Function function=vfunc.getFunction();
+
+		public boolean more() { return i<=n; }
+		public double  next() { 
+			double y=function.apply(x); 
+			x+=dx; i++; return y;
+		}
+	}
+
+	// ................ functionality ...........................
+
+	public void autoscale() { if (autoscale) scale(); }
+	public void scale()
+	{
+		double	max, min, x;
+
+		Iterator i=new FunctionIterator();
+
+		min=max=i.next();
+		while (i.more()) {
+			x=i.next();
+			if (x>max) max=x;
+			if (x<min) min=x;
+		}
+
+		if (ymap instanceof LinearMap) {
+			// leave some space
+			double delta=max-min;
+			min -= 0.1*delta;
+			max += 0.1*delta;
+		} else if (ymap instanceof LogMap) {	
+			// somewhat arbitrarily...			
+			if (min==0) min=max/10000;
+		}
+
+		vmap.setDomain(min,max);
+		vmap.changed(this);
+	}
+
+	synchronized public void paint( Graphics g)
+	{
+		super.paint(g); // draw axes or whatever
+
+		FunctionIterator i=new FunctionIterator();
+		double	x, y;
+
+		pen=getPen(g);
+		// pen.assert();
+		switch (type) {
+
+			case LINE:
+
+				x=i.x;
+				pen.moveto(x,i.next());
+				while (i.more()) {
+					x=i.x;
+					pen.lineto(x,i.next());
+				}
+				break;
+
+			case FILL3D:
+
+				while (i.more()) {
+					pen.moveto(i.x,0); y=i.next();
+					pen.abs(i.x,y).rectify();
+					pen.fill3DRect(true);
+				}
+				break;
+
+			case FILL:
+
+				while (i.more()) {
+					pen.moveto(i.x,0); y=i.next();
+					pen.abs(i.x,y).rectify();
+					pen.fillRect();
+				}
+				break;
+
+		}
+	}
+
+	public Dimension getPreferredSize() {
+		return new Dimension(w,h);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Generator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,23 @@
+/*
+ *	Generator.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+		This defines an object that generates a sequence of numbers.
+  */
+
+public interface Generator
+{
+	double next();				// return next number
+	void   next(double[] x);	// return next lot of numbers
+	void   dispose();			// clean up any resources used
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Identity.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Identity extends Function
+{
+	public void apply(double [] u, double [] y) { System.arraycopy(u,0,y,0,u.length); }
+	public void apply(double [] u) { return; }
+	public double apply(double t) { return t; }
+	public String format(String arg) { return arg; }
+	public Function inverse() { return this; }
+	public Function derivative() { return new Constant(1); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/IntArrayEditor.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,42 @@
+package samer.maths;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import java.util.*;
+
+public class IntArrayEditor extends BaseViewer
+{
+	int []	x;
+	VInteger index, value;
+
+	public IntArrayEditor(int [] x)
+	{
+		super(new Observable());
+
+		this.x = x;
+		index = new VInteger("index",0,0);
+		value = new VInteger("value",0,0);
+		index.setRange(0,x.length-1);
+		value.setRange(0,2*x[0]);
+		panel().setName("int array");
+		panel().setLayout(new StackLayout());
+		add(index);
+		add(value);
+		index.addObserver(this);
+		value.addObserver(this);
+	}
+
+	public void update(Observable obs, Object arg)
+	{
+		if (obs==index) {
+			value.setRange(0,2*x[index.value]);
+			value.value = x[index.value];
+			value.changed(this);
+		} else if (obs==value) {
+			if (arg!=this) {
+				x[index.value]=value.value;
+			}
+		} else super.update(obs,arg);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/IteratorImageSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,53 @@
+/*
+ *	IteratorImageSource.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+import  java.awt.image.*;
+
+/**
+	This is an image source that gets its values
+	from a Vec (vector) via its Vec.Iterator - ie,
+	it does not need access to an array of value
+  */
+
+public class IteratorImageSource extends ImageSourceBase
+{
+	Vec			vec;
+	byte []		buf;
+
+	public IteratorImageSource( Vec v) { this( v, v.size(), 1); }
+	public IteratorImageSource( Vec v, int w, int h)
+	{
+		vec		= v;
+		width	= w;
+		height	= h;
+		buf		= new byte[v.size()];
+	}
+
+
+	protected int getHints() {
+		return  ImageConsumer.TOPDOWNLEFTRIGHT 
+				| ImageConsumer.COMPLETESCANLINES
+				| ImageConsumer.SINGLEPASS;
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{
+		Vec.Iterator it=vec.iterator(); 
+
+		for (int i=0; it.more(); i++) {
+			buf[i] = (byte)map.clipInt(it.next());
+		}
+		ic.setPixels(0, 0, width, height, model, buf, 0, width);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/LineTrace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,45 @@
+/*
+ *	MatrixTrace.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  samer.tools.*;
+import  java.util.*;
+
+/**
+	This viewer outputs all the elements of a row or column
+	to a trace (graph of value against time step). All elements
+	of the row are column are consecutively output at each time
+	step.
+  */
+
+public class LineTrace extends Trace implements Observer
+{
+	Observable	obs;
+	Vec			src;
+
+	public LineTrace( Observable o, Vec v) { obs=o; src=v; }
+
+	public void attach() { obs.addObserver(this); }
+	public void detach() { obs.deleteObserver(this); super.detach(); }
+
+	public void update(Observable o, Object s) 
+	{
+		if (s==Viewable.DISPOSING) {
+			Shell.releaseViewer(this);
+		} else if (obs==o) {
+			Vec.Iterator i=src.iterator();
+			while (i.more()) next(i.next());
+		}
+	}
+	protected void next(double x) {} // !! fix this
+	protected void realized() { super.realized(); attach(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Linear.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,42 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+
+
+public class Linear extends Function
+{	
+	private double	a, b;
+
+	public Linear() { this( Shell.getDouble("a",1), Shell.getDouble("b",0)); }
+	public Linear(double a, double b) { this.a = a; this.b = b; }
+
+	public double apply(double t) { return a*t+b; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) { x[i]*=a;  x[i]+=b; }
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=a*x[i]+b;
+	}
+	public String format(String arg) { 
+		StringBuffer buf=new StringBuffer();
+		if (b!=0) {
+			buf.append(X.string(b));
+			if (a!=0) buf.append(" + ").append(X.string(a)).append(arg);
+		} else {
+			if (a!=0) buf.append(X.string(a)).append(arg);
+			else return "0";
+		}
+		return buf.toString();
+	}
+
+	public Function derivative() { return new Constant(a); }
+	public Function inverse() { return new Linear(-a/b,1/b); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Mat.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/*
+ *	Mat.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+	This is an interface for an element-wise addressable
+	matrix. Not generally used for computation, but for
+	user interface purposes.
+ */
+
+public interface Mat {
+
+	int			width();
+	int			height();
+	double		get(int i, int j);
+	void		set(int i, int j, double t);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatEditor.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,142 @@
+/*
+ *	MatEditor.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+
+/**
+	This is a mouse event handler that interprets mouse clicks
+	to edit a matrix. It assumes that it is handling mouse
+	events for a component the contains some representation of the 
+	matrix that is arranged in rows and columns, just like the
+	matrix itself (it doesn't have to be an image). The window
+	relative coordinates are simply mapped to a matrix element 
+	address.
+  */
+
+public class MatEditor extends MouseAdapter 
+	implements MouseMotionListener, Agent
+{
+	Component	canvas;
+	Mat			M;
+	VDouble		setto;
+	Observable	obs;
+	int			lasti=-1, lastj=-1;
+	double		dragval=0;
+	boolean		add=false;
+	boolean		b1down=false;
+
+	public MatEditor( Mat m, Component c, Observable v, Viewer vwr)
+	{
+		M=m; 
+		canvas=c;
+		setto = new VDouble("button1",1,0);
+		canvas.addMouseListener(this);
+		canvas.addMouseMotionListener(this);
+		obs=v;
+
+		vwr.exposeCommands(this);
+	}
+
+	public void getCommands(Agent.Registry r) { r.add("add",add); }
+	public void execute(String cmd, Environment env) {	
+		add=X._bool(env.datum(),!add); 
+	}
+
+	private void handle(MouseEvent e)
+	{
+		// get position in matrix
+		int i = (M.height()*e.getY())/canvas.getHeight();
+		int j = (M.width()*e.getX())/canvas.getWidth();
+
+		// check bounds
+		if (i<0 || i>=M.height()) return;
+		if (j<0 || j>=M.width()) return;
+
+		// correct for vertical flip
+		i=M.height()-i-1;
+
+		if (!add) {
+			if (i==lasti && j==lastj) return;
+			M.set(i,j,dragval);
+		} else M.set(i,j,M.get(i,j)+dragval);
+
+		lasti=i;
+		lastj=j;
+		obs.notifyObservers(new Point(j,i)); // Point as x,y into image raster
+	}
+
+	public void mouseMoved(MouseEvent e) {}
+	public void mouseDragged(MouseEvent e) { if (b1down) { handle(e); e.consume(); } }
+	public void mousePressed(MouseEvent e)
+	{
+		int f = e.getModifiers();
+
+		if ((f & InputEvent.BUTTON1_MASK)!=0) b1down=true;
+		if (b1down) {
+
+			// if ((f&(InputEvent.BUTTON2_MASK|InputEvent.BUTTON3_MASK))==0) {
+			if (!e.isControlDown()) {
+				dragval=setto.value;
+			} else {
+				dragval=add ? -setto.value : 0;
+				// canvas.addMouseListener(this); // to catch mouse up!
+				// b2down=true;
+			}
+
+			lasti=lastj=-1;
+			handle(e);
+			e.consume();
+
+		}	
+	}
+
+	public void mouseReleased(MouseEvent e)
+	{
+		int f = e.getModifiers();
+
+		if ((f & InputEvent.BUTTON1_MASK)!=0) {
+			// button 1 up - stop all dragging
+			b1down=false;
+
+			//if (b2down) {
+			//	canvas.removeMouseListener(this);
+			//	b2down=false;
+			//}
+			e.consume();
+		} /* else {
+
+			// something else up
+			if (b1down) {
+
+				if ((f&(InputEvent.BUTTON2_MASK|InputEvent.BUTTON3_MASK))!=0) {
+					// button 2 up
+					dragval=setto.value;
+					b2down=false;
+					canvas.removeMouseListener(this);
+					handle(e);
+				} 
+				e.consume();
+
+			} else {
+				Shell.print("button up while button 1 not down?");
+			}
+		} */
+	}
+
+	public void detach() { setto.dispose(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Mathx.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,269 @@
+/*
+ *	Mathx.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+	A Class full of static functions, mainly for manipulating
+	double arrays.
+  */
+
+public class Mathx
+{
+	private static double [] zeros = null;
+	private static int zlength = 0;
+
+	public double [] doubleArray(int n) { return new double[n]; }
+	
+	/** set to zeros */
+	public static void zero(double [] x)
+	{
+		if (zlength<x.length) {
+			zlength = x.length;
+			zeros = new double[zlength];
+			for (int i=0; i<zlength; i++) zeros[i]=0;
+		}
+		System.arraycopy(zeros,0,x,0,x.length);
+	}
+
+	/** set all to given value */
+	public static void setAll(double [] x, double a) {
+		for (int i=0; i<x.length; i++) x[i]=a;
+	}
+	
+	/** log in place */
+	public static void log(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=Math.log(x[i]);
+	}
+
+	/** negate in place */
+	public static void negate(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=-x[i];
+	}
+
+	/** negate to y: x[i]=y[i] for all i */
+	public static void negate(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=-x[i];
+	}
+
+	/** subtract: x[i]=y[i]-z[i] for all i */
+	public static void sub(double [] x, double [] y, double [] z) {
+		for (int i=0; i<x.length; i++) x[i]=y[i]-z[i];
+	}
+
+	public static void sub(int n, double [] x, double [] y, double [] z) {
+		for (int i=0; i<n; i++) x[i]=y[i]-z[i];
+	}
+
+	/** subtract in place y: x[i]-=y[i] for all i */
+	public static void sub(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) x[i]-=y[i];
+	}
+	
+	public static void sub(int n, double [] x, double [] y) {
+		for (int i=0; i<n; i++) x[i]-=y[i];
+	}
+
+	
+	/** subtract scalar in place y: x[i]-=y for all i */
+	public static void sub(double [] x, double y) {
+		for (int i=0; i<x.length; i++) x[i]-=y;
+	}
+
+	/** add two arrays: x[i]=y[i]+z[i] for all i */
+	public static void add(double [] x, double [] y, double [] z) {
+		for (int i=0; i<x.length; i++) x[i]=y[i]+z[i];
+	}
+
+	/** add in place y: x[i]+=y[i] for all i */
+	public static void add(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) x[i]+=y[i];
+	}
+
+	public static void add(int n, double [] x, double [] y) {
+		for (int i=0; i<n; i++) x[i]+=y[i];
+	}
+
+	/** add scalar in place y: x[i]+=y for all i */
+	public static void add(double [] x, double y) {
+		for (int i=0; i<x.length; i++) x[i]+=y;
+	}
+
+	/** return sum of elements in x */
+	public static double sum(double [] x)
+	{
+		double total=0;
+		for (int i=0; i<x.length; i++) total+=x[i];
+		return total;
+	}
+
+	public static void muladd(int n, double [] x, double [] y, double k) {
+		for (int i=0; i<n; i++) x[i]+=k*y[i];
+	}
+
+	/** return product of elements in x */
+	public static double prod(double [] x)
+	{
+		double total=1;
+		for (int i=0; i<x.length; i++) total*=x[i];
+		return total;
+	}
+
+	/** multiply by scalar in place: x[i] *=k */
+	public static void mul(double [] x, double k) {
+		for (int i=0; i<x.length; i++) x[i]*=k;
+	}
+
+	public static void mul(int n, double [] x, double k) {
+		for (int i=0; i<n; i++) x[i]*=k;
+	}
+
+	/** scalar multiply  x[i] = k*y[i] */
+	public static void mul(double [] x, double [] y, double k) {
+		for (int i=0; i<x.length; i++) x[i]=k*y[i];
+	}
+
+	/** elementwise multiply in place: x[i] *=y[i] */
+	public static void mul(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) x[i]*=y[i];
+	}
+
+	/** elementwise multiply  x[i] =y[i]*z[i] */
+	public static void mul(double [] x, double [] y, double [] z) {
+		for (int i=0; i<x.length; i++) x[i]=y[i]*z[i];
+	}
+
+	/** elementwise divide in place: x[i] /=y[i] */
+	public static void div(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) x[i]/=y[i];
+	}
+
+	/** elementwise divide: x[i]=y[i]/z[i] */
+	public static void div(double [] x, double [] y, double [] z) {
+		for (int i=0; i<x.length; i++) x[i]=y[i]/z[i];
+	}
+
+	/** return maximum element of x */
+	public static double max(double [] x)
+	{
+		double xmax=x[0];
+		for (int i=1; i<x.length; i++) if (x[i]>xmax) xmax=x[i];
+		return xmax;
+	}
+
+	/** return minimum element of x */
+	public static double min(double [] x)
+	{
+		double xmin=x[0];
+		for (int i=1; i<x.length; i++) if (x[i]<xmin) xmin=x[i];
+		return xmin;
+	}
+	
+	/** return index of supremum of elements in x */
+	public static int argmax(double [] x)
+	{
+		double xmax=x[0];
+		int	 imax=0;
+		for (int i=1; i<x.length; i++) {
+			if (x[i]>xmax) { xmax=x[i]; imax=i; }
+		}
+		return imax;
+	}
+
+	/** return dot product of a and b: sum_i a[i]*b[i] */
+	public static double dot( double [] a, double [] b)
+	{
+		double t=0;
+		for (int i=0; i<a.length; i++) t+=a[i]*b[i];
+		return t;
+	}
+
+	/** return 2-norm of a: sum_i a[i]*a[i] */
+	public static double norm2( double [] a)
+	{
+		double t=0;
+		for (int i=0; i<a.length; i++) t+=a[i]*a[i];
+		return t;
+	}
+
+	public static double norm2( int n, double [] a)
+	{
+		double t=0;
+		for (int i=0; i<n; i++) t+=a[i]*a[i];
+		return t;
+	}
+
+	/** copy a to b: b[i]=a[i] */
+	public static void copy( double [] a, double [] b) {
+		System.arraycopy(a,0,b,0,a.length);
+	}
+
+	/** return copy a in new array */
+	public static double [] copy( double [] a) {
+		double [] b = new double[a.length];
+		System.arraycopy(a,0,b,0,a.length);
+		return b;
+	}
+
+	public static double tanh(double t) {
+//		if (t<-24) return -1;
+//		if (t>24) return 1;
+		if (t<0) { double z=Math.exp(2*t); return (z-1)/(z+1); }
+		else     { double z=Math.exp(-2*t); return (1-z)/(1+z); }
+	}
+	
+	public static double atanh(double t) { return Math.log((1+t)/(1-t))/2; }
+	public static double cosh(double t) { double z=Math.exp(-t); return (1/z+z)/2; }
+	public static double sinh(double t) { double z=Math.exp(-t); return (1/z-z)/2; }
+
+	/** matrix multiplication: y[i] = sum_j A[i][j] x[j] */
+	public static void mul( double [] y, double [][]A, double [] x)
+	{
+		int n=y.length;
+		int m=x.length;
+		double [] arow;
+
+		for (int i=0; i<n; i++) {
+			double t=0;
+			arow=A[i];
+			for (int j=0; j<m; j++) t+=arow[j]*x[j];
+			y[i]=t;
+		}
+	}
+
+
+	/** set each elements of a by extracting successive values from g */
+	public static void set( double[] a, Generator g) {
+		g.next(a);
+		// int n=a.length; for (int i=0; i<n; i++) a[i]=g.next();
+	}
+
+	/** increment each element of a by a value extracted from g */
+	public void add( double[] a, Generator g) {
+		int n=a.length; for (int i=0; i<n; i++) a[i]+=g.next();
+	}
+
+	/** set each element using a function of its index */
+	public static void index( double[] a) {
+		for (int i=0; i<a.length; i++) a[i]=(double)i;
+	}
+
+	public static void indexFr( double[] a) {
+		int N=a.length; for (int i=0; i<N; i++) a[i]=(double)i/N;
+	}
+
+	/** set each element using a function of its index */
+	public static void table( double[] a, Function f) {
+		index(a); f.apply(a);
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Matrix.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,318 @@
+/*
+ *	Matrix.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths;
+import	samer.core.*;
+import   samer.core.util.*;
+import	java.util.*;
+import	java.io.*;
+
+/**
+	Represents a bundling of a Jama.Matrix with Viewable bits.
+	Create one of these and you can either keep it invisible,
+	expose its UI yourself, or let the Viewable framework
+	expose a default viewer automatically
+ */
+
+public class Matrix extends Jama.Matrix implements Mat, Saveable
+{
+	Viewable	viewable;
+
+	// ............... Viewable bits .................
+
+	private class Vbl extends Viewable {
+		Vbl(String nm) { super(nm); }
+		Vbl() { super("matrix"); }
+
+		/** returns current Agent if there is one, creates a MatrixAgent if not */
+		public Agent getAgent() {
+			if (super.getAgent()==null) setAgent(new MatrixAgent(Matrix.this));
+			return super.getAgent();
+		}
+
+		public Matrix getMatrix() { return Matrix.this; }
+		public Viewer getViewer()
+		{
+			BaseViewer		vwr = new BaseViewer(this);
+			StringBuffer	buf = new StringBuffer();
+
+			buf.append(getLabel())
+				.append(" (").append(getRowDimension())
+				.append(" by ").append(getColumnDimension())
+				.append(")");
+			vwr.setText(buf.toString());
+
+			return vwr;
+		}
+	}
+
+	public Observable	observable() { return viewable; }
+	public Viewable	viewable() { return viewable; }
+	public boolean		equals(Observable o) { return viewable==o; }
+	public Node		getNode() { return viewable.getNode(); }
+
+	public final void	changed(Object o)	{ viewable.changed(o); }
+	public final void	changed() { viewable.changed(); }
+	public void	addObserver(Observer o) { viewable.addObserver(o); }
+	public void	deleteObserver(Observer o) { viewable.deleteObserver(o); }
+	public void dispose() { viewable.dispose(); }
+
+	public void copyFrom(double[][] src) {
+		double[][] dest=getArray();
+		for (int i=0; i<src.length; i++) {
+			Mathx.copy(src[i],dest[i]);
+			changed();
+		}
+	}
+
+	// ................................................
+
+	public Matrix( String name, int m, int n) { this(name,m,n,1); }
+	public Matrix( String name, int m, int n, int flags) {
+		super(m,n); viewable=new Vbl(name);
+		if (flags==1) Shell.registerViewable(viewable);
+	}
+
+
+	public Matrix( int m, int n) { super(m,n); viewable=new Vbl(); Shell.registerViewable(viewable); }
+	public Matrix( double array[][]) { super(array); viewable=new Vbl(); Shell.registerViewable(viewable); }
+
+	public String toString() {
+		StringBuffer	buf = new StringBuffer();
+
+		buf.append(viewable.getLabel())
+			.append(" (").append(getRowDimension())
+			.append(" by ").append(getColumnDimension())
+			.append(")");
+		return buf.toString();
+	}
+
+	// implement Mat interface
+	public int width() { return getColumnDimension(); }
+	public int height() { return getRowDimension(); }
+
+	public Agent getAgent() { return viewable.getAgent(); }
+
+
+	// ................................................
+	// some useful additions to Matrix functionality
+
+	public void set( Generator g) {
+		for (int i=0; i<m; i++) g.next(A[i]);
+	}
+
+	public void apply( Function f) {
+		for (int i=0; i<m; i++) f.apply(A[i]);
+	}
+
+	public void add( Generator g)
+	{
+		for (int i=0; i<m; i++) {
+			for (int j=0; j<n; j++) {
+				A[i][j]+=g.next();
+			}
+		}
+	}
+
+
+   /** Set to identity matrix */
+
+   public void identity()
+   {
+      for (int i = 0; i < m; i++) {
+         for (int j = 0; j < n; j++) {
+            A[i][j] = (i == j ? 1.0 : 0.0);
+         }
+      }
+   }
+
+	public static Jama.Matrix identity(Jama.Matrix a)
+	{
+		double [][] A=a.getArray();
+		int m=a.getRowDimension();
+		int n=a.getColumnDimension();
+		for (int i = 0; i < m; i++) {
+			for (int j = 0; j < n; j++) {
+				A[i][j] = (i == j ? 1.0 : 0.0);
+			}
+		}
+		return a;
+	}
+	
+   /** Set to zero matrix */
+
+   public void zero() {
+      for (int i = 0; i < m; i++) { Mathx.zero(A[i]); }
+   }
+
+   /** Set to given matrix
+     * (need to make sure both matrices are the same size)
+		@param b the matrix to be copied
+     */
+
+   public void assign( Jama.Matrix b)
+   {
+      double[][] B=b.getArray();
+	  int mmax = B.length>m ? m : B.length;
+	  int nmax = B[0].length>n ? n : B[0].length;
+
+      for (int i = 0; i < mmax; i++) {
+		System.arraycopy(B[i],0,A[i],0,nmax);
+      }
+   }
+
+	// Saveable implementation
+
+	public void load(InputStream in) throws Exception {
+		ObjectInputStream	o=new ObjectInputStream(in);
+		assign((Jama.Matrix)o.readObject());
+		changed();
+	}
+
+	public void save(OutputStream out) throws Exception {
+		ObjectOutputStream	o=new ObjectOutputStream(out);
+		o.writeObject(new Jama.Matrix(getArray()));
+	}
+
+	public void write(Writer wr) throws Exception {
+		print(new PrintWriter(wr,true), new DoubleFormat(16),4);
+	}
+
+	public void read(Reader rdr) throws Exception {
+		Jama.Matrix A=Jama.Matrix.read(new BufferedReader(rdr));
+		assign(A);	changed();
+	}
+
+/** Symmetrise in place preserving trace.
+		Will fail if matrix is not square. */
+	public void symmetrise()
+	{
+		double a, _G[][]=getArray();
+		for (int i=0; i<n; i++) {
+			for (int j=i+1; j<n; j++) {
+				a=(_G[i][j]+_G[j][i])/2;
+				_G[i][j]=_G[j][i]=a;
+			}
+		}
+	}
+
+	/** Antisymmetrise in place.
+		Will fail if matrix is not square. */
+	public void antisymmetrise()
+	{
+		double a, _G[][]=getArray();
+		for (int i=0; i<n; i++) {
+			for (int j=i+1; j<n; j++) {
+				a=(_G[i][j]-_G[j][i])/2;
+				_G[i][j]=a;	_G[j][i]=-a;
+			}
+			_G[i][i]=0;
+		}
+	}
+
+	/** return log(abs(det(this))) (must be square matrix) */
+	
+	public double logdet() {
+		int n=getRowDimension();
+		double [][] x=lu().getU().getArray();
+		double L=0;
+		for (int i=0; i<n; i++) L+= Math.log(Math.abs(x[i][i]));
+		return L;
+	}
+	// ................................................
+
+	public Vec getRow(int k) { return new Row(k); }
+	public Vec getColumn(int k) { return new Column(k); }
+
+	public static Vec getDiagonal(final Jama.Matrix A) {
+		return new Vec() {
+			double[][] x=A.getArray();
+
+			public int size() { return x.length; }
+			public double[] array() { return null; }
+			public Mat mat() {
+				return new Mat() {
+					// Mat implementation
+					public int width() { return x.length; }
+					public int height() { return 1; }
+					public double get( int i, int j) { return x[j][j]; }
+					public void set( int i, int j, double t) { x[j][j]=t; }
+				};
+			}
+			public Iterator iterator() {
+				return new Iterator() {
+					int i=0, n=x.length;
+					public void rewind() { i=0; }
+					public boolean more() { return i<n; }
+					public double next() {
+						double y=x[i][i]; i++; return y;
+					}
+				};
+			}
+		};
+	}
+
+	private abstract class Slice implements Vec, Vec.Iterator
+	{
+		protected int i, j, n;
+
+		Slice(int n, int j) { this.n=n; this.j=j; i=0; }
+
+		// Vec implementation
+		public final Vec.Iterator	iterator() { i=0; return this; }
+		public final int	size() { return n; }
+		public final void	rewind() { i=0; }
+		public final boolean more() { return i<n; }
+	}
+
+	private class Row extends Slice {
+		double []	x;
+
+		public Row(int rownum) {
+			super(Matrix.this.getColumnDimension(),rownum);
+			x=getArray()[rownum];
+		}
+
+		public final double		next() { return x[i++]; }
+		public final double[]	array() { return x; }
+		public final Mat		mat() {
+			return new Mat() {
+				// Mat implementation
+				public int width() { return Row.this.n; }
+				public int height() { return 1; }
+				public double get( int i, int j) { return x[j]; }
+				public void set( int i, int j, double t) { x[j]=t; }
+			};
+		}
+	}
+
+	private class Column extends Slice {
+		double [][]	x;
+		int			j;
+
+		public Column(int colnum) {
+			super(Matrix.this.getRowDimension(),colnum);
+			x=getArray();
+			j=colnum;
+		}
+
+		public final double next() { return x[i++][j]; }
+		public final double[] array() { return null; }
+		public final Mat		mat() {
+			return new Mat() {
+				public final int width() { return Column.this.n; }
+				public final int height() { return 1; }
+				public final double get( int i, int k) { return x[k][j]; }
+				public final void set( int i, int k, double t) { x[k][j]=t; }
+			};
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixAgent.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,89 @@
+/*
+ *	MatrixAgent.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import  samer.core.*;
+import  samer.core.Agent.*;
+
+/**
+	Provides a load of useful commands for dealing with
+	a matrix.
+  */
+
+public class MatrixAgent extends Saver
+{
+	private Matrix M;
+
+	public MatrixAgent(Matrix m) { super(m,m.getNode()); M=m; }
+
+	public void getCommands(Registry r)
+	{
+		r.add("zeros").add("identity").add("multiply");
+		r.group(); super.getCommands(r); r.group();
+		r.add("image").add("editor");
+		r.add("rowcolumn");
+	}
+
+	public String toString() { return "MatrixAgent("+M+")"; }
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("identity"))	{ M.identity(); M.changed(); }
+		else if (cmd.equals("zeros"))	{ M.zero();     M.changed(); }
+		else if (cmd.equals("multiply")) {
+			double K=X._double(env.datum("factor"),1);
+			M.timesEquals(K);
+			M.changed();
+		} else if (cmd.equals("rowcolumn")) {
+			new RowColumn(M);
+
+		} else if (cmd.equals("plotter")) {
+
+			pushNode("plotter");
+			Viewer vwr = new MatrixPlotter(M);
+			Shell.expose(vwr, "window");
+			Shell.pop();
+
+		} else if (cmd.equals("image")) {
+
+			pushNode("image");
+
+			Viewer vwr = new MatrixImage(M);
+			Shell.expose(vwr, "window");
+			Shell.pop();
+
+		} else if(cmd.equals("editor")) {
+
+			pushNode("editor");
+			Shell.expose((Viewer)(new MatrixImageEditor(M)),"window");
+			Shell.pop();
+		} else super.execute(cmd,env);
+	}
+
+	private void pushNode(String nm) { Shell.push(new Node(nm,M.getNode())); }
+}
+
+class MatrixImageEditor extends MatrixImage
+{
+	MatEditor	editor;
+
+	public MatrixImageEditor(Matrix A) {
+		super(A);
+		editor = new MatEditor(A,this,A.observable(),this);
+	}
+
+	public void detach()
+	{
+		editor.detach();
+		super.detach();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixImage.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,58 @@
+/*
+ *	MatrixImage.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  samer.tools.*;
+import  java.awt.Color;
+
+public class MatrixImage extends ImageViewer
+{
+	Matrix		M;
+	Node		n;
+
+	public MatrixImage( Matrix M)
+	{
+		// should make an intelligent choice of 
+		// image source depending on shape of matrix
+		super(new MatrixImageSource( M, true),M.observable());
+		this.n=Shell.env().node();
+		this.M=M;
+	}
+
+	public void scale()
+	{
+		double	max, min, x;
+		int		n=M.getRowDimension();
+		int		m=M.getColumnDimension();
+
+		min=max=M.get(0,0);
+		for (int	i=0; i<n; i++) {
+			for (int	j=0; j<m; j++) {
+				x=M.get(i,j);
+				if (x>max) max=x;
+				if (x<min) min=x;
+			}
+		}
+
+		getVMap().setDomain(min,max);
+		getVMap().changed(this);
+	}
+
+	public static Viewer getViewerFor(Matrix M)
+	{ 
+		Shell.push(new Node("image",M.getNode()));
+		Viewer vwr = new MatrixImage(M);
+		Shell.pop();
+
+		return vwr;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixImageSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+/*
+ *	MatrixImageSource.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+import  java.awt.image.*;
+import  Jama.Matrix;
+
+/** This matrix image source sends pixels a scan line
+	at a time
+
+	TODO:
+		flip horizontally or vertically
+		flip diagonally
+		replaceable map (ie nonlinear map)
+*/
+
+public class MatrixImageSource extends ImageSourceBase
+{
+	Matrix		matrix;
+	byte []		scanline;
+
+	public MatrixImageSource( Matrix mat) { this(mat,true); }
+	public MatrixImageSource( Matrix mat, boolean fb)
+	{
+		matrix	= mat;
+		width		= mat.getColumnDimension();
+		height	= mat.getRowDimension();
+		scanline	= new byte[width];
+	}
+
+	public void newMatrix(Matrix mat) { matrix=mat; sendPixels();	}
+
+	protected int getHints() {
+		return  ImageConsumer.TOPDOWNLEFTRIGHT 
+				| ImageConsumer.COMPLETESCANLINES
+				| ImageConsumer.SINGLEPASS;
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{
+		double[][] X=matrix.getArray();
+
+		for (int j=height-1; j>=0; j--) {
+			double [] Xj = X[j];
+			for (int i=0; i<width; i++) {
+				scanline[i] = (byte)map.clipInt(Xj[i]);
+			}
+			ic.setPixels(0, height-1-j, width, 1, model, scanline, 0, 1);
+		} 
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixImageSourceF.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+/*
+ *	MatrixImageSourceF.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+import  java.awt.image.*;
+import  Jama.Matrix;
+
+/** This one sends pixels in vertical strips: better for
+	column vectors or very narrow matrices
+ */
+
+public class MatrixImageSourceF extends ImageSourceBase
+{
+	Matrix		matrix;
+	byte []		strip;
+
+	public MatrixImageSourceF( Matrix mat)
+	{
+		matrix	= mat;
+		width		= mat.getColumnDimension();
+		height	= mat.getRowDimension();
+		strip		= new byte[height];
+	}
+
+	public void newMatrix(Matrix mat) { matrix=mat; sendPixels();	}
+
+	protected int getHints() { 
+		if (width==1) {
+			return  ImageConsumer.TOPDOWNLEFTRIGHT 
+					| ImageConsumer.COMPLETESCANLINES
+					| ImageConsumer.SINGLEPASS;
+		} else {
+			return ImageConsumer.RANDOMPIXELORDER | ImageConsumer.SINGLEPASS; 
+		}
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{
+		double[][] X=matrix.getArray();
+
+		for (int i=0; i<width; i++) {
+			for (int j=0; j<height; j++) {
+				strip[height-1-j] = (byte)map.clipInt(X[j][i]);
+			}
+			ic.setPixels(i, 0, 1, height, model, strip, 0, 1);
+		} 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixPanel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,149 @@
+/*
+ *	MatrixPanel.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.core.*;
+
+/**
+	A text based matrix editor
+  */
+
+public class MatrixPanel extends BaseViewer
+	implements FocusListener, ActionListener
+{
+	int			rowdim, coldim;
+	Matrix		M;
+	Field[][]	TF;
+	boolean		isvalid;
+	String		errmsg;
+	boolean		readonly;
+	Color			validColor, badColor;
+
+	public MatrixPanel( Matrix A) { this(A,true); }
+	public MatrixPanel( Matrix A, boolean qedit) 
+	{
+		super(A.observable());
+
+		int m = A.getRowDimension();
+		int n = A.getColumnDimension();
+
+		readonly = !qedit;
+
+		/* initialize to all 0 */
+		int i, j;
+		setLayout(new GridLayout(m,n,2,2));
+		rowdim = m; coldim = n;
+		M = A;
+
+		TF = new Field[m][n];
+		isvalid = true;
+		for (i=0; i < m; i++) {
+			for (j=0; j < n; j++){
+				TF[i][j] = new Field(6);
+				TF[i][j].setEditable(qedit);
+				add(TF[i][j]);
+			}
+		}
+
+		validColor = TF[0][0].getForeground();
+		badColor   = Color.red;
+		update(null,null);
+	}
+
+	public void update(java.util.Observable o, Object src) 
+	{
+		if (src!=this) { // &&&
+			for (int i=0; i < rowdim; i++) {
+				for (int j=0; j< coldim; j++) {
+					TF[i][j].setForeground(validColor);
+					TF[i][j].setText(numfmt._format(M.get(i,j)));
+					TF[i][j].edited=false;
+				}
+			}
+		}
+		super.update(o,src);
+	}
+
+
+	boolean Validate(boolean qcheck)
+	{
+		/* check validity of all edited entries and change M
+		   If qcheck is true, check all entries
+		*/
+		String newtext="";
+		isvalid = true;
+		for (int i=0; i < rowdim; i++) {
+			for (int j=0; j < coldim; j++) {
+				if (TF[i][j].edited || qcheck) {
+					try {
+						newtext = TF[i][j].getText().trim();
+						double newv = numfmt._parse(newtext);
+						M.set(i,j,newv);
+						TF[i][j].setForeground(validColor);
+						TF[i][j].edited = false;
+						TF[i][j].repaint();
+					} catch( Exception ex) {
+						TF[i][j].setForeground(badColor);
+						TF[i][j].repaint();
+						isvalid = false;
+						if (ex instanceof NumberFormatException) 
+							errmsg = "Invalid number:"+newtext;
+						else errmsg = ex.getMessage();
+						Shell.print(errmsg);
+					}
+				}
+			}
+		}
+
+		if (isvalid) M.changed(this);
+		return isvalid;
+	} 
+      
+	public void focusGained( FocusEvent e) {}
+	public void focusLost( FocusEvent e) { 
+		if (!readonly) { 
+			Component c=e.getComponent();
+			if (c instanceof Field) {
+				((Field)c).edited=true; 
+				Validate(false); 
+			}
+		}
+	}
+	public void actionPerformed( ActionEvent e)
+	{
+		// could mean return pressed in a field
+		Object c=e.getSource();
+		if (c instanceof Field) {
+			((Field)c).edited=true; 
+			Validate(false); 
+		}
+	}
+
+	static DoubleFormat numfmt=new DoubleFormat(3);
+
+	class Field extends TextField
+	{
+		boolean edited=false;
+
+		public Field(int cols)
+		{ 
+			super(cols); 
+			this.addFocusListener(MatrixPanel.this);
+			this.addActionListener(MatrixPanel.this);
+		}
+	}  
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixPlotter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,53 @@
+/*
+ *	MatrixPlotter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  java.util.*;
+
+/**
+	A Vector plotter that gets its data from a matrix
+	row or column
+  */
+
+public class MatrixPlotter extends VectorPlotter
+{
+	RowColumn	src;
+
+	public MatrixPlotter(final Matrix A)
+	{
+		super(A.observable());
+		src = new RowColumn(new Node("rowcolumn"), A);
+		setVec(src.getVec());
+		exposeCommands(src);
+		src.addObserver(new Observer() {
+			public void update(Observable o, Object s) { 
+				setVec(src.getVec());
+				update(A.observable(),null);
+				// if (autoscale) scale();
+				repaint();
+			}
+		} );
+	}
+
+	public void attach() 
+	{ 
+		super.attach();
+		Shell.registerViewable(src);
+	}
+
+	public void detach()
+	{
+		Shell.deregisterViewable(src);
+		super.detach();
+		src.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixTImageSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,59 @@
+/*
+ *	MatrixTImageSource.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+import  java.awt.image.*;
+import  Jama.Matrix;
+
+/** This matrix image source sends pixels a scan line
+	at a time
+
+	TODO:
+		flip horizontally or vertically
+		flip diagonally
+		replaceable map (ie nonlinear map)
+*/
+
+public class MatrixTImageSource extends ImageSourceBase
+{
+	Matrix		matrix;
+	byte []		scanline;
+
+	public MatrixTImageSource( Matrix mat) { this(mat,true); }
+	public MatrixTImageSource( Matrix mat, boolean fb)
+	{
+		matrix	= mat;
+		width		= mat.getRowDimension();
+		height	= mat.getColumnDimension();
+		scanline	= new byte[width];
+	}
+
+	public void newMatrix(Matrix mat) { matrix=mat; sendPixels();	}
+
+	protected int getHints() {
+		return  ImageConsumer.TOPDOWNLEFTRIGHT 
+				| ImageConsumer.COMPLETESCANLINES
+				| ImageConsumer.SINGLEPASS;
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{
+		double[][] X=matrix.getArray();
+
+		for (int j=height-1; j>=0; j--) {
+			for (int i=0; i<width; i++) {
+				scanline[i] = (byte)map.clipInt(X[i][j]);
+			}
+			ic.setPixels(0, height-1-j, width, 1, model, scanline, 0, 1);
+		} 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixTImageSourceF.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+/*
+ *	MatrixTImageSourceF.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+import  Jama.Matrix;
+import  java.awt.image.*;
+
+/** This one sends pixels in vertical strips: better for
+	column vectors or very narrow matrices
+ */
+
+public class MatrixTImageSourceF extends ImageSourceBase
+{
+	Matrix		matrix;
+	byte []		strip;
+
+	public MatrixTImageSourceF( Matrix mat)
+	{
+		matrix	= mat;
+		width		= mat.getRowDimension();
+		height	= mat.getColumnDimension();
+		strip		= new byte[height];
+	}
+
+	public void newMatrix(Matrix mat) { matrix=mat; sendPixels();	}
+
+	protected int getHints() { 
+		if (width==1) {
+			return  ImageConsumer.TOPDOWNLEFTRIGHT 
+					| ImageConsumer.COMPLETESCANLINES
+					| ImageConsumer.SINGLEPASS;
+		} else {
+			return ImageConsumer.RANDOMPIXELORDER | ImageConsumer.SINGLEPASS; 
+		}
+	}
+	protected void sendPixels(ImageConsumer ic)
+	{
+		double[][] X=matrix.getArray();
+
+		for (int i=0; i<width; i++) {
+			double[] Xi=X[i]; // can't believe compiler isn't doing this!
+			for (int j=0; j<height; j++) {
+				strip[height-1-j] = (byte)map.clipInt(Xi[j]);
+			}
+			ic.setPixels(i, 0, 1, height, model, strip, 0, 1);
+		} 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixTimesVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+
+public class MatrixTimesVector extends VectorFunctionOfVector implements SafeTask
+{
+	int m, n;
+	double [][] a;
+	double [] x, y, arow;
+
+	public MatrixTimesVector( Vec out, Matrix matrix, Vec in) {
+		this(out.array(),matrix,in.array());
+	}
+
+	public MatrixTimesVector(Matrix matrix)
+	{
+		n = matrix.getRowDimension();
+		m = matrix.getColumnDimension();
+		a = matrix.getArray();
+	}
+	
+	public MatrixTimesVector( double [] out, Matrix matrix)
+	{
+		n = matrix.getRowDimension();
+		m = matrix.getColumnDimension();
+		a = matrix.getArray();
+		y = out;
+	}
+
+	public MatrixTimesVector( double [] out, Matrix matrix, double [] in)
+	{
+		n = matrix.getRowDimension();
+		m = matrix.getColumnDimension();
+		a = matrix.getArray();
+		x = in;
+		y = out;
+	}
+
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+	public void run() {
+		for (int i=0; i<n; i++) {
+			double t=0;
+			arow=a[i];
+			for (int j=0; j<m; j++) t+=arow[j]*x[j];
+			y[i]=t;
+		}
+	}
+
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<n; i++) {
+			double t=0;
+			arow=a[i];
+			for (int j=0; j<m; j++) t+=arow[j]*x[j];
+			y[i]=t;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/MatrixTransposeTimesVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+
+public class MatrixTransposeTimesVector extends VectorFunctionOfVector
+	implements SafeTask
+{
+	int m, n;
+	double [][] a;
+	double [] x, y, arow;
+
+	public MatrixTransposeTimesVector( Vec out, Matrix matrix, Vec in) {
+		this(out.array(),matrix,in.array());
+	}
+	public MatrixTransposeTimesVector(Matrix matrix) {
+		m = matrix.getRowDimension();
+		n = matrix.getColumnDimension();
+		a = matrix.getArray();
+	}
+
+	public MatrixTransposeTimesVector( double[] out, Matrix matrix, double[] in) {
+		this(matrix); x = in; y = out;
+	}
+
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+	public void run() {
+		java.util.Arrays.fill(y,0);
+		for (int j=0; j<m; j++) {
+			double t=x[j];
+			arow=a[j];
+			for (int i=0; i<n; i++) y[i]+=arow[i]*t;
+		}
+	}
+
+
+	public void apply(double [] x, double [] y) {
+		java.util.Arrays.fill(y,0);
+		for (int j=0; j<m; j++) {
+			double t=x[j];
+			arow=a[j];
+			for (int i=0; i<n; i++) y[i]+=arow[i]*t;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Neg.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Neg extends Function
+{	
+	public double apply(double t) { return -t; }
+	public void apply(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=-x[i];
+	}
+	public void apply(double [] x, double [] y) {
+		for (int i=0; i<x.length; i++) y[i]=-x[i];
+	}
+	public String format(String arg) { return "-"+arg; }
+	public Function inverse() { return new Neg(); }
+	public Function derivative() { return new Constant(-1); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Ops.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,163 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths;
+import	samer.core.*;
+import	samer.tools.*;
+import	java.util.*;
+
+
+/**
+	An agent which allows the creation of vectors and
+	matrices, and can also arrange for them to be
+	multiplied as part of the current task list
+ */
+
+public class Ops
+{
+	public static Task update(final Viewable v) {
+		return new AnonymousTask() { public void run() { v.changed(); } };
+	}
+
+	public static Task times(VVector out, Matrix A, VVector x) {
+		return new MatrixTimesVector(out,A,x);
+	}
+
+	// copy as much as possible from one vector to another
+	public static Task transfer(final Vec in, final Vec out) {
+		final int len=Math.min(in.size(),out.size());
+		double src[]=in.array();
+
+		if (src!=null) 	return new ArrayCopy(src,0,out.array(),0,len);
+		else 				return new IteratorCopy(in,out,len);
+	}
+
+	// copy a given range from one vector to another
+	public static Task transfer(
+		final Vec in, int inpos, final Vec out, int outpos, int len)
+	{
+		return new ArrayCopy(in.array(),inpos,out.array(),outpos,len);
+	}
+
+	// copy a listed elements to another vector
+	public static Task transfer(final Vec in, final Vec out, final int[] elements) {
+		return new AnonymousTask() {
+			double [] dst=out.array();
+			double [] src=in.array();
+			int N=elements.length;
+			public void run() {
+				for (int i=0; i<N; i++) dst[i]=src[elements[i]];
+			}
+		};
+	}
+
+	public static Task apply(Vec vout, final Function f, Vec vin) {
+		final double [] in = vin.array();
+		final double [] out = vout.array();
+		return new AnonymousTask() {
+			Function fn=f;
+			public void run() { fn.apply(in,out); }
+			public void setFunction(Function fn) { this.fn=fn; }
+		};
+	}
+
+	public static Task apply(final Function fn, Vec vin) {
+		final double [] in = vin.array();
+		return new AnonymousTask() {
+			public void run() { fn.apply(in); }
+		};
+	}
+
+	public static Task apply(final VVector vout, final VectorFunctionOfVector fn, VVector vin) {
+		final double [] in = vin.array();
+		final double [] out= vout.array();
+		return new AnonymousTask() {
+			public void run() { fn.apply(in,out); vout.changed(); }
+		};
+	}
+
+	public static void apply( Function fn, Matrix A) {
+		double _A[][]=A.getArray();
+		int N=A.getRowDimension();
+		for (int i=0; i<N; i++) fn.apply(_A[i]); 
+		A.changed();
+	}
+
+	public static void apply( Function fn, Matrix B, Matrix A) {
+		double _A[][]=A.getArray(),_B[][]=B.getArray();
+		int N=A.getRowDimension();
+		for (int i=0; i<N; i++) fn.apply(_B[i],_A[i]); 
+		A.changed();
+	}
+
+
+	
+	public static Task plusEquals(final VVector x, final VVector y) {
+		final double [] _x=x.array(), _y=y.array();
+		return new AnonymousTask() {
+			public void run() { Mathx.add(_x,_y); x.changed(); }
+		};
+	}
+	
+	public static Task timesEquals(final VVector x, final VVector y) {
+		final double [] _x=x.array(), _y=y.array();
+		return new AnonymousTask() {
+			public void run() { Mathx.mul(_x,_y); x.changed(); }
+		};
+	}
+
+	public static Task apply(final VectorFunctionOfVector fn, final VVector vinout) {
+		final double [] in = vinout.array();
+		return new AnonymousTask() {
+			public void run() { fn.apply(in); vinout.changed(); }
+		};
+	}
+
+	/**
+		causes a task to run whenever an observable changes
+	 */
+	public static void triggerTask( final Task task, Observable obs)
+	{
+		obs.addObserver( new Observer() {
+			public void update(Observable o, Object a) { 
+				if (a==Viewable.DISPOSING) {
+					o.deleteObserver(this);
+					task.dispose();
+					return;
+				}
+				try { task.run(); }
+				catch (Exception ex) {}
+			}
+		} );
+	}
+
+	public static class ArrayCopy extends NullTask {
+		Object src, dst;
+		int		i, j, n;
+		public ArrayCopy(Object s, int spos, Object d, int dpos, int len) {
+			src=s; dst=d; i=spos; j=dpos; n=len;
+		}
+		public void run() { System.arraycopy(src,i,dst,j,n);	}
+	}
+
+	public static class IteratorCopy extends NullTask {
+		Vec	src, dst;
+		int 	N;
+		
+		public IteratorCopy(Vec src, Vec dst, int N) {
+			this.src=src; this.dst=dst; this.N=N;
+		}
+		
+		public void run() {
+			Vec.Iterator it=src.iterator();
+			double	[] a=dst.array();
+			for (int i=0; i<N; i++) a[i]=it.next();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Parameter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+/*
+ *	Parameter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import samer.core.types.*;
+
+public abstract class Parameter implements DoubleModel 
+{
+	double last=0;
+	public double get() { return last; }
+	public void set(double t) { setParameter(t); last=t; }
+	protected abstract void setParameter(double t);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Probe.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,15 @@
+package samer.maths;
+
+public class Probe implements Vec
+{
+	Vec	target;
+
+	public Probe(Vec target) { setTarget(target); }
+	public void setTarget(Vec target) { this.target=target; }
+
+	public int size() { return target.size(); }
+ 	public Mat mat() { return target.mat(); }
+	public Iterator iterator() { return target.iterator(); }
+	public double [] array() { return target.array(); }
+}
+			
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Product.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Product implements Generator
+{
+	Generator g1, g2;
+
+	public Product( Generator g1, Generator g2) { this.g1=g1; this.g2=g2; }
+
+	public void   dispose() { g1.dispose(); g2.dispose(); }
+	public double next() { return g1.next()*g2.next(); }
+	public void   next(double [] x) { 
+		g1.next(x);
+		for (int i=0; i<x.length; i++) x[i]*=g2.next(); 
+	}
+
+	public String toString() { return "Product("+g1+","+g2+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/RowColumn.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,162 @@
+/*
+ *	RowColumn.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  java.util.*;
+
+/**
+	Looks like a vector externally, but reads data
+	from a row or column of a matrix. Provides 
+	commands for setting which row or column to use,
+	and for switching between rows and columns.
+  */
+
+public class RowColumn extends VVector implements Mat, Observer
+{
+	Matrix			M;
+	VInteger			num; 
+	int				rowcol;
+	Mat				mat;
+
+	public final static Object FLIPPED   = new Object();
+	public final static Object SWITCHED  = new Object();
+
+	public RowColumn(Matrix A) { this( new Node("rowcolumn",A.getNode()), A); }
+	public RowColumn(Node n, Matrix A) 
+	{ 
+		super(n,A.getColumn(0));
+
+		Shell.push(node);
+		M=A; rowcol=COL;
+		boolean rowwise=Shell.getBoolean("rowwise",(A.getRowDimension()==1));
+		if (rowwise) { vec=A.getRow(0); rowcol=ROW; }
+		Shell.pop();
+
+		if (rowcol==ROW) createVRow();
+		else createVColumn();
+
+		M.addObserver(this);
+	}
+
+	// Vec implementation
+	public double[] array() { return null; }
+	public Vec getVec() { return this; }
+	public Mat mat() { if (mat==null) mat=vec.mat(); return this; }
+
+	// Mat implementation
+	public int width() { return mat.width(); }
+	public int height() { return mat.height(); }
+	public double get( int i, int j) { return mat.get(i,j); }
+	public void set( int i, int j, double t) { mat.set(i,j,t); }
+
+	private void createVRow()
+	{
+		Shell.push(getNode().getParent());
+		num = new VInteger("row",0,Variable.NOINIT);
+		num.setRange(0,M.getRowDimension()-1);
+		num.addObserver(this);
+		Shell.registerViewable(num);
+		Shell.pop();
+	}
+
+	private void createVColumn()
+	{
+		Shell.push(getNode().getParent());
+		num = new VInteger("column",0,Variable.NOINIT);
+		num.setRange(0,M.getColumnDimension()-1);
+		num.addObserver(this);
+		Shell.registerViewable(num);
+		Shell.pop();
+	}
+
+	public void dispose() 
+	{
+		Shell.deregisterViewable(num);
+		M.deleteObserver(this);
+		num.dispose();
+		super.dispose();
+	}
+
+	public void setNum(int n) { num.value=n; num.changed(); }
+
+	public void setRow(int r) { 
+		num.value=r; vec=M.getRow(r);
+		if (mat!=null) mat=vec.mat();
+		if (rowcol==ROW) changed(SWITCHED);
+		else { rowcol=ROW; changed(FLIPPED); }
+	}
+
+	public void setColumn(int r) { 
+		num.value=r; vec=M.getColumn(r); 
+		if (mat!=null) mat=vec.mat();
+		if (rowcol==COL) changed(SWITCHED);
+		else { rowcol=COL; changed(FLIPPED); }
+	}
+
+	public void getCommands(Agent.Registry r) {
+		super.getCommands(r); r.group();
+		r.add("row").add("column").add("dispose");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("row")) {
+
+			if (rowcol==COL) {
+				num.deleteObserver(this);
+				num.dispose();
+				createVRow();
+				setRow(0);
+			}
+
+			// no need to get number: num is automatically exposed
+			// env.datum().get(num);
+
+		} else if (cmd.equals("column")) {
+
+			if (rowcol==ROW) {
+				num.deleteObserver(this);
+				num.dispose();
+				createVColumn();
+				setColumn(0);
+			}
+
+			// no need to get number: num is automatically exposed
+			// env.datum().get(num);
+		} else if (cmd.equals("dispose")) {
+			dispose();
+		} else super.execute(cmd,env);
+	}
+
+	public void notifyObservers(Object s) {
+		super.notifyObservers(s);
+		if (s!=Viewable.DISPOSING && s!=RowColumn.SWITCHED) {
+			M.changed(this); // pass notification onto matrix observers
+		}
+	}
+
+	public void update(Observable o, Object s) { // &&&
+		if (M.equals(o)) { // Matrix changed
+			if (s==Viewable.DISPOSING)	dispose();
+			else if (s!=this)	super.notifyObservers(this);
+		} else if (num.equals(o)) {
+			if (rowcol==ROW) setRow(num.value);
+			else setColumn(num.value);
+		}
+	}
+
+	private final static int ROW = 1;
+	private final static int COL = 2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/SparseMatrix.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,75 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class SparseMatrix {
+	int			max, n;	// number of elements
+	int[]		i, j;			// element indices
+	double[]	x;			// element values
+
+	public SparseMatrix(String name) {}
+	public SparseMatrix(String name, SparseMatrix mask) {
+		n=mask.n;
+		i=(int[])mask.i.clone();
+		j=(int[])mask.j.clone();
+		x=new double[n];
+	}
+
+	/** allocate space for E elements and remove all elements */
+	public void allocate(int E) {
+		this.max=E; 	n=0;
+		i=new int[E];
+		j=new int[E];
+		x=new double[E];
+	}
+
+	/** add a new element to list. (Must be room for it) */
+	public void addElement( int i, int j, double x) {
+		this.i[n]=i;
+		this.j[n]=j;
+		this.x[n]=x;
+		n++;
+	}
+
+	public void times(double [] out, double [] in) {
+		Mathx.zero(out);
+		for (int k=0; k<n; k++) {
+			out[i[k]]+=x[k]*in[j[k]];
+		}
+	}
+
+	public void transposeTimes(double [] out, double [] in) {
+		Mathx.zero(out);
+		for (int k=0; k<n; k++) {
+			out[j[k]]+=x[k]*in[i[k]];
+		}
+	}
+
+	public void zero() { Mathx.zero(x); }
+
+	public void addOuterProduct(double[] a, double[] b) {
+		for (int k=0; k<n; k++) x[k] += a[i[k]]*b[j[k]];
+	}
+
+	public void icaUpdate(SparseMatrix GW, double eta, double batch) {
+		double[] dx=GW.x;
+		Mathx.mul(dx,1/batch);
+		for (int k=0; k<n; k++) x[k] += eta*(dx[k]-x[k]);
+	}
+
+	public void identity() { for (int k=0; k<n; k++) x[k] = (i[k]==j[k]) ? 1 : 0; }
+	public void getMatrix(Matrix A) {
+		A.zero();
+		for (int k=0; k<n; k++) A.set(i[k],j[k],x[k]);
+	}
+		
+	public void changed() {}
+	public void dispose() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Sum.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Sum implements Generator
+{
+	Generator g1, g2;
+
+	public Sum( Generator g1, Generator g2) { this.g1=g1; this.g2=g2; }
+
+	public void   dispose() { g1.dispose(); g2.dispose(); }
+	public double next() { return g1.next()+g2.next(); }
+	public void   next(double [] x) { 
+		g1.next(x);
+		for (int i=0; i<x.length; i++) x[i]+=g2.next(); 
+	}
+
+	public String toString() { return g1.toString()+"+"+g2; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VFunction.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	VFunction.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  samer.core.util.*;
+import  samer.maths.*;
+import  java.util.*;
+
+import  samer.core.util.Tools;
+
+/**
+	A Viewable for a Function - provides a UI for getting
+	a plot of the function and for looking at its derivative
+	(would like to be able to switch the Function too)
+  */
+
+public class VFunction extends Viewable implements Agent
+{
+	Function	fn;
+
+	public VFunction(String name) { this(name,null); }
+	public VFunction(String name, Function f) 
+	{
+		super(name); fn=f; setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public void dispose() { Shell.deregisterViewable(this); super.dispose(); }
+	public void setFunction(Function f) { fn=f; changed(); }
+	public Function getFunction() { return fn; }
+	public Viewer getViewer()
+	{
+		BaseViewer vwr = new BaseViewer(this) {
+			{ update(VFunction.this,null); }
+			public void update(Observable o, Object a) {
+				setText( 
+					getLabel() + ": "
+					+ (fn==null ? "null" : fn.format("t")) 
+				);
+				super.update(o,a);
+			}
+		};
+
+		return vwr;
+	}
+
+	public void getCommands(Agent.Registry r) { 
+		r.add("plotter").add("derivative").add("inverse"); 
+	}
+
+	public void execute(String cmd, Environment env) {
+		if (cmd.equals("plotter")) {
+			Shell.push(new Node("plotter",getNode()));
+			FunctionPlotter plotter = new FunctionPlotter(this);
+			Shell.expose((Viewer)plotter,"window");
+			Shell.pop();
+		} else if (cmd.equals("derivative")) {
+			Shell.push(node);
+			final VFunction dfn = new VFunction("derivative",fn.derivative());
+			Shell.pop();
+			addObserver( new Observer() {
+				// this chains any update messages along to derivatives
+				public void update(Observable o,Object arg) { dfn.changed(); }
+			} );
+			
+		} else if (cmd.equals("inverse")) {
+			Shell.push(node);
+			final VFunction dfn = new VFunction("inverse",fn.inverse());
+			Shell.pop();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VGenerator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,78 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths;
+import	samer.core.*;
+import	samer.core.types.*;
+import	samer.core.util.*;
+import	java.awt.*;
+import	java.util.*;
+
+/**
+	A Viewable random number generator.
+	The Generator itself must expose any parameters
+	it has, but this object allows the user to
+	control what class of generator to use. 
+  */
+
+public class VGenerator extends Viewable implements Agent, Generator
+{
+	Generator	gen;
+	String		desc;		// description of the current generator
+
+	public VGenerator(String nm) throws Exception { this(nm,new Zero()); }
+	public VGenerator(String nm, Generator g) throws Exception {
+		super(nm); setAgent(this);	gen = g;
+		Shell.registerViewable(this);
+	}
+	
+	public double next() { return gen.next(); }
+	public void   next(double[] x) { gen.next(x); }
+
+	public void dispose() 
+	{
+		Shell.deregisterViewable(this);
+		gen.dispose();
+		super.dispose();
+	}
+
+	public Generator getGenerator() { return gen; }
+	public void setGenerator(Generator g) {
+		gen.dispose(); gen=g; changed();
+	}
+
+	public Viewer getViewer() { return new UI(); }
+
+	private class UI extends BaseViewer {
+		UI() {
+			super(VGenerator.this);
+			update(VGenerator.this,null);
+		}
+
+		public void update(Observable o, Object arg) {
+			super.update(o,arg);
+			Shell.trace("VGenerator update to "+gen.toString());
+			setText(getLabel()+": "+gen.toString());
+		}
+	}
+
+	public void getCommands(Registry r)	{ r.add("set").add("next"); }	
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("set")) {
+			Shell.push(getNode());
+			setGenerator((Generator)X.object(env.datum()));
+			Shell.pop();
+		} else if (cmd.equals("next")) {
+			env.add(new Double(gen.next()));
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,334 @@
+/*
+ *	VVector.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.core.*;
+import  samer.core.util.*;
+import  samer.tools.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+import  java.io.*;
+/**
+	A Viewable Vec. The default viewer displays only
+	the name and size of the vector, but the attached
+	Agent allows creation of other types of viewer.
+  */
+
+public class VVector extends Viewable implements Vec, Agent, Saveable
+{
+	Vec	vec;
+
+	protected VVector() {}
+
+	public VVector(Node node, Vec v) {
+		super(node); vec=v; setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public VVector(Node node, double [] x) { this(node,new Vec.ForArray(x)); }
+	public VVector(String nm, double [] x) { this(new Node(nm), x); }
+	public VVector(String nm, int n) { this(new Node(nm), n); }
+	public VVector(Node node, int n) {
+		this(node,new Vec.ForArray(new double[n]));
+	}
+
+	public void addSaver() { addAgent(new Saver(this,getNode())); }
+
+	// Vec implementation
+	public Iterator	iterator()	{ return vec.iterator(); }
+	public int			size()		{ return vec.size(); }
+	public Mat			mat()			{ return vec.mat(); }
+	public double[]	array()		{ return vec.array(); }
+
+	public Vec    getVec() { return vec; }
+	public Viewer getViewer()
+	{
+		BaseViewer		vwr = new BaseViewer(this);
+		StringBuffer	buf=new StringBuffer();
+
+		buf.append(getLabel())
+			.append(" (").append(vec.size())
+			.append(")");
+		vwr.setText(buf.toString());
+
+		return vwr;
+	}
+
+	public void copyFrom(double[] y) { Mathx.copy(y,array()); changed(); }
+	public void copyTo(double[] y) { Mathx.copy(array(),y); }
+	// Saveable implementation
+	public void save(OutputStream out) throws Exception {
+		new ObjectOutputStream(out).writeObject(array());
+	}
+
+	public void load(InputStream in) throws Exception {
+		Object o=new ObjectInputStream(in).readObject();
+		Mathx.copy((double [])o,array()); 	changed();
+	}
+
+		/** Write the given Vec to a PrintWriter as one line of text,
+		consisting of space delimited numbers. */
+
+	public void write(Writer w) { print(new PrintWriter(w)); }
+	public void print(PrintWriter prn) {
+		Vec.Iterator i=vec.iterator();
+		prn.print(i.next());
+		while (i.more()) {
+			prn.print(' ');
+			prn.print(i.next());
+		}
+		prn.println();
+		prn.flush();
+	}
+
+	/** Reads a line of numbers from the reader and stores in the Vec */
+	public void read(Reader input) throws IOException
+	{
+		StreamTokenizer tok= new StreamTokenizer(new BufferedReader(input));
+
+		/*
+		a)	words are made from only +,-,.,e,E, or digits
+		 b) if other tokens may exist in a line, these are ignored
+		 c) if there is too much stuff on one line, the rest is discarded.
+		 d) if there aren't enough numbers, throw an exception.
+		 */
+
+		tok.resetSyntax();
+		tok.wordChars('+','+');
+		tok.wordChars('-','-');
+		tok.wordChars('0','9');
+		tok.wordChars('.','.');
+		tok.wordChars('e','e');
+		tok.wordChars('E','E');
+		tok.commentChar('#');
+		tok.commentChar(';');
+		tok.commentChar('%');
+		tok.whitespaceChars(0, ' ');
+		tok.eolIsSignificant(true);
+
+      // Ignore initial empty lines
+		while (tok.nextToken() == StreamTokenizer.TT_EOL);
+		if (tok.ttype == StreamTokenizer.TT_EOF)
+			throw new EOFException("EOF on vector read.");
+
+		double [] x=vec.array();
+		int			i=0;
+
+		// get first x.length words and convert to numbers
+		do {
+			if (tok.ttype==StreamTokenizer.TT_WORD)
+				x[i++]=Double.parseDouble(tok.sval);
+		} while (tok.nextToken()!=StreamTokenizer.TT_EOL && i<x.length);
+		// !! what if EOF?
+		if (i<(x.length-1)) throw new IOException("not enough numbers");
+
+		// now mop up rest of line
+		while (tok.ttype!=StreamTokenizer.TT_EOL) tok.nextToken();
+		changed();
+	}
+
+	public void getCommands(Registry r) {
+		r.add("zeros").add("negate").add("set").group();
+		r.add("plotter")
+		 .add("image")
+		 .add("reshaped image")
+		 .add("trace")
+		 .add("image editor")
+		 .add("plotter editor")
+		 .add("multitrace");
+		r.group();
+		r.add("publish");
+
+	}
+
+	private void expose(Viewer v) { Shell.expose(v,"window"); }
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("zeros")) {
+
+			double [] x = vec.array();
+			if (x!=null) Mathx.zero(x);
+			else {	// try using Mat interface instead
+				Mat mat = vec.mat();
+				if (mat!=null) for (int i=0; i<mat.width(); i++) mat.set(1,i,0);
+				else throw new Exception("Vector inaccessible: "+getLabel());
+			}
+			changed();
+
+		} else if (cmd.equals("set")) {
+
+			double y=X._double(env.datum(),1);
+			double [] x = vec.array();
+			if (x!=null) Mathx.setAll(x,y);
+			else {	// try using Mat interface instead
+				Mat mat = vec.mat();
+				if (mat!=null) for (int i=0; i<mat.width(); i++) mat.set(1,i,y);
+				else throw new Exception("Vector inaccessible: "+getLabel());
+			}
+			changed();
+
+		} else if (cmd.equals("negate")) {
+
+			double [] x = vec.array();
+			if (x!=null) Mathx.negate(x);
+			else {	// try using Mat interface instead
+				Mat mat = vec.mat();
+				if (mat!=null) for (int i=0; i<mat.width(); i++) mat.set(1,i,-mat.get(1,i));
+				else throw new Exception("Vector inaccessible: "+getLabel());
+			}
+			changed();
+
+		} else if (cmd.equals("plotter")) {
+
+			pushNode("plotter");
+			expose(new VectorPlotter(this,getVec()));
+			Shell.pop();
+
+		} else if (cmd.equals("plotter editor")) {
+
+			pushNode("editor.plotter");
+			expose(new VectorEditor(this,getVec()));
+			Shell.pop();
+
+		} else if (cmd.equals("image")) {
+
+			Node n=pushNode("image");
+			expose(createVectorImage(n,vec.size(),1));
+			Shell.pop();
+
+		} else if (cmd.equals("reshaped image")) {
+
+			Node n=pushNode("reshaped.image");
+			int w=Shell.getInt("width",1);
+			int h=Shell.getInt("height",vec.size());
+			expose(createVectorImage( n, w, h));
+			Shell.pop();
+
+		} else if (cmd.equals("image editor")) {
+
+			Node n=pushNode("editor.image");
+
+			final Shell.Window win = Shell.getWindow("window");
+			final ImageViewer vwr = createVectorImage(n,vec.size(),1);
+			final MatEditor editor = new MatEditor(mat(),vwr,this,vwr);
+
+			win.container().setLayout( new BorderLayout(6,6));
+			win.container().add( vwr.getComponent(), "Center");
+			// win.container().add( editor.setto.getViewer().getComponent(),"South");
+			Shell.registerViewable(editor.setto);
+			win.addWindowListener( new WindowAdapter() {
+				public void windowClosing(WindowEvent e) {
+					editor.detach();
+					vwr.detach();
+					win.dispose();
+				}
+			} );
+			win.expose();
+
+			// vwr.exposeCommands(this);
+
+			Shell.pop();
+
+		} else if (cmd.equals("trace")) {
+
+			Node node=pushNode("trace");
+			ImageSourceBase imgsrc=createImageSource(1,vec.size());
+			expose(new ImageTrace(imgsrc,this));
+			Shell.pop();
+
+		} else if (cmd.equals("multitrace")) {
+
+			Node node=pushNode("trace");
+			expose(new VectorTraceObs(this,node));
+			Shell.pop();
+		} else if (cmd.equals("publish")) {
+			Shell.put(X.string(env.datum(),node.fullName()),this);
+		}
+	}
+
+
+	private Node pushNode(String nm) {
+		Node n=new Node(nm,getNode());
+		Shell.push(n);
+		return n;
+	}
+
+	private ImageSourceBase createImageSource(int w, int h)
+	{
+		// this chooses an ImageSource depending on
+		// the capabilities of the Vec
+		double [] array=array();
+
+		if (array!=null) {
+			if (w>1) return new ArrayImageSource(array,w,h);
+			else     return new ArrayVImageSource(array);
+		} else {
+			return new IteratorImageSource(getVec(),w,h);
+		}
+	}
+
+	private ImageViewer createVectorImage( final Node n, int w, int h)
+	{
+
+		/*
+			The VImageViewer handles displaying the image of
+			a supplied ImageSource, but this object handles
+			scaling of the colour map to match the range of
+			values in a Vec, accessed by iterator rather than
+			array.
+		  */
+		return new ImageViewer( createImageSource(w,h), this) {
+			public void scale()
+			{
+				Vec.Iterator	i=vec.iterator();
+				double			max, min, x;
+
+				min=max=i.next();
+				while (i.more()) {
+					x=i.next();
+					if (x>max) max=x;
+					if (x<min) min=x;
+				}
+
+				getVMap().setDomain(min,max);
+				getVMap().changed(this);
+			}
+		};
+	}
+}
+
+
+class VectorTraceObs extends VectorTrace implements Observer {
+	Observable obs;
+	Node		node;
+
+	VectorTraceObs(VVector v, Node n) {
+		super(v);
+		obs=v;
+		node=n;
+	}
+
+	public void attach() {	super.attach(); obs.addObserver(this); }
+	public void detach() {	obs.deleteObserver(this); super.detach(); }
+	public void update(Observable o, Object arg)
+	{
+		if (o==obs) {
+			if (arg==Viewable.DISPOSING) {
+				Shell.releaseViewer(this);
+			} else {
+				try { run(); }
+				catch (Exception ex) {}
+			}
+		} else super.update(o,arg);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Vec.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,73 @@
+/*
+ *	Vec.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+	Interface for a vector that can be access via either
+	an iterator (read only), or a double array (read/write)
+	or via a Mat interface.
+  */
+
+public interface Vec 
+{
+	int			size();
+	Iterator	iterator(); 
+	double[]	array();				
+	Mat			mat();
+
+	/** access vector by iterator */
+	public interface Iterator {
+		boolean	more();
+		double	next();
+	}
+
+	public interface InputIterator {
+		boolean	more();
+		void    next(double t);
+	}
+
+	/**
+		An implementation of Vec that uses an array to
+		store the values.
+	  */
+
+	public static class ForArray implements Vec, Mat, java.io.Serializable
+	{
+		double []	x;
+		public ForArray( double[] a) { x=a; }
+		public ForArray( int n) { x=new double[n]; }
+
+		public int size() { return x.length; }
+		public double[] array() { return x; }
+		public Vec.Iterator iterator() { return new Iterator(); }
+		public Mat mat() { return this; }
+		public int width() { return size(); }
+		public int height() { return 1; }
+		public double get( int i, int j) { return x[j]; }
+		public void	  set( int i, int j, double t) { x[j]=t; }
+
+		class Iterator implements Vec.Iterator {
+			int			i=0;
+			
+			public boolean more() { return i<x.length; }
+			public double  next() { return x[i++]; }
+		};
+		
+		class InputIterator implements Vec.InputIterator {
+			int			i=0;
+			
+			public boolean more() { return i<x.length; }
+			public void    next(double t) { x[i++]=t; }
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorEditor.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,83 @@
+/*
+ *	VectorEditor.java	
+ *
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import  samer.core.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.util.*;
+
+public class VectorEditor extends VectorPlotter 
+	implements MouseListener, MouseMotionListener
+{
+	Mat		mat;
+	double	lasty;
+	int		lasti;
+
+	public VectorEditor(Observable o, Vec s) {
+		super(o,s);
+		addMouseListener(this);
+		addMouseMotionListener(this);
+		mat=s.mat();
+	}
+
+	private void handle(MouseEvent e,boolean dragging)
+	{
+		// get inverse mapping of position
+		double x = xmap.inverseFromInt(e.getX());
+		double y = ymap.inverseFromInt(height-e.getY());
+		int    i = (int)x;
+
+		if (i>=0 && i<mat.width()) {
+			if (dragging) {
+				if (i>lasti) {
+					for (int j=lasti+1; j<=i; j++) {
+						double t=(j-lasti)/(float)(i-lasti);
+						double yy = t*y + (1-t)*lasty;
+						mat.set(1,j,yy);
+					}
+				} else if (i<lasti) {
+					for (int j=lasti-1; j>=i; j--) {
+						double t=(j-lasti)/(float)(i-lasti);
+						double yy = t*y + (1-t)*lasty;
+						mat.set(1,j,yy);
+					}
+				} else {
+					mat.set(1,i,y);
+				}
+			} else {
+				mat.set(1,i,y);
+			}
+			obs.notifyObservers(null);
+			lasty=y;
+			lasti=i;
+		}
+	}
+
+	public void mouseMoved(MouseEvent e) {}
+	public void mouseDragged(MouseEvent e) { 
+		int f = e.getModifiers();
+		if ((f & InputEvent.BUTTON1_MASK)!=0) {
+			handle(e,true); e.consume(); 
+		}
+	}
+	public void mousePressed(MouseEvent e) { 
+		int f = e.getModifiers();
+		if ((f & InputEvent.BUTTON1_MASK)!=0) {
+			handle(e,false); e.consume(); 
+		}
+	}
+	public void mouseReleased(MouseEvent e) {}
+	public void mouseClicked(MouseEvent e) {}
+	public void mouseEntered(MouseEvent e) {}
+	public void mouseExited(MouseEvent e) {}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorFunctionOfVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/*
+ *	VectorFunctionOfVector.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+/**
+  *		Defines a real-valued function of a vector
+  *		
+  */
+public abstract class VectorFunctionOfVector
+{
+	public abstract void apply(double [] in, double [] out);
+	public void apply(double [] inout) {
+		double [] tmp=new double[inout.length];
+		apply(inout,tmp);
+		Mathx.copy(tmp,inout);
+	}
+	public void dispose() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorPlotter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,216 @@
+/*
+ *	VectorPlotter.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.Agent.*;
+import samer.tools.*;
+
+/**
+	A Viewer that draws a variety of graphs from data in a vector
+  */
+
+public class VectorPlotter extends Plotter implements Agent, Observer
+{
+	private Vec			vector;
+	private boolean	autoscale=false;
+	private int			type;
+	private Pen			pen;
+	private VMap		vmap=new VMap(ymap);
+
+	Observable	obs;
+	Node			node=null;
+
+	public final static int LINE=0;
+	public final static int STEP=1;
+	public final static int FILL=2;
+	public final static int FILL3D=3;
+	public final static int CLOSED=4;
+	public final static int STEPS=5;
+
+	public VectorPlotter(Observable o, Vec s) { this(o); setVec(s); }
+	protected VectorPlotter(Observable o)
+	{
+		obs=o;
+		node=Shell.env().node();
+
+		type = Shell.getInt("type",LINE);
+		setAxes( XAXIS); // no Y axis please
+		// pen = getPen();
+
+		vmap.addObserver(this);
+		ymap = vmap.getMap();
+
+		// attach commands from this agent to this Viewer
+		exposeCommands( this);
+		exposeCommands( vmap);
+	}
+
+	public Dimension getPreferredSize() {
+		int cx=Shell.getInt("cell.width",Shell.getInt("cell.size",2));
+		return new Dimension(cx*vector.size(),96);
+	}
+	protected void realized() { super.realized(); attach(); }
+
+	// .............. Viewer bits .............................
+
+	public void update(Observable o, Object s)
+	{
+		if (s==this) return; // &&&
+		if (s==Viewable.DISPOSING) {
+			Shell.releaseViewer(this);
+		} else if (obs==o) {
+			if (autoscale) scale();
+			repaint();
+		} else if (o==vmap) {
+			if (s==VMap.NEW_MAP) ymap = vmap.getMap();
+			if (autoscale) scale(); repaint();
+		}
+	}
+
+	public void attach() { obs.addObserver(this); }
+	public void detach()
+	{
+		obs.deleteObserver(this);
+		super.detach();
+	}
+
+	// .............. Agent bits ..............................
+
+	public void getCommands(Registry r)
+	{
+		r.add("line",type==LINE)
+			.add("box",type==CLOSED)
+			.add("fill",type==FILL)
+			.add("fill3d",type==FILL3D)
+			.add("steps",type==STEPS);
+		r.add("scale").add("autoscale",autoscale);
+		r.group(); r.add("publish");
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if      (c.equals("line"))		{ type=LINE; repaint(); }
+		else if (c.equals("box"))		{ type=CLOSED; repaint(); }
+		else if (c.equals("fill"))		{ type=FILL; repaint(); }
+		else if (c.equals("fill3d"))	{ type=FILL3D; repaint(); }
+		else if (c.equals("steps"))	{ type=STEPS; repaint(); }
+		else if (c.equals("scale"))	{ scale(); repaint(); }
+		else if (c.equals("autoscale")) {
+			autoscale = X._bool(env.datum(),!autoscale);
+			if (autoscale) { scale(); repaint(); }
+		} else if (c.equals("publish"))
+			Shell.put(X.string(env.datum(),"plotter"),this);
+	}
+
+	// ................ functionality ...........................
+
+	public void setVec( Vec v) 
+	{ 
+		vector = v; 
+		xmap.setDomain(0,vector.size()); 
+		if (autoscale) scale();
+	}
+
+	public void scale()
+	{
+		double	max, min, x;
+	
+		Vec.Iterator i=vector.iterator();
+		min=max=i.next();
+		while (i.more()) {
+			x=i.next();
+			if (x>max) max=x;
+			if (x<min) min=x;
+		}
+
+		if (ymap instanceof LinearMap) {
+			// leave some space
+			double delta=max-min;
+			min -= 0.1*delta;
+			max += 0.1*delta;
+		} else if (ymap instanceof LogMap) {	
+			// somewhat arbitrarily...			
+			if (min==0) min=max/10000;
+		}
+
+		vmap.setDomain(min,max);
+		vmap.changed(this);
+	}
+
+	public void update(Graphics g) {
+		g.clearRect(0,0,width,height);
+		paint(g);
+	}
+	
+	public void paint( Graphics g)
+	{
+		Vec.Iterator i=vector.iterator();
+
+		super.paint(g); // draw axes or whatever
+		pen=getPen(g);
+		// pen.assert();
+
+		switch (type) {
+
+			case LINE:
+
+				pen.moveto(0,i.next());
+				for (int j=1; i.more(); j++) {
+					pen.lineto(j,i.next());
+				}
+				break;
+
+			case FILL3D:
+
+				for (int j=0; i.more(); j++) {
+					pen.moveto(j,0);
+					pen.abs(j+1,i.next()).rectify();
+					pen.fill3DRect(true);
+				}
+				break;
+
+			case FILL:
+
+				for (int j=0; i.more(); j++) {
+					pen.moveto(j,0);
+					pen.abs(j+1,i.next()).rectify();
+					pen.fillRect();
+				}
+				break;
+
+			case STEPS:
+
+				pen.moveto(0,i.next());
+				for (int j=1; i.more(); j++) {
+					pen.rel(1,0).lineto();
+					pen.abs(j,i.next()).lineto();
+				}
+				pen.rel(1,0).lineto();
+				break;
+
+			case CLOSED:
+
+				for (int j=0; i.more(); j++) {
+					pen.moveto(j,0);
+					pen.abs(j+1,i.next()).rectify();
+					pen.rect();
+				}
+				break;
+
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorPlusEqualsVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,32 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+
+public class VectorPlusEqualsVector extends AnonymousTask 
+{
+	int	 n;
+	double [] x, y;
+
+	public VectorPlusEqualsVector( double [] inout, double [] in)
+	{
+		n = inout.length;
+		x = in; y = inout;
+	}
+
+	public VectorPlusEqualsVector( Vec inout, Vec in)
+	{
+		n = inout.size();
+		x = in.array();
+		y = inout.array();
+	}
+
+	public void run() { for (int i=0; i<n; i++) y[i]+=x[i]; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorTimesEqualsScalar.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+import  samer.tools.*;
+
+public class VectorTimesEqualsScalar extends AnonymousTask 
+{
+	int	 n;
+	double [] x;
+	double k;
+
+	public VectorTimesEqualsScalar( Vec inout, double k)
+	{
+		n = inout.size();
+		x = inout.array(); 
+		this.k=k;
+	}
+
+	public void run() { for (int i=0; i<n; i++) x[i]*=k; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/VectorTrace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,78 @@
+/*
+ *	VectorPlotter.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+import java.util.*;
+import java.awt.*;
+import java.awt.event.*;
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.Agent.*;
+import samer.tools.*;
+import java.awt.image.IndexColorModel;
+
+/**
+	A Viewer that draws multiple traces: one for each element of a vector
+  */
+
+public class VectorTrace extends Trace
+{
+	private Vec			vec;
+	private Renderer		R;
+	private int[]			old;
+	private Color[]		cols;
+
+	public VectorTrace(Vec v)
+	{
+		IndexColorModel cmod=(IndexColorModel)Shell.get("colormap",ImageSourceBase.GREY);
+		R=(Renderer)Shell.get("renderer",Renderer.LINE);
+
+		int N=v.size(), M=cmod.getMapSize();
+		cols=new Color[N];
+		old=new int[N];
+		vec=v;
+
+		for (int i=0; i<N; i++) cols[i]=new Color(cmod.getRGB(i%M));
+	}
+
+	protected void realized() { super.realized(); attach(); }
+
+	public void run()
+	{
+		super.run();
+		Vec.Iterator it=vec.iterator();
+		int	i,j;
+
+		for (i=0; it.more(); i++) {
+			j=height-map.toInt(it.next());
+			graphics.setColor(cols[i]);
+			R.draw(graphics,x1,x2,old[i],j,j0);
+			old[i]=j;
+		}
+	}
+	// .............. Agent bits ..............................
+
+	public void getCommands(Registry r)
+	{
+		super.getCommands(r);
+		r.group(); r.add("line").add("fill").add("fill3d").add("steps");
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if      (c.equals("line"))		{ R=Renderer.LINE; }
+		else if (c.equals("fill"))		{ R=Renderer.FILL; }
+		else if (c.equals("fill3d"))	{ R=Renderer.FILL3D; }
+		else if (c.equals("steps"))	{ R=Renderer.STEPS; }
+		else super.execute(c,env);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/Zero.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,25 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths;
+
+public class Zero extends Function implements Generator
+{
+	public void dispose() {}
+
+	public double next() { return 0; }
+	public void   next(double [] x) { Mathx.zero(x); }
+
+	public double apply(double t) { return 0; }
+	public void   apply(double [] x) { Mathx.zero(x); }
+	public void   apply(double [] x, double [] y) { Mathx.zero(y); }
+
+	public String toString() { return "Zero"; }
+	public String format(String arg) { return "0"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/AbsXFConvergence.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+
+
+public class AbsXFConvergence
+{
+	double	XTOL=1e-7;	// various tolerances
+	double  FTOL=XTOL*XTOL;
+	
+	public void setXTolerance( double tolx) { XTOL=tolx; }
+	public void setFTolerance( double tolf) { FTOL=tolf; }
+	
+	public boolean isSatisfied(State S) 
+	{
+		// small step taken
+		// this compares the actual step taken with
+		if (Math.abs(S.P1.f-S.P2.f)>FTOL) return false;
+		if (S.alpha*S.normh>XTOL) return false;
+		return true;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,23 @@
+/AbsXFConvergence.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Condition.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/ConjGrad.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/ConstrainedConjGrad.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/ConstrainedGillMurray.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/ConstrainedMinimiser.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Constraints.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/CubicLineSearch.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Datum.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Functionx.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/GConvergence.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/GillMurray.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/MinimiserBase.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/PolynomialLineSearch.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/Positivity.java/1.1.1.1/Fri Dec 10 03:29:28 2004//
+/State.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/SubspaceFunctionx.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/UnconstrainedConjGrad.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/UnconstrainedMinimiser.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Util.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/XFConvergence.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/ZeroCrossingSparsity.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/maths/opt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Condition.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,15 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+
+public interface Condition
+{
+	boolean	test();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/ConjGrad.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,54 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class ConjGrad
+{
+	double[]	dg;
+	double		gg, dgg;
+	double		invhess;
+	State		S;
+
+	public ConjGrad(State s)
+	{
+		S  = s;
+		dg = new double[S.n];
+		invhess = 1;
+	}
+
+	public void init() {
+		Mathx.negate(S.P1.g,S.h);
+		Mathx.mul(S.h,invhess);
+		S.normh=Util.maxabs(S.h);
+	}
+
+	public void update()
+	{
+		Mathx.sub(dg,S.P2.g,S.P1.g);
+		gg  = Mathx.norm2(S.P1.g);
+		dgg = Mathx.dot(dg,S.P2.g);
+
+		Mathx.mul(S.h,dgg/gg);
+		Mathx.sub(S.h,S.P2.g);
+		Mathx.mul(S.h,invhess);
+		S.normh=Util.maxabs(S.h);
+
+		double s2=Mathx.dot(S.P2.g,S.h);
+		if (s2>0) {
+			// Shell.trace("steepest descent");
+			Mathx.negate(S.P2.g,S.h);
+			S.normh=Util.maxabs(S.h);
+			s2=Mathx.dot(S.P2.g,S.h);
+		}
+		S.P2.s=s2;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/ConstrainedConjGrad.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,48 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class ConstrainedConjGrad extends ConjGrad
+{
+	Constraints C;
+
+	public ConstrainedConjGrad(State s, Constraints c) {
+		super(s); C=c;
+	}
+
+	public void init() {
+		C.negate(S.P1.g,S.h);
+		C.zeroInactive(S.h);
+		S.normh=Util.maxabs(S.h);
+	}
+
+	public void update()
+	{
+		C.sub(dg,S.P2.g,S.P1.g);
+		gg  = C.dot(S.P1.g,S.P1.g);
+		dgg = C.dot(dg,S.P2.g);
+
+		C.mul(S.h,dgg/gg);
+		C.sub(S.h,S.P2.g);
+		S.normh=Util.maxabs(S.h);
+
+		double s2=C.dot(S.P2.g,S.h);
+		if (s2>0) {
+			// Shell.trace("steepest descent");
+			C.negate(S.P2.g,S.h);
+			C.zeroInactive(S.h);
+			S.normh=Util.maxabs(S.h);
+			s2=C.dot(S.P2.g,S.h);
+		}
+		S.P2.s=s2;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/ConstrainedGillMurray.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,69 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class ConstrainedGillMurray extends GillMurray
+{
+	State		S;
+	Constraints C;
+	
+	public ConstrainedGillMurray(State s, Constraints c) {
+		super(s); S=s; C=c;
+	}
+
+	public void computeHg(double [] g)
+	{
+		C.zeroInactive(S.h);
+		C.mul(S.h,H,g);
+		C.negate(S.h);
+		S.normh = Util.maxabs(S.h);
+	}
+
+	public void steepest() {
+		C.negate(S.P1.g,S.h);
+		C.zeroInactive(S.h);
+		S.normh = Util.maxabs(S.h);
+	}
+
+	public void resetDimension(int k) {
+		double [] hk=H0.getArray()[k];
+		for (int i=0; i<S.n; i++) H[i][k]=H[k][i]=hk[i];
+	}
+
+	/* calculate new hessian and search direction */
+	public void update()
+	{
+		// sparse subtraction and dot product
+		C.sub(u,S.P2.x,S.P1.x);
+		C.sub(v,S.P2.g,S.P1.g);
+		double uv = C.dot(u,v);
+
+		if (uvCheck(uv,C.dot(u,u),C.dot(v,v))) {
+			C.mul(Hv,H,v);
+
+			double a = 1/uv;
+			double b = a*(1+a*C.dot(v,Hv));
+
+			for (int k=0; k<C.m; k++) {
+				int i=C.active[k];
+				for (int l=0; l<k; l++) {
+					int j=C.active[l];
+					H[i][j] = H[i][j] - a*(Hv[i]*u[j]+u[i]*Hv[j]) + b*u[i]*u[j];
+					H[j][i] = H[i][j];
+				}
+				H[i][i] = H[i][i] - a*(2*Hv[i]*u[i]) + b*u[i]*u[i];
+			}
+		}
+		computeHg(S.P2.g);
+		S.setSlope2(C.dot(S.P2.g,S.h));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/ConstrainedMinimiser.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,192 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.heavy.*;
+
+/**
+		Constrained minimiser.
+
+		-	ConjugateGradient 
+		-	OR Quasi-newton (using GillMurray uydates)
+		-	Safeguarded cubic interpolation line search using gradients
+
+		We expect a Class object to be in object Space
+		to tell us what kind of constraints to create
+  */
+
+
+public class ConstrainedMinimiser extends MinimiserBase implements Agent
+{
+	ConstrainedGillMurray	dir;
+//	ConstrainedConjGrad		dir;
+	Constraints					cons;	// handles line search
+	VDouble						percentage;
+	boolean toggle=false;
+
+	/** expected stack top: Vec, Functionx, Class */
+	public ConstrainedMinimiser(Vec v, Functionx f, Constraints.Factory constraintFactory) 
+	{
+		super(v,f);
+		cons = constraintFactory.build(this);
+		init();
+	}
+
+	public ConstrainedMinimiser(Vec v, Functionx f, Class conscl)
+	{
+		super(v,f);
+
+		if (conscl==ZeroCrossingSparsity.class) {
+			cons = new ZeroCrossingSparsity(this);
+		} else if (conscl==Positivity.class) {
+			cons = new Positivity(this);
+		} else {
+			throw new Error("Unrecognised constrain class: "+conscl);
+		}
+		init();
+	}
+
+	private void init() {
+		dir = new ConstrainedGillMurray(this,cons);
+//		dir = new ConstrainedConjGrad(this,cons);
+		percentage=new VDouble("releaseFactor",0.01);
+
+		// add( dir.hessin.viewable());
+		add( percentage);
+		cons.activateAll();
+	}
+
+	public void setHessian(Jama.Matrix H) { dir.setInitialHessian(H); }
+
+	public void getCommands(Agent.Registry r) {
+		super.getCommands(r);
+		r.add("all").add("run");
+		r.add("report").add("release").add("resetHess");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("run"))  			run();
+		else if (cmd.equals("report")) 	cons.report();
+		else if (cmd.equals("release")) 	releaseDimensions(P1);
+		else if (cmd.equals("all")) {
+			toggle = X._bool(env.datum(),!toggle);
+			if (toggle) cons.activateAll();
+			else cons.deactivateAll();
+		} else if (cmd.equals("resetHess")) {
+			dir.resetHessian();
+		} else super.execute(cmd,env);
+	}
+
+	private boolean releaseDimensions(Datum P)
+	{
+		if (cons.release(P)) {
+			dir.resetDimension(cons.getReleasedDimension());
+
+			int p=cons.getReleasableDimensions()-1;
+
+			// going to release a percentage of releasable dims?
+			// or absolute number?
+			p=(int)(percentage.value*p);
+			// if (p>1) p=1;
+			for (; p>0; p--) {
+				cons.release(P);
+				dir.resetDimension(cons.getReleasedDimension());
+			}
+
+ 			return true;
+		}
+		return false;
+	}
+
+	public void run()
+	{
+		double	beta;
+		int		i, maxiter=getMaxiter();
+		boolean	triedSteepest=false;
+
+		// we start from the current state instead.
+		// cons.initialise should set up the constraints
+		// to reflect the current state.
+		cons.initialise();
+
+		evaluate();
+		releaseDimensions(P1);
+
+		if (cons.activeCount()==0) {
+			iters.next(0);
+			sig3.off();
+			return;
+		}
+
+
+		sig1.off();
+
+		// must reset hessian for active dimensions
+		cons.zeroInactive(P2.x);
+		dir.resetHessian();
+		dir.hessin.changed();
+		dir.init();
+		setSlope();
+		beta = initialStep();
+		// beta = beta.value; ??
+
+		for (i=0; i<maxiter; i++) {
+
+			// constrained line search with initial step beta0
+			lstest.init();
+			cons.lineSearch(lstest,ls,beta);
+			lsiters.next(lstest.count);
+			steplength.next(alpha);
+
+			if (lstest.tiny && (P2.f>=P1.f)) {
+				//  tiny step was no good
+				sig1.on();
+				sig2.off();
+				if (gconv.isSatisfied(P1.g,cons)) break;
+				if (triedSteepest) break;
+				sig2.on();
+
+				beta = this.beta.value;
+				dir.update();			// ??
+				if (dir.uvc) dir.init();
+				else		 dir.steepest();
+				setSlope();
+				triedSteepest=true;
+				continue;
+			}
+
+
+			// check gradients at P2
+			if (!releaseDimensions(P2)) {
+				// don't quit if any dimensions released
+				if (cons.activeCount()==0) break;
+				if (xfconv.isSatisfied(this)) {
+					if (gconv.isSatisfied(P2.g,cons)) break;
+				}
+			}
+
+			// beta = beta.value;
+			beta = nextStep();
+			dir.update();
+			move();
+			perIteration();
+		}
+
+		perOptimisation(i);
+		dir.hessin.changed();
+	}
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Constraints.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,181 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public abstract class Constraints
+{
+	public State		S;
+	public int[]		active;			// active dimensions
+	public int[]		inactive;		// inactive dimensions
+	public int			n,m;			// number of active dimensions
+
+	public Constraints(State s)
+	{
+		S=s; n=S.n;
+		active = new int[n];
+		inactive = new int[n];
+		activateAll();
+	}
+
+	public final int activeCount() { return m; }
+
+	public void report() 
+	{
+		Shell.print("inactive dimensions:");
+		for (int i=0; i<(n-m); i++) {
+			Shell.print(" - "+inactive[i]);
+		}
+		Shell.print("active dimensions:");
+		for (int i=0; i<m; i++) {
+			Shell.print(" + "+active[i]);
+		}
+		Shell.print("  active: "+m);
+		Shell.print("inactive: "+(n-m));
+	}
+
+	public void activateAll() {
+		for (int i=0; i<n; i++) active[i]=i;
+		m=n;
+	}
+
+	public void deactivateAll() { 
+		for (int i=0; i<n; i++) inactive[i]=i;
+		m=0; 
+	}
+
+	public void zeroInactive(double [] z) {
+		for (int i=0; i<(n-m); i++) z[inactive[i]]=0;
+	}
+
+	/**
+			Inactivate the i'th dimension
+			Presupposes that it is not already inactive
+	  */	
+	public final void inactivate(int i) 
+	{
+		inactive[n-m]=i;
+		int j=Util.find(i,active,m);
+		if (j<(m-1)) {
+			System.arraycopy(active,j+1,active,j,m-j-1); 
+		}
+		m--;
+	}
+
+	/**
+			activate the i'th dimension
+			Presupposes that it is not already inactive
+	  */	
+	public final void activate(int i) 
+	{
+		active[m]=i;
+		int j=Util.find(i,inactive,n-m);
+		if (j<(n-m-1)) {
+			System.arraycopy(inactive,j+1,inactive,j,n-m-j-1); 
+		}
+		m++;
+	}
+
+	/**
+			take a step of lambda*h, set alpha, but don't
+			evaluate function at new point
+	  */
+	public void step(double lambda)
+	{
+		for (int i=0; i<m; i++) {
+			int j=active[i];
+			S.P2.x[j] = S.P1.x[j] + lambda*S.h[j];
+		}
+		S.alpha=lambda;
+	}
+
+	/**		evaluate function and gradient at P2 */
+	public void eval2()
+	{
+		S.func.evaluate(S.P2);
+		S.P2.s = dot(S.P2.g,S.h);
+	}
+
+	/**		sparse matrix mutiplication */
+	public final void mul( double [] y, double [][]A, double [] x)
+	{
+		double [] arow;
+
+		for (int k=0; k<m; k++) {
+			int i=active[k];
+			double t=0;
+			arow=A[i];
+			for (int l=0; l<m; l++) { int j=active[l]; t+=arow[j]*x[j]; }
+			y[i]=t;
+		}
+	}
+
+	/**		sparse vector dot product */
+	public final double dot( double [] a, double [] b)
+	{
+		double t=0;
+		for (int k=0; k<m; k++) { int i=active[k]; t+=a[i]*b[i]; }
+		return t;
+	}
+
+	/**		sparse vector time scalar */
+	public final void mul( double [] a, double b)
+	{
+		for (int k=0; k<m; k++) { int i=active[k]; a[i]*=b; }
+	}
+
+	/**		sparse vector subtraction */
+	public final void sub( double [] out, double [] a, double [] b)
+	{
+		for (int k=0; k<m; k++) { int i=active[k]; out[i]=a[i]-b[i]; }
+	}
+
+	/**		sparse vector subtraction in place */
+	public final void sub( double [] a, double [] b)
+	{
+		for (int k=0; k<m; k++) { int i=active[k]; a[i]-=b[i]; }
+	}
+
+
+	/**		sparse vector negation in place */
+	public final void negate(double [] x) 
+	{
+		for (int k=0; k<m; k++) { int i=active[k]; x[i]=-x[i]; }
+	}
+	
+	/**		sparse vector negation in place */
+	public final void negate(double [] x, double [] y) 
+	{
+		for (int k=0; k<m; k++) { int i=active[k]; y[i]=-x[i]; }
+	}
+	
+	/**		sparse max(abs(x)) */
+	public final double maxabs(double [] x)
+	{
+		double max=0;
+		for (int k=0; k<m; k++) {
+			double xk = Math.abs(x[active[k]]);
+			if (xk>max) max=xk;
+		}
+		return max;
+	}
+
+	// ugh
+	public boolean release(Datum P) { return false; }
+	public int getReleasedDimension() { return -1; }
+	public int getReleasableDimensions() { return 0; }
+	public abstract void lineSearch(Condition c, CubicLineSearch ls, double step);
+	public abstract void initialise();
+
+	public interface Factory {
+		public Constraints build(MinimiserBase min);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/CubicLineSearch.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,69 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+
+public class CubicLineSearch
+{
+	double	ZETA=0.0625;	// factor for safeguarding
+	State		S;
+	
+	public CubicLineSearch(State s) { S=s; }
+
+	public void setSafeguardFactor( double z) { ZETA=z; }	
+
+	protected final double extrapolate()
+	{
+		double beta=S.cubic()-S.alpha;
+
+		if (Double.isInfinite(beta) || Double.isNaN(beta)) {
+			return S.alpha*1.6;	
+		} else if (beta>0) {
+			if (beta<0.5*S.alpha) beta=S.alpha*0.5;
+			else if (beta>2*S.alpha) beta=2*S.alpha;
+			return beta;
+		} else {
+			return S.alpha*1.6;	
+			// if (beta>8) beta=8;
+		}
+	}
+
+	protected final double interpolate()
+	{
+		if (S.P2.s>0) {
+			double beta=S.cubic();
+			double safe=ZETA*S.alpha;
+			if (Double.isNaN(beta) || Double.isInfinite(beta)) {
+				beta=S.alpha/2; // bisect
+			} else if (beta<=safe || beta>=(S.alpha-safe)) {
+				beta=S.alpha/2; // bisect
+			} 
+			if (S.alpha<0.1) beta/=2; //	adust
+			return beta;
+		} else {
+			return S.alpha/2;
+		}
+	}
+
+	public void run(Condition convergence)
+	{
+		while (!convergence.test()) {
+			if (S.P2.f<S.P1.f && S.P2.s<0) {
+				double beta=extrapolate();
+				S.move();
+				S.step(beta);
+			} else
+				S.step(interpolate());
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Datum.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+
+public class Datum {
+	public double []	x, g;		// position and gradient
+	public double		f, s;		// value and slope
+
+	Datum(int n) {
+		x = new double[n];
+		g = new double[n];
+	}
+
+	Datum(int n, double [] y) {
+		x = y;
+		g = new double[n];
+	}
+
+	public void copy(Datum P) {
+		Mathx.copy(P.x,x);
+		Mathx.copy(P.g,g);
+		f=P.f;
+		s=P.s;
+	}
+
+	public void dispose() { x=null; g=null; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Functionx.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+
+/**
+	This is a function interface that is designed
+	to allow efficient implementations of minimisation
+	algorithms by recognising the fact that the
+	function and its gradient may be repeatedly 
+	evaluated at the same point in different parts
+	of the code - hence we can save ourselves
+	some computation.
+
+ */
+
+
+public interface Functionx
+{
+	/** get value and gradient for supplied point */
+	void evaluate( Datum P);
+
+	/** set argument to x, return value and put gradient in dx */
+	double evaluate( double [] x, double [] grad);
+
+	void dispose();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/GConvergence.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+
+public class GConvergence
+{
+	double		GTOL;
+	
+	public void setGTolerance( double tolg) { GTOL=tolg; }
+	
+	public boolean isSatisfied(double [] g, Constraints C) 
+	{
+		for (int k=0; k<C.m; k++) {
+			int i=C.active[k];
+			if (g[i]>GTOL) return false;
+		}
+		return true;
+	}
+
+	public boolean isSatisfied(double [] g, State S) 
+	{
+		for (int i=0; i<S.n; i++) {
+			if (g[i]>GTOL) return false;
+		}
+		return true;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/GillMurray.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,88 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class GillMurray
+{
+	public Matrix		hessin;
+	Jama.Matrix	H0;
+	double[][]	H;				// approximate inverse Hessian
+	double[]		u, v, Hv;	// used in updating hessian
+	double		uv;
+	State			S;
+	boolean		uvc;
+
+	public GillMurray(State s)
+	{
+		S = s;
+		hessin = new Matrix("H",s.n,s.n);
+		H = hessin.getArray();
+		u = new double[s.n];
+		v = new double[s.n];
+		Hv= new double[s.n];
+		uv= 0;
+
+		H0=Matrix.identity(new Jama.Matrix(s.n,s.n));
+		resetHessian();
+	}
+
+	public void dispose() { 
+		H=null;
+		u=v=Hv=null;
+		hessin.dispose();
+		S=null;
+	}
+
+	public void setInitialHessian(Jama.Matrix H0) { this.H0=H0; }
+	public void resetHessian() { hessin.assign(H0); }
+	public void init() { computeHg(S.P1.g); }
+
+	public void steepest() {
+		Mathx.negate(S.P1.g,S.h);
+		S.normh = Util.maxabs(S.h);
+	}
+
+	public void computeHg(double [] g) {
+		Mathx.mul(S.h,H,g);
+		Mathx.negate(S.h);
+		S.normh = Util.maxabs(S.h);
+	}
+
+	protected boolean uvCheck( double uv, double uu, double vv) {
+		return uvc = (uv>1e-6*Math.sqrt(uu*vv));
+	}
+
+	public void update()
+	{
+		// calculate new hessian
+		Mathx.sub(v,S.P2.g,S.P1.g);
+ 		Mathx.sub(u,S.P2.x,S.P1.x);
+		double uv=Mathx.dot(u,v);
+
+		if (uvCheck(uv,Mathx.norm2(u),Mathx.norm2(v))) {
+
+			Mathx.mul(Hv,H,v);
+			double a = 1/uv;
+			double b = a*(1+a*Mathx.dot(v,Hv));
+
+			for (int i=0; i<S.n; i++) {
+				for (int j=0; j<i; j++) {
+					H[i][j] = H[i][j] - a*(Hv[i]*u[j]+u[i]*Hv[j]) + b*u[i]*u[j]; 
+					H[j][i] = H[i][j];
+				}
+				H[i][i] = H[i][i] - a*(2*Hv[i]*u[i]) + b*u[i]*u[i];
+			}
+		}
+		computeHg(S.P2.g);
+		S.setSlope2(Mathx.dot(S.P2.g,S.h));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/MinimiserBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,248 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.*;
+import  samer.tools.*;
+import	samer.core.util.swing.*;
+import	java.awt.*;
+import	java.util.*;
+
+/**
+		This is a base class for running multidimensional optimisation
+		It requires the following objects to exist in object space
+		(they are used by the State base class default constructor)
+
+		Functionx	"functionx":	the function to be minimised
+		VVector		"vector":		the vector to work with
+
+		ConstrainedMinimiser also requires "constraintClass" to
+		exist.
+
+  */
+
+
+public abstract class MinimiserBase extends State implements SafeTask, Agent
+{
+	// private Node	node;
+
+	protected VVector					x1,x2,g1,g2,vh;
+	protected VDouble				beta; // initial step length
+	protected CubicLineSearch		ls;
+	protected LSCondition			lstest; // convergence test for line search
+	protected AbsXFConvergence	xfconv; // convergence test for optimisation
+	protected GConvergence		gconv;
+	protected double					XTOL=1e-4;
+	protected VInteger				vmaxiter;
+	protected boolean					flange;	// signal vector changes every iteration
+
+	protected Meter				lsiters, iters;
+	protected Meter				steplength;
+	protected LED					sig1, sig2, sig3;
+	
+	private LinkedList<Viewable> viewables;
+
+	public MinimiserBase(Vec x, Functionx func)
+	{
+		super(x, func);
+
+		// node = new Node("Minimiser");
+		//Shell.push(node);
+
+		boolean oldreg=Shell.setAutoRegister(false);
+		viewables = new LinkedList<Viewable>();
+
+		x1 = new VVector("x1", P1.x); // independent view?
+		x2 = new VVector("x2", P2.x);
+		g1 = new VVector("g1", P1.g);
+		g2 = new VVector("g2", P2.g);
+		vh  = new VVector("h", h);
+		beta = new VDouble("beta",1);
+		vmaxiter=new VInteger("maxiter",400);
+		xfconv=new AbsXFConvergence();
+		gconv=new GConvergence();
+		gconv.setGTolerance(0.005);
+		flange=Shell.getBoolean("vprogress",false);
+		ls = new CubicLineSearch(this);
+		ls.setSafeguardFactor(0.125);
+		lstest = new LSCondition();
+
+		steplength = createMeter("step length",2,false,new Color(200,170,0));
+		lsiters = createMeter("line search iterations",20,false,new Color(90,100,255));
+		iters   = createMeter("iterations",2*x1.size(), true, new Color(200,50,0));
+		sig1 = new LED(new Color(240,190,20));
+		sig2 = new LED(new Color(90,100,255));
+		sig3 = new LED(new Color(250,60,20));
+		sig1.setToolTipText("Tiny line search step");
+		sig2.setToolTipText("Resetting Hessian, trying steepest descent");
+		sig3.setToolTipText("Maximum iterations reached");
+
+
+		// register some viewables locally
+		// add(x1); add(x2); add(g1); add(g2); add(vh); 
+		add(beta);
+		add(vmaxiter);
+
+		add(new VParameter("xtol", new Parameter() {
+				public void setParameter(double t) {
+					xfconv.setXTolerance(t);
+					XTOL=t;
+				}
+			} )
+		);
+
+		add(new VParameter("ftol", new Parameter() {
+				public void setParameter(double t) {
+					xfconv.setFTolerance(t);
+				}
+			} )
+		);
+
+		add(new VParameter("gtol", new Parameter() {
+				public void setParameter(double t) {
+					gconv.setGTolerance(t);
+				}
+			} )
+		);
+
+		add(new VParameter("ZETA", new Parameter() {
+				public void setParameter(double t) {
+					ls.setSafeguardFactor(t);
+				}
+			} )
+		);
+		Shell.setAutoRegister(oldreg);
+		// Shell.pop();
+	}
+
+	public Viewer getViewer() {
+		return new VPanel() {
+			{
+				setLayout( new StackLayout());
+				// add(Shell.createButtonsFor(MinimiserBase.this));
+
+				// set default border for meterbox and signal box?
+				VPanel meterbox = new VPanel();
+				//meterbox.setChildBorder(BorderFactory.createLoweredBevelBorder());
+				meterbox.setLayout( new StackLayout(8));
+				meterbox.add(steplength);
+				meterbox.add(iters);
+				meterbox.add(lsiters);
+
+				VPanel signalbox = new VPanel();
+				//signalbox.setChildBorder(BorderFactory.createLoweredBevelBorder());
+				signalbox.setLayout( new FlowLayout(FlowLayout.LEFT));
+				signalbox.add(sig1);
+				signalbox.add(sig2);
+				signalbox.add(sig3);
+
+				add(meterbox);
+				add(signalbox);
+				
+				add(x1); add(x2); add(g1); add(g2); add(vh);
+				for (Iterator<Viewable> it=viewables.iterator(); it.hasNext();) {
+					add(it.next());
+				}
+				// now add all other viewables
+			}
+		};
+	}
+
+	public void dispose() { super.dispose(); }
+
+	public void add(Viewable vbl) { viewables.add(vbl); }
+	public Viewable[] getViewables() { return viewables.toArray(new Viewable[0]); }
+
+	public int  getMaxiter() { return vmaxiter.value; }
+	protected void perIteration() {	if (flange) x1.changed(); }
+	protected void perOptimisation(int i) {
+		if (P2.f<=P1.f) {
+			move();
+			if (flange) x1.changed();
+		}
+
+		iters.next(i);
+		if (i<vmaxiter.value) sig3.off();
+		else sig3.on();
+	}
+
+	public void starting() {}
+	public void stopping() {}
+
+	public void getCommands(Agent.Registry r) {
+		r.add("eval").add("step").add("move").add("turn").add("info");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("step")) {
+			step(beta.value);
+			g2.changed();
+			x2.changed();
+		} else if (cmd.equals("info")) Shell.print(toString());
+		else if (cmd.equals("move")) {
+			steplength.next(alpha);
+			move();
+			x1.changed();
+			g1.changed();
+		} else if (cmd.equals("eval")) {
+			evaluate();
+			x1.changed();
+			g1.changed();
+			setSlope();
+		} else if (cmd.equals("turn")) {
+			Mathx.negate(P1.g,h);
+			setSlope();
+			vh.changed();
+		}
+	}
+
+	class LSCondition implements Condition
+	{
+		double MU=1e-4;		// ensure function decreases enough
+		double ETA=0.1;		// ensure gradient is smaller than last
+		int		count;
+		boolean tiny;
+
+		LSCondition()
+		{
+			add(new VParameter("ETA",new DoubleModel() {
+					public double get() { return ETA; }
+					public void set(double t) { ETA=t; }
+				} )
+			);
+		}
+
+		public void init() { tiny=false; count=0; }
+		public boolean test()
+		{
+			if (count++>96) {
+				Shell.trace("\n**** LINE SEARCH OVERRUN ****\n");
+				return true;
+			}
+			if (alpha*normh<XTOL) { tiny=true; return true; }
+			return (P2.f<P1.f+MU*alpha*P1.s) && (Math.abs(P2.s)<-ETA*P1.s);
+		}
+	}
+
+	private static Meter createMeter(String label, double max, boolean reinit, Color color) {
+		Shell.push(label);
+		Meter m=new Meter();
+		m.setForeground(color);
+		m.setBackground(color.darker().darker());
+		m.getMap().setDomain(0,max);
+		m.setToolTipText(label);
+		m.exposeMap(reinit);
+		Shell.pop();
+		return m;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/PolynomialLineSearch.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,74 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+/**
+		Line search from <b>Numerical Recipes in C</b>, pretty
+		much as supplied. 
+
+		I removed the max step and slope checking and made it the
+		responsibility of the calling code to check these.
+		Also, this works with ONE-DIMENSIONAL functions: the stuff
+		about vectors can be handled by a <code>LineFunction</code> object.
+ */
+
+public class PolynomialLineSearch
+{
+	State		S;
+
+	public PolynomialLineSearch(State s) { S=s; }
+
+	/**
+		This assumes that the initial step has already been taken
+		@param	alamin	minimum step size
+	  */
+
+	public void run(Condition termination)
+	{
+		double alam, alam2, f3;
+		double tmplam;
+
+		// if initial step is ok...
+		if (termination.test()) return;
+
+		// backtrack using quadratic interpolation
+		tmplam = -S.P1.s/(2*(S.P1.f-S.P2.f-S.P1.s));
+		alam = S.alpha;
+
+		for (;;) {
+
+			// remember failed parameters
+			alam2=alam;	f3=S.P2.f;
+			alam=Math.max(tmplam,0.1*alam);
+
+			S.step(alam);
+
+			// if step was ok...
+			if (termination.test()) return;
+
+			// backtrack using cubic interpolation
+			double rhs1 = S.P2.f - S.P1.f - alam*S.P1.s;
+			double rhs2 = f3     - S.P1.f - alam2*S.P1.s;
+			double a = (rhs1/(alam*alam) - rhs2/(alam2*alam2)) / (alam-alam2);
+			double b = (-alam2*rhs1/(alam*alam)+alam*rhs2/(alam2*alam2))/(alam-alam2);
+
+			if (a==0.0) tmplam = -S.P1.s/(2*b);
+			else {
+				double disc=b*b-2*a*S.P1.s;
+				if (disc<0) tmplam=alam/2;
+				else if (b<=0) tmplam=(-b+Math.sqrt(disc))/(3*a);
+				else tmplam=-S.P1.s/(b+Math.sqrt(disc));
+			}
+			if (tmplam>alam/2) tmplam=alam/2;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Positivity.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,179 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+
+/**
+	Cubic line search with positivity constraints
+	dimensions become inactive when they go to
+	zero and the gradient > GEPS
+ */
+ 
+public class Positivity extends Constraints
+{
+	double		XEPS=1e-6;
+	double		GEPS=1e-4;
+	int []		zerod;
+	int			released;
+
+	public Positivity(MinimiserBase minimiser)
+	{ 
+		super(minimiser);
+		zerod=new int[n];
+
+		minimiser.add(new VParameter("XEPS", new DoubleModel() {
+				public void set(double t) { XEPS=t; }
+				public double get() { return XEPS; }
+			} )
+		);
+
+		minimiser.add(new VParameter("GEPS", new DoubleModel() {
+				public void set(double t) { GEPS=t; }
+				public double get() { return GEPS; }
+			} )
+		);
+	}
+	
+	/** constrain all dimensions which are currently set
+	    to zero.
+	  */
+
+	public void initialise()
+	{
+		int p=0, q=0;
+
+		for (int i=0; i<n; i++) {
+			if (S.P1.x[i]<=0) { inactive[p++]=i; S.P1.x[i]=0; }
+			else active[q++]=i;
+		}
+		m=q;
+	}
+
+	/**
+		This finds the constrained dimension with the
+		largest positive gradient, and if of
+		that gradient is bigger than 1, then releases 
+		that dimension so that it can take part in the 
+		optimization
+	 */
+
+	public boolean release(Datum P)
+	{
+		if (m==n) return false;
+
+		int imax=-1;
+		double grad=-GEPS; // tolerance
+
+		for (int k=0; k<(n-m); k++) {
+			int j=inactive[k];
+			if (P.g[j]<grad) {
+				grad=P.g[j];
+				imax=j;
+			}
+		}
+		
+		if (imax!=-1) {	activate(imax); released=imax; return true; }
+		else return false;
+	}
+
+	public int getReleasedDimension() { return released; }
+
+	/**
+			Take a step but make sure none of the coordinates
+			becomes negative. This function returns true if
+			any dimensions were inactivated - implying that
+			we should finish the line search. The alternative
+			is that even the clipped step was too long and
+			we need to interpolate some more.
+	  */
+
+	public boolean clipStep(double beta)
+	{
+
+		step(beta);
+
+		
+		// got to find sign swappers
+		int imin=-1;
+		double alphamin=beta; // ??
+			
+		for (int k=0; k<m; k++) {
+			int i=active[k];
+			if (S.P2.x[i]<=XEPS) {
+				double alpha=-S.P1.x[i]/S.h[i];
+				if (imin==-1 || alpha<alphamin) {
+					imin=i;
+					alphamin=alpha;
+				}
+			}
+		}
+
+		// if no negative values, evaluate and return		
+		if (imin==-1) { S.eval2(); return false; } 
+		
+		// atlease one dimension has become 
+		// zero or negative. imin was the first
+		// what if alphamin=0?
+		step(alphamin);
+			
+		// now we should check for ANY unconstrained
+		// x[i] being less than XEPS, and set it to
+		// exactly zero, including, obviously x[j]
+		int numzerod=0;
+		for (int k=0; k<m; k++) {
+			int j=active[k];
+			if (S.P2.x[j]<=XEPS) {
+				S.P2.x[j]=0;
+				zerod[numzerod++]=j;
+			}
+		}
+
+		eval2();
+
+		// next, check zeroed dimensions
+		// for constraint eligibilty
+		boolean flag=false;
+		
+		for (int k=0; k<numzerod; k++) {
+			int j=zerod[k];
+			if (S.P2.g[j]>=-GEPS) {
+				inactivate(j);
+				flag=true;
+			}
+		}
+
+		return flag;
+	}
+
+
+	public void lineSearch(Condition convergence, CubicLineSearch ls, double beta0)
+	{
+		if (clipStep(beta0)) return;
+
+		while (!convergence.test()) {
+			// formulate any other direction change conditions
+
+			if (S.P2.f<S.P1.f && S.P2.s<0) {
+				double beta=ls.extrapolate();
+				S.move();
+				if (clipStep(beta)) break;
+			} else { 
+				// since both P1 and P2 must satisfy positivity
+				// constraints, all points between them do alse,
+				// so no worries about interpolation
+				step(ls.interpolate());
+				eval2();
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/State.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,146 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+
+public class State
+{
+	public Functionx	func;			// function
+	public int			n;				// number of dimensions
+	public double[]	h;				// search direction
+	public Datum		P1, P2;		// two bracket points and a new point
+	public double		alpha;		// step length
+	public double		normh;		// some norm of h
+
+	/** x must have an accessible array */
+	public State( Vec x, Functionx func)
+	{
+		this.n = x.size();
+		this.func = func;
+		P1 = new Datum(n,x.array());
+		P2 = new Datum(n);
+		h = new double[n];
+	}
+
+	public void dispose() 
+	{ 
+		func.dispose(); 
+		P1.dispose(); 
+		P2.dispose(); 
+		h=null; 
+	}
+
+	/** estimated step to minimum using cubic interpolation of current state */
+	public final double cubic() { return Util.cubici(P1.f,P1.s,P2.f,P2.s,alpha); }
+
+	/** evaluate at P1 */
+	public final void evaluate() { func.evaluate(P1);	}
+
+	/** move P1 to where P2 is now */
+	public final void move() { P1.copy(P2); } // assert that P1.s<0 ?
+
+	/** take step of length lambda from 
+	    P1 in direction of h, evaluate and store in P2 */
+	public void step(double lambda)
+	{
+		for (int i=0; i<n; i++) {
+			P2.x[i] = P1.x[i] + lambda*h[i];
+		}
+
+		func.evaluate(P2);
+		P2.s = Mathx.dot(P2.g,h);
+		alpha=lambda;
+	}
+
+	/** evaluate at P2 */
+	public final void eval2()
+	{
+		func.evaluate(P2);
+		P2.s = Mathx.dot(P2.g,h);
+	}
+
+	/** evaluate slope at P1 using gradient at P1 */	
+	public final void setSlope() { 
+		double s1 = Mathx.dot(P1.g,h); 
+		if (Double.isNaN(s1)) throw new Error( "slope 1 is NaN");
+		if (s1>0) {
+			Shell.trace(toString());
+			Shell.trace("bad new slope="+s1);
+		}
+		P1.s = s1;
+	}
+
+	/** set slope at P2, assert new slope is negative */	
+	public final void setSlope2(double s2)
+	{
+		if (Double.isNaN(s2)) throw new Error( "slope 2 is NaN");
+
+		if (s2>0) {
+			Shell.trace(" ***** BAD DIRECTION UPDATE **** ");
+			Shell.trace(toString());
+			Shell.trace("-- slope = "+s2);
+		}
+	
+		P2.s=s2;
+	}
+
+	public String toString() {
+		return append(new StringBuffer()).toString();
+	}
+	
+	public double initialStep() {
+		double step=2*Math.abs(P1.f/P1.s);
+		if (Double.isNaN(step)) return 1;
+		return Util.clip(0.01,step,1);
+	}
+
+	/** estimate initial step for line search after turn */
+	public double nextStep()
+	{
+		double beta;
+
+		if (P2.s<=P1.s) return 1;		
+		if (P2.s>0) {
+			// signal: 'overshoot, updhess'
+			// expect beta between 0 and 1
+			if (alpha<0.9) beta=alpha;
+			else beta=cubic();
+			if (Double.isNaN(beta) || Double.isInfinite(beta)) beta=1;
+		} else {
+			// signal: 'undershoot, updhess'
+			double gamma=1.5*alpha; if (gamma<2) gamma=2;
+			double delta=alpha*(P2.s-P1.s)-P2.s+(alpha>1?alpha:1);
+			// double delta=uv-P2.s+(alpha>1?alpha:1);
+			beta=cubic();
+			if (Double.isNaN(beta) || Double.isInfinite(beta) || beta<alpha) beta=2*alpha+1e-5;
+			beta*=1.2;
+			if (gamma<beta) beta=gamma;
+			if (delta<beta) beta=delta;
+		}
+
+		return beta;
+	}
+
+	public StringBuffer append(StringBuffer info) 
+	{
+		info.append(DoubleFormat.format(P1.f,4))
+			.append(", ")
+			.append(DoubleFormat.format(P1.s,4))
+			.append("\t")
+			.append(DoubleFormat.format(alpha,4))
+			.append("\t")
+			.append(DoubleFormat.format(P2.f,4))
+			.append(", ")
+			.append(DoubleFormat.format(P2.s,4))
+			.append(" : "); // .append(this.info);
+		return info;		
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/SubspaceFunctionx.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+
+/**
+	This is a function interface that is designed
+	to allow efficient implementations of minimisation
+	algorithms by recognising the fact that the
+	function and its gradient may be repeatedly 
+	evaluated at the same point in different parts
+	of the code - hence we can save ourselves
+	some computation.
+
+ */
+
+
+public class SubspaceFunctionx implements Functionx
+{
+	Functionx	fn;	// underlying function
+	Datum			P;		// Datum big enough for fn
+	int []		k;		// small array of indices into big space
+	int			m;
+
+	public SubspaceFunctionx(Functionx fn, int n, int m) {
+		this.fn=fn;
+		this.m=m;
+		P=new Datum(n);
+		k=new int[m];
+	}
+
+	/** means ith coor in little space maps to jth coor in big space */
+	public void setMap(int i, int j) { k[i]=j; }
+	public double[] getX() { return P.x; }
+	
+	/** get value and gradient for supplied point */
+	public void evaluate( Datum P) {
+		projectUp(P.x, this.P.x);
+		fn.evaluate(this.P);
+		P.f=this.P.f;
+		projectDown(this.P.g,P.g);
+	}
+
+	/** set argument to x, return value and put gradient in dx */
+	public double evaluate( double [] x, double [] g) {
+		projectUp(x,P.x);
+		P.f=fn.evaluate(P.x,P.g);
+		projectDown(P.g,g);
+		return P.f;
+	}
+
+	protected void projectUp(double [] a, double [] b) {
+		for (int i=0; i<m; i++) b[k[i]]=a[i];
+	}
+	
+	protected void projectDown(double [] a, double [] b) {
+		for (int i=0; i<m; i++) b[i]=a[k[i]];
+	}
+
+	public void dispose() { P.dispose(); fn.dispose(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/UnconstrainedConjGrad.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,91 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.core.util.heavy.*;
+
+/**
+		unconstrained minimiser for smooth functions:
+		-	ConjugateGradient 
+		-	OR Quasi-newton (using GillMurray updates)
+
+		-	Safeguarded cubic interpolation line search using gradients
+   */
+
+
+public class UnconstrainedConjGrad extends MinimiserBase
+{
+	ConjGrad		dir;
+	double			guess;
+
+	public UnconstrainedConjGrad(Vec v, Functionx f)
+	{
+		super(v,f);
+		dir = new ConjGrad(this);
+		add(new VParameter( "hessian", new DoubleModel() {
+			public void set(double h) { dir.invhess=1/h; }
+			public double get() { return 1/dir.invhess; }
+		} ));
+	}
+
+	public void stopping() {}
+	public void run()
+	{
+		double	beta;
+		int		i, maxiter=getMaxiter();
+		boolean	triedSteepest=false;
+
+		// dir.resetHessian(1);
+		evaluate();
+		dir.init();
+		setSlope();
+		// beta = vs.beta.value;
+		beta = initialStep();
+		sig1.off();
+
+		for (i=0; i<maxiter; i++) {
+
+			step(beta);
+			lstest.init();
+			ls.run(lstest);			// line search
+			lsiters.next(lstest.count);
+			steplength.next(alpha);
+
+			if (lstest.tiny && (P2.f>=P1.f)) {
+				//  tiny step was no good
+				sig1.on();
+				sig2.off();
+				if (gconv.isSatisfied(P1.g,this)) break;
+				if (triedSteepest=true) break;
+				sig2.on();
+
+				beta = this.beta.value;
+
+
+				dir.init(); // reset to steepest descent
+				setSlope();
+				triedSteepest=true;
+				continue;
+			}
+
+			if (xfconv.isSatisfied(this)) { break; }
+
+			beta = nextStep();
+			// beta = vs.beta.value;
+			dir.update();
+			move();
+			perIteration();
+		}
+
+		perOptimisation(i); // finishing off stuff
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/UnconstrainedMinimiser.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,95 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.util.heavy.*;
+
+
+/**
+		unconstrained minimiser for smooth functions:
+		-	ConjugateGradient 
+		-	OR Quasi-newton (using GillMurray uydates)
+
+		-	Safeguarded cubic interpolation line search using gradients
+   */
+
+
+
+
+
+public class UnconstrainedMinimiser extends MinimiserBase
+{
+	GillMurray		dir;
+	double			guess;
+
+	/** expects to find Vec at top of stack, 
+		Functionx just below.
+	  */
+	public UnconstrainedMinimiser(Vec v, Functionx f) 
+	{
+		// can we rely on evaluation order here?
+		super(v,f);
+		dir = new GillMurray(this);
+		add( dir.hessin.viewable());
+	}
+
+	public void run()
+	{
+		double	beta;
+		int		i, maxiter=getMaxiter();
+		// boolean	triedSteepest=false;
+
+		// dir.resetHessian(1);
+		evaluate(); 
+		dir.init();
+		setSlope();
+		// beta = beta.value;
+		beta = initialStep();
+		sig1.off();
+
+		for (i=1; i<=maxiter; i++) {
+		
+			lstest.init();
+			step(beta);
+			ls.run(lstest);			// line search
+			lsiters.next(lstest.count);
+			steplength.next(alpha);
+			
+			if (lstest.tiny && (P2.f>=P1.f)) {
+				//  tiny step was no good
+				sig1.on();
+				sig2.off();
+				if (gconv.isSatisfied(P1.g,this)) break;
+				// if (triedSteepest=true) break;
+				sig2.on();
+
+				beta = this.beta.value;
+				// dir.steepest();
+				dir.update(); 
+				dir.init(); 
+				setSlope();
+				// triedSteepest=true;
+				continue;
+			}
+
+			if (xfconv.isSatisfied(this)) { break; }
+			
+			// beta = beta.value; 
+			beta = nextStep();
+			dir.update();			
+			move();
+			perIteration();
+		}
+
+		perOptimisation(i);
+		dir.hessin.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/Util.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,60 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+
+public class Util
+{
+	public static double maxabs(double [] x)
+	{
+		double m=Math.abs(x[0]);
+		for (int i=1; i<x.length; i++) {
+			if (x[i]<-m)	 m=-x[i];
+			else if (x[i]>m) m=x[i];
+		}
+		return m;
+	}
+
+	// returns abs(x)	> tol ? x : tol*sgn(x)
+	public static double unzero(double x, double tol) {
+		if (x>tol) return x;
+		else if (x<-tol) return x;
+		else if (x>0) return tol;
+		else return -tol;
+	}
+
+	public static boolean between(double b, double u, double c)
+	{
+		if (b<c) return ((b<u) && (u<c));
+		else     return ((c<u) && (u<b));
+	}
+
+	public static double clip(double lower, double t, double upper)
+	{
+		if (t<=lower) return lower;
+		else if (t>=upper) return upper;
+		else return t;
+	}
+
+	public static double cubici( double f1, double g1, double f2, double g2, double lambda)
+	{
+		double z=g2+g1-3*(f2-f1)/lambda;
+		double w=z*z-g1*g2;
+		w = (w>0) ? Math.sqrt(w) : 0;
+		return lambda*((z+g1+w)/(g2+g1+2*z));
+	}
+
+	public static int find( int i, int [] A, int n)
+	{
+		for (int j=0; j<n; j++) {
+			if (A[j]==i) return j;
+		}
+		return -1;		
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/XFConvergence.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,28 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+
+// this used to happen in QuasiNewton
+// after any step was taken (including during line searches)
+// of-course, S.h cannot change during a line search
+
+public class XFConvergence
+{
+	double	XTOL, FTOL;	// various tolerances
+	
+	public void setXTolerance( double tolx) { XTOL=tolx; }
+	public void setFTolerance( double tolf) { FTOL=tolf; }
+	
+	public boolean isSatisfied(State S) 
+	{
+		return (Util.maxabs(S.h)<2*XTOL) && (Math.abs(S.P1.s)<2*FTOL);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/opt/ZeroCrossingSparsity.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,256 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.opt;
+import  samer.maths.*;
+import  samer.core.*;
+import  samer.core.types.*;
+import  java.util.*;
+
+/**
+		Constraints and line minimisations for functions with gradient
+		discontinuity at co-ordinate zeros (hyperplanes). 
+		The ZeroCrossingSparsity class handles this by checking for
+		zero crossings during the line search. If a gradient 
+		discontinuity causes a change of sign in the gradient,
+		that dimension is constrained and becomes inactive (drops
+		out of minimisation). It can later be reactivated if
+		the algorithm determines that the gradient no longer 
+		changes sign at that point.
+  */
+
+public class ZeroCrossingSparsity extends Constraints
+{
+	public double	alphas[];
+	public int		crossings[];
+	public int		numcrossings;
+	public int		clipped=0;
+	private int		released, releasable;
+	private double	XEPS=1e-6, GEPS=1e-4;
+	private double	GTHRESH=1;
+
+	public static Factory factory() {
+		return new Factory() {
+			public Constraints build(MinimiserBase minimiser) { 
+				return new ZeroCrossingSparsity(minimiser);
+			}
+		};
+	}
+
+	public ZeroCrossingSparsity(MinimiserBase minimiser)
+	{
+		super(minimiser);
+		crossings=new int[n];
+		alphas=new double[n];
+
+		minimiser.add(new VParameter("XEPS", new DoubleModel() {
+				public void set(double t) { XEPS=t; }
+				public double get() { return XEPS; }
+			} )
+		);
+
+		minimiser.add(new VParameter("GEPS", new DoubleModel() {
+				public void set(double t) { GEPS=t; }
+				public double get() { return GEPS; }
+			} )
+		);
+
+		try {
+			final Object jump=Shell.get("ZeroCrossingSparsity.jump");
+			if (jump instanceof Double) {
+				GTHRESH=((Double)jump).doubleValue();
+				Shell.print("Gradient jump="+GTHRESH);
+			} else if (jump instanceof VDouble) {
+				GTHRESH=((VDouble)jump).value;
+				((VDouble)jump).addObserver( new Observer() {
+					public void update(Observable o, Object arg) {
+						GTHRESH=((VDouble)jump).value;
+					}
+				} );
+				Shell.print("Gradient jump in VDouble="+GTHRESH);
+			}
+		} catch (Exception ex) {
+			Shell.print("*** no jump object found! ***");
+			Shell.print(ex.toString());
+			ex.printStackTrace();
+		}
+	}
+
+	public void setGThreshold(double gt) { GTHRESH=gt; }
+
+	/** constrain all dimensions which are currently set
+	    to zero.
+	  */
+
+	public void initialise()
+	{
+		int p=0, q=0;
+
+		for (int i=0; i<n; i++) {
+			if (S.P1.x[i]==0) inactive[p++]=i;
+			else active[q++]=i;
+		}
+		m=q;
+	}
+
+
+	/** find all the zero crossings */
+		
+	private boolean check() 
+	{
+		// got to find sign swappers
+		numcrossings=0;
+		for (int j=0; j<m; j++) {
+			int i=active[j];
+			if ( (S.P1.x[i]>XEPS && S.P2.x[i]<XEPS)
+			  || (S.P2.x[i]>-XEPS && S.P1.x[i]<-XEPS) ) {
+				crossings[numcrossings]=i;
+				alphas[numcrossings]=-S.P1.x[i]/S.h[i];
+				numcrossings++;
+			}
+		}
+		return numcrossings>0;
+	}
+
+	public void report() 
+	{
+		if (numcrossings>0) {
+			Shell.trace("crossings: "+numcrossings);
+			for (int i=0; i<numcrossings; i++) {
+				Shell.trace("dim: "+crossings[i]+" alpha: "+alphas[i]);
+			}
+		}
+		super.report();
+	}
+	
+
+	/**
+		This finds the constrained dimension with the
+		largest gradient, and if that absolute value of
+		that gradient is bigger than 1, then releases 
+		that dimension so that it can take part in the 
+		optimization
+	 */
+
+	public boolean release(Datum P)
+	{
+		if (m==n) return false; // all active
+
+		int imax=-1;
+		double grad=GTHRESH+GEPS;
+
+		releasable=0;
+		for (int k=0; k<(n-m); k++) {
+			int j=inactive[k];
+			if (Math.abs(P.g[j])>grad) {
+				releasable++;
+				grad=Math.abs(P.g[j]);
+				imax=j;
+			}
+		}
+		
+		if (imax!=-1) {	
+			activate(imax); released=imax; 
+			return true; 
+		}
+		else return false;
+	}
+
+	public int getReleasedDimension() { return released; }
+	public int getReleasableDimensions() { return releasable; }
+
+	public void lineSearch(Condition convergence, CubicLineSearch ls, double beta0)
+	{
+		boolean zcdone=false;
+
+		step(beta0);
+		eval2();
+
+		while (!convergence.test()) {
+
+			// formulate any other direction change conditions
+
+			if (S.P2.f<S.P1.f && S.P2.s<0) {
+				double beta=ls.extrapolate();
+				S.move();
+				step(beta);
+				eval2();
+				zcdone=false;
+			} else { 
+				/* couple of options here:
+					we could check all the zero crossings in one go.
+					if we find one that needs constraining, then
+					we're done.
+					otherwise, we don't need to check zero crossings
+					again unless we extrapolate
+
+					other option is to backtrack one zero crossing
+					at a time
+
+					OR find zero crossing just after (or before) 
+					expected minimum
+					
+				 */
+
+				// get cubic step
+				double interp = ls.interpolate();
+
+				if (!zcdone) { check(); zcdone=true; }
+
+				// try to pick a good step length
+				// bearing in mind the zero crossings we have
+				if (numcrossings>0) {
+
+					// we are going to look at the alphas, and
+					// find the smallest one that is between 
+					// interp and current alpha
+
+					int best=-1;
+					double bestAlpha=S.alpha;
+
+					for (int k=0; k<numcrossings; k++) {
+						double beta=alphas[k];
+						if (beta>=interp && beta<bestAlpha) {
+							best=k; bestAlpha=beta;
+						}
+					}
+	
+					if (best!=-1) {
+						int		j=crossings[best];
+
+						// kth zero crossing of jth dimension
+						step(bestAlpha);
+						S.P2.x[j]=0;
+						eval2();
+						if (Math.abs(S.P2.g[j])<=GTHRESH-GEPS) {
+							inactivate(j);
+							// Shell.trace("- inactivating: "+j);
+							return;
+
+							// what if SEVERAL dimensions
+							// end up close to zero:
+							// should we constrain them all?
+						} else {
+							// Shell.trace("truncating");
+							// what?
+							// should we stick with this point, or
+							// move to interp?
+							continue;
+						}
+					} // else fall through to ordinary step
+				} 
+
+				// no crossings, take ordinary step
+				step(interp);
+				eval2();
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/BaseRandom.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,25 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+import  java.util.Random;
+
+abstract public class BaseRandom implements Generator
+{
+	protected Random rnd;
+
+	public BaseRandom() { rnd=new Random(); }
+	public void dispose() {}
+	public void next(double [] x)
+	{
+		int i, n=x.length;
+		for (i=0; i<n; i++) x[i] = next();
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Binary.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.types.*;
+
+public class Binary extends BaseRandom
+{
+	VDouble	p = new VDouble("p",0.5);
+
+	public Binary() {}
+	public Binary(double p) { this.p.value=p; this.p.changed(); }
+
+	public void dispose() { p.dispose(); }
+	public double next() { return (rnd.nextDouble()<p.value) ? 1.0 : 0.0; }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=(rnd.nextDouble()<p.value) ? 1.0 : 0.0; 
+	}
+
+	public String toString() { return "Binary"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/BinaryVec.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,48 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* Similar to binary, but has different bit probabilities
+   for elements of vector
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+public class BinaryVec extends BaseRandom
+{
+	int		n;
+	VVector	probs;
+	double	[] p;
+	boolean ownp;
+
+	public BinaryVec(int n, double pp) { 
+		this(new VVector("probs",n)); 
+		ownp=true;
+		for (int i=0; i<n; i++) p[i]=pp;
+	}
+
+	public BinaryVec(VVector probs) { 
+		this.n=probs.size();
+		this.probs=probs;
+		p=probs.array(); 
+		ownp=false;
+	}
+
+	public int  getSize() { return n; }
+	public void dispose() { if (ownp) probs.dispose(); }
+	public double next() { return (rnd.nextDouble()<p[0]) ? 1.0 : 0.0; }
+	public void   next(double [] x) { 
+		int i, j;
+		for (i=0,j=0; i<x.length; i++,j++) {
+			if (j>=n) j=0;
+			x[i]=(rnd.nextDouble()<p[j]) ? 1.0 : 0.0; 
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/BipolarUniform.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class BipolarUniform extends BaseRandom
+{
+	public double next() { return 2*rnd.nextDouble()-1; }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=2*rnd.nextDouble()-1; 
+	}
+	public String toString() { return "Uniform[-1,1)"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/BoundedHyperbolic.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,46 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.types.*;
+import  java.util.*;
+
+/*
+ *		Hyperbolic distribution: power law with exponent 1.
+ *		Integral of pdf diverges in both directions, so we
+ *		need both upper and lower cut-offs.
+ */
+public class BoundedHyperbolic extends BaseRandom implements Observer
+{
+	VDouble min = new VDouble("min",1);
+	VDouble max = new VDouble("max",2);
+	double  a, b;
+
+	public void dispose() { min.dispose(); max.dispose(); }
+	public double next() { return b*Math.exp(a*rnd.nextDouble()); }
+
+	public BoundedHyperbolic( double min, double max) 
+	{
+		this();
+		this.min.value = min; this.min.changed();
+		this.max.value = max; this.max.changed();
+	}
+
+	public BoundedHyperbolic() 
+	{
+		min.addObserver(this);
+		max.addObserver(this);
+		update(null,null);
+	}
+
+	public void update(Observable o, Object oo) {
+		a=Math.log(min.value/max.value); 
+		b=max.value;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/BoundedUniform.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,45 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.types.*;
+import  java.util.*;
+
+public class BoundedUniform extends BaseRandom implements Observer
+{
+	VDouble min = new VDouble("min",0);
+	VDouble max = new VDouble("max",1);
+	double  a, b;
+
+	public String toString() { return "Uniform["+min.value+","+max.value+")"; }
+	
+	public void dispose() { min.dispose(); max.dispose(); }
+	public double next() { return a + b*rnd.nextDouble(); }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=a + b*rnd.nextDouble(); 
+	}
+
+	public BoundedUniform( double min, double max) 
+	{
+		this();
+		this.min.value = min; this.min.changed();
+		this.max.value = max; this.max.changed();
+	}
+
+	public BoundedUniform() 
+	{
+		min.addObserver(this);
+		max.addObserver(this);
+		update(null,null);
+	}
+
+	public void update(Observable o, Object oo) {
+		a=min.value; b=max.value-min.value;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Brownian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  java.util.*;
+
+public class Brownian extends BaseRandom
+{
+	double	prev=0;
+
+	public void reset()  { prev=0; }
+	public double next() { return prev+=rnd.nextGaussian(); }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/BaseRandom.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Binary.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/BinaryVec.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/BipolarUniform.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/BoundedHyperbolic.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/BoundedUniform.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Brownian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Cauchy.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Exponential.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Gaussian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GeneralisedExponential.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GeneralisedLaplacian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Laplacian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Logistic.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Mixture.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MixtureVec.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/NormalisedGaussian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/PosteriorSampler.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/PowerLaw.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Raleigh.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/RectifiedCauchy.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/RectifiedGaussian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/RectifiedLogistic.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/SparseMixture.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Ternary.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Uniform.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/maths/random
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Cauchy.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,18 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  java.util.*;
+
+public class Cauchy extends BaseRandom
+{
+	public double next() { 
+		return Math.tan(0.9999*Math.PI*(rnd.nextDouble()-0.5));
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Exponential.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class Exponential extends BaseRandom
+{
+	public double next()
+	{ 
+		double x;
+		do { x=rnd.nextDouble(); } while (x==0.0);
+		return -Math.log(x); 
+	}
+	public String toString() { return "Exponential"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Gaussian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,36 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.*;
+import  samer.core.types.*;
+
+public class Gaussian extends BaseRandom
+{
+	VDouble	var;
+	VDouble	mean;
+
+	public Gaussian() {
+		var=new VDouble("variance", 1.0);
+		mean=new VDouble("mean", 0.0);
+	}
+
+	public Gaussian(double v, double m) {
+		var=new VDouble("variance",v,Variable.REGISTER|Variable.NOINIT);
+		mean=new VDouble("mean",m,Variable.REGISTER|Variable.NOINIT);
+	}
+
+	public void dispose() { var.dispose(); mean.dispose(); }
+	public double next() { return mean.value + var.value*rnd.nextGaussian(); }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=mean.value+var.value*rnd.nextGaussian();
+	}
+
+	public String toString() { return "Gaussian"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/GeneralisedExponential.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.maths.*;
+
+// This is going to work by the rejection method
+// (see Numerical Recipes in C)
+// We'll use the cauchy distribution as our
+// bounding function
+
+// NB ONLY WORKS FOR alpha<=2!
+
+public class GeneralisedExponential implements Generator
+{
+	BaseRandom	cauchy = new RectifiedCauchy();
+	VDouble		alpha = new VDouble("alpha", 1);
+
+	public void dispose() { cauchy.dispose(); alpha.dispose(); }
+	public double next()
+	{ 
+		double x, f, g, a=alpha.value;
+		do {
+			// first, get a Cauchy distributed RV
+			x = 2*cauchy.next();
+			f = 4/(4+x*x); // cauchy
+			g = Math.exp(-Math.pow(x,a)); // exponential
+		} while (f*cauchy.rnd.nextDouble()>g);
+		return x; 
+	}
+
+	public void next(double [] x)
+	{
+		for (int i=0; i<x.length; i++) x[i]=next();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/GeneralisedLaplacian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,37 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.*;
+import  samer.core.types.*;
+
+// This is going to work by the rejection method
+// (see Numerical Recipes in C)
+// We'll use the cauchy distribution as our
+// bounding function
+
+// NB ONLY WORKS FOR alpha<=2!
+
+public class GeneralisedLaplacian extends Cauchy
+{
+	VDouble	alpha = new VDouble("alpha", 1);
+
+	public void dispose() { alpha.dispose(); }
+	public double next()
+	{ 
+		double x, f, g, a=alpha.value;
+		do {
+			// first, get a Cauchy distributed RV
+			x = 2*super.next();
+			f = 4/(4+x*x); // cauchy
+			g = Math.exp(-Math.pow(Math.abs(x),a)); // exponential
+		} while (f*rnd.nextDouble()>g);
+		return x; 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Laplacian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,23 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class Laplacian extends BaseRandom
+{
+	public double next()
+	{ 
+		double x;
+		do { x=2*rnd.nextDouble()-1; } while (x==0.0);
+		if (x>0) return -Math.log(x); 
+		else     return Math.log(-x);
+	}
+
+	public String toString() { return "Laplacian"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Logistic.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+
+public class Logistic extends BaseRandom
+{
+	public double next()	{ return Mathx.atanh(2*rnd.nextDouble()-1); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Mixture.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+public class Mixture extends BaseRandom
+{
+	VDouble		p = new VDouble("p",0.5);
+	Generator	g1;
+	Generator	g2;
+
+	public void dispose() { p.dispose(); g1.dispose(); g2.dispose(); }
+	public double next() { return (rnd.nextDouble()<p.value) ? g1.next() : g2.next(); }
+
+	public Mixture(Generator g1, Generator g2) 
+	{
+		this.g1=g1;
+		this.g2=g2;
+	}
+
+	public String toString() { return "Mixture("+g1+","+g2+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/MixtureVec.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,38 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+public class MixtureVec extends BaseRandom
+{
+	BinaryVec	u;
+	Generator	g1;
+	Generator	g2;
+
+	public void dispose() { u.dispose(); g1.dispose(); g2.dispose(); }
+	public double next() { return (u.next()==1) ? g1.next() : g2.next(); }
+
+	public void next(double [] x)
+	{ 
+		u.next(x);
+		for (int i=0; i<x.length; i++) {
+			if (x[i]==1) x[i]=g1.next();
+			else         x[i]=g2.next();
+		}
+	}
+
+	public MixtureVec(Generator g1, Generator g2, BinaryVec u) 
+	{
+		this.u=u;
+		this.g1=g1;
+		this.g2=g2;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/NormalisedGaussian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class NormalisedGaussian extends BaseRandom
+{
+	public double next() { return rnd.nextGaussian(); }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=rnd.nextGaussian();
+	}
+	public String toString() { return "Gaussian"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/PosteriorSampler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,50 @@
+package samer.maths.random;
+import samer.maths.*;
+import samer.core.*;
+
+/**
+ sample from posterior
+ instead of supplying weighting factor,
+ reject a fraction of the samples 
+ make take a long time if A<<sigma
+*/
+
+class PosteriorSampler extends BaseRandom
+{
+	double A, sigma;
+	double std, var, mean;
+
+	public PosteriorSampler() {}
+
+	public void setA(double a) { A=a; std=sigma/A; var=std*std; }
+	public void setSigma(double s) { sigma=s; std=sigma/A; var=std*std; }
+	public void setx(double x) { mean=x/A; }
+
+	public double next() 
+	{
+		double v;
+		boolean ok=false;
+
+		do {
+			v=mean + std*rnd.nextGaussian();
+
+			if (v<=-var) {
+				v=v+var;
+				if (mean<0) {
+					double k=Math.exp(2*mean);
+					double u=rnd.nextDouble();
+					if (u<k) ok=true;
+				} else ok=true;
+			} else if (v>=var) {
+				v=v-var;
+				if (mean>0) {
+					double k=Math.exp(-2*mean);
+					double u=rnd.nextDouble();
+					if (u<k) ok=true;
+				} else ok=true;
+			}
+		} while (!ok);
+
+		return v;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/PowerLaw.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,39 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.types.*;
+import  java.util.*;
+
+/*
+ *		Generates random numbers from a single-sider power-law 
+ *		with a lower cut-off, but no upper cut-off. The
+ *		exponent must therefore be strictly less than 1.
+ */
+public class PowerLaw extends BaseRandom implements Observer
+{
+	VDouble min = new VDouble("min",1);
+	VDouble D   = new VDouble("exponent",1);
+	double  a, b;
+
+	public void dispose() { min.dispose(); D.dispose(); }
+	public double next() { return a*Math.pow(rnd.nextDouble(),b); }
+
+	public PowerLaw() 
+	{
+		min.addObserver(this);
+		D.addObserver(this);
+		update(null,null);
+	}
+
+	public void update(Observable o, Object oo) {
+		a=min.value;
+		b=-1/D.value;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Raleigh.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class Raleigh extends BaseRandom
+{
+	public double next()
+	{ 
+		double x;
+		do { x=rnd.nextDouble(); } while (x==0.0);
+		return Math.sqrt(-2*Math.log(x)); 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/RectifiedCauchy.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class RectifiedCauchy extends BaseRandom
+{
+	public double next() { 
+		return Math.tan(0.499*Math.PI*rnd.nextDouble());
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/RectifiedGaussian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,18 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class RectifiedGaussian extends BaseRandom
+{
+	public double next() { return Math.abs(rnd.nextGaussian()); }
+	public void   next(double [] x) { 
+		for (int i=0; i<x.length; i++) x[i]=Math.abs(rnd.nextGaussian());
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/RectifiedLogistic.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+
+public class RectifiedLogistic extends BaseRandom
+{
+	public double next()	{ return Mathx.atanh(rnd.nextDouble()); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/SparseMixture.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+public class SparseMixture extends BaseRandom
+{
+	VDouble		p = new VDouble("p",0.5);
+	Generator	g1;
+	
+	public void dispose() { g1.dispose(); p.dispose(); }
+	public double next() { return (rnd.nextDouble()<p.value) ? 0 : g1.next(); }
+
+	public SparseMixture(Generator g1) { this.g1=g1; }
+	public String toString() { return "Sparsified "+g1; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Ternary.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+import  samer.core.types.*;
+
+public class Ternary extends BaseRandom
+{
+	VDouble	p = new VDouble("p",0.5);
+
+	public void dispose() { p.dispose(); }
+	public double next() { 
+		double r=rnd.nextDouble();
+		if (r>=p.value) return 0;
+		if (r<p.value/2) return -1;
+		return 1;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/maths/random/Uniform.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,19 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.maths.random;
+
+public class Uniform extends BaseRandom
+{
+	public double next() { return rnd.nextDouble(); }
+	public void   next(double [] x) {
+		for (int i=0; i<x.length; i++) x[i]=rnd.nextDouble(); 
+	}
+	public String toString() { return "Uniform[0,1)"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,14 @@
+/CorrelationTask.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/CovarianceTask.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/DistanceTask.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Euclidean.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GeometricFilter.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MDS.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MDSBase.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Manhatten.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MatrixBall.java.not/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MatrixPointViewer2.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Minkowski.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/NewMDS.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/ProximityFilter.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/mds
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/CorrelationTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+package samer.mds;
+
+// import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+	Transfer correlation matrix to MDS distances. Assumes 1s
+	down the main diagonal and a symmetric matrix.
+  */
+public class CorrelationTask extends AnonymousTask
+{
+	int		N;
+	double [] d;				// linear array of distances
+	double [][] _R;			// matrix of correlation coefficients
+		
+	/** link each object to all the others using distances in matrix, returns a task
+		that can be used to refresh distances from original matrix */
+	public CorrelationTask(MDSBase mds, Matrix R) {
+		N = R.getRowDimension();
+		
+		d=new double[N*(N - 1)/2];
+		_R=R.getArray();
+		
+		mds.clearLinks(d);
+		for (int k=0, i=0; i<N; i++) 
+			for (int j=0; j<i; j++) mds.setLink(k++,i,j);
+		
+		run();
+	}
+
+	public Vec getDistances() { return new Vec.ForArray(d); }
+	public void run() {
+		for (int k=0, i=0; i<N; i++) {
+			double [] Ri=_R[i];
+			for (int j=0; j<i; j++)
+				d[k++]=Math.sqrt(-Math.log(Math.abs(Ri[j])));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/CovarianceTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,44 @@
+package samer.mds;
+
+// import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+	Transfer covariance matrix to MDS distances
+	Assumes that elements are not normalised to unit variance
+  */
+public class CovarianceTask extends AnonymousTask
+{
+	int		N;
+	double [] d;				// linear array of distances
+	double [][] _C;			// matrix of covariances
+	double [] var;			// array of variances
+		
+	/** link each object to all the others using distances in matrix, returns a task
+		that can be used to refresh distances from original matrix */
+	public CovarianceTask(MDSBase mds, Matrix C) {
+		N = C.getRowDimension();
+		
+		d=new double[N*(N - 1)/2];
+		var=new double[N];
+		_C=C.getArray();
+		
+		mds.clearLinks(d);
+		for (int k=0, i=0; i<N; i++) 
+			for (int j=0; j<i; j++) mds.setLink(k++,i,j);
+		
+		run();
+	}
+
+	public Vec getDistances() { return new Vec.ForArray(d); }
+	public void run() {
+		for (int i=0; i<N; i++) var[i]=_C[i][i];
+		for (int k=0, i=0; i<N; i++) {
+			double [] Ci=_C[i];
+			double vari=var[i];
+			for (int j=0; j<i; j++)
+				d[k++]=Math.sqrt(0.5*Math.log(vari*var[j]/(Ci[j]*Ci[j])));
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/DistanceTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,39 @@
+package samer.mds;
+
+// import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+	Transfer distances directly from a distance matrix to an MDS
+	object's distance vector.
+*/
+public class DistanceTask extends AnonymousTask
+{
+	int		N;
+	double [] d;				// linear array of distances
+	double [][] _D;			// matrix of source data
+		
+	/** link each object to all the others using distances in matrix, returns a task
+		that can be used to refresh distances from original matrix */
+	public DistanceTask(MDSBase mds, Matrix D) {
+		N = D.getRowDimension();
+		
+		d=new double[N*(N - 1)/2];
+		_D=D.getArray();
+		
+		mds.clearLinks(d);
+		for (int k=0, i=0; i<N; i++) 
+			for (int j=i+1; j<N; j++) mds.setLink(k++,i,j);
+		
+		run();
+	}
+
+	public Vec getDistances() { return new Vec.ForArray(d); }
+	public void run() {
+		for (int k=0, i=0; i<N; i++) {
+			double [] Drow=_D[i];
+			for (int j=i+1; j<N; j++) d[k++]=Drow[j];
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/Euclidean.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,11 @@
+package samer.mds;
+
+/** Euclidean metric */
+
+public class Euclidean implements MDS.Metric {
+	public double d(double [] x, double [] y, double [] r) {
+		double a=0;
+		for (int i=0; i<r.length; i++) { r[i]=y[i]-x[i]; a+=r[i]*r[i]; }
+		return Math.sqrt(a);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/GeometricFilter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+package samer.mds;
+
+import samer.maths.*;
+import samer.tools.*;
+
+public class GeometricFilter extends AnonymousTask {
+	int				N;
+	Matrix		P;			// point positions (N by E)
+	Vec			F;			// filter coefficients (N element)
+	FunctionOfVector	fn;		// map from proximity to coeff.
+	
+	public GeometricFilter(Matrix P, Vec F, FunctionOfVector fn) {
+		this.P=P; this.F=F; this.fn=fn;
+		N=F.size();
+	}
+	public void run() { 	
+		double [][] _P=P.getArray();
+		double [] _F=F.array();
+		for (int i=0; i<N; i++) _F[i] = fn.apply(_P[i]);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/MDS.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,90 @@
+package samer.mds;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+     This is an alternative version of MDS that uses less memory.
+     Rather than keep a record of the force in each link, it accumulates
+     the link forces on a per-object basis.
+ */
+public class MDS extends MDSBase
+{
+	Metric		metric;		// metric function
+	Stress		stress;		// stress function
+
+	public interface Metric {
+		/** return distance between x and y, put y-x in r */
+		double d(double [] x, double [] y, double [] r);
+	}
+
+	public interface Stress {
+		/** accumulate stress due to a link and return dStress/dcurrent */
+		double add( double target, double current);
+
+		/** return normalised stress and reset for next time */
+		double done();
+
+		/** return last value returned by done() */
+		double get();
+	}
+
+	public static class SamerStress implements Stress {
+		double S=0, a=0;
+		int			n=0;
+
+		public double add( double target, double current) {
+			a += sqr(current/target-1); n++;
+			return (current-target)/(target*target);
+		}
+		public double done() { S=a/n; a=0; n=0; return S; }
+		public double get() { return S; }
+		private final static double sqr(double t) {return t*t;}
+	}
+
+	public MDS(Matrix p)
+	{
+		super(p);
+
+		Shell.push(node);
+		metric=new Euclidean();
+		stress=new SamerStress();
+		Shell.pop();
+	}
+
+	public void setMetric(Metric m) { metric=m; }
+
+	public void run()
+	{
+		double [][] _P=P.getArray();
+		double	d, dS;
+		int 		i, j, k;
+
+		// accumulate all forces on a per object basis
+
+		for (k=0; k<N; k++) Mathx.zero(F[k]); // zero out object forces
+		for (k=0; k<M; k++) {			// for each link
+			i=l1[k]; j=l2[k]; 				// object indices
+			d=metric.d(_P[i],_P[j],f); 		// current distance, vector from i to j in f
+			dS=stress.add(D[k],d);
+
+			if (d>0) { // ignore if current distance is zero
+				// replace f with dS/dd * grad d
+				Mathx.mul(f,dS/d);
+
+				// f contains 'force' on j from i
+				// accumulate this force for both objects (only E dimensions used)
+				Mathx.add(E,F[i],f);
+				Mathx.sub(E,F[j],f);
+			}
+		}
+		S.set(stress.done());
+
+		// now move objects at the ends of each link,
+		// but only the first E dimensions
+		for (k=0; k<N; k++) Mathx.muladd(E,_P[k],F[k],rate.value);
+		P.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/MDSBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,69 @@
+package samer.mds;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+	MDS base class. Manages a NxE matrix of object positions,
+	an array of links (end point object indices and a distance per link),
+	a stress value and a learning rate, and a buffer which for
+	accumulating the "force" on each object.
+
+	Client code or subclass must set up link array and implement
+	the actual adaptation algorithm.
+*/
+
+public class MDSBase extends Viewable implements Task
+{
+	int			N, M, E;		// points, links, dimensions
+	Matrix		P;			// object positions
+	VDouble		S, rate;	// stress, learning rate
+	double[]		D;			// input distances
+	short []		l1, l2;		// arrays of link end points
+	double [][]	F;			// object 'forces'
+	double []	f; 		// force buffer
+
+	public MDSBase(Matrix p)
+	{
+		super("mds");
+
+		P=p;
+		Shell.push(node);
+		N = p.getRowDimension();
+		E = p.getColumnDimension();
+		Shell.print("MDS: "+N+" objects");
+		Shell.print("MDS: space is "+E+" dimensional");
+		rate = new VDouble("rate",0.001);
+		S = new VDouble("stress");
+		Shell.pop();
+		F = new double[N][P.getColumnDimension()];
+		f = new double[P.getColumnDimension()];
+		M=0;
+		D = new double[M];
+	}
+
+	/** optimises only first E columns of P
+		E must be less than width of original P */
+	public void setDimensionality(int e) { E=e; }
+
+	/** link each object to all the others , returns distance array */
+	public void clearLinks(double [] D) {
+		M=D.length;
+		Shell.print("MDS: creating "+M+" links.");
+
+		l1 = new short[M];
+		l2 = new short[M];
+		this.D = D;
+	}
+
+	/** the kth link joint objects i and j */
+	public void setLink(int k, int i, int j) { l1[k]=(short)i; l2[k]=(short)j; }
+	public double [] getLinkArray() { return D; }
+
+	public void dispose() { S.dispose(); rate.dispose(); }
+	public void starting() {}
+	public void stopping() {}
+	public void run() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/Manhatten.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,11 @@
+package samer.mds;
+
+/** city block or manhatten metricc */
+
+public class Manhatten implements MDS.Metric {
+	public double d(double [] x, double [] y, double [] r) {
+		double a=0;
+		for (int i=0; i<r.length; i++) { r[i]=y[i]-x[i]; a+=Math.abs(r[i]); }
+		return a;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/MatrixBall.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,107 @@
+package samer.mds;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.event.*;
+import samer.core.types.*;
+import samer.core.*;
+import art.oz.*;
+
+public class MatrixBall implements Drawable, Updatable
+{
+	// instance data .....................................
+
+	int         	x, y, ox, oy;
+	double    rx, ry;
+	boolean	changed=true;
+
+	protected	Rectangle dirty=new Rectangle();
+
+	public MatrixBall()	{
+		ox = x = 0; oy = y = 0;
+		rx = 0; ry = 0;
+	}
+
+
+	// static data ........................................
+
+	static Image    defaultBlob;
+	static int      IW=4, IH=4;
+
+	public void draw( Graphics2D g)   { g.drawImage( defaultBlob, ox=x, oy=y, null); }
+	public void undraw( Graphics2D g) { g.clearRect( ox, oy, IW, IH); }
+
+
+	public void moveTo(int x, int y) { this.x=x; this.y=y; }
+	
+	Rectangle tmp=new Rectangle();
+
+	public void update( Oz oz) {
+		dirty.setBounds(x,y,IW,IH);
+		Oz.union(dirty,ox,oy,IW,IH);
+		oz.invalidateRect(dirty);
+	}
+
+	public static Image getImage() { return defaultBlob; }
+	public static void setImage(Image normal) { 
+		defaultBlob = normal; 
+	}
+
+	public static void setBallSize(int w, int h)
+	{
+		IW=w; IH=h;
+		defaultBlob = new BufferedImage(IW,IH,BufferedImage.TYPE_4BYTE_ABGR_PRE);
+	}
+
+	public static void drawBall( Image img, Color c, float alpha)
+	{
+		Graphics2D g=(Graphics2D)img.getGraphics();
+		AlphaComposite comp;
+		
+		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+		g.setBackground(new Color(0,0,0,0));
+		g.clearRect(0,0,IW,IH);
+		g.setComposite( AlphaComposite.SrcOver);
+		drawBall(g,c,alpha);
+		g.dispose();
+	}
+	
+	public static void drawMarker( Image img, Color c, float alpha)
+	{
+		Graphics2D g=(Graphics2D)img.getGraphics();
+		AlphaComposite comp;
+
+		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+		g.setBackground(new Color(0,0,0,0));
+		g.clearRect(0,0,IW,IH);
+		g.setComposite( AlphaComposite.SrcOver);
+		float [] rgba=c.getRGBComponents(null);
+
+		// ball image has transparent background
+		g.setColor(new Color(0,0,0,80));
+		g.fillRect(0,0,IW,IH);
+		g.setColor(new Color(rgba[0],rgba[1],rgba[2],alpha));
+		g.fillRect(1,1,IW-2,IH-2);
+		g.dispose();
+	}
+	
+	public static void drawBall( Graphics2D g, Color c, float alpha)
+	{
+		int cx = IW/2;
+		int cy = IH/2;
+		
+		float [] rgba=c.getRGBComponents(null);
+//		float [] rgba2=c.brighter().getRGBComponents(null);
+		
+		// ball image has transparent background
+		g.setColor(new Color(0,0,0,80));
+		oval(g,cx+1,cy+1,IW/2-2,IH/2-2);
+		g.setColor(new Color(rgba[0],rgba[1],rgba[2],alpha));
+		oval(g,cx,cy,IW/2-3,IH/2-3);
+//		g.setColor(new Color(rgba2[0],rgba2[1],rgba2[2],alpha));
+//		oval(g,4*cx/5,4*cy/5,IH/6,IW/6);
+	}
+
+	static void oval(Graphics2D g,  int x, int y, int rx, int ry) {
+		g.fillOval(x-rx,y-ry,2*rx,2*ry);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/MatrixPointViewer2.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,113 @@
+package samer.mds;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.util.*;
+import java.awt.*;
+
+public class MatrixPointViewer2 extends samer.core.util.swing.VCanvas implements Task, Observer, Agent
+{
+	Matrix			P;			// point positions
+	Vec			x;			// point activities
+	int				N;
+	int				k1, k2;
+	Color[]		clut;
+	VMap			xmap, ymap, cmap;
+	VInteger		markerSize;
+	int[]			ix, iy;
+	
+	public MatrixPointViewer2(Matrix P, Vec x) {
+		this.P=P;
+		this.x=x;
+		N=P.getRowDimension();
+		k1=0; k2=1;
+
+//		ColorRamp cramp=new ColorRamp(256);
+//		cramp.set(0,Color.black);
+//		cramp.gradientTo(255,Color.white);
+		clut=new Color[256];
+		for (int i=0; i<256; i++) clut[i]=new Color(255,255,255,i);
+
+		ix = new int[N];
+		iy = new int[N];
+		
+		markerSize=new VInteger("markerSize",4);
+		cmap=new VMap(new LinearMap(256),new Node("cmap"));
+		xmap=new VMap(new LinearMap(256),new Node("xmap"));
+		ymap=new VMap(new LinearMap(256),new Node("ymap"));
+		exposeCommands(this);
+
+		P.viewable().addObserver(this);
+		xmap.addObserver(this);
+		ymap.addObserver(this);
+	}
+
+	public void sized() {
+		xmap.getMap().setIntRange(width);
+		ymap.getMap().setIntRange(height);
+		update(null,null);
+	}
+	
+	public void attach() { P.viewable().addObserver(this); }
+	public void detach() {
+		P.viewable().deleteObserver(this);
+		xmap.dispose();
+		ymap.dispose();
+		cmap.dispose();
+		markerSize.dispose();
+	}	
+
+	public void rotate() {
+		k2++;
+		if (k2>=P.getColumnDimension()) {
+			k2=0;	k1++;
+			if (k1>=P.getColumnDimension()) k1=0;
+		}
+		if (k2==k1) rotate();
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() { repaint(); }
+	public void dispose() { detach(); }
+	
+	public void update(Observable o, Object a)
+	{
+		double [][] p=P.getArray();
+		IMap		xm=xmap.getMap();
+		IMap		ym=ymap.getMap();
+		
+		for (int i=0; i<N; i++) {
+			double r[]=p[i];
+			ix[i]=xm.toInt(r[k1]);
+			iy[i]=ym.toInt(r[k2]);
+		}
+		repaint();
+	}
+
+	public void paint(Graphics g) {
+		double [] a=x.array();
+		IMap		cm=cmap.getMap();
+		int			b=markerSize.value;
+
+		clear(g);
+		for (int i=0; i<N; i++) {
+			g.setColor(clut[cm.clipInt(a[i])]);
+			g.fillRect(ix[i],iy[i],b,b);
+		}
+	}
+
+	public void getCommands(Registry r) {
+		r.add("rotate").add("x-map").add("y-map").add("c-map");
+	}
+	public void execute(String cmd, Environment env)
+	{
+		if (cmd.equals("rotate")) { rotate(); update(null,null); }
+		else if (cmd.equals("x-map")) Shell.expose(xmap.getViewer(),"x-map");
+		else if (cmd.equals("y-map")) Shell.expose(ymap.getViewer(),"y-map");
+		else if (cmd.equals("c-map")) Shell.expose(cmap.getViewer(),"c-map");
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/Minkowski.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+package samer.mds;
+import samer.core.types.*;
+import samer.maths.*;
+
+/** Minkowski metric */
+
+public class Minkowski implements MDS.Metric {
+	VDouble exponent=new VDouble("exponent",1);
+	public Minkowski(double p) { exponent.set(p); }
+	public double d(double [] x, double [] y, double [] r) {
+		Mathx.sub(r,y,x);
+		double q=0, p=exponent.value;
+		for (int i=0; i<r.length; i++) q+=Math.pow(r[i],p);
+		return Math.pow(q,1/p);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/NewMDS.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,93 @@
+package samer.mds;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+     This is a version that does not use a separete metric and
+	stress function: the stress function is defined directly in terms
+	of the displacement vectors between objects. The distances
+	are now  generalised link targets.
+ */
+public class NewMDS extends MDSBase
+{
+	Stress		stress;		// stress function
+
+	public interface Stress {
+		/** accumulate stress due to a link given end points, return gradient
+			in g, return true if gradient is usable, false of gradient is bad (eg singularity) */
+		boolean add( double target, double [] x, double [] y, double [] g);
+
+		/** return normalised stress and reset for next time */
+		double done();
+
+		/** return last value returned by done() */
+		double get();
+	}
+
+	public static class Laplacian implements Stress {
+		double S=0, a=0;
+		int			n=0, E;
+
+		public Laplacian(int E) { this.E=E; }
+		
+		/** add stress due to link from x to y. Force in link is returned in g.
+			Target is assumed to be a length measured according to a 1-norm. 
+		*/
+		public boolean add( double target, double [] x, double [] y, double [] g) {
+			double b=0;
+			for (int i=0; i<E; i++) {
+				b+=Math.abs(x[i]-y[i]);
+				g[i]=sgn(x[i]-y[i]);
+			}
+			b += sqr(b/target-1); n++;
+			Mathx.mul(g,(b-target)/(target*target));
+			return true;
+		}
+		
+		/** finish accumulating stress terms: reset accumulators for next
+			iteration and return normalised stress (ie per link) 
+		*/
+		public double done() { S=a/n; a=0; n=0; return S; }
+		
+		/** return last stress value */
+		public double get() { return S; }
+		private final static double sqr(double t) {return t*t;}
+		private final static double sgn(double t) {
+			if (t<0) return -1; else if (t>0) return +1; else return 0;
+		}
+	}
+
+	public NewMDS(Matrix p)	{
+		super(p);
+		Shell.push(node);
+		stress=new Laplacian(E);
+		Shell.pop();
+	}
+
+	public void run()
+	{
+		double [][] _P=P.getArray();
+		double	d, dS;
+		int 		i, j, k;
+
+		// accumulate all forces on a per object basis
+
+		for (k=0; k<N; k++) Mathx.zero(F[k]); // zero out object forces
+		for (k=0; k<M; k++) {			// for each link
+			i=l1[k]; j=l2[k]; 				// object indices
+			if (stress.add(D[k],_P[j],_P[i],f)) {
+				Mathx.add(E,F[i],f);
+				Mathx.sub(E,F[j],f);
+			}
+		}
+		S.set(stress.done());
+
+		// now move objects at the ends of each link,
+		// but only the first E dimensions
+		for (k=0; k<N; k++) Mathx.muladd(E,_P[k],F[k],rate.value);
+		P.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/mds/ProximityFilter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,37 @@
+package samer.mds;
+
+import samer.maths.*;
+import samer.tools.*;
+import samer.core.types.*;
+import java.util.*;
+
+/** Compute component-wise filter coefficients using a
+	a distance/proximity matrix. The filter kernel is centred on
+	one of the elements, so that the coefficients are a function
+	of the distance/proximity between each unit and the given
+	"pivot" element.
+*/
+	 
+public class ProximityFilter extends NullTask implements Observer {
+	Matrix		R;
+	VVector		F;
+	VFunction	map;		// map from proximity to coeff.
+	VInteger	i;			// centre element, num elements
+
+	public ProximityFilter(Matrix R, VVector F, VFunction map) {
+		this.R=R; this.F=F; this.map=map;
+		i=new VInteger("pivot",0);
+		i.setRange(0,R.getRowDimension()-1);
+
+		R.addObserver(this);
+		map.addObserver(this);
+		i.addObserver(this);
+	}
+	public void run() { 	map.getFunction().apply(R.getArray()[i.value],F.array()); }
+	public void update(Observable obs, Object arg) { run(); F.changed(); }
+	public void dispose() {
+		map.deleteObserver(this);
+		R.deleteObserver(this);
+		i.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,5 @@
+/MidiRecorder.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MidiRecorderBase.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MidiSynth.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/MidiWithAftertouch.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/midi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/MidiRecorder.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,82 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.midi;
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.util.*;
+import java.io.*;
+import javax.sound.midi.*;
+
+/**
+	Attempts to do some temporal smoothing on the
+	imput vector. Its a bit like a median filter.
+	A note doesn't switch on until the corresponding
+	vector element has been above threshold for
+	<countThresh> consecutive steps, and similarly
+	for switching off.
+  */
+
+public class MidiRecorder extends MidiRecorderBase implements Task
+{
+	Vec in;
+	int n;
+	int [] nnums, chans;
+	double [] x;
+	VInteger	offset;
+	VBoolean pedal;
+	VDouble factor;
+
+	public MidiRecorder(Vec input) throws Exception {
+
+		Shell.push(node);
+		factor = new VDouble("factor",128,0);
+		offset = new VInteger("offset",0,0);
+		pedal  = new VBoolean("pedal",false,0);
+		// setAgent(this);
+		// addAgent(new Saver(this));
+		Shell.pop();
+
+		in = input;
+		n = in.size();
+		x = in.array();
+
+		nnums = new int[n];
+		chans = new int[n];
+		for (int i=0; i<n; i++) { nnums[i]=i; chans[i]=0; }
+	}
+
+	public int mapVelocity(double x) {
+		int vel=(int)(factor.value*x);
+		if (vel>127) vel=127;
+		return vel;
+	}
+
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+
+	public void run()
+	{
+		for (int i=0; i<n; i++) {
+
+			if (x[i]>0) {
+					int nnum=nnums[i]+offset.value;
+					int vel=mapVelocity(x[i]);
+					noteOn(chans[i],nnum, vel);
+			} else if (x[i]<0 && !pedal.value) {
+					int nnum=nnums[i]+offset.value;
+					noteOff(chans[i],nnum);
+			}
+		}
+		tick();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/MidiRecorderBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,99 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.midi;
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import java.util.*;
+import java.io.*;
+import javax.sound.midi.*;
+
+
+public abstract class MidiRecorderBase extends NamedTask implements Agent
+{
+    Sequence	sequence;
+	Track		track;
+	int			currentTime;
+	public 		VInteger	T;
+	boolean	recording=false;
+
+	public MidiRecorderBase() throws Exception
+	{
+		super("midi");
+		sequence = new Sequence(Sequence.PPQ, 10);
+		track = sequence.createTrack();
+		currentTime=0;
+		T = new VInteger("tickTime",100);
+	}
+
+	public void getCommands(Agent.Registry r) {
+		r.add("record").add("stop").add("save").add("clear");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("save")) {
+			saveMidiFile(new File(X.string(env.datum("filename"),"synth.mid")));
+		} else if (cmd.equals("clear")) {
+			sequence = new Sequence(Sequence.PPQ, 10);
+			track = sequence.createTrack();
+			currentTime=0;
+		} else if (cmd.equals("record")) {
+			recording=true;
+		} else if (cmd.equals("stop")) {
+			recording=false;
+		}
+	}
+
+    /**
+     * given 120 bpm:
+     *   (120 bpm) / (60 seconds per minute) = 2 beats per second
+     *   2 / 1000 beats per millisecond
+     *   (2 * resolution) ticks per second
+     *   (2 * resolution)/1000 ticks per millisecond, or 
+     *      (resolution / 500) ticks per millisecond
+     *   ticks = milliseconds * resolution / 500
+     */
+    public void noteOn(int ch, int num,int vel) 
+	{
+		if (!recording) return;
+        try {
+		    ShortMessage message = new ShortMessage();
+            long tick = currentTime * sequence.getResolution() / 500;
+            message.setMessage(ShortMessage.NOTE_ON+ch, num, vel); 
+            track.add(new MidiEvent(message, tick));
+        } catch (Exception ex) { ex.printStackTrace(); }
+    }
+
+    public void noteOff(int ch, int num)
+	{
+		if (!recording) return;
+        try {
+		    ShortMessage message = new ShortMessage();
+            long tick = currentTime * sequence.getResolution() / 500;
+            message.setMessage(ShortMessage.NOTE_OFF+ch, num, 0);
+            track.add(new MidiEvent(message, tick));
+        } catch (Exception ex) { ex.printStackTrace(); }
+    }
+
+	public void tick() { if (recording) currentTime+=T.value; }
+
+    public void saveMidiFile(File file) throws Exception
+	{
+        int[] fileTypes = MidiSystem.getMidiFileTypes(sequence);
+        if (fileTypes.length == 0) {
+            System.out.println("Can't save sequence");
+        } else {
+            if (MidiSystem.write(sequence, fileTypes[0], file) == -1) {
+                throw new IOException("Problems writing to file");
+            } 
+        }
+    }
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/MidiSynth.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,227 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.midi;
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.util.*;
+import java.io.*;
+import javax.sound.midi.*;
+
+
+/**
+	A class which generates midi events from the
+	values of an input vector. Each element of the vector
+	corresponds to a certain midi note number. The loudness
+	of a note depends on the value of the corresponding
+	vector element.
+
+	Parameters:
+		trigger note on events.
+
+		offset is added to the vector element number to get a
+		midi note number.
+
+		pedal control whether or not note off events are generated
+  */
+
+public class MidiSynth extends Viewable implements Agent, Task, Saveable
+{
+	VVector			in;
+	Synthesizer		synthesizer=null;
+
+	protected int			n;
+	protected double		[] x;
+	protected int			[] nnums;
+	protected int			[] chans;
+	protected MidiChannel	[] cc;
+
+	protected VDouble		factor;
+	protected VInteger	offset;
+	protected VBoolean	pedal;
+
+	public MidiSynth(VVector input)
+	{
+		super("midisynth");
+
+		Shell.push(node);
+		factor = new VDouble("factor",128,0);
+		offset = new VInteger("offset",0,0);
+		pedal  = new VBoolean("pedal",false,0);
+		setAgent(this);
+		addAgent(new Saver(this));
+		Shell.pop();
+
+		in = input;
+		n = in.size();
+		x = in.array();
+
+		nnums = new int[n];
+		chans = new int[n];
+		for (int i=0; i<n; i++) { nnums[i]=i; chans[i]=0; }
+
+		try { getAgent().execute("load", Shell.env()); open(); }
+		catch (Exception ex) { ex.printStackTrace(); }
+	}
+
+	public Viewer getViewer() {
+		return new BaseViewer(this) {
+			{
+				panel().setLayout( new StackLayout(3));
+				add(factor);
+				add(offset);
+				add(pedal);
+				add(Shell.createButtonsFor(MidiSynth.this));
+			}
+		};
+	}
+
+	public void open() throws Exception {
+		if (synthesizer!=null) { Shell.print("already open"); return; }
+		if ((synthesizer = MidiSystem.getSynthesizer()) == null) {
+			throw new Exception("getSynthesizer() failed");
+		}
+		Shell.print("opening synthesizer");
+		synthesizer.open();
+
+		cc = synthesizer.getChannels();
+		Shell.print("got synth and channel:"+synthesizer+cc);
+	}
+
+	public void close() {
+		if (synthesizer != null) {
+			Shell.print("closing synthesiser");
+			synthesizer.close();
+			synthesizer = null;
+		}
+	}
+
+	public void dispose() {
+		close();
+		factor.dispose();
+		offset.dispose();
+		pedal.dispose();
+		super.dispose();
+	}
+
+	public void silence() {
+		for (int i=0; i<n; i++) {
+			cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
+		}
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()
+	{
+		if (synthesizer==null) return;
+
+		for (int i=0; i<n; i++) {
+			if (x[i]>0) {
+				cc[chans[i]].noteOn(nnums[i]+offset.value,mapVelocity(x[i]));
+			} else if (x[i]<0 && !pedal.value) {
+				cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
+			}
+		}
+	}
+
+	public void getCommands(Agent.Registry r) {
+		r.add("open").add("close").add("silence").add("edit");
+	}
+
+	public void execute(String cmd, Environment env) throws Exception
+	{
+		if (cmd.equals("open")) open();
+		else if (cmd.equals("close"))	close();
+		else if (cmd.equals("silence"))	silence();
+		else if (cmd.equals("edit"))
+			Shell.expose( new Editor(),"MidiSynthEditor");
+	}
+
+	public void save(OutputStream s) throws Exception 	{
+		ObjectOutputStream	o=new ObjectOutputStream(s);
+		o.writeObject(nnums);
+		o.writeObject(chans);
+		o.flush();
+	}
+
+	public void load(InputStream s)  throws Exception {
+		ObjectInputStream	o=new ObjectInputStream(s);
+		int [] newnotes = (int [])o.readObject();
+		int [] newchans = (int [])o.readObject();
+		safecopy( newnotes, nnums);
+		safecopy( newchans,chans);
+	}
+
+	public void read(Reader r) throws Exception { throw new Exception("unsupported"); }
+	public void write(Writer w) throws Exception { throw new Exception("unsupported"); }
+
+	private static void safecopy( int [] src, int [] dest) 	{
+		int n=src.length; if (dest.length<n) n=dest.length;
+		System.arraycopy( src, 0, dest, 0, n);
+	}
+
+	public int mapVelocity(double x) {
+		int vel=(int)(factor.value*x);
+		if (vel>127) vel=127;
+		return vel;
+	}
+
+	class Editor extends BaseViewer
+	{
+		VInteger	i=new VInteger("input number",0,Variable.NOINIT);
+		VInteger	n=new VInteger("note number",nnums[0],Variable.NOINIT);
+		VInteger	c=new VInteger("channel number",chans[0],Variable.NOINIT);
+		VInteger    p=new VInteger("program",0,0);
+		VBoolean	l1=new VBoolean("lock note",false,Variable.NOINIT);
+		VBoolean	l2=new VBoolean("lock channel",false,Variable.NOINIT);
+
+		public Editor() {
+			super(MidiSynth.this);
+
+			i.setRange(0,nnums.length-1);
+			n.setRange(0,127);
+			c.setRange(0,15);
+			n.setRange(0,127);
+			p.setRange(0,127);
+			setLayout( new StackLayout());
+			add(i);	add(n); 	add(c);
+			add(p);	add(l1); 	add(l2);
+			i.addObserver(this);
+			n.addObserver(this);
+			c.addObserver(this);
+			p.addObserver(this);
+		}
+
+		public void update(Observable o, Object arg)
+		{
+			disposeFilter(o,arg);
+			if (arg==this) return; // &&&
+			if (o==i) {
+				if (l1.value) { nnums[i.value]=n.value; }
+				else { n.value = nnums[i.value]; n.changed(this); }
+
+				if (l2.value) { chans[i.value]=c.value; }
+				else { c.value = chans[i.value]; c.changed(this); }
+
+				p.value = cc[c.value].getProgram();
+				p.changed(this);
+			} else if (o==n) {
+				nnums[i.value]=n.value;
+			} else if (o==c) {
+				chans[i.value]=c.value;
+			} else if (o==p) {
+				cc[c.value].programChange(p.value);
+			}
+		}
+	}
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/midi/MidiWithAftertouch.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,60 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.midi;
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.heavy.*;
+import samer.core.util.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.util.*;
+import java.io.*;
+import javax.sound.midi.*;
+
+
+/**
+	When element crosses threshold upwards:	note on
+	When element drops below threshold:			note off
+	While element remains above threshold		adjust velocity
+  */
+
+public class MidiWithAftertouch extends MidiSynth
+{
+	protected boolean		[] states;
+
+	public MidiWithAftertouch(VVector input)
+	{
+		super(input);
+
+		states= new boolean[n];
+		for (int i=0; i<n; i++) states[i]=false;
+	}
+
+	public void run()
+	{
+		if (synthesizer==null) return; 
+
+		for (int i=0; i<n; i++) {
+			if (x[i]>0) {
+				int vel=mapVelocity(x[i]);
+				if (!states[i]) {
+					cc[chans[i]].noteOn(nnums[i]+offset.value,vel);
+					states[i]=true;
+				} else {
+					// note is still on - adjust pressure--not working
+					cc[chans[i]].setPolyPressure(nnums[i]+offset.value,vel);
+				}
+			} else if (states[i]) { // note is on but now below thresh
+				if (!pedal.value) cc[chans[i]].noteOff(nnums[i]+offset.value, 0);
+				states[i]=false;
+			}
+		}
+	}
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/#Model.java#	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+public interface Model
+{
+	/** return size of vector this model expects */
+	int getSize();
+	
+	/** model should begin observing this vector */
+	void setInput(Vec x);
+
+	/** should infer values latent variables */
+	void infer();
+
+	/**
+		 contract is that getEnergy and getGradient
+		must return correct values for current x after
+		infer and compute has been called, but not necessarily
+		before.
+
+:q
+
+		This is to give model an opportunity to
+		cache values of energy and gradient to avoid repeated
+		computations.
+	*/
+	void compute();
+
+	/** return E = -log p(x) */
+	double getEnergy();
+
+	/** return dE/dx */
+	double [] getGradient();
+
+	public void dispose();
+
+	/** This presents a more functional interface to the model
+	so that it can be driven by an optimiser. See classes
+	Functionx and MinimiserBase in package samer.maths.opt. */
+
+	public Functionx functionx();
+
+	/** This represents a training algorithm for a Model
+		Trainer is responsible for counting calls to accumulate()
+		between flushes
+	*/
+
+	public interface Trainer {
+		/** collect statistics for parameter update */
+		public void accumulate();
+
+		/** weighted accumulate */
+		public void accumulate(double w);
+
+		/** use collected stats to update parameters and reset */
+		public void flush();
+
+		/** Must be equivalent to reset(); accumulate(); flush();
+			but can be optimised for non-batched training */
+		public void oneshot();
+
+		/** reset accumulators without updating parameters */
+		public void reset();
+
+		public void dispose();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/AlignedGaussian.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,108 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+/**
+	Differential scaler: scales and offsets each element of a vector
+	independently aiming to match a given prior model. This is
+	like ICA using a diagonal weight matrix, with a 'zero-mean'
+	normalisation built in, though it doesn't actually the mean to
+	do this, but some statistic based on the prior model.
+*/
+
+public class AlignedGaussian extends AnonymousTask implements Model
+{
+	private int			n;
+	private Vec			x;
+	private VVector	s;
+	private VVector	w;		// vector of multipliers
+	private VDouble	E;
+	private VDouble	logA;
+
+	double []		_x, _s, _g, _w, _m, phi;
+
+	public AlignedGaussian( Vec input) { this(input.size()); setInput(input); }
+	public AlignedGaussian( int N)
+	{
+		n = N;
+
+		x = null;
+		w = new VVector("w",n);		w.addSaver();
+		s = new VVector("s",n);
+		E = new VDouble("E");
+		logA = new VDouble("log|A|",0);
+		
+
+		_s = s.array();
+		_w = w.array();
+		_g = new double[n];
+		phi = null;
+		reset();
+	}
+
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public VVector weights() { return w; }
+	public void setInput(Vec in) { x=in; _x=x.array(); }
+	public void reset() { reset(1.0); }
+	public void reset(double k) {
+		Mathx.setAll(_w,k); w.changed();
+		logA.set(-sumlog(_w));
+	}
+
+	public String toString() { return "AlignedGaussian("+x+")"; }
+	private static double sumlog(double [] x) {
+		double S=0;
+		for (int i=0; i<x.length; i++) S += Math.log(x[i]);
+		return S;
+	}
+
+	public void dispose()
+	{
+		logA.dispose();
+		w.dispose();
+		s.dispose();
+		super.dispose();
+	}
+
+	public void infer() { Mathx.mul(_s,_x,_w); s.changed(); }
+	public void compute() { 
+		Mathx.mul(_g,_s,_w); 
+		E.set(0.5*Mathx.norm2(_s)+logA.value);
+	}
+
+	public double	getEnergy() { return E.value; }
+	public double [] getGradient() { return _g; }
+
+	public Functionx functionx() {
+		return new Functionx() {
+			double [] s=new double[n];
+
+			public void dispose() {}
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				Mathx.mul(s,x,_w);
+				Mathx.mul(g,s,_w);
+				return 0.5*Mathx.norm2(s); // +logA.value;
+			}
+		};
+	}
+
+	public void starting() { logA.set(-sumlog(_w)); }
+	public void stopping() {}
+	public void run() { infer(); compute(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/BatchedTrainer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,65 @@
+//
+//  BatchedTrainer.java
+//  
+//
+//  Created by Samer Abdallah on Wed Jul 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.models;
+
+import samer.core.types.*;
+import samer.tools.*;
+
+/** Manages a Model.Trainer to do batched learning.
+	Calls accumulate() each iteration
+	Flushes every <batch> iterations.
+	Calls reset() on starting()
+ */
+
+public class BatchedTrainer extends AnonymousTask {
+	Model.Trainer	trainer;
+	VInteger				batch;
+	int							count;
+	Task						preFlush, postFlush;
+
+	public BatchedTrainer(Model.Trainer T) { this(T,1); }
+	public BatchedTrainer(Model.Trainer T, int b) {
+		batch=new VInteger("batch",b);
+		batch.setRange(1,batch.getMax());
+		trainer=T;
+		count=batch.value;
+		postFlush=new NullTask();
+		preFlush=new NullTask();
+	}
+
+	public Model.Trainer getTrainer() { return trainer; }
+	public void setBatch(int n) { batch.set(n); }
+	public VInteger getBatch() { return batch; }
+
+	public void setPostFlush(Task t) { postFlush.dispose(); postFlush=t; }
+	public Task getPostFlush() { return postFlush; }
+	public void setPreFlush(Task t) { preFlush.dispose(); preFlush=t; }
+	public Task getPreFlush() { return preFlush; }
+
+	public String toString() { return "BatchedTrainer/"+batch.value+":"+trainer; }
+
+	public void dispose() { 
+		preFlush.dispose(); 
+		postFlush.dispose();
+		trainer.dispose(); 
+		batch.dispose(); 
+	}
+
+	public void starting() { count=batch.value; trainer.reset(); }
+	public void stopping() {}
+	public void run() throws Exception {
+		trainer.accumulate();
+		if ((--count)<=0) {
+			preFlush.run();
+			trainer.flush();
+			postFlush.run();
+			count=batch.value;
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/AlignedGaussian.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/BatchedTrainer.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/Covariance.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/DiffScaler.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GaussianStats.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GaussianStatsOnline.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/GeneralisedExponential.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/ICA.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/ICAScalerSync.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/ICAWithScaler.java/1.1.1.1/Fri Dec 10 03:29:29 2004//
+/IIDPrior.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/JointHistogramBase.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/MOGModel.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/MOGVector.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/MatrixTrainer.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Mixture.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Model.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/NoisyICA.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Scaler.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SignalHistogram.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SmoothGeneralisedExponential.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SparseICA.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/VarianceICA.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+D/notyet////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/models
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/Covariance.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,84 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.maths.*;
+import  samer.tools.*;
+import  java.util.*;
+
+/**
+	Collect covariance statistics assuming input is zero mean.
+*/
+public class Covariance extends NamedTask
+{
+	VVector		vector;
+	Matrix		C;
+	int			n, count;
+	double	[] 	x;
+	double	[][] _C;
+	VDouble	rate;
+	double	[] sig;
+
+	public Covariance(VVector vec) throws Exception
+	{
+		super("covariance");
+		Shell.push(node);
+		
+		n=vec.size();
+		C = new Matrix("C",n,n);	// second moment: sum products
+		rate=new VDouble("rate",0.001);
+		Shell.pop();
+
+		sig= new double[n];
+		_C=C.getArray();
+		x=vec.array();
+		vector=vec;
+	}
+
+	public void dispose() { rate.dispose(); C.dispose(); }
+
+	public void reset() { C.zero(); }
+	public void getCorrelation(Matrix R) {
+		double [][] _R=R.getArray();
+		
+		// first get std devs and put 1s down diagonal
+		for (int i=0; i<n; i++) {
+			sig[i] = Math.sqrt(_C[i][i]);
+		}
+
+		for (int i=0; i<n; i++) {
+			for (int j=0; j<i; j++) { // off diagonal
+				_R[i][j] = _C[i][j]/(sig[i]*sig[j]);
+//				_R[j][i] = _R[i][j];
+			}
+			_R[i][i]=1;
+		}
+		R.changed();
+	}
+
+	
+	public void starting() {}
+	public void stopping() {}
+	public void run()
+	{
+		double eta=rate.value;
+		
+		for (int i=0; i<n; i++) {
+			double  [] a=_C[i];
+			double  k=x[i];
+			for (int j=0; j<=i; j++) {
+				a[j] += eta*(k*x[j]-a[j]);
+			}
+		}
+		C.changed();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/DiffScaler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,322 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+/**
+	Differential scaler: scales and offsets each element of a vector
+	independently aiming to match a given prior model. This is
+	like ICA using a diagonal weight matrix, with a 'zero-mean'
+	normalisation built in, though it doesn't actually the mean to
+	do this, but some statistic based on the prior model.
+*/
+
+public class DiffScaler extends AnonymousTask implements Model
+{
+	private Model 		M; // models P(s)
+	private int			n;
+	private Vec			x;
+	private VVector	s;
+	private VVector	w;		// vector of multipliers
+	private VVector	mu;	// vector of offsets
+	private VDouble	logA;
+
+	double []		_x, _s, _g, _w, _m, phi;
+
+	public DiffScaler( Vec input, Model M) { this(input); setOutputModel(M); M.setInput(s); }
+	public DiffScaler( Vec input) { this(input.size()); setInput(input); }
+	public DiffScaler( int N)
+	{
+		n = N;
+
+		x = null;
+		mu = new VVector("mu",n);	mu.addSaver();
+		w = new VVector("w",n);		w.addSaver();
+		s = new VVector("output",n);
+		logA = new VDouble("log|A|");
+
+		_s = s.array();
+		_w = w.array();
+		_m = mu.array();
+		_g = new double[n];
+		phi = null;
+		reset();
+	}
+
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public VVector weights() { return w; }
+	public VVector offsets() { return mu; }
+	public Model getOutputModel() { return M;	}
+	public void setOutputModel(Model m) { M=m;	}
+	public void setInput(Vec in) { x=in; _x=x.array(); }
+	public void reset() { reset(1.0); }
+	public void reset(double k) {
+		Mathx.setAll(_w,k); w.changed();
+		Mathx.setAll(_m,0); mu.changed();
+		logA.set(-sumlog(_w));
+	}
+
+	public String toString() { return "DiffScaler("+x+")"; }
+	private static double sumlog(double [] x) {
+		double S=0;
+		for (int i=0; i<x.length; i++) S += Math.log(x[i]);
+		return S;
+	}
+
+	public void dispose()
+	{
+		logA.dispose();
+		mu.dispose();
+		w.dispose();
+		s.dispose();
+		super.dispose();
+	}
+
+	public void infer() {
+		for (int i=0; i<n; i++) _s[i] = _w[i]*(_x[i]-_m[i]);
+		s.changed();
+	}
+
+	public void compute() {
+		Mathx.mul(_g,M.getGradient(),_w);
+	}
+
+	public double	getEnergy() { return M.getEnergy() + logA.value; }
+	public double [] getGradient() { return _g; }
+
+	public Functionx functionx() {
+		return new Functionx() {
+			Functionx fM=M.functionx();
+			double [] s=new double[n];
+
+			public void dispose() { fM.dispose(); }
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				for (int i=0; i<n; i++) s[i] = _w[i]*(x[i]-_m[i]);
+				double E=fM.evaluate(s,g);
+				Mathx.mul(g,_w);
+				return E+logA.value;
+			}
+		};
+	}
+
+	public void starting() { logA.set(-sumlog(_w)); }
+	public void stopping() {}
+	public void run() { infer(); }
+
+	public Model.Trainer getTrainer() { return new Trainer(); }
+	public Model.Trainer getOffsetTrainer() { return new OffsetTrainer(); }
+	public Model.Trainer getScaleTrainer() { return new ScaleTrainer(); }
+	public Model.Trainer getTensionedTrainer() { return  new TensionedTrainer(); }
+
+
+	public class Trainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble		rate1=new VDouble("scaleRate",0.0001);
+		VDouble		rate2=new VDouble("offsetRate",0.000001);
+		double[]		G,H;
+		double []	_s;
+		double		count; // n
+
+
+		public Trainer() {
+//			n=DiffScaler.this.n;
+			_s = s.array();
+			G = new double[n];
+			H = new double[n];
+		}
+
+		public String toString() { return "Trainer:"+DiffScaler.this; }
+
+		public VDouble getScaleRate() { return rate1; }
+		public VDouble getOffsetRate() { return rate2; }
+
+		public void reset() { count=0; Mathx.zero(G); Mathx.zero(H); }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			double [] phi=M.getGradient();
+			for (int i=0; i<n; i++) {
+				G[i] += w*(phi[i]*_s[i] - 1);
+				H[i] += w*phi[i];
+			}
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+
+			double eta1 = rate1.value/count;
+			double eta2 = rate2.value/count;
+
+			for (int i=0; i<n; i++) {
+				_m[i] += eta2*H[i]/_w[i];
+				_w[i] *= Math.exp(-eta1*G[i]);
+			}
+			logA.value+=eta1*Mathx.sum(G);
+			logA.changed();
+			mu.changed();
+			w.changed();
+			reset();
+		}
+
+		public void oneshot() { reset(); accumulate(); flush(); }
+		public void dispose() { rate1.dispose(); rate2.dispose(); }
+		public void starting() { reset(); }
+		public void run() { accumulate(); flush(); }
+	}
+
+	public class ScaleTrainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble	scale=new VDouble("scale",0.001);
+		VDouble	stretch=new VDouble("stretch",0.001/n);
+		double		thresh=Shell.getDouble("anomaly",20*n);
+		double[]		G, H, _s;
+		double		count; // n
+
+
+		public ScaleTrainer() {
+			_s = s.array();
+			G = new double[n];
+			// H = new double[n];
+		}
+
+		public String toString() { return "ScaleTrainer:"+DiffScaler.this; }
+
+		public VDouble getScaleRate() { return scale; }
+		public VDouble getStretchRate() { return stretch; }
+
+		public void reset() { count=0; Mathx.zero(G); }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			if (M.getEnergy()>thresh) return;
+			double [] phi=M.getGradient();
+			for (int i=0; i<n; i++) {
+				G[i] += w*(phi[i]*_s[i] - 1);
+				// H[i] += w*phi[i];
+			}
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+
+
+			{	// filter elements of G
+				double beta = stretch.value/scale.value;
+				double meanG = Mathx.sum(G)/n;
+				for (int i=0; i<n; i++) {
+					G[i]=meanG+beta*(G[i]-meanG);
+				}
+			}
+
+			double alpha = scale.value/count;
+			for (int i=0; i<n; i++) {
+				double tmp=Math.exp(-alpha*G[i]);
+				if (Double.isNaN(tmp)) throw new Error("alt: NaN"+i);
+				_w[i] *= tmp;
+			}
+			logA.value+=alpha*Mathx.sum(G);
+			logA.changed();
+			w.changed();
+			reset();
+		}
+
+		public void oneshot() { reset(); accumulate(); flush(); }
+		public void dispose() { scale.dispose(); stretch.dispose(); }
+		public void starting() { reset(); }
+		public void run() { accumulate(); flush(); }
+	}
+
+	public class OffsetTrainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble		rate2=new VDouble("offsetRate",0.000001);
+		double[]		H;
+		double		count; // n
+
+
+		public OffsetTrainer() {
+	//		n=DiffScaler.this.n;
+			H = new double[n];
+		}
+
+		public String toString() { return "OffsetTrainer:"+DiffScaler.this; }
+
+		public VDouble getOffsetRate() { return rate2; }
+
+		public void reset() { count=0; Mathx.zero(H); }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			double [] phi=M.getGradient();
+			for (int i=0; i<n; i++) H[i] += w*phi[i];
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+
+			double eta2 = rate2.value/count;
+
+			for (int i=0; i<n; i++) {
+				_m[i] += eta2*H[i]/_w[i];
+			}
+			mu.changed();
+			reset();
+		}
+
+		public void oneshot() { reset(); accumulate(1); flush(); }
+		public void dispose() { rate2.dispose(); }
+		public void starting() { reset(); }
+		public void run() { accumulate(1); flush(); }
+	}
+	
+	public class TensionedTrainer extends Trainer
+	{
+		VDouble		tension=new VDouble("tension",0.01);
+		double			lw[]=new double[n];
+
+		public TensionedTrainer() {}
+
+		public String toString() { return "TensionedTrainer:"+DiffScaler.this; }
+
+		public VDouble getTension() { return tension; }
+
+		public void flush() {
+			double T=tension.value;
+			int i;
+
+			// go through and modify G
+			for (i=0; i<n; i++) { lw[i]=Math.log(_w[i]); }
+			G[0] -= T*(lw[1]-lw[0]);	i=n-1;
+			G[i] -= T*(lw[i-1]-lw[i]); 	i--;
+			for (; i>0; i--) {
+				G[i] -= T*(lw[i-1] -2*lw[i]+lw[i+1]);
+			}
+
+			// do the same for H?
+			// may have to modify T.
+			H[0] -= T*(_m[1]-_m[0]);	i=n-1;
+			H[i] -= T*(_m[i-1]-_m[i]); 	i--;
+			for (; i>0; i--) {
+				H[i] -= T*(_m[i-1] -2*_m[i]+_m[i+1]);
+			}
+
+			super.flush();
+		}
+
+		public void dispose() { tension.dispose(); super.dispose(); }
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/GaussianStats.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,125 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+import  java.util.*;
+
+/**
+	Collect statistics about a vector: accumulates
+	sums and sums of products, then computes mean
+	and covariance.
+
+	This is NOT a model! Computing energies and probabilities
+	directly from the first and second moments is horrible, since
+	you need the inverse of the covariance matrix. You could,
+	however, use this to train a Gaussian model.
+ */
+
+public class GaussianStats extends NullTask
+{
+	VVector	vector;
+	VVector	sumx;
+	Matrix		sumxx;
+	int			n, count;
+	double	[] _sumx, x;
+	double	[][] _sumxx;
+	double	[] sig;
+
+	public GaussianStats(VVector vec) throws Exception
+	{
+		n=vec.size();
+		sumx = new VVector("t1",n);	// first moment: sum
+		sumxx = new Matrix("t2",n,n);	// second moment: sum products
+
+		_sumx=sumx.array();
+		_sumxx=sumxx.getArray();
+		x=vec.array();
+		vector=vec;
+		sig= new double[n];
+		
+	}
+
+	public void dispose() {
+		sumx.dispose();
+		sumxx.dispose();
+	}
+
+	public void getMean(VVector mu) { getMean(mu.array()); mu.changed(); }
+	public void getMean(double [] mu) { Mathx.mul(mu, _sumx, 1.0/count);	}
+	public void getCovariance(Matrix C) {
+		// compute mean products
+		C.assign(sumxx);
+		C.timesEquals(1.0/count);
+
+		// subtract square mean from mean square
+		double [][] _C=C.getArray();
+
+		for (int i=0; i<n; i++) {
+			double tmp=_sumx[i]/count; // diagonal
+			for (int j=0; j<i; j++) { // off diagonal
+				_C[i][j] -= tmp*(_sumx[j]/count);
+				_C[j][i] = _C[i][j];
+			}
+			_C[i][i] -= tmp*tmp;
+		}
+		C.changed();
+	}
+
+	public void getCorrelation(Matrix R) {
+		// compute mean products
+		R.assign(sumxx);
+		R.timesEquals(1.0/count);
+
+		double [][] _R=R.getArray();
+
+		// first get std devs and put 1s down diagonal
+		for (int i=0; i<n; i++) {
+			double tmp=_sumx[i]/count; // diagonal
+			sig[i] = Math.sqrt(_R[i][i] - tmp*tmp);
+			_R[i][i]=1;
+		}
+
+		for (int i=0; i<n; i++) {
+			double tmp=_sumx[i]/count;
+			for (int j=0; j<i; j++) { // off diagonal
+				_R[i][j] -= tmp*(_sumx[j]/count);
+				_R[i][j] /= sig[i]*sig[j];
+				_R[j][i] = _R[i][j];
+			}
+		}
+		R.changed();
+	}
+
+	public void reset() {
+		Mathx.zero(_sumx);
+		sumxx.zero(); count=0;
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()
+	{
+		Mathx.add(_sumx,x);
+
+		for (int i=0; i<n; i++) {
+			double  [] a=_sumxx[i];
+			double  k=x[i];
+			for (int j=0; j<=i; j++) {
+				a[j] += k*x[j];
+			}
+		}
+		sumx.changed();
+		sumxx.changed();
+		count++;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/GaussianStatsOnline.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,63 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.core.types.*;
+
+/**
+	Similar to GaussianStats:
+		Collect statistics about a vector: accumulates
+		sums and sums of products, then computes mean
+		and covariance.
+	
+		This is NOT a model! Computing energies and probabilities
+		directly from the first and second moments is horrible, since
+		you need the inverse of the covariance matrix. You could,
+		however, use this to train a Gaussian model.
+
+	BUT uses a moving average with a learning rate to track changes 
+ */
+
+public class GaussianStatsOnline extends GaussianStats
+{
+	VDouble	rate1,rate2;
+
+	public GaussianStatsOnline(VVector vec) throws Exception
+	{
+		super(vec);
+		rate1 = new VDouble("mean.rate",0.0001);
+		rate2 = new VDouble("cov.rate",0.0001);
+		sumx.addSaver();
+		count=1; // should stay that way.
+	}
+
+	public void reset() { super.reset(); count=1; }
+	public void dispose() { rate2.dispose(); rate1.dispose(); super.dispose(); }
+	public void run()
+	{
+		double r;
+		
+		r=rate1.value;
+		for (int i=0; i<n; i++) _sumx[i] += r*(x[i]-_sumx[i]);
+		
+		r=rate2.value;
+		for (int i=0; i<n; i++) {
+			double  [] a=_sumxx[i];
+			double  k=x[i];
+			for (int j=0; j<=i; j++) {
+				a[j] += r*(k*x[j]-a[j]);
+			}
+		}
+		sumx.changed();
+		sumxx.changed();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/GeneralisedExponential.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,171 @@
+package samer.models;
+
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+import samer.core.*;
+import samer.core.types.*;
+
+
+public class GeneralisedExponential extends NullTask implements Model {
+	Vec		input;
+	VVector	alpha, e, grad;
+	int			N;
+	VDouble	E;
+	double[]	x, g, e0, _e, a;
+	double	L0;
+
+	public GeneralisedExponential(Vec x) { this(x.size()); setInput(x); }
+	public GeneralisedExponential(int n)  {
+		N=n;
+		E=new VDouble("E");
+		e=new VVector("e",N);
+		grad=new VVector("phi",N);
+		alpha=new VVector("alpha",N);
+		alpha.addSaver();
+
+		g=grad.array(); // new double[N];
+		e0=new double[N];
+		a=alpha.array();
+		_e=e.array();
+
+		Mathx.setAll(a,1.0); L0=0;
+	}
+
+	public String toString() { return "GeneralisedExponential("+input+")"; }
+	public void setInput(Vec in) { input=in; x=input.array(); }
+	public int getSize() { return N; }
+	public void dispose() {
+		alpha.dispose();
+		grad.dispose();
+		E.dispose();
+		e.dispose();
+	}
+
+	public VVector	getEnergyVector() { return e; }
+	public VDouble	getEnergySignal() { return E; }
+	public double	getEnergy() { return E.value; }
+	public double [] getGradient() { return g; 	}
+	public VVector  getAlphas() { return alpha; }
+
+	public void run() { compute(); }
+	public void infer() {}
+	public void compute() {
+
+		// compute log likelihood
+
+		for (int i=0; i<N; i++) _e[i] = Math.pow(Math.abs(x[i]),a[i]);
+
+		// compute gradient g_i = dL/dx_i
+		for (int i=0; i<N; i++) {
+			if (x[i]==0) g[i]=0;
+			else g[i] = a[i]*(_e[i]/x[i]);
+		}
+
+		e.changed();
+		grad.changed();
+		E.set(Mathx.sum(_e)+L0);
+	}
+
+	private void precompute() {
+		// this computes the x-independent part of log p(x), ie fn of alpha
+		for (int i=0; i<N; i++) e0[i]= Math.log((2/a[i]))+logGamma(1/a[i]);
+		L0=Mathx.sum(e0);
+	}
+
+	public Functionx functionx() {
+		return new Functionx() {
+			double [] __e=new double[N];
+			public void dispose() {}
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				for (int i=0; i<N; i++) {
+					if (x[i]==0) { g[i]=0; __e[i]=0; }
+					else {
+						__e[i] = Math.pow(Math.abs(x[i]),a[i]);
+						g[i] = a[i]*(__e[i]/x[i]);
+					}
+				}
+				return  Mathx.sum(__e)+L0;
+			}
+		};
+	}
+
+	public Trainer getTrainer() { return new Trainer(); }
+
+	public class Trainer extends AnonymousTask implements Model.Trainer {
+		VDouble	rate;		// learning rate
+		double[]	A;		// statistics
+		double	count;
+
+		// estimation:
+		//	1/beta = alpha*avg(abs(x^alpha));
+
+		public Trainer() {
+			rate=new VDouble("rate",0.001);
+			A=new double[N];
+		}
+
+		public String toString() { return "Trainer:"+GeneralisedExponential.this; }
+		public VDouble getRate() { return rate; }
+		
+		public void reset() { Mathx.zero(A);	count=0; }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			for (int i=0; i<N; i++) {
+				if (x[i]!=0) A[i] -= w*_e[i]*Math.log(Math.abs(x[i]));
+			}
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return;
+			double eta=rate.value;
+
+			for (int i=0; i<N; i++) {
+				double ra=1/a[i];
+				a[i] += eta*(A[i]/count + ra*(1+ra*digamma(ra)));
+				// make sure a[i] not negative:
+				if (a[i]<=0) a[i]=0.01; // a small value
+
+				// precompute for next round
+				e0[i]= Math.log(2*ra)+logGamma(ra);
+			}
+			L0=Mathx.sum(e0);
+			alpha.changed();
+			reset();
+		}
+
+		public void oneshot() { reset(); accumulate(1); flush(); }
+		public void dispose() { rate.dispose(); }
+		public void starting() { reset(); }
+		public void run() { accumulate(1); flush(); }
+
+	}
+
+	private static double S=1e-5, C=8.5,
+		S3=8.33333333333333333333E-2,
+		S4=8.33333333333333333333E-3,
+		S5=3.96825396825396825397E-3,
+		D1=-0.5772156649;
+
+	public static double digamma(double t) {
+		double z=0;
+		if (t<S) return D1-1/t;
+		for (z=0; t<C; t++) z-=1/t;
+		double r=1/t;
+		z+=Math.log(t) - 0.5*r;
+		r*=r;
+		z-=r*(S3 - r*(S4 - r*S5));
+		return z;
+	}
+
+	private static double gamma(double t) {
+		return samer.functions.Gamma.gamma(t);
+		// return edu.uah.math.distributions.Functions.gamma(t);
+	}
+	private static double logGamma(double t) {
+		return samer.functions.Gamma.logOfGamma(t);
+		// return edu.uah.math.distributions.Functions.logGamma(t);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/ICA.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,362 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.Agent.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+import  samer.maths.opt.*;
+
+public class ICA extends Viewable implements SafeTask, Model, Agent
+{
+	Model			sourceModel;
+	int				n;
+	Vec			x;
+	Matrix			W, A;
+	VVector  		s;				// state
+	VDouble		logA;
+	double[]		_g; // cached dE/dx
+
+	MatrixTimesVector							infer;
+	MatrixTransposeTimesVector	grad;
+
+	public ICA(Vec input) { this(input.size()); setInput(input); }
+	public ICA(int N) { this(new Node("ica"),N); }
+	public ICA(Node node, int N)
+	{
+		super(node);
+		Shell.push(node);
+
+		n = N;
+
+		x = null;
+		W = new Matrix("W",n,n);
+		A = new Matrix("A",n,n); 	// should we defer creation of this?
+		s = new VVector("s",n);
+		logA = new VDouble( "log |A|");
+		infer = null;
+		Shell.pop();
+
+		W.identity(); W.changed();
+		grad = new MatrixTransposeTimesVector(W);
+		_g = new double[n];
+
+		setAgent(this);
+	}
+
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public Model getOutputModel() { return sourceModel; }
+	public void setOutputModel(Model m) {	sourceModel=m; }
+	public void setInput(Vec input) {
+		if (input.size()!=n) throw new Error("Input vector is the wrong size");
+		x = input; infer = new MatrixTimesVector(s,W,x);
+	}
+
+	public Matrix getWeightMatrix() { return W; }
+	public Matrix getBasisMatrix() { return A; }
+
+	public void dispose()
+	{
+		W.dispose(); A.dispose();
+		logA.dispose();
+		s.dispose();
+		infer.dispose();
+		grad.dispose();
+
+		super.dispose();
+	}
+
+	public void infer() {	// compute s=Wx
+		infer.run();
+		s.changed();
+	}
+
+	public void compute() {
+		grad.apply(sourceModel.getGradient(),_g);
+	}
+
+	public double getEnergy() { return sourceModel.getEnergy()+logA.value; }
+	public double[] getGradient() { return _g; }
+
+	public Functionx functionx() {
+		return new Functionx() {
+			Functionx fM=sourceModel.functionx();
+			double [] s=ICA.this.s.array(); //new double[n];
+			double [] gs=new double[n];
+
+			public void dispose() { fM.dispose();  }
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				infer.apply(x,s); double E=fM.evaluate(s,gs);
+				grad.apply(gs,g); return E+logA.value;
+			}
+		};
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() { infer(); }
+
+	public void getCommands(Registry r) { r.add("basis").add("logdet"); }
+	public void execute(String cmd, Environment env)
+	{
+		if (cmd.equals("basis")) {
+			Shell.print("computing ICA basis...");
+			A.assign(W.inverse());
+			A.changed();
+			Shell.print("...done.");
+		} else if (cmd.equals("logdet")) {
+			logA.set(-W.logdet());
+		}
+	}
+
+	public Trainer getTrainer() { return new ON2Trainer(); }
+	public Trainer getAltTrainer() { return new ON3Trainer(); }
+	public Trainer getDecayWhenActiveTrainer() { return new ON2DecayWhenActive(); }
+
+	/** This trainer uses an O(N^2) run step and an O(N^2) flush. */
+	
+	public class ON2Trainer implements Model.Trainer
+	{
+		double[][]		_W, _GW;
+		double[]         _s, buf;
+		VDouble			rate;
+		Matrix				GW;
+		int					_n;
+		double			thresh, batch;
+		MatrixTransposeTimesVector sW;
+
+		public ON2Trainer()
+		{
+			_n=n;
+			GW=new Matrix("GW",n,n);
+			rate=new VDouble("rate",0.01);
+			thresh=Shell.getDouble("anomaly",n*20);
+			batch=0;
+
+			_s=s.array();
+			_GW=GW.getArray();
+			_W=W.getArray();
+			buf=new double[n]; // general purpose n-buffer
+			sW = new MatrixTransposeTimesVector(buf,W,_s);
+		}
+
+		public String toString() { return "ON2Trainer:"+ICA.this; }
+		public void dispose() { GW.dispose(); rate.dispose(); }
+		public void reset() { GW.zero(); GW.changed(); batch=0; }
+		public void oneshot() { accumulate(1); flush(); }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w)
+		{
+			// HACK!
+			if (sourceModel.getEnergy()>thresh) return;
+
+			double q, p[];
+			batch+=w;
+
+			sW.run(); // buf = W'*s
+			double[] phi=sourceModel.getGradient();
+			for (int i=0; i<_n; i++) {
+				double [] r=_W[i];
+//			p = _GW[i]; q=phi[i];
+//			for (int j=0; j<_n; j++) p[j] += w*(q*buf[j] - r[j]);
+				p = _GW[i]; q=w*phi[i];
+				for (int j=0; j<_n; j++) p[j] += q*buf[j];
+			}
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+			double eta=-rate.value/batch;
+
+			// now W += eta*GW
+			for (int i=0; i<_n; i++) {
+				double [] p = _W[i],	q = _GW[i];
+//			for (int j=0; j<_n; j++) p[j] += eta*q[j];
+				for (int j=0; j<_n; j++) p[j] += eta*(q[j]-batch*p[j]);
+//			Mathx.mul(q,1.0/batch);
+			}
+			GW.changed();
+
+			// reset for next batch
+			W.changed();  GW.zero();
+			batch=0;
+		}
+	}
+
+	public class ON2DecayWhenActive extends ON2Trainer {
+		VDouble th=new VDouble("thresh",0.0);
+
+		public String toString() { return "DecayWhenActiveTrainer:"+ICA.this; }
+		public void accumulate(double w) {
+			if (sourceModel.getEnergy()>thresh) return;
+
+			double q, p[];
+			batch+=w;
+
+			sW.run(); // buf = W'*s
+			double[] phi=sourceModel.getGradient();
+			for (int i=0; i<_n; i++) {
+				double [] r=_W[i];
+				p = _GW[i]; q=w*phi[i];
+				for (int j=0; j<_n; j++) p[j] += q*buf[j];
+			}
+
+			// decay when active part
+			double thresh=th.value;
+			for (int j=0; j<_n; j++)
+				if (isActive(_s[j],thresh))
+					for (int i=0; i<_n; i++)
+						_GW[i][j] -= _W[i][j];
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+			double eta=-rate.value/batch;
+
+			// now W += eta*GW
+			for (int i=0; i<_n; i++) {
+				double [] p = _W[i],	q = _GW[i];
+				for (int j=0; j<_n; j++) p[j] += eta*q[j];
+			}
+			GW.changed();
+			W.changed();  GW.zero();
+			batch=0;
+		}
+	}
+	static boolean isActive(double s, double t) { return s>=t || s<=-t; }
+
+	/** This trainer saves on an O(N^2) step during accumulation, at
+		the expense of an O(N^3) flush. As long as the batch size
+		is O(N), then it should be about the same overall. The advantage
+		is the collected statistics are more transparent, and can be used
+		to make scalar or diagonal updates more frequenty. */
+
+
+	public class ON3Trainer extends AnonymousTask implements Model.Trainer
+	{
+		Matrix			G;
+		double[][]	_G, _W;
+		double[]     _s, buf;
+		VDouble		rate;
+		int				_n;
+		double		batch, thresh;
+
+		public ON3Trainer()
+		{
+			_n=n;
+			G=new Matrix("G",n,n);
+			rate=new VDouble("rate",0.01);
+			thresh=Shell.getDouble("anomaly",20*n);
+			batch=0;
+
+			_s=s.array();
+			_G=G.getArray();
+			_W=W.getArray();
+			buf=new double[n]; // general purpose n-buffer
+		}
+
+		public String toString() { return "ON3Trainer:"+ICA.this; }
+
+		/** this is so you can manipulate the matrix before flushing */
+		public Matrix getGMatrix() { return G; }
+
+		public void starting() { reset(); }
+		public void run() { accumulate(); }
+
+		public void dispose() { G.dispose(); rate.dispose();	super.dispose(); }
+		public void oneshot() { accumulate(1); flush(); }
+		public void reset() { G.zero(); batch=0; }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w)
+		{
+			// HACK!
+			if (sourceModel.getEnergy()>thresh) return; 
+
+			double q, p[];
+			batch+=w;
+
+			double[] phi=sourceModel.getGradient();
+			for (int i=0; i<_n; i++) {
+				p = _G[i]; q=w*phi[i];
+//				if (Double.isNaN(q)) throw new Error("NAN"+i);
+				for (int j=0; j<_n; j++) p[j] += q*_s[j];
+				p[i] -= w;
+			}
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+			double eta=-rate.value/batch;
+
+			G.changed();
+			
+			// this is going to do a matrix G *= W, in place
+			for (int i=0; i<_n; i++) {
+				for (int j=0; j<_n; j++) {
+					double a=0;
+					for (int k=0; k<_n; k++) a += _G[i][k]*_W[k][j];
+					buf[j] = a;
+				}
+				Mathx.copy(buf,_G[i]);
+			}
+
+			// now W += eta*G
+			for (int i=0; i<_n; i++) {
+				double [] p = _W[i],	q = _G[i];
+				for (int j=0; j<n; j++) p[j] += eta*q[j];
+			}
+
+			reset(); // ready for next batch
+		}
+	}
+
+	// See Hyvarinen's paper that Nick gave me. Not finished
+	public class NewtonTrainer extends ON3Trainer
+	{
+		Function		dgamma;
+		VVector		f;			// scnd derivatives of log prior
+		double[]     _f;
+
+		public NewtonTrainer(Function dg)
+		{
+			dgamma=dg;
+			f=new VVector("f",n);
+			_f=f.array();
+		}
+
+		public void dispose() { f.dispose(); dgamma.dispose();	super.dispose(); }
+		public void reset() { Mathx.zero(_f); super.reset(); }
+		public void accumulate(double w)
+		{
+			// HACK!
+			if (sourceModel.getEnergy()>thresh) return;
+
+			dgamma.apply(_s,buf);
+			Mathx.add(_f,buf);
+			super.accumulate(w);
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+
+			// first do some things to G, then do normal flush
+
+			super.flush();
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/ICAScalerSync.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,28 @@
+package samer.models;
+
+import samer.maths.*;
+import samer.tools.*;
+
+/**
+	This is a task which subsumes a post-scaling into an ICA weight matrix
+*/
+
+public class ICAScalerSync extends AnonymousTask {
+	Matrix	W;
+	VVector	w;
+
+	public ICAScalerSync(ICA ica, DiffScaler sc) {
+		W=ica.getWeightMatrix();
+		w=sc.weights();
+	}
+
+	public void run() {
+		double [][] _W=W.getArray();
+		double [] _w=w.array();
+		int			n=w.size();
+		for (int i=0; i<n; i++) Mathx.mul(_W[i],_w[i]);
+		Mathx.setAll(_w,1);
+		w.changed();
+		W.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/ICAWithScaler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,163 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.Agent.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+
+public class ICAWithScaler extends ICA
+{
+	VVector  		k;			// state, scaling vector
+	double[]		__k, tmp;
+
+	public ICAWithScaler(Vec input) { this(input.size()); setInput(input); }
+	public ICAWithScaler(int N)
+	{
+		super(N);
+		Shell.push(node);
+		k = new VVector("k",n);
+		Shell.pop();
+		__k=k.array();
+		tmp=new double[n];
+
+		for (int i=0; i<n; i++) __k[i]=1;
+		k.changed();
+	}
+
+	public void dispose() { k.dispose(); super.dispose(); }
+	public void infer() {	// this overrides ICA.infer
+		infer.run(); // compute s=Wx
+		Mathx.mul(s.array(),__k);
+		s.changed();
+	}
+
+	public void compute() {
+		Mathx.mul(tmp,sourceModel.getGradient(),__k);
+		grad.apply(tmp,_g);
+	}
+
+	public samer.maths.opt.Functionx functionx() { return null; }
+
+	public void fold() {
+		for (int i=0; i<n; i++) {
+			Mathx.mul(W.getArray()[i],__k[i]);
+			__k[i]=1;
+		}
+		k.changed();
+		W.changed();
+	}
+
+	public Trainer getDiffTrainer() { return new DifferentialTrainer(); }
+	public Trainer getScaleTrainer() { return new ScalerTrainer(); }
+
+
+	public class DifferentialTrainer extends ON3Trainer {
+		VDouble		scaleRate,stretchRate;
+		double		lastflush;
+
+		public DifferentialTrainer() {
+			scaleRate=new VDouble("alpha",0.1);
+			stretchRate=new VDouble("beta",0.05);
+		}
+
+		public void reset() { super.reset(); lastflush=0; }
+		public void flush() { diffFlush(); fold(); super.flush(); lastflush=0; }
+		public void diffFlush() // flush multipliers to k instead of W
+		{
+			double batchlet=batch-lastflush;
+			if (batchlet==0) return;
+
+			// do differential learning on trace & diagonal of G
+			double alpha=scaleRate.value/batchlet;
+			double beta=stretchRate.value/batchlet;
+
+			// compute factors and scale each row of W
+			double mu=G.trace()/n,dl;
+			for (int i=0; i<_n; i++) {
+				dl=alpha*mu+beta*(_G[i][i]-mu);
+				double tmp=Math.exp(-dl);
+				// if (Double.isNaN(tmp)) throw new Error("alt: NaN"+i);
+				__k[i]*=tmp; // instead of Mathx.mul(_W[i],tmp);
+				_G[i][i]=0;
+			}
+			k.changed();
+			lastflush=batch;
+		}
+	}
+
+	/** This one trains ONLY the scaler part, not the ICA part, so is a lot faster
+		than using the differential trainer with a zero learning rate. */
+	
+	public class ScalerTrainer extends AnonymousTask implements Model.Trainer
+	{
+		VVector		G;
+		double[]		_G;
+		double[]     _g,_s;
+		VDouble		scaleRate,stretchRate;
+		int				_n;
+		double		batch,thresh;
+		
+		public ScalerTrainer()
+		{
+			_n=n;
+			G=new VVector("G",n);
+			thresh=Shell.getDouble("anomaly",20*n);
+			scaleRate=new VDouble("alpha",0.02);
+			stretchRate=new VDouble("beta",0.002);
+			batch=0;
+
+			_s=s.array();
+			_G=G.array();
+		}
+
+		public void starting() { reset(); }
+		public void run() { accumulate(); }
+
+		public void dispose() { G.dispose(); scaleRate.dispose(); stretchRate.dispose(); super.dispose(); }
+		public void oneshot() { accumulate(); flush(); }
+		public void reset() { Mathx.zero(_G); batch=0; }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			// HACK!
+			if (sourceModel.getEnergy()>thresh) return; 
+			batch+=w;
+
+			double[] phi=sourceModel.getGradient();
+			for (int i=0; i<_n; i++) _G[i] += w*(phi[i]*_s[i] - 1);
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+
+			G.changed();
+			
+			// do differential learning on trace & diagonal of G
+			double alpha=scaleRate.value/batch;
+			double beta=stretchRate.value/batch;
+			
+			// compute factors and scale each row of W
+			double mu=Mathx.sum(_G)/n, dl;
+			for (int i=0; i<_n; i++) {
+				dl=alpha*mu+beta*(_G[i]-mu);
+				double tmp=Math.exp(-dl);
+				if (Double.isNaN(tmp)) throw new Error("alt: NaN"+i);
+				__k[i]*=tmp; // instead of Mathx.mul(_W[i],tmp);
+			}
+			k.changed();
+		
+			reset(); // ready for next batch
+		}
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/IIDPrior.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,85 @@
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.functions.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+/**
+	Non adaptive model of vector in which each component is
+	independent of the others and all are identically distributed
+	according to a given prior
+	*/
+
+public class IIDPrior extends AnonymousTask implements Model
+{
+	Vec 		x;
+	VVector	e; // , g;
+	Function	logprior, phi;
+	VDouble	E;
+
+	double [] _x, _e, _g;
+
+	// default model is Gaussian
+	public IIDPrior(int n) { this(n,new HalfSquare()); }
+	public IIDPrior(Vec in) { this(in.size(),new HalfSquare()); setInput(in); }
+	public IIDPrior(Vec in, Function E) { this(in.size(),E); setInput(in); }
+	public IIDPrior(int N, Function f)
+	{
+		int n=N;
+		e=new VVector("e",n);
+		// g=new VVector("phi",n);
+		E=new VDouble("E");
+		logprior = f; phi = f.derivative();
+		_e = e.array();
+		_g = new double[n]; // g.array();
+	}
+
+	public int getSize() { return e.size(); }
+
+	public String toString() { return "IIDPrior:"+logprior.format("x"); }
+
+	public void dispose() {
+		e.dispose();
+		// g.dispose();
+		E.dispose();
+		logprior.dispose();
+		phi.dispose();
+	}
+
+	public void setInput(Vec input) {	x=input; _x=x.array(); }
+	public void setLogPrior(Function f) {
+		phi.dispose(); logprior.dispose();
+		logprior=f; phi=f.derivative();
+	}
+
+	public VVector	getEnergyVector() { return e; }
+	public VDouble	getEnergySignal() { return E; }
+	public double	getEnergy() { return E.value; }
+	public double [] getGradient() { return _g; 	}
+	public void infer() {}
+	public void compute()
+	{
+	  	phi.apply(_x,_g); // g.changed();
+		logprior.apply(_x,_e);	e.changed();
+		E.set(Mathx.sum(_e));
+	}
+
+	public Functionx functionx() {
+		return new Functionx() {
+			public void dispose() {}
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				logprior.apply(x,g);
+				double E=Mathx.sum(g);
+				phi.apply(x,g);
+				return E;
+			}
+		};
+	}
+
+	public void run() { compute(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/JointHistogramBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,72 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.util.*;
+
+public class JointHistogramBase extends AnonymousTask {
+	Matrix			bins;
+	IMap			xmap,ymap;
+	double[][]		binArray;
+	double[]		lbwx, lbwy; // log of bin widths
+	int				count, M;
+	DoubleModel	x, y;
+	VDouble			L;
+
+	public JointHistogramBase()
+	{
+		M=Shell.getInt("bins",32);
+		setMaps(new LinearMap(-1,1,M),new LinearMap(-1,1,M));
+		bins = new Matrix("bins",M,M);
+		L=new VDouble("likelihood");
+		binArray=bins.getArray();
+		lbwx=new double[M];
+		lbwy=new double[M];
+	}
+
+	public void setInputs(DoubleModel _x, DoubleModel _y) { x=_x; y=_y; }
+	public void setMaps(IMap xm, IMap ym) {
+		xmap=xm; xmap.setIntRange(M);
+		ymap=ym; ymap.setIntRange(M);
+		// this assumes bins matrix is square
+		for (int i=0; i<binArray.length; i++) {
+			lbwx[i]=Math.log(xmap.inverseFromInt(i+1) - xmap.inverseFromInt(i));
+			lbwy[i]=Math.log(ymap.inverseFromInt(i+1) - ymap.inverseFromInt(i));
+		}
+	}
+	public void clear() { count=0; bins.zero(); bins.changed(); }
+	public Matrix getBinMatrix() { return bins; }
+	public VDouble getLikelihoodSignal() { return L; }
+
+	public void dispose() { bins.dispose(); L.dispose(); }
+	public void run() { L.set(data(x.get(),y.get())); }
+
+	public void normalise() {
+		int n=binArray.length, c=0;
+		for (int i=0; i<n; i++) c+=(int)Mathx.sum(binArray[i]);
+		count=c;
+		Shell.print("JointHistogram: count="+count);
+ 	}
+
+	public final double data(double x, double y)	{
+		int k=xmap.clipInt(x);
+		int j=ymap.clipInt(y);
+		double L=-Math.log((++binArray[j][k])/(double)(++count)) + lbwx[k] + lbwy[j];
+		bins.changed();
+		return L;
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/MOGModel.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,188 @@
+package samer.models;
+
+import	samer.core.*;
+import	samer.core.types.*;
+import	samer.maths.*;
+import	samer.tools.*;
+
+public class MOGModel extends NamedTask
+{
+	Generator input;
+
+	int		N, state;			// num states
+	VDouble	Z;
+
+	VVector	vt, vpost;			// deviations, posterior
+	VVector	vw, vmu, vsig;		// weights, means, and stddevs
+
+	double[] t, post;				// deviations, posterior
+	double[]	w, mu, sig;			// weights, means, and stddevs
+	double[] dw, dmu, dsig;		// deltas
+	VDouble	nuw, numu, nusig;	// learning rates
+	boolean	lrnW, lrnMu, lrnSig;
+
+	final static double Q=1/Math.sqrt(2*Math.PI);;
+
+	public MOGModel(Generator in, int n)
+	{
+		super("mog");
+		input=in;
+
+		Shell.push(node);
+		N=n;
+
+		Z = new VDouble("likelihood");
+
+		t		= new double[N];
+		post	= new double[N];
+		w		= new double[N];
+		mu		= new double[N];
+		sig	= new double[N];
+		dw		= new double[N];
+		dmu	= new double[N];
+		dsig	= new double[N];
+
+		vpost=new VVector("p",post);
+		vw=new VVector("weights",w);
+		vmu=new VVector("means",mu);
+		vsig=new VVector("sigmas",sig);
+
+		lrnW=Shell.getBoolean("weights.learn",true);
+		lrnMu=Shell.getBoolean("means.learn",true);
+		lrnSig=Shell.getBoolean("sigmas.learn",true);
+
+		nuw=new VDouble("weights.learn.rate",.001);
+		numu=new VDouble("means.learn.rate",.001);
+		nusig=new VDouble("sigmas.learn.rate",.001);
+
+//		nu=new VDouble("learn.rate",0.001);
+		Shell.pop();
+
+		// initialise parameters
+		Generator rnd=new samer.maths.random.NormalisedGaussian();
+
+		// weights...
+		Mathx.zero(w);
+		Mathx.add(w,1.0/N);
+		vw.changed();
+
+		// means...
+		Mathx.set(mu,rnd);
+		vmu.changed();
+
+		// sigmas
+		Mathx.zero(sig);
+		Mathx.add(sig,1);
+		vsig.changed();
+
+	}
+
+	public void run() { data(input.next()); }
+	public void starting() { 
+		Mathx.zero(dw);	
+		Mathx.zero(dmu);	
+		Mathx.zero(dsig);	
+
+		// make sure weights are normalised properly
+		Mathx.mul(w,1/Mathx.sum(w));
+	}
+
+	public Task flushTask() { 
+		return new AnonymousTask() {
+			public void run() { flush(); }
+		};
+	}
+
+	public Function getPDF() 
+	{
+		return new Function() {
+			public double apply(double x) {
+				double Z=0;
+				for (int i=0; i<N; i++) {
+					t[i]=(x-mu[i])/sig[i];
+					Z+=(w[i]/sig[i])*Math.exp(-0.5*t[i]*t[i]);
+				}
+				return Z*Q;
+			}
+			public String format(String x) {
+				return "mogpdf("+x+")";
+			}
+		};
+	}
+
+	public void data(double x) 
+	{
+		// find posterior and MAP state
+		state=0;	double Z=0;
+		for (int i=0; i<N; i++) {
+			t[i]=(x-mu[i])/sig[i];
+			post[i] = (w[i]/sig[i])*Math.exp(-0.5*t[i]*t[i]);
+			Z+=post[i];
+
+			if (post[i]>post[state]) state=i;
+		}
+		Mathx.mul(post,1/Z);
+		Z *= Q;
+
+		if (lrnW||lrnMu||lrnSig) {
+			// buffer changes to parameters
+			for (int i=0; i<N; i++) {
+				double p=post[i], tt=t[i];
+				if (lrnW)		dw[i]  += p;
+				if (lrnMu)	dmu[i] += p*tt;
+				if (lrnSig)	dsig[i]+= p*(tt*tt-1);
+			}
+		}
+
+		this.Z.value=Z; 
+		this.Z.changed();
+		vpost.changed();
+	}
+
+	public void flush()
+	{
+		if (lrnMu) {
+			Mathx.mul(dmu,sig);
+			flush(mu,dmu,numu.value);
+			vmu.changed();
+		}
+		if (lrnSig)	{ 
+			Mathx.mul(dsig,sig);
+			flush(sig,dsig,nusig.value);
+			vsig.changed();
+		}
+		if (lrnW)	{ 
+/*
+			// normalise
+			Mathx.mul(w,1/Mathx.sum(w));
+
+			Mathx.div(dw,w);
+			double lambda=Mathx.sum(dw)/N;
+			Mathx.sub(dw,lambda);
+			flush(w,dw,nuw.value);
+ */
+
+			double lambda=Mathx.dot(w,dw)/Mathx.dot(w,w);
+			double nu=nuw.value;
+
+			for (int i=0; i<N; i++) {
+				dw[i] -= lambda*w[i];			// project away from w
+				w[i]  *= Math.exp(nu*dw[i]);  // update w
+			}
+			Mathx.zero(dw);	
+
+			// normalise
+			Mathx.mul(w,1/Mathx.sum(w));
+
+			vw.changed();
+		}
+
+	}
+
+	private void flush(double [] theta, double [] dtheta, double nu) 
+	{
+		Mathx.mul(dtheta,nu); // *this.nu.value); 
+		Mathx.add(theta,dtheta); 
+		Mathx.zero(dtheta);	
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/MOGVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,284 @@
+package samer.models;
+
+import	samer.core.*;
+import	samer.core.types.*;
+import	samer.maths.*;
+import	samer.tools.*;
+import	java.util.*;
+
+public class MOGVector extends NamedTask
+{
+	Vec		input;
+
+	int		N, M;					// num states, number of inputs
+	VVector	s;						// states
+	VVector	l;						// likelihoods
+	VDouble	L;						// total likelihood
+		
+	Matrix	t;						// deviations: t=(x-mu)/sig
+	Matrix	post;					// posterior over states
+	Matrix	w, mu, sig;			// weights, means, stddevs
+	Matrix	dw, dmu, dsig;		// accumulated stats for learning
+
+	VDouble	nuw, numu, nusig;	// learning rates
+
+
+	// ------------ private bits ------------------------
+
+	private final static double Q=0.5*Math.log(2*Math.PI);
+	private double[] tmp;
+	private double [] _s;
+	private double [] _l;
+	private double [][] _t;
+	private double [][] _w;
+	private double [][] _mu;
+	private double [][] _sig;
+	private double [][] _post;
+	// ---------------------------------------------------
+
+	public MOGVector(Vec in, int n)
+	{
+		super("mog");
+		input=in;
+
+		Shell.push(node);
+		N=n; M=in.size();
+
+		s = new VVector("state",M);
+		l = new VVector("-log p(s)",M);
+		L = new VDouble("likelihood");
+
+		t		= new Matrix("t",N,M);
+		post	= new Matrix("p(s|x)",N,M);
+		mu		= new Matrix("means",N,M);
+		sig	= new Matrix("sigmas",N,M);
+		w		= new Matrix("weight",N,M);
+		dmu	= new Matrix("dmu",N,M);
+		dsig	= new Matrix("dsig",N,M);
+		dw		= new Matrix("dw",N,M);
+
+		tmp=new double[M];
+
+		Shell.pop();
+
+		// initialise parameters
+
+		// weights...
+		w.set(new Constant(1.0/N));
+		w.changed();
+
+		// means...
+		for (int i=0; i<N; i++) {
+			mu.setMatrix(i,i,0,M-1,new Jama.Matrix(1,M,(double)i));
+		}
+		mu.changed();
+
+		// sigmas
+		sig.set(new Constant(1));
+		sig.changed();
+
+
+		// ----- initialise private bits ----------
+		_s=s.array();
+		_l=l.array();
+		_t=t.getArray();
+		_w=w.getArray();
+		_mu=mu.getArray();
+		_sig=sig.getArray();
+		_post=post.getArray();
+	}
+
+	// normalise column sum of w, return array of sums
+	private void normalise(double [][] w, double[] sum) {
+		// make sure weights are normalised properly
+		Mathx.zero(sum);
+		for (int i=0; i<N; i++) Mathx.add(sum,w[i]);
+		for (int i=0; i<N; i++) Mathx.div(w[i],sum);
+	}
+
+	public VFunction getPDF() { 
+		PDF		 fn=new PDF();
+		VFunction vfn=new VFunction("pdf",fn);
+		fn.setupObservers(vfn);
+		return vfn; 
+	}
+
+	public void run() 
+	{
+		// matlab equivalent code:
+		// t = (x - mu)./sig
+		// post = (w./sig).*exp(-0.5*t.^2)
+		// [dummy, s] = max(post,2)
+		// Z = sum(post,2)
+		// post = post./(Z*ones(1,N))
+		// Z=Z*Q;
+
+		{
+			// Vec.Iterator it=input.iterator();
+
+			double [] x=input.array();
+
+			for (int i=0; i<N; i++) {					
+				for (int j=0; j<M; j++) {
+					_t[i][j] = (x[j]-_mu[i][j])/_sig[i][j];
+					_post[i][j] = (_w[i][j]/_sig[i][j])*Math.exp(-0.5*_t[i][j]*_t[i][j]);
+				}
+			}
+
+			// this computes partition function 
+			// and normalises posterior in one go
+			normalise(_post,_l);
+
+			// get MAP state
+			for (int j=0; j<M; j++) {
+				int		state=0;	
+				double	pmax=_post[0][j];
+				
+				for (int i=1; i<N; i++) {
+					if (_post[i][j]>pmax) { state=i; pmax=_post[i][j]; }
+				}
+				_s[j]=state;
+			}
+
+			for (int j=0; j<M; j++) _l[j]=-Math.log(_l[j]);
+
+			L.value = Mathx.sum(_l);
+		}
+
+		L.changed();
+		t.changed();
+		s.changed();
+		l.changed();
+		post.changed();
+	}
+
+	public Task learnTask() {
+		return new AnonymousTask() {
+			// buffer changes to parameters
+			double [][] _dw=dw.getArray();
+			double [][] _dmu=dmu.getArray();
+			double [][] _dsig=dsig.getArray();
+
+			public void starting() { 
+				dw.zero();	
+				dmu.zero();	
+				dsig.zero();
+				normalise(w.getArray(),tmp);
+			}
+
+			public void run() {
+				for (int i=0; i<N; i++) {
+					for (int j=0; j<M; j++) {
+						double pp=_post[i][j], tt=_t[i][j];
+						_dw[i][j]  += pp;
+						_dmu[i][j] += pp*tt;
+						_dsig[i][j]+= pp*(tt*tt-1);
+					}
+				}
+			}
+		};
+	}
+
+	public Task flushTask() { 
+		Shell.push(node);
+
+		try {
+			return new AnonymousTask() {
+
+				VDouble nuw=new VDouble("weights.learn.rate",.001);
+				VDouble numu=new VDouble("means.learn.rate",.001);
+				VDouble nusig=new VDouble("sigmas.learn.rate",.001);
+
+				double [][] _w=w.getArray();
+				double [][] _dw=dw.getArray();
+
+				public void run()
+				{
+					// mu += numu*dmu.*sig
+					// sig += nusig*dsig.*sig;
+					// lambda = sum(w.*dw,2)./sum(w.*w,2)
+					//	dw -= (lambda*ones(1,N)) .* w
+					// w *= exp(nu*dw)
+
+					dmu.arrayTimesEquals(sig);
+					dmu.timesEquals(nusig.value);
+					mu.plusEquals(dmu);
+					mu.changed();
+					dmu.zero();
+
+					dsig.arrayTimesEquals(sig);
+					dsig.timesEquals(nusig.value);
+					sig.plusEquals(dsig);
+					sig.changed();
+					dsig.zero();
+
+					{
+						// the effect of this is to project
+						// dw away from w. the resulting vector
+						// is then added to the log of w
+
+						double nu=nuw.value;
+
+						for (int j=0; j<M; j++) {
+							double w2=0, lambda=0;
+							for (int i=0; i<N; i++) {
+								lambda += _w[i][j]*_dw[i][j];
+								w2     += _w[i][j]*_w[i][j];
+							}
+							tmp[j]=lambda/w2;
+						}
+
+						for (int i=0; i<N; i++) {
+							for (int j=0; j<M; j++) {
+								_w[i][j]  *= Math.exp(
+									nu*(_dw[i][j] - tmp[j]*_w[i][j])
+								);  // update w
+							}
+						}
+					}
+
+					normalise(w.getArray(),tmp);
+					w.changed();
+					dw.zero();	
+				}
+			};
+		} finally { Shell.pop(); }
+	}
+
+	class PDF extends Function implements Observer {
+		VInteger		index;
+		Viewable		vbl=null;
+
+		public PDF() { 
+			index=new VInteger("index",M/2); 
+			index.setRange(0,M-1); 
+			index.addObserver(this);
+		}
+
+		public void dispose() { index.dispose(); }
+
+		public double apply(double x) {
+			double Z=0;
+			for (int i=0; i<N; i++) {
+				int	 j=index.value;
+				double t=(x-_mu[i][j])/_sig[i][j];
+				Z+=(_w[i][j]/_sig[i][j])*Math.exp(-0.5*t*t);
+			}
+			return Z;
+		}
+		public String format(String x) {
+			return "mogpdf("+x+")";
+		}
+
+		public void setupObservers(Viewable v) {
+			w.addObserver(this);
+			mu.addObserver(this);
+			sig.addObserver(this);
+			vbl=v;
+		}
+
+		public void update(Observable o, Object arg) {
+			if (arg!=Viewable.DISPOSING) vbl.changed();
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/MatrixTrainer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.maths.*;
+// import  samer.tools.*;
+
+/**
+	Handles batched delta updates to a matrix.
+	The default flush multiplies the accumulated
+	delta by the learing rate and adds it to the
+	matrix.
+ */
+
+public class MatrixTrainer implements Model.Trainer, DoubleModel
+{
+	protected VParameter	ratep;		// learning rate
+	protected Matrix		A, T;			// A=target matrix, T=matrix of deltas
+	protected double[][]	_A, _T;
+	protected double		rate=1;
+	protected int			n, m;
+	protected double []  a, b;
+	protected double	count=0;
+
+	public MatrixTrainer(Vec left, Matrix A, Vec right) {
+		// must have left.size()=n, right.size()=m
+		this(left.array(),A,right.array());
+	}
+
+	public MatrixTrainer(double [] a, Matrix A, double [] b)
+	{
+		this.A = A;
+		n = A.getRowDimension();
+		m = A.getColumnDimension();
+		_A = A.getArray();
+
+		ratep = new VParameter("rate",this);
+		T = new Matrix("deltas",n,m);
+		_T = T.getArray();
+		this.a=a; this.b=b;
+	}
+
+	public void set(double r) { rate=r; }
+	public double get() { return rate; }
+	public VParameter getRate() { return ratep; }
+
+	protected void outerProduct(double w, double [] a, double [] b) {
+		for (int i=0; i<n; i++) {
+			double q=w*a[i], p[] = _T[i]; 
+			for (int j=0; j<m; j++) p[j] += q*b[j];
+		}
+	}
+	
+	public void dispose() { T.dispose(); ratep.dispose(); }
+	public void reset() { T.zero(); T.changed(); count=0; }
+	public void oneshot() { accumulate(1); flush(); }
+	public void accumulate() { accumulate(1); } 
+	public void accumulate(double w) { count+=w; outerProduct(w,a,b); }
+	
+	public void flush() {
+		if (count==0) return;
+		double eta=rate/count;
+
+		T.changed(); // to display accumulated stats
+		for (int i=0; i<n; i++) {
+			double [] p = _A[i], q = _T[i];
+			for (int j=0; j<m; j++) p[j] += eta*q[j];
+			Mathx.zero(q);
+		}
+		A.changed();
+		count=0;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/Mixture.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,153 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+
+public class Mixture extends NamedTask implements Model
+{
+	private Model 		M[]; 	// models
+	private int			n, m; // size of vector, num models
+	private Vec			x;		// input
+	private VVector	w;		// prior weights
+	private VVector	s;		// posterior
+	private int			k; 	// MAP estimate
+	private VDouble	Z;		// Parition function, ie p(x)
+	private double[]  _x,_s,_w,_g;
+
+	public Mixture( Vec input, int m) { this(input.size(), m); setInput(input); }
+	public Mixture( int N, int L)
+	{
+		super("mixture");
+		Shell.push(node);
+
+		n = N;
+		m = L;
+
+		x = null;
+		w = new VVector("prior",m);
+		s = new VVector("posterior",m);
+		Z = new VDouble("Z");
+		M = new Model[m];
+		Shell.pop();
+	
+		_s=s.array();
+		_w=w.array();
+		_g=new double[n];
+		Mathx.set(_w,new Constant(1.0/L));
+	}
+
+	public VVector prior() 		{ return w; }
+	public VVector posterior() { return s; }
+	public void setModel(int i, Model m) { M[i]=m;	}
+	public void setInput(Vec in) { x=in; _x=x.array(); }
+	public int getSize() { return n; }
+
+	public void dispose()
+	{
+		s.dispose();
+		w.dispose();
+		Z.dispose();
+		for (int i=0; i<m; i++) M[i].dispose();
+		super.dispose();
+	}
+
+	public void infer() {
+		// get models to compute energies.
+		// for (int i=0; i<m; i++) { M[i].infer(); M[i].compute(); }
+
+		// compute relative posterior
+		for (int i=0; i<m; i++) _s[i] = M[i].getEnergy(); // collect energies
+		double Emin=Mathx.min(_s);
+		for (int i=0; i<m; i++) _s[i] = _w[i]*Math.exp(Emin-_s[i]);
+
+		// compute partition function, normalise posterior
+		Z.set(Mathx.sum(_s));	// compute parition function
+		k=Mathx.argmax(_s);	// get MAP model
+		Mathx.mul(_s,1/Z.value);	// normalise posterior
+		s.changed();
+	}
+
+	public void compute()
+	{
+		/* compute gradients weighted by posterior */
+		Mathx.zero(_g);
+		for (int i=0; i<m; i++) {
+			double [] phi = M[i].getGradient();
+			for (int j=0; j<n; j++) _g[j] += _s[i]*phi[j];
+		}
+	}
+
+	public double	getEnergy() { return -Math.log(Z.value); }
+	public double [] getGradient() { return _g; }
+
+	public Functionx functionx() { return null; }
+
+	public void run() { infer(); }
+
+	public Trainer getTrainer() { return new Trainer(); }
+
+	public class Trainer implements Model.Trainer
+	{
+		Model.Trainer	T[];
+		VDouble		rate;
+		VVector		dw;
+		double		batch, _dw[];
+
+		public Trainer() {
+			T=new Model.Trainer[m]; // should all be null
+			rate=new VDouble("rate",0.001);
+			dw=new VVector("dw",m);
+			_dw=dw.array();
+		}
+
+		public void setTrainer(int i,Model.Trainer t) { T[i]=t; }
+		public void dispose() { rate.dispose(); dw.dispose(); }
+
+		public void accumulate() { accumulate(1.0); }
+		public void accumulate(double w) {
+			batch+=w;
+			for (int i=0;i<m; i++) {
+				if (T[i]!=null) T[i].accumulate(w*_s[i]); // sweet
+			}
+
+			// now accumulate info about priors
+			Mathx.add(_dw,_s);
+		}
+
+		public void oneshot() { accumulate(1.0); flush(); }
+		public void flush() {
+			for (int i=0; i<m; i++) if (T[i]!=null) T[i].flush();
+         double lambda=Mathx.dot(_w,_dw)/Mathx.dot(_w,_w);
+			double nu=rate.value/batch;
+
+			dw.changed();
+			for (int i=0; i<m; i++) {
+				_w[i] *= Math.exp(nu*(_dw[i]-lambda*_w[i])); // update w
+			}
+			Mathx.zero(_dw); batch=0;
+
+			// normalise
+			Mathx.mul(_w,1/Mathx.sum(_w));
+			w.changed();
+		}
+		public void reset() { 
+			for (int i=0; i<m; i++) if (T[i]!=null) T[i].reset();
+			Mathx.zero(_dw);
+			batch=0;
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/Model.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,77 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.maths.Vec;
+import samer.maths.opt.Functionx;
+
+public interface Model
+{
+	/** return size of vector this model expects */
+	int getSize();
+	
+	/** model should begin observing this vector */
+	void setInput(Vec x);
+
+	/** should infer values latent variables */
+	void infer();
+
+	/**
+		 contract is that getEnergy and getGradient
+		must return correct values for current x after
+		infer and compute has been called, but not necessarily
+		before.
+
+		This is to give model an opportunity to
+		cache values of energy and gradient to avoid repeated
+		computations.
+	*/
+	void compute();
+
+	/** return E = -log p(x) */
+	double getEnergy();
+
+	/** return dE/dx */
+	double [] getGradient();
+
+	public void dispose();
+
+	/** This presents a more functional interface to the model
+	so that it can be driven by an optimiser. See classes
+	Functionx and MinimiserBase in package samer.maths.opt. */
+
+	public Functionx functionx();
+
+	/** This represents a training algorithm for a Model
+		Trainer is responsible for counting calls to accumulate()
+		between flushes
+	*/
+
+	public interface Trainer {
+		/** collect statistics for parameter update */
+		public void accumulate();
+
+		/** weighted accumulate */
+		public void accumulate(double w);
+
+		/** use collected stats to update parameters and reset */
+		public void flush();
+
+		/** Must be equivalent to reset(); accumulate(); flush();
+			but can be optimised for non-batched training */
+		public void oneshot();
+
+		/** reset accumulators without updating parameters */
+		public void reset();
+
+		public void dispose();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/NoisyICA.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,191 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+import  samer.maths.*;
+import  samer.maths.opt.*;
+
+public class NoisyICA extends NamedTask implements Model
+{
+	Vec				x;				// data (input)
+	int				n, m;			// sizes (data, sources)
+	Matrix		A;				// basis matrix
+	Model		Ms, Me;	// source and noise models
+	VVector	s, z, e;		// sources, reconstruction, error
+	VDouble		E;				// energy
+
+	Task			inference=new NullTask();
+
+
+	// ----- variables used in computations -----------------
+
+	private	double []	e_;
+	private	double []	x_;
+	private	double []	z_;
+	private	double []	s_;
+	private	VectorFunctionOfVector tA, tAt;
+
+
+	public NoisyICA(Vec in,int outs) { this(new Node("noisyica"),in.size(),outs); setInput(in); }
+	public NoisyICA(int ins,int outs) { this(new Node("noisyica"),ins,outs); }
+	public NoisyICA(Node node, int inputs, int outputs)
+	{
+		super(node);
+		Shell.push(node);
+
+		n = inputs;
+		m = outputs;
+
+		s = new VVector("s",m);
+		z = new VVector("z",n);
+		e = new VVector("e",n);
+		E = new VDouble("E");
+		A = new Matrix("A",n,m);
+		A.identity();
+
+		e_ = e.array();
+		z_ = z.array();
+		s_ = s.array();
+		tA = new MatrixTimesVector(A);
+		tAt= new MatrixTransposeTimesVector(A);
+
+		Shell.pop();
+	}
+
+	public Model getSourceModel() { return Ms; }
+	public Model getNoiseModel() { return Me; }
+	public void  setSourceModel(Model m) { Ms=m; Ms.setInput(s); }
+	public void  setNoiseModel(Model m) { Me=m; Me.setInput(e); }
+	public void  setInput(Vec in) { x=in; x_ = x.array(); }
+	public Matrix basisMatrix() { return A; }
+	public VVector output() { return s; }
+	public VVector error() { return e; }
+	public VVector reconstruction() { return z; }
+
+	public int  getSize() { return n; }
+
+	public void setInferenceTask(Task t) { inference=t; }
+
+	public void infer() {
+		try {	inference.run(); }
+		catch (Exception ex) { 
+			Shell.trace("error: "+ex);
+			ex.printStackTrace();
+			throw new Error("inference failed: "+ex); }
+		tA.apply(s_,z_); Mathx.sub(e_,x_,z_);
+		e.changed(); z.changed(); s.changed();
+	}
+
+	public void compute() {
+		E.set(Me.getEnergy() + Ms.getEnergy());
+		// what about dE/dx?
+	}
+	public double getEnergy() { return E.value; }
+	public double [] getGradient() { return null; } // this is wrong
+
+	/** get basis vector norms into given array */
+	public void norms(double [] na)
+	{
+		double [][] M=A.getArray();
+
+		Mathx.zero(na);
+		for (int i=0; i<n; i++) {
+			double [] Mi=M[i];
+			for (int j=0; j<m; j++) {
+				na[j] += Mi[j]*Mi[j];
+			}
+		}
+	}
+
+	public void run() { infer(); }
+	public void dispose()
+	{
+		s.dispose();
+		A.dispose();
+		e.dispose();
+		z.dispose();
+		E.dispose();
+		tA.dispose();
+		tAt.dispose();
+
+		super.dispose();
+	}
+
+	public Functionx functionx() { return null; }
+
+	public Functionx posterior()	{
+		// returns Functionx which evaluates E and dE/ds at current x
+		return new Functionx() {
+			Functionx fMs=Ms.functionx();
+			Functionx fMe=Me.functionx();
+			double [] e=new double[n];
+			double [] ge=new double[n];
+			double [] gs=new double[m];
+
+			public void dispose() { fMs.dispose(); fMe.dispose(); }
+			public void evaluate( Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate( double [] s, double [] g)
+			{
+				tA.apply(s,z_); Mathx.sub(e,x_,z_);
+				double Ee=fMe.evaluate(e,ge); tAt.apply(ge,gs); // gs=A'*gamma(e)
+				double Es=fMs.evaluate(s,g);	Mathx.sub(g,gs); // g=gamma(s)-ge
+				return Es+Ee;
+			}
+		};
+	}
+
+	public Trainer learnHebbian() 	{ return new MatrixTrainer(e_,A,s_); }
+
+	public Trainer learnLewickiSejnowski()
+	{
+		final double [] h =new double[n];
+		final double [] f =new double[m];
+		return new MatrixTrainer(h,A,s_) {
+
+			public void accumulate(double w) {
+				// tAt.apply(Me.getGradient(),f); tA.apply(f,h);
+				tA.apply(Ms.getGradient(),h);
+				super.accumulate(w);
+			}
+			public void flush() { // flush with decay
+				for (int j=0; j<this.m; j++)
+					for (int i=0; i<this.n; i++)
+						_T[i][j] -= count*_A[i][j];
+				super.flush();
+			}
+		};
+	}
+
+	public Trainer learnDecayWhenActive()
+	{
+		final double [] h =new double[n];
+		return new MatrixTrainer(h,A,s_) {
+			VDouble				th=new VDouble("threshold",0.01);
+			public void accumulate(double w) {
+				// perhaps would like to get info out of optimiser here
+				tA.apply(Ms.getGradient(),h);
+				super.accumulate(w);
+
+				// decay when active part
+				double thresh=th.value;
+				for (int j=0; j<this.m; j++)
+					if (isActive(s_[j],thresh))
+						for (int i=0; i<this.n; i++)
+							_T[i][j] -= _A[i][j];
+			}
+
+			public VDouble getThreshold() { return th; }
+		};
+	}
+	static boolean isActive(double s, double t) { return s>t || s<-t; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/Scaler.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,271 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+
+/**
+	Automatic gain control for a given input vector.
+	Ouput appears in out. Also generates a trace of
+	'loudness' of input signal.
+  */
+
+public class Scaler extends NullTask implements Model
+{
+	private Model 		M;
+	private int			n;
+	private Vec			x;
+	private VVector	s;
+	private VDouble	multiplier;
+	private VDouble	offset;
+	private double	logK;
+
+	double []		_x, _s, _g, phi;
+
+	public Scaler( Vec input, Model M) { this(input); setOutputModel(M); M.setInput(s); }
+	public Scaler( Vec input) { this(input.size()); setInput(input); }
+	public Scaler( int N)
+	{
+		n = N;
+
+		x = null;
+		s = new VVector("output",n);
+		multiplier = new VDouble("scale",1.0,VDouble.SIGNAL);
+		offset = new VDouble("offset",0.0,VDouble.SIGNAL);
+		
+		_s = s.array();
+		_g = new double[n];
+		phi = null;
+		reset();
+		logK=Math.log(multiplier.value);
+	}
+
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public VDouble getScale() { return multiplier; }
+	public VDouble getOffset() { return offset; }
+	public Model getOutputModel() { return M;	}
+	public void setOutputModel(Model m) { M=m;	}
+	public void setInput(Vec in) { x=in; _x=x.array(); }
+	public void reset() {
+		// multiplier.load(Shell.env());
+		// offset.load(Shell.env());
+	}
+
+	public String toString() { return "Scaler:"+x; } // +"->"+s; }
+	public void dispose()
+	{
+		offset.dispose();
+		multiplier.dispose();
+		s.dispose();
+		super.dispose();
+	}
+
+	public void infer() {
+		double a=offset.value, k=1/multiplier.value;
+		for (int i=0; i<n; i++) _s[i] = k*(_x[i]-a);
+		s.changed();
+	}
+
+	public void compute() {
+		Mathx.mul(_g,M.getGradient(),1/multiplier.value);
+	}
+
+	public double	getEnergy() { return M.getEnergy() + n*logK; }
+	public double [] getGradient() { return _g; }
+
+	public Functionx functionx() {
+		return new Functionx() {
+			Functionx fM=M.functionx();
+			double [] s=new double[n];
+
+			public void dispose() { fM.dispose(); }
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				double a=offset.value, k=1/multiplier.value;
+				for (int i=0; i<n; i++) s[i] = k*(x[i]-a);
+				double E=fM.evaluate(s,g);
+				Mathx.mul(g,k);
+				return E+n*logK;
+			}
+		};
+	}
+
+	public void starting() { logK=Math.log(multiplier.value); }
+	public void stopping() {}
+	public void run() { infer(); }
+
+	public Trainer getTrainer() { return new Trainer(); }
+	public OffsetTrainer getOffsetTrainer()	{ return new OffsetTrainer(); }
+	public ScaleTrainer getScaleTrainer()	{ return new ScaleTrainer(); }
+
+	public class Trainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble		rate1=new VDouble("scaleRate",0.001);
+		VDouble		rate2=new VDouble("offsetRate",0.000001);
+		double		G,H,count;
+		double []	_s;
+		int				n;
+
+
+		public Trainer() { _s = s.array(); n=Scaler.this.n; }
+
+		public void reset() { count=0; G=0; H=0; }
+		public String toString() { return "Trainer:"+Scaler.this; }
+
+		public VDouble getScaleRate() { return rate1; }
+		public VDouble getOffsetRate() { return rate2; }
+
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+//			if (M.getEnergy() > 8000) return;
+			double [] phi=M.getGradient();
+			double	g=0;
+			for (int i=0; i<n; i++) g += phi[i]*_s[i] - 1;
+			G += w*g;
+			H += w*Mathx.sum(phi);
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+
+			double k=multiplier.value;
+			double mu=offset.value;
+
+			mu += (rate2.value/count)*k*H/n;
+			G *= rate1.value/(n*count);
+			k *= Math.exp(G);
+			multiplier.set(k);
+			offset.set(mu);
+			logK+=G;
+			reset();
+		}
+
+		public void oneshot() {
+			double [] phi=M.getGradient();
+			G=0; H = Mathx.sum(phi);
+			for (int i=0; i<n; i++) G += phi[i]*_s[i] - 1;
+
+			double k=multiplier.value;
+			double mu=offset.value;
+
+			mu += rate2.value*k*H/n;
+			G *= rate1.value/n;
+			k *= Math.exp(G);
+			multiplier.set(k);
+			offset.set(mu);
+			logK+=G;
+		}
+
+
+		public void dispose() { rate1.dispose(); rate2.dispose(); }
+		public void starting() { reset(); logK=Math.log(multiplier.value); }
+		public void run() { oneshot(); }
+	}
+
+	public class ScaleTrainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble	rate1=new VDouble("scaleRate",0.001);
+		double		G,count;
+		double []	_s;
+		int				n;
+
+
+		public ScaleTrainer() { _s = s.array(); n=Scaler.this.n; }
+		public String toString() { return "ScaleTrainer:"+Scaler.this; }
+
+		public void reset() { count=0; G=0; }
+
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			double [] phi=M.getGradient();
+			double	g=0;
+			for (int i=0; i<n; i++) g += phi[i]*_s[i] - 1;
+			G += w*g;
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+
+			double k=multiplier.value;
+
+			G *= rate1.value/(n*count);
+			k *= Math.exp(G);
+			multiplier.set(k);
+			logK+=G;
+			reset();
+		}
+
+		public void oneshot() {
+			double [] phi=M.getGradient();
+			G=0;
+			for (int i=0; i<n; i++) G += phi[i]*_s[i] - 1;
+
+			double k=multiplier.value;
+
+			G *= rate1.value/n;
+			k *= Math.exp(G);
+			multiplier.set(k);
+			logK+=G;
+		}
+
+
+		public void dispose() { rate1.dispose(); }
+		public void starting() { reset(); logK=Math.log(multiplier.value); }
+		public void run() { oneshot(); }
+	}
+
+	/** This trains only the offset, not the scale */
+	public class OffsetTrainer extends AnonymousTask implements Model.Trainer
+	{
+		VDouble		rate2=new VDouble("offsetRate",0.000001);
+		double		H, count;
+		int				n;
+
+		public OffsetTrainer() { n=Scaler.this.n; }
+		public String toString() { return "OffsetTrainer:"+Scaler.this; }
+
+		public void reset() { count=0; H=0; }
+
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			double [] phi=M.getGradient();
+			H += w*Mathx.sum(phi);
+			count+=w;
+		}
+
+		public void flush() {
+			if (count==0) return; // nothing to do
+			offset.value += (rate2.value/count)*multiplier.value*H/n;
+			offset.changed();
+			reset();
+		}
+
+		public void oneshot() {
+			double [] phi=M.getGradient();
+			H = Mathx.sum(phi);
+			offset.value += rate2.value*multiplier.value*H/n;
+			offset.changed();
+		}
+
+		public void dispose() { rate2.dispose(); }
+		public void starting() { reset(); }
+		public void run() { oneshot(); }
+	}
+	// could have alternative trainers if prior is Gaussian or Laplacian,
+	// in which case, parameters can be estimated in closed form
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/SignalHistogram.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+package	samer.models;
+import	samer.tools.*;
+import	samer.maths.*;
+import	samer.core.*;
+import	samer.core.types.*;
+
+public class SignalHistogram extends JointHistogramBase
+{
+	Generator		gen;
+	double		buf[];
+	int				size, i;
+	VInteger		lag;
+
+	public SignalHistogram(Generator g, int bufsize) {
+		lag=new VInteger("lag",1);
+		lag.setRange(1,bufsize-1);
+		buf=new double[bufsize];
+		size=bufsize;
+		gen=g;
+	}
+
+	public void run() {
+		int j=i-lag.value; if (j<0) j+= size;
+		buf[i]=gen.next(); if (i>=size) i=0;
+		L.set(data(buf[i],buf[j]));
+		i++;
+	}
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/SmoothGeneralisedExponential.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,107 @@
+package samer.models;
+
+import samer.maths.*;
+import samer.maths.opt.*;
+import samer.tools.*;
+import samer.core.*;
+import samer.core.types.*;
+import java.util.*;
+
+/**
+	Non-adaptive generalised exponential factorial prior: the pointy
+	bit of the usual GeneralisedExponential has been smoothed out
+	by blending with a quadratic.
+ */
+
+public class SmoothGeneralisedExponential extends NamedTask implements Model, Observer {
+	Vec		input;
+	VVector	alpha, e, grad;
+	int			N;
+	VDouble	E;
+	double[]	x, g, e0, _e, a, eps;
+	double	last_eps;
+
+	public SmoothGeneralisedExponential(Vec x) { this(x.size()); setInput(x); }
+	public SmoothGeneralisedExponential(int n)  {
+		super("genExp");
+		Shell.push(node);
+		N=n;
+		E=new VDouble("E");
+		e=new VVector("e",N);
+		grad=new VVector("phi",N);
+		alpha=new VVector("alpha",N);
+		eps=new double[N];
+		alpha.addSaver();
+		Shell.pop();
+
+		alpha.addObserver(this);
+		g=grad.array(); // new double[N];
+		e0=new double[N];
+		a=alpha.array();
+		_e=e.array();
+		
+		Mathx.setAll(a,1.0); 
+		setEps(0.1);
+	}
+
+	public void update(Observable obs, Object arg) {
+		setEps(last_eps);
+	}
+	public void setEps(double e) {
+		last_eps=e;
+		for (int i=0; i<N; i++) { eps[i]=Math.pow(e,2-a[i]); }
+	}
+	public void setInput(Vec in) { input=in; x=input.array(); }
+	public int getSize() { return N; }
+	public void dispose() {
+		alpha.dispose();
+		grad.dispose();
+		E.dispose();
+	}
+
+	public VVector	getEnergyVector() { return e; }
+	public VDouble	getEnergySignal() { return E; }
+	public double	getEnergy() { return E.value; }
+	public double [] getGradient() { return g; 	}
+	public VVector  getAlpha() { return alpha; }
+	
+	public void run() { compute(); }
+	public void infer() {}
+	public void compute() {
+		// compute log likelihood
+
+		for (int i=0; i<N; i++) {
+			double t=Math.abs(x[i]);
+			_e[i] = t*t/(Math.pow(t,2-a[i]) + eps[i]);
+		}
+
+		// compute gradient g_i = dL/dx_i
+		for (int i=0; i<N; i++) {
+			if (x[i]==0) g[i]=0;
+			else g[i] = a[i]*(_e[i]/x[i]);
+		}
+
+		e.changed();
+		grad.changed();
+		E.set(Mathx.sum(_e));
+	}
+
+	public Functionx functionx() {
+		return new Functionx() {
+			double [] __e=new double[N];
+			public void dispose() {}
+			public void evaluate(Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate(double [] x, double [] g) {
+				for (int i=0; i<N; i++) {
+					if (x[i]==0) { g[i]=0; __e[i]=0; }
+					else {
+						double t=Math.abs(x[i]);
+						__e[i] = t*t/(Math.pow(t,2-a[i]) + eps[i]);
+						g[i] = a[i]*(__e[i]/x[i]);
+					}
+				}
+				return  Mathx.sum(__e); // +L0;
+			}
+		};
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/SparseICA.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,298 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.Agent.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+import  java.util.*;
+
+public class SparseICA extends NamedTask implements Model, Agent
+{
+	Model			sourceModel;
+	int					n;
+	Vec				x;
+	SparseMatrix	W; // , A;
+	VVector  		s;				// state
+	VDouble			logA;
+	double[]			_g; // cached dE/dx
+
+	public SparseICA(Vec input) { this(input.size()); setInput(input); }
+	public SparseICA(int N)
+	{
+		super("ica");
+		Shell.push(node);
+
+		n = N;
+
+		x = null;
+		W = new SparseMatrix("W");
+		// A = new SparseMatrix("A",n,n);
+		s = new VVector("s",n);
+		logA = new VDouble( "log |A|");
+		Shell.pop();
+
+		W.identity(); W.changed();
+		_g = new double[n];
+	}
+
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public Model getOutputModel() { return sourceModel; }
+	public void setOutputModel(Model m) {	sourceModel=m; }
+	public void setInput(Vec input) {
+		if (input.size()!=n) throw new Error("Input vector is the wrong size");
+		x = input;
+	}
+
+	public SparseMatrix getWeightMatrix() { return W; }
+	// public Matrix getBasisMatrix() { return A; }
+
+	public void dispose()
+	{
+		W.dispose(); // A.dispose();
+		logA.dispose();
+		s.dispose();
+		// infer.dispose();
+		// grad.dispose();
+
+		super.dispose();
+	}
+
+	public void infer() { W.times(s.array(),x.array()); s.changed(); }
+	public void compute() { W.transposeTimes(_g,sourceModel.getGradient()); }
+	public double getEnergy() { return sourceModel.getEnergy()+logA.value; }
+	public double[] getGradient() { return _g; }
+	public samer.maths.opt.Functionx functionx() { return null; }
+
+	public void starting() { }
+	public void stopping() {}
+	public void run() { infer(); }
+
+	public void getCommands(Registry r) { r.add("basis").add("logdet"); }
+	public void execute(String cmd, Environment env)
+	{
+	/*
+		if (cmd.equals("basis")) {
+			Shell.print("computing ICA basis...");
+			// sparse matrix inverse
+			// much easier if matrix is block decomposable!
+			A.assign(W.inverse());
+			A.changed();
+			Shell.print("...done.");
+		} else if (cmd.equals("logdet")) {
+			Shell.print("computing SVD...");
+			// double [] s=W.svd().getSingularValues();
+			// Shell.print("...done.");
+			// Mathx.log(s);
+			// logA.set(-Mathx.sum(s));
+		}
+	 */
+	}
+
+	public Trainer getTrainer() { return new ON2Trainer(); }
+	public Trainer getAltTrainer() { return new ON3Trainer(); }
+
+	/** This trainer uses an O(N^2) run step and an O(N^2) flush. */
+
+	public class ON2Trainer implements Model.Trainer
+	{
+		double[]         buf;
+		VDouble		rate;
+		SparseMatrix	GW;
+		int					_n;
+		double			thresh;
+		double			batch;
+
+		public ON2Trainer()
+		{
+			_n=n;
+			Shell.push(getNode());
+			GW=new SparseMatrix("GW",W); // copy pattern from W
+			rate=new VDouble("rate",0.01);
+			thresh=Shell.getDouble("anomaly",n*20);
+			Shell.pop();
+			batch=0;
+
+			buf=new double[n]; // general purpose n-buffer
+		}
+
+		public void dispose() { GW.dispose(); rate.dispose(); }
+		public void reset() { GW.zero(); GW.changed(); batch=0; }
+		public void oneshot() { accumulate(1); flush(); }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			batch+=w;
+
+			W.transposeTimes(buf,s.array()); // buf = W'*s
+			Mathx.mul(buf,w); 						// buf = w*W'*s
+			GW.addOuterProduct(sourceModel.getGradient(),buf); // GW+=grad*buf'
+			// could subtract w*W here
+		}
+
+		public void flush() 	{
+			if (batch==0) return;
+			W.icaUpdate(GW,-rate.value,batch); // W += eta(GW/batch - W)
+			W.changed();
+			GW.zero();
+			batch=0;
+		}
+	}
+
+	/** This trainer saves on an O(N^2) step during accumulation, at
+		the expense of an O(N^3) flush. As long as the batch size
+		is O(N), then it should be about the same overall. The advantage
+		is the collected statistics are more transparent, and can be used
+		to make scalar or diagonal updates more frequenty. */
+
+
+	public class ON3Trainer extends AnonymousTask implements Model.Trainer
+	{
+		SparseMatrix	G;
+		double[]     	buf;
+		VDouble		rate;
+		int					_n;
+		double			batch, thresh;
+
+		public ON3Trainer()
+		{
+			_n=n;
+			G=new SparseMatrix("G");
+			// set up G so that it has the right links
+			rate=new VDouble("rate",0.01);
+			thresh=Shell.getDouble("anomaly",20*n);
+			batch=0;
+
+			buf=new double[n]; // general purpose n-buffer
+		}
+
+		/** this is so you can manipulate the matrix before flushing */
+		public SparseMatrix getGMatrix() { return G; }
+
+		public void starting() { reset(); }
+		public void run() { accumulate(); }
+
+		public void dispose() { G.dispose(); rate.dispose();	super.dispose(); }
+		public void oneshot() { accumulate(1); flush(); }
+		public void reset() { G.zero(); batch=0; }
+		public void accumulate() { accumulate(1); }
+		public void accumulate(double w) {
+			double _s[]=s.array();
+			batch+=w;
+
+			Mathx.copy(sourceModel.getGradient(),buf);
+			Mathx.mul(buf,w);
+			G.addOuterProduct(buf,_s);
+			// subtract identity to prevent loss of precision?
+		}
+
+		public void flush()
+		{
+			if (batch==0) return;
+
+			// compute deltas: dW=W - G*W/batch;
+			// now W += eta*dW
+			// double eta=rate.value;
+			// for (each link) W[i][j] += eta*dW[i][j];
+			reset(); // ready for next batch
+		}
+	}
+
+	// Initialisation methods
+	
+	/** x is an N-dim vector.
+		R is an N by N symmetric similarity matrix.
+		M is number of unit pairs (butterflies)  build into ICA model */
+	
+	public void init1(Matrix R, int M) {
+		double [][]	_R=R.getArray();
+		TreeSet		edges=new TreeSet();
+
+		Shell.status("Building sorted edge list...");
+		for (int i=0; i<n; i++) {
+			for (int j=i+1; j<n; j++) {
+				edges.add(new Edge(i,j,_R[i][j]));
+			}
+		}
+		Shell.status("Edge list complete.");
+		Shell.status("Adding edges to sparse matrix...");
+
+		W.allocate(n+2*M);
+		for (int i=0; i<n; i++) W.addElement(i,i,1);
+
+		Iterator it=edges.iterator();
+		for (int k=0; k<M; k++) {
+			Edge e=(Edge)it.next();
+			W.addElement(e.i,e.j,0);
+			W.addElement(e.j,e.i,0);
+		}
+		Shell.status("Sparse matrix complete.");
+	}
+
+	/** This version only builds disjoint butterfly pairs, ie only 2N edges per layer
+		Need a version that builds bigger local modules. */
+	public void init2(Matrix R) {
+		double [][]	_R=R.getArray();
+		boolean []	flags=new boolean[n];
+		TreeSet		edges=new TreeSet();
+
+		Shell.status("Building sorted edge list...");
+		for (int i=0; i<n; i++) {
+			for (int j=i+1; j<n; j++) {
+				edges.add(new Edge(i,j,_R[i][j]));
+			}
+		}
+		Shell.status("Edge list complete.");
+		Shell.status("Adding edges to sparse matrix...");
+
+		W.allocate(2*n);
+		Iterator it=edges.iterator();
+		for (int k=0; k<n; k+=2)  {
+			Edge e;
+			do { e=(Edge)it.next(); } while (flags[e.i] || flags[e.j]);
+			W.addElement(e.i,e.i,1);
+			W.addElement(e.i,e.j,0);
+			W.addElement(e.j,e.i,0);
+			W.addElement(e.j,e.j,1);
+			flags[e.i]=flags[e.j]=true;
+		}
+		Shell.status("Sparse matrix complete.");
+	}
+}
+
+class Edge implements Comparable {
+	int	i, j;
+	double x;
+
+	public Edge(int i, int j, double x) { this.i=i; this.j=j; this.x=x; }
+	public int compareTo(Object o) {
+		Edge e=(Edge)o;
+		// NB: REVERSE ordering on x
+		if (x>e.x) return -1;
+		else if (x<e.x) return 1;
+		else if (i<e.i) return -1;
+		else if (i>e.i) return 1;
+		else if (j<e.j) return -1;
+		else if (j>e.j) return 1;
+		else return 0;
+	}
+	public String toString() {
+		StringBuffer buf=new StringBuffer("(");
+		buf.append(i);
+		buf.append(",");
+		buf.append(j);
+		buf.append(":");
+		buf.append(x);
+		return buf.toString();
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/VarianceICA.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,188 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+import  samer.maths.*;
+import  samer.maths.opt.*;
+
+public class VarianceICA extends NamedTask implements Model
+{
+	Vec		x;				// data (input)
+	int		n, m;			// sizes (data, sources)
+	Matrix	A;				// basis matrix
+	Model		Ms;			// source model
+	VVector	s, z, e;		// sources, reconstruction, error
+	VDouble	E;				// energy
+
+	Task			inference=new NullTask();
+
+
+	// ----- variables used in computations -----------------
+
+	private	double []	e_;
+	private	double []	x_;
+	private	double []	z_;
+	private	double []	s_;
+	private	VectorFunctionOfVector tA, tAt;
+
+
+	public VarianceICA(Node node, int inputs, int outputs)
+	{
+		super(node);
+		Shell.push(node);
+
+		n = inputs;
+		m = outputs;
+
+		s = new VVector("s",m);
+		z = new VVector("z",n);
+		e = new VVector("e",n);
+		E = new VDouble("E");
+		A = new Matrix("A",n,m);
+		A.identity();
+
+		e_ = e.array();
+		z_ = z.array();
+		s_ = s.array();
+		tA = new MatrixTimesVector(A);
+		tAt= new MatrixTransposeTimesVector(A);
+
+		Shell.pop();
+	}
+
+	public Model getSourceModel() { return Ms; }
+	public void  setSourceModel(Model m) { Ms=m; Ms.setInput(s); }
+	public void  setInput(Vec in) { x=in; x_ = x.array(); }
+	public Matrix basisMatrix() { return A; }
+	public VVector output() { return s; }
+	public VVector error() { return e; }
+
+	public int  getSize() { return n; }
+
+	public void setInferenceTask(Task t) { inference=t; }
+
+	public void infer() {
+		try {	inference.run(); }
+		catch (Exception ex) { throw new Error("inference failed"); }
+		tA.apply(s_,z_); 
+		Mathx.sub(e_,x_,z_);
+		Mathx.div(e_,z_);
+		Mathx.div(e_,z_);
+		e.changed(); z.changed(); s.changed();
+	}
+
+	public void compute() {
+		double EE=0;
+		for (int i=0; i<n; i++) {
+			double t=x_[i]/z_[i];
+			EE += t - Math.log(t);
+		}
+		E.set(EE - n + Ms.getEnergy());
+		// what about dE/dx?
+	}
+	public double getEnergy() { return E.value; }
+	public double [] getGradient() { return null; } // this is wrong
+
+	public void run() { infer(); }
+	public void dispose()
+	{
+		s.dispose();
+		A.dispose();
+		e.dispose();
+		z.dispose();
+		E.dispose();
+		tA.dispose();
+		tAt.dispose();
+
+		super.dispose();
+	}
+
+	public Functionx functionx() { return null; }
+
+	public Functionx posterior()	{
+		// returns Functionx which evaluates E and dE/ds at current x
+		return new Functionx() {
+			Functionx fMs=Ms.functionx();
+			double [] ge=new double[n];
+
+			public void dispose() { fMs.dispose(); }
+			public void evaluate( Datum P) { P.f=evaluate(P.x,P.g); }
+			public double evaluate( double [] s, double [] g)
+			{
+				double E=0;
+				
+				tA.apply(s,z_);	// z=As
+				for (int i=0; i<n; i++) {
+					double t=x_[i]/z_[i];
+					g[i] = (t-1)/z_[i];
+					E += t - Math.log(t);
+				}
+				tAt.apply(g,ge);  // ge=A'*g
+				E+=fMs.evaluate(s,g);
+				Mathx.sub(g,ge); 
+				return E;
+			}
+		};
+	}
+
+	public Trainer learnHebbian() 	{
+		Shell.push(node);
+		try {	return new MatrixTrainer(e_,A,s_); }
+		finally { Shell.pop(); }
+	}
+
+	public Trainer learnLewickiSejnowski()
+	{
+		Shell.push(node);
+		try {
+			final double [] h =new double[n];
+			final double [] f =new double[m];
+			return new MatrixTrainer(h,A,s_) {
+
+				public void accumulate(double w) {
+					tA.apply(Ms.getGradient(),h);
+					super.accumulate(w);
+				}
+				public void flush() { // flush with decay
+					for (int j=0; j<this.m; j++)
+						for (int i=0; i<this.n; i++)
+							_T[i][j] -= count*_A[i][j];
+					super.flush();
+				}
+			};
+		} finally { Shell.pop(); }
+	}
+
+	public Trainer learnDecayWhenActive()
+	{
+		Shell.push(node);
+		try {
+			final double [] h =new double[n];
+			return new MatrixTrainer(h,A,s_) {
+				VDouble				th=new VDouble("threshold",0.01);
+				public void accumulate(double w) {
+					tA.apply(Ms.getGradient(),h);
+					super.accumulate(w);
+
+					// decay when active part
+					double thresh=th.value;
+					for (int j=0; j<this.m; j++)
+						if (isActive(s_[j],thresh))
+							for (int i=0; i<this.n; i++)
+								_T[i][j] -= _A[i][j];
+				}
+			};
+		} finally { Shell.pop(); }
+	}
+	static boolean isActive(double s, double t) { return s>t || s<-t; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/notyet/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,3 @@
+/ModelGraph.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/PCA.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/notyet/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/models/notyet
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/notyet/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/notyet/ModelGraph.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,37 @@
+package samer.models;
+import samer.tools.*;
+
+
+public class ModelGraph extends AnonymousTask {
+
+	public void run() {}
+	
+	// need models (nodes)
+	// and edges
+
+	/*
+		Check model input and output ports
+		(Models need port descriptors)
+		Create buffers if necessary
+		setup plumbing:
+			setOutputModel
+			setInput
+
+		Setting up: read model graph and compile
+		appropriate task list.
+
+		do inference
+			compute latent variables
+				MAP estimates
+				posteriors
+
+		for learning:
+			compute gradients
+			collect stats (Trainer.accumulate)
+
+		subrate update models
+			flush trainers
+				old model + new stats --> new model
+			reset statistics
+	*/
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/models/notyet/PCA.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,153 @@
+/*
+ *	Copyright (c) 2002, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.models;
+import  samer.core.*;
+import  samer.core.Agent.*;
+import  samer.core.types.*;
+import  samer.tools.*;
+import  samer.maths.*;
+import  samer.maths.random.*;
+
+
+
+public abstract class PCA extends NamedTask implements Model
+{
+	int				n;
+	Vec			x;
+	VVector		s;
+	Matrix			W;
+	VDouble		logA;
+	double[]		_g,_s; // cached dE/dx
+	Model			sourceModel;
+
+	MatrixTimesVector					infer;
+	MatrixTransposeTimesVector	grad;
+
+	public PCA(Vec input) { this(input.size()); setInput(input); }
+	public PCA(int N)
+	{
+		super("pca");
+		Shell.push(node);
+
+		n = N;
+
+		x = null;
+		W = new Matrix("W",n,n);
+		s = new VVector("s",n);
+		logA = new VDouble( "log |A|",0.0,VDouble.SIGNAL);
+		infer = null;
+		Shell.pop();
+
+		grad = new MatrixTransposeTimesVector(W);
+		_g = new double[n];
+		_s = s.array();
+	}
+	
+	public int getSize() { return n; }
+	public VVector output() { return s; }
+	public void setInput(Vec input) {
+		if (input.size()!=n) throw new Error("Input vector is the wrong size");
+		x = input;
+		infer = new MatrixTimesVector(s,W,x);
+	}
+
+	public void dispose()
+	{
+		W.dispose();
+		logA.dispose();
+		s.dispose();
+		infer.dispose();
+		grad.dispose();
+
+		super.dispose();
+	}
+
+	public void infer() { infer.run(); s.changed(); } // compute s=Wx
+	public void compute() {
+		grad.apply(_g,_s);
+	}
+
+	public double getEnergy() { return logA.value + sourceModel.getEnergy(); }
+	public double[] getGradient() { return _g; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() { infer(); }
+
+	public Task getTrainingTask() { return new Trainer(); }
+
+	public class Trainer extends NamedTask
+	{
+		Matrix			G;
+		double[][]		_G, _W;
+		double[]         _g,_s, buf;
+		VDouble		rate;
+		int				batch, _n;
+
+		public Trainer()
+		{
+			super("learn",PCA.this.getNode());
+			Shell.push(Trainer.this.node);
+			_n=n;
+			G=new Matrix("G",n,n);
+			rate=new VDouble("rate",0.01);
+			Shell.pop();
+			batch=0;
+
+			_s=s.array();
+			_G=G.getArray();
+			_W=W.getArray();
+			buf=new double[n]; // general purpose n-buffer
+		}
+
+		public void dispose() { G.dispose(); rate.dispose();	super.dispose(); }
+		public void starting() { G.zero(); G.changed(); batch=0; }
+		public void run()
+		{
+			double q, p[];
+			batch++;
+
+			double[] phi=sourceModel.getGradient();
+			for (int i=0; i<_n; i++) {
+				p = _G[i]; q=phi[i];
+				for (int j=0; j<_n; j++) p[j] += q*_s[j];
+				p[i] -= 1;
+			}
+		}
+
+		public final void updateG() { G.changed(); }
+		public void flush()
+		{
+			double eta=-rate.value/batch;
+
+			// this is going to do a matrix G *= W, in place
+			for (int i=0; i<_n; i++) {
+				for (int j=0; j<_n; j++) {
+					double a=0;
+					for (int k=0; k<_n; k++) a += _G[i][k]*_W[k][j];
+					buf[j] = a;
+				}
+				Mathx.copy(buf,_G[i]);
+			}
+
+			// now W += eta*G
+			for (int i=0; i<_n; i++) {
+				double [] p = _W[i],	q = _G[i];
+				for (int j=0; j<n; j++) p[j] += eta*q[j];
+			}
+
+			// reset for next batch
+			W.changed();
+			G.zero();
+			batch=0;
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,8 @@
+/JavaProcedure.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SchemeList.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SilkCompleter.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SilkFunction.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SilkObserver.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SilkTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Terminal.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/silk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/JavaProcedure.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+package samer.silk;
+import samer.core.*;
+import jscheme.*;
+import jsint.*;
+
+//public class JavaProcedure implements SchemeProcedure {
+public class JavaProcedure extends Procedure {
+	public Object apply(Object [] args) {
+		for (int i=0; i<args.length; i++) {
+			Shell.trace("arg "+i+"="+args[i]);
+		}
+		return null;
+	}
+
+	public Object apply(Pair args) {
+		Shell.trace("apply to Pair");
+		return apply(U.listToVector(args));
+	}
+	public Object apply(SchemePair args) {
+		Shell.trace("apply to SchemePair");
+		return apply(U.listToVector(args));
+	}
+
+
+//	public void run() { Shell.print("run!"); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/SchemeList.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,62 @@
+package samer.silk;
+import java.util.*;
+import jscheme.*;
+
+public class SchemeList extends AbstractSequentialList {
+	SchemePair	head;
+
+	public SchemeList(SchemePair pair) { head=pair; }
+
+	public ListIterator listIterator(int index) {
+		return new Iterator(head,index);
+	}
+
+	public int size() {
+		int i=0;
+		for (SchemePair p=head; !p.isEmpty(); p=(SchemePair)p.getRest()) i++;
+		return i;
+	}
+
+	class Iterator implements ListIterator {
+		SchemePair	current, previous=null;
+		int			index=0;
+
+		public Iterator(SchemePair head, int index) { 
+			current=head;
+			for (int i=0; i<index; i++) next();
+		}
+
+		public void add(Object o) { 
+			if (previous==null) no();
+			current=new jsint.Pair(o,current);
+			previous.setRest(current);
+		}
+
+		public void remove() { no(); }
+//			if (previous==null) no();
+//			previous.setRest(current.getRest());
+//			current=(SchemePair)current.getRest();
+//		}
+
+		public void set(Object o) { previous.setFirst(o); }
+
+		public boolean hasNext() {
+			return !current.isEmpty();
+		}
+
+		public Object next() {
+			Object rc=current.getFirst();
+			previous=current;
+			current=(SchemePair)current.getRest();
+			index++;
+			return rc;
+		}
+
+		public int nextIndex() { return index; }
+		public boolean hasPrevious() { no(); return false; }
+		public Object previous() { no(); return null; }
+		public int previousIndex() { no(); return 0; }
+
+		private void no() { throw new Error("Unsupported"); }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/SilkCompleter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+package samer.silk;
+import samer.core.*;
+import java.util.*;
+import org.gnu.readline.*;
+import jsint.*;
+
+public class SilkCompleter implements ReadlineCompleter {
+	Iterator	it;
+	public String completer(String text, int state)
+	{
+		if (state == 0) {
+			// first call to completer(): initialize iterator
+			// it=Symbol.symbolTable.entrySet().iterator();
+			it=Symbol.symbolTable.values().iterator();
+		}
+		while (it.hasNext()) {
+			// Map.Entry entry = (Map.Entry)it.next();
+			// Symbol symbol=(Symbol)entry.getValue();
+			// String	name=(String)entry.getKey();
+			Symbol symbol=(Symbol)it.next();
+			String name=(String)symbol.toString();
+			if (name.startsWith(text) && symbol.isDefined()) return name;
+		}
+		return null; // we reached the last choice.
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/SilkFunction.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+package samer.silk;
+
+import java.util.*;
+import jsint.*;
+
+public class SilkFunction extends samer.maths.Function {
+	Procedure	fn;
+
+	public SilkFunction(Procedure fn) { this.fn=fn; }
+	public double apply( double t) {
+		Object[] args = { new Double(t) };
+		Object res = fn.apply(args); 
+		return ((Number)res).doubleValue();
+	}
+
+	public String format( String arg) { return "("+fn.getName()+")"; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/SilkObserver.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,13 @@
+package samer.silk;
+
+import java.util.*;
+import jsint.*;
+
+public class SilkObserver implements Observer {
+	Procedure	_update;
+
+	public SilkObserver(Procedure _update) { this._update=_update; }
+	public void update(Observable o, Object a) {
+		Object[] args = { o, a}; _update.apply(args); 
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/SilkTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,20 @@
+package samer.silk;
+
+import samer.tools.*;
+import java.util.*;
+import jsint.*;
+
+public class SilkTask implements Task, Observer {
+	Procedure	_start, _stop, _run, _dispose;
+	private final static Object[] args=new Object[0];
+
+	public SilkTask(Procedure _run) { this._run=_run; /* check minargs=0 */ }
+	public String toString() { return "Scheme:"+_run; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void dispose() {}
+	public void run() { _run.apply(args); }
+
+	public void update(Observable o, Object a) { _run.apply(args); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/silk/Terminal.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,106 @@
+package samer.silk;
+import java.net.*;
+import java.io.*;
+import jsint.*;
+
+/** Terminal to acces a remote JVM.
+	Connects to a given port on the remote host,
+	then relays System.in and out to the socket.
+ */
+
+public class Terminal {
+
+	public static void connect(Socket sock) throws Exception { connect(sock,null); }
+	public static void connect(Socket sock, Procedure readline) throws Exception {
+		InputStream	in=sock.getInputStream();
+		OutputStream	out=sock.getOutputStream();
+		Thread	reader=new Thread(new Transfer(in,System.out));
+
+		reader.start(); // everything coming from socket gets squirted to stdout
+
+		// this end should be responsible for writing prompt
+		if (readline!=null) 	{
+			PrintWriter prn=new PrintWriter(out,true);
+			try {
+				for (;;) {
+					prn.println((String)SI.call(readline,"remote> "));
+					Thread.sleep(100); // wait for reply
+				}
+			} catch (Exception ex) {}
+		} else (new Transfer(System.in,out)).run();
+		System.out.println();
+
+		sock.shutdownOutput();   // other end should notice this
+		reader.join(5000); 		// wait for reader to die, 5 seconds max
+		sock.close();
+  	}
+
+
+	static class Transfer implements Runnable {
+		InputStream	in;
+		OutputStream	out;
+		byte []			buffer;
+
+		public Transfer(InputStream in, OutputStream out) {
+			this.in=in;
+			this.out=out;
+			buffer=new byte[2048];
+		}
+
+		public void run() {
+			int n;
+			try {
+				do {
+					n=in.read(buffer,0,2048);
+					if (n>0) { out.write(buffer,0,n); out.flush(); }
+				} while (n>=0);
+    			} catch (Exception ex) { ex.printStackTrace(); }
+			System.err.println("reader thread terminating.");
+		}
+	}
+
+	public static void REPL(Socket call) throws Exception
+	{
+		Evaluator evaluator=Scheme.currentEvaluator();
+
+		PrintWriter	oldout=evaluator.getOutput();
+		PrintWriter	olderr=evaluator.getError();
+ 		PrintWriter newout=new PrintWriter(call.getOutputStream(),true);
+		InputPort 	newin=new InputPort(new BufferedReader(
+			new InputStreamReader(call.getInputStream())));
+
+
+ 		oldout.println("... starting new remote REPL.");
+ 		newout.println("Welcome to remote JVM - Type Ctrl-D to terminate session.");
+
+		// would like to replace System.err and System.out
+		// with multicast streams
+		evaluator.setOutput(newout);
+		evaluator.setError(newout);
+
+		try {
+			evaluator.readEvalWriteLoop("remote> ");
+/* Old version, can't work with jscheme 7.2
+			Object x;
+			while (!Scheme.EXIT) {
+				try {
+					newout.print("remote> "); newout.flush();
+					if ((x = newin.read()) == InputPort.EOF) break;
+					U.write(evaluator.eval(x), newout, true);
+					newout.println(); newout.flush();
+				} catch (Throwable e) { e.printStackTrace(newout); newout.flush(); }
+			}
+*/
+			// try to let the other end know that the show's over
+			call.shutdownInput();
+		}
+		finally {
+ 			newout.println("Remote session terminated.");
+	 		oldout.println("... remote REPL terminated.");
+			evaluator.setOutput(oldout);
+			evaluator.setError(olderr);
+			evaluator.setExit(false); // remote session not allowed to terminate JVM!
+			call.close(); // ?? or shutdownOutput();
+		}
+  	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/AnonymousTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+public abstract class AnonymousTask implements Task, java.io.Serializable
+{
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ArrayImageSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,42 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import  java.awt.image.*;
+
+public class ArrayImageSource extends ImageSourceBase
+{
+	double		array[];
+	byte			buf[];
+
+	public ArrayImageSource( double A[]) { this(A,A.length,1); }
+	public ArrayImageSource( double A[], boolean vertical) { this(A,1,A.length); }
+	public ArrayImageSource( double A[], int w, int h)
+	{
+		array		= A;
+		width		= w;
+		height	= h;
+		buf		= new byte[A.length];
+	}
+
+	protected int getHints() {
+		return  ImageConsumer.TOPDOWNLEFTRIGHT 
+				| ImageConsumer.COMPLETESCANLINES
+				| ImageConsumer.SINGLEPASS;
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{	
+		int i;
+		for (i=0; i<array.length; i++) {
+			buf[i] = (byte)map.clipInt(array[i]);
+		}
+		ic.setPixels(0, 0, width, height, model, buf, 0, width);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ArrayVImageSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import  java.awt.image.*;
+
+public class ArrayVImageSource extends ImageSourceBase
+{
+	double		array[];
+	byte			buf[];
+
+	public ArrayVImageSource( double A[])
+	{
+		array		= A;
+		width		= 1;
+		height   = A.length;
+		buf		= new byte[A.length];
+	}
+
+	protected int getHints() {
+		return  ImageConsumer.TOPDOWNLEFTRIGHT 
+				| ImageConsumer.COMPLETESCANLINES
+				| ImageConsumer.SINGLEPASS;
+	}
+
+	protected void sendPixels(ImageConsumer ic)
+	{	
+		int i, j;
+		for (i=0,j=array.length-1; i<array.length; i++,j--) {
+			buf[i] = (byte)map.clipInt(array[j]);
+		}
+		ic.setPixels(0, 0, width, height, model, buf, 0, 1);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+/AnonymousTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ArrayImageSource.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ArrayVImageSource.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ColorRamp.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/CompoundTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ImageSourceBase.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ImageTrace.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ImageTraceBase.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ImageVTrace.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ImageViewer.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/NamedTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/NullTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Plotter.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/RThread.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/RateSchedule.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Renderer.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SafeTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/ScatterPlot.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SignalTrace.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SubrateTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/SwitchTask.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Task.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/TaskLoop.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/TaskTrigger.java.not/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/Trace.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/vec2.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/tools
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ColorRamp.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,114 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import java.awt.Color;
+import java.awt.image.ColorModel;
+import java.awt.image.IndexColorModel;
+
+/**
+	Objects of these class could be used directly,
+	but main purpose is to help construct an IndexColorModel
+	for an image
+ */
+
+public class ColorRamp implements java.io.Serializable
+{
+	private byte	r[], g[], b[], a[];
+	private int	size;
+	private	int	lasti;
+	private Color	lastc;
+
+
+	public ColorRamp(int sz) 
+	{ 
+		size=sz;
+		r=new byte[size]; 
+		g=new byte[size]; 
+		b=new byte[size]; 
+		a=new byte[size]; 
+	}
+
+	public Color getColor(int i) { 
+		int ir = ((int)r[i] & 0xff);
+		int ig = ((int)g[i] & 0xff);
+		int ib = ((int)b[i] & 0xff);
+		return new Color(ir,ig,ib); 
+	}
+
+	public Color[] getColorArray() {
+		Color[]	clut=new Color[size];
+		for (int i=0; i<size; i++) clut[i]=getColor(i);
+		return clut;
+	}
+	
+	public int   getSize() { return size; }
+	public IndexColorModel getColorModel() { 
+		return new IndexColorModel(8,size,r,g,b); 
+	}
+
+	public void set( int i, Color c) { set(i,c,1); }
+	public void set( int i, Color c, double alpha)
+	{ 
+		r[i]=(byte)c.getRed();
+		g[i]=(byte)c.getGreen();
+		b[i]=(byte)c.getBlue();
+		a[i]=clip(256.0*alpha);
+		lasti=i; lastc=c;
+	}
+
+	public void gradientTo( int i, Color c) { 
+		gradient(lasti,lastc,1.0,i,c,1.0);
+	}
+
+	public void gradient( Color c1, Color c2) { 
+		gradient(0,c1,1.0,size-1,c2,1.0);
+	}
+
+	public void gradient( Color c1, double a1, Color c2, double a2) { 
+		gradient(0,c1,a1,size-1,c2,a2); 
+	}
+
+	public void gradient( int i1, Color c1, int i2, Color c2) { 
+		gradient(i1,c1,1,i2,c2,1); 
+	}
+
+	public void gradient( int i1, Color c1, double a1, int i2, Color c2, double a2)
+	{
+		double	_a, _r, _g, _b;
+		double	da, dr, dg, db;
+		double	di;
+		int		i;
+
+		di = i2-i1-1;
+
+		_a = 256*a1; 			da = (256*a2-_a)/di;    
+		_r = c1.getRed(); 		dr = (c2.getRed()-_r)/di;    
+		_g = c1.getGreen(); 	dg = (c2.getGreen()-_g)/di;
+		_b = c1.getBlue(); 		db = (c2.getBlue()-_b)/di;  
+
+		for (i=i1; i<=i2; i++) {
+			a[i] = clip(_a);
+			r[i] = clip(_r);
+			g[i] = clip(_g);
+			b[i] = clip(_b);
+			_a+=da; _r+=dr; _g+=dg; _b+=db;
+		}
+
+		lasti=i2; lastc=c2;
+	}
+
+	private static byte clip(double t)
+	{
+		if (t<0) return 0;
+		else if (t>=256.0) return (byte)255;
+		else return (byte)t;
+	}
+}
+	
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/CompoundTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,101 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+/**
+  *		This is a task that consists of a list of
+  *		sub tasks. The task is no more than the sum
+  *		of its subtasks -- ie there can be no extra
+  *		processing other than that done by the tasks
+  *		in the list. This is why the Task methods
+  *		are decalared <code>final</code>.
+  */
+
+public class CompoundTask implements Task
+{
+	private TaskLink head=null, tail=null;
+
+	public CompoundTask() {}
+	public CompoundTask(Task t) { addTask(t); }
+
+	public String toString() { return "CompoundTask"; }
+	
+	// task list implementation
+
+	public void addTask(Task t)
+	{
+		if (head==null) {
+			head=new TaskLink(t,null);
+			tail=head;
+		} else {
+			tail.next=new TaskLink(t,null);
+			tail=tail.next;
+		}
+	}
+
+	public void addTaskAfter(Task t, Task b)
+	{
+		if (head==null) addTask(t);
+		else if (b==null) head=new TaskLink(t,head);
+		else {
+			TaskLink q=head;
+			while (q!=null && q.task!=b) q=q.next;
+			if (q!=null) q.next=new TaskLink(t,q.next);
+			else addTask(t);
+		}
+	}
+
+	public void removeTask(Task t)
+	{
+		TaskLink prev=null;
+
+		for (TaskLink l=head; l!=null; prev=l, l=l.next) {
+			if (l.task==t) {
+				if (prev!=null) prev.next=l.next;
+				else head=l.next;
+				if (tail==l) tail=prev;
+			}
+		}
+	}
+
+	public Iterator iterator() { return new Iterator(); }
+
+	// Task implementation
+
+	public final void starting() {
+		for (TaskLink l=head; l!=null; l=l.next) l.task.starting();
+	}
+	public final void stopping() {
+		for (TaskLink l=head; l!=null; l=l.next) l.task.stopping();
+	}
+	public final void run() throws Exception {
+		for (TaskLink l=head; l!=null; l=l.next) l.task.run();
+	}
+	public void dispose() {
+		for (TaskLink l=head; l!=null; l=l.next) l.task.dispose();
+	}
+
+	// using a linked list for speed
+	private static class TaskLink {
+		Task		task;
+		TaskLink next;
+
+		TaskLink(Task t, TaskLink n) { task=t; next=n; }
+	}
+
+	// list iterator
+	public class Iterator implements java.util.Iterator {
+		TaskLink	l=head;
+		public final boolean more() { return l!=null; }
+		public final boolean hasNext() { return l!=null; }
+		public final Task		next() { Task t=l.task; l=l.next; return t; }
+		public final void    remove() { l.task=l.next.task; l.next=l.next.next; }
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ImageSourceBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,99 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import samer.core.*;
+import samer.core.util.*;
+import java.awt.image.*;
+import java.awt.Color;
+import java.util.*;
+
+import java.util.Hashtable;
+
+/**
+		<p>
+		Base class for image producers. Derived classes
+		must do the following:
+		<ul>
+			<li>	set width and height <b>before<b> any
+					consumers are added
+			<li>  implement getHints()
+			<li>	implement sendPixels(ImageConsumer)
+		</ul>
+
+ */
+
+public abstract class ImageSourceBase implements ImageProducer
+{
+	private		Hashtable			properties = new Hashtable();
+	private		Vector				consumers = new Vector();
+	protected	IndexColorModel	model = GREY;
+	protected	int					width, height;
+	protected	IMap					map = new LinearMap(model.getMapSize());
+
+	protected abstract int  getHints();
+	protected abstract void sendPixels(ImageConsumer ic);
+
+	public IMap	getMap() { return map; }
+	public void	setMap(IMap m) { map=m; m.setIntRange(model.getMapSize()); }
+
+	public int  getWidth() { return width; }
+	public int  getHeight() { return height; }
+	public void setColorModel(IndexColorModel cm) {
+		model=cm; map.setIntRange(model.getMapSize());
+
+		Enumeration cons = consumers.elements();
+		while (cons.hasMoreElements()) {
+    		ImageConsumer ic = (ImageConsumer)cons.nextElement();
+			ic.setColorModel(model);
+		}
+	}
+
+	public void startProduction(ImageConsumer ic) { addConsumer(ic); }
+	public void requestTopDownLeftRightResend(ImageConsumer ic) {}
+	public synchronized boolean isConsumer(ImageConsumer ic) { return consumers.contains(ic); }
+	public synchronized void removeConsumer(ImageConsumer ic) {	consumers.removeElement(ic); }
+	public synchronized void addConsumer(ImageConsumer ic)
+	{
+		if (consumers.contains(ic)) return;
+		consumers.addElement(ic);
+
+		try {
+			ic.setDimensions(width, height);
+			ic.setProperties(properties);
+			ic.setColorModel(model);
+			ic.setHints(getHints());
+			sendPixels(ic);
+			ic.imageComplete( ImageConsumer.SINGLEFRAMEDONE);
+		} catch (Exception e) {
+			ic.imageComplete(ImageConsumer.IMAGEERROR);
+		}
+	}
+
+
+	public void sendPixels()
+	{
+		Enumeration cons = consumers.elements();
+		while (cons.hasMoreElements()) {
+    		ImageConsumer ic = (ImageConsumer)cons.nextElement();
+			ic.setDimensions(width, height);
+			ic.setProperties(properties);
+			ic.setColorModel(model);
+			ic.setHints(getHints());
+			sendPixels(ic);
+			ic.imageComplete( ImageConsumer.SINGLEFRAMEDONE);
+		}
+	}
+
+	public static IndexColorModel	GREY,GREEN;
+	static {
+		ColorRamp	r = new ColorRamp(256);
+		r.gradient(Color.black,Color.white); GREY = r.getColorModel();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ImageTrace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,48 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import java.awt.*;
+import java.util.*;
+
+public class ImageTrace extends ImageTraceBase
+{
+	private	int		x=0;
+
+	public ImageTrace( ImageSourceBase i, Observable o) { super(i,o); }
+
+	public void next()
+	{ 
+		ip.sendPixels(); 
+
+		// make room for next image
+		if (scroll) while (x+sx>width) { 
+			graphics.copyArea(scrollStep,0,width-scrollStep,height,-scrollStep,0);
+			x-=scrollStep;
+		}
+		else if (x>=width) x=0; 
+
+		if (!sc) {
+			graphics.drawImage( img, x, 0, null);  
+		} else {
+			if (stretch) {
+				graphics.drawImage( img, x, 0, sx, height, null); 
+			} else {
+				graphics.drawImage( img, x, 0, sx, sy, null); 
+			}
+		}
+		getToolkit().sync();
+		
+		x+=sx;
+	}
+
+	public Dimension getPreferredSize() {
+		return new Dimension(cx*256,cy*ip.getHeight());
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ImageTraceBase.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,79 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+import java.awt.*;
+import java.util.*;
+import samer.core.*;
+import samer.core.util.*;
+
+public abstract class ImageTraceBase extends ImageViewer
+{
+	int		sx, sy;
+	int		scrollStep=1;
+	boolean	sc;
+	boolean	stretch=false;
+	boolean	scroll=false;
+
+	
+	ImageTraceBase( ImageSourceBase i, Observable o)
+	{
+		super(i,o);
+
+		setScroll(Shell.getBoolean("scroll",false));
+		setStretch(Shell.getBoolean("stretch",false));
+		setScrollStep(1);
+		setCellSize(cx,cy);
+	}
+
+	public void setScrollStep(int st) { scrollStep=st; }
+	public void setScroll(boolean f) { scroll=f; }
+	public void setStretch(boolean f) {
+		stretch = f;
+		sc = stretch || (cx!=1) || (cy!=1);
+	}
+
+	public void setCellSize( int a, int b) 
+	{ 
+		super.setCellSize(a,b);
+		sc = stretch || (cx!=1) || (cy!=1);
+		sx = cx*ip.getWidth();
+		sy = cy*ip.getHeight();
+	}
+
+	public void update( Graphics g) { clear(g); }
+	public void paint( Graphics g) { clear(g); }
+
+	public void getCommands(Agent.Registry r) {
+		super.getCommands(r); r.group();
+		r.add("scroll",scroll).add("stretch",stretch).add("cell.size");
+	}
+
+	public void execute(String cmd, Environment env)	throws Exception
+	{
+		if (cmd.equals("scroll")) {
+			setScroll(X._bool(env.datum(),!scroll));
+		} else if (cmd.equals("stretch")) {
+			setStretch(X._bool(env.datum(),!stretch));
+		} else if (cmd.equals("cell.size")) {
+			setCellSize(
+				X._int(env.datum("cell.width"),cx),
+				X._int(env.datum("cell.height"),cy)
+			);
+		} else super.execute(cmd,env);
+	}
+
+	public abstract void next();
+	
+	public void update(Observable o, Object oo) {
+		if (o==obs && oo!=Viewable.DISPOSING) next();
+		else super.update(o,oo);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ImageVTrace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,71 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import java.awt.*;
+import java.util.*;
+
+/**
+		Things to add:
+		UI for LinearMap used in MatrixImageSource
+		vertical and horizontal scaling:
+			cell size,
+			vertical stretch
+			vertical sweep version?
+			cooperate with MatrixImageSource for efficiency:
+			vertical strips rather than scan lines
+
+ */
+
+public class ImageVTrace extends ImageTraceBase
+{
+	private	int	y=0;
+
+	public ImageVTrace( ImageSourceBase i, Observable o) { super(i,o); }
+
+	public void next()
+	{ 
+		ip.sendPixels(); 
+
+		// img is m by n
+		
+		if (!sc) {
+			graphics.drawImage( img, 0, y, null);  
+		} else {
+			if (stretch) {
+				graphics.drawImage( img, 0, y, width, sy, null); 
+			} else {
+				graphics.drawImage( img, 0, y, sx, sy, null); 
+			}
+		}
+
+		// Scroll DOWN		
+		y-=sy;
+		if (scroll) while (y<0) { 
+			graphics.copyArea(0,0,width,height-scrollStep-1,0,scrollStep);
+			y+=scrollStep;
+		}
+		else if (y<0) y=height-1; 
+
+/*
+		// Scroll UP
+		y+=sy;
+		if (scroll) while (y>=height) { 
+			graphics.copyArea(0,scrollStep,width,height-1,0,-scrollStep);
+			y-=scrollStep;
+		}
+		else if (y>=height) y=0; 
+ */
+
+	}
+
+	public Dimension getPreferredSize() {
+		return new Dimension(cx*ip.getWidth(),cy*256);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ImageViewer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,135 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+import java.awt.*;
+import java.awt.image.*;
+import java.util.*;
+import samer.core.*;
+import samer.core.util.*;
+
+/**
+	A base class for displaying images of real values.
+	All that is needed is an ImageSource that implements
+	ImageSourceBase. The ImageViewer provides a VMap
+	for the IMap in the ImageSourceBase, and exposes the
+	VMaps commands in a popup menu.
+  */
+
+public class ImageViewer extends samer.core.util.heavy.VCanvas implements Observer, Agent
+{
+	protected ImageSourceBase	ip;
+	protected Image		img;
+	protected VMap		map;
+	protected Observable obs;
+	protected int			cx=1, cy=1, iw, ih;
+	private boolean		autoscale=false;
+
+	public ImageViewer( ImageSourceBase source, Observable o)
+	{
+		map = new VMap(source.getMap());
+		source.setMap(map.getMap());
+		source.setColorModel(
+			(IndexColorModel)Shell.datum("colormap")
+				.get(ColorModelCodec,ImageSourceBase.GREY));
+
+		ip	 = source; obs = o;
+		img = createImage(ip);
+		iw=img.getWidth(null);
+		ih=img.getHeight(null);
+
+		int cz=Shell.getInt("cell.size",4);
+		cx=Shell.getInt("cell.width",cz);
+		cy=Shell.getInt("cell.height",cz);
+
+		exposeCommands( this);
+		exposeCommands( map);
+		map.addObserver(this);
+	}
+
+	public void scale() {}
+	public void update(Observable o, Object s)
+	{
+		if (s==this) return;
+		else if (s==VMap.NEW_MAP) ip.setMap(map.getMap());
+		else if (s==Viewable.DISPOSING) {
+			if (o==obs) Shell.releaseViewer(this); return;
+		}
+
+		if (autoscale) scale();
+		ip.sendPixels();
+		if (s instanceof Point) {
+			Point p=(Point)s;
+			int x=(2*p.x*width+iw)/(2*iw);
+			int y=(2*p.y*height+ih)/(2*ih);
+			int w=(width+iw-1)/iw;
+			int h=(height+ih-1)/ih;
+			y=height-y-h;
+			repaint(0,x,y,w,h);
+		} else repaint(0,0,0,width,height);
+	}
+
+	public void attach() { super.attach(); if (obs!=null) obs.addObserver(this);	}
+	public void detach()	{ if (obs!=null) obs.deleteObserver(this); super.detach();	}
+
+	// .............. Agent bits ..............................
+
+	public void getCommands(Registry r)	{
+		r.add("scale").add("autoscale",autoscale).add("update");
+		r.group(); r.add("publish");
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if (c.equals("scale"))	{ scale(); update(null,null); }
+		else if	(c.equals("autoscale")) {
+			autoscale = X._bool(env.datum(),!autoscale);
+			if (autoscale) update(null,null);
+		} else if (c.equals("update")) { update(null,null); }
+		else if (c.equals("publish"))
+			Shell.put(X.string(env.datum(),"image"),this);
+	}
+
+	// .............. The rest ...............................
+
+	public VMap getVMap() { return map; }
+	public IMap getMap() { return ip.getMap(); }
+	public void setMap(IMap map) { ip.setMap(map); }
+	public void	setColorModel( IndexColorModel cm) {
+		ip.setColorModel(cm);
+		ip.sendPixels();
+		repaint();
+	}
+
+	public void update(Graphics g) {
+		g.drawImage( img, 0, 0, width, height, null);
+	}
+
+	public void paint( Graphics g) {
+		g.drawImage( img, 0, 0, width, height, null);
+	}
+
+	public void setCellSize( int w, int h) { cx=w; cy=h; }
+	public Dimension getPreferredSize() {
+		return new Dimension(cx*ip.width,cy*ip.height);
+	}
+
+	public static Environment.Codec ColorModelCodec = new Environment.Codec()
+	{
+		public Class targetClass() { return IndexColorModel.class; }
+
+		public String string(Object o) { return o.toString(); } // ??
+		public Object object(Object o) { return o; }
+		public Object decode(Object o) {
+			if (o instanceof IndexColorModel) return o;
+			return Shell.datum(o.toString()).get(this,null);
+		}
+	};
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/NamedTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,29 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.tools;
+import	samer.core.*;
+
+/**
+	A Task that has a Node.
+ */
+public abstract class NamedTask extends AnonymousTask implements java.io.Serializable
+{
+	protected Node	node;
+
+	protected NamedTask() {}
+	public NamedTask(Node node) { this.node = node; }
+	public NamedTask(String name, Node parent) {	this (new Node(name, parent)); }
+	public NamedTask(String name) { this(new Node(name));	}
+	public void dispose() { }
+
+	public Node getNode() { return node; }
+	public String toString() { return "Task:"+node; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/NullTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,18 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+public class NullTask implements SafeTask, java.io.Serializable
+{
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+	public void run() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/Plotter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,291 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import  samer.core.*;
+import  samer.core.util.*;
+import  java.awt.*;
+
+/**
+	<p>
+	A Plotter object is a Canvas with its own Graphics
+	(ie a GCanvas) which has two LinearMaps
+	to map a portion of 2d space to the window.
+	It can optionally draw the X and Y axes.
+
+	<p>
+	The inner class Pen provides access to drawing
+	functions in the real-valued coordinate space.
+ */
+
+public class Plotter extends samer.core.util.heavy.VCanvas
+{
+	/** for passing to setAxes(int) */
+	public static final int NEITHER = 0;
+	public static final int YAXIS = 2;
+	public static final int XAXIS = 1;
+	public static final int BOTH = 3;
+	public IMap	xmap, ymap;
+	
+	int			axesFlags=BOTH;
+	Color		axesColor;
+
+	/** 
+		Default constructor makes Plotter with both axes
+		drawn, in grey. LinearMaps take their default 
+		setup.
+		
+		@see samer.core.util.LinearMap
+	 */
+
+	public Plotter()
+	{
+		xmap = new LinearMap();
+		ymap = new LinearMap();
+
+		axesColor=Shell.getColor("axesColor",Color.gray);
+	}
+
+	public void exposeMaps() {
+		exposeCommands(new VMap(xmap));
+		exposeCommands(new VMap(ymap));
+	}
+
+	protected void sized() {
+		// make sure maps map to whole window
+		xmap.setIntRange(width);
+		ymap.setIntRange(height);
+	}
+
+	public Dimension getPreferredSize() { return new Dimension(256,256); }
+
+	/** use one of NONE, XAXIS, YAXIS or BOTH */
+	public void setAxes(int f) { axesFlags=f; }
+	public void setAxesColor(Color c) { axesColor=c; }
+
+	/** not really for public use */
+	public void drawAxes(Graphics g)
+	{ 
+		if (axesFlags!=0) {
+			g.setColor(axesColor);
+			
+			if ((axesFlags&XAXIS)!=0) {
+				int oy = height-ymap.toInt(0.0);
+				if (!ymap.wasClipped()) g.drawLine(0,oy,width-1,oy);
+			}
+
+			if ((axesFlags&YAXIS)!=0) {
+				int ox = xmap.toInt(0.0);
+				if (!xmap.wasClipped()) g.drawLine(ox,0,ox,height-1);
+			}
+
+			g.setColor(getForeground());
+		}
+	}
+
+	public void clear(Graphics g) { super.clear(g); drawAxes(g); }
+	public void paint(Graphics g) { Tools.initGraphics(g); drawAxes(g); }
+
+	/** return a new Pen for this Plotter */
+	public Pen	getPen() { return new Pen(graphics); }
+	public Pen	getPen(Graphics g) { return new Pen(g); }
+
+	// ----- drawing tools -------
+
+	/**
+		<p>
+		This class provides a state based plotting
+		environment (slightly inspired by Postscripts
+		crazy reverse polish). There is are <i>two</i>
+		current points: one for general use and another
+		which serves as the other point for lines,
+		rectangles and ellipses.
+
+		<p>
+		The primary current point can be set in absolute
+		coordinates using <code>abs(x,y)</code> or 
+		moved relatively using <code>rel(dx,dy)</code>.
+		The folling functions use <i>only</i> the primary 
+		current point:
+		<ul>
+			<li> <code>marker()</code>;
+			<li> <code>pixel()</code>;
+			<li> <code>blob()</code>.
+		</ul>
+		Calling <code>move()</code> copies the the location
+		of the primary current point to the secondary 
+		current point. The following functions use both
+		the current points:
+		<ul>
+			<li> <code>line()</code>: line between both points;
+			<li> <code>rect()</code>: empty rectangle bounding both points 
+			<li> <code>fillRect()</code>;
+			<li> <code>fill3DRect(boolean inOrOut)</code>;
+			<li> <code>ellipse()</code>;
+			<li> <code>fillEllipse()</code>.
+		</ul>
+		<p>
+		Some of the rectangle drawing commands
+		only work if the primary current point is below
+		and to the right (on the screen, that is) of the
+		secondary. The <code>rectify</code> function
+		swaps coordinates between the two points to make
+		it so. It will screw up any line drawing though.
+
+ */
+		
+	public class Pen
+	{
+		Graphics			graphics;
+		public Point		p0=new Point(); // secondary
+		public Point		p1=new Point(); // primary
+		vec2				r=new vec2(0,0);
+		int					moff=3, msz=moff*2;	// marker size
+		int					ix, iy;							// blob image hotspot
+		Color				col=getForeground();		// current colour
+		Image			blobImg;						// drawn by blob()
+
+		/**
+			<p>
+			A program can have several Pens, each with different
+			colours, but the underlying Graphics has a
+			single current Color. So, if you have multiple Pens,
+			each pen must <code>activate()</code> its colour
+			before drawing anything.
+		 */
+
+		public Pen(Graphics g) { graphics=g; }
+		final public Pen  activate() { graphics.setColor(col); return this; }
+		final public Pen  setColor(Color c) { col=c; graphics.setColor(c); return this; }
+		final public void setMarkerSize(int r) { moff=r; msz=2*r; }
+
+		/** returns true if the last primary current point was clipped */
+		public final boolean clipped() { return xmap.wasClipped() | ymap.wasClipped(); }
+		public final Pen abs( double x, double y) { r.x=x; r.y=y; map(); return this; }
+		public final Pen rel( double x, double y) { r.x+=x; r.y+=y; map(); return this; }
+
+		/** copies position of given pen to primary current point */
+		public final Pen set( Pen p) { r.x=p.r.x; r.y=p.r.y; p1.x=p.p1.x; p1.y=p.p1.y; return this; }
+		public final Pen move() { p0.x=p1.x; p0.y=p1.y; return this; }
+		public final Pen line() {
+			graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
+			return this;
+		}
+
+		public Pen rect() { 
+			graphics.drawRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
+			return this;
+		}
+
+		public Pen fillRect() { 
+			graphics.fillRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
+			return this;
+		}
+
+		/** this swaps xs and ys to make sure rectangles work */
+		public Pen rectify() {
+			if (p1.y<p0.y)	{ int tmp=p0.y; p0.y=p1.y; p1.y=tmp; }
+			if (p1.x<p0.x)	{ int tmp=p0.x; p0.x=p1.x; p1.x=tmp;	}
+			return this;
+		}
+
+		public Pen fill3DRect(boolean outin) {
+			if (p1.y!=p0.y) { // goes wrong otherwise
+				graphics.fill3DRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y,outin);
+			}
+			return this;
+		}
+
+		public Pen ellipse() { 
+			graphics.drawOval(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
+			return this;
+		}
+
+		public Pen fillEllipse() {
+			graphics.fillOval(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
+			return this;
+		}
+
+		public Pen marker() {
+			// graphics.drawOval(p1.x-moff,p1.y-moff,msz,msz);
+			graphics.fillRect(p1.x-moff,p1.y-moff,msz+1,msz+1);
+			// graphics.drawRect(p1.x-moff,p1.y-moff,msz,msz);
+			return this;
+		}
+
+		/** pixel drawn as 1x1 filled rectangle */
+		public Pen pixel() {
+			graphics.fillRect(p1.x,p1.y,1,1);
+			return this;
+		}
+
+		private Pen map() {
+			p1.x=xmap.toInt(r.x);
+			p1.y=ymap.toInt(r.y);
+//			if (xmap.wasClipped()) {
+//				if (p1.x<-16000) p1.x=-16000; else p1.x=16000;
+//			}
+			if (ymap.wasClipped()) {
+				if (p1.y<-32000) p1.y=32000;
+				else if (p1.y>32000) p1.y=-32000;
+				else p1.y=height-p1.y;
+			} else p1.y=height-p1.y;
+			return this;
+		}
+
+		/* These last three functions are here to speed up 
+		   two common operations: 
+
+				moveto(x,y) is exactly equivalent to abs(x,y).map().move();
+				lineto(x,y) is exactly equivalent to abs(x,y).map().line().move();
+				lineto(x,y) is exactly equivalent to line().move() ;
+		 */
+
+		public final Pen lineto() 
+		{ 
+			graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
+			p0.x=p1.x; p0.y=p1.y; 
+			return this;
+		}
+
+		public final Pen lineto(double x, double y) 
+		{ 
+			r.x=x; r.y=y; map();
+			graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
+			p0.x=p1.x; p0.y=p1.y; 
+			return this;
+		}
+
+		// this is exactly equivalent to abs(x,y).map().move();
+		public final Pen moveto(double x, double y) 
+		{ 
+			r.x=x; r.y=y; map();
+			p0.x=p1.x; p0.y=p1.y; 
+			return this;
+		}
+
+		/** draws the current blob image at the current point */
+		public Pen blob() { 
+			graphics.drawImage(blobImg,ix+p1.x,iy+p1.y,null); 
+			return this; 
+		}
+		
+		/** sets the blob image to be pixel of a given colour */	
+		public void setBlobColor(Color col) {
+			blobImg=createPixel(col); 
+		}
+
+		/** sets blob image to given image */
+		public void setBlobImage(Image i) { blobImg=i; ix=0; iy=0; }
+
+		/** sets blob image with given hotspot */
+		public void setBlobImage(Image i, int xhot, int yhot) { blobImg=i; ix=-xhot; iy=-yhot; }
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/RThread.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,336 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+import samer.core.*;
+import samer.core.util.*;
+import samer.core.types.*;
+import java.util.*;
+
+/** frame rate regulator */
+
+public class RThread extends Viewable implements Agent, Runnable
+{
+	Task		task, termhook;
+	Thread	thread;
+	int			prio;
+	boolean	running;
+	int			numloops=0;
+
+	int			N=10, count;
+	long		t0, elapsed, iterations;
+	boolean	regulated=true;
+	VDouble	target;			// target frame rate
+	double		actual;			// actual frame rate
+	long		period, wakeTime,nanos;
+
+	private volatile boolean paused=false;
+	private volatile boolean kill=false;
+
+
+	// .....Constructors................................
+
+	public RThread() { this(new NullTask()); }
+	public RThread(Task r)
+	{
+		super("regulator");
+
+		Shell.push(node);
+		target = new VDouble("target",50,0);
+		regulated = Shell.getBoolean("regulated",regulated);
+		setPriority(Shell.getDouble("thread.priority",-0.25));
+		Shell.pop();
+
+		setN(actual=target.value);
+		setPeriod();
+		setAgent(this);
+
+		task=r; termhook=null;
+		thread=new Thread(this);
+		thread.setPriority(prio);
+		running=false;
+
+		Shell.registerAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public Task onFinish(Task t) { Task old=termhook; termhook=t; return old; }
+	public Viewer	getViewer() { return new UI(); }
+
+	public void dispose()
+	{
+		Shell.deregisterAgent(this);
+		Shell.deregisterViewable(this);
+		target.dispose();
+		super.dispose();
+	}
+
+	public Task getTask() { return task; }
+	public void setTask(Task t) { task=t; }
+	
+	public class Kill extends Exception {}
+
+	public void interrupt() { thread.interrupt(); }
+	public void join() {
+		try { thread.join(); }
+		catch (InterruptedException ex) {}
+	}
+
+	public void start() { start(0); }
+	public void start(int n)
+	{
+		paused=false; kill=false;
+		numloops=n;
+		reset();
+		thread=new Thread(this);
+		thread.setPriority(prio);
+		thread.start();
+	}
+
+	/**	<b>Important:</b> this method BLOCKS until the
+	  *	thread co-operatively terminates, either naturally
+	  *	or by not handling the InterruptedException that
+	  *	will be thrown by the <code>checkpoint()</code> method
+	  *	the next time it is called.
+	  */
+
+	public void kill()
+	{
+		if (!thread.isAlive()) return;
+
+		synchronized (this) {
+			kill=true;
+			paused=true;
+			thread.interrupt(); // this will interrupt sleep, wait etc
+		}
+		try { thread.join(5000); }
+		catch (Exception ex) {
+			Shell.trace("RThread.kill failed: "+ex);
+		}
+	}
+
+
+	public void setPriority(double p)
+	{
+		Shell.trace("thread priority is "+p);
+		if (p==0) { prio=Thread.NORM_PRIORITY; }
+		else if (p>0) {
+			prio=Thread.NORM_PRIORITY+(int)(p*(Thread.MAX_PRIORITY-Thread.NORM_PRIORITY));
+		} else {
+			prio=Thread.NORM_PRIORITY-(int)(p*(Thread.MIN_PRIORITY-Thread.NORM_PRIORITY));
+		}
+	}
+
+	public void pause() { paused=true; }
+	public void unpause() {
+		if (paused) synchronized (this) {
+			paused=false; notifyAll();
+		}
+	}
+
+	/**	This method blocks if the thread has been paused
+	  *	and throws an InterruptedException if the thread
+	  *	has been killed.
+	  */
+
+	public final void checkpoint() throws Kill
+	{
+		if (paused) synchronized (this) {
+			Shell.trace("pausing");
+			running=false; task.stopping();
+			if (kill) throw new Kill();
+			try { wait(); } catch (Exception ex) {}
+			if (kill) throw new Kill();
+			running=true; task.starting(); reset();
+			Shell.trace("unpausing");
+		}
+	}
+
+	public void run()
+	{
+		try {
+			Shell.trace("Regulator: init");
+			task.starting();
+			running=true;
+
+			try {
+				if (numloops==0) {
+					for (;;) {
+						task.run();
+						if (regulated) tick();
+						//if (regulated) synchronized (this) { wait(); }
+						if (++count>=N) { tock(); changed(); }
+						checkpoint();
+					}
+				} else {
+					int n=numloops;
+					numloops=0;
+					for (int i=0;i<n;i++) {
+						task.run();
+						if (regulated) tick();
+						//if (regulated) synchronized (this) { wait(); }
+						if (++count>=N) { tock(); changed(); }
+						checkpoint();
+					}
+					task.stopping();
+					tock(); changed();
+				}
+			}
+			catch (Kill ex) { throw ex; }
+			catch (Exception ex) { task.stopping(); throw ex; }
+			finally {
+				running=false;
+				Shell.trace("Regulator: term");
+				if (termhook!=null) {
+					Shell.trace("running termination hook");
+					try { termhook.run(); }
+					catch (Exception ex) { ex.printStackTrace(); }
+				}
+			}
+		}
+		catch (Kill ex) {
+			System.out.println("Regulator: thread killed");
+		}
+		catch (Exception ex) {
+			System.out.println("Regulator: "+ex);
+			ex.printStackTrace();
+		}
+	}
+
+	private final void tick() throws Exception {
+		long now=System.currentTimeMillis();
+		if (now<wakeTime) {
+			Thread.sleep(wakeTime-now);
+			wakeTime+=period;
+		} else wakeTime=now+period;
+	}
+
+	public double fps()				{ return actual; }
+	public double elapsedTime() { return elapsed/1000.0; }
+	public long iterations() 			{ return iterations; }
+	public void setRate( double r) { target.value=r; target.changed(); }
+	public void regulate() { regulated=true; setPeriod(); }
+	public void deregulate() { regulated=false; }
+
+	private void setPeriod() {
+		period=(long)(1000.0/target.value);
+		// double T=(1000.0/target.value);
+		// period = (long)T;
+		// nanos = (long)(1000000.0*(T-period));
+		// Shell.trace("period = "+period+"ms + "+nanos+"ns");
+	}
+
+	public void reset()
+	{
+		setPeriod();
+		count=0; setN(actual);
+		t0=System.currentTimeMillis();
+		wakeTime=t0+period;
+	}
+
+
+	public void tock()
+	{
+		long	t = System.currentTimeMillis();
+		long	dt = t-t0;
+
+		elapsed+=dt;
+		iterations+=count;
+		actual = (1000.0*count)/dt;
+		count = 0;	t0 = t;
+		setN(actual); // try to count for 2 seconds
+		setPeriod();
+	}
+
+	private void setN(double rate)
+	{
+		// set the number of iterations to time
+		// given a certain rate
+		N=(int)(2*rate); 	// try to count for 2 seconds
+		if (N==0) N=1;	// at least 1!
+	}
+
+	public void getCommands(Agent.Registry r) {
+		r.add("start").add("pause").add("kill").add("step");
+		r.add("zero"); // do we want this one here?
+	}
+
+	public void execute(String c, Environment env) throws Exception
+	{
+		if      (c.equals("start") || c.equals("resume")) { if (thread.isAlive()) unpause(); else start(); }
+		else if (c.equals("stop") || c.equals("pause"))  pause();
+		else if (c.equals("step")) {
+			if (!running) {
+				task.starting();
+				task.run();
+				task.stopping();
+			} else {
+				Shell.print("Cannot step while thread is running.");
+			}
+		} else if (c.equals("regulated")) {
+			regulated = X._bool(env.datum(),!regulated);
+			reset(); changed();
+		} else if (c.equals("zero")) {
+			tock();  elapsed=iterations=0; changed();
+		} else if (c.equals("tock")) { tock(); changed(); }
+		else if (c.equals("exit") || c.equals("kill")) {
+			Shell.trace("killing thread...");
+			kill();
+			Shell.trace("thread killed.");
+		}
+	}
+
+	class UI extends BaseViewer
+	{
+		NumberViewer	actualRate=Shell.createNumberViewer("Actual rate",NumberViewer.TEXT);
+		NumberViewer	elapsedTime=Shell.createNumberViewer("Elapsed time",NumberViewer.TEXT);
+		NumberViewer	iterationCount=Shell.createNumberViewer("Iterations",NumberViewer.TEXT);
+		Viewer			targetViewer;
+		VBoolean		reg;
+
+		UI()
+		{
+			super(RThread.this);
+			setLayout( new StackLayout(2));
+			panel().setName(getLabel());
+
+			targetViewer = target.getViewer();
+			reg = new VBoolean("regulated",regulated,0);
+			reg.addObserver(this);
+
+			add( targetViewer.getComponent());
+			add( actualRate.getComponent());
+			add( elapsedTime.getComponent());
+			add( iterationCount.getComponent());
+			add( reg.getViewer().getComponent());
+
+			panel().add(Shell.createButtonsFor(RThread.this));
+		}
+
+		public void attach() { targetViewer.attach(); super.attach(); }
+		public void detach() {	targetViewer.detach(); super.detach(); }
+
+		public void update(Observable o, Object src)
+		{
+			if (reg==o && src!=this) {
+				regulated = reg.value;	setPeriod();
+			}
+			if (reg.value!=regulated) {
+				reg.value=regulated; reg.changed(this);
+			}
+
+			actualRate.set((int)actual);
+			elapsedTime.set((double)(elapsed/1000.0));
+			iterationCount.set((int)(iterations));
+			super.update(o,src);
+		}
+
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/RateSchedule.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+package samer.tools;
+
+import samer.core.types.*;
+import samer.core.*;
+
+public class RateSchedule extends AnonymousTask {
+	VDouble	rate,dec;
+	
+	public void setRatio(double r) { dec.set(1-r); }
+	public void setCount(double n) { dec.set(1/(n+1)); }
+	
+	public RateSchedule(VDouble rate) {
+		this.rate=rate;	
+		Shell.push(rate.getNode());
+		this.dec=new VDouble("relative dec",0.01);
+		Shell.pop();
+		// setCount(n); 
+	}
+
+	public void dispose() { dec.dispose(); super.dispose(); }
+	public void run() {
+		// rate.value*=n/(1+n); n+=1;
+		double d=dec.value;
+		if (d>=1) d=1; else if (d<0) d=0;
+		rate.value -= rate.value*d; // /(++n);
+		dec.value/=1+d;
+		dec.set(d/(1+d));
+		rate.changed();
+	}
+}
+
+// note to self: add agent to rate viewable.
+// need linked list of Agents -- DoubleAgent?!
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/Renderer.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+package samer.tools;
+
+import samer.core.util.*;
+import java.awt.*;
+
+public interface Renderer {
+	public void draw( Graphics g, int x1, int x2, int j1, int j2, int j0);
+
+	class Line implements Renderer {
+		public void draw( Graphics g, int x1, int x2, int j1, int j2, int j0) {
+			g.drawLine(x1,j1,x2,j2);
+		}
+	}
+
+	class Fill implements Renderer {
+		public void draw( Graphics g, int x1, int x2, int j1, int j2, int j0) {
+			if (j2>j0) g.fillRect(x1,j0,x2-x1,j2-j0);
+			else g.fillRect(x1,j2,x2-x1,j0-j2);
+		}
+	}
+
+	class Fill3D implements Renderer {
+		public void draw( Graphics g, int x1, int x2, int j1, int j2, int j0) {
+			// need to make sure rectangle is the right way up
+			if (j2>j0) g.fill3DRect(x1,j0,x2-x1,j2-j0,true);
+			else g.fill3DRect(x1,j2,x2-x1,j0-j2,true);
+		}
+	}
+
+	class Steps implements Renderer {
+		public void draw( Graphics g, int x1, int x2, int j1, int j2, int j0) {
+			g.drawLine(x1,j1,x1,j2);
+			g.drawLine(x1,j2,x2,j2);
+		}
+	}
+	public final static Renderer LINE=new Line();
+	public final static Renderer FILL=new Fill();
+	public final static Renderer FILL3D=new Fill3D();
+	public final static Renderer STEPS=new Steps();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/SafeTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+/**
+	An interface meant to represent processing that
+	needs to be done repeatedly in a loop. The task is to
+	be notified whenever the loop is started or stopped.
+ */
+
+public interface SafeTask extends Task
+{
+	void run();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/ScatterPlot.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,96 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+//import samer.maths.*;
+import java.util.*;
+import java.awt.*;
+
+/**
+	Builds up a 2D joint histogram of 2 elements of a vector.
+*/
+
+public class ScatterPlot extends Plotter implements Observer {
+	public VDouble alpha, fade,marksz;
+	Pen		pen;
+	Color		fader;
+	
+	public ScatterPlot()
+	{
+		exposeMaps();
+		
+		alpha=new VDouble("alpha",0.1);
+		fade=new VDouble("fade",0.02);
+		marksz=new VDouble("blob",2);
+		marksz.addObserver(this);
+		fade.addObserver(this);
+		alpha.addObserver(this);
+		fader=VColor.withAlpha(getBackground(),fade.value);
+		setForeground(VColor.withAlpha(getForeground(),alpha.value));
+	}
+
+	public void update(Graphics g) { Shell.print("update"); }
+	public void paint(Graphics g) {
+		Shell.print("paint");
+		g.setColor(VColor.withAlpha(getForeground(),255));
+		g.fillRect(0,0,width,height);
+	}
+	
+	public void dispose() {
+		alpha.dispose();
+		fade.dispose();
+		marksz.dispose();
+//		super.dispose();
+	}
+
+	public void plot(double x, double y) {
+		pen.abs(x,y).marker();
+	}
+
+	public void fade() {
+		graphics.setColor(fader);
+		graphics.fillRect(0,0,width,height);
+		graphics.setColor(getForeground());
+	}
+	
+	protected void sized()
+	{
+		super.sized();
+
+		Graphics2D	g2=(Graphics2D)graphics;
+		g2.setComposite(AlphaComposite.SrcOver);
+		g2.setPaint(getForeground());
+		pen=getPen(g2);
+		pen.setMarkerSize((int)marksz.value);
+	}
+
+	public void update(Observable o, Object a)
+	{
+		if (o==marksz) pen.setMarkerSize((int)marksz.value);
+		else if (o==fade) fader=VColor.withAlpha(getBackground(),fade.value);
+		else if (o==alpha) {
+			setForeground(VColor.withAlpha(getForeground(),alpha.value));
+		}
+	}
+/*
+	public Task vecTask(final Vec v, final int _i, final int _j) {
+		return new AnonymousTask() {
+			int		i=_i, j=_j;
+			double  [] x=v.array();
+			public void run() { plot(x[i],x[j]); }
+		};
+	}
+ */
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/SignalTrace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,53 @@
+/*
+ *	DoubleAgent.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.tools;
+import  samer.core.*;
+import  samer.core.types.*;
+import  java.util.*;
+import  java.awt.*;
+
+public class SignalTrace extends Trace
+{
+	VDouble		x;
+	Color			col;
+	Renderer		R;
+	int				oldj;
+
+	public SignalTrace(VDouble x) {
+		this.x=x;
+		col=Shell.getColor("color",getForeground());
+		R=(Renderer)Shell.get("renderer",Renderer.LINE);
+		oldj=-1;
+	}
+
+	public void run() {
+		super.run();
+		int j=height-map.toInt(x.value);
+		if (oldj<0) oldj=j;
+		graphics.setColor(col);
+		R.draw(graphics,x1,x2,oldj,j,j0);
+		oldj=j;
+	}
+	public void detach() { x.deleteObserver(this); }
+	public void update(Observable obs, Object arg) {
+		if (arg==Viewable.DISPOSING) { detach(); getParent().remove(this); }
+		else if (x==obs) run();
+		else super.update(obs,arg);
+	}
+
+	public void getCommands(Registry r) {	super.getCommands(r); r.add("renderer");	}
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("renderer")) R=(Renderer)Shell.get("renderer",Renderer.LINE);
+		else super.execute(cmd,env);
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/SubrateTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,45 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+/**
+  *		This is a task that runs a single child task
+  *		every N iterations, that is, at some integer
+  *      sub-multiple of the main loop rate
+  */
+
+public class SubrateTask implements Task, java.io.Serializable
+{
+	private Task	task;
+	private int		factor;	// subrate factor
+	private int		count;
+
+	protected SubrateTask() {}
+	public SubrateTask(int f) { factor=f; }
+	public SubrateTask(int f, Task t) { factor=f; task=t; count=factor; }
+
+	public int  getFactor() { return factor; }
+	public void setFactor(int f) {
+		factor=(f==0? 1 : f);	// at least 1
+		if (count>factor) count=factor; // cut short current batch
+	}
+
+	public void setTask(Task t) { task=t; }
+	public Task getTask() { return task; }
+
+	public final void starting() { task.starting(); count=factor; }
+	public final void stopping() { task.stopping(); }
+	public final void run() throws Exception {
+		if ((--count)<=0) { task.run(); count=factor; }
+	}
+
+	public void dispose() { task.dispose(); }
+	public String toString() { return "Subrate("+factor+"):"+task; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/SwitchTask.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,40 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import samer.core.types.*;
+
+/**
+  *		This is a task that runs a single child task
+  *		every N iterations, that is, at some integer
+  *      sub-multiple of the main loop rate
+  */
+
+public class SwitchTask implements Task
+{
+	private Task	task;
+	private VBoolean	enable;
+
+	public SwitchTask(Task t) { this(true,t); }
+	public SwitchTask(boolean e, Task t) { 
+		enable=new VBoolean("enable",e); 
+		enable.value=e; enable.changed(); task=t; 
+	}
+
+
+	public void enable() { enable.value=true; enable.changed(); }
+	public void disable() { enable.value=false; enable.changed(); }
+
+	public final void starting() { if (enable.value) task.starting(); }
+	public final void stopping() { if (enable.value) task.stopping(); }
+	public final void run() throws Exception { if (enable.value) task.run(); }
+
+	public void dispose() { task.dispose(); }
+	public String toString() { return "Switch("+enable.value+"):"+task; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/Task.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,24 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+/**
+	An interface meant to represent processing that
+	needs to be done repeatedly in a loop. The task is to
+	be notified whenever the loop is started or stopped.
+ */
+
+public interface Task
+{
+	void dispose();
+	void starting();
+	void stopping();
+	void run() throws Exception;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/TaskTrigger.java.not	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *	TaskTrigger.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS IS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package	samer.tools;
+import  samer.core.*;
+import  samer.core.util.*;
+import  samer.core.util.swing.Meter;
+import  samer.core.types.*;
+import  java.util.*;
+import  java.awt.*;
+
+	{
+		Task 			task;
+		Viewable			vbl;
+
+		SignalTrace(DoubleModel sig) {
+		}
+
+		public void detach() { task.dispose(); deleteObserver(this); }
+		public void update(Observable obs, Object arg) {
+			if (arg==Viewable.DISPOSING) { detach(); getParent().remove(this); }
+			else if (vbl==obs) run();
+			else super.update(obs,arg);
+		}
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/Trace.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,131 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+import  samer.core.*;
+import  samer.core.util.*;
+import  samer.core.util.heavy.*;
+import  java.awt.*;
+import  java.awt.event.*;
+import  java.awt.image.*;
+import  java.util.*;
+
+/**
+	Displays values of a single real variable as a
+	trace: value vs time. The trace can be set to scroll
+	or wrap when it reaches the right-hand edge.
+
+ */
+
+public class Trace extends VCanvas implements Observer, Agent, Task
+{
+	protected int		x1, x2, dx, j0=-1;
+	protected IMap	map;
+
+	boolean	scroll=false;
+	boolean	axisFlag;
+	Color		axisColor;
+	VMap		vmap;
+
+	public Trace()
+	{
+		dx = Shell.getInt("scrollStep",4);
+		scroll = Shell.getBoolean("scroll", false);
+		axisColor=Shell.getColor("axesColor",Color.gray);
+		axisFlag=Shell.getBoolean("axesFlag",false);
+
+		x1=0; x2=0;
+		vmap = new VMap(new LinearMap(-1,1));
+		vmap.addObserver(this);
+		exposeCommands(this);
+		exposeCommands(vmap);
+		map = vmap.getMap();
+	}
+
+	public IMap getMap() { return vmap.getMap(); }
+
+	public void setScroll(boolean f) { scroll=f; }
+	public void setStep(int s) { dx=s; }
+	public void setAxisColor(Color c) { axisColor=c; }
+	public void setAxis(boolean f) {
+		j0= -1; axisFlag=f; if (axisFlag) computeAxisPos();
+	}
+
+	public void drawAxis(Graphics g) 	{
+		g.setColor(axisColor);
+		g.drawLine(0,j0,width-1,j0);
+	}
+
+	public void paint(Graphics g) { if (j0>=0) drawAxis(g);	}
+	public void clear(Graphics g) { super.clear(g); paint(g); }
+
+	public void dispose() { vmap.dispose(); }
+	public void starting() {}
+	public void stopping() {}
+	/**
+		 moves the trace along one time step, by preparing
+		space for the next bit of plotting.
+	*/
+	public void run()
+	{
+		x1=x2; x2+=dx;
+		// graphics.setColor(getBackground());
+
+		if (x2>=width) {
+			if (scroll) { // scroll just enough
+				int st=1+x2-width;
+				graphics.copyArea(st,0,width-st,height,-st,0);
+				x1-=st; x2-=st;
+			} else { // fly back
+				// blank out dead space at right
+     				// and also first column of pixels at left
+				graphics.clearRect(x1+1,0,width-x1-1,height);
+				graphics.clearRect(0,0,1,height);
+				x1=0; x2=dx;
+			}
+		}
+
+		// clear rectangle and draw axis
+		graphics.clearRect(x1+1,0,dx,height);
+		if (j0>=0) {
+			graphics.setColor(axisColor);
+			graphics.fillRect(x1,j0,dx+1,1);
+		}
+	}
+
+
+	public void update(Observable o, Object arg)
+	{
+		if (o==vmap) {
+			if (arg==VMap.NEW_MAP) map=vmap.getMap();
+			if (axisFlag) computeAxisPos();
+			clear(getGraphics());
+		}
+  	}
+
+	public Dimension getPreferredSize() { return new Dimension(256,64); }
+	protected void sized() {
+		map.setIntRange(height);
+		if (axisFlag) computeAxisPos();
+	}
+
+	public void getCommands(Registry r) {
+		r.add("scroll",scroll).add("axis",axisFlag).add("step");
+	}
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("scroll")) { scroll = X._bool(env.datum(),!scroll); }
+		else if (cmd.equals("axis")) { setAxis(X._bool(env.datum(),!axisFlag));	}
+		else if (cmd.equals("step")) { dx = X._int(env.datum(),dx); }
+	}
+
+	private void computeAxisPos() {
+		j0 = height-map.toInt(0.0);
+		if (map.wasClipped()) j0=-1;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/tools/vec2.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,35 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.tools;
+
+public class vec2 implements java.io.Serializable {
+   public double x, y;
+
+   public double norm()        { return x*x+y*y; }
+   public vec2 neg()           { return new vec2(-x,-y); }
+   public void add( vec2 a)    { x+=a.x; y+=a.y; }
+   public void sub( vec2 a)    { x-=a.x; y-=a.y; }
+   public void mul( double k)  { x*=k; y*=k; }
+   public void div( double k)  { x/=k; y/=k; }
+   public void assign( vec2 a) { x=a.x; y=a.y; }
+   public void assign( double i, double j) { x=i; y=j; }
+   public void normalise()     { div( Math.sqrt(norm())); }
+
+   public static vec2 add( vec2 a, vec2 b)   { return new vec2(a.x+b.x,a.y+b.y); }
+   public static vec2 sub( vec2 a, vec2 b)   { return new vec2(a.x-b.x,a.y-b.y); }
+   public static vec2 div( vec2 a, double k) { return new vec2(a.x/k,a.y/k); }
+   public static vec2 mul( vec2 a, double k) { return new vec2(a.x*k,a.y*k); }
+   public static vec2 mul( double k, vec2 a) { return new vec2(a.x*k,a.y*k); }
+   public static double dot( vec2 a, vec2 b) { return a.x*b.x + a.y*b.y; }
+
+   public vec2()        {}
+   public vec2( vec2 a) { x=a.x; y=a.y; }
+   public vec2( double i, double j) { x=i; y=j; }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/CVS/Entries	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,38 @@
+/Clicker.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/DoubleToStream.java/1.1.1.1/Fri Dec 10 03:29:30 2004//
+/DoubleWriter.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/EnergyOperator.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/FFT.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/FFTVector.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/FIRFilter.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Filter.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/FilterVector.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/FilteredGenerator.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/GenerateDouble.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/GenerateVector.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Histogram.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/IIRFilter.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/JointHistogram.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Latch.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/LineIn.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/LineOut.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Matrices.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/MousePosition.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/NoisyLinearSource.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/OnsetMap.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Oscillator.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/OverlapAndAdd.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/RescaledIFT.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/SignalWindow.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/SpectralFIR.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Stacker.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Stacker2.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/StreamToDouble.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/StreamToVec.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/SumFnVec.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Trigger.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/VecToDouble.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/VecToStream.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/VecWriter.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+/Wavetable.java/1.1.1.1/Fri Dec 10 03:29:31 2004//
+D
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/CVS/Repository	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+/cvsroot/jslab/src/samer/units
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/CVS/Root	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,1 @@
+:ext:samer@dspmac1.elec.qmul.ac.uk:/cvsroot
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Clicker.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	MatEditor.java	
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+
+/**
+	This is a mouse event handler that interprets mouse clicks
+	to edit a matrix. It assumes that it is handling mouse
+	events for a component the contains some representation of the 
+	matrix that is arranged in rows and columns, just like the
+	matrix itself (it doesn't have to be an image). The window
+	relative coordinates are simply mapped to a matrix element 
+	address.
+  */
+
+public class Clicker extends MouseAdapter 
+	implements MouseMotionListener // , Agent
+{
+	Component	canvas;
+	int				w, h;
+	VInteger		x, y;
+
+	public Clicker( Component c, int w, int h)
+	{
+		canvas=c;
+		canvas.addMouseListener(this);
+		canvas.addMouseMotionListener(this);
+		this.w=w;
+		this.h=h;
+		x=y=null;
+		// vwr.exposeCommands(this);
+	}
+
+	public void setXReceiver(VInteger x) { this.x=x; }
+	public void setYReceiver(VInteger y) { this.y=y; }
+	
+/*
+	public void getCommands(Agent.Registry r) { r.add("add",add); }
+	public void execute(String cmd, Environment env) {	
+		add=X._bool(env.datum(),!add); 
+	}
+*/
+	private void handle(MouseEvent e)
+	{
+		// get position in matrix
+		int i = (h*e.getY())/canvas.getHeight();
+		int j = (w*e.getX())/canvas.getWidth();
+		// Shell.print("click: "+i+","+j);
+		
+		// check bounds
+		if (i<0 || i>=h) return;
+		if (j<0 || j>=w) return;
+
+		// correct for vertical flip
+		i=h-i-1;
+
+		if (x!=null) x.set(j);
+		if (y!=null) y.set(i); 
+	}
+
+	public void mouseMoved(MouseEvent e) {}
+	public void mouseDragged(MouseEvent e) { handle(e); e.consume(); }
+	public void mousePressed(MouseEvent e) { handle(e); e.consume(); }	
+
+//	public void detach() { setto.dispose(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/DoubleToStream.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,51 @@
+//
+//  DoubleToStream.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+/**
+	Write sequence of doubles to a stream in binary format.
+*/
+
+public class DoubleToStream extends AnonymousTask {
+	DoubleModel	x;		// data to send
+	OutputStream	out;	// stream to write to
+	DataOutputStream	objout;
+	
+	public DoubleToStream(DoubleModel x, OutputStream out) throws Exception
+	{
+		this.x=x;
+		this.out=out;
+		objout=new DataOutputStream(out);
+	}
+
+	public void dispose() {
+		try {
+			objout.flush();
+			objout.close();
+		} catch (Exception ex) {}
+		// close out?
+	}
+
+	public Task getTask() { return this; }
+	
+	public void run()  throws Exception {
+		objout.writeFloat((float)x.get());
+		/* autoflush? */
+	}
+	public void stopping() {
+		try { objout.flush(); }
+		catch (Exception ex) {}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/DoubleWriter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+//
+//  DoubleWriter.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+/**
+	Write sequence of doubles to a stream as text
+ */
+
+public class DoubleWriter extends AnonymousTask {
+	DoubleModel	x;		// data to send
+	OutputStream	out;	// stream to write to
+	PrintStream		prn;
+
+	public DoubleWriter(DoubleModel x, OutputStream out) throws Exception { this(x,out,true); }
+	public DoubleWriter(DoubleModel x, OutputStream out, boolean autoflush) throws Exception
+	{
+		this.x=x;
+		this.out=out;
+		prn=new PrintStream(out,autoflush); // autoflush or not?
+	}
+
+	public void dispose() {
+		try {
+			prn.flush();
+			prn.close();
+		} catch (Exception ex) {}
+		// close out?
+	}
+
+	public Task getTask() { return this; }
+	
+	public void run()  throws Exception {
+		prn.println(x.get());
+		// how often should we flush?
+	}
+	public void stopping() {
+		try { prn.flush(); }
+		catch (Exception ex) {}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/EnergyOperator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,31 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+
+public class EnergyOperator implements Filter
+{
+	double	u1=0, u2=0;	// previous two values
+
+	public EnergyOperator()	{}
+
+	public void dispose() {}
+
+	public double filter( double u0)
+	{
+		double	y=u1*u1 - u0*u2; 
+		u2=u1; 
+		u1=u0;
+
+		return y;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FFT.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,192 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.maths.*; // uses ComplexVector and Vec
+
+/**
+  *	<h2>Fast Fourier Transform</h2>
+  *	<h4>by Samer Abdallah</h4>
+  *	<h4>15 December 1999</h4>
+  *
+  *	<p>
+  *	Mostly from my old C++ version, though I should credit the following
+  *	FFT code for the idea of using a lookup table for the bit reversal
+  *   and also a complete lookup table of sines:
+  *
+  *	<pre>
+  *	>	From the Unix Version 2.4 by Steve Sampson, Public Domain,
+  *	>	September 1988.
+  *	>	Adapted for Java by Ben Stoltz <stoltz@sun.com>, September 1997
+  *	>
+  *	>	Refer to http://www.neato.org/~ben/Fft.html for updates and related
+  *	>	resources.
+  *	</pre>
+  *
+  *	<p>
+  *	My old version computed the bit-reversed indices on the fly - silly
+  *	really - don't know why I didn't think of a lookup table myself.
+  *	Also, it had a lookup table of sines and cosines of the form
+  *	sin( 2*PI/k) with k going 1, 2, 4, 8 .. N. This version has complete
+  *	tables for sin and cosine - which is a bit of a waste of memory,
+  *	but frankly, who cares?
+  *
+  *	<h3>Usage</h3>
+  *	<p>
+  *	It is the user's responsibility to fill the arrays real
+  *   and imag with data IN THE CORRECT BITREVERSED ORDER. This
+  *	is easy enough using the bitrev lookup table - something like this
+  *	would do the trick:
+  *	<pre>
+  *		for (int i=0; i<N; i++) {
+  *			int k=fft.bitrev[i]
+  *			fft.real[k] = theRealData[i];
+  *			fft.imag[k] = 0;
+  *		}				
+  *	</pre>
+  *	The arrays are used destructively, so it is also the user's 
+  *	responsibility, eg, to reset the imaginary parts to zero even
+  *	if they are always zero.
+  *
+  *	<p>
+  *	The results ends up in the arrays real and imag
+  */
+
+
+public class FFT 
+{
+	public	int				bitrev[];	// lookup table
+	public	double			H[];			// window - not yet used internally
+	public	double			real[];			
+	public	double			imag[];			
+
+	protected	ComplexVector	W;				// sines and cosines lookup table
+	protected	int				N;
+	protected	double			zeros[];
+
+	public FFT( int n)
+	{
+		N=n;
+		real = new double[N];
+		imag = new double[N];
+		W = new ComplexVector(N);
+		bitrev = new int[N];
+		H = new double[N];
+
+		// calculate bit reversal lookup table
+		int m=N/2, j=0;
+		for (int i=0; i<n; i++) {
+			bitrev[i]=j;
+			int b;
+			for (b=m; (b>1) && (j>=b); b>>=1) j-=b;
+			j+=b; 
+		}
+
+		// calculate sines and cosines lookup
+		double th=2*Math.PI/N;
+		for (int i=0; i<n; i++) {
+			W.real[i] = Math.cos(i*th); 
+			W.imag[i] = Math.sin(i*th); 
+		}
+
+		// table of zeros for fast initialisation
+		zeros = new double[N];
+		for (int i=0; i<N; i++) zeros[i]=0.0;
+	}
+
+	public int size() { return N; }
+	public final void input( double Y[])
+	{
+		System.arraycopy(zeros,0,imag,0,N);
+		for (int i=0; i<N; i++) {
+			real[bitrev[i]] = H[i]*Y[i];
+		}
+	}				
+
+	public final void brevcopy( double src[], double dst[] )
+	{
+		for (int i=0; i<src.length; i++) {
+			dst[bitrev[i]] = src[i];
+		}
+	}				
+
+	public final void input( Vec.Iterator it)
+	{
+		System.arraycopy(zeros,0,imag,0,N);
+		for (int i=0; i<N; i++) {
+			real[bitrev[i]] = H[i]*it.next();
+		}
+	}				
+
+	public final void outputPower( double S[])
+	{
+		// extract power
+		for (int i=0; i<S.length; i++) {
+			S[i] = real[i]*real[i] + imag[i]*imag[i];
+		}
+	}
+
+	public final void calculate()
+	{
+		double	a1,a2,b1,b2;
+		int		step, jump, i, k;
+		int		m=N/2, p;
+		double	wReal, wImag;
+
+		// these are cached for performance -
+		// the COMPILER ought to be doing this!
+		double	Real[] = real;
+		double	Imag[] = imag;
+		double	wr[] = W.real;
+		double	wi[] = W.imag;
+
+		step=1; jump=2;
+		while (step<N) {
+
+			p = 0; 
+			for (k=0; k<step; k++) {
+
+				// look up exp( (2*PI*i/N)*p );
+				wReal = wr[p]; 
+				wImag = wi[p]; 
+				p+=m;
+
+				for (i=k; i<N; i+=jump) {
+
+					int j=i+step;
+
+					// complex butterfly between i and j
+					a1 = Real[i];
+					a2 = Imag[i];
+
+
+					b1 = wReal*Real[j] - wImag*Imag[j];
+					b2 = wImag*Real[j] + wReal*Imag[j];
+
+					Real[i] = a1 + b1;
+					Imag[i] = a2 + b2;
+					Real[j] = a1 - b1;
+					Imag[j] = a2 - b2;
+				}
+			}
+			step=jump; jump<<=1; m>>=1;
+		}
+	}
+
+	// make everything conjugate - does inverse fft
+	public void invert()	{
+		for (int i=0; i<W.length; i++) W.imag[i] = -W.imag[i];
+	}
+
+	// useful window functions
+	public void setWindow(Function fn) {
+		for (int i=0; i<N; i++) H[i] = (double)i/N;
+		fn.apply(H); Mathx.mul(H,1/Math.sqrt(N));
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FFTVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,108 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+import samer.functions.*;
+
+/**
+	Manages a fourier transform from a given Vec into
+	another vector. Can create tasks appropriate for
+	a power spectrum or an arbitrary function of a
+	power spectrum.
+  */
+
+public class FFTVector extends FFT implements Task
+{
+	Vec			in;
+
+	public FFTVector(Vec in) throws Exception { this(in.size()); setInput(in); }
+	public FFTVector(int N) throws Exception
+	{
+		super(N);
+
+		// setup window function
+		String window = Shell.getString("ft.window","hamming");
+		if (window.equals("rectangular")) setWindow(new Constant(1.0));
+		else if (window.equals("hanning")) setWindow(new Hanning());
+		else setWindow(new Hamming());
+	}
+
+	public void   setInput(Vec in) { this.in = in; }
+	public String toString() { return "FT("+in+")"; }
+	public Vec    real() { return new Vec.ForArray(real); }
+	public Vec    imag() { return new Vec.ForArray(imag); }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() { input(in.iterator()); calculate(); }
+	public void dispose() {}
+
+	public Task calcTask() {
+		if (in.array()!=null) {
+			return new AnonymousTask() {
+				double [] b=in.array();
+				public void run() throws Exception {
+					input(b); calculate();
+				}
+				public String toString() { return FFTVector.this.toString()+": compute"; }
+			};
+		} else return this;
+	}
+
+	public Task getPower(final VVector A)
+	{
+		final double [] a=A.array();
+		return new AnonymousTask() {
+			public void run() throws Exception	{
+				outputPower(a); A.changed();
+			}
+			public String toString() { return FFTVector.this.toString()+":power->"+A; }
+		};
+	}
+
+	public Task getFnPower(final Function f, final VVector A)
+	{
+		final double [] a=A.array();
+		return new AnonymousTask() {
+			public void run() throws Exception {
+				outputPower(a); f.apply(a);
+				A.changed();
+			}
+			public void dispose() { f.dispose(); super.dispose(); }
+			public String toString() {
+				return FFTVector.this.toString()+":"+f.format("power")+"->"+A;
+			}
+		};
+	}
+
+	public Task getLinearFT(final VVector A)
+	{
+		return new AnonymousTask() {
+			double[] a=A.array();
+
+			public void run() throws Exception
+			{
+				int i=1,j=1;
+				a[0]=real[0];
+				for (; i<N/2; i++) {
+					a[j++] = real[i];
+					a[j++] = imag[i];
+				}
+				a[j]=real[i];  // i=N/2, j=N-1 (I hope)
+				A.changed();
+			}
+			public String toString() { return FFTVector.this.toString()+"->"+A; }
+		};
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FIRFilter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+import  java.util.*;
+
+public class FIRFilter implements Filter
+{
+	int		N;			// order of filter
+	double	A[];	// coefficients
+	double	u[];		// circular buffer of previous values
+	int		k;    		// current position in u buffer
+
+	public FIRFilter( int n)
+	{
+		N=n;
+		u=new double[n];
+		A=new double[n];
+		reset();
+	}
+
+	public FIRFilter( double [] A)
+	{
+		N=A.length;
+		u=new double[N];
+		this.A=A;
+		reset();
+	}
+
+	public void dispose() {}
+	public void reset() { Mathx.zero(u); k=0; }
+
+	/** FIR filter using array of filter coefficients */
+	public final double filter( double z)
+	{
+		if (k==0) k=N-1; else k--;
+		double	y=0;
+		u[k]=z;
+
+		int i=0, j;
+		for (j=k; j<N; j++) y += u[j]*A[i++];
+		for (j=0; j<k; j++) y += u[j]*A[i++];
+
+		return y;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Filter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,6 @@
+package samer.units;
+
+public interface Filter {
+	double	filter(double x);
+	void		dispose();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FilterVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,64 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import samer.tools.*;
+
+public class FilterVector extends NamedTask
+{
+	VDouble			rate;
+	VVector			low, high;
+	double []		x, y, mu;
+	int					N;
+
+	public FilterVector( Vec input)
+	{
+		super("filter");
+		N=input.size();
+
+		Shell.push(node);
+		rate = new VDouble("rate",0.01);
+		high  = new VVector("highpass",N);
+		low = new VVector("lowpass",N);
+		Shell.pop();
+
+		x = input.array();
+		y = high.array();
+		mu= low.array();
+	}
+
+	public void dispose()
+	{
+		rate.dispose();
+		high.dispose();
+		low.dispose();
+		super.dispose();
+	}
+
+	public VVector highPass() { return high; }
+	public VVector lowPass() { return low; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()
+	{
+		double r=rate.value;
+		
+		for (int i=0; i<N; i++) mu[i] += r*(x[i]-mu[i]);
+		for (int i=0; i<N; i++) y[i] = x[i] - mu[i];
+		
+		low.changed();
+		high.changed();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/FilteredGenerator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+package	samer.units;
+import	samer.core.*;
+import	samer.core.types.*;
+import	samer.maths.*;
+import	java.util.*;
+
+public class FilteredGenerator implements Generator
+{
+	Generator	in;
+	Filter		f;
+
+	public FilteredGenerator(Generator in, Filter f) {
+		this.in=in;
+		this.f=f;
+	}
+
+	public void dispose() { in.dispose(); f.dispose(); }
+	public double next() { return f.filter(in.next()); }
+	public void next(double [] x)	{
+		for (int i=0; i<x.length; i++) x[i]=f.filter(in.next());
+	}
+
+	public String toString() { return "filter("+in+")"; }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/GenerateDouble.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+package	samer.units;
+import	samer.core.types.*;
+import	samer.tools.*;
+import	samer.maths.*;
+
+public class GenerateDouble extends AnonymousTask
+{
+	Generator	gen;
+	DoubleModel	dbl;
+
+	public GenerateDouble(DoubleModel out, Generator g) { dbl=out;	gen=g; }
+	public DoubleModel output() { return dbl; }
+	public void setGenerator(Generator g) { gen=g; }
+	public void run() { dbl.set(gen.next()); }
+
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/GenerateVector.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,22 @@
+package	samer.units;
+import	samer.tools.*;
+import	samer.maths.*;
+
+public class GenerateVector extends AnonymousTask
+{
+	Generator	gen;
+	VVector		vec;
+	double		out[];
+
+	public GenerateVector(VVector out, Generator g)
+	{
+		this.out=out.array();
+		vec=out;
+		gen=g;
+	}
+
+	public Vec	output() { return vec; }
+	public void setGenerator(Generator g) { gen=g; }
+	public void run() { gen.next(out); /* vec.changed(); */ }
+}
+		
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Histogram.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,193 @@
+/*
+ *	Histogram.java
+ *
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.core.Agent.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.util.*;
+
+/**
+	This actually builds several histograms in parallel: one
+	for each element of a Vec or double array.  A IMap provides
+	the mapping from element values to histogram bins.
+	The result is a <i>Matrix</i>, each <i>row</i> of which
+	is the histogram for the corresponding element of the
+	input vector.
+  */
+
+public class Histogram extends Viewable implements Task, Agent
+{
+	private Vec			input;
+	private Matrix			bins;
+	private VMap			map;
+	private double[][]	binArray;
+	private double[]		lbw; // log of bin widths
+	private VVector		L;
+	private VDouble		sumL;
+	private int				N, count;
+	private double[]		x;
+
+	public Histogram( Vec input, int binCount)
+	{
+		super("histogram");
+
+		Shell.push(getNode());
+
+		N = input.size();
+		Shell.setAutoRegister(false);
+		bins = new Matrix("bins",N,binCount);
+		map = new VMap(new LinearMap(binCount));
+		L = new VVector("likelihood",N);
+		sumL = new VDouble("sumL");
+		Shell.setAutoRegister(true);
+		count=0; x=input.array();
+		lbw = new double[binCount];
+		Shell.pop();
+
+		setAgent(this);
+		binArray = bins.getArray();
+		Shell.registerViewable(this);
+	}
+
+	public Matrix getBinMatrix() { return bins; }
+	public VVector getLikelihoodVector() { return L; }
+	public VDouble getLikelihoodSignal() { return sumL; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()
+	{
+		IMap	binmap=map.getMap();
+		double [] l=L.array();
+
+		if (x!=null) {
+			for(int k=0; k<N; k++) {
+				int j=binmap.clipInt(x[k]);
+				l[k] = -Math.log(++binArray[k][j]) + lbw[j];
+			}
+		} else {
+			Vec.Iterator i=input.iterator();
+			for(int k=0; i.more(); k++) {
+				int j=binmap.clipInt(i.next());
+				l[k] = -Math.log(++binArray[k][j]) + lbw[j];
+			}
+		}
+
+		count++;
+		Mathx.add(l,Math.log(count));
+		sumL.value=Mathx.sum(l);
+
+		L.changed();
+		sumL.changed();
+		bins.changed();
+	}
+
+	public void clear() { bins.zero(); bins.changed(); count=0; }
+	public double[] normalise() {
+		count=(int)Mathx.sum(binArray[0]);
+		Shell.print("Histogram: count="+count);
+		Shell.print("Computing bin widths...");
+		IMap	binmap=map.getMap();
+
+		for (int i=0; i<lbw.length; i++) {
+			lbw[i]=Math.log(binmap.inverseFromInt(i+1) - binmap.inverseFromInt(i));
+		}
+		return lbw;
+	}
+
+	public void dispose() {
+		bins.dispose();
+		map.dispose();
+		L.dispose();
+		super.dispose();
+	}
+
+	public Viewer getViewer() {
+		DefaultViewer vwr=new DefaultViewer(this);
+		vwr.add(bins.viewable());
+		vwr.add(L);
+		vwr.add(sumL);
+		return vwr;
+	}
+
+	public void getCommands(Registry r) {
+		r.add("clear").add("normalise");
+		r.group(); map.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("clear")) clear();
+		else if (cmd.equals("normalise")) normalise();
+		map.execute(cmd,env);
+	}
+
+	public Equaliser getEqualiser() { return new Equaliser(); }
+
+	/** This is a function which uses a cumulative probability function
+		derived from the histogram to compute a transformation that
+		results in a uniformly distributed variable. It takes a SNAPSHOT
+		of the current histogram map and bin counts. You must update()
+		to update from current histogram.
+		*/
+	public class Equaliser extends VectorFunctionOfVector
+	{
+		IMap	map;
+		int 	N, M;
+		Matrix	C;
+		double K;
+		double [][]P;
+
+		public Equaliser() {
+			N=bins.getRowDimension();
+			M=bins.getColumnDimension();
+			C=new Matrix("cumulative",N,M);
+			P=C.getArray();
+			update();
+		}
+
+		public void dispose() { C.dispose(); }
+		public void update() {
+			map=Histogram.this.map.getMap();
+			K=map.getIntRange();
+			for (int i=0; i<N; i++) {
+				double T=0;
+				for (int j=0; j<M; j++) {
+					P[i][j]=(T+=binArray[i][j]);
+				}
+				Mathx.mul(P[i],1/T);
+			}
+			C.changed();
+		}
+
+		public void apply(double [] x) { apply(x,x); }
+		public void apply(double[] x, double[] y) {
+			for (int i=0; i<N; i++) {
+				double z=K*map.map(x[i]);
+				int j=(int)z;
+				if (j<0) y[i]=0;
+				else if (j>=M) y[i]=1;
+				else {
+					// linearly interpolate 
+					double P1=P[i][j];
+					double P0=(j==0)? 0 : P[i][j-1];
+					double d=z-j;
+					y[i]=(1-d)*P0 + d*P1;
+				}
+			}
+		}
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/IIRFilter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+import  java.util.*;
+
+public class IIRFilter implements Filter
+{
+	int		N;		// order of filter
+	double	A[];	// coefficients
+	double	u[];	// circular buffer of previous values
+	int		k;    // current position in u buffer
+
+	public IIRFilter( int n)
+	{
+		N=n; 
+		u=new double[n];
+		A=new double[n+1];
+		reset();
+	}
+
+	public IIRFilter( double [] A)
+	{
+		N=A.length-1; 
+		u=new double[N];
+		this.A=A;
+		reset();
+	}
+
+	public void dispose() {}
+	public void reset() { Mathx.zero(u); k=0; }
+
+	/** FIR filter using array of filter coefficients */
+	public final double filter( double z)
+	{
+		double	y=z*A[0]; 
+
+		int i=1, j;
+		for (j=k; j<N; j++) y += u[j]*A[i++];
+		for (j=0; j<k; j++) y += u[j]*A[i++];
+
+		if (k==0) k=N-1; else k--;
+		u[k]=y; // store output value in buffer
+		return y;
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/JointHistogram.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,141 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.util.*;
+
+/**
+	Builds up a 2D joint histogram of 2 elements of a vector.
+*/
+
+public class JointHistogram extends Viewable implements Agent, Task, Observer {
+	VInteger		I1, I2;
+	VMap			vmap;
+	Matrix			bins;
+	IMap			map;
+	int				i1, i2;
+	double[]		xArray;
+	double[][]	binArray;
+	double[]		lbw;
+	VDouble		L;
+	int				count;
+
+	public JointHistogram(Vec x, int bins, int i1, int i2) {
+		this(x,bins);
+		I1.value=i1; I1.changed();
+		I2.value=i2; I2.changed();
+	}
+
+	public JointHistogram(Vec x, int M)
+	{
+		super("joint.histogram");
+
+		xArray=x.array();
+		if (xArray==null) throw new Error("vec array not accessible");
+
+		Shell.push(node);
+
+		// int M=Shell.getInt("bins",32);
+		int N=x.size();
+
+		Shell.setAutoRegister(false);
+		I1=new VInteger("i1",1);
+		I2=new VInteger("i2",2);
+		I1.setRange(0,N-1);
+		I2.setRange(0,N-1);
+
+		lbw = new double[M];
+		vmap=new VMap(new LinearMap(0,1,M)); // ??
+		bins = new Matrix("bins",M,M);
+		L = new VDouble("likelihood");
+		Shell.setAutoRegister(true);
+		Shell.pop();
+
+		binArray=bins.getArray();
+		I1.addObserver(this);
+		I2.addObserver(this);
+		vmap.addObserver(this);
+		update(vmap,VMap.NEW_MAP);
+		setAgent(this);
+		Shell.registerViewable(this);
+	}
+
+	public void clear() { count=0; bins.zero(); bins.changed(); }
+	public Matrix getBinMatrix() { return bins; }
+	public VDouble getLikelihoodSignal() { return L; }
+	public VMap getVMap() { return vmap; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()	{
+		int j=map.clipInt(xArray[i1]);
+		int k=map.clipInt(xArray[i2]);
+		L.value=-Math.log((++binArray[j][k])/(double)(++count)) + lbw[k] + lbw[j];
+		L.changed();
+		bins.changed();
+	}
+
+	public void dispose() {
+		I1.dispose();
+		I2.dispose();
+		bins.dispose();
+		L.dispose();
+	}
+
+	public void normalise() {
+		int n=binArray.length, c=0;
+		for (int i=0; i<n; i++) c+=(int)Mathx.sum(binArray[i]);
+		count=c;
+		Shell.print("JointHistogram: count="+count);
+ 	}
+
+	public void update(Observable o, Object a)
+	{
+		if (o==vmap) {
+			if (a==VMap.NEW_MAP) map=vmap.getMap();
+			for (int i=0; i<binArray.length; i++) {
+				lbw[i]=Math.log(map.inverseFromInt(i+1) - map.inverseFromInt(i));
+			}
+		} else {
+			i1=I1.value;
+			i2=I2.value;
+		}
+	}
+
+	public void getCommands(Registry r) {
+		r.add("clear").add("normalise");
+		r.group(); vmap.getCommands(r);
+	}
+
+	public void execute(String cmd, Environment env) throws Exception {
+		if (cmd.equals("clear")) clear();
+		else if (cmd.equals("normalise")) normalise();
+		vmap.execute(cmd,env);
+	}
+
+	public Viewer getViewer()
+	{
+		DefaultViewer vwr=new DefaultViewer(this);
+
+		vwr.add(I1);
+		vwr.add(I2);
+		vwr.add(bins.viewable());
+		vwr.add(L);
+
+		return vwr;
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Latch.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.util.*;
+
+/**
+	Temporally smoothed thresholding latch
+  */
+
+public class Latch extends NamedTask
+{
+	VDouble	thresh;
+	VInteger	countThresh;
+	boolean	[] states;
+	int		[] counts;
+	VVector	output;
+	double[]	in,out;
+	int		n;
+		
+	public Latch(VVector input) 
+	{
+		super("latch");
+		n = input.size();
+		states = new boolean[n];
+		counts = new int[n];
+		Shell.push(node);
+		thresh = new VDouble("thresh",0.5);
+		countThresh = new VInteger("count_thresh",3);
+		output = new VVector("output", n);
+		Shell.pop();
+
+		in=input.array();
+		out=output.array();
+	}
+
+	public VVector output() { return output; }
+
+	public void run()
+	{
+		for (int i=0; i<n; i++) {
+
+			if (!states[i]) {
+
+				// unit is off - check to see if it should be on
+				if (in[i]>thresh.value) {
+					if (++counts[i] >= countThresh.value) {
+						out[i]=in[i];
+						states[i]=true;
+						counts[i]=0;
+					}
+				} else counts[i]=0;
+
+			} else {
+
+				// note is on - see about switching it off
+				if (in[i]<=0.8*thresh.value) {
+					if (++counts[i] >= countThresh.value) {
+						out[i]=-1;
+						states[i]=false;
+						counts[i]=0;
+					} else out[i]=in[i];
+				} else {
+					counts[i]=0;
+					out[i]=in[i];
+				}
+			}
+		}
+		output.changed();
+	}
+} 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/LineIn.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,61 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import samer.maths.*;
+import samer.core.*;
+import samer.audio.*;
+import samer.tools.*;
+
+/**
+	Manages sliding window audio input.
+	Acts as a sort of envelope class for audio input, containing the source,
+	the destination vector, and the associated reader task.
+*/
+
+public class LineIn implements Task
+{
+	private	AudioSource		source;
+	private	Task						reader=new NullTask();
+	private	VVector				B;
+	private	int							N, m;
+	private	double[]				buf;
+
+	public LineIn(AudioSource src, int N, int m) throws Exception {
+		Shell.print("LineIn: size="+N+", step="+m);
+
+		this.N=N; this.m=m; source=src;
+		B = new VVector(new Node("waveform"),N);
+		buf=B.array(); setStep(m);
+	}
+
+	public Vec output() { return B; }
+	public int getStep() { return m; }
+	public void setStep(int m) {
+		reader.dispose(); this.m=m;
+		reader=source.reader(buf,N-m,m);
+  	}
+
+	public AudioSource getSource() { return source; }
+	public AudioSource setSource(AudioSource s) {
+		AudioSource old=source; source=s; setStep(m);
+		return old;
+	}
+
+	public void dispose() { reader.dispose(); source.dispose(); B.dispose(); }
+	public void starting() { reader.starting(); }
+	public void stopping() { reader.stopping(); }
+	public void run() throws Exception {
+		if (N>m) System.arraycopy(buf,m,buf,0,N-m);
+		reader.run(); B.changed();
+	}
+
+	public String toString() { return "LineIn("+N+","+m+")->"+B; }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/LineOut.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.maths.*;
+import samer.core.*;
+import samer.core.types.*;
+import samer.audio.*;
+import samer.tools.*;
+import javax.sound.sampled.*;
+
+/**
+	A class which takes real valued samples from a VVector, converts
+	them to 16 bit integer samples, and writes them to an audio
+	device.
+
+	<p>
+	Can optionally output only a sub-window of input vector
+	This window is adjustable on the fly, so, for example, we can
+	output the last M samples of a sliding window.
+
+	*/
+
+public class LineOut implements Task
+{
+	AudioSink		sink;
+	Task					writer=new NullTask();
+
+	Vec						vec;
+	int						i0, i1;
+
+	public LineOut(Vec buf, AudioSink sink) throws Exception {
+		this.sink=sink; setInput(buf);
+	}
+
+	public Vec input() { return vec; }
+	public AudioSink getSink() { return sink; }
+	public void setSink(AudioSink sink) { this.sink=sink; setWindow(i0,i1); }
+	public void setInput(Vec vec) { this.vec=vec; setWindow(0,vec.size()); }
+	public void setWindow(int a,int b) {
+		i0=a; i1=b;  writer=sink.writer(vec.array(),i0,i1-i0);
+	}
+
+	public void dispose() { writer.dispose(); sink.dispose(); }
+	public void starting() { writer.starting(); }
+	public void stopping() { writer.stopping(); }
+	public void run() throws Exception { writer.run(); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Matrices.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,92 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+
+/** Some special matrix factories */
+public class Matrices
+{
+	public static void set(Matrix A, Generator G) { A.set(G); A.changed();	}
+	public static void add(Matrix A, Generator G) { A.add(G); A.changed(); }
+	
+	public static void fourierBasis(Matrix A)
+	{
+		int m=A.getColumnDimension();
+		int n=A.getRowDimension();
+		double [][] a = A.getArray();
+
+		for (int j=3; j<m;j+=2) {
+			double omega=(j-1)*Math.PI/m;
+			for (int i=0; i<n; i++) {
+				double theta=i*omega;
+				a[i][j-2] = Math.cos(theta);
+				a[i][j-1] = Math.sin(theta);
+			}
+		}
+		for (int i=0; i<n; i++) {
+			a[i][0]   = 1;
+			a[i][m-1] = (i%2)==0 ? 1 : -1;
+		}
+		A.changed();
+	}
+
+	public static void pingBasis(Matrix A) {
+		pingBasis(A,Shell.getDouble("gamma",0.5));
+	}
+
+	public static void pingBasis(Matrix A, double gamma)
+	{
+		int extra = (int)(3.0*16.0/gamma);
+		int m=A.getColumnDimension();
+		int n=A.getRowDimension();
+		double [][] a = A.getArray();
+
+		A.zero();
+
+		for (int j=0; j<m; j++) {
+			int jj=(int)((n+extra)*Math.random())-extra;
+			double omega=0.2+2*Math.random();
+			double t=0.0;
+			for (int i=0; i<n; i++) {
+				if (i>=jj) {
+					t=i-jj;
+					a[i][j]=Math.exp(-gamma*t/16)*Math.sin(omega*t);
+				} else a[i][j]=0;
+			}
+		}
+		A.changed();
+	}
+
+	public static void fuzzyIdentity(Matrix matrix) {
+		int		n = matrix.getRowDimension();
+		int		m = matrix.getColumnDimension();
+		fuzzyIdentity(matrix,Shell.getDouble("sigma",
+			(n>m) ? n/(double)m : m/(double)n));
+	}
+
+	public static void fuzzyIdentity(Matrix matrix, double s) 
+	{
+		int		n = matrix.getRowDimension();
+		int		m = matrix.getColumnDimension();
+		double	t = s/Math.max(n,m);
+		double	I[][] = matrix.getArray();
+
+		for (int i=0; i<n; i++) {
+			for (int j=0; j<m; j++) {
+				double Z = j/(double)(m-1) - i/(double)(n-1);
+				I[i][j] = Math.exp(-(Z*Z)/(2*t*t));
+			}
+		}
+
+		matrix.changed();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/MousePosition.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,60 @@
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.maths.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public class MousePosition implements MouseListener, MouseMotionListener
+{
+	private Node			node;
+	private Component	comp;
+	private VDouble		x, y;
+	private VBoolean		button;
+
+	public MousePosition( Component c)
+	{
+		node = new Node("mouse");
+
+		Shell.push(node);
+		x = new VDouble( "x");
+		y = new VDouble( "y");
+		button = new VBoolean("button",false);
+
+		comp=c;
+		comp.addMouseListener(this);
+	}
+
+	public void dispose() {
+		if (button.value) comp.removeMouseMotionListener(this);
+		comp.removeMouseListener(this);
+		x.dispose();
+		y.dispose();
+	}
+
+	// mouse event handlers
+	public void mouseClicked( MouseEvent e) {}
+	public void mouseEntered( MouseEvent e) {}
+	public void mouseExited( MouseEvent e)  {}
+	public void mousePressed( MouseEvent e)  {
+		button.value=true;
+		button.changed();
+		comp.addMouseMotionListener(this);
+	}
+
+	public void mouseReleased( MouseEvent e) {
+		button.value=false;
+		button.changed();
+		comp.removeMouseMotionListener(this);
+	}
+
+	// mouse motion handler
+	public void mouseDragged( MouseEvent e)  {
+		x.set(e.getX()); y.set(e.getY());
+	}
+	public void mouseMoved( MouseEvent e)   {
+		x.set(e.getX()); y.set(e.getY());
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/NoisyLinearSource.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,87 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+
+/** 
+	A class for generating random vectors according
+	to a particular generative model. If the output
+	is y, then
+		y = Bx + e
+	where x is a vector of indepedent identitically
+	distributed random variables, e is another vector of
+	iid random variables, and B is an arbitrary matrix.
+	The elements of x are the 'sources' and are drawn from
+	the random number generator rnd. The elements of e
+	are the 'noise' and are drawn from a different generator,
+	which defaults to Gaussian.
+  */
+
+public class NoisyLinearSource extends AnonymousTask
+{
+	public 	VGenerator	src, noise;
+	
+	VVector				s;		// sources
+	VVector				x;		// mixtures
+	VVector				e;		// noise
+	Matrix					A;		// mixing matrix
+
+	double []	xa, ea;
+	Task			t1, t2;
+
+	public NoisyLinearSource( int m, int n)	throws Exception
+	{
+		// super("source");
+
+		// Shell.push(node);
+		s   = new VVector("s",m);
+		x   = new VVector("x",n);
+		e   = new VVector("e",n);
+		A   = new Matrix("A",n,m);
+		A.identity();
+
+		src = new VGenerator("source");
+		noise = new VGenerator("noise");
+		// Shell.pop();
+
+		xa=s.array();
+		ea=e.array();
+		t1 = new MatrixTimesVector(x,A,s);
+		t2 = new VectorPlusEqualsVector(x,e);
+ 	}
+
+	public VVector	output() { return x; }
+	public Matrix	getMixingMatrix() { return A; }
+
+	public void run() throws Exception { 
+		src.next(xa); 
+		noise.next(ea); 
+		t1.run();
+		t2.run();
+		s.changed(); 
+		x.changed(); 
+		e.changed(); 
+	}
+
+	public void dispose() 
+	{
+		src.dispose();
+		noise.dispose();
+		s.dispose();
+		x.dispose();
+		e.dispose();
+		A.dispose();
+		t1.dispose();
+		t2.dispose();
+		super.dispose();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/OnsetMap.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,112 @@
+/*
+ *	Copyright (c) 2001, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.core.util.*;
+import samer.maths.*;
+import samer.tools.*;
+import java.util.*;
+
+public class OnsetMap extends Viewable implements Task, Observer {
+	VInteger		I1, I2;
+	VMap			vmap;
+	Matrix			bins;
+	IMap			map;
+	int				i1, i2;
+	double[]		xArray;
+	double[][]		binArray;
+	VDouble			L;
+	boolean		ison;
+	int				vel;
+	VDouble		thresh;
+
+	public OnsetMap(Vec x)
+	{
+		super("onsetmap");
+
+		xArray=x.array();
+		if (xArray==null) throw new Error("vec array not accessible");
+
+		Shell.push(node);
+
+		int M=Shell.getInt("bins",32);
+		int N=x.size();
+
+		I1=new VInteger("i1",1,0);
+		I2=new VInteger("i2",2,0);
+		I1.setRange(0,N-1);
+		I2.setRange(0,N-1);
+
+		vmap=new VMap(new LinearMap(-1,1,M));
+		map=vmap.getMap();
+
+		bins = new Matrix("bins",M,M,0); // no register
+		L = new VDouble("velocity");
+		thresh = new VDouble("threshold",1,0);
+
+		Shell.pop();
+
+		setAgent(vmap);
+		binArray=bins.getArray();
+		I1.addObserver(this);
+		I2.addObserver(this);
+		vmap.addObserver(this);
+		Shell.registerViewable(this);
+	}
+
+	public Matrix getBinMatrix() { return bins; }
+	public VDouble getVelocitySignal() { return L; }
+	public boolean isOnset() { return ison; }
+	public int getVelocity() { return vel; }
+
+	public void starting() {}
+	public void stopping() {}
+	public void run()	{
+		int j=map.clipInt(xArray[i1]);
+		int k=map.clipInt(xArray[i2]);
+		if (binArray[j][k]>thresh.value) {
+			ison=true;
+			vel=(int)(L.value=binArray[j][k]);
+		} else {
+			ison=false;
+			L.value=0;
+		}
+		L.changed();
+	}
+
+	public void dispose() {
+		I1.dispose();
+		I2.dispose();
+		bins.dispose();
+	}
+
+	public void update(Observable o, Object a) {
+		i1=I1.value;
+		i2=I2.value;
+		if (a==VMap.NEW_MAP) map=vmap.getMap();
+	}
+
+	public Viewer getViewer()
+	{
+		DefaultViewer vwr=new DefaultViewer(this);
+
+		vwr.add(I1);
+		vwr.add(I2);
+		vwr.add(bins.viewable());
+		vwr.add(L);
+		vwr.add(thresh);
+
+		return vwr;
+	}
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Oscillator.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,43 @@
+package	samer.units;
+import 	samer.core.*;
+import 	samer.core.types.*;
+import 	samer.maths.*;
+import		java.util.*;
+
+public class Oscillator implements Generator
+{
+	double c, s;
+	double x1, x2;
+
+	public Oscillator(double f) {	setFrequency(f); reset(); }
+
+	public DoubleModel getFrequencyModel() {
+		return new DoubleModel() {
+			public void set(double f) { setFrequency(f); }
+			public double get() { return Math.atan(s/c); }
+		};
+	}
+
+	public void reset() { x1=1; x2=0; }
+	public void setFrequency(double f) {
+		s=Math.sin(f);
+		c=Math.cos(f);
+	}
+
+	public void dispose() {}
+	public double next()
+	{
+		double y1 = x1*c - x2*s;
+		double y2 = x1*s + x2*c;
+		x1=y1; x2=y2;
+		return x2;
+	}
+
+	public void next(double [] x)	{
+		for (int i=0; i<x.length; i++) x[i]=next();
+	}
+
+	public String toString() { return "oscillator"; }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/OverlapAndAdd.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,72 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.maths.*;
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.functions.*;
+import javax.sound.sampled.*;
+
+/**
+ * Overlap and add input vectors into a buffer. At each iteration,
+ * the buffer is shifted by <hop> and the new data is added in.
+ */
+
+public class OverlapAndAdd extends NamedTask
+{
+	VVector			vec;	// input
+	VVector			out;
+	int				N, hop; // frame size, hop size
+	double[]			x, y; // input and output arrays
+	double[]			H; 	// array containing window, eg Hanning
+
+	/** Create overlap and add buffer for input vector with given hop size */
+	
+	public OverlapAndAdd(VVector input, int hop) throws Exception
+	{
+		super("overlap");
+		vec = input; N = vec.size();
+		out = new VVector("output",N);
+		H=new double[N];
+		x=vec.array();
+		y=out.array();
+		this.hop=hop;
+	}
+
+	/** Sets windowing array to samples from the given function.
+	 *  The domain [0,1) is mapped on to the array indices 0:N-1 
+	 */ 
+	
+	public void setWindow(Function fn) {
+		for (int i=0; i<N; i++) H[i] = (double)i/N;
+		fn.apply(H);
+	}
+
+	public VVector input() { return vec; }
+	public VVector output() { return out; }
+	public void setHop(int hop) { this.hop=hop; }
+
+	public void dispose() { out.dispose(); }
+	public void run() throws Exception
+	{
+		// shift everything in buffer along
+		System.arraycopy(y,hop,y,0,N-hop);
+
+		// addin new stuff
+		int i=0;
+		for (; i<N-hop; i++) y[i]+=H[i]*x[i];
+		for (; i<N; i++) y[i]=H[i]*x[i];
+
+		out.changed();
+	}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/RescaledIFT.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,62 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY;
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+
+import samer.core.*;
+import samer.maths.*;
+import samer.tools.*;
+import samer.functions.*;
+
+/**
+	Inverts a given FFT using an alternative magnitude spectrum
+  */
+
+public class RescaledIFT extends FFT implements Task
+{
+	Vec			mag;
+	FFT			ft;
+	double	k[];
+	VVector out;
+
+	public RescaledIFT(FFT ft, Vec mag) throws Exception
+	{
+		super(ft.size());
+		this.ft=ft;
+		this.mag=mag;
+		k=new double[N];
+		invert();
+		out=new VVector("ift.output", real);
+	}
+
+	public VVector output() { return out; }
+	
+	public void dispose() {}
+	public void starting() {}
+	public void stopping() {}
+	public void run() {
+		Vec.Iterator mit=mag.iterator();
+		int 		i, j;
+
+		for (i=0, j=N-1; mit.more(); i++, j--)
+			k[j]=k[i]=mit.next()/abs(ft.real[i],ft.imag[i]);
+		for (; i<=N/2; i++, j--) k[i]=k[j]=0;
+
+		for (i=0; i<N; i++) {
+			j=bitrev[i];
+			real[j]  = k[i]*ft.real[i];
+			imag[j] = k[i]*ft.imag[i];
+		}
+		calculate();
+		out.changed();
+	}
+
+	private static double abs(double x,double y) { return Math.sqrt(x*x+y*y); }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/SignalWindow.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,39 @@
+package	samer.units;
+import	samer.tools.*;
+import	samer.maths.*;
+
+public class SignalWindow extends AnonymousTask
+{
+	Generator	gen;
+	VVector		output;
+	double		out[], buf[];
+	int			size, count;
+
+	public SignalWindow(Generator g, int size) {
+		this(g,size,size);
+	}
+
+	public SignalWindow(Generator g, int size, int step)
+	{
+		output=new VVector("signalBlock", size);
+		out=output.array();
+		buf=new double[step];
+		this.size=size;
+		gen=g;
+	}
+
+	public VVector	output() { return output; }
+	public void starting() { count=0; }
+	public void run() { buf[count++]=gen.next(); }
+	public void flush() {
+		System.arraycopy(out,count,out,0,size-count);
+		System.arraycopy(buf,0,out,size-count,count);
+		count=0;
+		output.changed();
+	}
+
+	public Task flushTask() { 
+		return new NullTask() { public void run() { flush(); } };
+	}
+}
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/SpectralFIR.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,62 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+
+public class SpectralFIR implements Task
+{
+	FFT				fft;
+	Vec				spectrum;
+	VVector	A;
+	int				n, m;
+
+	public SpectralFIR(int n, VVector input)
+	{
+		this.n = n;
+
+		fft=new FFT(n);
+		fft.setWindow(new Constant(1));
+		fft.invert();
+
+		spectrum = input;
+		A=new VVector("coeffs",n);
+	}
+
+	public VVector coefficients() { return A; }
+
+	public void dispose() { A.dispose(); }
+	public void run() {
+		Vec.Iterator it=spectrum.iterator();
+		double [] _A=A.array();
+
+		Mathx.zero(fft.real);
+		Mathx.zero(fft.imag);
+
+		fft.real[fft.bitrev[0]]=it.next();	 // zero frequency
+		for (int i=1; it.more(); i++) {
+			fft.real[fft.bitrev[i]] = fft.real[fft.bitrev[n-i]] = it.next(); // pos and neg freqs
+		}
+		fft.calculate();
+
+		// copy FFT results to filter coefficients
+		// with some reordering
+		System.arraycopy( fft.real, n/2, _A, 0, n/2);
+		System.arraycopy( fft.real, 0, _A, n/2, n/2);
+		A.changed();
+	}
+
+	// private static double pos(double t) { if (t<0) return 0; else return t; }
+
+	public void starting() {}
+	public void stopping() {}
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Stacker.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,76 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+
+/*
+ *		Takes successive input vectors and stacks them into
+ *		one big output vector. Requires a task which it will
+ *		run to obtain each input vector.
+ */
+
+public class Stacker implements Task
+{
+	Node	node;
+	Task	nextvec;
+	Vec	srcvec;
+	int	size, step;
+	VVector	target;
+	double []	a, b;
+	int	k0, k1, k2;
+
+	public Stacker(Vec v, Task t, int size, int step) { this(v,t,size,step,v.size()); }
+	public Stacker(Vec v, Task t, int size, int step, int height)
+	{
+		node = new Node("stacker");
+
+		Shell.push(node);
+		srcvec=v; nextvec=t;
+		this.size = size;
+		this.step = step;
+
+		k0=height;
+		k1=step*k0;
+		k2=(size-step)*k0;
+
+		target = new VVector("output",k0*size);
+		a = target.array();
+		b = srcvec.array();
+		Mathx.zero(a);
+
+		Shell.pop();
+	}
+
+	public void dispose() {
+		nextvec.dispose();
+		target.dispose();
+		a=b=null;
+	}
+
+	public VVector output() { return target; }
+
+	public void starting() { nextvec.starting(); }
+	public void stopping() { nextvec.stopping(); }
+	public void run() throws Exception
+	{
+		// make some room in packed matrix
+		System.arraycopy(a,k1,a,0,k2);
+
+		for (int i=0, j=k2; i<step; i++) {
+			nextvec.run();
+			// copy vec into packed matrix
+			System.arraycopy(b,0,a,j,k0);
+			j+=k0;
+		}
+		target.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Stacker2.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.tools.*;
+
+/*
+ *		Takes successive input vectors and stacks them into
+ *		one big output vector. This version only stacks one
+ *		at new vector at a time and therefore does not need a
+ *		sub task to run to get new vectors.
+ */
+
+public class Stacker2 extends NullTask
+{
+	Node	node;
+	Vec	srcvec;
+	VVector	target;
+	double []	a;
+	int	k0, k1, k2;
+
+	public Stacker2(Vec v, int size) { this(v,size,v.size()); }
+	public Stacker2(Vec v, int size, int height)
+	{
+		node = new Node("stacker");
+
+		Shell.push(node);
+		srcvec=v; 
+
+		k0=height;
+		k1=k0;
+		k2=(size-1)*k0;
+
+		target = new VVector("output",k0*size);
+		a = target.array();
+		Mathx.zero(a);
+
+		Shell.pop();
+	}
+
+	public void dispose() { target.dispose(); }
+	public VVector output() { return target; }
+
+	public void run() {
+		System.arraycopy(a,k1,a,0,k2); // make some room 
+		System.arraycopy(srcvec.array(),0,a,k2,k0); // copy new data in
+		target.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/StreamToDouble.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,37 @@
+//
+//  StreamToVec.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.core.types.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+public class StreamToDouble extends AnonymousTask {
+	DoubleModel	x;
+	InputStream	in;
+	DataInputStream	objin;
+
+	public StreamToDouble(DoubleModel x, InputStream in) throws Exception
+	{
+		this.x=x;
+		this.in=in;
+		objin=new DataInputStream(in);
+	}
+
+	public void dispose() {
+		try { objin.close(); }
+		catch (Exception ex) {}
+		// close out?
+	}
+	public void run() throws Exception {
+		x.set((double)objin.readFloat());
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/StreamToVec.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,45 @@
+//
+//  StreamToVec.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+public class StreamToVec extends AnonymousTask {
+	Vec				x;
+	InputStream	in;
+	DataInputStream	objin;
+	Viewable			obs;
+	double []		a;
+	
+	public StreamToVec(VVector x, InputStream in) throws Exception
+	{
+		this.x=x;
+		this.in=in;
+		this.obs=x;
+		objin=new DataInputStream(in);
+		a=x.array();
+	}
+
+	public void dispose() {
+		try { objin.close(); }
+		catch (Exception ex) {}
+		// close out?
+	}
+	public void run() throws Exception {
+//		double [] read=(double[])objin.readObject();
+//		Mathx.copy(read,a);
+		for (int i=0; i<x.size(); i++) {
+			a[i]=(double)objin.readFloat();
+		}
+		obs.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/SumFnVec.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,30 @@
+package	samer.units;
+import	samer.core.types.*;
+import	samer.tools.*;
+import	samer.maths.*;
+
+public class SumFnVec extends FunctionOfVector implements SafeTask
+{
+	double []		x, fx;
+	DoubleModel	out;
+	Function		f;
+	
+	public SumFnVec(Function f, VVector x, DoubleModel out) {
+		this.x=x.array();
+		this.f=f;
+		this.out=out;
+		fx=new double[x.size()];
+	}
+
+	public void starting() {}
+	public void stopping() {}
+	public void run() {
+		f.apply(x,fx);
+		out.set(Mathx.sum(fx));
+	}
+
+	public double apply(double [] x) {
+		f.apply(x,fx); return Mathx.sum(fx);
+	}
+}
+		
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Trigger.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,57 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import samer.tools.*;
+import samer.maths.*;
+import samer.core.types.*;
+
+/**
+	Generates a 1 for each element that rises above threshold,
+	and a -1 for when it drops back below. Can be used to
+	drive MidiSynth, which interprets +1 as note-on and -1
+	as note-off.
+ */
+
+public class Trigger extends AnonymousTask
+{
+	boolean	[] states;
+	VDouble	thresh;
+	VVector	output;
+	double[]	in,out;
+	int		n;
+
+	public Trigger(VVector input, double th)
+	{
+		n = input.size();
+		states = new boolean[n];
+		in=input.array();
+		thresh=new VDouble("thresh",th);
+		output=new VVector("trigger",n);
+		out=output.array();
+	}
+
+	public VVector output() { return output; }
+
+	public void run()
+	{
+		double th=thresh.value;
+
+		for (int i=0; i<n; i++) {
+			if (in[i]>th) {
+				if (!states[i]) { out[i]=in[i]; states[i]=true; }
+				else out[i]=0;
+			} else {
+				if (states[i]) { out[i]=-1; states[i]=false; }
+				else out[i]=0;
+			}
+		}
+		output.changed();
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/VecToDouble.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+package	samer.units;
+import	samer.tools.*;
+import	samer.maths.*;
+import	samer.core.types.*;
+
+public class VecToDouble extends AnonymousTask
+{
+	// Vec			vec;
+	DoubleModel	sig;
+	int				i;
+	double		[] x;
+
+	public VecToDouble(Vec in, int j, DoubleModel out) { sig=out; i=j; x=in.array(); }
+	public DoubleModel	output() { return sig; }
+	public void setIndex(int j) { i=j; }
+	public void run() { sig.set(x[i]); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/VecToStream.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,69 @@
+//
+//  VecToStream.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+/** Write sequence of vectors to stream in binary format. */
+
+public class VecToStream extends AnonymousTask {
+	Vec				x;		// the vector itself
+	OutputStream	out;	// stream to write to
+	DataOutputStream	objout;
+	Task				task;
+	
+	public VecToStream(Vec x, OutputStream out) throws Exception
+	{
+		this.x=x;
+		this.out=out;
+		objout=new DataOutputStream(out);
+
+		double [] a=x.array();
+		//if (a!=null) task=new ArrayObjectWriter(a);
+		//else
+			task=new IteratorFloatWriter();
+	}
+
+	public void dispose() {
+		try {
+			objout.flush();
+			objout.close();
+		} catch (Exception ex) {}
+		
+		// close out?
+	}
+
+	public Task getTask() { return task; }
+	
+	public void run()  throws Exception { task.run(); /* autoflush? */ }
+	public void stopping() {
+		try { objout.flush(); }
+		catch (Exception ex) {}
+	}
+	
+	class ArrayObjectWriter extends AnonymousTask {
+		double [] array;
+		public ArrayObjectWriter(double [] a) { array=a; }
+		public void run() throws Exception {
+			// objout.writeObject(array);
+		}
+	}
+	
+	class IteratorFloatWriter extends AnonymousTask {
+		public void run() throws Exception {
+			Vec.Iterator i=x.iterator();
+			while (i.more()) {
+				objout.writeFloat((float)i.next());
+			}
+		}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/VecWriter.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,42 @@
+//
+//  VecWriter.java
+//  
+//
+//  Created by Samer Abdallah on Mon Jun 10 2002.
+//  Copyright (c) 2002 __MyCompanyName__. All rights reserved.
+//
+
+package samer.units;
+
+import samer.core.*;
+import samer.tools.*;
+import samer.maths.*;
+import java.io.*;
+
+public class VecWriter extends AnonymousTask {
+	Vec				x;		// the vector itself
+	PrintWriter		prn;
+	
+	public VecWriter(Vec x, Writer out) throws Exception {
+		this.x=x; prn = new PrintWriter(out);
+	}
+
+	public void dispose() {
+		try { prn.flush(); } catch (Exception ex) {}
+		// prn.close();
+	}
+
+	public void run()  throws Exception {
+		Vec.Iterator i=x.iterator();
+		prn.print(i.next());
+		while (i.more()) {
+			prn.print(' ');
+			prn.print(i.next());
+		}
+		prn.println();
+	}
+	
+	public void stopping() {
+		try { prn.flush(); } catch (Exception ex) {}
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/samer/units/Wavetable.java	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,66 @@
+/*
+ *	Copyright (c) 2000, Samer Abdallah, King's College London.
+ *	All rights reserved.
+ *
+ *	This software is provided AS iS and WITHOUT ANY WARRANTY; 
+ *	without even the implied warranty of MERCHANTABILITY or 
+ *	FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+package samer.units;
+import  samer.core.*;
+import  samer.maths.*;
+import  samer.maths.random.*;
+
+/**
+	Periodic generator: generates periodic signal from
+	a wave table
+ */
+
+public class Wavetable implements Generator
+{
+	int		start, end, j;
+	Vec		vec;
+	double [] pp;
+
+	public Wavetable(Vec vec) {
+		this(vec,0,vec.size());
+	}
+
+	public Wavetable(Vec vec, int start, int end) 
+	{ 
+		this.vec   = vec;
+		this.start = start;
+		this.end   = end;
+		pp = vec.array();
+		j = start;
+	}
+
+	public int  period() { return end-start; }
+	public void dispose() {}
+	public double next() 
+	{ 
+		double r=pp[j++]; 
+		if (j>=end) j=start; 
+		return r; 
+	}
+
+	public void next(double [] x) 
+	{ 
+		int	remaining=x.length;
+		int	iput=0;
+
+		while (remaining>0) {
+			int avail = end-j;
+			int block = remaining > avail ? avail : remaining;
+
+			System.arraycopy( pp, j, x,iput, block);
+			j+=block; iput+=block; remaining-=block;
+			if (j>=end) j=start;
+		}
+	}
+
+	public String toString() { return "wavetable"; }
+} 
+		
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/analysis.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,90 @@
+;(load "view3d.scm")
+(load "models.scm")
+(load "functions.scm")
+
+(define o CompoundFunction.)
+
+(define distances null)
+(define reset-P null)
+(define computeD null)
+(define get-P null)
+
+
+(define (stats->mds stats mds)
+	(let* ((N (.N$# mds))
+			(R (Matrix. "R" N N))
+			(stats->corr (task (.getCorrelation stats R)))
+			(corr->D	(samer.mds.CorrelationTask. mds R)))
+		(set! distances (VVector. "distances" (.getLinkArray mds)))
+		(set! computeD
+			(seq stats->corr corr->D
+				(Ops.apply (o (vscale 16.0) (vpower 1.0)) distances)
+				(Ops.update distances)
+			)
+		)
+		(matexec R "image")
+		computeD
+	)
+)
+
+(define (R->mds R mds)
+	(set! distances (VVector. "distances" (.getLinkArray mds)))
+	(set! computeD
+		(seq 
+			(samer.mds.CorrelationTask. mds R)
+			(Ops.apply (o (vscale 16.0) (vpower 1.0)) distances)
+			(Ops.update distances)
+		)
+	)
+	(matexec R "image")
+	computeD
+)
+
+
+(define (analyse x)
+	(define N (.size x))
+;	(define hist (histogram x 256))
+	(define stats (node (child x "statistics") (GaussianStatsOnline. x)))
+	(define P (node (.getNode x) (Matrix. "P" N 3)))   ; 4D points
+	(define mds (samer.mds.MDS. P))
+	(define tasks (seq stats))
+
+	(set! reset-P (lambda () (.set P (samer.maths.random.NormalisedGaussian.))))
+	(set! get-P (lambda () P))
+	;(matexec P "load")
+
+	(reset-P)
+	;(.setMetric mds (samer.mds.Manhatten.))
+	;(exec (viewable "mds.stress") "trace")
+	(matexec P "image")
+	;(exec (.getLikelihoodSignal hist) "trace")
+
+	(with-tasks tasks
+		(addtasks 
+;			hist
+			(sub 128 (stats->mds stats mds))
+			(sub 24 mds))
+;		(view3d x P id)
+	)
+	tasks
+)
+								  
+(define (analyse-mds x)
+	(define N (.size x))
+	(define R (Matrix. "R" N N))
+	(define P (node (.getNode x) (Matrix. "P" N 3)))   ; 4D points
+	(define mds (samer.mds.MDS. P))
+
+	(set! reset-P (lambda () (.set P (samer.maths.random.NormalisedGaussian.))))
+	(set! get-P (lambda () P))
+	;(matexec P "load")
+
+	(reset-P)
+	;(.setMetric mds (samer.mds.Manhatten.))
+	;(exec (viewable "mds.stress") "trace")
+	(matexec P "image")
+
+	(seq 
+		(sub 128 (R->mds R mds))
+		(sub 24 mds))
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/audio.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,97 @@
+;(import "javax.sound.sampled.*")
+
+;;; getting mixers
+(define (get-mixers)	(vector->list (javax.sound.sampled.AudioSystem.getMixerInfo)))
+(define (pr-mixers) (print (get-mixers)))
+(define (mixer mi) (javax.sound.sampled.AudioSystem.getMixer mi))
+(define (mixer-n n) (mixer (list-ref (get-mixers) n)))
+(define (default-mixer) (mixer-n (Shell.getInt "mixer" 1)))
+
+
+;;; constructing formats
+(define (mono rate) (multi 1 rate))
+(define (stereo rate) (multi 2 rate))
+(define (multi chans rate) (format 16 chans rate))
+(define (format bits chans rate) 
+	(javax.sound.sampled.AudioFormat. (.floatValue rate) bits chans #t #f))
+
+; If current Environment contains "format", then we use that,
+; otherwise, we get values for "rate" [22050] and "channel" [1].
+(define (default-format) 
+  (Shell.get "format" 
+    (multi (Shell.getInt "channels" 1) (Shell.getInt "rate" 22050))))
+
+;;; construct DataLine.Info. args = (format [bufsize])
+(define (_dli cl args) (apply javax.sound.sampled.DataLine$Info. (cons cl args)))
+(define (target-info . args) (_dli javax.sound.sampled.TargetDataLine.class args))
+(define (source-info . args) (_dli javax.sound.sampled.SourceDataLine.class args))
+
+
+
+;;; getting lines
+
+; get a Line from AudioSystem given Info
+(define-method (line info) (javax.sound.sampled.AudioSystem.getLine info))
+
+; get a Line from a particular Mixer using Info
+(define-method (line mixer info) (.getLine mixer info))
+
+
+;;; getting LineSource and LineSink
+(define _src samer.audio.LineSource.)
+(define _snk samer.audio.LineSink.)
+(define (_sbs b l) (.setBufferSize l b) l)
+
+(define-method (linesrc) 				(linesrc (default-format)))
+(define-method (linesnk) 				(linesnk (default-format)))
+(define-method (linesrc fmt) 			(.open (_src (line (target-info fmt)) fmt)))
+(define-method (linesnk fmt) 			(.open (_snk (line (source-info fmt bf)) fmt))) 
+(define-method (linesrc mx fmt)		(.open (_src (line mx (target-info fmt)) fmt)))
+(define-method (linesnk mx fmt)		(.open (_snk (line mx (source-info fmt)) fmt)))
+(define-method (linesrc mx fmt bf)	(.open (_sbs bf (_src (line mx (target-info fmt bf)) fmt))))
+(define-method (linesnk mx fmt bf)	(.open (_sbs bf (_snk (line mx (source-info fmt bf)) fmt))))
+(define-method (linesrc-buf fmt bf) (.open (_sbs bf (_src (line (target-info fmt bf)) fmt))))
+(define-method (linesnk-buf fmt bf) (.open (_sbs bf (_snk (line (source-info fmt bf)) fmt))))
+(define filesnk samer.audio.FileSink.)
+
+(define streamsrc samer.audio.StreamSource.)
+
+;; to do: buffer size?
+;; specify default mixer in user.props
+
+(define (display-mixer m)
+	(print "\n **************************** \n")
+	(print (.getMixerInfo m))
+;	(print "\n---controls:") (print(.getControls m))
+	(print "\n---source line info:") (print(.getSourceLineInfo m))
+	(print "\n---target line info:") (print(.getTargetLineInfo m))
+;	(print "\n---source lines:") 		(print(.getSourceLines m))
+;	(print "\n---target lines:") 		(print(.getTargetLines m))
+	#null
+)
+
+;;; buffering audio input into frames with a certain hop size
+(define-method (linein size step) (linein (linesrc) size step))
+(define-method (linein (source samer.audio.AudioSource) size step)
+	(define line (LineIn. source size step))
+	(put "LineIn" line)
+	(addtask line)
+	(.output line) )
+
+
+
+;;; Format conversion
+(define (convert format stream)
+	(javax.sound.sampled.AudioSystem.getAudioInputStream format stream))
+
+;;; get audio input stream from file object
+(define-method (astream (f java.io.File)) 
+	(javax.sound.sampled.AudioSystem.getAudioInputStream f))
+
+;;; get audio input stream from any stream
+(define-method (astream (f java.io.InputStream)) 
+	(javax.sound.sampled.AudioSystem.getAudioInputStream f))
+
+;;; get audio input stream from named file
+(define-method (astream (fn String))  (astream (java.io.File. fn)))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/color.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,47 @@
+(import "java.awt.Color")
+
+;;; create a colormap of linear ramps
+(define (colormap n c0 . pairs)
+	(define cramp (ColorRamp. n))
+	(define (gradto pairs)
+		(if (not (null? pairs))
+			(begin
+				(.gradientTo cramp (car pairs) (cadr pairs))
+				(gradto (cddr pairs)))))
+	(.set cramp 0 c0)
+	(gradto pairs)
+	(.getColorModel cramp))
+
+(define (grey) ImageSourceBase.GREY$)
+(put "colormaps.grey" (grey))
+;(put "colormaps.green" (green))
+
+(define (green)
+	(colormap 256
+		Color.black$
+		64 (Color. 0 80 0)
+		128 (Color. 40 160 40)
+		196 (Color. 120 220 120)
+		255 (Color. 200 255 200)))
+
+(define (redgreen)
+	(colormap 256
+		(Color. 255 140 140)
+		64 (Color. 200 40 40)
+		128 Color.black$
+		196 (Color. 40 200 40)
+		255 (Color. 140 255 140)))
+
+(define (hot)
+	(colormap 256
+		(Color. 160 180 255)
+		128 Color.black$
+		196 (Color. 200 80 0)
+		255 (Color. 255 200 60)))
+
+(define (middle-map middle)
+	(colormap 256 Color.black$ 128 middle 255 Color.white$))
+
+;these are middle maps
+;(put "spectrum.trace.colormap" (cmap (Color. 180 100 40)))
+;(put "colormap" (middle-map (Color. 210 40 40)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/filelist.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,56 @@
+(import "java.util.*")
+(import "java.awt.*")
+(import "java.io.*")
+(import "javax.swing.*")
+
+(define (edit-list L)
+	(define dlg (JFileChooser.))
+	(.setMultiSelectionEnabled dlg #t)
+	(if (pair? L) 
+		(begin
+			(.setCurrentDirectory dlg (car L))
+			(.setSelectedFiles dlg (list->array java.io.File.class L))
+		)
+	)
+	(.showDialog dlg null "Done")
+	(vector->list (.getSelectedFiles dlg))
+)
+
+(define (restore-list name) (map File. (eval-string (get name))))
+(define (store-list name L)
+	(X.store name (string-append "'"
+		(.toString (map .toString	L)))))
+
+
+(define filesrc null)
+
+(define (get-playlist)        (array->list (.toArray (.getPlaylist filesrc))))
+(define (set-playlist L)
+   (.setPlaylist filesrc (Arrays.asList (list->vector L)))
+   (.rewind filesrc))
+
+(define (edit-playlist)       (set-playlist (edit-list (get-playlist))))
+(define (restore-playlist)    (set-playlist (restore-list "playlist.files")))
+(define (store-playlist)      (store-list "playlist.files" (get-playlist)))
+(define (clear-playlist)      (set-playlist ()))
+(define (rewind) (.rewind filesrc))
+
+(define (filesource . format)
+   (set! filesrc (samer.audio.FileSource.))
+	(if (not (null? format)) (.setTargetFormat filesrc (car format)))
+   (tryCatch   (restore-playlist) (lambda (ex) ()))
+   filesrc)
+
+(define (dirsource ext . format)
+   (define dir (VFile. "playlist.directory"))
+   (set! filesrc (samer.audio.FileSource.))
+	(if (not (null? format)) (.setTargetFormat filesrc (car format)))
+   (on-change dir                                             
+     (.setDirectory filesrc (.getFile dir) ext)
+      (.rewind filesrc))
+   (tryCatch   (.changed dir) (lambda (ex) ()))
+   filesrc)
+
+(define (wav? f) (.endsWith (.toString f) ".wav"))
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/filter.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,32 @@
+(define (hp x)
+	; Normaliser used as high pass filter to remove slow variations
+	(define n (node "phase1" (NormaliseVector. x)))
+	(addtasks n)
+	(.output n)
+)
+
+(define (lp x)	
+	; Normaliser used as low pass filter to remove fast variations
+	(define n (node "lp" (NormaliseVector. x)))
+	(addtasks n)
+	(.mean n)
+)
+
+(define (bp x) (lp (hp x)))
+
+
+(define (smooth-signal sig) (addtask
+	(node (.getNode sig)
+		(GenerateDouble. (VDouble. "smoothed")
+			(FilteredGenerator. (DoubleGenerator. sig)	
+				(IIRFilter.
+					; two element double array controlled by VDouble
+					(let ((a (double[] #(1 0)))
+							(p (samer.core.types.VDouble. "smoothness" 1.0)))
+						(on-change p 
+							(let ((r (Math.exp (- (.get p)))))
+								(double[] a 0 r)
+								(double[] a 1 (- 1 r))))
+						(.changed p)
+						a )))))))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/functions.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,124 @@
+
+(define (matmult A x nm)
+	(define y (VVector. nm (.getRowDimension A)))
+	(addtask (seq
+		(Ops.times y A x)
+		(Ops.update y)))
+	y
+)
+
+;;; apply function to vector
+(define (fn-vec fn in outname)
+	(let ((out (VVector. outname (.size in))))
+		(addtasks (Ops.apply out fn in) (Ops.update out))
+		out))
+
+
+; set up signal containing of sum_i fn(x_i)
+(define (sum-fn fn x nm)
+	(define sig (node (.getNode x) (VDouble. nm)))
+	(addtask (SumFnVec. fn x sig))
+	sig
+)
+
+;;; power spectrum
+(define (ft-vec in)
+   (define ftv (FFTVector. in))
+   (addtask (.calcTask ftv))
+   (put "FFTVector" ftv)
+   ftv
+)
+
+(define (ft-power ftv)
+   (define y (VVector. "ft.power" (+ 1 (/ (.size ftv) 2))))
+   (addtask (.getPower ftv y))                                
+   y                                                          
+)
+                                                              
+;;; magnitude spectrum, ie sqrt(power)                        
+(define (ft-mag ftv)                                          
+   (define y (VVector. "ft.mag" (+ 0 (/ (.size ftv) 2))))     
+   (addtasks (.getFnPower ftv (Sqrt.) y))                     
+   y                                                          
+)                                                             
+
+;; log spectrum, ie log(power)                               
+(define (ft-log ftv)                                          
+   (define y (VVector. "ft.log" (+ 1 (/ (.size ftv) 2))))     
+   (addtasks (.getFnPower ftv (Log.) y))
+   y
+)
+
+;;; linear FT, real valued version with sin and cosine parts
+(define (ft-linear ftv)
+   (define y (VVector. "ft" (.size ftv)))
+   (addtask (.getLinearFT ftv y))
+   y
+)
+
+;;; creates parameter viewables for a VFunction
+;;; vfn: the VFunction (we need the node and the observable parts)
+;;; models: list of (String,DoubleModel) pairs: we create a
+;;;				VParameter with the given name for each DoubleModel
+
+(define (vfn-params vfn models)
+   (define obs (observer (.changed vfn)))
+   (node (.getNode vfn)
+      (for-each
+         (lambda (model)
+			;; these VParameters will INITIALISE the DoubleModel with a value
+			;; read from the environment
+            (define param (VParameter. (first model) (second model)))
+            (.addObserver param obs)
+         )
+         models)))
+
+(define (id x) x)
+(define (vscale k) (define f (Scale. k)) (VParameter. "scale" f) f)
+(define (vpower k) (define f (Power. k)) (VParameter. "power" f) f)
+(define (vgenexp)
+	(define genexp (samer.functions.LogGenExp.))
+	(define vfn (VFunction. "logprior" genexp))
+	(vfn-params vfn `( ( "quad" ,genexp ,(.getEpsModel genexp))))
+	vfn
+)
+
+(define-method (logcosh)
+	(define fn (LogGenCosh.))
+	(define vfn (VFunction. "logcosh" fn))
+	(vfn-params vfn `(("alpha" ,fn)))
+	fn)
+
+(define-method (genexp alpha lin quad)
+	(define fn (LogGenExp2.))
+	(.set (.getAlphaModel fn) alpha)
+	(.set (.getLinearScale fn) lin)
+	(.set (.getQuadraticScale fn) quad)
+	fn
+)
+
+(define-method (genexp)
+	(define fn (LogGenExp2.))
+	(define vfn (VFunction. "genexp" fn))
+	(vfn-params vfn `(
+		("alpha" ,fn)
+		("lin"      ,(.getLinearScale fn))
+		("quad"  ,(.getQuadraticScale fn))
+	))
+	fn
+)
+
+(define (nonneg logpr str)
+	(define sq (ScaledFunction. (Square.) str))
+	(define vfn (VFunction. "hybrid" (HybridFunction. sq logpr)))
+;	(vfn-params vfn `(("strictness" ,sq)))
+	(.getFunction vfn)
+)
+
+
+; returns list of integers from start to end
+(define (range start end)
+  (define (rr l j) (if (< j start) l (rr (cons j l) (- j 1))))
+  (rr () (- end 1))
+)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/genfilter.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,113 @@
+;;; Preamble
+(load "audio.scm")
+(load "lineout.scm")
+(load "functions.scm")
+
+(import "samer.mds.*")
+
+;;; transfer filter fn to vector of values
+(define (set-filter F fn)
+	(define f (.mat F))
+	(for-each
+		(lambda (i) (.set f 0 i (fn i)))
+		(range 0 N))
+	(.changed F)
+)
+
+;; convert vector of values into a filter fn
+(define (filter-fn F)
+	(let ((mat (.mat F)))
+		(lambda (i) (.get mat 0 i))))
+
+;; returns fn f(i) that returns 1 if d'th coordinate of P(i) <op> th
+;; eg (coor-test P 2 > 0.5) is function which returns P(i,2) > 0.5
+(define (coor-test P d op th)
+	(lambda (i) (if (op (.get P i d) th) 1.0 0.0)))
+
+
+;;; set up tasks for ICA domain filtering using f as a function
+;;; which returns (f i) as the scaling factor for the ith ICA component
+;;; source is an AudioSource.
+(define (direct-recon source N hop f sink)
+	(define x (linein source N hop))
+	(define W (Matrix. "W" N N))		; ICA matrix
+	(define K (Matrix. "K" N N))			; total filtering matrix
+	(define z (VVector. "z" N))				; reconstruction
+	(addtask (Ops.times z K x) (Ops.update z))
+	(overlap-and-add sink z hop)
+	(on-change W (.assign K (total-matrix W f)))
+	(matexec W "load")
+)
+
+(define (ica-recon s A sink hop)
+	(define N (.size s))
+	(define F (VVector. "F" N))			; the source domain filter
+	(define z (VVector. "z" N))
+	(addtasks (Ops.timesEquals s F) (Ops.times z A s))
+	(overlap-and-add sink z hop))
+
+
+(define (recon source N hop sink)
+	(define x (norm (linein source N hop)))
+	(define ica (mk-ica x laplace-spec))
+	(define s (.output ica))
+	(define F (VVector. "F" N))			; the source domain filter
+	(define W (.getWeightMatrix ica))
+	(define A (.getBasisMatrix ica))
+	(define z (VVector. "z" N))
+	(define order (Matrix. "order" 5 512))
+
+	(addtasks (Ops.timesEquals s F) (Ops.times z A s))
+	(overlap-and-add sink z hop)
+
+	(on-change W (exec ica "basis"))
+	(matexec W "load")
+)
+
+;; returns total transformation matrix  formed by filtering
+;; in the ICA domain. f is a function which returns the scaling
+;; factor for the i'th component, ie (f i) is a scalar.
+(define (total-matrix W f)
+	(define D (Jama.Matrix. N N 0.0))
+	(for-each
+		(lambda (i) (.set D i i (f i)))
+      (range 0 N))
+	(.times (.inverse W) (.times D W))
+)
+
+; eg (total-matrix W (coor-test P 1 > 0.0))
+; filters out all components whos MDS y-coor <= 0
+
+;; transfer values from G to F reordered by order
+(define-method (rank-filter F order G)
+	(rank-filter F order G 0 (.size G)))
+
+(define-method (rank-filter F order G start end)
+	(Mathx.set F (Zero.))
+	(let ((f (.mat F)) (g (.mat G)) (I (.mat order)))
+		(for-each
+			(lambda (i) (.set f 0  (.get I 0 i)  (.get g 0 i)))
+			(range start end)))
+	(.changed F)
+)
+
+;;; filter is a certain spherically symmetric kernel centred on
+;;; a particular component. Geometry directly from correlation
+;;; matrix (not from MDS configuation)
+(define (proximity-filter R F fn)
+	(ProximityFilter. R F (VFunction. "proximity kernel" fn)) f)
+
+(define (geometric-filter P f)
+	(define n (.getRowDimension P))
+	(define E (.getColumnDimension P))
+	(define off (VDouble. "offset" 0.0))
+	(define norm	(VVector. "normal" E))
+	(define hp	(LogisticHyperplane. (.array norm) (.value$ off)))
+	(define gf		(GeometricFilter. P f hp))
+	(define obs (observer (.setOffset hp (.value$ off)) (.run gf) (.changed f)))
+	(.addObserver P obs)
+	(.addObserver off obs)
+	(.addObserver norm obs)
+	f)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/genmodel.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,43 @@
+; Test noisy linear mixtures
+; first version using NoisyLinearSource
+
+(put "mix.p" 0.08)
+(put "mix.gauss.mean" 0)
+(put "mix.gauss.variance" 0.1)
+(put "noise.mean" 0)
+(put "noise.variance" 0.05)
+
+(node "v1"
+	(addtask	(NoisyLinearSource. 8 16))
+
+	(load-generator (viewable "noise"))
+	(load-generator (viewable "source"))
+)
+
+; scheme version
+
+(node "v2"
+	(let* 
+		(	(n	8)
+			(m 16)
+			(x (VVector. "x" n))
+			(A (Matrix.  "A" m n))
+			(e (VVector. "e" m))
+			(y (VVector. "y" m))
+			(g1 (VGenerator. "source"))
+			(g2 (VGenerator. "noise"))
+		)	
+		(addtasks
+			(GenerateVector. x g1)
+			(GenerateVector. e g2)
+			(MatrixTimesVector. y A x)
+			(VectorPlusEqualsVector. y e)
+			(Ops.update x)
+			(Ops.update y)
+			(Ops.update e)
+		)
+	)
+	(load-generator (viewable "noise"))
+	(load-generator (viewable "source"))
+)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/ica/args	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,3 @@
+#properties
+#Fri Dec 19 16:33:08 GMT 2003
+exposed.bounds=(4,22,244,574)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/ica/run.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,6 @@
+(load "audio.scm")
+(load "models.scm")
+
+(define x (nonorm (linein (filesource) 512 512)))
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/ica/train.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,21 @@
+(import "samer.models.*")
+
+
+(define (preflush) null)
+(define (alt-train-ica ica)
+	(define ica-train
+		(node (Node. "learn" (.getNode ica))
+			(.getDiffTrainer ica)))
+
+	(addtasks
+		ica-train
+		(sub 6 (task	(.diffFlush ica-train)))
+		(sub (* 6 256)
+			(seq
+				(task (preflush) (.flush ica-train))
+				(sub 16 (task (exec ica "basis")))
+			)
+		)
+	)
+	ica-train
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/joints.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,58 @@
+
+(define (joints x min max)
+	(define nd (.getNode x))
+	(define dir (java.io.File. (.getName nd)))
+
+ 	(Shell.push nd)
+
+	; could just make a map and put it
+	(put "joint.histogram.map.symmetric" #f)
+	(put "joint.histogram.map.maximum" max)
+	(put "joint.histogram.map.minimum" min)
+	(put "joint.histogram.vector" x)
+	(put "joint.histogram.bins.dir" dir)
+)
+
+(define (joint a b)
+	; need to set:
+	;	map domain
+	;	filename for saved histogram
+	;	node for this histogram
+
+	(define x (get "joint.histogram.vector"))
+	(define dir (get "joint.histogram.bins.dir"))
+	(define name (string-append "j" (.toString a) "v"  (.toString b)))
+	(.mkdirs dir)
+	(put "joint.histogram.bins.file" (java.io.File. dir name))
+	(addtask
+	;	(node name
+			(JointHistogram. x 128 a b)
+	;	)
+	)
+)
+
+
+(define s (.output ica))
+(define e (viewable "prior.e"))
+(define log_s (vecfn s (LogAbs.) "log_s"))
+(define energy (vecfn s (Square.) "energy"))
+
+(joints s -60 60)
+(joint 79 229)
+(joint 237 229)
+(Shell.pop)
+
+(joints e 0 12)  ; was 10
+(joint 79 229)
+(joint 237 229)
+;(Shell.pop)
+
+(joints log_s -8 8)  ; was -6 8 i think
+(joint 79 229)
+(joint 237 229)
+;(Shell.pop)
+
+(joints energy 0 3600)
+(joint 79 229)
+(joint 237 229)
+(Shell.pop)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/lineout.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,49 @@
+(define set-step null)
+(define line-on null)
+(define line-off null)
+(define _lineout null)
+
+
+
+
+;;; Audio output from given vector to given AudioSink
+;;; Task is added to current task list, and functions line-on
+;;; and line-off are defined to insert and remove the lineout task.
+;;; Function set-step defined to change hop size.
+;;; Optional final parameter is hop size
+(define-method (lineout sink (in Vec) hop)
+	(let ((out 		(LineOut. in sink))
+			(tlist 	(tasks)))
+		(set! set-step (lambda (m) (.setWindow out 0 m)))
+		(set! line-on (lambda ()
+			(.starting out) (Thread.sleep 200L)
+			(.addTask tlist out)))
+		(set! line-off (lambda ()
+			(.removeTask tlist out)
+			(.stopping out) (Thread.sleep 200L)))
+		(set-step hop)
+		(addtasks out)
+		out))
+			
+(define-method (lineout (in Vec)) (lineout (linesnk) in))
+(define-method (lineout sink (in Vec)) (lineout sink in (.size in)))
+(define-method (lineout sink (in LineIn))
+	(put "lineout.scale" 1.0)
+	(let ((out (lineout sink (.output in))))
+		(set-step (.getStep in))
+		(set! set-step (lambda (n)
+			(.setStep in n)
+			(.setWindow out 0 n)))))
+
+(define-method (overlap-and-add sink x hop)
+	(define oa  (OverlapAndAdd. x hop))
+	(define line (LineOut. (.output oa) sink))
+	(.setWindow oa (Hanning.))
+	(.setWindow line 0 hop)
+	(addtasks oa line)
+	(set! _lineout line)
+	(set! set-step (lambda (h)
+		(.setHop oa h)
+		(.setWindow line 0 h)))
+	line)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/midi.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,59 @@
+(import "samer.midi.*")
+
+(define (tomidi in)
+	(letrec (
+			(nout 49)	; room for 4 octaves
+			(patch (Matrix. "Synth" nout (.size in)))
+			(out (VVector. "sout" nout))
+			(trigger (Trigger. out 1.0)) ; could use Latch instead
+			(events (.output trigger))
+			(synth (MidiSynth. events)))
+
+		(addtasks
+		  (MatrixTimesVector. out patch in)
+		  trigger synth)
+
+		(matexec patch "load")
+		(exec synth "open")
+		(expose synth)
+		synth
+	)
+)
+
+; (import "javax.sound.midi.*")
+
+; (define _synth null)
+; (define (synth) (set! _synth (javax.sound.midi.MidiSystem.getSynthesizer)))
+; (define (c0) (vector-ref (.getChannels _synth) 0))
+; (define (open) (.open _synth))
+; (define (close) (.close _synth))
+; (define (on pitch) (.noteOn (c0) pitch 80))
+; (define (off pitch) (.noteOff (c0) pitch 0))
+
+
+;; trigger midi events from a signal using an 2 sample window and
+;; an onset map.
+
+(define (midirec L)
+   (define sigwin (SignalWindow. L 2))
+   (define onset-map (OnsetMap. (.output sigwin)))
+   (define rec (MidiRecorderBase.))
+   (define imap (LinearMap. 128))
+   (define vel-map
+      (samer.core.util.VMap. imap (Node. "velmap")))
+
+   (matexec (.getBinMatrix onset-map) "load")
+   (Shell.exposeCommands rec)
+   (compound-task
+      sigwin
+      (.flushTask sigwin)
+      onset-map
+      (task
+         (if (.isOnset onset-map)
+            (.noteOn rec 0 (.clipInt imap (.get L)) 80)
+            ; (.noteOff rec 0 64)
+         )
+         (.tick rec)
+      )
+   )
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/modelbase.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,72 @@
+;;; these functions handle the model hierarchy: it is notionally
+;;; a multidimensional array. A particular model is a member of
+;;; the product space:
+;;; 	{ sampling-rate x {mono, stereo} x frame-size x ensemble x model-class }
+;;; sampling-rate in { 11kHz, 22kHz, 44kHz }
+;;; frame-size is an integer
+;;; ensemble denotes the set of audio files used to train the model
+;;; model-class is eg, ICA, Gaussian, etc.
+;;; The model classes may have a taxonomic hierarchy, eg, 
+;;;    Gaussian: full covariance, spherical, diagonal, PCA
+;;; and may have finer refinements, eg
+;;;    ICA with exponential prior, cauchy prior, generalised exponential
+;;; In addition, there may be different instances of each model,
+;;; trained at different times using a different realisation of the 
+;;; ensemble.
+;;;
+;;; Of-course, the file system doesn't support multidimensional arrays or
+;;; product spaces: only strict hierarchies, so there needs to be a mapping
+;;; between the two. The order in which the dimensions are arranged is somewhat
+;;; arbitrary and invovles replication of directory names. Hence, these
+;;; functions to automate the whole thing.
+
+(define root "models")		; root defaults to "models" in current directory
+(define (_rate rate)			; return path component for rate
+	(string-append (.toString rate) "kmono"))
+
+(define (_frame fr)
+	(string-append "x" (.toString fr)))
+		
+
+(define (model-path rate frame data class)
+	(define / "/")		; path separator
+	(string-append 
+		root / 
+		(_rate rate) / 
+		data /  
+		(_frame frame) /
+		class /
+	)
+)
+
+;; set up environment for running given model
+(define (push-model rate x class data)
+
+	; compose path for properties file
+	(define model-props (cat (model-path rate (.size x) data class) "args"))		
+	
+	; create new properties object for persistent properties
+	;(define model-env (samer.core.util.Properties. (env) (Node. class (.getNode x))))
+	(define model-env (samer.core.util.Properties. (env) (.getNode x)))
+	
+	; load any previously saved properties
+	(.load model-env (java.io.FileInputStream. model-props))
+	
+	; push an environment for non-persistent objects, with the properties as parent
+	(Shell.push (samer.core.util.HashMap. model-env))	
+	(put "props-file" model-props)		; save the properties file name for later
+	
+	;; should we load a model script here?
+)
+
+(define (pop-model)
+	; current environment should be a  HashMap containing "props-file"
+	; it's parent should be a Properties environment 
+	; so we save the parent environment to the recovered file
+	(.save (.parent (env)) (java.io.FileOutputStream. (get "props-file")))
+	(Shell.pop)		; this will unlink and discard both environments
+)
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/models.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,225 @@
+(import "samer.models.*")
+
+(define vec VVector.)
+
+; prior-spec: (name constructor mk-trainer batch flush-tasks)
+(define (iid-spec logprior)  `("iid" ,(lambda (n) (IIDPrior. n logprior))))
+(define genexp-spec `("genexp" 	,samer.models.GeneralisedExponential. ,.getTrainer 128))
+(define cauchy-spec `("cauchy"	,(lambda (n) (IIDPrior. n (LogCauchy.)))))
+(define gauss-spec  `("gauss" 	,(lambda (n) (IIDPrior. n (HalfSquare.)))))
+(define laplace-spec `("laplace" ,(lambda (n) (IIDPrior. n (Abs.)))))
+(define ica-spec	`("ica" ,ICA. .getTrainer 512))
+(define a-gauss-spec  `("gauss" 	,(lambda (n) (AlignedGaussian. n))))
+
+
+;;; macro for extracting things from a model-spec
+(define-macro (let-model name const train spec . body)
+	`(let ((,name (car ,spec)) (,const (cadr ,spec)) (,train (cddr ,spec)))
+			. ,body))
+
+
+;; what about flush tasks?
+(define (maybe-train model train)
+  (if (not (null? train))
+    (let ((trainer (BatchedTrainer. ((car train) model) (cadr train)))
+	         (post-flush (caddr train)))
+    	(addtask trainer)
+	   (if (not (null? post-flush))
+			(.setPostFlush trainer post-flush)))))
+
+;;; this is a sort of model combinator
+
+(define (chain-2 x spec-1 spec-2)
+  (let-model name-1 cons-1 train-1 spec-1
+  (let-model name-2 cons-2 train-2 spec-2
+	 (node name-1
+		(let* ((model-1 (cons-1 x))
+			 	 (model-2	(node name-2 (cons-2 (.output model-1)))))
+		  (.setOutputModel model-1 model-2)
+		  (addtasks model-1 model-2)
+		  (node name-2 (maybe-train model-2 train-2))
+		  (maybe-train model-1 train-1)
+		  (list model-1 model-2))))))
+
+(define (scaler-spec . training-spec)
+	(append `("scaler" ,Scaler.) training-spec))
+
+(define (mk-scaler x prior . trainer)
+  (node (.getNode x)
+    (let ((models (chain-2 x (apply scaler-spec trainer) prior)))
+	   (.output (car models)))))
+
+
+(define (mk-diffscaler x prior . trainer)
+  (node (.getNode x)
+    (chain-2 x (append `("diffScaler" ,DiffScaler.) trainer) prior)))
+
+
+;;; these are the old methods defined in terms of the above
+(define (norm in) (mk-scaler in laplace-spec .getTrainer 8))
+(define (offset in) (mk-scaler in laplace-spec .getOffsetTrainer 8))
+(define (nonorm in) (mk-scaler in laplace-spec))
+(define (diffnorm x prior) (.output (car (mk-diffscaler x prior .getTrainer 16))))
+(define (diffscale x prior) (.output (car (mk-diffscaler x prior .getScaleTrainer 16))))
+(define (diffoffset 	x prior) (.output (car (mk-diffscaler x prior .getOffsetTrainer 16))))
+(define (smoothscale	x prior)	(.output (car (mk-diffscaler x prior .getTensionedTrainer 16))))
+
+
+;;;; ........... ICA ............
+
+; trainers: .getTrainer
+; trainers: .getDecayWhenActiveTrainer
+(define (ica-spec . training-spec)
+	(let ((ica-cons
+   	(lambda (x)
+  			(let ((ica (ICA. (cur-node) (.size x))))
+				(.setInput ica x)
+				(Shell.registerViewable ica)
+				ica))))
+    `("ica" ,ica-cons . ,training-spec)))
+
+
+(define (mk-ica x prior . trainer)
+  (node (.getNode x)
+	 (if (null? trainer)
+		(car (chain-2 x (ica-spec) prior))
+		(car (chain-2 x (ica-spec (car trainer) (.size x)) prior)))))
+
+
+ ; auto: load weights, basis rowcolumn viewer
+;	(matexec (.getWeightMatrix ica) "load")
+;	(matexec (.getBasisMatrix ica) "rowcolumn")
+
+; flush tasks:
+;		(exec ica "basis")
+;		(exec ica "logdet")
+;		(exec basis "save")
+;		(ICAScalerSync.) (for 3 model version)
+
+
+; trainers: .getScaleTrainer
+; trainers: .getDiffTrainer
+; (define (mk-ica-scaler x prior trainer)
+;   (node (.getNode x)
+;     (let ((models (chain-2 x `("ica" ,ICAWithScaler. ,trainer ,(.size x)) prior)))
+; 	 	(Shell.registerViewable (car models))
+; 	   (.output (car models)))))
+
+;		(.diffFlush trainer)				; (more frequent)
+
+
+
+(define (histogram vec bins)
+	(define hist (node (.getNode vec) (Histogram. vec bins)))
+	;(addtask hist)
+	hist)
+
+
+(define (chain-3 x spec-1 spec-2 spec-3)
+  (let-model name-1 cons-1 train-1 spec-1
+  (let-model name-2 cons-2 train-2 spec-2
+  (let-model name-3 cons-3 train-3 spec-3
+	 (node name-1
+		(let* ((model-1 (cons-1 x))
+			 	 (model-2	(node name-2 (cons-2 (.output model-1))))
+				 (model-3 	(node name-2 (node name-3 (cons-3 (.output model-2))))))
+		  (.setOutputModel model-1 model-2)
+		  (.setOutputModel model-2 model-3)
+		  (addtasks (task
+		  		(.infer model-1)
+		  		(.infer model-2)
+		  		; (.infer model-3)
+				; this is wrong - only need to compute if training
+		  		(.compute model-3)
+		  		(.compute model-2)))
+				; no need to compute model 1 if there is no model 0
+		  (maybe-train model-1 train-1)
+		  (node name-2 (maybe-train model-2 train-2))
+		  (node name-2 (node name-3 (maybe-train model-3 train-3)))
+		  (list model-1 model-2 model-3)))))))
+
+;; flush tasks for model 1/2 trainers?
+	'(sub 32 (seq
+		(ICAScalerSync. ica scaler)
+		(task (exec ica "basis"))))
+
+;;;; Mixture models
+
+(define (mix-2 x spec-1 spec-2)
+  (let-model name-1 cons-1 train-1 spec-1
+  (let-model name-2 cons-2 train-2 spec-2
+  (let* ((model-1 (node name-1 (cons-1 x)))
+  			(model-2	(node name-2 (cons-2 x)))
+			(mixture (Mixture. x 2))
+			(trainer (.getTrainer mixture)))
+		(.setModel M 0 model-1)
+		(.setModel M 1 model-2)
+		(.setTrainer trainer 0 (.getTrainer model-1))
+		(.setTrainer trainer 0 (.getTrainer model-2))
+		(addtasks 
+			(task
+				(.infer model-1) (.compute model-1)
+				(.infer model-2) (.compute model-2)
+				(.infer mixture))
+				(BatchedTrainer. trainer 4))))))
+		
+
+
+
+;;;; Noisy ICA
+
+(import "samer.maths.opt.*")
+
+(define (std-opt s opt)
+	(put "optimiser" opt)
+	(expose (.getViewer opt) "optimiser")
+	(seq (GenerateVector. s (Zero.)) opt))
+
+
+(define (uqn-optimiser s fn) (std-opt s (UnconstrainedMinimiser. s fn)))
+(define (ucg-optimiser s fn) (std-opt s (UnconstrainedConjGrad. s fn)))
+(define (pos-optimiser s fn) (std-opt s (ConstrainedMinimiser. s fn Positivity.class)))
+(define (zc-optimiser s fn)
+	(Shell.put "ZeroCrossingSparsity.jump" (VDouble. "logprior.jump" 1.0))
+	(std-opt s (ConstrainedMinimiser. s fn ZeroCrossingSparsity.class)))
+
+
+(define (ica-cons m) (lambda (x)
+	(let ((ica (NoisyICA. (cur-node) (.size x) m)))
+		(.setInput ica x)
+		ica)))
+
+(define (noisyica input num-outs e-spec s-spec mk-optimiser)
+	(mk-noisyica input
+		`("noisyica" ,(ica-cons num-outs) ,.learnDecayWhenActive ,(.size input))
+		e-spec s-spec mk-optimiser))
+
+(define (noisyica-notrain input num-outs e-spec s-spec mk-optimiser)
+	(mk-noisyica input
+		`("noisyica" ,(ica-cons num-outs) )
+		e-spec s-spec mk-optimiser))
+
+(define (mk-noisyica input ica-spec e-spec s-spec mk-optimiser)
+	; x: input vector
+	(let-model  ica-name ica-cons ica-train ica-spec
+	(let-model e-name e-cons e-train e-spec
+	(let-model s-name s-cons s-train s-spec
+	(node ica-name
+		(letrec (	(ica	 		(ica-cons input))
+							(s-model (node "s"(s-cons (.output ica))))
+							(e-model (node "e" (e-cons (.error ica)))))
+
+			(.setSourceModel ica s-model)
+			(.setNoiseModel  ica e-model)
+			(.setInferenceTask ica (mk-optimiser (.output ica) (.posterior ica)))
+;			(on-change (.basisMatrix ica)
+;				(.setHessian (get "optimiser")
+;					(.inverse (.times (.transpose A) A))))
+
+			(addtasks ica e-model s-model)
+			(maybe-train ica ica-train)
+			(node "e" (node e-name (maybe-train e-model e-train)))
+			(node "s" (node s-name (maybe-train s-model s-train)))
+
+			(list ica e-model s-model)))))))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/newica.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,33 @@
+(import "samer.models.*")
+
+(define (newica x)
+	(define ica (ICA. x))
+	(define scaler (DiffScaler. (.output ica)))
+	(define genexp (GeneralisedExponential. (.output scaler)))
+
+	;;; Training
+	(define t-scaler (BatchedTrainer. (.getScaleTrainer scaler) 4))
+	(define t-genexp (BatchedTrainer. (.getTrainer genexp) 256))
+	(define t-ica    (BatchedTrainer. (.getTrainer ica) (.size x)))
+
+	(.setOutputModel ica scaler)
+	(.setOutputModel scaler genexp)
+
+	;;; resync and compute basis every 16 ICA updates
+	(.setFlushTask t-ica
+		(sub 32 (seq
+			(ICAScalerSync. ica scaler)
+			(task (exec ica "basis")))))
+
+	;;; Runnable tasks
+	(addtasks
+		ica
+		scaler
+		genexp
+		(task (.compute scaler))
+		t-genexp t-scaler t-ica
+	)
+
+	;;; return all bits and pieces
+	(list ica scaler genexp t-ica t-scaler t-genexp)
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/old/audio.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,79 @@
+;(import "javax.sound.sampled.*")
+
+;;; getting mixers
+(define (get-mixers)	(vector->list (javax.sound.sampled.AudioSystem.getMixerInfo)))
+(define (pr-mixers) (print (get-mixers)))
+(define (mixer mi) (javax.sound.sampled.AudioSystem.getMixer mi))
+(define (mixer-n n) (mixer (list-ref (get-mixers) n)))
+(define (default-mixer) (mixer-n (Shell.getInt "mixer" 1)))
+
+
+
+;;; formats
+(define (mono rate) (multi 1 rate))
+(define (stereo rate) (multi 2 rate))
+(define (multi chans rate) (format 16 chans rate))
+(define (format bits chans rate) (javax.sound.sampled.AudioFormat. (.floatValue rate) bits chans #t #f))
+
+;;; construct line info from given format
+(define (target format)
+	(javax.sound.sampled.DataLine$Info.
+		javax.sound.sampled.TargetDataLine.class format))
+
+(define (source format)
+	(javax.sound.sampled.DataLine$Info.
+		javax.sound.sampled.SourceDataLine.class format))
+
+;;; these two just return the first target/source line info respectively
+;;; (define (target-info m) (vector-ref (.getTargetLineInfo m) 0))
+;;; (define (source-info m) (vector-ref (.getSourceLineInfo m) 0))
+
+;;; getting line from info and optional mixer
+(define-method (line info) (javax.sound.sampled.AudioSystem.getLine info))
+(define-method (line mixer info) (.getLine mixer info))
+
+;;; these two just return the mixer's first target/source line respectively
+(define (target-line m) (line m (vector-ref (.getTargetLineInfo m) 0)))
+(define (source-line m) (line m (vector-ref (.getSourceLineInfo m) 0)))
+
+(define _src samer.audio.LineSource.)
+(define _snk samer.audio.LineSink.)
+(define (_op1 l) (.open l) l)
+(define (_op2 l fmt) (.open l fmt) l)
+
+(define-method (linesrc) 					(_op1 (_src)))
+(define-method (linesrc fmt) 			(_op1 (_src (line (target fmt)))))
+(define-method (linesrc m fmt)		(_op2 (_src (target-line m)) fmt))
+(define-method (linesnk fmt) 			(_op1 (_snk (line (source fmt)))))
+(define-method (linesnk m fmt)		(_op2 (_snk (source-line m)) fmt))
+
+;; to do: buffer size?
+;; integrate with LineSource.defaultLine and VLine.defaultFormat
+;; specify default mixer in user.props
+
+(define (display-mixer m)
+	(print "\n **************************** \n")
+	(print (.getMixerInfo m))
+;	(print "\n---controls:") (print(.getControls m))
+	(print "\n---source line info:") (print(.getSourceLineInfo m))
+	(print "\n---target line info:") (print(.getTargetLineInfo m))
+;	(print "\n---source lines:") 		(print(.getSourceLines m))
+;	(print "\n---target lines:") 		(print(.getTargetLines m))
+	#null
+)
+
+;; default line in
+(define-method (linein size step) (linein (linesrc) size step))
+
+
+;;; Format conversion
+(define (convert format stream)
+	(javax.sound.sampled.AudioSystem.getAudioInputStream format stream))
+
+;;; get audio input stream from file object
+(define-method (astream (f java.io.File)) 
+	(javax.sound.sampled.AudioSystem.getAudioInputStream f))
+
+;;; get audio input stream from named file
+(define-method (astream (fn String))  (astream (java.io.File. fn)))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/old/genfilter.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,112 @@
+;;; Preamble
+(load "audio.scm")
+(load "lineout.scm")
+(load "functions.scm")
+
+(import "samer.mds.*")
+
+;;; transfer filter fn to vector of values
+(define (set-filter F fn)
+	(define f (.mat F))
+	(for-each
+		(lambda (i) (.set f 0 i (fn i)))
+		(range 0 N))
+	(.changed F)
+)
+
+;; convert vector of values into a filter fn
+(define (filter-fn F)
+	(let ((mat (.mat F)))
+		(lambda (i) (.get mat 0 i))))
+
+;; returns fn f(i) that returns 1 if d'th coordinate of P(i) <op> th
+;; eg (coor-test P 2 > 0.5) is function which returns P(i,2) > 0.5
+(define (coor-test P d op th)
+	(lambda (i) (if (op (.get P i d) th) 1.0 0.0)))
+
+
+;;; set up tasks for ICA domain filtering using f as a function
+;;; which returns (f i) as the scaling factor for the ith ICA component
+;;; source is an AudioSource.
+(define (direct-recon source N hop f)
+	(define x (linein source N hop))
+	(define W (Matrix. "W" N N))		; ICA matrix
+	(define K (Matrix. "K" N N))			; total filtering matrix
+	(define z (VVector. "z" N))				; reconstruction
+	(addtask (Ops.times z K x) (Ops.update z))
+	(overlap-and-add z hop)
+	(on-change W (.assign K (total-matrix W f)))
+	(matexec W "load")
+)
+
+(define (ica-recon s A sink hop)
+	(define F (VVector. "F" N))			; the source domain filter
+	(define z (VVector. "z" N))
+	(addtasks (Ops.timesEquals s F) (Ops.times z A s))
+	(overlap-and-add sink z hop))
+
+
+(define (recon source N hop sink)
+	(define x (norm (linein source N hop)))
+	(define ica (mk-ica x laplace-spec))
+	(define s (.output ica))
+	(define F (VVector. "F" N))			; the source domain filter
+	(define W (.getWeightMatrix ica))
+	(define A (.getBasisMatrix ica))
+	(define z (VVector. "z" N))
+	(define order (Matrix. "order" 5 512))
+
+	(addtasks (Ops.timesEquals s F) (Ops.times z A s))
+	(overlap-and-add sink z hop)
+
+	(on-change W (exec ica "basis"))
+	(matexec W "load")
+)
+
+;; returns total transformation matrix  formed by filtering
+;; in the ICA domain. f is a function which returns the scaling
+;; factor for the i'th component, ie (f i) is a scalar.
+(define (total-matrix W f)
+	(define D (Jama.Matrix. N N 0.0))
+	(for-each
+		(lambda (i) (.set D i i (f i)))
+      (range 0 N))
+	(.times (.inverse W) (.times D W))
+)
+
+; eg (total-matrix W (coor-test P 1 > 0.0))
+; filters out all components whos MDS y-coor <= 0
+
+;; transfer values from G to F reordered by order
+(define-method (rank-filter F order G)
+	(rank-filter F order G 0 (.size G)))
+
+(define-method (rank-filter F order G start end)
+	(Mathx.set F (Zero.))
+	(let ((f (.mat F)) (g (.mat G)) (I (.mat order)))
+		(for-each
+			(lambda (i) (.set f 0  (.get I 0 i)  (.get g 0 i)))
+			(range start end)))
+	(.changed F)
+)
+
+;;; filter is a certain spherically symmetric kernel centred on
+;;; a particular component. Geometry directly from correlation
+;;; matrix (not from MDS configuation)
+(define (proximity-filter R F fn)
+	(ProximityFilter. R F (VFunction. "proximity kernel" fn)) f)
+
+(define (geometric-filter P f)
+	(define n (.getRowDimension P))
+	(define E (.getColumnDimension P))
+	(define off (VDouble. "offset" 0.0))
+	(define norm	(VVector. "normal" E))
+	(define hp	(LogisticHyperplane. (.array norm) (.value$ off)))
+	(define gf		(GeometricFilter. P f hp))
+	(define obs (observer (.setOffset hp (.value$ off)) (.run gf) (.changed f)))
+	(.addObserver P obs)
+	(.addObserver off obs)
+	(.addObserver norm obs)
+	f)
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/old/lineout.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,68 @@
+(define set-step null)
+(define line-on null)
+(define line-off null)
+(define _lineout null)
+
+(define-method (overlap-and-add x hop)
+	(define oa  (OverlapAndAdd. x hop))
+	(define line (LineOut. (.output oa)))
+	(.setWindow oa (Hanning.))
+	(.setWindow line 0 hop)
+	(addtasks oa line)
+	(set! _lineout line)
+	(set! set-step (lambda (h)
+		(.setHop oa h)
+		(.setWindow line 0 h)))
+)
+
+(define-method (overlap-and-add sink x hop)
+	(define oa  (OverlapAndAdd. x hop))
+	(.setWindow oa (Hanning.))
+	(addtasks oa (.writer sink (.array (.output oa)) 0 hop))
+)
+
+(define-method (lineout (linein LineIn))
+	(put "audio.scale" 1.0)
+	(let ((lineout (LineOut. (.output linein))))
+		(.setWindow lineout 0 (.getStep linein))
+		(set! set-step (lambda (n)
+			(.setStep linein n)
+			(.setWindow lineout 0 n)))
+		(set! line-on (lambda ()
+			(.starting lineout)
+			(Thread.sleep 200L)
+			(addafter linein lineout)))
+		(set! line-off (lambda ()
+			(remove lineout)
+			(.stopping lineout)
+			(Thread.sleep 200L)))))
+
+(define-method (lineout (in Vec))
+	(let ((lineout (LineOut. in) (n (.size in)))
+			(tasklist (tasks)))
+		(set! set-step (lambda (m)
+			(.setWindow lineout (- n m) n)))
+		(set! line-on (lambda ()
+			(.starting lineout)
+			(Thread.sleep 200L)
+			(.addTask tasklist lineout)))
+		(set! line-off (lambda ()
+			(.removeTask tasklist lineout)
+			(.stopping lineout)
+			(Thread.sleep 200L)))))
+
+(define-method (lineout n)
+	(put "audio.scale" 32767.0)
+	(let (	(lineout (LineOut. n)))
+		(set! set-step (lambda (m)
+			(.setWindow lineout (- n m) n)))
+		(set! line-on (lambda ()
+			(.starting lineout)
+			(Thread.sleep 200L)
+			(addtask lineout)))
+		(set! line-off (lambda ()
+			(remove lineout)
+			(.stopping lineout)
+			(Thread.sleep 200L)))))
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/old/shell.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,172 @@
+(display "loading shell.silk\n")
+
+(import "samer.core.*")
+(import "samer.core.types.*")
+(import "samer.silk.*")
+
+(define true #t)
+(define false #f)
+
+
+(define (for-it proc it)
+	(if (.hasNext it)
+		(begin
+			(proc (.next it))
+			(for-it proc it))))
+
+
+;;; directory handling
+
+(define (abs-path path) (.getCanonicalPath (java.io.File. path)))
+(define (pwd) (abs-path "."))
+;(define .. "..")
+(define (cd dir)
+	(System.setProperty "user.dir" (abs-path dir))
+	(System.getProperty "user.dir"))
+(define (ls . paths)
+	(array->list (.listFiles (java.io.File.
+		(if (null? paths) "." (first paths))
+	))))
+
+(define (filter p? l) (reverse (filter-rev p? l ())))
+(define (filter-rev p? l a)
+	(if (null? l) a
+		(let ((h (car l)) (t (cdr l)))
+			(if (p? h)
+				(filter-rev p? t (cons h a))
+				(filter-rev p? t a)))))
+
+(define push Shell.push)
+(define pop Shell.pop)
+(define env Shell.env)
+(define cat string-append)
+
+(define (pr-env)
+	(for-it
+		(lambda (b)
+			(display (.name b))
+			(display "=")
+			(write (.get b X.ObjectCodec$ null))
+			(display "\n"))
+		(.data (Shell.env))))
+
+
+(define (vbls) (.getViewables (get "ViewableManager")))
+(define (pr-vbls)
+	(for-it
+		(lambda (v)
+			(display (.toString (.getNode v)))
+			(newline))
+		(vbls)))
+
+(define (it->list it)
+	(define (accum it list)
+		(if (not (.hasNext it))
+			list
+			(accum it (cons (.next it) list))))
+	(reverse (accum it ())))
+
+(define (view-vector L name)
+	(Shell.expose (javax.swing.JScrollPane. (javax.swing.JList. L)) name)
+	null)
+
+(define (view-list L name) (view-vector (list->vector L) name))
+
+(define (print l)
+	(define (print-list l n)
+		(if (null? l)
+			(newline)
+			(begin
+				(display (cat (number->string n) ": " (first l)))
+				(newline)
+				(print-list (rest l) (+ n 1)))))
+	(if (list? l)
+		(print-list l 0)
+		(if (vector? l)
+			(print (vector->list l))
+			(begin (display l) (newline))
+		)
+	)
+)
+
+;;; ------------ some macros ------------
+
+(define node (macro (name . body)
+	`(begin
+		(Shell.push ,name)
+		(let ((a
+			(tryCatch
+				(begin . ,body)
+				(lambda (ex) (Shell.pop) (throw ex)))))
+			(Shell.pop)
+			a))))
+
+; ; (define node (macro (name . body)
+; ; 	`(let*	(	(a (Shell.push ,name))
+; ; 					(b (begin . ,body))		)
+; ; 		(Shell.pop) b
+; ; 	))
+; ; )
+
+;;; this creates a named node as a child of (.getNode parent)
+(define (child parent name) (Node. name (.getNode parent)))
+
+;;; alternative version
+;(define node (macro (name . body)
+;	`(Shell.push ,name)
+;	`(let ((b (begin . ,body)))
+;		(Shell.pop) b)
+;))
+
+(define observer (macro body `(samer.silk.SilkObserver. (lambda (o a) ,@body))))
+(define on-change (macro (o . body)
+	`(.addObserver ,o (samer.silk.SilkObserver. (lambda (o a) ,@body)))
+))
+
+;;; ---------------------------------------
+
+(define-method (exec (agent Agent) cmd) (.execute agent cmd (Shell.env)))
+(define-method (exec (vbl Viewable) cmd) (.execute (.getAgent vbl) cmd (Shell.env)))
+(define-method (exec (mat samer.maths.Matrix) cmd) (.execute (.getAgent mat) cmd (Shell.env)))
+(define (matexec matrix cmd) (exec (samer.maths.MatrixAgent. matrix) cmd))
+
+(define (viewable name) (.getViewable (get "ViewableManager") (.abs (Shell.env) name)))
+(define (edit-vbl vbl)
+	(Shell.showDialogFor
+		(.getComponent (.getViewer vbl))
+		(.getLabel vbl)))
+
+(define (cur-node) (.node (env)))
+(define (set nm vl) (X.store nm vl))
+(define (put nm vl) (Shell.put nm vl))
+(define (get nm) (Shell.get nm))
+(define (interp cmd) (display "**** deprecated ****\n") 
+	(.dispatch (get "AgentManager") cmd (Shell.env)))
+(define (pr-viewables)	(.listViewables (get "ViewableManager")))
+(define (exit) 		(.dispatch (get "AgentManager") "exit" (Shell.env)))
+(define-method (expose) (.dispatch (get "AgentManager") "expose" (Shell.env)))
+(define-method (expose (name String)) (Shell.expose (viewable name)))
+(define-method (expose (vbl Viewable)) (Shell.expose (.getViewer vbl) (.fullName (.getNode vbl))))
+(define-method (expose (vwr Viewer) (name String)) (Shell.expose vwr name))
+
+; another kind of store
+;(define (store nm obj) (.store (Shell.env) nm obj X.StringCodec$))
+
+(define (hclicker canvas_name rcname)
+	(define rc (viewable rcname))
+	(define cl (Clicker. (get canvas_name) (+ (.getMax rc) 1) 1))
+	(.setXReceiver cl rc))
+
+(define (vclicker canvas_name rcname)
+	(define rc (viewable rcname))
+	(define cl (Clicker. (get canvas_name) 1 (+ (.getMax rc) 1)))
+	(.setYReceiver cl rc))
+
+
+;; buffering input. Always using this so put here
+(define-method (linein size step) (linein (samer.audio.LineSource.) size step))
+(define-method (linein (source samer.audio.AudioSource) size step)
+	(define line (LineIn. source size step))
+	(put "LineIn" line)
+	(addtask line)
+	(.output line) )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/old/synthesis.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,52 @@
+(import "samer.maths.random.*")
+(load "lineout.scm")
+
+; sets the Generator of a VGenerator to one
+; constructed in it's own context.
+(define (load-generator gen)
+	(letrec ((nd (.getNode gen))
+		(spec (Shell.getString (.fullName nd)))
+		(g (node nd (eval-string spec))) )
+		(.setGenerator gen g)
+	)
+)
+
+
+(define (filter-gen filt gen) (FilteredGenerator. gen filt))
+(define (gen->vector gen n)
+  (define x (VVector. (cat "buffer(" (.toString gen) ")") n))
+  (define t (GenerateVector. x gen))
+  (addtask t)
+  x)
+
+(define (specsynth in N M)
+  (define filter (SpectralFilter. in N))
+  (addtask filter)
+  ;(gen->vector (filter-gen filter (VGenerator. "source" (Binary.))) M))
+  (gen->vector (filter-gen filter (BipolarUniform.)) M )
+)
+
+(define (specsynth-async in N M)
+  (define filter (SpectralFilter. in N))
+  (addtask filter)
+  (node "synth"
+	  (put "regulator.thread.priority" -0.1)
+	  (let ((new-tasks  (CompoundTask.)))
+	    (RThread. new-tasks)
+		 (with-tasks new-tasks
+			 (gen->vector (filter-gen filter (NormalisedGaussian. ))  M))
+	  )))
+
+(define (synth2 ft mag hop)
+  (define ift (RescaledIFT. ft mag))
+  (addtask ift)
+  (overlap-and-add (.output ift) hop))
+
+ ;;; this generates a white noise signal modulated by
+;;; another signal E
+
+(define (noise-resynth E N)
+	(define buf (gen->vector samer.maths.random.NormalisedGaussian.))
+	(addtask (task (Mathx.mul (.array buf) (- (.get E) 200))))
+	(lineout buf)
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/props.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,26 @@
+; __________________________________________
+; open local args file and push on to environment stack
+; this will now accept all stored data. also adds agent to
+; save on exit.
+
+(define local-props null)
+(define local-file null)
+(define (push-properties file)
+	(set! local-props (samer.core.util.Properties. (Shell.env)))
+	(set! local-file file)
+	(tryCatch
+		(.load local-props (java.io.FileInputStream. file))
+		(lambda (e) (Shell.trace (string-append "failed to load"))))
+	(Shell.push local-props)
+
+	;;; this changes to global exit procedure to save the local
+	;;; properties as well as the regular properties
+	(set! exit (lambda ()
+		(display (string-append "saving local properites to " local-file))
+		(.save local-props (java.io.FileOutputStream. local-file))
+		(Shell.interpret "exit")
+		(System.exit 0)
+	))
+)
+
+ 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/readline.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,27 @@
+;;; sets up java readline to provide command line
+;;; editting, history, and completion for jscheme.
+
+; redirect input to readline reader
+;(define (set-input-port port) (set! jsint.Scheme.input$ port))
+
+(define (readline-reader prompt) 
+	(org.gnu.readline.ReadlineReader. prompt
+		org.gnu.readline.ReadlineLibrary.GnuReadline$))
+
+(org.gnu.readline.Readline.initReadline "jscheme")
+(org.gnu.readline.Readline.readInitFile "/Users/samer/.inputrc")
+(set! current-readline-reader (readline-reader ":"))
+(.setInput (jsint.Scheme.currentEvaluator) (jsint.InputPort. current-readline-reader))
+(define (set-prompt prompt) (.setPrompt current-readline-reader prompt))
+
+		
+; this seems to stop terminal getting confused after exit
+(.addShutdownHook (Runtime.getRuntime)
+	(Thread. (lambda () 
+		(display "cleaning up readline.\n")
+		(org.gnu.readline.Readline.cleanup))))
+		
+
+; enable completion by looking up words in jscheme's symbol table
+(org.gnu.readline.Readline.setCompleter (samer.silk.SilkCompleter.))
+(set-prompt ">")			 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/scheme-client.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,8 @@
+(define (readline prompt)
+	(org.gnu.readline.Readline.readline prompt)) 
+
+(define-method (connect h l) 
+	(samer.silk.Terminal.connect (java.net.Socket. h 2000) l))
+(define-method (connect h) 
+	(samer.silk.Terminal.connect (java.net.Socket. h 2000) readline))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/scheme-server.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,16 @@
+(display "Creating remote session server.\n")
+(define server (java.net.ServerSocket. 2000))
+
+(define (remote-repl s) 
+	(display "Waiting for connection...\n")
+	(let ((call (.accept s)))
+		(display (string-append "Received connection from " (.toString call) "\n"))
+		(.start (Thread. (lambda () (service call))))))
+
+
+(define (service call)
+	(display "Asynchronous REPL initiated.\n")
+	(samer.silk.Terminal.REPL call))
+
+(define (serve-for-ever) (remote-repl server) (serve-for-ever))
+(.start (Thread. serve-for-ever))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/shell.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,160 @@
+(import "samer.core.*")
+(import "samer.core.types.*")
+(import "samer.silk.*")
+
+(define true #t)
+(define false #f)
+
+
+(define (for-it proc it)
+	(if (.hasNext it)
+		(begin
+			(proc (.next it))
+			(for-it proc it))))
+
+
+;;; directory handling
+
+(define (abs-path path) (.getCanonicalPath (java.io.File. path)))
+(define (pwd) (abs-path "."))
+;(define .. "..")
+(define (cd dir)
+	(System.setProperty "user.dir" (abs-path dir))
+	(System.getProperty "user.dir"))
+(define (ls . paths)
+	(array->list (.listFiles (java.io.File.
+		(if (null? paths) "." (first paths))
+	))))
+
+(define (filter p? l) (reverse (filter-rev p? l ())))
+(define (filter-rev p? l a)
+	(if (null? l) a
+		(let ((h (car l)) (t (cdr l)))
+			(if (p? h)
+				(filter-rev p? t (cons h a))
+				(filter-rev p? t a)))))
+
+;(define push Shell.push)
+;(define pop Shell.pop)
+(define env Shell.env)
+(define cat string-append)
+
+(define (pr-env)
+	(for-it
+		(lambda (b)
+			(display (.name b))
+			(display "=")
+			(write (.get b X.ObjectCodec$ null))
+			(display "\n"))
+		(.data (Shell.env))))
+
+
+(define (vbls) (.getViewables (get "ViewableManager")))
+(define (pr-vbls)
+	(for-it
+		(lambda (v)
+			(display (.toString (.getNode v)))
+			(newline))
+		(vbls)))
+
+(define (it->list it)
+	(define (accum it list)
+		(if (not (.hasNext it))
+			list
+			(accum it (cons (.next it) list))))
+	(reverse (accum it ())))
+
+(define (view-vector L name)
+	(Shell.expose (javax.swing.JScrollPane. (javax.swing.JList. L)) name)
+	null)
+
+(define (view-list L name) (view-vector (list->vector L) name))
+
+(define (print l)
+	(define (print-list l n)
+		(if (null? l)
+			(newline)
+			(begin
+				(display (cat (number->string n) ": " (first l)))
+				(newline)
+				(print-list (rest l) (+ n 1)))))
+	(if (list? l)
+		(print-list l 0)
+		(if (vector? l)
+			(print (vector->list l))
+			(begin (display l) (newline))
+		)
+	)
+)
+
+;;; ------------ some macros ------------
+
+(define node (macro (name . body)
+	`(begin
+		(Shell.push ,name)
+		(let ((a
+			(tryCatch
+				(begin . ,body)
+				(lambda (ex) (Shell.pop) (throw ex)))))
+			(Shell.pop)
+			a))))
+
+; ; (define node (macro (name . body)
+; ; 	`(let*	(	(a (Shell.push ,name))
+; ; 					(b (begin . ,body))		)
+; ; 		(Shell.pop) b
+; ; 	))
+; ; )
+
+;;; this creates a named node as a child of (.getNode parent)
+(define (child parent name) (Node. name (.getNode parent)))
+
+;;; alternative version
+;(define node (macro (name . body)
+;	`(Shell.push ,name)
+;	`(let ((b (begin . ,body)))
+;		(Shell.pop) b)
+;))
+
+(define observer (macro body `(samer.silk.SilkObserver. (lambda (o a) ,@body))))
+(define on-change (macro (o . body)
+	`(.addObserver ,o (samer.silk.SilkObserver. (lambda (o a) ,@body)))
+))
+
+;;; ---------------------------------------
+
+(define-method (exec (agent Agent) cmd) (.execute agent cmd (Shell.env)))
+(define-method (exec (vbl Viewable) cmd) (.execute (.getAgent vbl) cmd (Shell.env)))
+(define-method (exec (mat samer.maths.Matrix) cmd) (.execute (.getAgent mat) cmd (Shell.env)))
+(define (matexec matrix cmd) (exec (samer.maths.MatrixAgent. matrix) cmd))
+
+(define (viewable name) (.getViewable (get "ViewableManager") (.abs (Shell.env) name)))
+(define (edit-vbl vbl)
+	(Shell.showDialogFor
+		(.getComponent (.getViewer vbl))
+		(.getLabel vbl)))
+
+(define (cur-node) (.node (env)))
+(define (set nm vl) (X.store nm vl))
+(define (put nm vl) (Shell.put nm vl))
+(define (get nm) (Shell.get nm))
+(define (pr-viewables)	(.listViewables (get "ViewableManager")))
+(define (exit) 		(.dispatch (get "AgentManager") "exit" (Shell.env)))
+(define-method (expose) (.dispatch (get "AgentManager") "expose" (Shell.env)))
+(define-method (expose (name String)) (Shell.expose (viewable name)))
+(define-method (expose (vbl Viewable)) (Shell.expose (.getViewer vbl) (.fullName (.getNode vbl))))
+(define-method (expose (vwr Viewer) (name String)) (Shell.expose vwr name))
+
+; another kind of store
+;(define (store nm obj) (.store (Shell.env) nm obj X.StringCodec$))
+
+(define (hclicker canvas_name rcname)
+	(define rc (viewable rcname))
+	(define cl (Clicker. (get canvas_name) (+ (.getMax rc) 1) 1))
+	(.setXReceiver cl rc))
+
+(define (vclicker canvas_name rcname)
+	(define rc (viewable rcname))
+	(define cl (Clicker. (get canvas_name) 1 (+ (.getMax rc) 1)))
+	(.setYReceiver cl rc))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/signals.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,41 @@
+;;; extract one component of a vector and put it in a VDouble
+(define-method (signal name) (VDouble. name))
+(define-method (signal vec i)
+	(node (.getNode vec)
+		(let ((sig (VDouble. (.toString i))))
+			(addtask (VectorToDouble. vec i sig))
+			sig
+		)
+	)
+)
+
+;;; lagged signal histogram
+(define (sig:hist sig)
+	(define sigwin (SignalWindow. sig 4 1))
+	(define hist (JointHistogram. (.output sigwin) 0 4))
+	(addtasks sigwin (.flushTask sigwin) hist)
+	(put "jointhist" hist)
+	hist
+)
+
+(define (sig:- bigE smallE dE)
+	(addtask (GenerateDouble. dE
+		(Difference. bigE smallE)))
+	dE
+)
+
+;;; make a task to write all sigs in siglist
+(define (sig:write base siglist)
+	;;; map a VDouble to a DoubleWriter
+	(define (sig->writer x)
+		(.mkdirs (java.io.File. base))
+		(DoubleWriter. x
+			(buffer (ofstream (cat base "/" (.getLabel x) ".txt")))
+			#f))
+
+	;;; now map all signals to writers and make CompoundTask
+	(apply seq (map sig->writer siglist))
+)
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/sockets.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+(define (make-server) (java.net.ServerSocket. 2000))
+(define (accept s) (display "waiting for connection...\n") (.accept s))
+(define (connect host) (display "connecting...\n") (java.net.Socket. host 2000))
+(define (istream s) (.getInputStream s))
+(define (ostream s) (.getOutputStream s))
+(load "streams.scm")
+
+(define-method (send (socket java.net.Socket) (x Vec))
+	(VecToStream. x (buffer (ostream socket))))
+(define-method (recv (socket java.net.Socket) (x Vec))
+	(StreamToVec. x (buffer (istream socket))))
+	
+(define-method (send (socket java.net.Socket) (x DoubleModel))
+	(SignalToStream. x (buffer (ostream socket))))
+(define-method (recv (socket java.net.Socket) (x DoubleModel))
+	(StreamToDouble. x (buffer (istream socket))))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/spectro.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,17 @@
+(load "audio.scm")
+(load "filelist.scm")
+(load "functions.scm")
+(load "models.scm")
+
+(put "map.symmetric" false)
+
+(define (spectro source n m)
+	(define x (ft-mag (ft-vec (offset (linein source n m)))))
+	(define z (diffscale x genexp-spec))
+
+	(expose)
+	(node (child x "diffScaler")
+		(exec (viewable "genexp.e") "trace")
+		(exec (viewable "w") "load")
+		(exec (viewable "mu") "load")
+		(viewable "output")))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/streams.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,43 @@
+(define (ifstream fn) (java.io.FileInputStream. fn))
+(define (ofstream fn) (java.io.FileOutputStream. fn))
+(define (fwriter fn) (java.io.FileWriter. fn))
+(define (freader fn) (java.io.FileReader. fn))
+
+(define-method (buffer (in java.io.InputStream)) (java.io.BufferedInputStream. in))
+(define-method (buffer (out java.io.OutputStream)) (java.io.BufferedOutputStream. out))
+(define-method (buffer (in java.io.Reader)) (java.io.BufferedReader. in))
+(define-method (buffer (out java.io.Writer)) (java.io.BufferedWriter. out))
+
+(define (make-pipe)
+	(define writer (java.io.PipedOutputStream.))
+	(define reader (java.io.PipedInputStream. writer))
+	(list writer reader)
+)
+
+(define-method (send (pipe Pair) (x Vec)) (VecToStream. x (first pipe)))
+(define-method (recv (pipe Pair) (x Vec)) (StreamToVec. x (second pipe)))
+(define-method (send (pipe Pair) (x DoubleModel)) (SignalToStream. x (first pipe)))
+(define-method (recv (pipe Pair) (x DoubleModel)) (StreamToDouble. x (second pipe)))
+
+(define (with-infile fname proc)
+	(let* (	(f (ifstream fname))
+			(rc (proc f)))
+		(.close f) rc))
+
+(define (with-outfile fname proc)
+	(let* (	(f (ofstream fname))
+			(rc (proc f)))
+		(.close f) rc))
+
+(define (with thing proc)
+	(let ((rc (proc thing)))
+		(.close thing) rc))
+
+(define (oostream s) (java.io.ObjectOutputStream. s))
+(define (iostream s) (java.io.ObjectInputStream. s))
+
+
+;; convert saveable from binary to text
+(define (totext thing file txtfile)
+  (with (ifstream file) (lambda (f) (.load thing f)))
+  (with (fwriter txtfile) (lambda (f) (.write thing f))))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/synthesis.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,67 @@
+(import "samer.maths.random.*")
+(load "lineout.scm")
+
+; sets the Generator of a VGenerator to one
+; constructed in it's own context.
+(define (load-generator gen)
+	(letrec ((nd (.getNode gen))
+		(spec (Shell.getString (.fullName nd)))
+		(g (node nd (eval-string spec))) )
+		(.setGenerator gen g)
+	)
+)
+
+(define (fir-filter coeffs) (FIRFilter. (.array coeffs)))
+(define (iir-filter coeffs) (IIRFilter. (.array coeffs)))
+
+(define (spectral-fir n spec)
+   (define filter (SpectralFIR. n spec))
+	(Ops.triggerTask filter spec)
+	(.coefficients filter))
+		
+
+(define (filter-gen filt gen) (FilteredGenerator. gen filt))
+(define (gen->vector n gen)
+  (define x (VVector. (cat "buffer(" (.toString gen) ")") n))
+  (define t (GenerateVector. x gen))
+  (addtasks t (Ops.update x))
+  x)
+
+(define (oscillator f)
+   (define osc (Oscillator. f))
+	(define vf (VDouble. "freq" f))
+	(on-change vf (.setFrequency osc (.get vf)))
+;	(samer.core.types.VParameter. "freq" (.getFrequencyModel osc))
+	osc)
+			
+(define (specsynth in N M)
+  (define filter (SpectralFilter. in N))
+  (addtask filter)
+  ;(gen->vector (filter-gen filter (VGenerator. "source" (Binary.))) M))
+  (gen->vector (filter-gen filter (BipolarUniform.)) M )
+)
+
+(define (specsynth-async in N M)
+  (define filter (SpectralFilter. in N))
+  (addtask filter)
+  (node "synth"
+	  (put "regulator.thread.priority" -0.1)
+	  (let ((new-tasks  (CompoundTask.)))
+	    (RThread. new-tasks)
+		 (with-tasks new-tasks
+			 (gen->vector M (filter-gen filter (NormalisedGaussian. ))))
+	  )))
+
+(define (synth2 ft mag hop sink)
+  (define ift (RescaledIFT. ft mag))
+  (addtask ift)
+  (overlap-and-add sink (.output ift) hop))
+
+ ;;; this generates a white noise signal modulated by
+;;; another signal E
+
+(define (noise-resynth E N sink)
+	(define buf (gen->vector N samer.maths.random.NormalisedGaussian.))
+	(addtask (task (Mathx.mul (.array buf) (- (.get E) 200))))
+	(lineout sink buf)
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/task.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,88 @@
+;;; task related utilities
+(import "samer.tools.*")
+
+
+(define task (macro body `(SilkTask. (lambda () ,@body))))
+
+;;; convert a CompoundTask to a Scheme list
+(define (tasks->list tasks)
+	(define L ())
+	(define (list-it it)
+		(if (.more it) (begin
+			(set! L (append L (list (.next it))))
+		(list-it it))))
+	(list-it (.iterator tasks))
+	L
+)
+
+;;; create and access main task list
+
+(define _thread null)
+(define _tasklist_stack ())
+
+(define (start) (exec _thread "start"))
+(define (stop)  (exec _thread "stop"))
+(define (thread) _thread)
+
+;;; creates a task list/thread if none exists, returns a task list
+(define (tasks)
+	(if (null? _tasklist_stack)
+		(let ((t (CompoundTask.)))
+			(set! _thread (RThread. t))
+			(push-tasklist t)
+			t
+		)
+		(first _tasklist_stack)
+	)
+)
+
+(define (push-tasklist t)
+  (set! _tasklist_stack (cons t _tasklist_stack)))
+
+(define (pop-tasklist)
+  (let ((t (first _tasklist_stack)))
+    (set! _tasklist_stack (rest _tasklist_stack))
+	 t))
+
+(define with-tasks (macro (tasks . body)
+	`(begin
+		(push-tasklist ,tasks)
+		(tryCatch
+			(let ((a (begin . ,body))) (pop-tasklist) a)
+			(lambda (ex) (pop-tasklist) (throw ex))))))
+
+; add task to current task list
+(define (addtask t) (.addTask (tasks) t) t)
+(define (removetask t) (.removeTask (tasks) t) t)
+(define-method (add (t Task)) (.addTask (tasks) t) t)
+(define-method (addafter (a Task) (t Task)) (.addTaskAfter (tasks) t a) t)
+(define-method (remove (t Task)) (.removeTask (tasks) t) t)
+
+; add multiple tasks to current task list
+(define (addtasks . t)
+	(for-each (lambda (t) (.addTask (tasks) t)) t)
+	(tasks) )
+
+(define-method (pr-tasks) (print (tasks->list (tasks))))
+(define-method (view-tasks) (view-tasks (tasks)))
+(define-method (view-tasks tasks) (view-list (tasks->list tasks) "Tasks"))
+(define-method (task-ref (n Integer)) (list-ref (tasks->list (tasks)) n))
+(define-method (task-ref tasks (n Integer)) (list-ref (tasks->list tasks) n))
+
+(define (switch task) (SwitchTask. task))
+
+;;; Create a subrate task and a UI for the subrate factor
+;;; !! need to dispose of VInteger when task is disposed.
+(define (sub n task)
+	(define vn (VInteger. "subfactor" n))
+	(define subt (SubrateTask. n task))
+	(on-change vn (.setFactor subt (.value$ vn)))
+	(.value$ vn n) (.changed vn)
+	subt
+)
+
+(define (seq . tasks)
+	(define c (CompoundTask.))
+	(for-each (lambda (t) (.addTask c t)) tasks)
+	c)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/tools.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,6 @@
+;;; this covers most of what tools used to contain,
+;;; plus the audio input stuff
+;(load "audio.scm")
+(load "filelist.scm")
+(load "models.scm")
+(load "functions.scm")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/view3d.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,93 @@
+(import "samer.j3d.*")
+(import "samer.j3d.Util")
+
+
+(define (xform . nodes)
+	(define tg (javax.media.j3d.TransformGroup.))
+	(for-each (lambda (node) (.addChild tg node)) nodes)
+	tg)
+
+(define (branch . nodes)
+	(define bg (javax.media.j3d.BranchGroup.))
+	(for-each (lambda (node) (.addChild bg node)) nodes)
+	bg)
+
+(define (root3d . nodes)
+	(define r (Root.))
+	(for-each (lambda (node) (.addChild r node)) nodes)
+	r)
+	
+(define shape javax.media.j3d.Shape3D.)
+(define (appearance shape app) (.setAppearance shape app) shape)
+
+(define (manipulate tg)
+	(Util.mouseRotate tg)
+;	(Util.mouseTranslate tg)
+	(Util.mouseZoom tg)
+	tg)
+
+(define (rotating period) (lambda (x) (Util.addRotator period x)))
+	
+(put "lookfrom" "(10 20 64)")
+
+(define c3f javax.vecmath.Color3f.)
+(define (white) (c3f 1f 1f 1f))
+(define (green) (c3f 0.1f 1f 0.2f))
+
+
+(define (view3d vec points container mk-view)
+	(node (.getNode vec)
+	  (node "3d"
+		(define view (mk-view))
+		(define VG (ViewGroup.))
+		(define root
+			(root3d
+				(container (xform (manipulate (xform
+					(appearance (Axes.) (Util.color (green) (Util.alpha 0.5 (Util.wireframe))))
+					(shape 
+						(Points3DAlpha. points vec) 	
+						;(Points4D. points vec) 	
+						(Util.alpha 0 (Util.points)))
+				))))
+				VG
+			)
+		)
+		(.attachView VG view)
+		(addtask view)
+		(.compile root)
+		(.activate root)
+	  )
+	)
+)
+
+;;; immediate mode viewer:
+;	get root
+;	add viewer
+;   get renderer
+;   set geometry and appearance
+
+(define (view-patches x)
+	(define patches (Matrix. "PatchesMatrix" 512 6))
+	(put "stereo" #f)
+	(put "linewidth" 1)
+	;(addtask (.getTask (samer.j3d.J3DViewer. patches x)))
+	;(model (PatchArrayAlpha. points vec)		(flat (alpha 0.0 (patches))))
+)
+
+;		Optional background colour
+;		(Util.addBackground root 
+;			(javax.media.j3d.Background 
+;				(Color3f. 0.26f 0.23f 0.35f)));
+
+;;; appearance bundles
+'(
+	(define (pointy1) (alpha 0.8 (color '(0.8 0.6 1) (points))))
+	(define (pointy3) (color '(0.8 0.6 1) (points)))
+	(define (wireframe1) (color '(0.6 0.4 0.5) (transparent 0.4 (wireframe)))) 
+	(define (wireframe2) (color '(0.8 0.6 1) (transparent 0.7 (wireframe)))) 
+	(define (wireframe3) 
+		(define col (c3f 0.6 0.5 0.7))
+		(Util.material col col 48 (wireframe)))
+)
+
+	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/viewables.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,34 @@
+;;; This is a non-scrolly version
+
+(define (expose-all vbls name)
+	(define win (Shell.getWindow name))
+	(define cnt (.container win))
+	(.setLayout cnt (javax.swing.BoxLayout. cnt javax.swing.BoxLayout.Y_AXIS$))
+	(for-each (lambda (v) (.add cnt (.getComponent (.getViewer v)))) vbls)
+	;;; window listener?
+	;;; container listener?
+	(.addWindowListener win (Shell.closeListener win))
+	(.expose win)
+)
+
+;;; Scrolly version a bit more complicated
+
+'(define (expose-all-scrolly vbls name)
+	(define win (Shell.getWindow name))
+	(define box (javax.swing.Box.createVerticalBox))
+	(define scr (javax.swing.JScrollPane. box))
+	(define (no-scrollbars)
+		(define sb=(.getVerticalScrollBar scr))
+		(if (eq? sb null) 
+			#t 
+			(not (.isVisible sb))))
+
+	(.setBorder scr null)
+	(.add (.container win) scr)
+	(for-each (lambda (v) (.add box (.getComponent (.getViewer v)))) vbls)
+	;;; window listener?
+	;;; container listener?
+	;;; packing/scrollbar policy?
+	(.addWindowListener win (Shell.closeListener win))
+	(.expose win)
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scheme/weird.scm	Tue Jan 17 17:50:20 2012 +0000
@@ -0,0 +1,60 @@
+(define (sieve n pr) (if (divides n pr) pr (cons n pr)))
+(define (div n m) (equal? 0 (remainder n m)))
+(define (divides n factors)
+	(if (null? factors) #f
+		(if (div n (first factors)) #t
+			(divides n (rest factors)))))
+
+(define primeso
+	(let ((hashed (java.util.ArrayList.)))
+		(define (set n l) (.add hashed n l) l)
+
+		(.add hashed `())
+		(.add hashed `())
+		(.add hashed `(2))
+
+		(lambda (n)
+			(if (< n (.size hashed))
+				(.get hashed n)
+				(begin
+					(.ensureCapacity hashed (+ n 1))
+					(set n (sieve n (primes (- n 1)))))))))
+
+(define (accum-primes n sofar limit)
+	(if (> n limit) sofar
+		(accum-primes (+ n 1) (sieve n sofar) limit)))
+
+(define (primes limit) (accum-primes 2 () limit))
+
+; alternative is to make a big or list by mapping
+; factors to a list of procedures: (m1 m2 ..) -> ((div m1) (div m2) ...)
+
+(define (prime? n) (equal? n (first (primes n))))
+
+(define (prime-factors n)
+
+`(define (factors n)
+	(define prime-factors (prime-factors n))
+	; now make all products including 1 but excluding n
+	; this is a binary enumeration, basically
+)
+
+(define (proper-divisors n)
+
+
+(define (abundant? n)
+	(< n (apply + (factors n))))
+
+
+(define (weird? n)
+	; get factors
+	; check abundancy
+	; is n a sum of any of its factors?
+	(define sum (apply + proper-divisors))
+	(if (<= sum n) #f		; ie not abundant
+		(begin
+			(define discrep (- n sum))
+			; can we make discrep by summing divisors <= discrep
+   		)
+     )
+)
\ No newline at end of file