JAL-1807 Bob's first commit -- Applet loaded; needs image j2s/develop-bh
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 21 Jul 2015 10:42:36 +0000 (11:42 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 21 Jul 2015 10:42:36 +0000 (11:42 +0100)
277 files changed:
src/awt2swing/Button.java [new file with mode: 0644]
src/awt2swing/Canvas.java [new file with mode: 0644]
src/awt2swing/Checkbox.java [new file with mode: 0644]
src/awt2swing/CheckboxMenuItem.java [new file with mode: 0644]
src/awt2swing/Choice.java [new file with mode: 0644]
src/awt2swing/Frame.java [new file with mode: 0644]
src/awt2swing/Label.java [new file with mode: 0644]
src/awt2swing/Menu.java [new file with mode: 0644]
src/awt2swing/MenuBar.java [new file with mode: 0644]
src/awt2swing/MenuItem.java [new file with mode: 0644]
src/awt2swing/Panel.java [new file with mode: 0644]
src/awt2swing/PopupMenu.java [new file with mode: 0644]
src/awt2swing/ScrollPane.java [new file with mode: 0644]
src/awt2swing/Scrollbar.java [new file with mode: 0644]
src/awt2swing/TextArea.java [new file with mode: 0644]
src/awt2swing/TextField.java [new file with mode: 0644]
src/com/stevesoft/pat/BackRefRule.java
src/com/stevesoft/pat/BasicStringBufferLike.java
src/com/stevesoft/pat/CaseMgr.java
src/com/stevesoft/pat/DirFileRegex.java
src/com/stevesoft/pat/FileRegex.java
src/com/stevesoft/pat/MessageManager.java [new file with mode: 0644]
src/com/stevesoft/pat/NonDirFileRegex.java
src/com/stevesoft/pat/Pattern.java
src/com/stevesoft/pat/RegRes.java
src/com/stevesoft/pat/Regex.java
src/com/stevesoft/pat/RegexReader.java
src/com/stevesoft/pat/RegexTokenizer.java
src/com/stevesoft/pat/RegexWriter.java
src/com/stevesoft/pat/ReplaceRule.java
src/com/stevesoft/pat/Replacer.java
src/com/stevesoft/pat/Skip.java
src/com/stevesoft/pat/Skip2.java
src/com/stevesoft/pat/SkipBMH.java
src/com/stevesoft/pat/StringBufferLike.java
src/com/stevesoft/pat/Transformer.java
src/com/stevesoft/pat/Util.java [new file with mode: 0644]
src/com/stevesoft/pat/Validator.java
src/com/stevesoft/pat/oneChar.java
src/com/stevesoft/pat/parsePerl.java
src/com/stevesoft/pat/wrap/CharArrayBufferWrap.java
src/com/stevesoft/pat/wrap/RandomAccessFileWrap.java
src/com/stevesoft/pat/wrap/StringBufferWrap.java
src/com/stevesoft/pat/wrap/WriterWrap.java
src/fr/orsay/lri/varna/models/rna/RNA.java [new file with mode: 0644]
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/AlignmentAnnotationUtils.java
src/jalview/analysis/AlignmentSorter.java
src/jalview/analysis/Finder.java
src/jalview/analysis/NJTree.java
src/jalview/analysis/ParseProperties.java
src/jalview/analysis/Rna.java
src/jalview/analysis/StructureFrequency.java
src/jalview/api/analysis/ViewBasedAnalysisI.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/appletgui/AlignmentPanel.java
src/jalview/appletgui/AnnotationColourChooser.java
src/jalview/appletgui/AnnotationColumnChooser.java
src/jalview/appletgui/AnnotationLabels.java
src/jalview/appletgui/AnnotationPanel.java
src/jalview/appletgui/AnnotationRowFilter.java
src/jalview/appletgui/AppletJmol.java
src/jalview/appletgui/AppletJmolBinding.java
src/jalview/appletgui/CutAndPasteTransfer.java
src/jalview/appletgui/EditNameDialog.java
src/jalview/appletgui/EmbmenuFrame.java
src/jalview/appletgui/ExtJmol.java
src/jalview/appletgui/FeatureColourChooser.java
src/jalview/appletgui/FeatureRenderer.java
src/jalview/appletgui/FeatureSettings.java
src/jalview/appletgui/Finder.java
src/jalview/appletgui/FontChooser.java
src/jalview/appletgui/IdCanvas.java
src/jalview/appletgui/IdPanel.java
src/jalview/appletgui/IdwidthAdjuster.java
src/jalview/appletgui/JVDialog.java
src/jalview/appletgui/OverviewPanel.java
src/jalview/appletgui/PCAPanel.java
src/jalview/appletgui/PairwiseAlignPanel.java
src/jalview/appletgui/RedundancyPanel.java
src/jalview/appletgui/RotatableCanvas.java
src/jalview/appletgui/ScalePanel.java
src/jalview/appletgui/SeqCanvas.java
src/jalview/appletgui/SeqPanel.java
src/jalview/appletgui/SliderPanel.java
src/jalview/appletgui/SplitFrame.java
src/jalview/appletgui/TitledPanel.java
src/jalview/appletgui/Tooltip.java
src/jalview/appletgui/TreeCanvas.java
src/jalview/appletgui/TreePanel.java
src/jalview/appletgui/UserDefinedColours.java
src/jalview/bin/Cache.java
src/jalview/bin/JalviewLite.java
src/jalview/commands/EditCommand.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentView.java
src/jalview/datamodel/CigarBase.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceI.java
src/jalview/io/AlignmentProperties.java
src/jalview/io/AnnotationFile.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/FastaFile.java
src/jalview/io/FeaturesFile.java
src/jalview/io/FileParse.java
src/jalview/io/IdentifyFile.java
src/jalview/io/JnetAnnotationMaker.java
src/jalview/io/ModellerDescription.java
src/jalview/io/NewickFile.java
src/jalview/javascript/JSFunctionExec.java
src/jalview/javascript/JsSelectionSender.java
src/jalview/jsdev/Constants.java [new file with mode: 0644]
src/jalview/jsdev/GenericFileAdapter.java [new file with mode: 0644]
src/jalview/jsdev/JSRegex.java [new file with mode: 0644]
src/jalview/jsdev/JavaScriptRegExp.java [new file with mode: 0644]
src/jalview/jsdev/RegExp.java [new file with mode: 0644]
src/jalview/jsdev/api/RegExpInterface.java [new file with mode: 0644]
src/jalview/jsdev/api/VarnaRNA.java [new file with mode: 0644]
src/jalview/math/Matrix.java
src/jalview/math/RotatableMatrix.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/schemes/ResidueProperties.java
src/jalview/schemes/TCoffeeColourScheme.java
src/jalview/structures/models/AAStructureBindingModel.java
src/jalview/util/AWTConsole.java
src/jalview/util/Comparison.java
src/jalview/util/DBRefUtils.java
src/jalview/util/GroupUrlLink.java
src/jalview/util/MessageManager.java
src/jalview/util/QuickSort.java
src/jalview/util/UrlLink.java
src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java
src/jalview/workers/ConsensusThread.java
src/javajs/J2SIgnoreImport.java [new file with mode: 0644]
src/javajs/J2SRequireImport.java [new file with mode: 0644]
src/javajs/api/BytePoster.java [new file with mode: 0644]
src/javajs/api/EigenInterface.java [new file with mode: 0644]
src/javajs/api/EventManager.java [new file with mode: 0644]
src/javajs/api/FontManager.java [new file with mode: 0644]
src/javajs/api/GenericBinaryDocument.java [new file with mode: 0644]
src/javajs/api/GenericCifDataParser.java [new file with mode: 0644]
src/javajs/api/GenericColor.java [new file with mode: 0644]
src/javajs/api/GenericFileInterface.java [new file with mode: 0644]
src/javajs/api/GenericImageDialog.java [new file with mode: 0644]
src/javajs/api/GenericImageEncoder.java [new file with mode: 0644]
src/javajs/api/GenericLineReader.java [new file with mode: 0644]
src/javajs/api/GenericMenuInterface.java [new file with mode: 0644]
src/javajs/api/GenericMouseInterface.java [new file with mode: 0644]
src/javajs/api/GenericPlatform.java [new file with mode: 0644]
src/javajs/api/GenericZipInputStream.java [new file with mode: 0644]
src/javajs/api/GenericZipTools.java [new file with mode: 0644]
src/javajs/api/HTMLElement.java [new file with mode: 0644]
src/javajs/api/HTMLWindowEvent.java [new file with mode: 0644]
src/javajs/api/Interface.java [new file with mode: 0644]
src/javajs/api/JSInterface.java [new file with mode: 0644]
src/javajs/api/JSONEncodable.java [new file with mode: 0644]
src/javajs/api/JmolObjectInterface.java [new file with mode: 0644]
src/javajs/api/PlatformViewer.java [new file with mode: 0644]
src/javajs/api/SC.java [new file with mode: 0644]
src/javajs/api/SwingController.java [new file with mode: 0644]
src/javajs/api/ZInputStream.java [new file with mode: 0644]
src/javajs/awt/BorderLayout.java [new file with mode: 0644]
src/javajs/awt/Color.java [new file with mode: 0644]
src/javajs/awt/Component.java [new file with mode: 0644]
src/javajs/awt/Container.java [new file with mode: 0644]
src/javajs/awt/Dimension.java [new file with mode: 0644]
src/javajs/awt/Font.java [new file with mode: 0644]
src/javajs/awt/LayoutManager.java [new file with mode: 0644]
src/javajs/awt/event/ActionEvent.java [new file with mode: 0644]
src/javajs/awt/event/ActionListener.java [new file with mode: 0644]
src/javajs/awt/event/Event.java [new file with mode: 0644]
src/javajs/awt/event/ItemEvent.java [new file with mode: 0644]
src/javajs/awt/event/WindowEvent.java [new file with mode: 0644]
src/javajs/awt/event/WindowListener.java [new file with mode: 0644]
src/javajs/export/PDFCreator.java [new file with mode: 0644]
src/javajs/export/PDFObject.java [new file with mode: 0644]
src/javajs/img/BMPDecoder.java [new file with mode: 0644]
src/javajs/img/CRCEncoder.java [new file with mode: 0644]
src/javajs/img/GifEncoder.java [new file with mode: 0644]
src/javajs/img/ImageEncoder.java [new file with mode: 0644]
src/javajs/img/Jpg64Encoder.java [new file with mode: 0644]
src/javajs/img/JpgEncoder.java [new file with mode: 0644]
src/javajs/img/PdfEncoder.java [new file with mode: 0644]
src/javajs/img/PngEncoder.java [new file with mode: 0644]
src/javajs/img/PpmEncoder.java [new file with mode: 0644]
src/javajs/swing/AbstractButton.java [new file with mode: 0644]
src/javajs/swing/AbstractTableModel.java [new file with mode: 0644]
src/javajs/swing/ButtonGroup.java [new file with mode: 0644]
src/javajs/swing/Cell.java [new file with mode: 0644]
src/javajs/swing/ColumnSelectionModel.java [new file with mode: 0644]
src/javajs/swing/Document.java [new file with mode: 0644]
src/javajs/swing/FlowLayout.java [new file with mode: 0644]
src/javajs/swing/Grid.java [new file with mode: 0644]
src/javajs/swing/GridBagConstraints.java [new file with mode: 0644]
src/javajs/swing/GridBagLayout.java [new file with mode: 0644]
src/javajs/swing/Insets.java [new file with mode: 0644]
src/javajs/swing/JButton.java [new file with mode: 0644]
src/javajs/swing/JCheckBox.java [new file with mode: 0644]
src/javajs/swing/JCheckBoxMenuItem.java [new file with mode: 0644]
src/javajs/swing/JComboBox.java [new file with mode: 0644]
src/javajs/swing/JComponent.java [new file with mode: 0644]
src/javajs/swing/JComponentImp.java [new file with mode: 0644]
src/javajs/swing/JContentPane.java [new file with mode: 0644]
src/javajs/swing/JDialog.java [new file with mode: 0644]
src/javajs/swing/JEditorPane.java [new file with mode: 0644]
src/javajs/swing/JLabel.java [new file with mode: 0644]
src/javajs/swing/JMenu.java [new file with mode: 0644]
src/javajs/swing/JMenuItem.java [new file with mode: 0644]
src/javajs/swing/JPanel.java [new file with mode: 0644]
src/javajs/swing/JPopupMenu.java [new file with mode: 0644]
src/javajs/swing/JRadioButtonMenuItem.java [new file with mode: 0644]
src/javajs/swing/JScrollPane.java [new file with mode: 0644]
src/javajs/swing/JSplitPane.java [new file with mode: 0644]
src/javajs/swing/JTable.java [new file with mode: 0644]
src/javajs/swing/JTextField.java [new file with mode: 0644]
src/javajs/swing/JTextPane.java [new file with mode: 0644]
src/javajs/swing/ListSelectionModel.java [new file with mode: 0644]
src/javajs/swing/SwingConstants.java [new file with mode: 0644]
src/javajs/swing/TableCellRenderer.java [new file with mode: 0644]
src/javajs/swing/TableColumn.java [new file with mode: 0644]
src/javajs/util/A4.java [new file with mode: 0644]
src/javajs/util/AU.java [new file with mode: 0644]
src/javajs/util/AjaxURLConnection.java [new file with mode: 0644]
src/javajs/util/AjaxURLStreamHandler.java [new file with mode: 0644]
src/javajs/util/AjaxURLStreamHandlerFactory.java [new file with mode: 0644]
src/javajs/util/ArrayDataReader.java [new file with mode: 0644]
src/javajs/util/BArray.java [new file with mode: 0644]
src/javajs/util/BC.java [new file with mode: 0644]
src/javajs/util/BS.java [new file with mode: 0644]
src/javajs/util/Base64.java [new file with mode: 0644]
src/javajs/util/BinaryDocument.java [new file with mode: 0644]
src/javajs/util/CU.java [new file with mode: 0644]
src/javajs/util/CifDataParser.java [new file with mode: 0644]
src/javajs/util/CompoundDocDirEntry.java [new file with mode: 0644]
src/javajs/util/CompoundDocHeader.java [new file with mode: 0644]
src/javajs/util/CompoundDocument.java [new file with mode: 0644]
src/javajs/util/DF.java [new file with mode: 0644]
src/javajs/util/DataReader.java [new file with mode: 0644]
src/javajs/util/Eigen.java [new file with mode: 0644]
src/javajs/util/Encoding.java [new file with mode: 0644]
src/javajs/util/LimitedLineReader.java [new file with mode: 0644]
src/javajs/util/ListDataReader.java [new file with mode: 0644]
src/javajs/util/Lst.java [new file with mode: 0644]
src/javajs/util/M3.java [new file with mode: 0644]
src/javajs/util/M34.java [new file with mode: 0644]
src/javajs/util/M4.java [new file with mode: 0644]
src/javajs/util/Matrix.java [new file with mode: 0644]
src/javajs/util/Measure.java [new file with mode: 0644]
src/javajs/util/OC.java [new file with mode: 0644]
src/javajs/util/P3.java [new file with mode: 0644]
src/javajs/util/P3i.java [new file with mode: 0644]
src/javajs/util/P4.java [new file with mode: 0644]
src/javajs/util/PT.java [new file with mode: 0644]
src/javajs/util/Quat.java [new file with mode: 0644]
src/javajs/util/Rdr.java [new file with mode: 0644]
src/javajs/util/SB.java [new file with mode: 0644]
src/javajs/util/StringDataReader.java [new file with mode: 0644]
src/javajs/util/T3.java [new file with mode: 0644]
src/javajs/util/T3d.java [new file with mode: 0644]
src/javajs/util/T3i.java [new file with mode: 0644]
src/javajs/util/T4.java [new file with mode: 0644]
src/javajs/util/V3.java [new file with mode: 0644]
src/javajs/util/V3d.java [new file with mode: 0644]
src/javajs/util/XmlUtil.java [new file with mode: 0644]
src/javajs/util/ZipData.java [new file with mode: 0644]
src/javajs/util/ZipTools.java [new file with mode: 0644]
src/netscape/javascript/JSException.java [new file with mode: 0644]
src/netscape/javascript/JSObject.java [new file with mode: 0644]
src/org/exolab/castor/mapping/Mapping.java [new file with mode: 0644]
src/org/exolab/castor/xml/Unmarshaller.java [new file with mode: 0644]
src/org/jmol/viewer/Viewer.java [new file with mode: 0644]
src/swingjs/JSEvent.java [new file with mode: 0644]
src/swingjs/JSThread.java [new file with mode: 0644]
src/swingjs/api/JSFunction.java [new file with mode: 0644]

diff --git a/src/awt2swing/Button.java b/src/awt2swing/Button.java
new file mode 100644 (file)
index 0000000..2e4b773
--- /dev/null
@@ -0,0 +1,16 @@
+package awt2swing;
+
+import javax.swing.JButton;
+
+
+public class Button extends JButton {
+
+       public Button() {
+               super();
+       }
+
+       public Button(String text) {
+               super(text);
+       }
+
+}
diff --git a/src/awt2swing/Canvas.java b/src/awt2swing/Canvas.java
new file mode 100644 (file)
index 0000000..73a6ce6
--- /dev/null
@@ -0,0 +1,6 @@
+package awt2swing;
+
+
+public class Canvas extends Panel {
+
+}
diff --git a/src/awt2swing/Checkbox.java b/src/awt2swing/Checkbox.java
new file mode 100644 (file)
index 0000000..c320798
--- /dev/null
@@ -0,0 +1,23 @@
+package awt2swing;
+
+import javax.swing.JCheckBox;
+
+public class Checkbox extends JCheckBox {
+
+       public Checkbox(String string, boolean b) {
+               super(string, b);
+       }
+
+       public Checkbox() {
+               super();
+       }
+
+       public boolean getState() {
+               return isSelected();
+       }
+
+       public void setState(boolean b) {
+               setSelected(b);
+       }
+
+}
diff --git a/src/awt2swing/CheckboxMenuItem.java b/src/awt2swing/CheckboxMenuItem.java
new file mode 100644 (file)
index 0000000..4be61dd
--- /dev/null
@@ -0,0 +1,28 @@
+package awt2swing;
+
+import javax.swing.JCheckBoxMenuItem;
+
+public class CheckboxMenuItem extends JCheckBoxMenuItem {
+
+       public CheckboxMenuItem(String string) {
+               super(string);
+       }
+
+       public CheckboxMenuItem() {
+       }
+
+       public CheckboxMenuItem(String string, boolean b) {
+               super(string, b);
+       }
+
+       public boolean getState() {
+               return isSelected();
+       }
+       
+       
+       public void setState(boolean tf) {
+               setSelected(tf);
+       }
+
+
+}
diff --git a/src/awt2swing/Choice.java b/src/awt2swing/Choice.java
new file mode 100644 (file)
index 0000000..b9bda7c
--- /dev/null
@@ -0,0 +1,12 @@
+package awt2swing;
+
+import javax.swing.JComboBox;
+
+
+public class Choice extends JComboBox {
+
+       public void select(Object key) {
+               setSelectedItem(key);
+       }
+
+}
diff --git a/src/awt2swing/Frame.java b/src/awt2swing/Frame.java
new file mode 100644 (file)
index 0000000..2535321
--- /dev/null
@@ -0,0 +1,55 @@
+package awt2swing;
+
+import javax.swing.JFrame;
+
+public class Frame extends JFrame {
+
+       public Frame(String title) {
+               super(title);
+               /**
+                * @j2sNative
+                * 
+                * xxxf = this;
+                */
+               {}
+       }
+
+       public Frame() {
+               super();
+               /**
+                * @j2sNative
+                * 
+                * xxxf = this;
+                */
+               {}
+       }
+
+       public void remove(int i) {
+               /**
+                * SwingJ has a somewhat reduced method set; we just use
+                * this interface to add ones we feel we need.
+                * 
+                * @j2sNative
+                * 
+                * this.removeInt(i);
+                * 
+                */
+               {
+                       super.remove(i);
+               }
+       }
+       
+       public void setMenuBar(MenuBar m) {
+               setJMenuBar(m);
+       }
+
+  public void unsetMenuBar() {
+       setJMenuBar(null);
+       }
+
+
+       public MenuBar getMenubar() {
+               return (MenuBar) getJMenuBar();
+       }
+
+}
diff --git a/src/awt2swing/Label.java b/src/awt2swing/Label.java
new file mode 100644 (file)
index 0000000..2cfc18c
--- /dev/null
@@ -0,0 +1,24 @@
+package awt2swing;
+
+import javax.swing.JLabel;
+
+public class Label extends JLabel {
+
+       public Label() {
+               super();
+       }
+       
+       public Label(String text) {
+               super(text);
+       }
+       
+       public Label(String text, int center) {
+               super(text, center);
+       }
+
+       public void setAlignment(int alignment) {
+               setAlignmentX(alignment);
+               
+       }
+
+}
diff --git a/src/awt2swing/Menu.java b/src/awt2swing/Menu.java
new file mode 100644 (file)
index 0000000..ea4b672
--- /dev/null
@@ -0,0 +1,17 @@
+package awt2swing;
+
+import javax.swing.JMenu;
+
+public class Menu extends JMenu {
+
+       public Menu(String title) {
+               super(title);
+               title=null;
+       }
+
+       public Menu() {
+               super();
+               String s = null;
+       }
+
+}
diff --git a/src/awt2swing/MenuBar.java b/src/awt2swing/MenuBar.java
new file mode 100644 (file)
index 0000000..b5ca89b
--- /dev/null
@@ -0,0 +1,7 @@
+package awt2swing;
+
+import javax.swing.JMenuBar;
+
+public class MenuBar extends JMenuBar {
+
+}
diff --git a/src/awt2swing/MenuItem.java b/src/awt2swing/MenuItem.java
new file mode 100644 (file)
index 0000000..038db10
--- /dev/null
@@ -0,0 +1,15 @@
+package awt2swing;
+
+import javax.swing.JMenuItem;
+
+public class MenuItem extends JMenuItem {
+
+       public MenuItem(String string) {
+               super(string);
+       }
+
+       public MenuItem() {
+               super();
+       }
+
+}
diff --git a/src/awt2swing/Panel.java b/src/awt2swing/Panel.java
new file mode 100644 (file)
index 0000000..ac06a5b
--- /dev/null
@@ -0,0 +1,18 @@
+package awt2swing;
+
+import java.awt.Graphics;
+import java.awt.LayoutManager;
+
+import javax.swing.JPanel;
+
+public class Panel extends JPanel {
+
+       public Panel(LayoutManager layout) {
+               super(layout);
+       }
+
+       public Panel() {
+               super();
+       }
+       
+}
diff --git a/src/awt2swing/PopupMenu.java b/src/awt2swing/PopupMenu.java
new file mode 100644 (file)
index 0000000..09cbdb3
--- /dev/null
@@ -0,0 +1,16 @@
+package awt2swing;
+
+import javax.swing.JPopupMenu;
+
+public class PopupMenu extends JPopupMenu {
+
+       public PopupMenu() {
+               super();
+       }
+
+       public PopupMenu(String string) {
+               super(string);
+       }
+       
+
+}
diff --git a/src/awt2swing/ScrollPane.java b/src/awt2swing/ScrollPane.java
new file mode 100644 (file)
index 0000000..31da13c
--- /dev/null
@@ -0,0 +1,7 @@
+package awt2swing;
+
+import javax.swing.JScrollPane;
+
+public class ScrollPane extends JScrollPane {
+
+}
diff --git a/src/awt2swing/Scrollbar.java b/src/awt2swing/Scrollbar.java
new file mode 100644 (file)
index 0000000..47783f9
--- /dev/null
@@ -0,0 +1,19 @@
+package awt2swing;
+
+import javax.swing.JScrollBar;
+
+public class Scrollbar extends JScrollBar {
+
+       public Scrollbar(int direction) {
+               super(direction);
+       }
+
+       public Scrollbar() {
+               super();
+       }
+
+       public Scrollbar(int orientation, int value, int extent, int min, int max) {
+               super(orientation, value, extent, min, max);
+       }
+
+}
diff --git a/src/awt2swing/TextArea.java b/src/awt2swing/TextArea.java
new file mode 100644 (file)
index 0000000..042016c
--- /dev/null
@@ -0,0 +1,15 @@
+package awt2swing;
+
+import javax.swing.JTextArea;
+
+public class TextArea extends JTextArea {
+
+       public TextArea(int rows, int cols) {
+               super(rows, cols);
+       }
+
+       public TextArea() {
+               super();
+       }
+
+}
diff --git a/src/awt2swing/TextField.java b/src/awt2swing/TextField.java
new file mode 100644 (file)
index 0000000..bfbfbfa
--- /dev/null
@@ -0,0 +1,46 @@
+package awt2swing;
+
+import jalview.structures.models.AAStructureBindingModel;
+
+import java.awt.event.TextEvent;
+import java.awt.event.TextListener;
+
+import javax.swing.JTextField;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+
+public class TextField extends JTextField {
+
+       public TextField(int width) {
+               super(width);
+       }
+
+       public TextField() {
+               super();
+       }
+
+       public TextField(String text, int width) {
+               super(text, width);
+       }
+
+       public void addTextListener(final TextListener textListener) {
+               getDocument().addDocumentListener(new DocumentListener() {
+
+                       @Override
+                       public void insertUpdate(DocumentEvent e) {
+                       }
+
+                       @Override
+                       public void removeUpdate(DocumentEvent e) {
+                               // TODO Auto-generated method stub
+
+                       }
+
+                       @Override
+                       public void changedUpdate(DocumentEvent e) {
+                               textListener.textValueChanged(new TextEvent(this, 0));
+                       }
+               });
+       }
+
+}
index daacbc1..e5c0778 100755 (executable)
@@ -24,7 +24,7 @@ public class BackRefRule extends ReplaceRule
 
   public void apply(StringBufferLike sb, RegRes res)
   {
-    String x = res.stringMatched(n);
+    String x = res.stringMatchedI(n);
     sb.append(x == null ? "" : x);
   }
 
index adb10f1..89224e6 100755 (executable)
@@ -13,7 +13,7 @@ com.stevesoft.pat;
  */
 public interface BasicStringBufferLike
 {
-  public void append(char c);
+  public void appendC(char c);
 
   public void append(String s);
 
index 393dac9..077c795 100755 (executable)
@@ -22,4171 +22,4176 @@ final public class CaseMgr
   final static boolean java_1_0 = false;
 
   /** Convert a character to upper case . */
-  public static char toUpperCase(char c)
+  public static char toUpperCaseC(char c)
   {
-    if (java_1_0)
-    {
-      int ret = (int) c;
-      switch (c)
-      {
-      case 97:
-        ret = 65;
-        break;
-      case 98:
-        ret = 66;
-        break;
-      case 99:
-        ret = 67;
-        break;
-      case 100:
-        ret = 68;
-        break;
-      case 101:
-        ret = 69;
-        break;
-      case 102:
-        ret = 70;
-        break;
-      case 103:
-        ret = 71;
-        break;
-      case 104:
-        ret = 72;
-        break;
-      case 105:
-        ret = 73;
-        break;
-      case 106:
-        ret = 74;
-        break;
-      case 107:
-        ret = 75;
-        break;
-      case 108:
-        ret = 76;
-        break;
-      case 109:
-        ret = 77;
-        break;
-      case 110:
-        ret = 78;
-        break;
-      case 111:
-        ret = 79;
-        break;
-      case 112:
-        ret = 80;
-        break;
-      case 113:
-        ret = 81;
-        break;
-      case 114:
-        ret = 82;
-        break;
-      case 115:
-        ret = 83;
-        break;
-      case 116:
-        ret = 84;
-        break;
-      case 117:
-        ret = 85;
-        break;
-      case 118:
-        ret = 86;
-        break;
-      case 119:
-        ret = 87;
-        break;
-      case 120:
-        ret = 88;
-        break;
-      case 121:
-        ret = 89;
-        break;
-      case 122:
-        ret = 90;
-        break;
-      case 224:
-        ret = 192;
-        break;
-      case 225:
-        ret = 193;
-        break;
-      case 226:
-        ret = 194;
-        break;
-      case 227:
-        ret = 195;
-        break;
-      case 228:
-        ret = 196;
-        break;
-      case 229:
-        ret = 197;
-        break;
-      case 230:
-        ret = 198;
-        break;
-      case 231:
-        ret = 199;
-        break;
-      case 232:
-        ret = 200;
-        break;
-      case 233:
-        ret = 201;
-        break;
-      case 234:
-        ret = 202;
-        break;
-      case 235:
-        ret = 203;
-        break;
-      case 236:
-        ret = 204;
-        break;
-      case 237:
-        ret = 205;
-        break;
-      case 238:
-        ret = 206;
-        break;
-      case 239:
-        ret = 207;
-        break;
-      case 240:
-        ret = 208;
-        break;
-      case 241:
-        ret = 209;
-        break;
-      case 242:
-        ret = 210;
-        break;
-      case 243:
-        ret = 211;
-        break;
-      case 244:
-        ret = 212;
-        break;
-      case 245:
-        ret = 213;
-        break;
-      case 246:
-        ret = 214;
-        break;
-      case 248:
-        ret = 216;
-        break;
-      case 249:
-        ret = 217;
-        break;
-      case 250:
-        ret = 218;
-        break;
-      case 251:
-        ret = 219;
-        break;
-      case 252:
-        ret = 220;
-        break;
-      case 253:
-        ret = 221;
-        break;
-      case 254:
-        ret = 222;
-        break;
-      case 255:
-        ret = 376;
-        break;
-      case 257:
-        ret = 256;
-        break;
-      case 259:
-        ret = 258;
-        break;
-      case 261:
-        ret = 260;
-        break;
-      case 263:
-        ret = 262;
-        break;
-      case 265:
-        ret = 264;
-        break;
-      case 267:
-        ret = 266;
-        break;
-      case 269:
-        ret = 268;
-        break;
-      case 271:
-        ret = 270;
-        break;
-      case 273:
-        ret = 272;
-        break;
-      case 275:
-        ret = 274;
-        break;
-      case 277:
-        ret = 276;
-        break;
-      case 279:
-        ret = 278;
-        break;
-      case 281:
-        ret = 280;
-        break;
-      case 283:
-        ret = 282;
-        break;
-      case 285:
-        ret = 284;
-        break;
-      case 287:
-        ret = 286;
-        break;
-      case 289:
-        ret = 288;
-        break;
-      case 291:
-        ret = 290;
-        break;
-      case 293:
-        ret = 292;
-        break;
-      case 295:
-        ret = 294;
-        break;
-      case 297:
-        ret = 296;
-        break;
-      case 299:
-        ret = 298;
-        break;
-      case 301:
-        ret = 300;
-        break;
-      case 303:
-        ret = 302;
-        break;
-      case 305:
-        ret = 73;
-        break;
-      case 307:
-        ret = 306;
-        break;
-      case 309:
-        ret = 308;
-        break;
-      case 311:
-        ret = 310;
-        break;
-      case 314:
-        ret = 313;
-        break;
-      case 316:
-        ret = 315;
-        break;
-      case 318:
-        ret = 317;
-        break;
-      case 320:
-        ret = 319;
-        break;
-      case 322:
-        ret = 321;
-        break;
-      case 324:
-        ret = 323;
-        break;
-      case 326:
-        ret = 325;
-        break;
-      case 328:
-        ret = 327;
-        break;
-      case 331:
-        ret = 330;
-        break;
-      case 333:
-        ret = 332;
-        break;
-      case 335:
-        ret = 334;
-        break;
-      case 337:
-        ret = 336;
-        break;
-      case 339:
-        ret = 338;
-        break;
-      case 341:
-        ret = 340;
-        break;
-      case 343:
-        ret = 342;
-        break;
-      case 345:
-        ret = 344;
-        break;
-      case 347:
-        ret = 346;
-        break;
-      case 349:
-        ret = 348;
-        break;
-      case 351:
-        ret = 350;
-        break;
-      case 353:
-        ret = 352;
-        break;
-      case 355:
-        ret = 354;
-        break;
-      case 357:
-        ret = 356;
-        break;
-      case 359:
-        ret = 358;
-        break;
-      case 361:
-        ret = 360;
-        break;
-      case 363:
-        ret = 362;
-        break;
-      case 365:
-        ret = 364;
-        break;
-      case 367:
-        ret = 366;
-        break;
-      case 369:
-        ret = 368;
-        break;
-      case 371:
-        ret = 370;
-        break;
-      case 373:
-        ret = 372;
-        break;
-      case 375:
-        ret = 374;
-        break;
-      case 378:
-        ret = 377;
-        break;
-      case 380:
-        ret = 379;
-        break;
-      case 382:
-        ret = 381;
-        break;
-      case 383:
-        ret = 83;
-        break;
-      case 387:
-        ret = 386;
-        break;
-      case 389:
-        ret = 388;
-        break;
-      case 392:
-        ret = 391;
-        break;
-      case 396:
-        ret = 395;
-        break;
-      case 402:
-        ret = 401;
-        break;
-      case 409:
-        ret = 408;
-        break;
-      case 417:
-        ret = 416;
-        break;
-      case 419:
-        ret = 418;
-        break;
-      case 421:
-        ret = 420;
-        break;
-      case 424:
-        ret = 423;
-        break;
-      case 429:
-        ret = 428;
-        break;
-      case 432:
-        ret = 431;
-        break;
-      case 436:
-        ret = 435;
-        break;
-      case 438:
-        ret = 437;
-        break;
-      case 441:
-        ret = 440;
-        break;
-      case 445:
-        ret = 444;
-        break;
-      case 453:
-        ret = 452;
-        break;
-      case 454:
-        ret = 452;
-        break;
-      case 456:
-        ret = 455;
-        break;
-      case 457:
-        ret = 455;
-        break;
-      case 459:
-        ret = 458;
-        break;
-      case 460:
-        ret = 458;
-        break;
-      case 462:
-        ret = 461;
-        break;
-      case 464:
-        ret = 463;
-        break;
-      case 466:
-        ret = 465;
-        break;
-      case 468:
-        ret = 467;
-        break;
-      case 470:
-        ret = 469;
-        break;
-      case 472:
-        ret = 471;
-        break;
-      case 474:
-        ret = 473;
-        break;
-      case 476:
-        ret = 475;
-        break;
-      case 479:
-        ret = 478;
-        break;
-      case 481:
-        ret = 480;
-        break;
-      case 483:
-        ret = 482;
-        break;
-      case 485:
-        ret = 484;
-        break;
-      case 487:
-        ret = 486;
-        break;
-      case 489:
-        ret = 488;
-        break;
-      case 491:
-        ret = 490;
-        break;
-      case 493:
-        ret = 492;
-        break;
-      case 495:
-        ret = 494;
-        break;
-      case 498:
-        ret = 497;
-        break;
-      case 499:
-        ret = 497;
-        break;
-      case 501:
-        ret = 500;
-        break;
-      case 507:
-        ret = 506;
-        break;
-      case 509:
-        ret = 508;
-        break;
-      case 511:
-        ret = 510;
-        break;
-      case 513:
-        ret = 512;
-        break;
-      case 515:
-        ret = 514;
-        break;
-      case 517:
-        ret = 516;
-        break;
-      case 519:
-        ret = 518;
-        break;
-      case 521:
-        ret = 520;
-        break;
-      case 523:
-        ret = 522;
-        break;
-      case 525:
-        ret = 524;
-        break;
-      case 527:
-        ret = 526;
-        break;
-      case 529:
-        ret = 528;
-        break;
-      case 531:
-        ret = 530;
-        break;
-      case 533:
-        ret = 532;
-        break;
-      case 535:
-        ret = 534;
-        break;
-      case 595:
-        ret = 385;
-        break;
-      case 596:
-        ret = 390;
-        break;
-      case 598:
-        ret = 393;
-        break;
-      case 599:
-        ret = 394;
-        break;
-      case 600:
-        ret = 398;
-        break;
-      case 601:
-        ret = 399;
-        break;
-      case 603:
-        ret = 400;
-        break;
-      case 608:
-        ret = 403;
-        break;
-      case 611:
-        ret = 404;
-        break;
-      case 616:
-        ret = 407;
-        break;
-      case 617:
-        ret = 406;
-        break;
-      case 623:
-        ret = 412;
-        break;
-      case 626:
-        ret = 413;
-        break;
-      case 643:
-        ret = 425;
-        break;
-      case 648:
-        ret = 430;
-        break;
-      case 650:
-        ret = 433;
-        break;
-      case 651:
-        ret = 434;
-        break;
-      case 658:
-        ret = 439;
-        break;
-      case 940:
-        ret = 902;
-        break;
-      case 941:
-        ret = 904;
-        break;
-      case 942:
-        ret = 905;
-        break;
-      case 943:
-        ret = 906;
-        break;
-      case 945:
-        ret = 913;
-        break;
-      case 946:
-        ret = 914;
-        break;
-      case 947:
-        ret = 915;
-        break;
-      case 948:
-        ret = 916;
-        break;
-      case 949:
-        ret = 917;
-        break;
-      case 950:
-        ret = 918;
-        break;
-      case 951:
-        ret = 919;
-        break;
-      case 952:
-        ret = 920;
-        break;
-      case 953:
-        ret = 921;
-        break;
-      case 954:
-        ret = 922;
-        break;
-      case 955:
-        ret = 923;
-        break;
-      case 956:
-        ret = 924;
-        break;
-      case 957:
-        ret = 925;
-        break;
-      case 958:
-        ret = 926;
-        break;
-      case 959:
-        ret = 927;
-        break;
-      case 960:
-        ret = 928;
-        break;
-      case 961:
-        ret = 929;
-        break;
-      case 963:
-        ret = 931;
-        break;
-      case 964:
-        ret = 932;
-        break;
-      case 965:
-        ret = 933;
-        break;
-      case 966:
-        ret = 934;
-        break;
-      case 967:
-        ret = 935;
-        break;
-      case 968:
-        ret = 936;
-        break;
-      case 969:
-        ret = 937;
-        break;
-      case 970:
-        ret = 938;
-        break;
-      case 971:
-        ret = 939;
-        break;
-      case 972:
-        ret = 908;
-        break;
-      case 973:
-        ret = 910;
-        break;
-      case 974:
-        ret = 911;
-        break;
-      case 976:
-        ret = 914;
-        break;
-      case 977:
-        ret = 920;
-        break;
-      case 981:
-        ret = 934;
-        break;
-      case 982:
-        ret = 928;
-        break;
-      case 995:
-        ret = 994;
-        break;
-      case 997:
-        ret = 996;
-        break;
-      case 999:
-        ret = 998;
-        break;
-      case 1001:
-        ret = 1000;
-        break;
-      case 1003:
-        ret = 1002;
-        break;
-      case 1005:
-        ret = 1004;
-        break;
-      case 1007:
-        ret = 1006;
-        break;
-      case 1008:
-        ret = 922;
-        break;
-      case 1009:
-        ret = 929;
-        break;
-      case 1072:
-        ret = 1040;
-        break;
-      case 1073:
-        ret = 1041;
-        break;
-      case 1074:
-        ret = 1042;
-        break;
-      case 1075:
-        ret = 1043;
-        break;
-      case 1076:
-        ret = 1044;
-        break;
-      case 1077:
-        ret = 1045;
-        break;
-      case 1078:
-        ret = 1046;
-        break;
-      case 1079:
-        ret = 1047;
-        break;
-      case 1080:
-        ret = 1048;
-        break;
-      case 1081:
-        ret = 1049;
-        break;
-      case 1082:
-        ret = 1050;
-        break;
-      case 1083:
-        ret = 1051;
-        break;
-      case 1084:
-        ret = 1052;
-        break;
-      case 1085:
-        ret = 1053;
-        break;
-      case 1086:
-        ret = 1054;
-        break;
-      case 1087:
-        ret = 1055;
-        break;
-      case 1088:
-        ret = 1056;
-        break;
-      case 1089:
-        ret = 1057;
-        break;
-      case 1090:
-        ret = 1058;
-        break;
-      case 1091:
-        ret = 1059;
-        break;
-      case 1092:
-        ret = 1060;
-        break;
-      case 1093:
-        ret = 1061;
-        break;
-      case 1094:
-        ret = 1062;
-        break;
-      case 1095:
-        ret = 1063;
-        break;
-      case 1096:
-        ret = 1064;
-        break;
-      case 1097:
-        ret = 1065;
-        break;
-      case 1098:
-        ret = 1066;
-        break;
-      case 1099:
-        ret = 1067;
-        break;
-      case 1100:
-        ret = 1068;
-        break;
-      case 1101:
-        ret = 1069;
-        break;
-      case 1102:
-        ret = 1070;
-        break;
-      case 1103:
-        ret = 1071;
-        break;
-      case 1105:
-        ret = 1025;
-        break;
-      case 1106:
-        ret = 1026;
-        break;
-      case 1107:
-        ret = 1027;
-        break;
-      case 1108:
-        ret = 1028;
-        break;
-      case 1109:
-        ret = 1029;
-        break;
-      case 1110:
-        ret = 1030;
-        break;
-      case 1111:
-        ret = 1031;
-        break;
-      case 1112:
-        ret = 1032;
-        break;
-      case 1113:
-        ret = 1033;
-        break;
-      case 1114:
-        ret = 1034;
-        break;
-      case 1115:
-        ret = 1035;
-        break;
-      case 1116:
-        ret = 1036;
-        break;
-      case 1118:
-        ret = 1038;
-        break;
-      case 1119:
-        ret = 1039;
-        break;
-      case 1121:
-        ret = 1120;
-        break;
-      case 1123:
-        ret = 1122;
-        break;
-      case 1125:
-        ret = 1124;
-        break;
-      case 1127:
-        ret = 1126;
-        break;
-      case 1129:
-        ret = 1128;
-        break;
-      case 1131:
-        ret = 1130;
-        break;
-      case 1133:
-        ret = 1132;
-        break;
-      case 1135:
-        ret = 1134;
-        break;
-      case 1137:
-        ret = 1136;
-        break;
-      case 1139:
-        ret = 1138;
-        break;
-      case 1141:
-        ret = 1140;
-        break;
-      case 1143:
-        ret = 1142;
-        break;
-      case 1145:
-        ret = 1144;
-        break;
-      case 1147:
-        ret = 1146;
-        break;
-      case 1149:
-        ret = 1148;
-        break;
-      case 1151:
-        ret = 1150;
-        break;
-      case 1153:
-        ret = 1152;
-        break;
-      case 1169:
-        ret = 1168;
-        break;
-      case 1171:
-        ret = 1170;
-        break;
-      case 1173:
-        ret = 1172;
-        break;
-      case 1175:
-        ret = 1174;
-        break;
-      case 1177:
-        ret = 1176;
-        break;
-      case 1179:
-        ret = 1178;
-        break;
-      case 1181:
-        ret = 1180;
-        break;
-      case 1183:
-        ret = 1182;
-        break;
-      case 1185:
-        ret = 1184;
-        break;
-      case 1187:
-        ret = 1186;
-        break;
-      case 1189:
-        ret = 1188;
-        break;
-      case 1191:
-        ret = 1190;
-        break;
-      case 1193:
-        ret = 1192;
-        break;
-      case 1195:
-        ret = 1194;
-        break;
-      case 1197:
-        ret = 1196;
-        break;
-      case 1199:
-        ret = 1198;
-        break;
-      case 1201:
-        ret = 1200;
-        break;
-      case 1203:
-        ret = 1202;
-        break;
-      case 1205:
-        ret = 1204;
-        break;
-      case 1207:
-        ret = 1206;
-        break;
-      case 1209:
-        ret = 1208;
-        break;
-      case 1211:
-        ret = 1210;
-        break;
-      case 1213:
-        ret = 1212;
-        break;
-      case 1215:
-        ret = 1214;
-        break;
-      case 1218:
-        ret = 1217;
-        break;
-      case 1220:
-        ret = 1219;
-        break;
-      case 1224:
-        ret = 1223;
-        break;
-      case 1228:
-        ret = 1227;
-        break;
-      case 1233:
-        ret = 1232;
-        break;
-      case 1235:
-        ret = 1234;
-        break;
-      case 1237:
-        ret = 1236;
-        break;
-      case 1239:
-        ret = 1238;
-        break;
-      case 1241:
-        ret = 1240;
-        break;
-      case 1243:
-        ret = 1242;
-        break;
-      case 1245:
-        ret = 1244;
-        break;
-      case 1247:
-        ret = 1246;
-        break;
-      case 1249:
-        ret = 1248;
-        break;
-      case 1251:
-        ret = 1250;
-        break;
-      case 1253:
-        ret = 1252;
-        break;
-      case 1255:
-        ret = 1254;
-        break;
-      case 1257:
-        ret = 1256;
-        break;
-      case 1259:
-        ret = 1258;
-        break;
-      case 1263:
-        ret = 1262;
-        break;
-      case 1265:
-        ret = 1264;
-        break;
-      case 1267:
-        ret = 1266;
-        break;
-      case 1269:
-        ret = 1268;
-        break;
-      case 1273:
-        ret = 1272;
-        break;
-      case 1377:
-        ret = 1329;
-        break;
-      case 1378:
-        ret = 1330;
-        break;
-      case 1379:
-        ret = 1331;
-        break;
-      case 1380:
-        ret = 1332;
-        break;
-      case 1381:
-        ret = 1333;
-        break;
-      case 1382:
-        ret = 1334;
-        break;
-      case 1383:
-        ret = 1335;
-        break;
-      case 1384:
-        ret = 1336;
-        break;
-      case 1385:
-        ret = 1337;
-        break;
-      case 1386:
-        ret = 1338;
-        break;
-      case 1387:
-        ret = 1339;
-        break;
-      case 1388:
-        ret = 1340;
-        break;
-      case 1389:
-        ret = 1341;
-        break;
-      case 1390:
-        ret = 1342;
-        break;
-      case 1391:
-        ret = 1343;
-        break;
-      case 1392:
-        ret = 1344;
-        break;
-      case 1393:
-        ret = 1345;
-        break;
-      case 1394:
-        ret = 1346;
-        break;
-      case 1395:
-        ret = 1347;
-        break;
-      case 1396:
-        ret = 1348;
-        break;
-      case 1397:
-        ret = 1349;
-        break;
-      case 1398:
-        ret = 1350;
-        break;
-      case 1399:
-        ret = 1351;
-        break;
-      case 1400:
-        ret = 1352;
-        break;
-      case 1401:
-        ret = 1353;
-        break;
-      case 1402:
-        ret = 1354;
-        break;
-      case 1403:
-        ret = 1355;
-        break;
-      case 1404:
-        ret = 1356;
-        break;
-      case 1405:
-        ret = 1357;
-        break;
-      case 1406:
-        ret = 1358;
-        break;
-      case 1407:
-        ret = 1359;
-        break;
-      case 1408:
-        ret = 1360;
-        break;
-      case 1409:
-        ret = 1361;
-        break;
-      case 1410:
-        ret = 1362;
-        break;
-      case 1411:
-        ret = 1363;
-        break;
-      case 1412:
-        ret = 1364;
-        break;
-      case 1413:
-        ret = 1365;
-        break;
-      case 1414:
-        ret = 1366;
-        break;
-      case 7681:
-        ret = 7680;
-        break;
-      case 7683:
-        ret = 7682;
-        break;
-      case 7685:
-        ret = 7684;
-        break;
-      case 7687:
-        ret = 7686;
-        break;
-      case 7689:
-        ret = 7688;
-        break;
-      case 7691:
-        ret = 7690;
-        break;
-      case 7693:
-        ret = 7692;
-        break;
-      case 7695:
-        ret = 7694;
-        break;
-      case 7697:
-        ret = 7696;
-        break;
-      case 7699:
-        ret = 7698;
-        break;
-      case 7701:
-        ret = 7700;
-        break;
-      case 7703:
-        ret = 7702;
-        break;
-      case 7705:
-        ret = 7704;
-        break;
-      case 7707:
-        ret = 7706;
-        break;
-      case 7709:
-        ret = 7708;
-        break;
-      case 7711:
-        ret = 7710;
-        break;
-      case 7713:
-        ret = 7712;
-        break;
-      case 7715:
-        ret = 7714;
-        break;
-      case 7717:
-        ret = 7716;
-        break;
-      case 7719:
-        ret = 7718;
-        break;
-      case 7721:
-        ret = 7720;
-        break;
-      case 7723:
-        ret = 7722;
-        break;
-      case 7725:
-        ret = 7724;
-        break;
-      case 7727:
-        ret = 7726;
-        break;
-      case 7729:
-        ret = 7728;
-        break;
-      case 7731:
-        ret = 7730;
-        break;
-      case 7733:
-        ret = 7732;
-        break;
-      case 7735:
-        ret = 7734;
-        break;
-      case 7737:
-        ret = 7736;
-        break;
-      case 7739:
-        ret = 7738;
-        break;
-      case 7741:
-        ret = 7740;
-        break;
-      case 7743:
-        ret = 7742;
-        break;
-      case 7745:
-        ret = 7744;
-        break;
-      case 7747:
-        ret = 7746;
-        break;
-      case 7749:
-        ret = 7748;
-        break;
-      case 7751:
-        ret = 7750;
-        break;
-      case 7753:
-        ret = 7752;
-        break;
-      case 7755:
-        ret = 7754;
-        break;
-      case 7757:
-        ret = 7756;
-        break;
-      case 7759:
-        ret = 7758;
-        break;
-      case 7761:
-        ret = 7760;
-        break;
-      case 7763:
-        ret = 7762;
-        break;
-      case 7765:
-        ret = 7764;
-        break;
-      case 7767:
-        ret = 7766;
-        break;
-      case 7769:
-        ret = 7768;
-        break;
-      case 7771:
-        ret = 7770;
-        break;
-      case 7773:
-        ret = 7772;
-        break;
-      case 7775:
-        ret = 7774;
-        break;
-      case 7777:
-        ret = 7776;
-        break;
-      case 7779:
-        ret = 7778;
-        break;
-      case 7781:
-        ret = 7780;
-        break;
-      case 7783:
-        ret = 7782;
-        break;
-      case 7785:
-        ret = 7784;
-        break;
-      case 7787:
-        ret = 7786;
-        break;
-      case 7789:
-        ret = 7788;
-        break;
-      case 7791:
-        ret = 7790;
-        break;
-      case 7793:
-        ret = 7792;
-        break;
-      case 7795:
-        ret = 7794;
-        break;
-      case 7797:
-        ret = 7796;
-        break;
-      case 7799:
-        ret = 7798;
-        break;
-      case 7801:
-        ret = 7800;
-        break;
-      case 7803:
-        ret = 7802;
-        break;
-      case 7805:
-        ret = 7804;
-        break;
-      case 7807:
-        ret = 7806;
-        break;
-      case 7809:
-        ret = 7808;
-        break;
-      case 7811:
-        ret = 7810;
-        break;
-      case 7813:
-        ret = 7812;
-        break;
-      case 7815:
-        ret = 7814;
-        break;
-      case 7817:
-        ret = 7816;
-        break;
-      case 7819:
-        ret = 7818;
-        break;
-      case 7821:
-        ret = 7820;
-        break;
-      case 7823:
-        ret = 7822;
-        break;
-      case 7825:
-        ret = 7824;
-        break;
-      case 7827:
-        ret = 7826;
-        break;
-      case 7829:
-        ret = 7828;
-        break;
-      case 7841:
-        ret = 7840;
-        break;
-      case 7843:
-        ret = 7842;
-        break;
-      case 7845:
-        ret = 7844;
-        break;
-      case 7847:
-        ret = 7846;
-        break;
-      case 7849:
-        ret = 7848;
-        break;
-      case 7851:
-        ret = 7850;
-        break;
-      case 7853:
-        ret = 7852;
-        break;
-      case 7855:
-        ret = 7854;
-        break;
-      case 7857:
-        ret = 7856;
-        break;
-      case 7859:
-        ret = 7858;
-        break;
-      case 7861:
-        ret = 7860;
-        break;
-      case 7863:
-        ret = 7862;
-        break;
-      case 7865:
-        ret = 7864;
-        break;
-      case 7867:
-        ret = 7866;
-        break;
-      case 7869:
-        ret = 7868;
-        break;
-      case 7871:
-        ret = 7870;
-        break;
-      case 7873:
-        ret = 7872;
-        break;
-      case 7875:
-        ret = 7874;
-        break;
-      case 7877:
-        ret = 7876;
-        break;
-      case 7879:
-        ret = 7878;
-        break;
-      case 7881:
-        ret = 7880;
-        break;
-      case 7883:
-        ret = 7882;
-        break;
-      case 7885:
-        ret = 7884;
-        break;
-      case 7887:
-        ret = 7886;
-        break;
-      case 7889:
-        ret = 7888;
-        break;
-      case 7891:
-        ret = 7890;
-        break;
-      case 7893:
-        ret = 7892;
-        break;
-      case 7895:
-        ret = 7894;
-        break;
-      case 7897:
-        ret = 7896;
-        break;
-      case 7899:
-        ret = 7898;
-        break;
-      case 7901:
-        ret = 7900;
-        break;
-      case 7903:
-        ret = 7902;
-        break;
-      case 7905:
-        ret = 7904;
-        break;
-      case 7907:
-        ret = 7906;
-        break;
-      case 7909:
-        ret = 7908;
-        break;
-      case 7911:
-        ret = 7910;
-        break;
-      case 7913:
-        ret = 7912;
-        break;
-      case 7915:
-        ret = 7914;
-        break;
-      case 7917:
-        ret = 7916;
-        break;
-      case 7919:
-        ret = 7918;
-        break;
-      case 7921:
-        ret = 7920;
-        break;
-      case 7923:
-        ret = 7922;
-        break;
-      case 7925:
-        ret = 7924;
-        break;
-      case 7927:
-        ret = 7926;
-        break;
-      case 7929:
-        ret = 7928;
-        break;
-      case 7936:
-        ret = 7944;
-        break;
-      case 7937:
-        ret = 7945;
-        break;
-      case 7938:
-        ret = 7946;
-        break;
-      case 7939:
-        ret = 7947;
-        break;
-      case 7940:
-        ret = 7948;
-        break;
-      case 7941:
-        ret = 7949;
-        break;
-      case 7942:
-        ret = 7950;
-        break;
-      case 7943:
-        ret = 7951;
-        break;
-      case 7952:
-        ret = 7960;
-        break;
-      case 7953:
-        ret = 7961;
-        break;
-      case 7954:
-        ret = 7962;
-        break;
-      case 7955:
-        ret = 7963;
-        break;
-      case 7956:
-        ret = 7964;
-        break;
-      case 7957:
-        ret = 7965;
-        break;
-      case 7968:
-        ret = 7976;
-        break;
-      case 7969:
-        ret = 7977;
-        break;
-      case 7970:
-        ret = 7978;
-        break;
-      case 7971:
-        ret = 7979;
-        break;
-      case 7972:
-        ret = 7980;
-        break;
-      case 7973:
-        ret = 7981;
-        break;
-      case 7974:
-        ret = 7982;
-        break;
-      case 7975:
-        ret = 7983;
-        break;
-      case 7984:
-        ret = 7992;
-        break;
-      case 7985:
-        ret = 7993;
-        break;
-      case 7986:
-        ret = 7994;
-        break;
-      case 7987:
-        ret = 7995;
-        break;
-      case 7988:
-        ret = 7996;
-        break;
-      case 7989:
-        ret = 7997;
-        break;
-      case 7990:
-        ret = 7998;
-        break;
-      case 7991:
-        ret = 7999;
-        break;
-      case 8000:
-        ret = 8008;
-        break;
-      case 8001:
-        ret = 8009;
-        break;
-      case 8002:
-        ret = 8010;
-        break;
-      case 8003:
-        ret = 8011;
-        break;
-      case 8004:
-        ret = 8012;
-        break;
-      case 8005:
-        ret = 8013;
-        break;
-      case 8017:
-        ret = 8025;
-        break;
-      case 8019:
-        ret = 8027;
-        break;
-      case 8021:
-        ret = 8029;
-        break;
-      case 8023:
-        ret = 8031;
-        break;
-      case 8032:
-        ret = 8040;
-        break;
-      case 8033:
-        ret = 8041;
-        break;
-      case 8034:
-        ret = 8042;
-        break;
-      case 8035:
-        ret = 8043;
-        break;
-      case 8036:
-        ret = 8044;
-        break;
-      case 8037:
-        ret = 8045;
-        break;
-      case 8038:
-        ret = 8046;
-        break;
-      case 8039:
-        ret = 8047;
-        break;
-      case 8048:
-        ret = 8122;
-        break;
-      case 8049:
-        ret = 8123;
-        break;
-      case 8050:
-        ret = 8136;
-        break;
-      case 8051:
-        ret = 8137;
-        break;
-      case 8052:
-        ret = 8138;
-        break;
-      case 8053:
-        ret = 8139;
-        break;
-      case 8054:
-        ret = 8154;
-        break;
-      case 8055:
-        ret = 8155;
-        break;
-      case 8056:
-        ret = 8184;
-        break;
-      case 8057:
-        ret = 8185;
-        break;
-      case 8058:
-        ret = 8170;
-        break;
-      case 8059:
-        ret = 8171;
-        break;
-      case 8060:
-        ret = 8186;
-        break;
-      case 8061:
-        ret = 8187;
-        break;
-      case 8064:
-        ret = 8072;
-        break;
-      case 8065:
-        ret = 8073;
-        break;
-      case 8066:
-        ret = 8074;
-        break;
-      case 8067:
-        ret = 8075;
-        break;
-      case 8068:
-        ret = 8076;
-        break;
-      case 8069:
-        ret = 8077;
-        break;
-      case 8070:
-        ret = 8078;
-        break;
-      case 8071:
-        ret = 8079;
-        break;
-      case 8080:
-        ret = 8088;
-        break;
-      case 8081:
-        ret = 8089;
-        break;
-      case 8082:
-        ret = 8090;
-        break;
-      case 8083:
-        ret = 8091;
-        break;
-      case 8084:
-        ret = 8092;
-        break;
-      case 8085:
-        ret = 8093;
-        break;
-      case 8086:
-        ret = 8094;
-        break;
-      case 8087:
-        ret = 8095;
-        break;
-      case 8096:
-        ret = 8104;
-        break;
-      case 8097:
-        ret = 8105;
-        break;
-      case 8098:
-        ret = 8106;
-        break;
-      case 8099:
-        ret = 8107;
-        break;
-      case 8100:
-        ret = 8108;
-        break;
-      case 8101:
-        ret = 8109;
-        break;
-      case 8102:
-        ret = 8110;
-        break;
-      case 8103:
-        ret = 8111;
-        break;
-      case 8112:
-        ret = 8120;
-        break;
-      case 8113:
-        ret = 8121;
-        break;
-      case 8115:
-        ret = 8124;
-        break;
-      case 8131:
-        ret = 8140;
-        break;
-      case 8144:
-        ret = 8152;
-        break;
-      case 8145:
-        ret = 8153;
-        break;
-      case 8160:
-        ret = 8168;
-        break;
-      case 8161:
-        ret = 8169;
-        break;
-      case 8165:
-        ret = 8172;
-        break;
-      case 8179:
-        ret = 8188;
-        break;
-      case 8560:
-        ret = 8544;
-        break;
-      case 8561:
-        ret = 8545;
-        break;
-      case 8562:
-        ret = 8546;
-        break;
-      case 8563:
-        ret = 8547;
-        break;
-      case 8564:
-        ret = 8548;
-        break;
-      case 8565:
-        ret = 8549;
-        break;
-      case 8566:
-        ret = 8550;
-        break;
-      case 8567:
-        ret = 8551;
-        break;
-      case 8568:
-        ret = 8552;
-        break;
-      case 8569:
-        ret = 8553;
-        break;
-      case 8570:
-        ret = 8554;
-        break;
-      case 8571:
-        ret = 8555;
-        break;
-      case 8572:
-        ret = 8556;
-        break;
-      case 8573:
-        ret = 8557;
-        break;
-      case 8574:
-        ret = 8558;
-        break;
-      case 8575:
-        ret = 8559;
-        break;
-      case 9424:
-        ret = 9398;
-        break;
-      case 9425:
-        ret = 9399;
-        break;
-      case 9426:
-        ret = 9400;
-        break;
-      case 9427:
-        ret = 9401;
-        break;
-      case 9428:
-        ret = 9402;
-        break;
-      case 9429:
-        ret = 9403;
-        break;
-      case 9430:
-        ret = 9404;
-        break;
-      case 9431:
-        ret = 9405;
-        break;
-      case 9432:
-        ret = 9406;
-        break;
-      case 9433:
-        ret = 9407;
-        break;
-      case 9434:
-        ret = 9408;
-        break;
-      case 9435:
-        ret = 9409;
-        break;
-      case 9436:
-        ret = 9410;
-        break;
-      case 9437:
-        ret = 9411;
-        break;
-      case 9438:
-        ret = 9412;
-        break;
-      case 9439:
-        ret = 9413;
-        break;
-      case 9440:
-        ret = 9414;
-        break;
-      case 9441:
-        ret = 9415;
-        break;
-      case 9442:
-        ret = 9416;
-        break;
-      case 9443:
-        ret = 9417;
-        break;
-      case 9444:
-        ret = 9418;
-        break;
-      case 9445:
-        ret = 9419;
-        break;
-      case 9446:
-        ret = 9420;
-        break;
-      case 9447:
-        ret = 9421;
-        break;
-      case 9448:
-        ret = 9422;
-        break;
-      case 9449:
-        ret = 9423;
-        break;
-      case 65345:
-        ret = 65313;
-        break;
-      case 65346:
-        ret = 65314;
-        break;
-      case 65347:
-        ret = 65315;
-        break;
-      case 65348:
-        ret = 65316;
-        break;
-      case 65349:
-        ret = 65317;
-        break;
-      case 65350:
-        ret = 65318;
-        break;
-      case 65351:
-        ret = 65319;
-        break;
-      case 65352:
-        ret = 65320;
-        break;
-      case 65353:
-        ret = 65321;
-        break;
-      case 65354:
-        ret = 65322;
-        break;
-      case 65355:
-        ret = 65323;
-        break;
-      case 65356:
-        ret = 65324;
-        break;
-      case 65357:
-        ret = 65325;
-        break;
-      case 65358:
-        ret = 65326;
-        break;
-      case 65359:
-        ret = 65327;
-        break;
-      case 65360:
-        ret = 65328;
-        break;
-      case 65361:
-        ret = 65329;
-        break;
-      case 65362:
-        ret = 65330;
-        break;
-      case 65363:
-        ret = 65331;
-        break;
-      case 65364:
-        ret = 65332;
-        break;
-      case 65365:
-        ret = 65333;
-        break;
-      case 65366:
-        ret = 65334;
-        break;
-      case 65367:
-        ret = 65335;
-        break;
-      case 65368:
-        ret = 65336;
-        break;
-      case 65369:
-        ret = 65337;
-        break;
-      case 65370:
-        ret = 65338;
-        break;
-      }
-      return (char) ret;
-    }
+//    if (java_1_0)
+//    {
+//      int ret = (int) c;
+//      switch (c)
+//      {
+//      case 97:
+//        ret = 65;
+//        break;
+//      case 98:
+//        ret = 66;
+//        break;
+//      case 99:
+//        ret = 67;
+//        break;
+//      case 100:
+//        ret = 68;
+//        break;
+//      case 101:
+//        ret = 69;
+//        break;
+//      case 102:
+//        ret = 70;
+//        break;
+//      case 103:
+//        ret = 71;
+//        break;
+//      case 104:
+//        ret = 72;
+//        break;
+//      case 105:
+//        ret = 73;
+//        break;
+//      case 106:
+//        ret = 74;
+//        break;
+//      case 107:
+//        ret = 75;
+//        break;
+//      case 108:
+//        ret = 76;
+//        break;
+//      case 109:
+//        ret = 77;
+//        break;
+//      case 110:
+//        ret = 78;
+//        break;
+//      case 111:
+//        ret = 79;
+//        break;
+//      case 112:
+//        ret = 80;
+//        break;
+//      case 113:
+//        ret = 81;
+//        break;
+//      case 114:
+//        ret = 82;
+//        break;
+//      case 115:
+//        ret = 83;
+//        break;
+//      case 116:
+//        ret = 84;
+//        break;
+//      case 117:
+//        ret = 85;
+//        break;
+//      case 118:
+//        ret = 86;
+//        break;
+//      case 119:
+//        ret = 87;
+//        break;
+//      case 120:
+//        ret = 88;
+//        break;
+//      case 121:
+//        ret = 89;
+//        break;
+//      case 122:
+//        ret = 90;
+//        break;
+//      case 224:
+//        ret = 192;
+//        break;
+//      case 225:
+//        ret = 193;
+//        break;
+//      case 226:
+//        ret = 194;
+//        break;
+//      case 227:
+//        ret = 195;
+//        break;
+//      case 228:
+//        ret = 196;
+//        break;
+//      case 229:
+//        ret = 197;
+//        break;
+//      case 230:
+//        ret = 198;
+//        break;
+//      case 231:
+//        ret = 199;
+//        break;
+//      case 232:
+//        ret = 200;
+//        break;
+//      case 233:
+//        ret = 201;
+//        break;
+//      case 234:
+//        ret = 202;
+//        break;
+//      case 235:
+//        ret = 203;
+//        break;
+//      case 236:
+//        ret = 204;
+//        break;
+//      case 237:
+//        ret = 205;
+//        break;
+//      case 238:
+//        ret = 206;
+//        break;
+//      case 239:
+//        ret = 207;
+//        break;
+//      case 240:
+//        ret = 208;
+//        break;
+//      case 241:
+//        ret = 209;
+//        break;
+//      case 242:
+//        ret = 210;
+//        break;
+//      case 243:
+//        ret = 211;
+//        break;
+//      case 244:
+//        ret = 212;
+//        break;
+//      case 245:
+//        ret = 213;
+//        break;
+//      case 246:
+//        ret = 214;
+//        break;
+//      case 248:
+//        ret = 216;
+//        break;
+//      case 249:
+//        ret = 217;
+//        break;
+//      case 250:
+//        ret = 218;
+//        break;
+//      case 251:
+//        ret = 219;
+//        break;
+//      case 252:
+//        ret = 220;
+//        break;
+//      case 253:
+//        ret = 221;
+//        break;
+//      case 254:
+//        ret = 222;
+//        break;
+//      case 255:
+//        ret = 376;
+//        break;
+//      case 257:
+//        ret = 256;
+//        break;
+//      case 259:
+//        ret = 258;
+//        break;
+//      case 261:
+//        ret = 260;
+//        break;
+//      case 263:
+//        ret = 262;
+//        break;
+//      case 265:
+//        ret = 264;
+//        break;
+//      case 267:
+//        ret = 266;
+//        break;
+//      case 269:
+//        ret = 268;
+//        break;
+//      case 271:
+//        ret = 270;
+//        break;
+//      case 273:
+//        ret = 272;
+//        break;
+//      case 275:
+//        ret = 274;
+//        break;
+//      case 277:
+//        ret = 276;
+//        break;
+//      case 279:
+//        ret = 278;
+//        break;
+//      case 281:
+//        ret = 280;
+//        break;
+//      case 283:
+//        ret = 282;
+//        break;
+//      case 285:
+//        ret = 284;
+//        break;
+//      case 287:
+//        ret = 286;
+//        break;
+//      case 289:
+//        ret = 288;
+//        break;
+//      case 291:
+//        ret = 290;
+//        break;
+//      case 293:
+//        ret = 292;
+//        break;
+//      case 295:
+//        ret = 294;
+//        break;
+//      case 297:
+//        ret = 296;
+//        break;
+//      case 299:
+//        ret = 298;
+//        break;
+//      case 301:
+//        ret = 300;
+//        break;
+//      case 303:
+//        ret = 302;
+//        break;
+//      case 305:
+//        ret = 73;
+//        break;
+//      case 307:
+//        ret = 306;
+//        break;
+//      case 309:
+//        ret = 308;
+//        break;
+//      case 311:
+//        ret = 310;
+//        break;
+//      case 314:
+//        ret = 313;
+//        break;
+//      case 316:
+//        ret = 315;
+//        break;
+//      case 318:
+//        ret = 317;
+//        break;
+//      case 320:
+//        ret = 319;
+//        break;
+//      case 322:
+//        ret = 321;
+//        break;
+//      case 324:
+//        ret = 323;
+//        break;
+//      case 326:
+//        ret = 325;
+//        break;
+//      case 328:
+//        ret = 327;
+//        break;
+//      case 331:
+//        ret = 330;
+//        break;
+//      case 333:
+//        ret = 332;
+//        break;
+//      case 335:
+//        ret = 334;
+//        break;
+//      case 337:
+//        ret = 336;
+//        break;
+//      case 339:
+//        ret = 338;
+//        break;
+//      case 341:
+//        ret = 340;
+//        break;
+//      case 343:
+//        ret = 342;
+//        break;
+//      case 345:
+//        ret = 344;
+//        break;
+//      case 347:
+//        ret = 346;
+//        break;
+//      case 349:
+//        ret = 348;
+//        break;
+//      case 351:
+//        ret = 350;
+//        break;
+//      case 353:
+//        ret = 352;
+//        break;
+//      case 355:
+//        ret = 354;
+//        break;
+//      case 357:
+//        ret = 356;
+//        break;
+//      case 359:
+//        ret = 358;
+//        break;
+//      case 361:
+//        ret = 360;
+//        break;
+//      case 363:
+//        ret = 362;
+//        break;
+//      case 365:
+//        ret = 364;
+//        break;
+//      case 367:
+//        ret = 366;
+//        break;
+//      case 369:
+//        ret = 368;
+//        break;
+//      case 371:
+//        ret = 370;
+//        break;
+//      case 373:
+//        ret = 372;
+//        break;
+//      case 375:
+//        ret = 374;
+//        break;
+//      case 378:
+//        ret = 377;
+//        break;
+//      case 380:
+//        ret = 379;
+//        break;
+//      case 382:
+//        ret = 381;
+//        break;
+//      case 383:
+//        ret = 83;
+//        break;
+//      case 387:
+//        ret = 386;
+//        break;
+//      case 389:
+//        ret = 388;
+//        break;
+//      case 392:
+//        ret = 391;
+//        break;
+//      case 396:
+//        ret = 395;
+//        break;
+//      case 402:
+//        ret = 401;
+//        break;
+//      case 409:
+//        ret = 408;
+//        break;
+//      case 417:
+//        ret = 416;
+//        break;
+//      case 419:
+//        ret = 418;
+//        break;
+//      case 421:
+//        ret = 420;
+//        break;
+//      case 424:
+//        ret = 423;
+//        break;
+//      case 429:
+//        ret = 428;
+//        break;
+//      case 432:
+//        ret = 431;
+//        break;
+//      case 436:
+//        ret = 435;
+//        break;
+//      case 438:
+//        ret = 437;
+//        break;
+//      case 441:
+//        ret = 440;
+//        break;
+//      case 445:
+//        ret = 444;
+//        break;
+//      case 453:
+//        ret = 452;
+//        break;
+//      case 454:
+//        ret = 452;
+//        break;
+//      case 456:
+//        ret = 455;
+//        break;
+//      case 457:
+//        ret = 455;
+//        break;
+//      case 459:
+//        ret = 458;
+//        break;
+//      case 460:
+//        ret = 458;
+//        break;
+//      case 462:
+//        ret = 461;
+//        break;
+//      case 464:
+//        ret = 463;
+//        break;
+//      case 466:
+//        ret = 465;
+//        break;
+//      case 468:
+//        ret = 467;
+//        break;
+//      case 470:
+//        ret = 469;
+//        break;
+//      case 472:
+//        ret = 471;
+//        break;
+//      case 474:
+//        ret = 473;
+//        break;
+//      case 476:
+//        ret = 475;
+//        break;
+//      case 479:
+//        ret = 478;
+//        break;
+//      case 481:
+//        ret = 480;
+//        break;
+//      case 483:
+//        ret = 482;
+//        break;
+//      case 485:
+//        ret = 484;
+//        break;
+//      case 487:
+//        ret = 486;
+//        break;
+//      case 489:
+//        ret = 488;
+//        break;
+//      case 491:
+//        ret = 490;
+//        break;
+//      case 493:
+//        ret = 492;
+//        break;
+//      case 495:
+//        ret = 494;
+//        break;
+//      case 498:
+//        ret = 497;
+//        break;
+//      case 499:
+//        ret = 497;
+//        break;
+//      case 501:
+//        ret = 500;
+//        break;
+//      case 507:
+//        ret = 506;
+//        break;
+//      case 509:
+//        ret = 508;
+//        break;
+//      case 511:
+//        ret = 510;
+//        break;
+//      case 513:
+//        ret = 512;
+//        break;
+//      case 515:
+//        ret = 514;
+//        break;
+//      case 517:
+//        ret = 516;
+//        break;
+//      case 519:
+//        ret = 518;
+//        break;
+//      case 521:
+//        ret = 520;
+//        break;
+//      case 523:
+//        ret = 522;
+//        break;
+//      case 525:
+//        ret = 524;
+//        break;
+//      case 527:
+//        ret = 526;
+//        break;
+//      case 529:
+//        ret = 528;
+//        break;
+//      case 531:
+//        ret = 530;
+//        break;
+//      case 533:
+//        ret = 532;
+//        break;
+//      case 535:
+//        ret = 534;
+//        break;
+//      case 595:
+//        ret = 385;
+//        break;
+//      case 596:
+//        ret = 390;
+//        break;
+//      case 598:
+//        ret = 393;
+//        break;
+//      case 599:
+//        ret = 394;
+//        break;
+//      case 600:
+//        ret = 398;
+//        break;
+//      case 601:
+//        ret = 399;
+//        break;
+//      case 603:
+//        ret = 400;
+//        break;
+//      case 608:
+//        ret = 403;
+//        break;
+//      case 611:
+//        ret = 404;
+//        break;
+//      case 616:
+//        ret = 407;
+//        break;
+//      case 617:
+//        ret = 406;
+//        break;
+//      case 623:
+//        ret = 412;
+//        break;
+//      case 626:
+//        ret = 413;
+//        break;
+//      case 643:
+//        ret = 425;
+//        break;
+//      case 648:
+//        ret = 430;
+//        break;
+//      case 650:
+//        ret = 433;
+//        break;
+//      case 651:
+//        ret = 434;
+//        break;
+//      case 658:
+//        ret = 439;
+//        break;
+//      case 940:
+//        ret = 902;
+//        break;
+//      case 941:
+//        ret = 904;
+//        break;
+//      case 942:
+//        ret = 905;
+//        break;
+//      case 943:
+//        ret = 906;
+//        break;
+//      case 945:
+//        ret = 913;
+//        break;
+//      case 946:
+//        ret = 914;
+//        break;
+//      case 947:
+//        ret = 915;
+//        break;
+//      case 948:
+//        ret = 916;
+//        break;
+//      case 949:
+//        ret = 917;
+//        break;
+//      case 950:
+//        ret = 918;
+//        break;
+//      case 951:
+//        ret = 919;
+//        break;
+//      case 952:
+//        ret = 920;
+//        break;
+//      case 953:
+//        ret = 921;
+//        break;
+//      case 954:
+//        ret = 922;
+//        break;
+//      case 955:
+//        ret = 923;
+//        break;
+//      case 956:
+//        ret = 924;
+//        break;
+//      case 957:
+//        ret = 925;
+//        break;
+//      case 958:
+//        ret = 926;
+//        break;
+//      case 959:
+//        ret = 927;
+//        break;
+//      case 960:
+//        ret = 928;
+//        break;
+//      case 961:
+//        ret = 929;
+//        break;
+//      case 963:
+//        ret = 931;
+//        break;
+//      case 964:
+//        ret = 932;
+//        break;
+//      case 965:
+//        ret = 933;
+//        break;
+//      case 966:
+//        ret = 934;
+//        break;
+//      case 967:
+//        ret = 935;
+//        break;
+//      case 968:
+//        ret = 936;
+//        break;
+//      case 969:
+//        ret = 937;
+//        break;
+//      case 970:
+//        ret = 938;
+//        break;
+//      case 971:
+//        ret = 939;
+//        break;
+//      case 972:
+//        ret = 908;
+//        break;
+//      case 973:
+//        ret = 910;
+//        break;
+//      case 974:
+//        ret = 911;
+//        break;
+//      case 976:
+//        ret = 914;
+//        break;
+//      case 977:
+//        ret = 920;
+//        break;
+//      case 981:
+//        ret = 934;
+//        break;
+//      case 982:
+//        ret = 928;
+//        break;
+//      case 995:
+//        ret = 994;
+//        break;
+//      case 997:
+//        ret = 996;
+//        break;
+//      case 999:
+//        ret = 998;
+//        break;
+//      case 1001:
+//        ret = 1000;
+//        break;
+//      case 1003:
+//        ret = 1002;
+//        break;
+//      case 1005:
+//        ret = 1004;
+//        break;
+//      case 1007:
+//        ret = 1006;
+//        break;
+//      case 1008:
+//        ret = 922;
+//        break;
+//      case 1009:
+//        ret = 929;
+//        break;
+//      case 1072:
+//        ret = 1040;
+//        break;
+//      case 1073:
+//        ret = 1041;
+//        break;
+//      case 1074:
+//        ret = 1042;
+//        break;
+//      case 1075:
+//        ret = 1043;
+//        break;
+//      case 1076:
+//        ret = 1044;
+//        break;
+//      case 1077:
+//        ret = 1045;
+//        break;
+//      case 1078:
+//        ret = 1046;
+//        break;
+//      case 1079:
+//        ret = 1047;
+//        break;
+//      case 1080:
+//        ret = 1048;
+//        break;
+//      case 1081:
+//        ret = 1049;
+//        break;
+//      case 1082:
+//        ret = 1050;
+//        break;
+//      case 1083:
+//        ret = 1051;
+//        break;
+//      case 1084:
+//        ret = 1052;
+//        break;
+//      case 1085:
+//        ret = 1053;
+//        break;
+//      case 1086:
+//        ret = 1054;
+//        break;
+//      case 1087:
+//        ret = 1055;
+//        break;
+//      case 1088:
+//        ret = 1056;
+//        break;
+//      case 1089:
+//        ret = 1057;
+//        break;
+//      case 1090:
+//        ret = 1058;
+//        break;
+//      case 1091:
+//        ret = 1059;
+//        break;
+//      case 1092:
+//        ret = 1060;
+//        break;
+//      case 1093:
+//        ret = 1061;
+//        break;
+//      case 1094:
+//        ret = 1062;
+//        break;
+//      case 1095:
+//        ret = 1063;
+//        break;
+//      case 1096:
+//        ret = 1064;
+//        break;
+//      case 1097:
+//        ret = 1065;
+//        break;
+//      case 1098:
+//        ret = 1066;
+//        break;
+//      case 1099:
+//        ret = 1067;
+//        break;
+//      case 1100:
+//        ret = 1068;
+//        break;
+//      case 1101:
+//        ret = 1069;
+//        break;
+//      case 1102:
+//        ret = 1070;
+//        break;
+//      case 1103:
+//        ret = 1071;
+//        break;
+//      case 1105:
+//        ret = 1025;
+//        break;
+//      case 1106:
+//        ret = 1026;
+//        break;
+//      case 1107:
+//        ret = 1027;
+//        break;
+//      case 1108:
+//        ret = 1028;
+//        break;
+//      case 1109:
+//        ret = 1029;
+//        break;
+//      case 1110:
+//        ret = 1030;
+//        break;
+//      case 1111:
+//        ret = 1031;
+//        break;
+//      case 1112:
+//        ret = 1032;
+//        break;
+//      case 1113:
+//        ret = 1033;
+//        break;
+//      case 1114:
+//        ret = 1034;
+//        break;
+//      case 1115:
+//        ret = 1035;
+//        break;
+//      case 1116:
+//        ret = 1036;
+//        break;
+//      case 1118:
+//        ret = 1038;
+//        break;
+//      case 1119:
+//        ret = 1039;
+//        break;
+//      case 1121:
+//        ret = 1120;
+//        break;
+//      case 1123:
+//        ret = 1122;
+//        break;
+//      case 1125:
+//        ret = 1124;
+//        break;
+//      case 1127:
+//        ret = 1126;
+//        break;
+//      case 1129:
+//        ret = 1128;
+//        break;
+//      case 1131:
+//        ret = 1130;
+//        break;
+//      case 1133:
+//        ret = 1132;
+//        break;
+//      case 1135:
+//        ret = 1134;
+//        break;
+//      case 1137:
+//        ret = 1136;
+//        break;
+//      case 1139:
+//        ret = 1138;
+//        break;
+//      case 1141:
+//        ret = 1140;
+//        break;
+//      case 1143:
+//        ret = 1142;
+//        break;
+//      case 1145:
+//        ret = 1144;
+//        break;
+//      case 1147:
+//        ret = 1146;
+//        break;
+//      case 1149:
+//        ret = 1148;
+//        break;
+//      case 1151:
+//        ret = 1150;
+//        break;
+//      case 1153:
+//        ret = 1152;
+//        break;
+//      case 1169:
+//        ret = 1168;
+//        break;
+//      case 1171:
+//        ret = 1170;
+//        break;
+//      case 1173:
+//        ret = 1172;
+//        break;
+//      case 1175:
+//        ret = 1174;
+//        break;
+//      case 1177:
+//        ret = 1176;
+//        break;
+//      case 1179:
+//        ret = 1178;
+//        break;
+//      case 1181:
+//        ret = 1180;
+//        break;
+//      case 1183:
+//        ret = 1182;
+//        break;
+//      case 1185:
+//        ret = 1184;
+//        break;
+//      case 1187:
+//        ret = 1186;
+//        break;
+//      case 1189:
+//        ret = 1188;
+//        break;
+//      case 1191:
+//        ret = 1190;
+//        break;
+//      case 1193:
+//        ret = 1192;
+//        break;
+//      case 1195:
+//        ret = 1194;
+//        break;
+//      case 1197:
+//        ret = 1196;
+//        break;
+//      case 1199:
+//        ret = 1198;
+//        break;
+//      case 1201:
+//        ret = 1200;
+//        break;
+//      case 1203:
+//        ret = 1202;
+//        break;
+//      case 1205:
+//        ret = 1204;
+//        break;
+//      case 1207:
+//        ret = 1206;
+//        break;
+//      case 1209:
+//        ret = 1208;
+//        break;
+//      case 1211:
+//        ret = 1210;
+//        break;
+//      case 1213:
+//        ret = 1212;
+//        break;
+//      case 1215:
+//        ret = 1214;
+//        break;
+//      case 1218:
+//        ret = 1217;
+//        break;
+//      case 1220:
+//        ret = 1219;
+//        break;
+//      case 1224:
+//        ret = 1223;
+//        break;
+//      case 1228:
+//        ret = 1227;
+//        break;
+//      case 1233:
+//        ret = 1232;
+//        break;
+//      case 1235:
+//        ret = 1234;
+//        break;
+//      case 1237:
+//        ret = 1236;
+//        break;
+//      case 1239:
+//        ret = 1238;
+//        break;
+//      case 1241:
+//        ret = 1240;
+//        break;
+//      case 1243:
+//        ret = 1242;
+//        break;
+//      case 1245:
+//        ret = 1244;
+//        break;
+//      case 1247:
+//        ret = 1246;
+//        break;
+//      case 1249:
+//        ret = 1248;
+//        break;
+//      case 1251:
+//        ret = 1250;
+//        break;
+//      case 1253:
+//        ret = 1252;
+//        break;
+//      case 1255:
+//        ret = 1254;
+//        break;
+//      case 1257:
+//        ret = 1256;
+//        break;
+//      case 1259:
+//        ret = 1258;
+//        break;
+//      case 1263:
+//        ret = 1262;
+//        break;
+//      case 1265:
+//        ret = 1264;
+//        break;
+//      case 1267:
+//        ret = 1266;
+//        break;
+//      case 1269:
+//        ret = 1268;
+//        break;
+//      case 1273:
+//        ret = 1272;
+//        break;
+//      case 1377:
+//        ret = 1329;
+//        break;
+//      case 1378:
+//        ret = 1330;
+//        break;
+//      case 1379:
+//        ret = 1331;
+//        break;
+//      case 1380:
+//        ret = 1332;
+//        break;
+//      case 1381:
+//        ret = 1333;
+//        break;
+//      case 1382:
+//        ret = 1334;
+//        break;
+//      case 1383:
+//        ret = 1335;
+//        break;
+//      case 1384:
+//        ret = 1336;
+//        break;
+//      case 1385:
+//        ret = 1337;
+//        break;
+//      case 1386:
+//        ret = 1338;
+//        break;
+//      case 1387:
+//        ret = 1339;
+//        break;
+//      case 1388:
+//        ret = 1340;
+//        break;
+//      case 1389:
+//        ret = 1341;
+//        break;
+//      case 1390:
+//        ret = 1342;
+//        break;
+//      case 1391:
+//        ret = 1343;
+//        break;
+//      case 1392:
+//        ret = 1344;
+//        break;
+//      case 1393:
+//        ret = 1345;
+//        break;
+//      case 1394:
+//        ret = 1346;
+//        break;
+//      case 1395:
+//        ret = 1347;
+//        break;
+//      case 1396:
+//        ret = 1348;
+//        break;
+//      case 1397:
+//        ret = 1349;
+//        break;
+//      case 1398:
+//        ret = 1350;
+//        break;
+//      case 1399:
+//        ret = 1351;
+//        break;
+//      case 1400:
+//        ret = 1352;
+//        break;
+//      case 1401:
+//        ret = 1353;
+//        break;
+//      case 1402:
+//        ret = 1354;
+//        break;
+//      case 1403:
+//        ret = 1355;
+//        break;
+//      case 1404:
+//        ret = 1356;
+//        break;
+//      case 1405:
+//        ret = 1357;
+//        break;
+//      case 1406:
+//        ret = 1358;
+//        break;
+//      case 1407:
+//        ret = 1359;
+//        break;
+//      case 1408:
+//        ret = 1360;
+//        break;
+//      case 1409:
+//        ret = 1361;
+//        break;
+//      case 1410:
+//        ret = 1362;
+//        break;
+//      case 1411:
+//        ret = 1363;
+//        break;
+//      case 1412:
+//        ret = 1364;
+//        break;
+//      case 1413:
+//        ret = 1365;
+//        break;
+//      case 1414:
+//        ret = 1366;
+//        break;
+//      case 7681:
+//        ret = 7680;
+//        break;
+//      case 7683:
+//        ret = 7682;
+//        break;
+//      case 7685:
+//        ret = 7684;
+//        break;
+//      case 7687:
+//        ret = 7686;
+//        break;
+//      case 7689:
+//        ret = 7688;
+//        break;
+//      case 7691:
+//        ret = 7690;
+//        break;
+//      case 7693:
+//        ret = 7692;
+//        break;
+//      case 7695:
+//        ret = 7694;
+//        break;
+//      case 7697:
+//        ret = 7696;
+//        break;
+//      case 7699:
+//        ret = 7698;
+//        break;
+//      case 7701:
+//        ret = 7700;
+//        break;
+//      case 7703:
+//        ret = 7702;
+//        break;
+//      case 7705:
+//        ret = 7704;
+//        break;
+//      case 7707:
+//        ret = 7706;
+//        break;
+//      case 7709:
+//        ret = 7708;
+//        break;
+//      case 7711:
+//        ret = 7710;
+//        break;
+//      case 7713:
+//        ret = 7712;
+//        break;
+//      case 7715:
+//        ret = 7714;
+//        break;
+//      case 7717:
+//        ret = 7716;
+//        break;
+//      case 7719:
+//        ret = 7718;
+//        break;
+//      case 7721:
+//        ret = 7720;
+//        break;
+//      case 7723:
+//        ret = 7722;
+//        break;
+//      case 7725:
+//        ret = 7724;
+//        break;
+//      case 7727:
+//        ret = 7726;
+//        break;
+//      case 7729:
+//        ret = 7728;
+//        break;
+//      case 7731:
+//        ret = 7730;
+//        break;
+//      case 7733:
+//        ret = 7732;
+//        break;
+//      case 7735:
+//        ret = 7734;
+//        break;
+//      case 7737:
+//        ret = 7736;
+//        break;
+//      case 7739:
+//        ret = 7738;
+//        break;
+//      case 7741:
+//        ret = 7740;
+//        break;
+//      case 7743:
+//        ret = 7742;
+//        break;
+//      case 7745:
+//        ret = 7744;
+//        break;
+//      case 7747:
+//        ret = 7746;
+//        break;
+//      case 7749:
+//        ret = 7748;
+//        break;
+//      case 7751:
+//        ret = 7750;
+//        break;
+//      case 7753:
+//        ret = 7752;
+//        break;
+//      case 7755:
+//        ret = 7754;
+//        break;
+//      case 7757:
+//        ret = 7756;
+//        break;
+//      case 7759:
+//        ret = 7758;
+//        break;
+//      case 7761:
+//        ret = 7760;
+//        break;
+//      case 7763:
+//        ret = 7762;
+//        break;
+//      case 7765:
+//        ret = 7764;
+//        break;
+//      case 7767:
+//        ret = 7766;
+//        break;
+//      case 7769:
+//        ret = 7768;
+//        break;
+//      case 7771:
+//        ret = 7770;
+//        break;
+//      case 7773:
+//        ret = 7772;
+//        break;
+//      case 7775:
+//        ret = 7774;
+//        break;
+//      case 7777:
+//        ret = 7776;
+//        break;
+//      case 7779:
+//        ret = 7778;
+//        break;
+//      case 7781:
+//        ret = 7780;
+//        break;
+//      case 7783:
+//        ret = 7782;
+//        break;
+//      case 7785:
+//        ret = 7784;
+//        break;
+//      case 7787:
+//        ret = 7786;
+//        break;
+//      case 7789:
+//        ret = 7788;
+//        break;
+//      case 7791:
+//        ret = 7790;
+//        break;
+//      case 7793:
+//        ret = 7792;
+//        break;
+//      case 7795:
+//        ret = 7794;
+//        break;
+//      case 7797:
+//        ret = 7796;
+//        break;
+//      case 7799:
+//        ret = 7798;
+//        break;
+//      case 7801:
+//        ret = 7800;
+//        break;
+//      case 7803:
+//        ret = 7802;
+//        break;
+//      case 7805:
+//        ret = 7804;
+//        break;
+//      case 7807:
+//        ret = 7806;
+//        break;
+//      case 7809:
+//        ret = 7808;
+//        break;
+//      case 7811:
+//        ret = 7810;
+//        break;
+//      case 7813:
+//        ret = 7812;
+//        break;
+//      case 7815:
+//        ret = 7814;
+//        break;
+//      case 7817:
+//        ret = 7816;
+//        break;
+//      case 7819:
+//        ret = 7818;
+//        break;
+//      case 7821:
+//        ret = 7820;
+//        break;
+//      case 7823:
+//        ret = 7822;
+//        break;
+//      case 7825:
+//        ret = 7824;
+//        break;
+//      case 7827:
+//        ret = 7826;
+//        break;
+//      case 7829:
+//        ret = 7828;
+//        break;
+//      case 7841:
+//        ret = 7840;
+//        break;
+//      case 7843:
+//        ret = 7842;
+//        break;
+//      case 7845:
+//        ret = 7844;
+//        break;
+//      case 7847:
+//        ret = 7846;
+//        break;
+//      case 7849:
+//        ret = 7848;
+//        break;
+//      case 7851:
+//        ret = 7850;
+//        break;
+//      case 7853:
+//        ret = 7852;
+//        break;
+//      case 7855:
+//        ret = 7854;
+//        break;
+//      case 7857:
+//        ret = 7856;
+//        break;
+//      case 7859:
+//        ret = 7858;
+//        break;
+//      case 7861:
+//        ret = 7860;
+//        break;
+//      case 7863:
+//        ret = 7862;
+//        break;
+//      case 7865:
+//        ret = 7864;
+//        break;
+//      case 7867:
+//        ret = 7866;
+//        break;
+//      case 7869:
+//        ret = 7868;
+//        break;
+//      case 7871:
+//        ret = 7870;
+//        break;
+//      case 7873:
+//        ret = 7872;
+//        break;
+//      case 7875:
+//        ret = 7874;
+//        break;
+//      case 7877:
+//        ret = 7876;
+//        break;
+//      case 7879:
+//        ret = 7878;
+//        break;
+//      case 7881:
+//        ret = 7880;
+//        break;
+//      case 7883:
+//        ret = 7882;
+//        break;
+//      case 7885:
+//        ret = 7884;
+//        break;
+//      case 7887:
+//        ret = 7886;
+//        break;
+//      case 7889:
+//        ret = 7888;
+//        break;
+//      case 7891:
+//        ret = 7890;
+//        break;
+//      case 7893:
+//        ret = 7892;
+//        break;
+//      case 7895:
+//        ret = 7894;
+//        break;
+//      case 7897:
+//        ret = 7896;
+//        break;
+//      case 7899:
+//        ret = 7898;
+//        break;
+//      case 7901:
+//        ret = 7900;
+//        break;
+//      case 7903:
+//        ret = 7902;
+//        break;
+//      case 7905:
+//        ret = 7904;
+//        break;
+//      case 7907:
+//        ret = 7906;
+//        break;
+//      case 7909:
+//        ret = 7908;
+//        break;
+//      case 7911:
+//        ret = 7910;
+//        break;
+//      case 7913:
+//        ret = 7912;
+//        break;
+//      case 7915:
+//        ret = 7914;
+//        break;
+//      case 7917:
+//        ret = 7916;
+//        break;
+//      case 7919:
+//        ret = 7918;
+//        break;
+//      case 7921:
+//        ret = 7920;
+//        break;
+//      case 7923:
+//        ret = 7922;
+//        break;
+//      case 7925:
+//        ret = 7924;
+//        break;
+//      case 7927:
+//        ret = 7926;
+//        break;
+//      case 7929:
+//        ret = 7928;
+//        break;
+//      case 7936:
+//        ret = 7944;
+//        break;
+//      case 7937:
+//        ret = 7945;
+//        break;
+//      case 7938:
+//        ret = 7946;
+//        break;
+//      case 7939:
+//        ret = 7947;
+//        break;
+//      case 7940:
+//        ret = 7948;
+//        break;
+//      case 7941:
+//        ret = 7949;
+//        break;
+//      case 7942:
+//        ret = 7950;
+//        break;
+//      case 7943:
+//        ret = 7951;
+//        break;
+//      case 7952:
+//        ret = 7960;
+//        break;
+//      case 7953:
+//        ret = 7961;
+//        break;
+//      case 7954:
+//        ret = 7962;
+//        break;
+//      case 7955:
+//        ret = 7963;
+//        break;
+//      case 7956:
+//        ret = 7964;
+//        break;
+//      case 7957:
+//        ret = 7965;
+//        break;
+//      case 7968:
+//        ret = 7976;
+//        break;
+//      case 7969:
+//        ret = 7977;
+//        break;
+//      case 7970:
+//        ret = 7978;
+//        break;
+//      case 7971:
+//        ret = 7979;
+//        break;
+//      case 7972:
+//        ret = 7980;
+//        break;
+//      case 7973:
+//        ret = 7981;
+//        break;
+//      case 7974:
+//        ret = 7982;
+//        break;
+//      case 7975:
+//        ret = 7983;
+//        break;
+//      case 7984:
+//        ret = 7992;
+//        break;
+//      case 7985:
+//        ret = 7993;
+//        break;
+//      case 7986:
+//        ret = 7994;
+//        break;
+//      case 7987:
+//        ret = 7995;
+//        break;
+//      case 7988:
+//        ret = 7996;
+//        break;
+//      case 7989:
+//        ret = 7997;
+//        break;
+//      case 7990:
+//        ret = 7998;
+//        break;
+//      case 7991:
+//        ret = 7999;
+//        break;
+//      case 8000:
+//        ret = 8008;
+//        break;
+//      case 8001:
+//        ret = 8009;
+//        break;
+//      case 8002:
+//        ret = 8010;
+//        break;
+//      case 8003:
+//        ret = 8011;
+//        break;
+//      case 8004:
+//        ret = 8012;
+//        break;
+//      case 8005:
+//        ret = 8013;
+//        break;
+//      case 8017:
+//        ret = 8025;
+//        break;
+//      case 8019:
+//        ret = 8027;
+//        break;
+//      case 8021:
+//        ret = 8029;
+//        break;
+//      case 8023:
+//        ret = 8031;
+//        break;
+//      case 8032:
+//        ret = 8040;
+//        break;
+//      case 8033:
+//        ret = 8041;
+//        break;
+//      case 8034:
+//        ret = 8042;
+//        break;
+//      case 8035:
+//        ret = 8043;
+//        break;
+//      case 8036:
+//        ret = 8044;
+//        break;
+//      case 8037:
+//        ret = 8045;
+//        break;
+//      case 8038:
+//        ret = 8046;
+//        break;
+//      case 8039:
+//        ret = 8047;
+//        break;
+//      case 8048:
+//        ret = 8122;
+//        break;
+//      case 8049:
+//        ret = 8123;
+//        break;
+//      case 8050:
+//        ret = 8136;
+//        break;
+//      case 8051:
+//        ret = 8137;
+//        break;
+//      case 8052:
+//        ret = 8138;
+//        break;
+//      case 8053:
+//        ret = 8139;
+//        break;
+//      case 8054:
+//        ret = 8154;
+//        break;
+//      case 8055:
+//        ret = 8155;
+//        break;
+//      case 8056:
+//        ret = 8184;
+//        break;
+//      case 8057:
+//        ret = 8185;
+//        break;
+//      case 8058:
+//        ret = 8170;
+//        break;
+//      case 8059:
+//        ret = 8171;
+//        break;
+//      case 8060:
+//        ret = 8186;
+//        break;
+//      case 8061:
+//        ret = 8187;
+//        break;
+//      case 8064:
+//        ret = 8072;
+//        break;
+//      case 8065:
+//        ret = 8073;
+//        break;
+//      case 8066:
+//        ret = 8074;
+//        break;
+//      case 8067:
+//        ret = 8075;
+//        break;
+//      case 8068:
+//        ret = 8076;
+//        break;
+//      case 8069:
+//        ret = 8077;
+//        break;
+//      case 8070:
+//        ret = 8078;
+//        break;
+//      case 8071:
+//        ret = 8079;
+//        break;
+//      case 8080:
+//        ret = 8088;
+//        break;
+//      case 8081:
+//        ret = 8089;
+//        break;
+//      case 8082:
+//        ret = 8090;
+//        break;
+//      case 8083:
+//        ret = 8091;
+//        break;
+//      case 8084:
+//        ret = 8092;
+//        break;
+//      case 8085:
+//        ret = 8093;
+//        break;
+//      case 8086:
+//        ret = 8094;
+//        break;
+//      case 8087:
+//        ret = 8095;
+//        break;
+//      case 8096:
+//        ret = 8104;
+//        break;
+//      case 8097:
+//        ret = 8105;
+//        break;
+//      case 8098:
+//        ret = 8106;
+//        break;
+//      case 8099:
+//        ret = 8107;
+//        break;
+//      case 8100:
+//        ret = 8108;
+//        break;
+//      case 8101:
+//        ret = 8109;
+//        break;
+//      case 8102:
+//        ret = 8110;
+//        break;
+//      case 8103:
+//        ret = 8111;
+//        break;
+//      case 8112:
+//        ret = 8120;
+//        break;
+//      case 8113:
+//        ret = 8121;
+//        break;
+//      case 8115:
+//        ret = 8124;
+//        break;
+//      case 8131:
+//        ret = 8140;
+//        break;
+//      case 8144:
+//        ret = 8152;
+//        break;
+//      case 8145:
+//        ret = 8153;
+//        break;
+//      case 8160:
+//        ret = 8168;
+//        break;
+//      case 8161:
+//        ret = 8169;
+//        break;
+//      case 8165:
+//        ret = 8172;
+//        break;
+//      case 8179:
+//        ret = 8188;
+//        break;
+//      case 8560:
+//        ret = 8544;
+//        break;
+//      case 8561:
+//        ret = 8545;
+//        break;
+//      case 8562:
+//        ret = 8546;
+//        break;
+//      case 8563:
+//        ret = 8547;
+//        break;
+//      case 8564:
+//        ret = 8548;
+//        break;
+//      case 8565:
+//        ret = 8549;
+//        break;
+//      case 8566:
+//        ret = 8550;
+//        break;
+//      case 8567:
+//        ret = 8551;
+//        break;
+//      case 8568:
+//        ret = 8552;
+//        break;
+//      case 8569:
+//        ret = 8553;
+//        break;
+//      case 8570:
+//        ret = 8554;
+//        break;
+//      case 8571:
+//        ret = 8555;
+//        break;
+//      case 8572:
+//        ret = 8556;
+//        break;
+//      case 8573:
+//        ret = 8557;
+//        break;
+//      case 8574:
+//        ret = 8558;
+//        break;
+//      case 8575:
+//        ret = 8559;
+//        break;
+//      case 9424:
+//        ret = 9398;
+//        break;
+//      case 9425:
+//        ret = 9399;
+//        break;
+//      case 9426:
+//        ret = 9400;
+//        break;
+//      case 9427:
+//        ret = 9401;
+//        break;
+//      case 9428:
+//        ret = 9402;
+//        break;
+//      case 9429:
+//        ret = 9403;
+//        break;
+//      case 9430:
+//        ret = 9404;
+//        break;
+//      case 9431:
+//        ret = 9405;
+//        break;
+//      case 9432:
+//        ret = 9406;
+//        break;
+//      case 9433:
+//        ret = 9407;
+//        break;
+//      case 9434:
+//        ret = 9408;
+//        break;
+//      case 9435:
+//        ret = 9409;
+//        break;
+//      case 9436:
+//        ret = 9410;
+//        break;
+//      case 9437:
+//        ret = 9411;
+//        break;
+//      case 9438:
+//        ret = 9412;
+//        break;
+//      case 9439:
+//        ret = 9413;
+//        break;
+//      case 9440:
+//        ret = 9414;
+//        break;
+//      case 9441:
+//        ret = 9415;
+//        break;
+//      case 9442:
+//        ret = 9416;
+//        break;
+//      case 9443:
+//        ret = 9417;
+//        break;
+//      case 9444:
+//        ret = 9418;
+//        break;
+//      case 9445:
+//        ret = 9419;
+//        break;
+//      case 9446:
+//        ret = 9420;
+//        break;
+//      case 9447:
+//        ret = 9421;
+//        break;
+//      case 9448:
+//        ret = 9422;
+//        break;
+//      case 9449:
+//        ret = 9423;
+//        break;
+//      case 65345:
+//        ret = 65313;
+//        break;
+//      case 65346:
+//        ret = 65314;
+//        break;
+//      case 65347:
+//        ret = 65315;
+//        break;
+//      case 65348:
+//        ret = 65316;
+//        break;
+//      case 65349:
+//        ret = 65317;
+//        break;
+//      case 65350:
+//        ret = 65318;
+//        break;
+//      case 65351:
+//        ret = 65319;
+//        break;
+//      case 65352:
+//        ret = 65320;
+//        break;
+//      case 65353:
+//        ret = 65321;
+//        break;
+//      case 65354:
+//        ret = 65322;
+//        break;
+//      case 65355:
+//        ret = 65323;
+//        break;
+//      case 65356:
+//        ret = 65324;
+//        break;
+//      case 65357:
+//        ret = 65325;
+//        break;
+//      case 65358:
+//        ret = 65326;
+//        break;
+//      case 65359:
+//        ret = 65327;
+//        break;
+//      case 65360:
+//        ret = 65328;
+//        break;
+//      case 65361:
+//        ret = 65329;
+//        break;
+//      case 65362:
+//        ret = 65330;
+//        break;
+//      case 65363:
+//        ret = 65331;
+//        break;
+//      case 65364:
+//        ret = 65332;
+//        break;
+//      case 65365:
+//        ret = 65333;
+//        break;
+//      case 65366:
+//        ret = 65334;
+//        break;
+//      case 65367:
+//        ret = 65335;
+//        break;
+//      case 65368:
+//        ret = 65336;
+//        break;
+//      case 65369:
+//        ret = 65337;
+//        break;
+//      case 65370:
+//        ret = 65338;
+//        break;
+//      }
+//      return (char) ret;
+//    }
     return Character.toUpperCase(c);
   }
 
   /** Convert a character to lower case. */
-  public static char toLowerCase(char c)
+  public static char toLowerCaseC(char c)
   {
-    if (java_1_0)
-    {
-      int ret = (int) c;
-      switch (c)
-      {
-      case 65:
-        ret = 97;
-        break;
-      case 66:
-        ret = 98;
-        break;
-      case 67:
-        ret = 99;
-        break;
-      case 68:
-        ret = 100;
-        break;
-      case 69:
-        ret = 101;
-        break;
-      case 70:
-        ret = 102;
-        break;
-      case 71:
-        ret = 103;
-        break;
-      case 72:
-        ret = 104;
-        break;
-      case 73:
-        ret = 105;
-        break;
-      case 74:
-        ret = 106;
-        break;
-      case 75:
-        ret = 107;
-        break;
-      case 76:
-        ret = 108;
-        break;
-      case 77:
-        ret = 109;
-        break;
-      case 78:
-        ret = 110;
-        break;
-      case 79:
-        ret = 111;
-        break;
-      case 80:
-        ret = 112;
-        break;
-      case 81:
-        ret = 113;
-        break;
-      case 82:
-        ret = 114;
-        break;
-      case 83:
-        ret = 115;
-        break;
-      case 84:
-        ret = 116;
-        break;
-      case 85:
-        ret = 117;
-        break;
-      case 86:
-        ret = 118;
-        break;
-      case 87:
-        ret = 119;
-        break;
-      case 88:
-        ret = 120;
-        break;
-      case 89:
-        ret = 121;
-        break;
-      case 90:
-        ret = 122;
-        break;
-      case 192:
-        ret = 224;
-        break;
-      case 193:
-        ret = 225;
-        break;
-      case 194:
-        ret = 226;
-        break;
-      case 195:
-        ret = 227;
-        break;
-      case 196:
-        ret = 228;
-        break;
-      case 197:
-        ret = 229;
-        break;
-      case 198:
-        ret = 230;
-        break;
-      case 199:
-        ret = 231;
-        break;
-      case 200:
-        ret = 232;
-        break;
-      case 201:
-        ret = 233;
-        break;
-      case 202:
-        ret = 234;
-        break;
-      case 203:
-        ret = 235;
-        break;
-      case 204:
-        ret = 236;
-        break;
-      case 205:
-        ret = 237;
-        break;
-      case 206:
-        ret = 238;
-        break;
-      case 207:
-        ret = 239;
-        break;
-      case 208:
-        ret = 240;
-        break;
-      case 209:
-        ret = 241;
-        break;
-      case 210:
-        ret = 242;
-        break;
-      case 211:
-        ret = 243;
-        break;
-      case 212:
-        ret = 244;
-        break;
-      case 213:
-        ret = 245;
-        break;
-      case 214:
-        ret = 246;
-        break;
-      case 216:
-        ret = 248;
-        break;
-      case 217:
-        ret = 249;
-        break;
-      case 218:
-        ret = 250;
-        break;
-      case 219:
-        ret = 251;
-        break;
-      case 220:
-        ret = 252;
-        break;
-      case 221:
-        ret = 253;
-        break;
-      case 222:
-        ret = 254;
-        break;
-      case 256:
-        ret = 257;
-        break;
-      case 258:
-        ret = 259;
-        break;
-      case 260:
-        ret = 261;
-        break;
-      case 262:
-        ret = 263;
-        break;
-      case 264:
-        ret = 265;
-        break;
-      case 266:
-        ret = 267;
-        break;
-      case 268:
-        ret = 269;
-        break;
-      case 270:
-        ret = 271;
-        break;
-      case 272:
-        ret = 273;
-        break;
-      case 274:
-        ret = 275;
-        break;
-      case 276:
-        ret = 277;
-        break;
-      case 278:
-        ret = 279;
-        break;
-      case 280:
-        ret = 281;
-        break;
-      case 282:
-        ret = 283;
-        break;
-      case 284:
-        ret = 285;
-        break;
-      case 286:
-        ret = 287;
-        break;
-      case 288:
-        ret = 289;
-        break;
-      case 290:
-        ret = 291;
-        break;
-      case 292:
-        ret = 293;
-        break;
-      case 294:
-        ret = 295;
-        break;
-      case 296:
-        ret = 297;
-        break;
-      case 298:
-        ret = 299;
-        break;
-      case 300:
-        ret = 301;
-        break;
-      case 302:
-        ret = 303;
-        break;
-      case 304:
-        ret = 105;
-        break;
-      case 306:
-        ret = 307;
-        break;
-      case 308:
-        ret = 309;
-        break;
-      case 310:
-        ret = 311;
-        break;
-      case 313:
-        ret = 314;
-        break;
-      case 315:
-        ret = 316;
-        break;
-      case 317:
-        ret = 318;
-        break;
-      case 319:
-        ret = 320;
-        break;
-      case 321:
-        ret = 322;
-        break;
-      case 323:
-        ret = 324;
-        break;
-      case 325:
-        ret = 326;
-        break;
-      case 327:
-        ret = 328;
-        break;
-      case 330:
-        ret = 331;
-        break;
-      case 332:
-        ret = 333;
-        break;
-      case 334:
-        ret = 335;
-        break;
-      case 336:
-        ret = 337;
-        break;
-      case 338:
-        ret = 339;
-        break;
-      case 340:
-        ret = 341;
-        break;
-      case 342:
-        ret = 343;
-        break;
-      case 344:
-        ret = 345;
-        break;
-      case 346:
-        ret = 347;
-        break;
-      case 348:
-        ret = 349;
-        break;
-      case 350:
-        ret = 351;
-        break;
-      case 352:
-        ret = 353;
-        break;
-      case 354:
-        ret = 355;
-        break;
-      case 356:
-        ret = 357;
-        break;
-      case 358:
-        ret = 359;
-        break;
-      case 360:
-        ret = 361;
-        break;
-      case 362:
-        ret = 363;
-        break;
-      case 364:
-        ret = 365;
-        break;
-      case 366:
-        ret = 367;
-        break;
-      case 368:
-        ret = 369;
-        break;
-      case 370:
-        ret = 371;
-        break;
-      case 372:
-        ret = 373;
-        break;
-      case 374:
-        ret = 375;
-        break;
-      case 376:
-        ret = 255;
-        break;
-      case 377:
-        ret = 378;
-        break;
-      case 379:
-        ret = 380;
-        break;
-      case 381:
-        ret = 382;
-        break;
-      case 385:
-        ret = 595;
-        break;
-      case 386:
-        ret = 387;
-        break;
-      case 388:
-        ret = 389;
-        break;
-      case 390:
-        ret = 596;
-        break;
-      case 391:
-        ret = 392;
-        break;
-      case 393:
-        ret = 598;
-        break;
-      case 394:
-        ret = 599;
-        break;
-      case 395:
-        ret = 396;
-        break;
-      case 398:
-        ret = 600;
-        break;
-      case 399:
-        ret = 601;
-        break;
-      case 400:
-        ret = 603;
-        break;
-      case 401:
-        ret = 402;
-        break;
-      case 403:
-        ret = 608;
-        break;
-      case 404:
-        ret = 611;
-        break;
-      case 406:
-        ret = 617;
-        break;
-      case 407:
-        ret = 616;
-        break;
-      case 408:
-        ret = 409;
-        break;
-      case 412:
-        ret = 623;
-        break;
-      case 413:
-        ret = 626;
-        break;
-      case 416:
-        ret = 417;
-        break;
-      case 418:
-        ret = 419;
-        break;
-      case 420:
-        ret = 421;
-        break;
-      case 423:
-        ret = 424;
-        break;
-      case 425:
-        ret = 643;
-        break;
-      case 428:
-        ret = 429;
-        break;
-      case 430:
-        ret = 648;
-        break;
-      case 431:
-        ret = 432;
-        break;
-      case 433:
-        ret = 650;
-        break;
-      case 434:
-        ret = 651;
-        break;
-      case 435:
-        ret = 436;
-        break;
-      case 437:
-        ret = 438;
-        break;
-      case 439:
-        ret = 658;
-        break;
-      case 440:
-        ret = 441;
-        break;
-      case 444:
-        ret = 445;
-        break;
-      case 452:
-        ret = 454;
-        break;
-      case 453:
-        ret = 454;
-        break;
-      case 455:
-        ret = 457;
-        break;
-      case 456:
-        ret = 457;
-        break;
-      case 458:
-        ret = 460;
-        break;
-      case 459:
-        ret = 460;
-        break;
-      case 461:
-        ret = 462;
-        break;
-      case 463:
-        ret = 464;
-        break;
-      case 465:
-        ret = 466;
-        break;
-      case 467:
-        ret = 468;
-        break;
-      case 469:
-        ret = 470;
-        break;
-      case 471:
-        ret = 472;
-        break;
-      case 473:
-        ret = 474;
-        break;
-      case 475:
-        ret = 476;
-        break;
-      case 478:
-        ret = 479;
-        break;
-      case 480:
-        ret = 481;
-        break;
-      case 482:
-        ret = 483;
-        break;
-      case 484:
-        ret = 485;
-        break;
-      case 486:
-        ret = 487;
-        break;
-      case 488:
-        ret = 489;
-        break;
-      case 490:
-        ret = 491;
-        break;
-      case 492:
-        ret = 493;
-        break;
-      case 494:
-        ret = 495;
-        break;
-      case 497:
-        ret = 499;
-        break;
-      case 498:
-        ret = 499;
-        break;
-      case 500:
-        ret = 501;
-        break;
-      case 506:
-        ret = 507;
-        break;
-      case 508:
-        ret = 509;
-        break;
-      case 510:
-        ret = 511;
-        break;
-      case 512:
-        ret = 513;
-        break;
-      case 514:
-        ret = 515;
-        break;
-      case 516:
-        ret = 517;
-        break;
-      case 518:
-        ret = 519;
-        break;
-      case 520:
-        ret = 521;
-        break;
-      case 522:
-        ret = 523;
-        break;
-      case 524:
-        ret = 525;
-        break;
-      case 526:
-        ret = 527;
-        break;
-      case 528:
-        ret = 529;
-        break;
-      case 530:
-        ret = 531;
-        break;
-      case 532:
-        ret = 533;
-        break;
-      case 534:
-        ret = 535;
-        break;
-      case 902:
-        ret = 940;
-        break;
-      case 904:
-        ret = 941;
-        break;
-      case 905:
-        ret = 942;
-        break;
-      case 906:
-        ret = 943;
-        break;
-      case 908:
-        ret = 972;
-        break;
-      case 910:
-        ret = 973;
-        break;
-      case 911:
-        ret = 974;
-        break;
-      case 913:
-        ret = 945;
-        break;
-      case 914:
-        ret = 946;
-        break;
-      case 915:
-        ret = 947;
-        break;
-      case 916:
-        ret = 948;
-        break;
-      case 917:
-        ret = 949;
-        break;
-      case 918:
-        ret = 950;
-        break;
-      case 919:
-        ret = 951;
-        break;
-      case 920:
-        ret = 952;
-        break;
-      case 921:
-        ret = 953;
-        break;
-      case 922:
-        ret = 954;
-        break;
-      case 923:
-        ret = 955;
-        break;
-      case 924:
-        ret = 956;
-        break;
-      case 925:
-        ret = 957;
-        break;
-      case 926:
-        ret = 958;
-        break;
-      case 927:
-        ret = 959;
-        break;
-      case 928:
-        ret = 960;
-        break;
-      case 929:
-        ret = 961;
-        break;
-      case 931:
-        ret = 963;
-        break;
-      case 932:
-        ret = 964;
-        break;
-      case 933:
-        ret = 965;
-        break;
-      case 934:
-        ret = 966;
-        break;
-      case 935:
-        ret = 967;
-        break;
-      case 936:
-        ret = 968;
-        break;
-      case 937:
-        ret = 969;
-        break;
-      case 938:
-        ret = 970;
-        break;
-      case 939:
-        ret = 971;
-        break;
-      case 994:
-        ret = 995;
-        break;
-      case 996:
-        ret = 997;
-        break;
-      case 998:
-        ret = 999;
-        break;
-      case 1000:
-        ret = 1001;
-        break;
-      case 1002:
-        ret = 1003;
-        break;
-      case 1004:
-        ret = 1005;
-        break;
-      case 1006:
-        ret = 1007;
-        break;
-      case 1025:
-        ret = 1105;
-        break;
-      case 1026:
-        ret = 1106;
-        break;
-      case 1027:
-        ret = 1107;
-        break;
-      case 1028:
-        ret = 1108;
-        break;
-      case 1029:
-        ret = 1109;
-        break;
-      case 1030:
-        ret = 1110;
-        break;
-      case 1031:
-        ret = 1111;
-        break;
-      case 1032:
-        ret = 1112;
-        break;
-      case 1033:
-        ret = 1113;
-        break;
-      case 1034:
-        ret = 1114;
-        break;
-      case 1035:
-        ret = 1115;
-        break;
-      case 1036:
-        ret = 1116;
-        break;
-      case 1038:
-        ret = 1118;
-        break;
-      case 1039:
-        ret = 1119;
-        break;
-      case 1040:
-        ret = 1072;
-        break;
-      case 1041:
-        ret = 1073;
-        break;
-      case 1042:
-        ret = 1074;
-        break;
-      case 1043:
-        ret = 1075;
-        break;
-      case 1044:
-        ret = 1076;
-        break;
-      case 1045:
-        ret = 1077;
-        break;
-      case 1046:
-        ret = 1078;
-        break;
-      case 1047:
-        ret = 1079;
-        break;
-      case 1048:
-        ret = 1080;
-        break;
-      case 1049:
-        ret = 1081;
-        break;
-      case 1050:
-        ret = 1082;
-        break;
-      case 1051:
-        ret = 1083;
-        break;
-      case 1052:
-        ret = 1084;
-        break;
-      case 1053:
-        ret = 1085;
-        break;
-      case 1054:
-        ret = 1086;
-        break;
-      case 1055:
-        ret = 1087;
-        break;
-      case 1056:
-        ret = 1088;
-        break;
-      case 1057:
-        ret = 1089;
-        break;
-      case 1058:
-        ret = 1090;
-        break;
-      case 1059:
-        ret = 1091;
-        break;
-      case 1060:
-        ret = 1092;
-        break;
-      case 1061:
-        ret = 1093;
-        break;
-      case 1062:
-        ret = 1094;
-        break;
-      case 1063:
-        ret = 1095;
-        break;
-      case 1064:
-        ret = 1096;
-        break;
-      case 1065:
-        ret = 1097;
-        break;
-      case 1066:
-        ret = 1098;
-        break;
-      case 1067:
-        ret = 1099;
-        break;
-      case 1068:
-        ret = 1100;
-        break;
-      case 1069:
-        ret = 1101;
-        break;
-      case 1070:
-        ret = 1102;
-        break;
-      case 1071:
-        ret = 1103;
-        break;
-      case 1120:
-        ret = 1121;
-        break;
-      case 1122:
-        ret = 1123;
-        break;
-      case 1124:
-        ret = 1125;
-        break;
-      case 1126:
-        ret = 1127;
-        break;
-      case 1128:
-        ret = 1129;
-        break;
-      case 1130:
-        ret = 1131;
-        break;
-      case 1132:
-        ret = 1133;
-        break;
-      case 1134:
-        ret = 1135;
-        break;
-      case 1136:
-        ret = 1137;
-        break;
-      case 1138:
-        ret = 1139;
-        break;
-      case 1140:
-        ret = 1141;
-        break;
-      case 1142:
-        ret = 1143;
-        break;
-      case 1144:
-        ret = 1145;
-        break;
-      case 1146:
-        ret = 1147;
-        break;
-      case 1148:
-        ret = 1149;
-        break;
-      case 1150:
-        ret = 1151;
-        break;
-      case 1152:
-        ret = 1153;
-        break;
-      case 1168:
-        ret = 1169;
-        break;
-      case 1170:
-        ret = 1171;
-        break;
-      case 1172:
-        ret = 1173;
-        break;
-      case 1174:
-        ret = 1175;
-        break;
-      case 1176:
-        ret = 1177;
-        break;
-      case 1178:
-        ret = 1179;
-        break;
-      case 1180:
-        ret = 1181;
-        break;
-      case 1182:
-        ret = 1183;
-        break;
-      case 1184:
-        ret = 1185;
-        break;
-      case 1186:
-        ret = 1187;
-        break;
-      case 1188:
-        ret = 1189;
-        break;
-      case 1190:
-        ret = 1191;
-        break;
-      case 1192:
-        ret = 1193;
-        break;
-      case 1194:
-        ret = 1195;
-        break;
-      case 1196:
-        ret = 1197;
-        break;
-      case 1198:
-        ret = 1199;
-        break;
-      case 1200:
-        ret = 1201;
-        break;
-      case 1202:
-        ret = 1203;
-        break;
-      case 1204:
-        ret = 1205;
-        break;
-      case 1206:
-        ret = 1207;
-        break;
-      case 1208:
-        ret = 1209;
-        break;
-      case 1210:
-        ret = 1211;
-        break;
-      case 1212:
-        ret = 1213;
-        break;
-      case 1214:
-        ret = 1215;
-        break;
-      case 1217:
-        ret = 1218;
-        break;
-      case 1219:
-        ret = 1220;
-        break;
-      case 1223:
-        ret = 1224;
-        break;
-      case 1227:
-        ret = 1228;
-        break;
-      case 1232:
-        ret = 1233;
-        break;
-      case 1234:
-        ret = 1235;
-        break;
-      case 1236:
-        ret = 1237;
-        break;
-      case 1238:
-        ret = 1239;
-        break;
-      case 1240:
-        ret = 1241;
-        break;
-      case 1242:
-        ret = 1243;
-        break;
-      case 1244:
-        ret = 1245;
-        break;
-      case 1246:
-        ret = 1247;
-        break;
-      case 1248:
-        ret = 1249;
-        break;
-      case 1250:
-        ret = 1251;
-        break;
-      case 1252:
-        ret = 1253;
-        break;
-      case 1254:
-        ret = 1255;
-        break;
-      case 1256:
-        ret = 1257;
-        break;
-      case 1258:
-        ret = 1259;
-        break;
-      case 1262:
-        ret = 1263;
-        break;
-      case 1264:
-        ret = 1265;
-        break;
-      case 1266:
-        ret = 1267;
-        break;
-      case 1268:
-        ret = 1269;
-        break;
-      case 1272:
-        ret = 1273;
-        break;
-      case 1329:
-        ret = 1377;
-        break;
-      case 1330:
-        ret = 1378;
-        break;
-      case 1331:
-        ret = 1379;
-        break;
-      case 1332:
-        ret = 1380;
-        break;
-      case 1333:
-        ret = 1381;
-        break;
-      case 1334:
-        ret = 1382;
-        break;
-      case 1335:
-        ret = 1383;
-        break;
-      case 1336:
-        ret = 1384;
-        break;
-      case 1337:
-        ret = 1385;
-        break;
-      case 1338:
-        ret = 1386;
-        break;
-      case 1339:
-        ret = 1387;
-        break;
-      case 1340:
-        ret = 1388;
-        break;
-      case 1341:
-        ret = 1389;
-        break;
-      case 1342:
-        ret = 1390;
-        break;
-      case 1343:
-        ret = 1391;
-        break;
-      case 1344:
-        ret = 1392;
-        break;
-      case 1345:
-        ret = 1393;
-        break;
-      case 1346:
-        ret = 1394;
-        break;
-      case 1347:
-        ret = 1395;
-        break;
-      case 1348:
-        ret = 1396;
-        break;
-      case 1349:
-        ret = 1397;
-        break;
-      case 1350:
-        ret = 1398;
-        break;
-      case 1351:
-        ret = 1399;
-        break;
-      case 1352:
-        ret = 1400;
-        break;
-      case 1353:
-        ret = 1401;
-        break;
-      case 1354:
-        ret = 1402;
-        break;
-      case 1355:
-        ret = 1403;
-        break;
-      case 1356:
-        ret = 1404;
-        break;
-      case 1357:
-        ret = 1405;
-        break;
-      case 1358:
-        ret = 1406;
-        break;
-      case 1359:
-        ret = 1407;
-        break;
-      case 1360:
-        ret = 1408;
-        break;
-      case 1361:
-        ret = 1409;
-        break;
-      case 1362:
-        ret = 1410;
-        break;
-      case 1363:
-        ret = 1411;
-        break;
-      case 1364:
-        ret = 1412;
-        break;
-      case 1365:
-        ret = 1413;
-        break;
-      case 1366:
-        ret = 1414;
-        break;
-      case 4256:
-        ret = 4304;
-        break;
-      case 4257:
-        ret = 4305;
-        break;
-      case 4258:
-        ret = 4306;
-        break;
-      case 4259:
-        ret = 4307;
-        break;
-      case 4260:
-        ret = 4308;
-        break;
-      case 4261:
-        ret = 4309;
-        break;
-      case 4262:
-        ret = 4310;
-        break;
-      case 4263:
-        ret = 4311;
-        break;
-      case 4264:
-        ret = 4312;
-        break;
-      case 4265:
-        ret = 4313;
-        break;
-      case 4266:
-        ret = 4314;
-        break;
-      case 4267:
-        ret = 4315;
-        break;
-      case 4268:
-        ret = 4316;
-        break;
-      case 4269:
-        ret = 4317;
-        break;
-      case 4270:
-        ret = 4318;
-        break;
-      case 4271:
-        ret = 4319;
-        break;
-      case 4272:
-        ret = 4320;
-        break;
-      case 4273:
-        ret = 4321;
-        break;
-      case 4274:
-        ret = 4322;
-        break;
-      case 4275:
-        ret = 4323;
-        break;
-      case 4276:
-        ret = 4324;
-        break;
-      case 4277:
-        ret = 4325;
-        break;
-      case 4278:
-        ret = 4326;
-        break;
-      case 4279:
-        ret = 4327;
-        break;
-      case 4280:
-        ret = 4328;
-        break;
-      case 4281:
-        ret = 4329;
-        break;
-      case 4282:
-        ret = 4330;
-        break;
-      case 4283:
-        ret = 4331;
-        break;
-      case 4284:
-        ret = 4332;
-        break;
-      case 4285:
-        ret = 4333;
-        break;
-      case 4286:
-        ret = 4334;
-        break;
-      case 4287:
-        ret = 4335;
-        break;
-      case 4288:
-        ret = 4336;
-        break;
-      case 4289:
-        ret = 4337;
-        break;
-      case 4290:
-        ret = 4338;
-        break;
-      case 4291:
-        ret = 4339;
-        break;
-      case 4292:
-        ret = 4340;
-        break;
-      case 4293:
-        ret = 4341;
-        break;
-      case 7680:
-        ret = 7681;
-        break;
-      case 7682:
-        ret = 7683;
-        break;
-      case 7684:
-        ret = 7685;
-        break;
-      case 7686:
-        ret = 7687;
-        break;
-      case 7688:
-        ret = 7689;
-        break;
-      case 7690:
-        ret = 7691;
-        break;
-      case 7692:
-        ret = 7693;
-        break;
-      case 7694:
-        ret = 7695;
-        break;
-      case 7696:
-        ret = 7697;
-        break;
-      case 7698:
-        ret = 7699;
-        break;
-      case 7700:
-        ret = 7701;
-        break;
-      case 7702:
-        ret = 7703;
-        break;
-      case 7704:
-        ret = 7705;
-        break;
-      case 7706:
-        ret = 7707;
-        break;
-      case 7708:
-        ret = 7709;
-        break;
-      case 7710:
-        ret = 7711;
-        break;
-      case 7712:
-        ret = 7713;
-        break;
-      case 7714:
-        ret = 7715;
-        break;
-      case 7716:
-        ret = 7717;
-        break;
-      case 7718:
-        ret = 7719;
-        break;
-      case 7720:
-        ret = 7721;
-        break;
-      case 7722:
-        ret = 7723;
-        break;
-      case 7724:
-        ret = 7725;
-        break;
-      case 7726:
-        ret = 7727;
-        break;
-      case 7728:
-        ret = 7729;
-        break;
-      case 7730:
-        ret = 7731;
-        break;
-      case 7732:
-        ret = 7733;
-        break;
-      case 7734:
-        ret = 7735;
-        break;
-      case 7736:
-        ret = 7737;
-        break;
-      case 7738:
-        ret = 7739;
-        break;
-      case 7740:
-        ret = 7741;
-        break;
-      case 7742:
-        ret = 7743;
-        break;
-      case 7744:
-        ret = 7745;
-        break;
-      case 7746:
-        ret = 7747;
-        break;
-      case 7748:
-        ret = 7749;
-        break;
-      case 7750:
-        ret = 7751;
-        break;
-      case 7752:
-        ret = 7753;
-        break;
-      case 7754:
-        ret = 7755;
-        break;
-      case 7756:
-        ret = 7757;
-        break;
-      case 7758:
-        ret = 7759;
-        break;
-      case 7760:
-        ret = 7761;
-        break;
-      case 7762:
-        ret = 7763;
-        break;
-      case 7764:
-        ret = 7765;
-        break;
-      case 7766:
-        ret = 7767;
-        break;
-      case 7768:
-        ret = 7769;
-        break;
-      case 7770:
-        ret = 7771;
-        break;
-      case 7772:
-        ret = 7773;
-        break;
-      case 7774:
-        ret = 7775;
-        break;
-      case 7776:
-        ret = 7777;
-        break;
-      case 7778:
-        ret = 7779;
-        break;
-      case 7780:
-        ret = 7781;
-        break;
-      case 7782:
-        ret = 7783;
-        break;
-      case 7784:
-        ret = 7785;
-        break;
-      case 7786:
-        ret = 7787;
-        break;
-      case 7788:
-        ret = 7789;
-        break;
-      case 7790:
-        ret = 7791;
-        break;
-      case 7792:
-        ret = 7793;
-        break;
-      case 7794:
-        ret = 7795;
-        break;
-      case 7796:
-        ret = 7797;
-        break;
-      case 7798:
-        ret = 7799;
-        break;
-      case 7800:
-        ret = 7801;
-        break;
-      case 7802:
-        ret = 7803;
-        break;
-      case 7804:
-        ret = 7805;
-        break;
-      case 7806:
-        ret = 7807;
-        break;
-      case 7808:
-        ret = 7809;
-        break;
-      case 7810:
-        ret = 7811;
-        break;
-      case 7812:
-        ret = 7813;
-        break;
-      case 7814:
-        ret = 7815;
-        break;
-      case 7816:
-        ret = 7817;
-        break;
-      case 7818:
-        ret = 7819;
-        break;
-      case 7820:
-        ret = 7821;
-        break;
-      case 7822:
-        ret = 7823;
-        break;
-      case 7824:
-        ret = 7825;
-        break;
-      case 7826:
-        ret = 7827;
-        break;
-      case 7828:
-        ret = 7829;
-        break;
-      case 7840:
-        ret = 7841;
-        break;
-      case 7842:
-        ret = 7843;
-        break;
-      case 7844:
-        ret = 7845;
-        break;
-      case 7846:
-        ret = 7847;
-        break;
-      case 7848:
-        ret = 7849;
-        break;
-      case 7850:
-        ret = 7851;
-        break;
-      case 7852:
-        ret = 7853;
-        break;
-      case 7854:
-        ret = 7855;
-        break;
-      case 7856:
-        ret = 7857;
-        break;
-      case 7858:
-        ret = 7859;
-        break;
-      case 7860:
-        ret = 7861;
-        break;
-      case 7862:
-        ret = 7863;
-        break;
-      case 7864:
-        ret = 7865;
-        break;
-      case 7866:
-        ret = 7867;
-        break;
-      case 7868:
-        ret = 7869;
-        break;
-      case 7870:
-        ret = 7871;
-        break;
-      case 7872:
-        ret = 7873;
-        break;
-      case 7874:
-        ret = 7875;
-        break;
-      case 7876:
-        ret = 7877;
-        break;
-      case 7878:
-        ret = 7879;
-        break;
-      case 7880:
-        ret = 7881;
-        break;
-      case 7882:
-        ret = 7883;
-        break;
-      case 7884:
-        ret = 7885;
-        break;
-      case 7886:
-        ret = 7887;
-        break;
-      case 7888:
-        ret = 7889;
-        break;
-      case 7890:
-        ret = 7891;
-        break;
-      case 7892:
-        ret = 7893;
-        break;
-      case 7894:
-        ret = 7895;
-        break;
-      case 7896:
-        ret = 7897;
-        break;
-      case 7898:
-        ret = 7899;
-        break;
-      case 7900:
-        ret = 7901;
-        break;
-      case 7902:
-        ret = 7903;
-        break;
-      case 7904:
-        ret = 7905;
-        break;
-      case 7906:
-        ret = 7907;
-        break;
-      case 7908:
-        ret = 7909;
-        break;
-      case 7910:
-        ret = 7911;
-        break;
-      case 7912:
-        ret = 7913;
-        break;
-      case 7914:
-        ret = 7915;
-        break;
-      case 7916:
-        ret = 7917;
-        break;
-      case 7918:
-        ret = 7919;
-        break;
-      case 7920:
-        ret = 7921;
-        break;
-      case 7922:
-        ret = 7923;
-        break;
-      case 7924:
-        ret = 7925;
-        break;
-      case 7926:
-        ret = 7927;
-        break;
-      case 7928:
-        ret = 7929;
-        break;
-      case 7944:
-        ret = 7936;
-        break;
-      case 7945:
-        ret = 7937;
-        break;
-      case 7946:
-        ret = 7938;
-        break;
-      case 7947:
-        ret = 7939;
-        break;
-      case 7948:
-        ret = 7940;
-        break;
-      case 7949:
-        ret = 7941;
-        break;
-      case 7950:
-        ret = 7942;
-        break;
-      case 7951:
-        ret = 7943;
-        break;
-      case 7960:
-        ret = 7952;
-        break;
-      case 7961:
-        ret = 7953;
-        break;
-      case 7962:
-        ret = 7954;
-        break;
-      case 7963:
-        ret = 7955;
-        break;
-      case 7964:
-        ret = 7956;
-        break;
-      case 7965:
-        ret = 7957;
-        break;
-      case 7976:
-        ret = 7968;
-        break;
-      case 7977:
-        ret = 7969;
-        break;
-      case 7978:
-        ret = 7970;
-        break;
-      case 7979:
-        ret = 7971;
-        break;
-      case 7980:
-        ret = 7972;
-        break;
-      case 7981:
-        ret = 7973;
-        break;
-      case 7982:
-        ret = 7974;
-        break;
-      case 7983:
-        ret = 7975;
-        break;
-      case 7992:
-        ret = 7984;
-        break;
-      case 7993:
-        ret = 7985;
-        break;
-      case 7994:
-        ret = 7986;
-        break;
-      case 7995:
-        ret = 7987;
-        break;
-      case 7996:
-        ret = 7988;
-        break;
-      case 7997:
-        ret = 7989;
-        break;
-      case 7998:
-        ret = 7990;
-        break;
-      case 7999:
-        ret = 7991;
-        break;
-      case 8008:
-        ret = 8000;
-        break;
-      case 8009:
-        ret = 8001;
-        break;
-      case 8010:
-        ret = 8002;
-        break;
-      case 8011:
-        ret = 8003;
-        break;
-      case 8012:
-        ret = 8004;
-        break;
-      case 8013:
-        ret = 8005;
-        break;
-      case 8025:
-        ret = 8017;
-        break;
-      case 8027:
-        ret = 8019;
-        break;
-      case 8029:
-        ret = 8021;
-        break;
-      case 8031:
-        ret = 8023;
-        break;
-      case 8040:
-        ret = 8032;
-        break;
-      case 8041:
-        ret = 8033;
-        break;
-      case 8042:
-        ret = 8034;
-        break;
-      case 8043:
-        ret = 8035;
-        break;
-      case 8044:
-        ret = 8036;
-        break;
-      case 8045:
-        ret = 8037;
-        break;
-      case 8046:
-        ret = 8038;
-        break;
-      case 8047:
-        ret = 8039;
-        break;
-      case 8072:
-        ret = 8064;
-        break;
-      case 8073:
-        ret = 8065;
-        break;
-      case 8074:
-        ret = 8066;
-        break;
-      case 8075:
-        ret = 8067;
-        break;
-      case 8076:
-        ret = 8068;
-        break;
-      case 8077:
-        ret = 8069;
-        break;
-      case 8078:
-        ret = 8070;
-        break;
-      case 8079:
-        ret = 8071;
-        break;
-      case 8088:
-        ret = 8080;
-        break;
-      case 8089:
-        ret = 8081;
-        break;
-      case 8090:
-        ret = 8082;
-        break;
-      case 8091:
-        ret = 8083;
-        break;
-      case 8092:
-        ret = 8084;
-        break;
-      case 8093:
-        ret = 8085;
-        break;
-      case 8094:
-        ret = 8086;
-        break;
-      case 8095:
-        ret = 8087;
-        break;
-      case 8104:
-        ret = 8096;
-        break;
-      case 8105:
-        ret = 8097;
-        break;
-      case 8106:
-        ret = 8098;
-        break;
-      case 8107:
-        ret = 8099;
-        break;
-      case 8108:
-        ret = 8100;
-        break;
-      case 8109:
-        ret = 8101;
-        break;
-      case 8110:
-        ret = 8102;
-        break;
-      case 8111:
-        ret = 8103;
-        break;
-      case 8120:
-        ret = 8112;
-        break;
-      case 8121:
-        ret = 8113;
-        break;
-      case 8122:
-        ret = 8048;
-        break;
-      case 8123:
-        ret = 8049;
-        break;
-      case 8124:
-        ret = 8115;
-        break;
-      case 8136:
-        ret = 8050;
-        break;
-      case 8137:
-        ret = 8051;
-        break;
-      case 8138:
-        ret = 8052;
-        break;
-      case 8139:
-        ret = 8053;
-        break;
-      case 8140:
-        ret = 8131;
-        break;
-      case 8152:
-        ret = 8144;
-        break;
-      case 8153:
-        ret = 8145;
-        break;
-      case 8154:
-        ret = 8054;
-        break;
-      case 8155:
-        ret = 8055;
-        break;
-      case 8168:
-        ret = 8160;
-        break;
-      case 8169:
-        ret = 8161;
-        break;
-      case 8170:
-        ret = 8058;
-        break;
-      case 8171:
-        ret = 8059;
-        break;
-      case 8172:
-        ret = 8165;
-        break;
-      case 8184:
-        ret = 8056;
-        break;
-      case 8185:
-        ret = 8057;
-        break;
-      case 8186:
-        ret = 8060;
-        break;
-      case 8187:
-        ret = 8061;
-        break;
-      case 8188:
-        ret = 8179;
-        break;
-      case 8544:
-        ret = 8560;
-        break;
-      case 8545:
-        ret = 8561;
-        break;
-      case 8546:
-        ret = 8562;
-        break;
-      case 8547:
-        ret = 8563;
-        break;
-      case 8548:
-        ret = 8564;
-        break;
-      case 8549:
-        ret = 8565;
-        break;
-      case 8550:
-        ret = 8566;
-        break;
-      case 8551:
-        ret = 8567;
-        break;
-      case 8552:
-        ret = 8568;
-        break;
-      case 8553:
-        ret = 8569;
-        break;
-      case 8554:
-        ret = 8570;
-        break;
-      case 8555:
-        ret = 8571;
-        break;
-      case 8556:
-        ret = 8572;
-        break;
-      case 8557:
-        ret = 8573;
-        break;
-      case 8558:
-        ret = 8574;
-        break;
-      case 8559:
-        ret = 8575;
-        break;
-      case 9398:
-        ret = 9424;
-        break;
-      case 9399:
-        ret = 9425;
-        break;
-      case 9400:
-        ret = 9426;
-        break;
-      case 9401:
-        ret = 9427;
-        break;
-      case 9402:
-        ret = 9428;
-        break;
-      case 9403:
-        ret = 9429;
-        break;
-      case 9404:
-        ret = 9430;
-        break;
-      case 9405:
-        ret = 9431;
-        break;
-      case 9406:
-        ret = 9432;
-        break;
-      case 9407:
-        ret = 9433;
-        break;
-      case 9408:
-        ret = 9434;
-        break;
-      case 9409:
-        ret = 9435;
-        break;
-      case 9410:
-        ret = 9436;
-        break;
-      case 9411:
-        ret = 9437;
-        break;
-      case 9412:
-        ret = 9438;
-        break;
-      case 9413:
-        ret = 9439;
-        break;
-      case 9414:
-        ret = 9440;
-        break;
-      case 9415:
-        ret = 9441;
-        break;
-      case 9416:
-        ret = 9442;
-        break;
-      case 9417:
-        ret = 9443;
-        break;
-      case 9418:
-        ret = 9444;
-        break;
-      case 9419:
-        ret = 9445;
-        break;
-      case 9420:
-        ret = 9446;
-        break;
-      case 9421:
-        ret = 9447;
-        break;
-      case 9422:
-        ret = 9448;
-        break;
-      case 9423:
-        ret = 9449;
-        break;
-      case 65313:
-        ret = 65345;
-        break;
-      case 65314:
-        ret = 65346;
-        break;
-      case 65315:
-        ret = 65347;
-        break;
-      case 65316:
-        ret = 65348;
-        break;
-      case 65317:
-        ret = 65349;
-        break;
-      case 65318:
-        ret = 65350;
-        break;
-      case 65319:
-        ret = 65351;
-        break;
-      case 65320:
-        ret = 65352;
-        break;
-      case 65321:
-        ret = 65353;
-        break;
-      case 65322:
-        ret = 65354;
-        break;
-      case 65323:
-        ret = 65355;
-        break;
-      case 65324:
-        ret = 65356;
-        break;
-      case 65325:
-        ret = 65357;
-        break;
-      case 65326:
-        ret = 65358;
-        break;
-      case 65327:
-        ret = 65359;
-        break;
-      case 65328:
-        ret = 65360;
-        break;
-      case 65329:
-        ret = 65361;
-        break;
-      case 65330:
-        ret = 65362;
-        break;
-      case 65331:
-        ret = 65363;
-        break;
-      case 65332:
-        ret = 65364;
-        break;
-      case 65333:
-        ret = 65365;
-        break;
-      case 65334:
-        ret = 65366;
-        break;
-      case 65335:
-        ret = 65367;
-        break;
-      case 65336:
-        ret = 65368;
-        break;
-      case 65337:
-        ret = 65369;
-        break;
-      case 65338:
-        ret = 65370;
-        break;
-      }
-      return (char) ret;
-    }
+//    if (java_1_0)
+//    {
+//      int ret = (int) c;
+//      switch (c)
+//      {
+//      case 65:
+//        ret = 97;
+//        break;
+//      case 66:
+//        ret = 98;
+//        break;
+//      case 67:
+//        ret = 99;
+//        break;
+//      case 68:
+//        ret = 100;
+//        break;
+//      case 69:
+//        ret = 101;
+//        break;
+//      case 70:
+//        ret = 102;
+//        break;
+//      case 71:
+//        ret = 103;
+//        break;
+//      case 72:
+//        ret = 104;
+//        break;
+//      case 73:
+//        ret = 105;
+//        break;
+//      case 74:
+//        ret = 106;
+//        break;
+//      case 75:
+//        ret = 107;
+//        break;
+//      case 76:
+//        ret = 108;
+//        break;
+//      case 77:
+//        ret = 109;
+//        break;
+//      case 78:
+//        ret = 110;
+//        break;
+//      case 79:
+//        ret = 111;
+//        break;
+//      case 80:
+//        ret = 112;
+//        break;
+//      case 81:
+//        ret = 113;
+//        break;
+//      case 82:
+//        ret = 114;
+//        break;
+//      case 83:
+//        ret = 115;
+//        break;
+//      case 84:
+//        ret = 116;
+//        break;
+//      case 85:
+//        ret = 117;
+//        break;
+//      case 86:
+//        ret = 118;
+//        break;
+//      case 87:
+//        ret = 119;
+//        break;
+//      case 88:
+//        ret = 120;
+//        break;
+//      case 89:
+//        ret = 121;
+//        break;
+//      case 90:
+//        ret = 122;
+//        break;
+//      case 192:
+//        ret = 224;
+//        break;
+//      case 193:
+//        ret = 225;
+//        break;
+//      case 194:
+//        ret = 226;
+//        break;
+//      case 195:
+//        ret = 227;
+//        break;
+//      case 196:
+//        ret = 228;
+//        break;
+//      case 197:
+//        ret = 229;
+//        break;
+//      case 198:
+//        ret = 230;
+//        break;
+//      case 199:
+//        ret = 231;
+//        break;
+//      case 200:
+//        ret = 232;
+//        break;
+//      case 201:
+//        ret = 233;
+//        break;
+//      case 202:
+//        ret = 234;
+//        break;
+//      case 203:
+//        ret = 235;
+//        break;
+//      case 204:
+//        ret = 236;
+//        break;
+//      case 205:
+//        ret = 237;
+//        break;
+//      case 206:
+//        ret = 238;
+//        break;
+//      case 207:
+//        ret = 239;
+//        break;
+//      case 208:
+//        ret = 240;
+//        break;
+//      case 209:
+//        ret = 241;
+//        break;
+//      case 210:
+//        ret = 242;
+//        break;
+//      case 211:
+//        ret = 243;
+//        break;
+//      case 212:
+//        ret = 244;
+//        break;
+//      case 213:
+//        ret = 245;
+//        break;
+//      case 214:
+//        ret = 246;
+//        break;
+//      case 216:
+//        ret = 248;
+//        break;
+//      case 217:
+//        ret = 249;
+//        break;
+//      case 218:
+//        ret = 250;
+//        break;
+//      case 219:
+//        ret = 251;
+//        break;
+//      case 220:
+//        ret = 252;
+//        break;
+//      case 221:
+//        ret = 253;
+//        break;
+//      case 222:
+//        ret = 254;
+//        break;
+//      case 256:
+//        ret = 257;
+//        break;
+//      case 258:
+//        ret = 259;
+//        break;
+//      case 260:
+//        ret = 261;
+//        break;
+//      case 262:
+//        ret = 263;
+//        break;
+//      case 264:
+//        ret = 265;
+//        break;
+//      case 266:
+//        ret = 267;
+//        break;
+//      case 268:
+//        ret = 269;
+//        break;
+//      case 270:
+//        ret = 271;
+//        break;
+//      case 272:
+//        ret = 273;
+//        break;
+//      case 274:
+//        ret = 275;
+//        break;
+//      case 276:
+//        ret = 277;
+//        break;
+//      case 278:
+//        ret = 279;
+//        break;
+//      case 280:
+//        ret = 281;
+//        break;
+//      case 282:
+//        ret = 283;
+//        break;
+//      case 284:
+//        ret = 285;
+//        break;
+//      case 286:
+//        ret = 287;
+//        break;
+//      case 288:
+//        ret = 289;
+//        break;
+//      case 290:
+//        ret = 291;
+//        break;
+//      case 292:
+//        ret = 293;
+//        break;
+//      case 294:
+//        ret = 295;
+//        break;
+//      case 296:
+//        ret = 297;
+//        break;
+//      case 298:
+//        ret = 299;
+//        break;
+//      case 300:
+//        ret = 301;
+//        break;
+//      case 302:
+//        ret = 303;
+//        break;
+//      case 304:
+//        ret = 105;
+//        break;
+//      case 306:
+//        ret = 307;
+//        break;
+//      case 308:
+//        ret = 309;
+//        break;
+//      case 310:
+//        ret = 311;
+//        break;
+//      case 313:
+//        ret = 314;
+//        break;
+//      case 315:
+//        ret = 316;
+//        break;
+//      case 317:
+//        ret = 318;
+//        break;
+//      case 319:
+//        ret = 320;
+//        break;
+//      case 321:
+//        ret = 322;
+//        break;
+//      case 323:
+//        ret = 324;
+//        break;
+//      case 325:
+//        ret = 326;
+//        break;
+//      case 327:
+//        ret = 328;
+//        break;
+//      case 330:
+//        ret = 331;
+//        break;
+//      case 332:
+//        ret = 333;
+//        break;
+//      case 334:
+//        ret = 335;
+//        break;
+//      case 336:
+//        ret = 337;
+//        break;
+//      case 338:
+//        ret = 339;
+//        break;
+//      case 340:
+//        ret = 341;
+//        break;
+//      case 342:
+//        ret = 343;
+//        break;
+//      case 344:
+//        ret = 345;
+//        break;
+//      case 346:
+//        ret = 347;
+//        break;
+//      case 348:
+//        ret = 349;
+//        break;
+//      case 350:
+//        ret = 351;
+//        break;
+//      case 352:
+//        ret = 353;
+//        break;
+//      case 354:
+//        ret = 355;
+//        break;
+//      case 356:
+//        ret = 357;
+//        break;
+//      case 358:
+//        ret = 359;
+//        break;
+//      case 360:
+//        ret = 361;
+//        break;
+//      case 362:
+//        ret = 363;
+//        break;
+//      case 364:
+//        ret = 365;
+//        break;
+//      case 366:
+//        ret = 367;
+//        break;
+//      case 368:
+//        ret = 369;
+//        break;
+//      case 370:
+//        ret = 371;
+//        break;
+//      case 372:
+//        ret = 373;
+//        break;
+//      case 374:
+//        ret = 375;
+//        break;
+//      case 376:
+//        ret = 255;
+//        break;
+//      case 377:
+//        ret = 378;
+//        break;
+//      case 379:
+//        ret = 380;
+//        break;
+//      case 381:
+//        ret = 382;
+//        break;
+//      case 385:
+//        ret = 595;
+//        break;
+//      case 386:
+//        ret = 387;
+//        break;
+//      case 388:
+//        ret = 389;
+//        break;
+//      case 390:
+//        ret = 596;
+//        break;
+//      case 391:
+//        ret = 392;
+//        break;
+//      case 393:
+//        ret = 598;
+//        break;
+//      case 394:
+//        ret = 599;
+//        break;
+//      case 395:
+//        ret = 396;
+//        break;
+//      case 398:
+//        ret = 600;
+//        break;
+//      case 399:
+//        ret = 601;
+//        break;
+//      case 400:
+//        ret = 603;
+//        break;
+//      case 401:
+//        ret = 402;
+//        break;
+//      case 403:
+//        ret = 608;
+//        break;
+//      case 404:
+//        ret = 611;
+//        break;
+//      case 406:
+//        ret = 617;
+//        break;
+//      case 407:
+//        ret = 616;
+//        break;
+//      case 408:
+//        ret = 409;
+//        break;
+//      case 412:
+//        ret = 623;
+//        break;
+//      case 413:
+//        ret = 626;
+//        break;
+//      case 416:
+//        ret = 417;
+//        break;
+//      case 418:
+//        ret = 419;
+//        break;
+//      case 420:
+//        ret = 421;
+//        break;
+//      case 423:
+//        ret = 424;
+//        break;
+//      case 425:
+//        ret = 643;
+//        break;
+//      case 428:
+//        ret = 429;
+//        break;
+//      case 430:
+//        ret = 648;
+//        break;
+//      case 431:
+//        ret = 432;
+//        break;
+//      case 433:
+//        ret = 650;
+//        break;
+//      case 434:
+//        ret = 651;
+//        break;
+//      case 435:
+//        ret = 436;
+//        break;
+//      case 437:
+//        ret = 438;
+//        break;
+//      case 439:
+//        ret = 658;
+//        break;
+//      case 440:
+//        ret = 441;
+//        break;
+//      case 444:
+//        ret = 445;
+//        break;
+//      case 452:
+//        ret = 454;
+//        break;
+//      case 453:
+//        ret = 454;
+//        break;
+//      case 455:
+//        ret = 457;
+//        break;
+//      case 456:
+//        ret = 457;
+//        break;
+//      case 458:
+//        ret = 460;
+//        break;
+//      case 459:
+//        ret = 460;
+//        break;
+//      case 461:
+//        ret = 462;
+//        break;
+//      case 463:
+//        ret = 464;
+//        break;
+//      case 465:
+//        ret = 466;
+//        break;
+//      case 467:
+//        ret = 468;
+//        break;
+//      case 469:
+//        ret = 470;
+//        break;
+//      case 471:
+//        ret = 472;
+//        break;
+//      case 473:
+//        ret = 474;
+//        break;
+//      case 475:
+//        ret = 476;
+//        break;
+//      case 478:
+//        ret = 479;
+//        break;
+//      case 480:
+//        ret = 481;
+//        break;
+//      case 482:
+//        ret = 483;
+//        break;
+//      case 484:
+//        ret = 485;
+//        break;
+//      case 486:
+//        ret = 487;
+//        break;
+//      case 488:
+//        ret = 489;
+//        break;
+//      case 490:
+//        ret = 491;
+//        break;
+//      case 492:
+//        ret = 493;
+//        break;
+//      case 494:
+//        ret = 495;
+//        break;
+//      case 497:
+//        ret = 499;
+//        break;
+//      case 498:
+//        ret = 499;
+//        break;
+//      case 500:
+//        ret = 501;
+//        break;
+//      case 506:
+//        ret = 507;
+//        break;
+//      case 508:
+//        ret = 509;
+//        break;
+//      case 510:
+//        ret = 511;
+//        break;
+//      case 512:
+//        ret = 513;
+//        break;
+//      case 514:
+//        ret = 515;
+//        break;
+//      case 516:
+//        ret = 517;
+//        break;
+//      case 518:
+//        ret = 519;
+//        break;
+//      case 520:
+//        ret = 521;
+//        break;
+//      case 522:
+//        ret = 523;
+//        break;
+//      case 524:
+//        ret = 525;
+//        break;
+//      case 526:
+//        ret = 527;
+//        break;
+//      case 528:
+//        ret = 529;
+//        break;
+//      case 530:
+//        ret = 531;
+//        break;
+//      case 532:
+//        ret = 533;
+//        break;
+//      case 534:
+//        ret = 535;
+//        break;
+//      case 902:
+//        ret = 940;
+//        break;
+//      case 904:
+//        ret = 941;
+//        break;
+//      case 905:
+//        ret = 942;
+//        break;
+//      case 906:
+//        ret = 943;
+//        break;
+//      case 908:
+//        ret = 972;
+//        break;
+//      case 910:
+//        ret = 973;
+//        break;
+//      case 911:
+//        ret = 974;
+//        break;
+//      case 913:
+//        ret = 945;
+//        break;
+//      case 914:
+//        ret = 946;
+//        break;
+//      case 915:
+//        ret = 947;
+//        break;
+//      case 916:
+//        ret = 948;
+//        break;
+//      case 917:
+//        ret = 949;
+//        break;
+//      case 918:
+//        ret = 950;
+//        break;
+//      case 919:
+//        ret = 951;
+//        break;
+//      case 920:
+//        ret = 952;
+//        break;
+//      case 921:
+//        ret = 953;
+//        break;
+//      case 922:
+//        ret = 954;
+//        break;
+//      case 923:
+//        ret = 955;
+//        break;
+//      case 924:
+//        ret = 956;
+//        break;
+//      case 925:
+//        ret = 957;
+//        break;
+//      case 926:
+//        ret = 958;
+//        break;
+//      case 927:
+//        ret = 959;
+//        break;
+//      case 928:
+//        ret = 960;
+//        break;
+//      case 929:
+//        ret = 961;
+//        break;
+//      case 931:
+//        ret = 963;
+//        break;
+//      case 932:
+//        ret = 964;
+//        break;
+//      case 933:
+//        ret = 965;
+//        break;
+//      case 934:
+//        ret = 966;
+//        break;
+//      case 935:
+//        ret = 967;
+//        break;
+//      case 936:
+//        ret = 968;
+//        break;
+//      case 937:
+//        ret = 969;
+//        break;
+//      case 938:
+//        ret = 970;
+//        break;
+//      case 939:
+//        ret = 971;
+//        break;
+//      case 994:
+//        ret = 995;
+//        break;
+//      case 996:
+//        ret = 997;
+//        break;
+//      case 998:
+//        ret = 999;
+//        break;
+//      case 1000:
+//        ret = 1001;
+//        break;
+//      case 1002:
+//        ret = 1003;
+//        break;
+//      case 1004:
+//        ret = 1005;
+//        break;
+//      case 1006:
+//        ret = 1007;
+//        break;
+//      case 1025:
+//        ret = 1105;
+//        break;
+//      case 1026:
+//        ret = 1106;
+//        break;
+//      case 1027:
+//        ret = 1107;
+//        break;
+//      case 1028:
+//        ret = 1108;
+//        break;
+//      case 1029:
+//        ret = 1109;
+//        break;
+//      case 1030:
+//        ret = 1110;
+//        break;
+//      case 1031:
+//        ret = 1111;
+//        break;
+//      case 1032:
+//        ret = 1112;
+//        break;
+//      case 1033:
+//        ret = 1113;
+//        break;
+//      case 1034:
+//        ret = 1114;
+//        break;
+//      case 1035:
+//        ret = 1115;
+//        break;
+//      case 1036:
+//        ret = 1116;
+//        break;
+//      case 1038:
+//        ret = 1118;
+//        break;
+//      case 1039:
+//        ret = 1119;
+//        break;
+//      case 1040:
+//        ret = 1072;
+//        break;
+//      case 1041:
+//        ret = 1073;
+//        break;
+//      case 1042:
+//        ret = 1074;
+//        break;
+//      case 1043:
+//        ret = 1075;
+//        break;
+//      case 1044:
+//        ret = 1076;
+//        break;
+//      case 1045:
+//        ret = 1077;
+//        break;
+//      case 1046:
+//        ret = 1078;
+//        break;
+//      case 1047:
+//        ret = 1079;
+//        break;
+//      case 1048:
+//        ret = 1080;
+//        break;
+//      case 1049:
+//        ret = 1081;
+//        break;
+//      case 1050:
+//        ret = 1082;
+//        break;
+//      case 1051:
+//        ret = 1083;
+//        break;
+//      case 1052:
+//        ret = 1084;
+//        break;
+//      case 1053:
+//        ret = 1085;
+//        break;
+//      case 1054:
+//        ret = 1086;
+//        break;
+//      case 1055:
+//        ret = 1087;
+//        break;
+//      case 1056:
+//        ret = 1088;
+//        break;
+//      case 1057:
+//        ret = 1089;
+//        break;
+//      case 1058:
+//        ret = 1090;
+//        break;
+//      case 1059:
+//        ret = 1091;
+//        break;
+//      case 1060:
+//        ret = 1092;
+//        break;
+//      case 1061:
+//        ret = 1093;
+//        break;
+//      case 1062:
+//        ret = 1094;
+//        break;
+//      case 1063:
+//        ret = 1095;
+//        break;
+//      case 1064:
+//        ret = 1096;
+//        break;
+//      case 1065:
+//        ret = 1097;
+//        break;
+//      case 1066:
+//        ret = 1098;
+//        break;
+//      case 1067:
+//        ret = 1099;
+//        break;
+//      case 1068:
+//        ret = 1100;
+//        break;
+//      case 1069:
+//        ret = 1101;
+//        break;
+//      case 1070:
+//        ret = 1102;
+//        break;
+//      case 1071:
+//        ret = 1103;
+//        break;
+//      case 1120:
+//        ret = 1121;
+//        break;
+//      case 1122:
+//        ret = 1123;
+//        break;
+//      case 1124:
+//        ret = 1125;
+//        break;
+//      case 1126:
+//        ret = 1127;
+//        break;
+//      case 1128:
+//        ret = 1129;
+//        break;
+//      case 1130:
+//        ret = 1131;
+//        break;
+//      case 1132:
+//        ret = 1133;
+//        break;
+//      case 1134:
+//        ret = 1135;
+//        break;
+//      case 1136:
+//        ret = 1137;
+//        break;
+//      case 1138:
+//        ret = 1139;
+//        break;
+//      case 1140:
+//        ret = 1141;
+//        break;
+//      case 1142:
+//        ret = 1143;
+//        break;
+//      case 1144:
+//        ret = 1145;
+//        break;
+//      case 1146:
+//        ret = 1147;
+//        break;
+//      case 1148:
+//        ret = 1149;
+//        break;
+//      case 1150:
+//        ret = 1151;
+//        break;
+//      case 1152:
+//        ret = 1153;
+//        break;
+//      case 1168:
+//        ret = 1169;
+//        break;
+//      case 1170:
+//        ret = 1171;
+//        break;
+//      case 1172:
+//        ret = 1173;
+//        break;
+//      case 1174:
+//        ret = 1175;
+//        break;
+//      case 1176:
+//        ret = 1177;
+//        break;
+//      case 1178:
+//        ret = 1179;
+//        break;
+//      case 1180:
+//        ret = 1181;
+//        break;
+//      case 1182:
+//        ret = 1183;
+//        break;
+//      case 1184:
+//        ret = 1185;
+//        break;
+//      case 1186:
+//        ret = 1187;
+//        break;
+//      case 1188:
+//        ret = 1189;
+//        break;
+//      case 1190:
+//        ret = 1191;
+//        break;
+//      case 1192:
+//        ret = 1193;
+//        break;
+//      case 1194:
+//        ret = 1195;
+//        break;
+//      case 1196:
+//        ret = 1197;
+//        break;
+//      case 1198:
+//        ret = 1199;
+//        break;
+//      case 1200:
+//        ret = 1201;
+//        break;
+//      case 1202:
+//        ret = 1203;
+//        break;
+//      case 1204:
+//        ret = 1205;
+//        break;
+//      case 1206:
+//        ret = 1207;
+//        break;
+//      case 1208:
+//        ret = 1209;
+//        break;
+//      case 1210:
+//        ret = 1211;
+//        break;
+//      case 1212:
+//        ret = 1213;
+//        break;
+//      case 1214:
+//        ret = 1215;
+//        break;
+//      case 1217:
+//        ret = 1218;
+//        break;
+//      case 1219:
+//        ret = 1220;
+//        break;
+//      case 1223:
+//        ret = 1224;
+//        break;
+//      case 1227:
+//        ret = 1228;
+//        break;
+//      case 1232:
+//        ret = 1233;
+//        break;
+//      case 1234:
+//        ret = 1235;
+//        break;
+//      case 1236:
+//        ret = 1237;
+//        break;
+//      case 1238:
+//        ret = 1239;
+//        break;
+//      case 1240:
+//        ret = 1241;
+//        break;
+//      case 1242:
+//        ret = 1243;
+//        break;
+//      case 1244:
+//        ret = 1245;
+//        break;
+//      case 1246:
+//        ret = 1247;
+//        break;
+//      case 1248:
+//        ret = 1249;
+//        break;
+//      case 1250:
+//        ret = 1251;
+//        break;
+//      case 1252:
+//        ret = 1253;
+//        break;
+//      case 1254:
+//        ret = 1255;
+//        break;
+//      case 1256:
+//        ret = 1257;
+//        break;
+//      case 1258:
+//        ret = 1259;
+//        break;
+//      case 1262:
+//        ret = 1263;
+//        break;
+//      case 1264:
+//        ret = 1265;
+//        break;
+//      case 1266:
+//        ret = 1267;
+//        break;
+//      case 1268:
+//        ret = 1269;
+//        break;
+//      case 1272:
+//        ret = 1273;
+//        break;
+//      case 1329:
+//        ret = 1377;
+//        break;
+//      case 1330:
+//        ret = 1378;
+//        break;
+//      case 1331:
+//        ret = 1379;
+//        break;
+//      case 1332:
+//        ret = 1380;
+//        break;
+//      case 1333:
+//        ret = 1381;
+//        break;
+//      case 1334:
+//        ret = 1382;
+//        break;
+//      case 1335:
+//        ret = 1383;
+//        break;
+//      case 1336:
+//        ret = 1384;
+//        break;
+//      case 1337:
+//        ret = 1385;
+//        break;
+//      case 1338:
+//        ret = 1386;
+//        break;
+//      case 1339:
+//        ret = 1387;
+//        break;
+//      case 1340:
+//        ret = 1388;
+//        break;
+//      case 1341:
+//        ret = 1389;
+//        break;
+//      case 1342:
+//        ret = 1390;
+//        break;
+//      case 1343:
+//        ret = 1391;
+//        break;
+//      case 1344:
+//        ret = 1392;
+//        break;
+//      case 1345:
+//        ret = 1393;
+//        break;
+//      case 1346:
+//        ret = 1394;
+//        break;
+//      case 1347:
+//        ret = 1395;
+//        break;
+//      case 1348:
+//        ret = 1396;
+//        break;
+//      case 1349:
+//        ret = 1397;
+//        break;
+//      case 1350:
+//        ret = 1398;
+//        break;
+//      case 1351:
+//        ret = 1399;
+//        break;
+//      case 1352:
+//        ret = 1400;
+//        break;
+//      case 1353:
+//        ret = 1401;
+//        break;
+//      case 1354:
+//        ret = 1402;
+//        break;
+//      case 1355:
+//        ret = 1403;
+//        break;
+//      case 1356:
+//        ret = 1404;
+//        break;
+//      case 1357:
+//        ret = 1405;
+//        break;
+//      case 1358:
+//        ret = 1406;
+//        break;
+//      case 1359:
+//        ret = 1407;
+//        break;
+//      case 1360:
+//        ret = 1408;
+//        break;
+//      case 1361:
+//        ret = 1409;
+//        break;
+//      case 1362:
+//        ret = 1410;
+//        break;
+//      case 1363:
+//        ret = 1411;
+//        break;
+//      case 1364:
+//        ret = 1412;
+//        break;
+//      case 1365:
+//        ret = 1413;
+//        break;
+//      case 1366:
+//        ret = 1414;
+//        break;
+//      case 4256:
+//        ret = 4304;
+//        break;
+//      case 4257:
+//        ret = 4305;
+//        break;
+//      case 4258:
+//        ret = 4306;
+//        break;
+//      case 4259:
+//        ret = 4307;
+//        break;
+//      case 4260:
+//        ret = 4308;
+//        break;
+//      case 4261:
+//        ret = 4309;
+//        break;
+//      case 4262:
+//        ret = 4310;
+//        break;
+//      case 4263:
+//        ret = 4311;
+//        break;
+//      case 4264:
+//        ret = 4312;
+//        break;
+//      case 4265:
+//        ret = 4313;
+//        break;
+//      case 4266:
+//        ret = 4314;
+//        break;
+//      case 4267:
+//        ret = 4315;
+//        break;
+//      case 4268:
+//        ret = 4316;
+//        break;
+//      case 4269:
+//        ret = 4317;
+//        break;
+//      case 4270:
+//        ret = 4318;
+//        break;
+//      case 4271:
+//        ret = 4319;
+//        break;
+//      case 4272:
+//        ret = 4320;
+//        break;
+//      case 4273:
+//        ret = 4321;
+//        break;
+//      case 4274:
+//        ret = 4322;
+//        break;
+//      case 4275:
+//        ret = 4323;
+//        break;
+//      case 4276:
+//        ret = 4324;
+//        break;
+//      case 4277:
+//        ret = 4325;
+//        break;
+//      case 4278:
+//        ret = 4326;
+//        break;
+//      case 4279:
+//        ret = 4327;
+//        break;
+//      case 4280:
+//        ret = 4328;
+//        break;
+//      case 4281:
+//        ret = 4329;
+//        break;
+//      case 4282:
+//        ret = 4330;
+//        break;
+//      case 4283:
+//        ret = 4331;
+//        break;
+//      case 4284:
+//        ret = 4332;
+//        break;
+//      case 4285:
+//        ret = 4333;
+//        break;
+//      case 4286:
+//        ret = 4334;
+//        break;
+//      case 4287:
+//        ret = 4335;
+//        break;
+//      case 4288:
+//        ret = 4336;
+//        break;
+//      case 4289:
+//        ret = 4337;
+//        break;
+//      case 4290:
+//        ret = 4338;
+//        break;
+//      case 4291:
+//        ret = 4339;
+//        break;
+//      case 4292:
+//        ret = 4340;
+//        break;
+//      case 4293:
+//        ret = 4341;
+//        break;
+//      case 7680:
+//        ret = 7681;
+//        break;
+//      case 7682:
+//        ret = 7683;
+//        break;
+//      case 7684:
+//        ret = 7685;
+//        break;
+//      case 7686:
+//        ret = 7687;
+//        break;
+//      case 7688:
+//        ret = 7689;
+//        break;
+//      case 7690:
+//        ret = 7691;
+//        break;
+//      case 7692:
+//        ret = 7693;
+//        break;
+//      case 7694:
+//        ret = 7695;
+//        break;
+//      case 7696:
+//        ret = 7697;
+//        break;
+//      case 7698:
+//        ret = 7699;
+//        break;
+//      case 7700:
+//        ret = 7701;
+//        break;
+//      case 7702:
+//        ret = 7703;
+//        break;
+//      case 7704:
+//        ret = 7705;
+//        break;
+//      case 7706:
+//        ret = 7707;
+//        break;
+//      case 7708:
+//        ret = 7709;
+//        break;
+//      case 7710:
+//        ret = 7711;
+//        break;
+//      case 7712:
+//        ret = 7713;
+//        break;
+//      case 7714:
+//        ret = 7715;
+//        break;
+//      case 7716:
+//        ret = 7717;
+//        break;
+//      case 7718:
+//        ret = 7719;
+//        break;
+//      case 7720:
+//        ret = 7721;
+//        break;
+//      case 7722:
+//        ret = 7723;
+//        break;
+//      case 7724:
+//        ret = 7725;
+//        break;
+//      case 7726:
+//        ret = 7727;
+//        break;
+//      case 7728:
+//        ret = 7729;
+//        break;
+//      case 7730:
+//        ret = 7731;
+//        break;
+//      case 7732:
+//        ret = 7733;
+//        break;
+//      case 7734:
+//        ret = 7735;
+//        break;
+//      case 7736:
+//        ret = 7737;
+//        break;
+//      case 7738:
+//        ret = 7739;
+//        break;
+//      case 7740:
+//        ret = 7741;
+//        break;
+//      case 7742:
+//        ret = 7743;
+//        break;
+//      case 7744:
+//        ret = 7745;
+//        break;
+//      case 7746:
+//        ret = 7747;
+//        break;
+//      case 7748:
+//        ret = 7749;
+//        break;
+//      case 7750:
+//        ret = 7751;
+//        break;
+//      case 7752:
+//        ret = 7753;
+//        break;
+//      case 7754:
+//        ret = 7755;
+//        break;
+//      case 7756:
+//        ret = 7757;
+//        break;
+//      case 7758:
+//        ret = 7759;
+//        break;
+//      case 7760:
+//        ret = 7761;
+//        break;
+//      case 7762:
+//        ret = 7763;
+//        break;
+//      case 7764:
+//        ret = 7765;
+//        break;
+//      case 7766:
+//        ret = 7767;
+//        break;
+//      case 7768:
+//        ret = 7769;
+//        break;
+//      case 7770:
+//        ret = 7771;
+//        break;
+//      case 7772:
+//        ret = 7773;
+//        break;
+//      case 7774:
+//        ret = 7775;
+//        break;
+//      case 7776:
+//        ret = 7777;
+//        break;
+//      case 7778:
+//        ret = 7779;
+//        break;
+//      case 7780:
+//        ret = 7781;
+//        break;
+//      case 7782:
+//        ret = 7783;
+//        break;
+//      case 7784:
+//        ret = 7785;
+//        break;
+//      case 7786:
+//        ret = 7787;
+//        break;
+//      case 7788:
+//        ret = 7789;
+//        break;
+//      case 7790:
+//        ret = 7791;
+//        break;
+//      case 7792:
+//        ret = 7793;
+//        break;
+//      case 7794:
+//        ret = 7795;
+//        break;
+//      case 7796:
+//        ret = 7797;
+//        break;
+//      case 7798:
+//        ret = 7799;
+//        break;
+//      case 7800:
+//        ret = 7801;
+//        break;
+//      case 7802:
+//        ret = 7803;
+//        break;
+//      case 7804:
+//        ret = 7805;
+//        break;
+//      case 7806:
+//        ret = 7807;
+//        break;
+//      case 7808:
+//        ret = 7809;
+//        break;
+//      case 7810:
+//        ret = 7811;
+//        break;
+//      case 7812:
+//        ret = 7813;
+//        break;
+//      case 7814:
+//        ret = 7815;
+//        break;
+//      case 7816:
+//        ret = 7817;
+//        break;
+//      case 7818:
+//        ret = 7819;
+//        break;
+//      case 7820:
+//        ret = 7821;
+//        break;
+//      case 7822:
+//        ret = 7823;
+//        break;
+//      case 7824:
+//        ret = 7825;
+//        break;
+//      case 7826:
+//        ret = 7827;
+//        break;
+//      case 7828:
+//        ret = 7829;
+//        break;
+//      case 7840:
+//        ret = 7841;
+//        break;
+//      case 7842:
+//        ret = 7843;
+//        break;
+//      case 7844:
+//        ret = 7845;
+//        break;
+//      case 7846:
+//        ret = 7847;
+//        break;
+//      case 7848:
+//        ret = 7849;
+//        break;
+//      case 7850:
+//        ret = 7851;
+//        break;
+//      case 7852:
+//        ret = 7853;
+//        break;
+//      case 7854:
+//        ret = 7855;
+//        break;
+//      case 7856:
+//        ret = 7857;
+//        break;
+//      case 7858:
+//        ret = 7859;
+//        break;
+//      case 7860:
+//        ret = 7861;
+//        break;
+//      case 7862:
+//        ret = 7863;
+//        break;
+//      case 7864:
+//        ret = 7865;
+//        break;
+//      case 7866:
+//        ret = 7867;
+//        break;
+//      case 7868:
+//        ret = 7869;
+//        break;
+//      case 7870:
+//        ret = 7871;
+//        break;
+//      case 7872:
+//        ret = 7873;
+//        break;
+//      case 7874:
+//        ret = 7875;
+//        break;
+//      case 7876:
+//        ret = 7877;
+//        break;
+//      case 7878:
+//        ret = 7879;
+//        break;
+//      case 7880:
+//        ret = 7881;
+//        break;
+//      case 7882:
+//        ret = 7883;
+//        break;
+//      case 7884:
+//        ret = 7885;
+//        break;
+//      case 7886:
+//        ret = 7887;
+//        break;
+//      case 7888:
+//        ret = 7889;
+//        break;
+//      case 7890:
+//        ret = 7891;
+//        break;
+//      case 7892:
+//        ret = 7893;
+//        break;
+//      case 7894:
+//        ret = 7895;
+//        break;
+//      case 7896:
+//        ret = 7897;
+//        break;
+//      case 7898:
+//        ret = 7899;
+//        break;
+//      case 7900:
+//        ret = 7901;
+//        break;
+//      case 7902:
+//        ret = 7903;
+//        break;
+//      case 7904:
+//        ret = 7905;
+//        break;
+//      case 7906:
+//        ret = 7907;
+//        break;
+//      case 7908:
+//        ret = 7909;
+//        break;
+//      case 7910:
+//        ret = 7911;
+//        break;
+//      case 7912:
+//        ret = 7913;
+//        break;
+//      case 7914:
+//        ret = 7915;
+//        break;
+//      case 7916:
+//        ret = 7917;
+//        break;
+//      case 7918:
+//        ret = 7919;
+//        break;
+//      case 7920:
+//        ret = 7921;
+//        break;
+//      case 7922:
+//        ret = 7923;
+//        break;
+//      case 7924:
+//        ret = 7925;
+//        break;
+//      case 7926:
+//        ret = 7927;
+//        break;
+//      case 7928:
+//        ret = 7929;
+//        break;
+//      case 7944:
+//        ret = 7936;
+//        break;
+//      case 7945:
+//        ret = 7937;
+//        break;
+//      case 7946:
+//        ret = 7938;
+//        break;
+//      case 7947:
+//        ret = 7939;
+//        break;
+//      case 7948:
+//        ret = 7940;
+//        break;
+//      case 7949:
+//        ret = 7941;
+//        break;
+//      case 7950:
+//        ret = 7942;
+//        break;
+//      case 7951:
+//        ret = 7943;
+//        break;
+//      case 7960:
+//        ret = 7952;
+//        break;
+//      case 7961:
+//        ret = 7953;
+//        break;
+//      case 7962:
+//        ret = 7954;
+//        break;
+//      case 7963:
+//        ret = 7955;
+//        break;
+//      case 7964:
+//        ret = 7956;
+//        break;
+//      case 7965:
+//        ret = 7957;
+//        break;
+//      case 7976:
+//        ret = 7968;
+//        break;
+//      case 7977:
+//        ret = 7969;
+//        break;
+//      case 7978:
+//        ret = 7970;
+//        break;
+//      case 7979:
+//        ret = 7971;
+//        break;
+//      case 7980:
+//        ret = 7972;
+//        break;
+//      case 7981:
+//        ret = 7973;
+//        break;
+//      case 7982:
+//        ret = 7974;
+//        break;
+//      case 7983:
+//        ret = 7975;
+//        break;
+//      case 7992:
+//        ret = 7984;
+//        break;
+//      case 7993:
+//        ret = 7985;
+//        break;
+//      case 7994:
+//        ret = 7986;
+//        break;
+//      case 7995:
+//        ret = 7987;
+//        break;
+//      case 7996:
+//        ret = 7988;
+//        break;
+//      case 7997:
+//        ret = 7989;
+//        break;
+//      case 7998:
+//        ret = 7990;
+//        break;
+//      case 7999:
+//        ret = 7991;
+//        break;
+//      case 8008:
+//        ret = 8000;
+//        break;
+//      case 8009:
+//        ret = 8001;
+//        break;
+//      case 8010:
+//        ret = 8002;
+//        break;
+//      case 8011:
+//        ret = 8003;
+//        break;
+//      case 8012:
+//        ret = 8004;
+//        break;
+//      case 8013:
+//        ret = 8005;
+//        break;
+//      case 8025:
+//        ret = 8017;
+//        break;
+//      case 8027:
+//        ret = 8019;
+//        break;
+//      case 8029:
+//        ret = 8021;
+//        break;
+//      case 8031:
+//        ret = 8023;
+//        break;
+//      case 8040:
+//        ret = 8032;
+//        break;
+//      case 8041:
+//        ret = 8033;
+//        break;
+//      case 8042:
+//        ret = 8034;
+//        break;
+//      case 8043:
+//        ret = 8035;
+//        break;
+//      case 8044:
+//        ret = 8036;
+//        break;
+//      case 8045:
+//        ret = 8037;
+//        break;
+//      case 8046:
+//        ret = 8038;
+//        break;
+//      case 8047:
+//        ret = 8039;
+//        break;
+//      case 8072:
+//        ret = 8064;
+//        break;
+//      case 8073:
+//        ret = 8065;
+//        break;
+//      case 8074:
+//        ret = 8066;
+//        break;
+//      case 8075:
+//        ret = 8067;
+//        break;
+//      case 8076:
+//        ret = 8068;
+//        break;
+//      case 8077:
+//        ret = 8069;
+//        break;
+//      case 8078:
+//        ret = 8070;
+//        break;
+//      case 8079:
+//        ret = 8071;
+//        break;
+//      case 8088:
+//        ret = 8080;
+//        break;
+//      case 8089:
+//        ret = 8081;
+//        break;
+//      case 8090:
+//        ret = 8082;
+//        break;
+//      case 8091:
+//        ret = 8083;
+//        break;
+//      case 8092:
+//        ret = 8084;
+//        break;
+//      case 8093:
+//        ret = 8085;
+//        break;
+//      case 8094:
+//        ret = 8086;
+//        break;
+//      case 8095:
+//        ret = 8087;
+//        break;
+//      case 8104:
+//        ret = 8096;
+//        break;
+//      case 8105:
+//        ret = 8097;
+//        break;
+//      case 8106:
+//        ret = 8098;
+//        break;
+//      case 8107:
+//        ret = 8099;
+//        break;
+//      case 8108:
+//        ret = 8100;
+//        break;
+//      case 8109:
+//        ret = 8101;
+//        break;
+//      case 8110:
+//        ret = 8102;
+//        break;
+//      case 8111:
+//        ret = 8103;
+//        break;
+//      case 8120:
+//        ret = 8112;
+//        break;
+//      case 8121:
+//        ret = 8113;
+//        break;
+//      case 8122:
+//        ret = 8048;
+//        break;
+//      case 8123:
+//        ret = 8049;
+//        break;
+//      case 8124:
+//        ret = 8115;
+//        break;
+//      case 8136:
+//        ret = 8050;
+//        break;
+//      case 8137:
+//        ret = 8051;
+//        break;
+//      case 8138:
+//        ret = 8052;
+//        break;
+//      case 8139:
+//        ret = 8053;
+//        break;
+//      case 8140:
+//        ret = 8131;
+//        break;
+//      case 8152:
+//        ret = 8144;
+//        break;
+//      case 8153:
+//        ret = 8145;
+//        break;
+//      case 8154:
+//        ret = 8054;
+//        break;
+//      case 8155:
+//        ret = 8055;
+//        break;
+//      case 8168:
+//        ret = 8160;
+//        break;
+//      case 8169:
+//        ret = 8161;
+//        break;
+//      case 8170:
+//        ret = 8058;
+//        break;
+//      case 8171:
+//        ret = 8059;
+//        break;
+//      case 8172:
+//        ret = 8165;
+//        break;
+//      case 8184:
+//        ret = 8056;
+//        break;
+//      case 8185:
+//        ret = 8057;
+//        break;
+//      case 8186:
+//        ret = 8060;
+//        break;
+//      case 8187:
+//        ret = 8061;
+//        break;
+//      case 8188:
+//        ret = 8179;
+//        break;
+//      case 8544:
+//        ret = 8560;
+//        break;
+//      case 8545:
+//        ret = 8561;
+//        break;
+//      case 8546:
+//        ret = 8562;
+//        break;
+//      case 8547:
+//        ret = 8563;
+//        break;
+//      case 8548:
+//        ret = 8564;
+//        break;
+//      case 8549:
+//        ret = 8565;
+//        break;
+//      case 8550:
+//        ret = 8566;
+//        break;
+//      case 8551:
+//        ret = 8567;
+//        break;
+//      case 8552:
+//        ret = 8568;
+//        break;
+//      case 8553:
+//        ret = 8569;
+//        break;
+//      case 8554:
+//        ret = 8570;
+//        break;
+//      case 8555:
+//        ret = 8571;
+//        break;
+//      case 8556:
+//        ret = 8572;
+//        break;
+//      case 8557:
+//        ret = 8573;
+//        break;
+//      case 8558:
+//        ret = 8574;
+//        break;
+//      case 8559:
+//        ret = 8575;
+//        break;
+//      case 9398:
+//        ret = 9424;
+//        break;
+//      case 9399:
+//        ret = 9425;
+//        break;
+//      case 9400:
+//        ret = 9426;
+//        break;
+//      case 9401:
+//        ret = 9427;
+//        break;
+//      case 9402:
+//        ret = 9428;
+//        break;
+//      case 9403:
+//        ret = 9429;
+//        break;
+//      case 9404:
+//        ret = 9430;
+//        break;
+//      case 9405:
+//        ret = 9431;
+//        break;
+//      case 9406:
+//        ret = 9432;
+//        break;
+//      case 9407:
+//        ret = 9433;
+//        break;
+//      case 9408:
+//        ret = 9434;
+//        break;
+//      case 9409:
+//        ret = 9435;
+//        break;
+//      case 9410:
+//        ret = 9436;
+//        break;
+//      case 9411:
+//        ret = 9437;
+//        break;
+//      case 9412:
+//        ret = 9438;
+//        break;
+//      case 9413:
+//        ret = 9439;
+//        break;
+//      case 9414:
+//        ret = 9440;
+//        break;
+//      case 9415:
+//        ret = 9441;
+//        break;
+//      case 9416:
+//        ret = 9442;
+//        break;
+//      case 9417:
+//        ret = 9443;
+//        break;
+//      case 9418:
+//        ret = 9444;
+//        break;
+//      case 9419:
+//        ret = 9445;
+//        break;
+//      case 9420:
+//        ret = 9446;
+//        break;
+//      case 9421:
+//        ret = 9447;
+//        break;
+//      case 9422:
+//        ret = 9448;
+//        break;
+//      case 9423:
+//        ret = 9449;
+//        break;
+//      case 65313:
+//        ret = 65345;
+//        break;
+//      case 65314:
+//        ret = 65346;
+//        break;
+//      case 65315:
+//        ret = 65347;
+//        break;
+//      case 65316:
+//        ret = 65348;
+//        break;
+//      case 65317:
+//        ret = 65349;
+//        break;
+//      case 65318:
+//        ret = 65350;
+//        break;
+//      case 65319:
+//        ret = 65351;
+//        break;
+//      case 65320:
+//        ret = 65352;
+//        break;
+//      case 65321:
+//        ret = 65353;
+//        break;
+//      case 65322:
+//        ret = 65354;
+//        break;
+//      case 65323:
+//        ret = 65355;
+//        break;
+//      case 65324:
+//        ret = 65356;
+//        break;
+//      case 65325:
+//        ret = 65357;
+//        break;
+//      case 65326:
+//        ret = 65358;
+//        break;
+//      case 65327:
+//        ret = 65359;
+//        break;
+//      case 65328:
+//        ret = 65360;
+//        break;
+//      case 65329:
+//        ret = 65361;
+//        break;
+//      case 65330:
+//        ret = 65362;
+//        break;
+//      case 65331:
+//        ret = 65363;
+//        break;
+//      case 65332:
+//        ret = 65364;
+//        break;
+//      case 65333:
+//        ret = 65365;
+//        break;
+//      case 65334:
+//        ret = 65366;
+//        break;
+//      case 65335:
+//        ret = 65367;
+//        break;
+//      case 65336:
+//        ret = 65368;
+//        break;
+//      case 65337:
+//        ret = 65369;
+//        break;
+//      case 65338:
+//        ret = 65370;
+//        break;
+//      }
+//      return (char) ret;
+//    }
     return Character.toLowerCase(c);
   }
 
-  /** Convert a String to title case. */
+  /** Convert a String to title case. 
+   * 
+   * @j2sIgnore
+   * 
+   * 
+   */
   public static String toTitleCase(String s)
   {
-    StringBuffer sb = new StringBuffer();
+   StringBuffer sb = new StringBuffer();
     for (int i = 0; i < s.length(); i++)
     {
-      sb.append(CaseMgr.toTitleCase(s.charAt(i)));
+      sb.append(CaseMgr.toTitleCaseC(s.charAt(i)));
     }
     return sb.toString();
   }
@@ -4194,73 +4199,80 @@ final public class CaseMgr
   /** Convert a String to upper case. */
   public static String toUpperCase(String s)
   {
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0; i < s.length(); i++)
-    {
-      sb.append(CaseMgr.toUpperCase(s.charAt(i)));
-    }
-    return sb.toString();
+       return s.toUpperCase();
+//    StringBuffer sb = new StringBuffer();
+//    for (int i = 0; i < s.length(); i++)
+//    {
+//      sb.append(CaseMgr.toUpperCaseC(s.charAt(i)));
+//    }
+//    return sb.toString();
   }
 
   /** Convert a String to lower case. */
   public static String toLowerCase(String s)
   {
-    StringBuffer sb = new StringBuffer();
-    for (int i = 0; i < s.length(); i++)
-    {
-      sb.append(CaseMgr.toLowerCase(s.charAt(i)));
-    }
-    return sb.toString();
+       return s.toLowerCase();
+//    StringBuffer sb = new StringBuffer();
+//    for (int i = 0; i < s.length(); i++)
+//    {
+//      sb.append(CaseMgr.toLowerCaseC(s.charAt(i)));
+//    }
+//    return sb.toString();
   }
 
-  /** Convert a character to title case. */
-  public static char toTitleCase(char c)
+  /** Convert a character to title case. 
+   * 
+   * SwingJS -- BH -- ignoring title case. 
+   * 
+   * */
+  public static char toTitleCaseC(char c)
   {
-    if (java_1_0)
-    {
-      int ret = (int) toUpperCase(c);
-      switch (c)
-      {
-      case 452:
-        ret = 453;
-        break;
-      case 453:
-        ret = 453;
-        break;
-      case 454:
-        ret = 453;
-        break;
-      case 455:
-        ret = 456;
-        break;
-      case 456:
-        ret = 456;
-        break;
-      case 457:
-        ret = 456;
-        break;
-      case 458:
-        ret = 459;
-        break;
-      case 459:
-        ret = 459;
-        break;
-      case 460:
-        ret = 459;
-        break;
-      case 497:
-        ret = 498;
-        break;
-      case 498:
-        ret = 498;
-        break;
-      case 499:
-        ret = 498;
-        break;
-      }
-      return (char) ret;
-    }
-    return Character.toTitleCase(c);
+       return Character.toUpperCase(c);
+//    if (java_1_0)
+//    {
+//      int ret = (int) toUpperCaseC(c);
+//      switch (c)
+//      {
+//      case 452:
+//        ret = 453;
+//        break;
+//      case 453:
+//        ret = 453;
+//        break;
+//      case 454:
+//        ret = 453;
+//        break;
+//      case 455:
+//        ret = 456;
+//        break;
+//      case 456:
+//        ret = 456;
+//        break;
+//      case 457:
+//        ret = 456;
+//        break;
+//      case 458:
+//        ret = 459;
+//        break;
+//      case 459:
+//        ret = 459;
+//        break;
+//      case 460:
+//        ret = 459;
+//        break;
+//      case 497:
+//        ret = 498;
+//        break;
+//      case 498:
+//        ret = 498;
+//        break;
+//      case 499:
+//        ret = 498;
+//        break;
+//      }
+//      return (char) ret;
+//    }
+//    return Character.toTitleCase(c);
   }
 
   /**
@@ -4268,7 +4280,7 @@ final public class CaseMgr
    * definitions of upper, lower, and title case in this class when ignoreCase
    * is set.
    */
-  public static boolean regionMatches(StringLike s1, boolean ign, int i1,
+  public static boolean regionMatchesLike(StringLike s1, boolean ign, int i1,
           StringLike s2, int i2, int i3)
   {
     int itot = i2 + i3;
@@ -4290,7 +4302,7 @@ final public class CaseMgr
     {
       for (int i = i2; i < itot; i++)
       {
-        if (toLowerCase(s2.charAt(i)) != toLowerCase(s1.charAt(i1++)))
+        if (toLowerCaseC(s2.charAt(i)) != toLowerCaseC(s1.charAt(i1++)))
         {
           return false;
         }
@@ -4326,7 +4338,7 @@ final public class CaseMgr
     {
       for (int i = i2; i < itot; i++)
       {
-        if (toLowerCase(s2.charAt(i)) != toLowerCase(s1.charAt(i1++)))
+        if (toLowerCaseC(s2.charAt(i)) != toLowerCaseC(s1.charAt(i1++)))
         {
           return false;
         }
@@ -4340,7 +4352,7 @@ final public class CaseMgr
    * definitions of upper, lower, and title case in this class when ignoreCase
    * is set.
    */
-  public static boolean regionMatches(StringLike s1, boolean ign, int i1,
+  public static boolean regionMatchesLike2(StringLike s1, boolean ign, int i1,
           String s2, int i2, int i3)
   {
     int itot = i2 + i3;
@@ -4362,7 +4374,7 @@ final public class CaseMgr
     {
       for (int i = i2; i < itot; i++)
       {
-        if (toLowerCase(s2.charAt(i)) != toLowerCase(s1.charAt(i1++)))
+        if (toLowerCaseC(s2.charAt(i)) != toLowerCaseC(s1.charAt(i1++)))
         {
           return false;
         }
@@ -4376,7 +4388,7 @@ final public class CaseMgr
    * definitions of upper, lower, and title case in this class when ignoreCase
    * is set.
    */
-  public static boolean regionMatches(String s1, boolean ign, int i1,
+  public static boolean regionMatches2(String s1, boolean ign, int i1,
           String s2, int i2, int i3)
   {
     int itot = i2 + i3;
@@ -4398,7 +4410,7 @@ final public class CaseMgr
     {
       for (int i = i2; i < itot; i++)
       {
-        if (toLowerCase(s2.charAt(i)) != toLowerCase(s1.charAt(i1++)))
+        if (toLowerCaseC(s2.charAt(i)) != toLowerCaseC(s1.charAt(i1++)))
         {
           return false;
         }
index bc62910..64a50fc 100755 (executable)
@@ -13,19 +13,19 @@ package com.stevesoft.pat;
  */
 public class DirFileRegex extends FileRegex
 {
-  public DirFileRegex()
-  {
-    dirflag = DIR;
-  }
-
-  public DirFileRegex(String fp)
-  {
-    super(fp);
-    dirflag = DIR;
-  }
-
-  public static String[] list(String f)
-  {
-    return list(f, DIR);
-  }
+//  public DirFileRegex()
+//  {
+//    dirflag = DIR;
+//  }
+//
+//  public DirFileRegex(String fp)
+//  {
+//    super(fp);
+//    dirflag = DIR;
+//  }
+//
+//  public static String[] list(String f)
+//  {
+//    return list(f, DIR);
+//  }
 }
index 342d41c..263a005 100755 (executable)
@@ -65,259 +65,259 @@ import java.util.*;
  */
 public class FileRegex extends Regex
 {
-  /** Build an unitialized FileRegex. */
-  public FileRegex()
-  {
-    dirflag = EITHER;
-  }
-
-  /** Build a FileRegex form String s. */
-  public FileRegex(String s)
-  {
-    super(s);
-    dirflag = EITHER;
-  }
-
-  /**
-   * Compile a new pattern. Throws
-   * 
-   * @exception com.stevesoft.pat.RegSyntax
-   *                    for nonsensical patterns like "[9-0]+" just as Regex
-   *                    does.
-   * @see com.stevesoft.pat#compile(java.lang.String)
-   */
-  public void compile(String s) throws RegSyntax
-  {
-    String npat = toFileRegex(s);
-    super.compile(npat);
-    if (File.separatorChar == '\\') // MS-DOS
-    {
-      ignoreCase = true;
-    }
-  }
-
-  /**
-   * This is the method required by FileNameFilter. To get a listing of files in
-   * the current directory ending in .java, do this:
-   * 
-   * <pre>
-   * File dot = new File(&quot;.&quot;);
-   * 
-   * FileRegex java_files = new FileRegex(&quot;*.java&quot;);
-   * 
-   * String[] file_list = dot.list(java_files);
-   * </pre>
-   */
-  public boolean accept(File dir, String s)
-  {
-    if (dirflag != EITHER)
-    {
-      File f = new File(s);
-      if (f.isDirectory() && dirflag == NONDIR)
-      {
-        return false;
-      }
-      if (!f.isDirectory() && dirflag == DIR)
-      {
-        return false;
-      }
-    }
-    return matchAt(s, 0);
-  }
-
-  int dirflag = 0;
-
-  final static int EITHER = 0, DIR = 1, NONDIR = 2;
-
-  /**
-   * Provides an alternative to File.list -- this separates its argument
-   * according to File.pathSeparator. To each path, it splits off a directory --
-   * all characters up to and including the first instance of File.separator --
-   * and a file pattern -- the part that comes after the directory. It then
-   * produces a list of all the pattern matches on all the paths. Thus
-   * "*.java:../*.java" would produce a list of all the java files in this
-   * directory and in the ".." directory on a Unix machine. "*.java;..\\*.java"
-   * would do the same thing on a Dos machine.
-   */
-  public static String[] list(String f)
-  {
-    return list(f, EITHER);
-  }
-
-  static String[] list(String f, int df)
-  {
-    // return list_(f,new FileRegex());
-    StringTokenizer st = new StringTokenizer(f, File.pathSeparator);
-    Vector v = new Vector();
-    while (st.hasMoreTokens())
-    {
-      String path = st.nextToken();
-      list1(path, v, df, true);
-    }
-    String[] sa = new String[v.size()];
-    v.copyInto(sa);
-    return sa;
-  }
-
-  final static Regex root = new Regex(File.separatorChar == '/' ? "/$"
-          : "(?:.:|)\\\\$");
-
-  static void list1(String path, Vector v, int df, boolean rec)
-  {
-    // if path looks like a/b/c/ or d:\ then add .
-    if (root.matchAt(path, 0))
-    {
-      v.addElement(path + ".");
-      return;
-    }
-    File f = new File(path);
-    if (f.getParent() != null && rec)
-    {
-      Vector v2 = new Vector();
-      list1(f.getParent(), v2, DIR, true);
-      for (int i = 0; i < v2.size(); i++)
-      {
-        String path2 = ((String) v2.elementAt(i)) + File.separator
-                + f.getName();
-        list1(path2, v, df, false);
-      }
-    }
-    else
-    {
-      File base = new File(path);
-
-      String dir_s = base.getParent();
-      if (dir_s == null)
-      {
-        dir_s = ".";
-      }
-      File dir = new File(dir_s);
-
-      FileRegex fr = new FileRegex(base.getName());
-      if (fr.isLiteral())
-      {
-        v.addElement(dir_s + File.separator + base.getName());
-        return;
-      }
-      fr.dirflag = df;
-      String[] sa = dir.list(fr);
-      if (sa == null)
-      {
-        return;
-      }
-      for (int i = 0; i < sa.length; i++)
-      {
-        v.addElement(dir_s + File.separator + sa[i]);
-      }
-    }
-  }
-
-  /**
-   * This method takes a file regular expression, and translates it into the
-   * type of pattern used by a normal Regex.
-   */
-  public static String toFileRegex(String s)
-  {
-    StrPos sp = new StrPos(s, 0);
-    StringBuffer sb = new StringBuffer();
-    if (sp.incMatch("{?e="))
-    {
-      char e = sp.thisChar();
-      sp.inc();
-      if (sp.incMatch("}"))
-      {
-        sb.append("(?e=" + e + ")^");
-      }
-      else
-      {
-        sb.append("^(?e=");
-      }
-      sp.esc = e;
-    }
-    int ParenLvl = 0;
-    while (!sp.eos())
-    {
-      if (File.separatorChar == '\\')
-      {
-        if (sp.escaped())
-        {
-          sb.append("\\\\");
-        }
-        sp.dontMatch = false;
-      }
-      if (sp.incMatch("?"))
-      {
-        sb.append(".");
-      }
-      else if (sp.incMatch("."))
-      {
-        sb.append(sp.esc);
-        sb.append('.');
-      }
-      else if (sp.incMatch("{??"))
-      {
-        sb.append("(??");
-        ParenLvl++;
-        // allow negative lookahead to work
-      }
-      else if (sp.incMatch("{?!"))
-      {
-        sb.append("(?!");
-        ParenLvl++;
-        // allow positive lookahead to work
-      }
-      else if (sp.incMatch("{?="))
-      {
-        sb.append("(?=");
-        ParenLvl++;
-      }
-      else if (sp.incMatch("{"))
-      {
-        sb.append("(?:");
-        ParenLvl++;
-      }
-      else if (sp.incMatch("}"))
-      {
-        sb.append(')');
-        ParenLvl--;
-      }
-      else if (ParenLvl != 0 && sp.incMatch(","))
-      {
-        sb.append('|');
-      }
-      else if (sp.incMatch("*"))
-      {
-        sb.append(".*");
-      }
-      else
-      {
-        sb.append(sp.thisChar());
-        sp.inc();
-      }
-    }
-    sb.append("$");
-    return sb.toString();
-  }
-
-  public boolean isLiteral()
-  {
-    Pattern x = thePattern;
-    while (x != null && !(x instanceof End))
-    {
-      if (x instanceof oneChar)
-      {
-        ;
-      }
-      else if (x instanceof Skipped)
-      {
-        ;
-      }
-      else
-      {
-        return false;
-      }
-      x = x.next;
-    }
-    return true;
-  }
+//  /** Build an unitialized FileRegex. */
+//  public FileRegex()
+//  {
+//    dirflag = EITHER;
+//  }
+//
+//  /** Build a FileRegex form String s. */
+//  public FileRegex(String s)
+//  {
+//    super(s);
+//    dirflag = EITHER;
+//  }
+//
+//  /**
+//   * Compile a new pattern. Throws
+//   * 
+//   * @exception com.stevesoft.pat.RegSyntax
+//   *                    for nonsensical patterns like "[9-0]+" just as Regex
+//   *                    does.
+//   * @see com.stevesoft.pat#compile(java.lang.String)
+//   */
+//  public void compile(String s) throws RegSyntax
+//  {
+//    String npat = toFileRegex(s);
+//    super.compile(npat);
+//    if (File.separatorChar == '\\') // MS-DOS
+//    {
+//      ignoreCase = true;
+//    }
+//  }
+//
+//  /**
+//   * This is the method required by FileNameFilter. To get a listing of files in
+//   * the current directory ending in .java, do this:
+//   * 
+//   * <pre>
+//   * File dot = new File(&quot;.&quot;);
+//   * 
+//   * FileRegex java_files = new FileRegex(&quot;*.java&quot;);
+//   * 
+//   * String[] file_list = dot.list(java_files);
+//   * </pre>
+//   */
+//  public boolean accept(File dir, String s)
+//  {
+//    if (dirflag != EITHER)
+//    {
+//      File f = new File(s);
+//      if (f.isDirectory() && dirflag == NONDIR)
+//      {
+//        return false;
+//      }
+//      if (!f.isDirectory() && dirflag == DIR)
+//      {
+//        return false;
+//      }
+//    }
+//    return matchAt(s, 0);
+//  }
+//
+//  int dirflag = 0;
+//
+//  final static int EITHER = 0, DIR = 1, NONDIR = 2;
+//
+//  /**
+//   * Provides an alternative to File.list -- this separates its argument
+//   * according to File.pathSeparator. To each path, it splits off a directory --
+//   * all characters up to and including the first instance of File.separator --
+//   * and a file pattern -- the part that comes after the directory. It then
+//   * produces a list of all the pattern matches on all the paths. Thus
+//   * "*.java:../*.java" would produce a list of all the java files in this
+//   * directory and in the ".." directory on a Unix machine. "*.java;..\\*.java"
+//   * would do the same thing on a Dos machine.
+//   */
+//  public static String[] list(String f)
+//  {
+//    return list(f, EITHER);
+//  }
+//
+//  static String[] list(String f, int df)
+//  {
+//    // return list_(f,new FileRegex());
+//    StringTokenizer st = new StringTokenizer(f, File.pathSeparator);
+//    Vector v = new Vector();
+//    while (st.hasMoreTokens())
+//    {
+//      String path = st.nextToken();
+//      list1(path, v, df, true);
+//    }
+//    String[] sa = new String[v.size()];
+//    v.copyInto(sa);
+//    return sa;
+//  }
+//
+//  final static Regex root = new Regex(File.separatorChar == '/' ? "/$"
+//          : "(?:.:|)\\\\$");
+//
+//  static void list1(String path, Vector v, int df, boolean rec)
+//  {
+//    // if path looks like a/b/c/ or d:\ then add .
+//    if (root.matchAt(path, 0))
+//    {
+//      v.addElement(path + ".");
+//      return;
+//    }
+//    File f = new File(path);
+//    if (f.getParent() != null && rec)
+//    {
+//      Vector v2 = new Vector();
+//      list1(f.getParent(), v2, DIR, true);
+//      for (int i = 0; i < v2.size(); i++)
+//      {
+//        String path2 = ((String) v2.elementAt(i)) + File.separator
+//                + f.getName();
+//        list1(path2, v, df, false);
+//      }
+//    }
+//    else
+//    {
+//      File base = new File(path);
+//
+//      String dir_s = base.getParent();
+//      if (dir_s == null)
+//      {
+//        dir_s = ".";
+//      }
+//      File dir = new File(dir_s);
+//
+//      FileRegex fr = new FileRegex(base.getName());
+//      if (fr.isLiteral())
+//      {
+//        v.addElement(dir_s + File.separator + base.getName());
+//        return;
+//      }
+//      fr.dirflag = df;
+//      String[] sa = dir.list(fr);
+//      if (sa == null)
+//      {
+//        return;
+//      }
+//      for (int i = 0; i < sa.length; i++)
+//      {
+//        v.addElement(dir_s + File.separator + sa[i]);
+//      }
+//    }
+//  }
+//
+//  /**
+//   * This method takes a file regular expression, and translates it into the
+//   * type of pattern used by a normal Regex.
+//   */
+//  public static String toFileRegex(String s)
+//  {
+//    StrPos sp = new StrPos(s, 0);
+//    StringBuffer sb = new StringBuffer();
+//    if (sp.incMatch("{?e="))
+//    {
+//      char e = sp.thisChar();
+//      sp.inc();
+//      if (sp.incMatch("}"))
+//      {
+//        sb.append("(?e=" + e + ")^");
+//      }
+//      else
+//      {
+//        sb.append("^(?e=");
+//      }
+//      sp.esc = e;
+//    }
+//    int ParenLvl = 0;
+//    while (!sp.eos())
+//    {
+//      if (File.separatorChar == '\\')
+//      {
+//        if (sp.escaped())
+//        {
+//          sb.append("\\\\");
+//        }
+//        sp.dontMatch = false;
+//      }
+//      if (sp.incMatch("?"))
+//      {
+//        sb.append(".");
+//      }
+//      else if (sp.incMatch("."))
+//      {
+//        sb.append(sp.esc);
+//        sb.append('.');
+//      }
+//      else if (sp.incMatch("{??"))
+//      {
+//        sb.append("(??");
+//        ParenLvl++;
+//        // allow negative lookahead to work
+//      }
+//      else if (sp.incMatch("{?!"))
+//      {
+//        sb.append("(?!");
+//        ParenLvl++;
+//        // allow positive lookahead to work
+//      }
+//      else if (sp.incMatch("{?="))
+//      {
+//        sb.append("(?=");
+//        ParenLvl++;
+//      }
+//      else if (sp.incMatch("{"))
+//      {
+//        sb.append("(?:");
+//        ParenLvl++;
+//      }
+//      else if (sp.incMatch("}"))
+//      {
+//        sb.append(')');
+//        ParenLvl--;
+//      }
+//      else if (ParenLvl != 0 && sp.incMatch(","))
+//      {
+//        sb.append('|');
+//      }
+//      else if (sp.incMatch("*"))
+//      {
+//        sb.append(".*");
+//      }
+//      else
+//      {
+//        sb.append(sp.thisChar());
+//        sp.inc();
+//      }
+//    }
+//    sb.append("$");
+//    return sb.toString();
+//  }
+//
+//  public boolean isLiteral()
+//  {
+//    Pattern x = thePattern;
+//    while (x != null && !(x instanceof End))
+//    {
+//      if (x instanceof oneChar)
+//      {
+//        ;
+//      }
+//      else if (x instanceof Skipped)
+//      {
+//        ;
+//      }
+//      else
+//      {
+//        return false;
+//      }
+//      x = x.next;
+//    }
+//    return true;
+//  }
 }
diff --git a/src/com/stevesoft/pat/MessageManager.java b/src/com/stevesoft/pat/MessageManager.java
new file mode 100644 (file)
index 0000000..d752bba
--- /dev/null
@@ -0,0 +1,21 @@
+package com.stevesoft.pat;
+
+/**
+ * just a temporary implementation to avoid cross-referencing to jalview.
+ * @author Bob Hanson
+ *
+ */
+public class MessageManager {
+
+       public static String getString(String string) {
+               return string;
+       }
+
+       public static String formatMessage(String s, String...fields) {
+               // just a super super simple implementation to get us rolling
+               for (int i = 0; i < fields.length; i++)
+                       s += " " + fields[i];
+               return s;
+       }
+
+}
index 864243c..a2e1a3e 100755 (executable)
@@ -13,19 +13,19 @@ package com.stevesoft.pat;
  */
 public class NonDirFileRegex extends FileRegex
 {
-  public NonDirFileRegex()
-  {
-    dirflag = NONDIR;
-  }
-
-  public NonDirFileRegex(String fp)
-  {
-    super(fp);
-    dirflag = NONDIR;
-  }
-
-  public static String[] list(String f)
-  {
-    return list(f, NONDIR);
-  }
+//  public NonDirFileRegex()
+//  {
+//    dirflag = NONDIR;
+//  }
+//
+//  public NonDirFileRegex(String fp)
+//  {
+//    super(fp);
+//    dirflag = NONDIR;
+//  }
+//
+//  public static String[] list(String f)
+//  {
+//    return list(f, NONDIR);
+//  }
 }
index 3a3462c..0ea3f2e 100755 (executable)
@@ -7,7 +7,7 @@
 //
 package com.stevesoft.pat;
 
-import jalview.util.MessageManager;
+import com.stevesoft.pat.MessageManager;
 
 import java.util.*;
 
@@ -259,12 +259,12 @@ public abstract class Pattern
   /**
    * Clones this pattern elements without cloning others in the linked list.
    */
-  Pattern clone1(Hashtable h)
+  Pattern clone1(Hashtable<Object, Object> h)
   {
     throw new Error(MessageManager.formatMessage("error.no_such_method_as_clone1_for", new String[]{getClass().getName()}));
   }
 
-  Pattern clone(Hashtable h)
+  Pattern clone(Hashtable<Object, Object>  h)
   {
     Pattern p = (Pattern) h.get(this);
     if (p != null)
index a204c47..83a6c62 100755 (executable)
@@ -14,7 +14,7 @@ package com.stevesoft.pat;
 /**
  * This class is used to store a result from Regex
  */
-public class RegRes implements Cloneable
+public class RegRes
 {
   protected int[] marks = null;
 
@@ -48,20 +48,20 @@ public class RegRes implements Cloneable
     {
       int n = i + 1;
       sb
-              .append(" sub(" + n + ")=" + matchedFrom(n) + ":"
-                      + charsMatched(n));
+              .append(" sub(" + n + ")=" + matchedFromI(n) + ":"
+                      + charsMatchedI(n));
     }
     return sb.toString();
   }
 
-  public RegRes()
-  {
-  }
-
-  public RegRes(RegRes r)
-  {
-    copyOutOf(r);
-  }
+//  public RegRes()
+//  {
+//  }
+//
+//  public RegRes(RegRes r)
+//  {
+//    copyOutOf(r);
+//  }
 
   public void copyOutOf(RegRes r)
   {
@@ -91,11 +91,11 @@ public class RegRes implements Cloneable
     numSubs_ = r.numSubs_;
   }
 
-  public Object clone()
-  {
-    return new RegRes(this);
-  }
-
+//  public Object clone()
+//  {
+//    return new RegRes(this);
+//  }
+//
   public boolean equals(RegRes r)
   {
     if (charsMatched_ != r.charsMatched_ || matchFrom_ != r.matchFrom_
@@ -114,11 +114,11 @@ public class RegRes implements Cloneable
     }
     for (int i = 1; i <= numSubs_; i++)
     {
-      if (matchedFrom(i) != r.matchedFrom(i))
+      if (matchedFromI(i) != r.matchedFromI(i))
       {
         return false;
       }
-      else if (charsMatched(i) != r.charsMatched(i))
+      else if (charsMatchedI(i) != r.charsMatchedI(i))
       {
         return false;
       }
@@ -138,7 +138,7 @@ public class RegRes implements Cloneable
    * Obtains the position backreference number i begins to match, or -1 if
    * backreference i was not matched.
    */
-  public int matchedFrom(int i)
+  public int matchedFromI(int i)
   {
     if (marks == null || i > numSubs_)
     {
@@ -153,7 +153,7 @@ public class RegRes implements Cloneable
    * Obtains the number of characters matched by backreference i, or -1 if
    * backreference i was not matched.
    */
-  public int charsMatched(int i)
+  public int charsMatchedI(int i)
   {
     if (marks == null || i > numSubs_ || !didMatch_)
     {
@@ -161,15 +161,15 @@ public class RegRes implements Cloneable
     }
     // Integer in = (Integer)marks.get("right"+i);
     // int i2 = in==null ? -1 : in.intValue();
-    int mf = matchedFrom(i);
-    return mf < 0 ? -1 : marks[i + numSubs_] - matchedFrom(i);
+    int mf = matchedFromI(i);
+    return mf < 0 ? -1 : marks[i + numSubs_] - matchedFromI(i);
   }
 
   /**
    * This is either equal to matchedFrom(i)+charsMatched(i) if the match was
    * successful, or -1 if it was not.
    */
-  public int matchedTo(int i)
+  public int matchedToI(int i)
   {
     if (marks == null || i > numSubs_ || !didMatch_)
     {
@@ -182,9 +182,9 @@ public class RegRes implements Cloneable
    * Obtains a substring matching the nth set of parenthesis from the pattern.
    * See numSubs(void), or null if the nth backrefence did not match.
    */
-  public String stringMatched(int i)
+  public String stringMatchedI(int i)
   {
-    int mf = matchedFrom(i), cm = charsMatched(i);
+    int mf = matchedFromI(i), cm = charsMatchedI(i);
     return !didMatch_ || mf < 0 || cm < 0 ? null : src.substring(mf, mf
             + cm);
   }
@@ -203,9 +203,9 @@ public class RegRes implements Cloneable
    * This returns the part of the string that follows the ith backreference, or
    * null if the backreference did not match.
    */
-  public String left(int i)
+  public String leftI(int i)
   {
-    int mf = matchedFrom(i);
+    int mf = matchedFromI(i);
     return !didMatch_ || (mf < 0) ? null : src.substring(0, mf);
   }
 
@@ -224,9 +224,9 @@ public class RegRes implements Cloneable
    * This returns the string to the right of the ith backreference, or null if
    * the backreference did not match.
    */
-  public String right(int i)
+  public String rightI(int i)
   {
-    int mf = matchedFrom(i), cm = charsMatched(i);
+    int mf = matchedFromI(i), cm = charsMatchedI(i);
     return !didMatch_ || mf < 0 || cm < 0 ? null : src.substring(mf + cm,
             src.length());
   }
@@ -286,14 +286,14 @@ public class RegRes implements Cloneable
   }
 
   /** An older name for matchedFrom. */
-  public int matchFrom(int i)
+  public int matchFromI(int i)
   {
-    return matchedFrom(i);
+    return matchedFromI(i);
   }
 
   /** An older name for stringMatched. */
-  public String substring(int i)
+  public String substringI(int i)
   {
-    return stringMatched(i);
+    return stringMatchedI(i);
   }
 }
index 861c33b..5b788f2 100755 (executable)
@@ -7,12 +7,15 @@
 //
 package com.stevesoft.pat;
 
-import jalview.util.MessageManager;
+import com.stevesoft.pat.MessageManager;
 
-import java.io.*;
-import java.util.*;
+import jalview.jsdev.api.RegExpInterface;
 
-import com.stevesoft.pat.wrap.*;
+import java.io.File;
+import java.util.BitSet;
+import java.util.Hashtable;
+
+import com.stevesoft.pat.wrap.StringWrap;
 
 /** Matches a Unicode punctuation character. */
 class UnicodePunct extends UniValidator
@@ -169,7 +172,7 @@ class UnicodeUpper extends UniValidator
 
   final boolean isUpper(char c)
   {
-    return c == CaseMgr.toUpperCase(c) && c != CaseMgr.toLowerCase(c);
+    return c == CaseMgr.toUpperCaseC(c) && c != CaseMgr.toLowerCaseC(c);
   }
 }
 
@@ -183,7 +186,7 @@ class UnicodeLower extends UniValidator
 
   final boolean isLower(char c)
   {
-    return c != CaseMgr.toUpperCase(c) && c == CaseMgr.toLowerCase(c);
+    return c != CaseMgr.toUpperCaseC(c) && c == CaseMgr.toLowerCaseC(c);
   }
 }
 
@@ -284,7 +287,7 @@ class UnicodeLower extends UniValidator
  * @version package com.stevesoft.pat, release 1.5.3
  * @see Pattern
  */
-public class Regex extends RegRes implements FilenameFilter
+public class Regex extends RegRes implements RegExpInterface, Cloneable //implements FilenameFilter
 {
   /**
    * BackRefOffset gives the identity number of the first pattern. Version 1.0
@@ -298,25 +301,132 @@ public class Regex extends RegRes implements FilenameFilter
 
   patInt minMatch = new patInt(0);
 
-  static Hashtable validators = new Hashtable();
+  static Hashtable<Object, Object> validators = new Hashtable<Object, Object>();
   static
   {
-    define("p", "(?>1)", new UnicodePunct());
-    define("P", "(?>1)", new NUnicodePunct());
-    define("s", "(?>1)", new UnicodeWhite());
-    define("S", "(?>1)", new NUnicodeWhite());
-    define("w", "(?>1)", new UnicodeW());
-    define("W", "(?>1)", new NUnicodeW());
-    define("d", "(?>1)", new UnicodeDigit());
-    define("D", "(?>1)", new NUnicodeDigit());
-    define("m", "(?>1)", new UnicodeMath());
-    define("M", "(?>1)", new NUnicodeMath());
-    define("c", "(?>1)", new UnicodeCurrency());
-    define("C", "(?>1)", new NUnicodeCurrency());
-    define("a", "(?>1)", new UnicodeAlpha());
-    define("A", "(?>1)", new NUnicodeAlpha());
-    define("uc", "(?>1)", new UnicodeUpper());
-    define("lc", "(?>1)", new UnicodeLower());
+    defineV("p", "(?>1)", new UnicodePunct());
+    defineV("P", "(?>1)", new NUnicodePunct());
+    defineV("s", "(?>1)", new UnicodeWhite());
+    defineV("S", "(?>1)", new NUnicodeWhite());
+    defineV("w", "(?>1)", new UnicodeW());
+    defineV("W", "(?>1)", new NUnicodeW());
+    defineV("d", "(?>1)", new UnicodeDigit());
+    defineV("D", "(?>1)", new NUnicodeDigit());
+    defineV("m", "(?>1)", new UnicodeMath());
+    defineV("M", "(?>1)", new NUnicodeMath());
+    defineV("c", "(?>1)", new UnicodeCurrency());
+    defineV("C", "(?>1)", new NUnicodeCurrency());
+    defineV("a", "(?>1)", new UnicodeAlpha());
+    defineV("A", "(?>1)", new NUnicodeAlpha());
+    defineV("uc", "(?>1)", new UnicodeUpper());
+    defineV("lc", "(?>1)", new UnicodeLower());
+  }
+
+  ReplaceRule rep = null;
+
+
+  /**
+   * Initializes the object without a Pattern. To supply a Pattern use
+   * compile(String s).
+   * 
+   * @j2sIgnore
+   * 
+   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
+   */
+  @Deprecated
+  public Regex()
+  {
+  }
+
+  /**
+   * Create and compile both a Regex and a ReplaceRule.
+   * 
+   * @see com.stevesoft.pat.ReplaceRule
+   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
+   */
+  public Regex(String s, String strRp)
+  {
+    try
+    {
+       if (s != null)
+               compile(s);
+      if (strRp.length() > 0)
+        rep = ReplaceRule.perlCode(strRp);
+    } catch (RegSyntax rs)
+    {
+    }
+  }
+
+  /**
+   * Create and compile a Regex, but give it the ReplaceRule specified. This
+   * allows the user finer control of the Replacement process, if that is
+   * desired.
+   * 
+   * @j2sIgnore
+   * 
+   * @see com.stevesoft.pat.ReplaceRule
+   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
+   */
+  public Regex(String s, ReplaceRule rp)
+  {
+    this(s, "");
+    rep = rp;
+  }
+
+  /**
+   * Create and compile a Regex, but do not throw any exceptions. If you wish to
+   * have exceptions thrown for syntax errors, you must use the Regex(void)
+   * constructor to create the Regex object, and then call the compile method.
+   * Therefore, you should only call this method when you know your pattern is
+   * right. I will probably become more like
+   * 
+   * @j2sIgnore
+   * 
+   * @see com.stevesoft.pat.Regex#search(java.lang.String)
+   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
+   */
+  @Deprecated
+  public Regex(String s)
+  {
+       this(s, "");
+  }
+
+  /** A clone by any other name would smell as sweet. */
+  public Object clone()
+  {
+    return new Regex(null, "").cloneFrom(this);
+  }
+
+//  /** Return a clone of the underlying RegRes object. */
+//  public RegRes result()
+//  {
+//    return (RegRes) super.clone();
+//  }
+
+  /** Essentially clones the Regex object */
+  public Regex cloneFrom(Regex r)
+  {
+       copyOutOf(r);
+//    super((RegRes) r);
+    dontMatchInQuotes = r.dontMatchInQuotes;
+    esc = r.esc;
+    ignoreCase = r.ignoreCase;
+    gFlag = r.gFlag;
+    if (r.rep == null)
+    {
+      rep = null;
+    }
+    else
+    {
+      rep = (ReplaceRule) r.rep.clone();
+    }
+    /*
+     * try { compile(r.toString()); } catch(RegSyntax r_) {}
+     */
+    thePattern = r.thePattern.clone(new Hashtable<Object, Object>());
+    minMatch = r.minMatch;
+    skipper = r.skipper;
+    return this;
   }
 
   /** Set the dontMatch in quotes flag. */
@@ -374,68 +484,10 @@ public class Regex extends RegRes implements FilenameFilter
   }
 
   /**
-   * Initializes the object without a Pattern. To supply a Pattern use
-   * compile(String s).
-   * 
-   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
-   */
-  public Regex()
-  {
-  }
-
-  /**
-   * Create and compile a Regex, but do not throw any exceptions. If you wish to
-   * have exceptions thrown for syntax errors, you must use the Regex(void)
-   * constructor to create the Regex object, and then call the compile method.
-   * Therefore, you should only call this method when you know your pattern is
-   * right. I will probably become more like
-   * 
-   * @see com.stevesoft.pat.Regex#search(java.lang.String)
-   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
-   */
-  public Regex(String s)
-  {
-    try
-    {
-      compile(s);
-    } catch (RegSyntax rs)
-    {
-    }
-  }
-
-  ReplaceRule rep = null;
-
-  /**
-   * Create and compile both a Regex and a ReplaceRule.
-   * 
-   * @see com.stevesoft.pat.ReplaceRule
-   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
-   */
-  public Regex(String s, String rp)
-  {
-    this(s);
-    rep = ReplaceRule.perlCode(rp);
-  }
-
-  /**
-   * Create and compile a Regex, but give it the ReplaceRule specified. This
-   * allows the user finer control of the Replacement process, if that is
-   * desired.
-   * 
-   * @see com.stevesoft.pat.ReplaceRule
-   * @see com.stevesoft.pat.Regex#compile(java.lang.String)
-   */
-  public Regex(String s, ReplaceRule rp)
-  {
-    this(s);
-    rep = rp;
-  }
-
-  /**
    * Change the ReplaceRule of this Regex by compiling a new one using String
    * rp.
    */
-  public void setReplaceRule(String rp)
+  public void setReplaceRuleStr(String rp)
   {
     rep = ReplaceRule.perlCode(rp);
     repr = null; // Clear Replacer history
@@ -450,7 +502,7 @@ public class Regex extends RegRes implements FilenameFilter
   /**
    * Test to see if a custom defined rule exists.
    * 
-   * @see com.stevesoft.pat#define(java.lang.String,java.lang.String,Validator)
+   * @see com.stevesoft.pat#defineV(java.lang.String,java.lang.String,Validator)
    */
   public static boolean isDefined(String nm)
   {
@@ -460,7 +512,7 @@ public class Regex extends RegRes implements FilenameFilter
   /**
    * Removes a custom defined rule.
    * 
-   * @see com.stevesoft.pat#define(java.lang.String,java.lang.String,Validator)
+   * @see com.stevesoft.pat#defineV(java.lang.String,java.lang.String,Validator)
    */
   public static void undefine(String nm)
   {
@@ -471,7 +523,7 @@ public class Regex extends RegRes implements FilenameFilter
    * Defines a method to create a new rule. See test/deriv2.java and
    * test/deriv3.java for examples of how to use it.
    */
-  public static void define(String nm, String pat, Validator v)
+  public static void defineV(String nm, String pat, Validator v)
   {
     v.pattern = pat;
     validators.put(nm, v);
@@ -562,7 +614,7 @@ public class Regex extends RegRes implements FilenameFilter
             .toString();
   }
 
-  public StringLike replaceAll(StringLike s)
+  public StringLike replaceAllLike(StringLike s)
   {
     return _getReplacer().replaceAllRegion(s, this, 0, s.length());
   }
@@ -592,30 +644,6 @@ public class Regex extends RegRes implements FilenameFilter
     return _getReplacer().replaceAllRegion(s, this, start, end).toString();
   }
 
-  /** Essentially clones the Regex object */
-  public Regex(Regex r)
-  {
-    super((RegRes) r);
-    dontMatchInQuotes = r.dontMatchInQuotes;
-    esc = r.esc;
-    ignoreCase = r.ignoreCase;
-    gFlag = r.gFlag;
-    if (r.rep == null)
-    {
-      rep = null;
-    }
-    else
-    {
-      rep = (ReplaceRule) r.rep.clone();
-    }
-    /*
-     * try { compile(r.toString()); } catch(RegSyntax r_) {}
-     */
-    thePattern = r.thePattern.clone(new Hashtable());
-    minMatch = r.minMatch;
-    skipper = r.skipper;
-  }
-
   /**
    * By default, the escape character is the backslash, but you can make it
    * anything you want by setting this variable.
@@ -690,18 +718,6 @@ public class Regex extends RegRes implements FilenameFilter
     }
   }
 
-  /** A clone by any other name would smell as sweet. */
-  public Object clone()
-  {
-    return new Regex(this);
-  }
-
-  /** Return a clone of the underlying RegRes object. */
-  public RegRes result()
-  {
-    return (RegRes) super.clone();
-  }
-
   // prep sets global variables of class
   // Pattern so that it can access them
   // during an attempt at a match
@@ -762,9 +778,9 @@ public class Regex extends RegRes implements FilenameFilter
    * 
    * @see com.stevesoft.pat.Regex#search
    */
-  public boolean matchAt(StringLike s, int start_pos)
+  public boolean matchAtLike(StringLike s, int start_pos)
   {
-    return _search(s, start_pos, start_pos);
+    return _searchLike(s, start_pos, start_pos);
   }
 
   /**
@@ -782,13 +798,13 @@ public class Regex extends RegRes implements FilenameFilter
     return _search(s, 0, s.length());
   }
 
-  public boolean search(StringLike sl)
+  public boolean searchLike(StringLike sl)
   {
     if (sl == null)
     {
       throw new NullPointerException(MessageManager.getString("exception.null_string_like_given_to_regex_search"));
     }
-    return _search(sl, 0, sl.length());
+    return _searchLike(sl, 0, sl.length());
   }
 
   public boolean reverseSearch(String s)
@@ -800,13 +816,13 @@ public class Regex extends RegRes implements FilenameFilter
     return _reverseSearch(s, 0, s.length());
   }
 
-  public boolean reverseSearch(StringLike sl)
+  public boolean reverseSearchLike(StringLike sl)
   {
     if (sl == null)
     {
       throw new NullPointerException(MessageManager.getString("exception.null_string_like_given_to_regex_reverse_search"));
     }
-    return _reverseSearch(sl, 0, sl.length());
+    return _reverseSearchLike(sl, 0, sl.length());
   }
 
   /**
@@ -826,13 +842,13 @@ public class Regex extends RegRes implements FilenameFilter
     return _search(s, start, s.length());
   }
 
-  public boolean searchFrom(StringLike s, int start)
+  public boolean searchFromLike(StringLike s, int start)
   {
     if (s == null)
     {
         throw new NullPointerException(MessageManager.getString("exception.null_string_like_given_to_regex_search_from"));
     }
-    return _search(s, start, s.length());
+    return _searchLike(s, start, s.length());
   }
 
   /**
@@ -889,10 +905,10 @@ public class Regex extends RegRes implements FilenameFilter
 
   final boolean _search(String s, int start, int end)
   {
-    return _search(new StringWrap(s), start, end);
+    return _searchLike(new StringWrap(s), start, end);
   }
 
-  final boolean _search(StringLike s, int start, int end)
+  final boolean _searchLike(StringLike s, int start, int end)
   {
     if (gFlag && gFlagto > 0 && gFlags != null
             && s.unwrap() == gFlags.unwrap())
@@ -974,10 +990,10 @@ public class Regex extends RegRes implements FilenameFilter
 
   boolean _reverseSearch(String s, int start, int end)
   {
-    return _reverseSearch(new StringWrap(s), start, end);
+    return _reverseSearchLike(new StringWrap(s), start, end);
   }
 
-  boolean _reverseSearch(StringLike s, int start, int end)
+  boolean _reverseSearchLike(StringLike s, int start, int end)
   {
     if (gFlag && gFlagto > 0 && s.unwrap() == gFlags.unwrap())
     {
@@ -1054,21 +1070,21 @@ public class Regex extends RegRes implements FilenameFilter
     lasts = s;
   }
 
-  // Wanted user to over-ride this in alpha version,
-  // but it wasn't really necessary because of this trick:
-  Regex newRegex()
-  {
-    try
-    {
-      return (Regex) getClass().newInstance();
-    } catch (InstantiationException ie)
-    {
-      return null;
-    } catch (IllegalAccessException iae)
-    {
-      return null;
-    }
-  }
+//  // Wanted user to over-ride this in alpha version,
+//  // but it wasn't really necessary because of this trick:
+//  Regex newRegex()
+//  {
+//    try
+//    {
+//      return (Regex) getClass().newInstance();
+//    } catch (InstantiationException ie)
+//    {
+//      return null;
+//    } catch (IllegalAccessException iae)
+//    {
+//      return null;
+//    }
+//  }
 
   /**
    * Only needed for creating your own extensions of Regex. This method adds the
@@ -1100,7 +1116,7 @@ public class Regex extends RegRes implements FilenameFilter
    *                    is thrown when a nonsensensical pattern is supplied. For
    *                    example, a pattern beginning with *.
    */
-  protected void compile1(StrPos sp, Rthings mk) throws RegSyntax
+  protected void compileSP(StrPos sp, Rthings mk) throws RegSyntax
   {
     if (sp.match('['))
     {
@@ -1235,7 +1251,7 @@ public class Regex extends RegRes implements FilenameFilter
     }
     else if (sp.dontMatch && sp.c == 'B')
     {
-      Regex r = new Regex();
+      Regex r = new Regex(null, "");
       r._compile("(?!" + back_slash + "b)", mk);
       add(r.thePattern);
     }
@@ -1306,7 +1322,7 @@ public class Regex extends RegRes implements FilenameFilter
       if (validators.get(sbs) instanceof String)
       {
         String pat = (String) validators.get(sbs);
-        Regex r = newRegex();
+        Regex r = new Regex(null, "");
         Rthings rth = new Rthings(this);
         rth.noBackRefs = true;
         r._compile(pat, rth);
@@ -1325,7 +1341,7 @@ public class Regex extends RegRes implements FilenameFilter
             cm.v = v2;
             v2.pattern = p;
           }
-          Regex r = newRegex();
+          Regex r = new Regex(null, "");
           Rthings rth = new Rthings(this);
           rth.noBackRefs = true;
           r._compile(cm.v.pattern, rth);
@@ -1339,7 +1355,7 @@ public class Regex extends RegRes implements FilenameFilter
     else if (sp.match('('))
     {
       mk.parenLevel++;
-      Regex r = newRegex();
+      Regex r = new Regex(null, "");
       // r.or = new Or();
       sp.inc();
       if (sp.incMatch("?:"))
@@ -1398,7 +1414,7 @@ public class Regex extends RegRes implements FilenameFilter
       }
       if (r != null)
       {
-        add(r._compile(sp, mk));
+        add(r._compileSP(sp, mk));
       }
     }
     else if (sp.match('^'))
@@ -1534,7 +1550,7 @@ public class Regex extends RegRes implements FilenameFilter
     minMatch = null;
     sFlag = mFlag = ignoreCase = gFlag = false;
     StrPos sp = new StrPos(pat, 0);
-    thePattern = _compile(sp, mk);
+    thePattern = _compileSP(sp, mk);
     pt.marks = null;
     return thePattern;
   }
@@ -1543,11 +1559,11 @@ public class Regex extends RegRes implements FilenameFilter
 
   Or or = null;
 
-  Pattern _compile(StrPos sp, Rthings mk) throws RegSyntax
+  Pattern _compileSP(StrPos sp, Rthings mk) throws RegSyntax
   {
     while (!(sp.eos || (or != null && sp.match(')'))))
     {
-      compile1(sp, mk);
+      compileSP(sp, mk);
       sp.inc();
     }
     if (sp.match(')'))
@@ -1786,11 +1802,11 @@ public class Regex extends RegRes implements FilenameFilter
    */
   public String toString()
   {
-    if (false && thePattern == null)
-    {
-      return "";
-    }
-    else
+//    if (false && thePattern == null)
+//    {
+//      return "";
+//    }
+//    else
     {
       StringBuffer sb = new StringBuffer();
       if (esc != Pattern.ESC)
@@ -1927,7 +1943,7 @@ public class Regex extends RegRes implements FilenameFilter
     }
     minMatch = new patInt(0); // thePattern.countMinChars();
     thePattern = RegOpt.opt(thePattern, ignoreCase, dontMatchInQuotes);
-    skipper = Skip.findSkip(this);
+    skipper = Skip.findSkipRegex(this);
     // RegOpt.setParents(this);
     return;
   }
index 2e10f16..c89139a 100755 (executable)
@@ -95,7 +95,7 @@ public class RegexReader extends Reader
       {
         readData();
       }
-      else if (rp.getRegex().matchAt(wrap, rb.epos))
+      else if (rp.getRegex().matchAtLike(wrap, rb.epos))
       {
         if (wrap.overRun)
         {
index 0378f3a..1913124 100755 (executable)
@@ -47,9 +47,9 @@ public class RegexTokenizer implements Enumeration
       {
         if (r.substring() != null)
         {
-          v.addElement(r.substring(i + offset));
-          vi.addElement(new Integer(r.matchFrom(i + offset)
-                  + r.charsMatched(i + offset)));
+          v.addElement(r.substringI(i + offset));
+          vi.addElement(new Integer(r.matchFromI(i + offset)
+                  + r.charsMatchedI(i + offset)));
         }
       }
       pos = r.matchFrom() + r.charsMatched();
@@ -64,7 +64,7 @@ public class RegexTokenizer implements Enumeration
   public RegexTokenizer(String txt, String ptrn)
   {
     toParse = txt;
-    r = new Regex(ptrn);
+    r = new Regex(ptrn, "");
     offset = Regex.BackRefOffset;
     getMore();
   }
index 61bcdf6..6f23545 100755 (executable)
@@ -123,7 +123,7 @@ public class RegexWriter extends Writer
   {
     Regex rex = repr.getRegex();
     int eposOld = epos;
-    if (rex.matchAt(wrap, epos) && !wrap.overRun)
+    if (rex.matchAtLike(wrap, epos) && !wrap.overRun)
     {
       while (pos < epos)
       {
index bf56143..4805ed4 100755 (executable)
@@ -93,7 +93,7 @@ public abstract class ReplaceRule
 
   static Regex getvar = null;
 
-  final static Regex getv()
+  private static Regex getv()
   {
     // Thanks to Michael Jimenez for pointing out the need
     // to clone getvar rather than simply returning it.
@@ -113,7 +113,7 @@ public abstract class ReplaceRule
             "\\\\c([\u0000-\uFFFF])|" + // ref 8
             "\\\\x([A-Fa-f0-9]{2})|" + // ref 9
             "\\\\([\u0000-\uFFFF])" + // ref 10
-            ")");
+            ")", "");
     getvar.optimize();
     return getvar;
   }
@@ -142,9 +142,9 @@ public abstract class ReplaceRule
           head = add(head, new StringRule(s.substring(mt, mf)));
         }
         String var = null;
-        if ((var = gv.stringMatched(1 + off)) != null
-                || (var = gv.stringMatched(2 + off)) != null
-                || (var = gv.stringMatched(5 + off)) != null)
+        if ((var = gv.stringMatchedI(1 + off)) != null
+                || (var = gv.stringMatchedI(2 + off)) != null
+                || (var = gv.stringMatchedI(5 + off)) != null)
         {
           int d = 0;
           for (int i = 0; i < var.length(); i++)
@@ -160,7 +160,7 @@ public abstract class ReplaceRule
             head = new StringRule("" + (char) d);
           }
         }
-        else if ((var = gv.stringMatched(10 + off)) != null)
+        else if ((var = gv.stringMatchedI(10 + off)) != null)
         {
           if ("QELlUu".indexOf(var) >= 0)
           {
@@ -171,9 +171,9 @@ public abstract class ReplaceRule
             head = add(head, new StringRule(var));
           }
         }
-        else if ((var = gv.stringMatched(3 + off)) != null
-                || (var = gv.stringMatched(4 + off)) != null
-                || (var = gv.stringMatched(6 + off)) != null)
+        else if ((var = gv.stringMatchedI(3 + off)) != null
+                || (var = gv.stringMatchedI(4 + off)) != null
+                || (var = gv.stringMatchedI(6 + off)) != null)
         {
           String arg = "";
           int pc;
@@ -255,7 +255,7 @@ public abstract class ReplaceRule
             head = add(head, new StringRule("${" + var + "}"));
           }
         }
-        else if ((var = gv.stringMatched(7 + off)) != null)
+        else if ((var = gv.stringMatchedI(7 + off)) != null)
         {
           char c = var.charAt(0);
           if (c == 'n')
@@ -287,7 +287,7 @@ public abstract class ReplaceRule
             head = add(head, new StringRule("" + (char) 12));
           }
         }
-        else if ((var = gv.stringMatched(8 + off)) != null)
+        else if ((var = gv.stringMatchedI(8 + off)) != null)
         {
           char c = var.charAt(0);
           if (c < Ctrl.cmap.length)
@@ -296,7 +296,7 @@ public abstract class ReplaceRule
           }
           head = add(head, new StringRule("" + c));
         }
-        else if ((var = gv.stringMatched(9 + off)) != null)
+        else if ((var = gv.stringMatchedI(9 + off)) != null)
         {
           int d = 16 * getHexDigit(var.charAt(0))
                   + getHexDigit(var.charAt(1));
index b886f6a..ce512a5 100755 (executable)
@@ -7,7 +7,7 @@
 //
 package com.stevesoft.pat;
 
-import jalview.util.MessageManager;
+import com.stevesoft.pat.MessageManager;
 
 import com.stevesoft.pat.wrap.*;
 
@@ -182,7 +182,7 @@ public class Replacer
     {
       throw new NullPointerException(MessageManager.getString("exception.replace_null_regex_pointer"));
     }
-    if (rh.me._search(s, start, end))
+    if (rh.me._searchLike(s, start, end))
     {
       int rmn = rh.me.matchedTo();
       if (rh.me.charsMatched() == 0 && !isSpecial(rh.me.getReplaceRule()))
@@ -193,7 +193,7 @@ public class Replacer
       apply(rh.me);
       if (!first)
       {
-        for (int i = rmn; !want_more_text && rh.me._search(s, i, end); i = rmn)
+        for (int i = rmn; !want_more_text && rh.me._searchLike(s, i, end); i = rmn)
         {
           rmn = rh.me.matchedTo();
           if (rh.me.charsMatched() == 0)
@@ -245,7 +245,7 @@ public class Replacer
       int rmf = r.matchedFrom();
       for (int ii = pos; ii < rmf; ii++)
       {
-        sb.append(src.charAt(ii));
+        sb.appendC(src.charAt(ii));
       }
 
       for (ReplaceRule x = rp; x != null; x = x.next)
@@ -315,7 +315,7 @@ public class Replacer
     int s_end = src.length();
     for (int ii = pos; ii < s_end; ii++)
     {
-      sb.append(src.charAt(ii));
+      sb.appendC(src.charAt(ii));
     }
     src = null;
     lastMatchedTo = pos;
index d3f3822..c3e05f8 100755 (executable)
@@ -20,8 +20,8 @@ public class Skip
   static int mkmask(int c)
   {
     char x = (char) c;
-    return ~(CaseMgr.toUpperCase(x) | CaseMgr.toLowerCase(x) | CaseMgr
-            .toTitleCase(x));
+    return ~(CaseMgr.toUpperCaseC(x) | CaseMgr.toLowerCaseC(x) | CaseMgr
+            .toTitleCaseC(x));
   }
 
   String src;
@@ -102,7 +102,7 @@ public class Skip
         if (0 == (s.charAt(i) & mask))
         {
           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
-          if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
+          if (m1 || CaseMgr.regionMatchesLike2(s, ign, i, src, 0, src.length()))
           {
             return i - offset;
           }
@@ -116,7 +116,7 @@ public class Skip
         if (c == s.charAt(i))
         {
           // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
-          if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
+          if (m1 || CaseMgr.regionMatchesLike2(s, ign, i, src, 0, src.length()))
           {
             return i - offset;
           }
@@ -126,7 +126,7 @@ public class Skip
     return -1;
   }
 
-  static Skip findSkip(Regex r)
+  static Skip findSkipRegex(Regex r)
   {
     return findSkip(r.thePattern, r.ignoreCase, !r.dontMatchInQuotes);
   }
index 5f6bb5a..b498a3e 100755 (executable)
@@ -46,7 +46,7 @@ public class Skip2 extends Skip
       if (0 == (s.charAt(i) & mask) && 0 == (s.charAt(i + 1) & mask1))
       {
         // if(m1||s.regionMatches(ign,i,src,0,src.length()) )
-        if (m1 || CaseMgr.regionMatches(s, ign, i, src, 0, src.length()))
+        if (m1 || CaseMgr.regionMatchesLike2(s, ign, i, src, 0, src.length()))
         {
           return i - offset;
         }
index 1397b90..8529fdb 100755 (executable)
@@ -67,9 +67,9 @@ public class SkipBMH extends Skip
 
     sm1 = src.length() - 1;
     x = src.charAt(sm1);
-    uc = CaseMgr.toUpperCase(x);
-    lc = CaseMgr.toLowerCase(x);
-    tc = CaseMgr.toTitleCase(x);
+    uc = CaseMgr.toUpperCaseC(x);
+    lc = CaseMgr.toLowerCaseC(x);
+    tc = CaseMgr.toTitleCaseC(x);
 
     // We don't really want 65536 long arrays in skip[],
     // so we mask of the higher bits. This can be combined
@@ -80,9 +80,9 @@ public class SkipBMH extends Skip
       char x_ = src.charAt(k);
       if (ign)
       {
-        char uc_ = CaseMgr.toUpperCase(x_);
-        char lc_ = CaseMgr.toLowerCase(x_);
-        char tc_ = CaseMgr.toTitleCase(x_);
+        char uc_ = CaseMgr.toUpperCaseC(x_);
+        char lc_ = CaseMgr.toLowerCaseC(x_);
+        char tc_ = CaseMgr.toTitleCaseC(x_);
         skip[uc_ & (MAX_CHAR - 1)] = (char) (src.length() - k - 1);
         skip[lc_ & (MAX_CHAR - 1)] = (char) (src.length() - k - 1);
         skip[tc_ & (MAX_CHAR - 1)] = (char) (src.length() - k - 1);
@@ -139,7 +139,7 @@ public class SkipBMH extends Skip
         // table look-up is expensive, avoid it if possible
         if (anyc(s.charAt(k)))
         {
-          if (CaseMgr.regionMatches(src, ign, 0, s, k - sm1, sm1))
+          if (CaseMgr.regionMatches2(src, ign, 0, s, k - sm1, sm1))
           {
             return k - sm1 - offset;
           }
@@ -151,7 +151,7 @@ public class SkipBMH extends Skip
         // table look-up is expensive, avoid it if possible
         if (anyc(s.charAt(k)))
         {
-          if (CaseMgr.regionMatches(src, ign, 0, s, k - sm1, sm1))
+          if (CaseMgr.regionMatches2(src, ign, 0, s, k - sm1, sm1))
           {
             return k - sm1 - offset;
           }
@@ -171,7 +171,7 @@ public class SkipBMH extends Skip
         if (x == s.charAt(k))
         {
           // if(src.regionMatches(0,s,k-sm1,sm1))
-          if (CaseMgr.regionMatches(src, false, 0, s, k - sm1, sm1))
+          if (CaseMgr.regionMatches2(src, false, 0, s, k - sm1, sm1))
           {
             return k - sm1 - offset;
           }
@@ -184,7 +184,7 @@ public class SkipBMH extends Skip
         if (x == s.charAt(k))
         {
           // if(src.regionMatches(0,s,k-sm1,sm1))
-          if (CaseMgr.regionMatches(src, false, 0, s, k - sm1, sm1))
+          if (CaseMgr.regionMatches2(src, false, 0, s, k - sm1, sm1))
           {
             return k - sm1 - offset;
           }
index d125758..b4bada8 100755 (executable)
@@ -32,7 +32,7 @@ public class StringBufferLike implements BasicStringBufferLike
     return sbl.toString();
   }
 
-  public void append(char c)
+  public void appendC(char c)
   {
 
     switch (mode)
@@ -41,13 +41,13 @@ public class StringBufferLike implements BasicStringBufferLike
       mode = altMode;
       altMode = ' ';
     case 'U':
-      sbl.append(CaseMgr.toUpperCase(c));
+      sbl.appendC(CaseMgr.toUpperCaseC(c));
       break;
     case 'l':
       mode = altMode;
       altMode = ' ';
     case 'L':
-      sbl.append(CaseMgr.toLowerCase(c));
+      sbl.appendC(CaseMgr.toLowerCaseC(c));
       break;
     case 'Q':
       if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
@@ -57,10 +57,10 @@ public class StringBufferLike implements BasicStringBufferLike
       }
       else
       {
-        sbl.append('\\');
+        sbl.appendC('\\');
       }
     default:
-      sbl.append(c);
+      sbl.appendC(c);
       break;
     }
   }
@@ -69,7 +69,7 @@ public class StringBufferLike implements BasicStringBufferLike
   {
     for (int i = 0; i < s.length(); i++)
     {
-      append(s.charAt(i));
+      appendC(s.charAt(i));
     }
   }
 
index 84a3a46..b041aac 100755 (executable)
@@ -7,9 +7,7 @@
 //
 package com.stevesoft.pat;
 
-import jalview.util.MessageManager;
-
-import com.stevesoft.pat.wrap.*;
+import com.stevesoft.pat.wrap.StringWrap;
 
 /**
  * Replacement rule used by the Transformer.
@@ -64,7 +62,7 @@ public class Transformer
 {
   TransPat tp;
 
-  Regex rp = new Regex();
+  Regex rp;
 
   boolean auto_optimize;
 
@@ -81,6 +79,7 @@ public class Transformer
   /** Instantiate a new Transformer object. */
   public Transformer(boolean auto)
   {
+       rp = new Regex(null, "");
     auto_optimize = auto;
     tp = new TransPat();
     rp.setReplaceRule(new TransRepRule(this));
diff --git a/src/com/stevesoft/pat/Util.java b/src/com/stevesoft/pat/Util.java
new file mode 100644 (file)
index 0000000..88b01eb
--- /dev/null
@@ -0,0 +1,13 @@
+//
+// This software is now distributed according to
+// the Lesser Gnu Public License.  Please see
+// http://www.gnu.org/copyleft/lesser.txt for
+// the details.
+//    -- Happy Computing!
+//
+package com.stevesoft.pat;
+
+
+public abstract class Util
+{
+}
index dbedca5..de45f6c 100755 (executable)
@@ -31,7 +31,7 @@ public class Validator
    * 
    * By default, this method just returns end and thus does nothing.
    * 
-   * @see com.stevesoft.pat.Regex#define(java.lang.String,java.lang.String,com.stevesoft.pat.Validator)
+   * @see com.stevesoft.pat.Regex#defineV(java.lang.String,java.lang.String,com.stevesoft.pat.Validator)
    */
   public int validate(StringLike src, int start, int end)
   {
index ebbe991..d2ac38d 100755 (executable)
@@ -20,9 +20,9 @@ class oneChar extends Pattern
   {
     c = ci;
     char cu, cl, ct;
-    cu = CaseMgr.toUpperCase(c);
-    cl = CaseMgr.toLowerCase(c);
-    ct = CaseMgr.toTitleCase(c);
+    cu = CaseMgr.toUpperCaseC(c);
+    cl = CaseMgr.toLowerCaseC(c);
+    ct = CaseMgr.toTitleCaseC(c);
     if (c == cu)
     {
       altc = cl;
index 0d1f14e..db842c3 100755 (executable)
@@ -45,10 +45,10 @@ class parsePerl
 
   final public static String codify(String s, boolean keepbs)
   {
-    return codify(s, 0, s.length(), keepbs);
+    return codifyRange(s, 0, s.length(), keepbs);
   }
 
-  final public static String codify(String s, int i0, int iN, boolean keepbs)
+  final public static String codifyRange(String s, int i0, int iN, boolean keepbs)
   {
     StringBuffer sb = new StringBuffer();
     boolean ucmode = false, lcmode = false, litmode = false;
@@ -133,12 +133,12 @@ class parsePerl
 
   final static char uc(char c)
   {
-    return CaseMgr.toUpperCase(c);
+    return CaseMgr.toUpperCaseC(c);
   }
 
   final static char lc(char c)
   {
-    return CaseMgr.toLowerCase(c);
+    return CaseMgr.toLowerCaseC(c);
   }
 
   final static boolean needbs(char c)
@@ -303,7 +303,7 @@ class parsePerl
         return null;
       }
     }
-    Regex r = new Regex();
+    Regex r = new Regex(null, "");
     try
     {
       String pat = s1.toString(), reprul = s2.toString();
index c014a57..f82ccd2 100755 (executable)
@@ -17,7 +17,7 @@ public class CharArrayBufferWrap implements BasicStringBufferLike
 {
   StringBuffer sb = new StringBuffer();
 
-  public void append(char c)
+  public void appendC(char c)
   {
     sb.append(c);
   }
index f5b61ab..2ab5a95 100755 (executable)
 //
 package com.stevesoft.pat.wrap;
 
-import jalview.util.MessageManager;
-
-import java.io.*;
-
-import com.stevesoft.pat.*;
 
 /**
  * Provides a wrapper for a RandomAccessFile so that it can be searched by
  * Regex.
  */
-public class RandomAccessFileWrap implements StringLike
+public class RandomAccessFileWrap //implements StringLike
 {
-
-  long offset = 0;
-
-  public void setOffset(long o)
-  {
-    offset = o;
-    i0 = iend = 0;
-  }
-
-  public long getOffset()
-  {
-    return offset;
-  }
-
-  RandomAccessFile raf;
-
-  int i0 = 0, iend = 0;
-
-  byte[] buf = new byte[1024];
-
-  public int getBufferSize()
-  {
-    return buf.length;
-  }
-
-  public void setBufferSize(int bs)
-  {
-    buf = new byte[bs];
-    i0 = iend = 0;
-  }
-
-  public RandomAccessFileWrap(String file) throws IOException
-  {
-    this.raf = new RandomAccessFile(file, "r");
-  }
-
-  public RandomAccessFileWrap(RandomAccessFile raf)
-  {
-    this.raf = raf;
-  }
-
-  public char charAt(int i)
-  {
-    if (i >= i0 && i < iend)
-    {
-      return (char) buf[i - i0];
-    }
-
-    try
-    {
-      i0 = i - 5;
-      // if(i0+offset<0) i0=(int)(-offset);
-      if (i0 < 0)
-      {
-        i0 = 0;
-      }
-      raf.seek(i0 + offset);
-      iend = i0 + raf.read(buf, 0, buf.length);
-
-      if (i >= i0 && i < iend)
-      {
-        return (char) buf[i - i0];
-      }
-    } catch (Throwable t)
-    {
-    }
-
-    throw new ArrayIndexOutOfBoundsException(MessageManager.formatMessage("exception.out_of_bounds_for_file", new String[]{
-               Integer.valueOf(i).toString(),
-               Integer.valueOf(i0).toString(),
-               Integer.valueOf(iend).toString()
-    }));
-  }
-
-  public String toString()
-  {
-    throw new Error(MessageManager.getString("error.not_implemented"));
-  }
-
-  public int length()
-  {
-    try
-    {
-      long len = raf.length() - offset;
-      if (len > Integer.MAX_VALUE)
-      {
-        return Integer.MAX_VALUE;
-      }
-      return (int) len;
-    } catch (IOException ioe)
-    {
-      return 0;
-    }
-  }
-
-  public String substring(int i1, int i2)
-  {
-    StringBuffer sb = new StringBuffer();
-    for (int i = i1; i < i2; i++)
-    {
-      sb.append(charAt(i));
-    }
-    return sb.toString();
-  }
-
-  public Object unwrap()
-  {
-    return raf;
-  }
-
-  public static void main(String[] files) throws IOException
-  {
-    for (int i = 0; i < files.length; i++)
-    {
-      RandomAccessFileWrap fw = new RandomAccessFileWrap(
-              new RandomAccessFile(files[i], "r"));
-      Regex r = new Regex("toString\\(\\) *(?@{})");
-      r.setGFlag(true);
-      r.optimize();
-      System.out.print(files[i] + " ");
-      int j = 0;
-      do
-      {
-        if (r.searchFrom(fw, j))
-        {
-          System.out.println("Matched at index: " + r.matchedFrom());
-          j = r.matchedTo();
-        }
-        else
-        {
-          System.out.println("not found");
-        }
-        System.out.println(r.stringMatched());
-      } while (r.didMatch());
-    }
-  }
-
-  public BasicStringBufferLike newStringBufferLike()
-  {
-    return new StringBufferWrap();
-  }
-
-  public int indexOf(char c)
-  {
-    for (int i = 0; i < length(); i++)
-    {
-      if (charAt(i) == c)
-      {
-        return i;
-      }
-    }
-    return -1;
-  }
+//
+//  long offset = 0;
+//
+//  public void setOffset(long o)
+//  {
+//    offset = o;
+//    i0 = iend = 0;
+//  }
+//
+//  public long getOffset()
+//  {
+//    return offset;
+//  }
+//
+//  RandomAccessFile raf;
+//
+//  int i0 = 0, iend = 0;
+//
+//  byte[] buf = new byte[1024];
+//
+//  public int getBufferSize()
+//  {
+//    return buf.length;
+//  }
+//
+//  public void setBufferSize(int bs)
+//  {
+//    buf = new byte[bs];
+//    i0 = iend = 0;
+//  }
+//
+//  public RandomAccessFileWrap(String file) throws IOException
+//  {
+//    this.raf = new RandomAccessFile(file, "r");
+//  }
+//
+//  public RandomAccessFileWrap(RandomAccessFile raf)
+//  {
+//    this.raf = raf;
+//  }
+//
+//  public char charAt(int i)
+//  {
+//    if (i >= i0 && i < iend)
+//    {
+//      return (char) buf[i - i0];
+//    }
+//
+//    try
+//    {
+//      i0 = i - 5;
+//      // if(i0+offset<0) i0=(int)(-offset);
+//      if (i0 < 0)
+//      {
+//        i0 = 0;
+//      }
+//      raf.seek(i0 + offset);
+//      iend = i0 + raf.read(buf, 0, buf.length);
+//
+//      if (i >= i0 && i < iend)
+//      {
+//        return (char) buf[i - i0];
+//      }
+//    } catch (Throwable t)
+//    {
+//    }
+//
+//    throw new ArrayIndexOutOfBoundsException(MessageManager.formatMessage("exception.out_of_bounds_for_file", new String[]{
+//             Integer.valueOf(i).toString(),
+//             Integer.valueOf(i0).toString(),
+//             Integer.valueOf(iend).toString()
+//    }));
+//  }
+//
+//  public String toString()
+//  {
+//    throw new Error(MessageManager.getString("error.not_implemented"));
+//  }
+//
+//  public int length()
+//  {
+//    try
+//    {
+//      long len = raf.length() - offset;
+//      if (len > Integer.MAX_VALUE)
+//      {
+//        return Integer.MAX_VALUE;
+//      }
+//      return (int) len;
+//    } catch (IOException ioe)
+//    {
+//      return 0;
+//    }
+//  }
+//
+//  public String substring(int i1, int i2)
+//  {
+//    StringBuffer sb = new StringBuffer();
+//    for (int i = i1; i < i2; i++)
+//    {
+//      sb.append(charAt(i));
+//    }
+//    return sb.toString();
+//  }
+//
+//  public Object unwrap()
+//  {
+//    return raf;
+//  }
+//
+//  public static void main(String[] files) throws IOException
+//  {
+//    for (int i = 0; i < files.length; i++)
+//    {
+//      RandomAccessFileWrap fw = new RandomAccessFileWrap(
+//              new RandomAccessFile(files[i], "r"));
+//      Regex r = new Regex("toString\\(\\) *(?@{})");
+//      r.setGFlag(true);
+//      r.optimize();
+//      System.out.print(files[i] + " ");
+//      int j = 0;
+//      do
+//      {
+//        if (r.searchFromLike(fw, j))
+//        {
+//          System.out.println("Matched at index: " + r.matchedFrom());
+//          j = r.matchedTo();
+//        }
+//        else
+//        {
+//          System.out.println("not found");
+//        }
+//        System.out.println(r.stringMatched());
+//      } while (r.didMatch());
+//    }
+//  }
+//
+//  public BasicStringBufferLike newStringBufferLike()
+//  {
+//    return new StringBufferWrap();
+//  }
+//
+//  public int indexOf(char c)
+//  {
+//    for (int i = 0; i < length(); i++)
+//    {
+//      if (charAt(i) == c)
+//      {
+//        return i;
+//      }
+//    }
+//    return -1;
+//  }
 }
index d522461..53c27b2 100755 (executable)
@@ -17,7 +17,7 @@ public class StringBufferWrap implements BasicStringBufferLike
 {
   StringBuffer sb = new StringBuffer();
 
-  public void append(char c)
+  public void appendC(char c)
   {
     sb.append(c);
   }
index e72b5fa..a354639 100755 (executable)
@@ -28,7 +28,7 @@ public class WriterWrap implements BasicStringBufferLike
     this.w = w;
   }
 
-  public void append(char c)
+  public void appendC(char c)
   {
     try
     {
diff --git a/src/fr/orsay/lri/varna/models/rna/RNA.java b/src/fr/orsay/lri/varna/models/rna/RNA.java
new file mode 100644 (file)
index 0000000..ff63f83
--- /dev/null
@@ -0,0 +1,15 @@
+package fr.orsay.lri.varna.models.rna;
+
+public class RNA {
+
+       public int getSize() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       public String getStructDBN(boolean b) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+}
index 6dd3a97..278caa7 100755 (executable)
@@ -344,7 +344,7 @@ public class AAFrequency
             // { (char) c };
             vl[c] = profile[0][c];
           }
-          QuickSort.sortFloat(vl, ca);
+          QuickSort.sortFloatChar(vl, ca);
           for (int p = 0, c = ca.length - 1; profile[0][ca[c]] > 0; c--)
           {
             final char residue = ca[c];
@@ -425,7 +425,7 @@ public class AAFrequency
       ca[c] = (char) c;
       vl[c] = profile[0][c];
     }
-    QuickSort.sortFloat(vl, ca);
+    QuickSort.sortFloatChar(vl, ca);
     int nextArrayPos = 2;
     int totalPercentage = 0;
     int distinctValuesCount = 0;
@@ -480,7 +480,7 @@ public class AAFrequency
     {
       codons[i] = (char) i;
     }
-    QuickSort.sortInt(sortedCounts, codons);
+    QuickSort.sortIntChar(sortedCounts, codons);
     int totalPercentage = 0;
     int distinctValuesCount = 0;
     int j = 3;
@@ -615,7 +615,7 @@ public class AAFrequency
       int[] sortedCodonCounts = new int[codonCounts.length - 2];
       System.arraycopy(codonCounts, 2, sortedCodonCounts, 0,
               codonCounts.length - 2);
-      QuickSort.sortInt(sortedCodonCounts, codons);
+      QuickSort.sortIntChar(sortedCodonCounts, codons);
 
       int modalCodonEncoded = codons[codons.length - 1];
       int modalCodonCount = sortedCodonCounts[codons.length - 1];
index e02aa9e..381d24a 100644 (file)
@@ -8,10 +8,13 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javajs.J2SIgnoreImport;
+
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 
+@J2SIgnoreImport({jalview.renderer.AnnotationRenderer.class})
 public class AlignmentAnnotationUtils
 {
 
index e960e63..a41a1cc 100755 (executable)
@@ -129,7 +129,7 @@ public class AlignmentSorter
       seqs[i] = align.getSequenceAt(i);
     }
 
-    QuickSort.sortFloat(scores, seqs);
+    QuickSort.sortFloatObject(scores, seqs);
 
     setReverseOrder(align, seqs);
   }
@@ -268,7 +268,7 @@ public class AlignmentSorter
       length[i] = (seqs[i].getEnd() - seqs[i].getStart());
     }
 
-    QuickSort.sortFloat(length, seqs);
+    QuickSort.sortFloatObject(length, seqs);
 
     if (sortLengthAscending)
     {
@@ -607,7 +607,7 @@ public class AlignmentSorter
               .floatValue();
     }
 
-    QuickSort.sortFloat(ids, alignment);
+    QuickSort.sortFloatObject(ids, alignment);
   }
 
   /**
index 3c72598..3562dee 100644 (file)
@@ -24,11 +24,13 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SearchResults;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 import jalview.util.Comparison;
 
 import java.util.Vector;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class Finder
 {
@@ -49,7 +51,7 @@ public class Finder
 
   boolean findAll = false;
 
-  Regex regex = null;
+  RegExpInterface regex = null;
 
   /**
    * hold's last-searched position between calles to find(false)
@@ -86,7 +88,7 @@ public class Finder
     {
       searchString = searchString.toUpperCase();
     }
-    regex = new Regex(searchString);
+    regex = RegExp.newRegex(searchString);
     regex.setIgnoreCase(!caseSensitive);
     searchResults = new SearchResults();
     idMatch = new Vector();
@@ -333,7 +335,7 @@ public class Finder
   /**
    * @return the regex
    */
-  public Regex getRegex()
+  public RegExpInterface getRegex()
   {
     return regex;
   }
index 3674be1..16395c2 100644 (file)
@@ -38,7 +38,7 @@ import java.util.List;
 import java.util.Vector;
 
 /**
- * DOCUMENT ME!
+ * NeighborJoining tree
  * 
  * @author $author$
  * @version $Revision$
index 3347800..5fe7adb 100644 (file)
  */
 package jalview.analysis;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 
 public class ParseProperties
 {
@@ -80,7 +82,7 @@ public class ParseProperties
    *          description for each numeric field in regex match
    * @param regex
    *          Regular Expression string for passing to
-   *          <code>new com.stevesoft.patt.Regex(regex)</code>
+   *          <code>new jalview.jsdevt.Regex(regex)</code>
    * @param repeat
    *          true means the regex will be applied multiple times along the
    *          description string of each sequence
@@ -91,7 +93,7 @@ public class ParseProperties
           boolean repeat)
   {
     int count = 0;
-    Regex pattern = new Regex(regex);
+    RegExpInterface pattern = RegExp.newRegex(regex);
     if (pattern.numSubs() > ScoreNames.length)
     {
       // Check that we have enough labels and descriptions for any parsed
@@ -131,7 +133,7 @@ public class ParseProperties
         pos = pattern.matchedTo();
         for (int cols = 0; cols < pattern.numSubs(); cols++)
         {
-          String sstring = pattern.stringMatched(cols + 1);
+          String sstring = pattern.stringMatchedI(cols + 1);
           double score = Double.NaN;
           try
           {
index 1b89cd1..6b93dcb 100644 (file)
@@ -58,17 +58,16 @@ public class Rna
   private static HashSet<Character> closingParsSet = new HashSet<Character>(
           Arrays.asList(closingPars));
 
-  private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>()
-  // Initializing final data structure
-  {
-    private static final long serialVersionUID = 1L;
-    {
+  private static Hashtable<Character, Character> closingToOpening = new Hashtable<Character, Character>();
+  
+  
+  static {
+    // Initializing final data structure
       for (int i = 0; i < openingPars.length; i++)
       {
         // System.out.println(closingPars[i] + "->" + openingPars[i]);
-        put(closingPars[i], openingPars[i]);
+        closingToOpening.put(closingPars[i], openingPars[i]);
       }
-    }
   };
 
   private static boolean isOpeningParenthesis(char c)
index d7d07bc..d77c5ac 100644 (file)
@@ -421,7 +421,7 @@ public class StructureFrequency
          * ((c == 0) ? "" : "; ") + alphabet[c] + " " + ((int) tval) + "%"; } }
          * else {
          */
-        int[][] ca = new int[625][];
+        int[][] ca = javajs.util.AU.newInt2(625);// BH new int[625][];
         float[] vl = new float[625];
         int x = 0;
         for (int c = 65; c < 90; c++)
@@ -434,7 +434,7 @@ public class StructureFrequency
             x++;
           }
         }
-        QuickSort.sortFloat(vl, ca);
+        QuickSort.sortFloatObject(vl, ca);
         int p = 0;
 
         /*
@@ -487,7 +487,7 @@ public class StructureFrequency
 
     // TODO fix the object length, also do it in completeConsensus
     // Object[] ca = new Object[625];
-    int[][] ca = new int[625][];
+    int[][] ca = javajs.util.AU.newInt2(625);// BH new int[625][];
     float[] vl = new float[625];
     int x = 0;
     for (int c = 65; c < 90; c++)
@@ -500,7 +500,7 @@ public class StructureFrequency
         x++;
       }
     }
-    QuickSort.sortFloat(vl, ca);
+    QuickSort.sortFloatObject(vl, ca);
 
     int valuesCount = 0;
     rtnval[1] = 0;
@@ -526,6 +526,11 @@ public class StructureFrequency
     return result;
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String args[])
   {
     // Short test to see if checkBpType works
index 3404afc..2c171c5 100644 (file)
@@ -1,6 +1,5 @@
 package jalview.api.analysis;
 
-import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 
 public interface ViewBasedAnalysisI
index 1d59202..afa4c71 100644 (file)
@@ -53,10 +53,10 @@ import jalview.util.DBRefUtils;
 import jalview.util.MessageManager;
 import jalview.util.UrlLink;
 
-import java.awt.CheckboxMenuItem;
-import java.awt.Frame;
-import java.awt.Menu;
-import java.awt.MenuItem;
+import awt2swing.CheckboxMenuItem;
+import awt2swing.Frame;
+import awt2swing.Menu;
+import awt2swing.MenuItem;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -69,7 +69,7 @@ import java.util.Map;
 import java.util.TreeMap;
 import java.util.Vector;
 
-public class APopupMenu extends java.awt.PopupMenu implements
+public class APopupMenu extends awt2swing.PopupMenu implements
         ActionListener, ItemListener
 {
   private static final String ALL_ANNOTATIONS = "All";
@@ -420,7 +420,7 @@ AppletFormatAdapter.WRITEABLE_FORMATS[i]);
     }
   }
 
-  /**
+       /**
    * Build menus for annotation types that may be shown or hidden, and for
    * 'reference annotations' that may be added to the alignment.
    */
@@ -906,11 +906,11 @@ AppletFormatAdapter.WRITEABLE_FORMATS[i]);
         new AppletJmol(entry, new SequenceI[]
         { seq }, null, ap, AppletFormatAdapter.URL);
       }
-      else
-      {
-        new MCview.AppletPDBViewer(entry, new SequenceI[]
-        { seq }, null, ap, AppletFormatAdapter.URL);
-      }
+//      else
+//      {
+//        new MCview.AppletPDBViewer(entry, new SequenceI[]
+//        { seq }, null, ap, AppletFormatAdapter.URL);
+//      }
 
     }
     else
index 1fd4231..fd42e9d 100644 (file)
@@ -52,7 +52,9 @@ import jalview.io.AnnotationFile;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FeaturesFile;
 import jalview.io.NewickFile;
+import jalview.io.AlignFile;
 import jalview.io.TCoffeeScoreFile;
+import jalview.jsdev.GenericFileAdapter;
 import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.BuriedColourScheme;
 import jalview.schemes.ClustalxColourScheme;
@@ -77,17 +79,10 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.BorderLayout;
-import java.awt.Canvas;
-import java.awt.CheckboxMenuItem;
 import java.awt.Color;
 import java.awt.Font;
 import java.awt.FontMetrics;
-import java.awt.Frame;
 import java.awt.Graphics;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
@@ -110,7 +105,15 @@ import java.util.Map;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
-import org.jmol.viewer.Viewer;
+import awt2swing.Canvas;
+import awt2swing.CheckboxMenuItem;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Menu;
+import awt2swing.MenuBar;
+import awt2swing.MenuItem;
+
+//import org.jmol.viewer.Viewer;
 
 public class AlignFrame extends EmbmenuFrame implements ActionListener,
         ItemListener, KeyListener, AlignViewControllerGuiI
@@ -2926,7 +2929,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
       }
 
       @Override
-      public void paint(Graphics g)
+      public void paintComponent(Graphics g)
       {
         g.setColor(Color.white);
         g.fillRect(0, 0, getSize().width, getSize().height);
@@ -2934,7 +2937,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
         FontMetrics fm = g.getFontMetrics();
         int fh = fm.getHeight();
         int y = 5, x = 7;
-        g.setColor(Color.black);
+        g.setColor(Color.black); 
         // TODO: update this text for each release or centrally store it for
         // lite and application
         g.setFont(new Font("Helvetica", Font.BOLD, 14));
@@ -3731,7 +3734,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     this.add(statusBar, BorderLayout.SOUTH);
   }
 
-  public void setStatus(String string)
+       public void setStatus(String string)
   {
     statusBar.setText(string);
   };
@@ -3860,77 +3863,77 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     theApplet.validate();
   }
 
-  /**
-   * create a new binding between structures in an existing jmol viewer instance
-   * and an alignpanel with sequences that have existing PDBFile entries. Note,
-   * this does not open a new Jmol window, or modify the display of the
-   * structures in the original jmol window. Note This method doesn't work
-   * without an additional javascript library to exchange messages between the
-   * distinct applets. See http://issues.jalview.org/browse/JAL-621
-   * 
-   * @param viewer
-   *          JmolViewer instance
-   * @param sequenceIds
-   *          - sequence Ids to search for associations
-   */
-  public SequenceStructureBinding addStructureViewInstance(
-          Object jmolviewer, String[] sequenceIds)
-  {
-    Viewer viewer = null;
-    try
-    {
-      viewer = (Viewer) jmolviewer;
-    } catch (ClassCastException ex)
-    {
-      System.err.println("Unsupported viewer object :"
-              + jmolviewer.getClass());
-    }
-    if (viewer == null)
-    {
-      System.err.println("Can't use this object as a structure viewer:"
-              + jmolviewer.getClass());
-      return null;
-    }
-    SequenceI[] seqs = null;
-    if (sequenceIds == null || sequenceIds.length == 0)
-    {
-      seqs = viewport.getAlignment().getSequencesArray();
-    }
-    else
-    {
-      Vector sqi = new Vector();
-      AlignmentI al = viewport.getAlignment();
-      for (int sid = 0; sid < sequenceIds.length; sid++)
-      {
-        SequenceI sq = al.findName(sequenceIds[sid]);
-        if (sq != null)
-        {
-          sqi.addElement(sq);
-        }
-      }
-      if (sqi.size() > 0)
-      {
-        seqs = new SequenceI[sqi.size()];
-        for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
-        {
-          seqs[sid] = (SequenceI) sqi.elementAt(sid);
-        }
-      }
-      else
-      {
-        return null;
-      }
-    }
-    AAStructureBindingModel jmv = null;
-    // TODO: search for a jmv that involves viewer
-    if (jmv == null)
-    { // create a new viewer/jalview binding.
-      jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][]
-      { seqs });
-    }
-    return jmv;
-
-  }
+       /**
+        * create a new binding between structures in an existing jmol viewer instance
+        * and an alignpanel with sequences that have existing PDBFile entries. Note,
+        * this does not open a new Jmol window, or modify the display of the
+        * structures in the original jmol window. Note This method doesn't work
+        * without an additional javascript library to exchange messages between the
+        * distinct applets. See http://issues.jalview.org/browse/JAL-621
+        * 
+        * @param viewer
+        *          JmolViewer instance
+        * @param sequenceIds
+        *          - sequence Ids to search for associations
+        */
+       public SequenceStructureBinding addStructureViewInstance(Object jmolviewer,
+                       String[] sequenceIds) {
+               return null;
+               // Viewer viewer = null;
+               // try
+               // {
+               // viewer = (Viewer) jmolviewer;
+               // } catch (ClassCastException ex)
+               // {
+               // System.err.println("Unsupported viewer object :"
+               // + jmolviewer.getClass());
+               // }
+               // if (viewer == null)
+               // {
+               // System.err.println("Can't use this object as a structure viewer:"
+               // + jmolviewer.getClass());
+               // return null;
+               // }
+               // SequenceI[] seqs = null;
+               // if (sequenceIds == null || sequenceIds.length == 0)
+               // {
+               // seqs = viewport.getAlignment().getSequencesArray();
+               // }
+               // else
+               // {
+               // Vector sqi = new Vector();
+               // AlignmentI al = viewport.getAlignment();
+               // for (int sid = 0; sid < sequenceIds.length; sid++)
+               // {
+               // SequenceI sq = al.findName(sequenceIds[sid]);
+               // if (sq != null)
+               // {
+               // sqi.addElement(sq);
+               // }
+               // }
+               // if (sqi.size() > 0)
+               // {
+               // seqs = new SequenceI[sqi.size()];
+               // for (int sid = 0, sSize = sqi.size(); sid < sSize; sid++)
+               // {
+               // seqs[sid] = (SequenceI) sqi.elementAt(sid);
+               // }
+               // }
+               // else
+               // {
+               // return null;
+               // }
+               // }
+               // AAStructureBindingModel jmv = null;
+               // // TODO: search for a jmv that involves viewer
+               // if (jmv == null)
+               // { // create a new viewer/jalview binding.
+               // jmv = new ExtJmol(viewer, alignPanel, new SequenceI[][]
+               // { seqs });
+               // }
+               // return jmv;
+               //
+       }
 
   /**
    * bind a pdb file to a sequence in the current view
@@ -4028,78 +4031,67 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
 
   }
 
-  public void newStructureView(JalviewLite applet, PDBEntry pdb,
-          SequenceI[] seqs, String[] chains, String protocol)
-  {
-    // Scrub any null sequences from the array
-    Object[] sqch = cleanSeqChainArrays(seqs, chains);
-    seqs = (SequenceI[]) sqch[0];
-    chains = (String[]) sqch[1];
-    if (seqs == null || seqs.length == 0)
-    {
-      System.err
-              .println("JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
-    }
-    if (protocol == null || protocol.trim().length() == 0
-            || protocol.equals("null"))
-    {
-      protocol = (String) pdb.getProperty().get("protocol");
-      if (protocol == null)
-      {
-        System.err.println("Couldn't work out protocol to open structure: "
-                + pdb.getId());
-        return;
-      }
-    }
-    if (applet.useXtrnalSviewer)
-    {
-      // register the association(s) and quit, don't create any windows.
-      if (StructureSelectionManager.getStructureSelectionManager(applet)
-              .setMapping(seqs, chains, pdb.getFile(), protocol) == null)
-      {
-        System.err.println("Failed to map " + pdb.getFile() + " ("
-                + protocol + ") to any sequences");
-      }
-      return;
-    }
-    if (applet.isAlignPdbStructures() && applet.jmolAvailable)
-    {
-      // can only do alignments with Jmol
-      // find the last jmol window assigned to this alignment
-      AppletJmol ajm = null, tajm;
-      Vector jmols = applet
-.getAppletWindow(AppletJmol.class);
-      for (int i = 0, iSize = jmols.size(); i < iSize; i++)
-      {
-        tajm = (AppletJmol) jmols.elementAt(i);
-        if (tajm.ap.alignFrame == this)
-        {
-          ajm = tajm;
-          break;
-        }
-      }
-      if (ajm != null)
-      {
-        System.err
-                .println("Incremental adding and aligning structure to existing Jmol view not yet implemented.");
-        // try and add the pdb structure
-        // ajm.addS
-        ajm = null;
-      }
-    }
-    // otherwise, create a new window
-    if (applet.jmolAvailable)
-    {
-      new AppletJmol(pdb, seqs, chains, alignPanel, protocol);
-      applet.lastFrameX += 40;
-      applet.lastFrameY += 40;
-    }
-    else
-    {
-      new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
-    }
-
-  }
+       public void newStructureView(JalviewLite applet, PDBEntry pdb,
+                       SequenceI[] seqs, String[] chains, String protocol) {
+               // Scrub any null sequences from the array
+               Object[] sqch = cleanSeqChainArrays(seqs, chains);
+               seqs = (SequenceI[]) sqch[0];
+               chains = (String[]) sqch[1];
+               if (seqs == null || seqs.length == 0) {
+                       System.err
+                                       .println("JalviewLite.AlignFrame:newStructureView: No sequence to bind structure to.");
+               }
+               if (protocol == null || protocol.trim().length() == 0
+                               || protocol.equals("null")) {
+                       protocol = (String) pdb.getProperty().get("protocol");
+                       if (protocol == null) {
+                               System.err.println("Couldn't work out protocol to open structure: "
+                                               + pdb.getId());
+                               return;
+                       }
+               }
+               if (applet.useXtrnalSviewer) {
+                       // register the association(s) and quit, don't create any windows.
+                       if (StructureSelectionManager.getStructureSelectionManager(applet)
+                                       .setMapping(seqs, chains, pdb.getFile(), protocol) == null) {
+                               System.err.println("Failed to map " + pdb.getFile() + " (" + protocol
+                                               + ") to any sequences");
+                       }
+                       return;
+               }
+               if (applet.isAlignPdbStructures() && applet.jmolAvailable) {
+                       // can only do alignments with Jmol
+                       // find the last jmol window assigned to this alignment
+                       AppletJmol ajm = null, tajm;
+                       Vector jmols = applet.getAppletWindow(AppletJmol.class);
+                       for (int i = 0, iSize = jmols.size(); i < iSize; i++) {
+                               tajm = (AppletJmol) jmols.elementAt(i);
+                               if (tajm.ap.alignFrame == this) {
+                                       ajm = tajm;
+                                       break;
+                               }
+                       }
+                       if (ajm != null) {
+                               System.err
+                                               .println("Incremental adding and aligning structure to existing Jmol view not yet implemented.");
+                               // try and add the pdb structure
+                               // ajm.addS
+                               ajm = null;
+                       }
+               }
+               // otherwise, create a new window
+               // if (applet.jmolAvailable)
+               // {
+               new AppletJmol(pdb, seqs, chains, alignPanel, protocol);
+               applet.lastFrameX += 40;
+               applet.lastFrameY += 40;
+               // }
+               // else
+               // {
+               // new MCview.AppletPDBViewer(pdb, seqs, chains, alignPanel, protocol);
+               // }
+
+       }
 
   public void alignedStructureView(JalviewLite applet, PDBEntry[] pdb,
           SequenceI[][] seqs, String[][] chains, String[] protocols)
@@ -4148,22 +4140,22 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
   /**
    * Load the (T-Coffee) score file from the specified url
    * 
-   * @param source
+   * @param inFile
    *          File/URL/T-COFFEE score file contents
    * @throws IOException
    * @return true if alignment was annotated with data from source
    */
-  public boolean loadScoreFile(String source) throws IOException
+  public boolean loadScoreFile(String inFile) throws IOException
   {
 
-    TCoffeeScoreFile file = new TCoffeeScoreFile(source,
-            AppletFormatAdapter.checkProtocol(source));
+    TCoffeeScoreFile file = (TCoffeeScoreFile) GenericFileAdapter.getFile("TCoffeeScoreFile", inFile, 
+            AppletFormatAdapter.checkProtocol(inFile));        
     if (!file.isValid())
     {
       // TODO: raise dialog for gui
       System.err.println("Problems parsing T-Coffee scores: "
               + file.getWarningMessage());
-      System.err.println("Origin was:\n" + source);
+      System.err.println("Origin was:\n" + inFile);
       return false;
     }
 
index 68d6c90..65d263a 100644 (file)
@@ -257,7 +257,7 @@ public class AlignViewport extends AlignmentViewport implements
     return sq;
   }
 
-  java.awt.Frame nullFrame;
+  awt2swing.Frame nullFrame;
 
   protected FeatureSettings featureSettings = null;
 
@@ -268,8 +268,9 @@ public class AlignViewport extends AlignmentViewport implements
     font = f;
     if (nullFrame == null)
     {
-      nullFrame = new java.awt.Frame();
+      nullFrame = new awt2swing.Frame();
       nullFrame.addNotify();
+      nullFrame.setFont(font);
     }
 
     java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font);
index d82b3c3..c7bd08a 100644 (file)
@@ -33,10 +33,10 @@ import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FontMetrics;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
-import java.awt.Panel;
-import java.awt.Scrollbar;
+import awt2swing.Panel;
+import awt2swing.Scrollbar;
 import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.ComponentAdapter;
@@ -240,10 +240,9 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     {
       av.nullFrame = new Frame();
       av.nullFrame.addNotify();
+      av.nullFrame.setFont(av.font);
     }
-
     Graphics g = av.nullFrame.getGraphics();
-
     FontMetrics fm = g.getFontMetrics(av.font);
     AlignmentI al = av.getAlignment();
 
@@ -768,6 +767,8 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
 
   public void adjustmentValueChanged(AdjustmentEvent evt)
   {
+       if (annotationPanel == null)
+               return; // BH in process of loading
     int oldX = av.getStartRes();
     int oldY = av.getStartSeq();
 
@@ -968,7 +969,7 @@ public class AlignmentPanel extends Panel implements AdjustmentListener,
     paint(g);
   }
 
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
     invalidate();
     Dimension d = idPanel.idCanvas.getSize();
index 3d79588..6bbbf0a 100644 (file)
@@ -29,17 +29,17 @@ import jalview.schemes.ColourSchemeI;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Checkbox;
-import java.awt.Choice;
+import awt2swing.Button;
+import awt2swing.Checkbox;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Panel;
-import java.awt.Scrollbar;
-import java.awt.TextField;
+import awt2swing.Frame;
+import awt2swing.Panel;
+import awt2swing.Scrollbar;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
index 07eef12..b7f4290 100644 (file)
@@ -10,13 +10,13 @@ import jalview.viewmodel.annotationfilter.AnnotationFilterParameter;
 
 import java.awt.BorderLayout;
 import java.awt.CardLayout;
-import java.awt.Checkbox;
-import java.awt.Choice;
+import awt2swing.Checkbox;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.Panel;
-import java.awt.TextField;
+import awt2swing.Frame;
+import awt2swing.Panel;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
@@ -608,7 +608,7 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
     public void itemStateChanged(ItemEvent e)
     {
       aColChooser.setCurrentFutherActionPanel(this);
-      if (furtherAction.getSelectedItem().equalsIgnoreCase("Select"))
+      if (furtherAction.getSelectedItem().toString().equalsIgnoreCase("Select")) // BH added "toString()"
       {
         setActionOption(ACTION_OPTION_SELECT);
         updateView();
@@ -780,7 +780,6 @@ public class AnnotationColumnChooser extends AnnotationRowFilter implements
         public void textValueChanged(TextEvent e)
         {
           searchStringAction();
-
         }
 
       });
index c490fba..c823113 100755 (executable)
@@ -29,18 +29,18 @@ import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
 import jalview.util.ParseHtmlBodyAndLinks;
 
-import java.awt.Checkbox;
-import java.awt.CheckboxMenuItem;
+import awt2swing.Checkbox;
+import awt2swing.CheckboxMenuItem;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.FontMetrics;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.PopupMenu;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.PopupMenu;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.InputEvent;
@@ -788,7 +788,7 @@ public class AnnotationLabels extends Panel implements ActionListener,
     paint(g);
   }
 
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
     int w = getSize().width;
     int h = getSize().height;
index 6f406a4..27e589f 100755 (executable)
@@ -33,9 +33,9 @@ import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.PopupMenu;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.PopupMenu;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
@@ -541,7 +541,7 @@ public class AnnotationPanel extends Panel implements AwtRenderPanelI,
   }
 
   @Override
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
     Dimension d = getSize();
     imgWidth = d.width;
index 1345503..bcc9013 100644 (file)
@@ -4,13 +4,13 @@ import jalview.datamodel.AlignmentAnnotation;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.util.MessageManager;
 
-import java.awt.Button;
-import java.awt.Checkbox;
-import java.awt.Choice;
-import java.awt.Frame;
-import java.awt.Panel;
-import java.awt.Scrollbar;
-import java.awt.TextField;
+import awt2swing.Button;
+import awt2swing.Checkbox;
+import awt2swing.Choice;
+import awt2swing.Frame;
+import awt2swing.Panel;
+import awt2swing.Scrollbar;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.util.Vector;
 
index c981104..aa18f5f 100644 (file)
@@ -39,18 +39,18 @@ import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.CheckboxMenuItem;
+import awt2swing.CheckboxMenuItem;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.TextArea;
-import java.awt.TextField;
+import awt2swing.Menu;
+import awt2swing.MenuBar;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.TextArea;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -64,62 +64,10 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
 
-public class AppletJmol extends EmbmenuFrame implements
-// StructureListener,
-        KeyListener, ActionListener, ItemListener
+public class AppletJmol //extends EmbmenuFrame implements
+//        KeyListener, ActionListener, ItemListener
 
 {
-  Menu fileMenu = new Menu(MessageManager.getString("action.file"));
-
-  Menu viewMenu = new Menu(MessageManager.getString("action.view"));
-
-  Menu coloursMenu = new Menu(MessageManager.getString("action.colour"));
-
-  Menu chainMenu = new Menu(MessageManager.getString("action.show_chain"));
-
-  Menu helpMenu = new Menu(MessageManager.getString("action.help"));
-
-  MenuItem mappingMenuItem = new MenuItem(
-          MessageManager.getString("label.view_mapping"));
-
-  CheckboxMenuItem seqColour = new CheckboxMenuItem(
-          MessageManager.getString("action.by_sequence"), true);
-
-  CheckboxMenuItem jmolColour = new CheckboxMenuItem(
-          MessageManager.getString("action.using_jmol"), false);
-
-  MenuItem chain = new MenuItem(MessageManager.getString("action.by_chain"));
-
-  MenuItem charge = new MenuItem(
-          MessageManager.getString("label.charge_cysteine"));
-
-  MenuItem zappo = new MenuItem(MessageManager.getString("label.zappo"));
-
-  MenuItem taylor = new MenuItem(MessageManager.getString("label.taylor"));
-
-  MenuItem hydro = new MenuItem(
-          MessageManager.getString("label.hydrophobicity"));
-
-  MenuItem helix = new MenuItem(
-          MessageManager.getString("label.helix_propensity"));
-
-  MenuItem strand = new MenuItem(
-          MessageManager.getString("label.strand_propensity"));
-
-  MenuItem turn = new MenuItem(
-          MessageManager.getString("label.turn_propensity"));
-
-  MenuItem buried = new MenuItem(
-          MessageManager.getString("label.buried_index"));
-
-  MenuItem purinepyrimidine = new MenuItem(
-          MessageManager.getString("label.purine_pyrimidine"));
-
-  MenuItem user = new MenuItem(
-          MessageManager.getString("label.user_defined_colours"));
-
-  MenuItem jmolHelp = new MenuItem(
-          MessageManager.getString("label.jmol_help"));
 
   Panel scriptWindow;
 
@@ -144,500 +92,565 @@ public class AppletJmol extends EmbmenuFrame implements
 
   AppletJmolBinding jmb;
 
-  /**
-   * datasource protocol for access to PDBEntry
-   */
-  String protocol = null;
-
-  /**
-   * Load a bunch of pdb entries associated with sequences in the alignment and
-   * display them - aligning them if necessary.
-   * 
-   * @param pdbentries
-   *          each pdb file (at least one needed)
-   * @param boundseqs
-   *          each set of sequences for each pdb file (must match number of pdb
-   *          files)
-   * @param boundchains
-   *          the target pdb chain corresponding with each sequence associated
-   *          with each pdb file (may be null at any level)
-   * @param align
-   *          true/false
-   * @param ap
-   *          associated alignment
-   * @param protocol
-   *          how to get pdb data
-   */
-  public AppletJmol(PDBEntry[] pdbentries, SequenceI[][] boundseqs,
-          String[][] boundchains, boolean align, AlignmentPanel ap,
-          String protocol)
-  {
-    throw new Error(MessageManager.getString("error.not_yet_implemented"));
-  }
-
-  public AppletJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
-          AlignmentPanel ap, String protocol)
-  {
-    this.ap = ap;
-    jmb = new AppletJmolBinding(this, ap.getStructureSelectionManager(),
-            new PDBEntry[]
-            { pdbentry }, new SequenceI[][]
-            { seq }, new String[][]
-            { chains }, protocol);
-    jmb.setColourBySequence(true);
-    if (pdbentry.getId() == null || pdbentry.getId().length() < 1)
-    {
-      if (protocol.equals(AppletFormatAdapter.PASTE))
-      {
-        pdbentry.setId("PASTED PDB"
-                + (chains == null ? "_" : chains.toString()));
-      }
-      else
-      {
-        pdbentry.setId(pdbentry.getFile());
-      }
-    }
-
-    if (JalviewLite.debug)
-    {
-      System.err
-              .println("AppletJmol: PDB ID is '" + pdbentry.getId() + "'");
-    }
-
-    String alreadyMapped = StructureSelectionManager
-            .getStructureSelectionManager(ap.av.applet)
-            .alreadyMappedToFile(pdbentry.getId());
-    MCview.PDBfile reader = null;
-    if (alreadyMapped != null)
-    {
-      reader = StructureSelectionManager.getStructureSelectionManager(
-              ap.av.applet).setMapping(seq, chains, pdbentry.getFile(),
-              protocol);
-      // PROMPT USER HERE TO ADD TO NEW OR EXISTING VIEW?
-      // FOR NOW, LETS JUST OPEN A NEW WINDOW
-    }
-    MenuBar menuBar = new MenuBar();
-    menuBar.add(fileMenu);
-    fileMenu.add(mappingMenuItem);
-    menuBar.add(viewMenu);
-    mappingMenuItem.addActionListener(this);
-    viewMenu.add(chainMenu);
-    menuBar.add(coloursMenu);
-    menuBar.add(helpMenu);
-
-    charge.addActionListener(this);
-    hydro.addActionListener(this);
-    chain.addActionListener(this);
-    seqColour.addItemListener(this);
-    jmolColour.addItemListener(this);
-    zappo.addActionListener(this);
-    taylor.addActionListener(this);
-    helix.addActionListener(this);
-    strand.addActionListener(this);
-    turn.addActionListener(this);
-    buried.addActionListener(this);
-    purinepyrimidine.addActionListener(this);
-    user.addActionListener(this);
-
-    jmolHelp.addActionListener(this);
-
-    coloursMenu.add(seqColour);
-    coloursMenu.add(chain);
-    coloursMenu.add(charge);
-    coloursMenu.add(zappo);
-    coloursMenu.add(taylor);
-    coloursMenu.add(hydro);
-    coloursMenu.add(helix);
-    coloursMenu.add(strand);
-    coloursMenu.add(turn);
-    coloursMenu.add(buried);
-    coloursMenu.add(purinepyrimidine);
-    coloursMenu.add(user);
-    coloursMenu.add(jmolColour);
-    helpMenu.add(jmolHelp);
-    this.setLayout(new BorderLayout());
-
-    setMenuBar(menuBar);
-
-    renderPanel = new RenderPanel();
-    embedMenuIfNeeded(renderPanel);
-    this.add(renderPanel, BorderLayout.CENTER);
-    scriptWindow = new Panel();
-    scriptWindow.setVisible(false);
-    // this.add(scriptWindow, BorderLayout.SOUTH);
-
-    try
-    {
-      jmb.allocateViewer(renderPanel, true, ap.av.applet.getName()
-              + "_jmol_", ap.av.applet.getDocumentBase(),
-              ap.av.applet.getCodeBase(), "-applet", scriptWindow, null);
-    } catch (Exception e)
-    {
-      System.err
-              .println("Couldn't create a jmol viewer. Args to allocate viewer were:\nDocumentBase="
-                      + ap.av.applet.getDocumentBase()
-                      + "\nCodebase="
-                      + ap.av.applet.getCodeBase());
-      e.printStackTrace();
-      dispose();
-      return;
-    }
-    // jmb.newJmolPopup(true, "Jmol", true);
-
-    this.addWindowListener(new WindowAdapter()
-    {
-      public void windowClosing(WindowEvent evt)
-      {
-        closeViewer();
-      }
-    });
-    if (pdbentry.getProperty() == null)
-    {
-      pdbentry.setProperty(new Hashtable());
-      pdbentry.getProperty().put("protocol", protocol);
-    }
-    if (pdbentry.getFile() != null)
-    {
-      // import structure data from pdbentry.getFile based on given protocol
-      if (protocol.equals(AppletFormatAdapter.PASTE))
-      {
-        // TODO: JAL-623 : correctly record file contents for matching up later
-        // pdbentry.getProperty().put("pdbfilehash",""+pdbentry.getFile().hashCode());
-        loadInline(pdbentry.getFile());
-      }
-      else if (protocol.equals(AppletFormatAdapter.FILE)
-              || protocol.equals(AppletFormatAdapter.URL))
-      {
-        jmb.viewer.openFile(pdbentry.getFile());
-      }
-      else
-      {
-        // probably CLASSLOADER based datasource..
-        // Try and get a reader on the datasource, and pass that to Jmol
-        try
-        {
-          java.io.Reader freader = null;
-          if (reader != null)
-          {
-            if (JalviewLite.debug)
-            {
-              System.err
-                      .println("AppletJmol:Trying to reuse existing PDBfile IO parser.");
-            }
-            // re-use the one we opened earlier
-            freader = reader.getReader();
-          }
-          if (freader == null)
-          {
-            if (JalviewLite.debug)
-            {
-              System.err
-                      .println("AppletJmol:Creating new PDBfile IO parser.");
-            }
-            FileParse fp = new FileParse(pdbentry.getFile(), protocol);
-            fp.mark();
-            // reader = new MCview.PDBfile(fp);
-            // could set ID, etc.
-            // if (!reader.isValid())
-            // {
-            // throw new Exception("Invalid datasource.
-            // "+reader.getWarningMessage());
-            // }
-            // fp.reset();
-            freader = fp.getReader();
-          }
-          if (freader == null)
-          {
-            throw new Exception(MessageManager.getString("exception.invalid_datasource_couldnt_obtain_reader"));
-          }
-          jmb.viewer.openReader(pdbentry.getFile(), pdbentry.getId(),
-                  freader);
-        } catch (Exception e)
-        {
-          // give up!
-          System.err.println("Couldn't access pdbentry id="
-                  + pdbentry.getId() + " and file=" + pdbentry.getFile()
-                  + " using protocol=" + protocol);
-          e.printStackTrace();
-        }
-      }
-    }
-
-    JalviewLite.addFrame(this, jmb.getViewerTitle(), 400, 400);
-  }
-
-  public void loadInline(String string)
-  {
-    loadedInline = true;
-    jmb.loadInline(string);
-  }
-
-  void setChainMenuItems(Vector<String> chains)
-  {
-    chainMenu.removeAll();
-
-    MenuItem menuItem = new MenuItem(MessageManager.getString("label.all"));
-    menuItem.addActionListener(this);
-
-    chainMenu.add(menuItem);
-
-    CheckboxMenuItem menuItemCB;
-    for (String ch : chains)
-    {
-      menuItemCB = new CheckboxMenuItem(ch, true);
-      menuItemCB.addItemListener(this);
-      chainMenu.add(menuItemCB);
-    }
-  }
-
-  boolean allChainsSelected = false;
-
-  void centerViewer()
-  {
-    Vector<String> toshow = new Vector<String>();
-    for (int i = 0; i < chainMenu.getItemCount(); i++)
-    {
-      if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
-      {
-        CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);
-        if (item.getState())
-        {
-          toshow.addElement(item.getLabel());
-        }
-      }
-    }
-    jmb.centerViewer(toshow);
-  }
-
-  void closeViewer()
-  {
-    jmb.closeViewer();
-    jmb = null;
-    this.setVisible(false);
-  }
-
-  public void actionPerformed(ActionEvent evt)
-  {
-    if (evt.getSource() == mappingMenuItem)
-    {
-      CutAndPasteTransfer cap = new CutAndPasteTransfer(
-              false, null);
-      Frame frame = new Frame();
-      frame.add(cap);
-
-      StringBuffer sb = new StringBuffer();
-      try
-      {
-        cap.setText(jmb.printMappings());
-      } catch (OutOfMemoryError ex)
-      {
-        frame.dispose();
-        System.err
-                .println("Out of memory when trying to create dialog box with sequence-structure mapping.");
-        return;
-      }
-      JalviewLite.addFrame(frame,
-              MessageManager.getString("label.pdb_sequence_mapping"), 550,
-              600);
-    }
-    else if (evt.getSource() == charge)
-    {
-      setEnabled(charge);
-      jmb.colourByCharge();
-    }
-
-    else if (evt.getSource() == chain)
-    {
-      setEnabled(chain);
-      jmb.colourByChain();
-    }
-    else if (evt.getSource() == zappo)
-    {
-      setEnabled(zappo);
-      jmb.setJalviewColourScheme(new ZappoColourScheme());
-    }
-    else if (evt.getSource() == taylor)
-    {
-      setEnabled(taylor);
-      jmb.setJalviewColourScheme(new TaylorColourScheme());
-    }
-    else if (evt.getSource() == hydro)
-    {
-      setEnabled(hydro);
-      jmb.setJalviewColourScheme(new HydrophobicColourScheme());
-    }
-    else if (evt.getSource() == helix)
-    {
-      setEnabled(helix);
-      jmb.setJalviewColourScheme(new HelixColourScheme());
-    }
-    else if (evt.getSource() == strand)
-    {
-      setEnabled(strand);
-      jmb.setJalviewColourScheme(new StrandColourScheme());
-    }
-    else if (evt.getSource() == turn)
-    {
-      setEnabled(turn);
-      jmb.setJalviewColourScheme(new TurnColourScheme());
-    }
-    else if (evt.getSource() == buried)
-    {
-      setEnabled(buried);
-      jmb.setJalviewColourScheme(new BuriedColourScheme());
-    }
-    else if (evt.getSource() == purinepyrimidine)
-    {
-      jmb.setJalviewColourScheme(new PurinePyrimidineColourScheme());
-    }
-    else if (evt.getSource() == user)
-    {
-      setEnabled(user);
-      new UserDefinedColours(this);
-    }
-    else if (evt.getSource() == jmolHelp)
-    {
-      try
-      {
-        ap.av.applet.getAppletContext().showDocument(
-                new java.net.URL(
-                        "http://jmol.sourceforge.net/docs/JmolUserGuide/"),
-                "jmolHelp");
-      } catch (java.net.MalformedURLException ex)
-      {
-      }
-    }
-    else
-    {
-      allChainsSelected = true;
-      for (int i = 0; i < chainMenu.getItemCount(); i++)
-      {
-        if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
-        {
-          ((CheckboxMenuItem) chainMenu.getItem(i)).setState(true);
-        }
-      }
-
-      centerViewer();
-      allChainsSelected = false;
-    }
-  }
-
-  /**
-   * tick or untick the seqColour menu entry or jmoColour entry depending upon
-   * if it was selected or not.
-   * 
-   * @param itm
-   */
-  private void setEnabled(MenuItem itm)
-  {
-    jmolColour.setState(itm == jmolColour);
-    seqColour.setState(itm == seqColour);
-    jmb.setColourBySequence(itm == seqColour);
-  }
-
-  public void itemStateChanged(ItemEvent evt)
-  {
-    if (evt.getSource() == jmolColour)
-    {
-      setEnabled(jmolColour);
-      jmb.setColourBySequence(false);
-    }
-    else if (evt.getSource() == seqColour)
-    {
-      setEnabled(seqColour);
-      jmb.colourBySequence(ap);
-    }
-    else if (!allChainsSelected)
-    {
-      centerViewer();
-    }
-  }
-
-  public void keyPressed(KeyEvent evt)
-  {
-    if (evt.getKeyCode() == KeyEvent.VK_ENTER && scriptWindow.isVisible())
-    {
-      jmb.eval(inputLine.getText());
-      history.append("\n$ " + inputLine.getText());
-      inputLine.setText("");
-    }
-
-  }
-
-  public void keyTyped(KeyEvent evt)
-  {
-  }
-
-  public void keyReleased(KeyEvent evt)
-  {
-  }
-
-  public void updateColours(Object source)
-  {
-    AlignmentPanel panel = (AlignmentPanel) source;
-    jmb.colourBySequence(panel);
-  }
-
-  public void updateTitleAndMenus()
-  {
-    if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
-    {
-      repaint();
-      return;
-    }
-    setChainMenuItems(jmb.chainNames);
-    jmb.colourBySequence(ap);
-
-    setTitle(jmb.getViewerTitle());
-  }
-
-  public void showUrl(String url)
-  {
-    try
-    {
-      ap.av.applet.getAppletContext().showDocument(new java.net.URL(url),
-              "jmolOutput");
-    } catch (java.net.MalformedURLException ex)
-    {
-    }
-  }
-
-  Panel splitPane = null;
-
-  public void showConsole(boolean showConsole)
-  {
-    if (showConsole)
-    {
-      remove(renderPanel);
-      splitPane = new Panel();
-
-      splitPane.setLayout(new java.awt.GridLayout(2, 1));
-      splitPane.add(renderPanel);
-      splitPane.add(scriptWindow);
-      scriptWindow.setVisible(true);
-      this.add(splitPane, BorderLayout.CENTER);
-      splitPane.setVisible(true);
-      splitPane.validate();
-    }
-    else
-    {
-      scriptWindow.setVisible(false);
-      remove(splitPane);
-      add(renderPanel, BorderLayout.CENTER);
-      splitPane = null;
-    }
-    validate();
-  }
-
-  public float[][] functionXY(String functionName, int x, int y)
-  {
-    return null;
-  }
-
-  // /End JmolStatusListener
-  // /////////////////////////////
 
+       public AppletJmol(PDBEntry entry, SequenceI[] sequenceIs, Object object,
+                       AlignmentPanel ap2, String uRL) {
+               // TODO Auto-generated constructor stub
+       }
+
+
+       public void setJalviewColourScheme(UserColourScheme ucs) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       
+       //  Menu fileMenu = new Menu(MessageManager.getString("action.file"));
+//
+//  Menu viewMenu = new Menu(MessageManager.getString("action.view"));
+//
+//  Menu coloursMenu = new Menu(MessageManager.getString("action.colour"));
+//
+//  Menu chainMenu = new Menu(MessageManager.getString("action.show_chain"));
+//
+//  Menu helpMenu = new Menu(MessageManager.getString("action.help"));
+//
+//  MenuItem mappingMenuItem = new MenuItem(
+//          MessageManager.getString("label.view_mapping"));
+//
+//  CheckboxMenuItem seqColour = new CheckboxMenuItem(
+//          MessageManager.getString("action.by_sequence"), true);
+//
+//  CheckboxMenuItem jmolColour = new CheckboxMenuItem(
+//          MessageManager.getString("action.using_jmol"), false);
+//
+//  MenuItem chain = new MenuItem(MessageManager.getString("action.by_chain"));
+//
+//  MenuItem charge = new MenuItem(
+//          MessageManager.getString("label.charge_cysteine"));
+//
+//  MenuItem zappo = new MenuItem(MessageManager.getString("label.zappo"));
+//
+//  MenuItem taylor = new MenuItem(MessageManager.getString("label.taylor"));
+//
+//  MenuItem hydro = new MenuItem(
+//          MessageManager.getString("label.hydrophobicity"));
+//
+//  MenuItem helix = new MenuItem(
+//          MessageManager.getString("label.helix_propensity"));
+//
+//  MenuItem strand = new MenuItem(
+//          MessageManager.getString("label.strand_propensity"));
+//
+//  MenuItem turn = new MenuItem(
+//          MessageManager.getString("label.turn_propensity"));
+//
+//  MenuItem buried = new MenuItem(
+//          MessageManager.getString("label.buried_index"));
+//
+//  MenuItem purinepyrimidine = new MenuItem(
+//          MessageManager.getString("label.purine_pyrimidine"));
+//
+//  MenuItem user = new MenuItem(
+//          MessageManager.getString("label.user_defined_colours"));
+//
+//  MenuItem jmolHelp = new MenuItem(
+//          MessageManager.getString("label.jmol_help"));
+//
+//  /**
+//   * datasource protocol for access to PDBEntry
+//   */
+//  String protocol = null;
+//
+//  /**
+//   * Load a bunch of pdb entries associated with sequences in the alignment and
+//   * display them - aligning them if necessary.
+//   * 
+//   * @param pdbentries
+//   *          each pdb file (at least one needed)
+//   * @param boundseqs
+//   *          each set of sequences for each pdb file (must match number of pdb
+//   *          files)
+//   * @param boundchains
+//   *          the target pdb chain corresponding with each sequence associated
+//   *          with each pdb file (may be null at any level)
+//   * @param align
+//   *          true/false
+//   * @param ap
+//   *          associated alignment
+//   * @param protocol
+//   *          how to get pdb data
+//   */
+//  public AppletJmol(PDBEntry[] pdbentries, SequenceI[][] boundseqs,
+//          String[][] boundchains, boolean align, AlignmentPanel ap,
+//          String protocol)
+//  {
+//    throw new Error(MessageManager.getString("error.not_yet_implemented"));
+//  }
+//
+//  public AppletJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
+//          AlignmentPanel ap, String protocol)
+//  {
+//    this.ap = ap;
+//    jmb = new AppletJmolBinding(this, ap.getStructureSelectionManager(),
+//            new PDBEntry[]
+//            { pdbentry }, new SequenceI[][]
+//            { seq }, new String[][]
+//            { chains }, protocol);
+//    jmb.setColourBySequence(true);
+//    if (pdbentry.getId() == null || pdbentry.getId().length() < 1)
+//    {
+//      if (protocol.equals(AppletFormatAdapter.PASTE))
+//      {
+//        pdbentry.setId("PASTED PDB"
+//                + (chains == null ? "_" : chains.toString()));
+//      }
+//      else
+//      {
+//        pdbentry.setId(pdbentry.getFile());
+//      }
+//    }
+//
+//    if (JalviewLite.debug)
+//    {
+//      System.err
+//              .println("AppletJmol: PDB ID is '" + pdbentry.getId() + "'");
+//    }
+//
+//    String alreadyMapped = StructureSelectionManager
+//            .getStructureSelectionManager(ap.av.applet)
+//            .alreadyMappedToFile(pdbentry.getId());
+//    MCview.PDBfile reader = null;
+//    if (alreadyMapped != null)
+//    {
+//      reader = StructureSelectionManager.getStructureSelectionManager(
+//              ap.av.applet).setMapping(seq, chains, pdbentry.getFile(),
+//              protocol);
+//      // PROMPT USER HERE TO ADD TO NEW OR EXISTING VIEW?
+//      // FOR NOW, LETS JUST OPEN A NEW WINDOW
+//    }
+//    MenuBar menuBar = new MenuBar();
+//    menuBar.add(fileMenu);
+//    fileMenu.add(mappingMenuItem);
+//    menuBar.add(viewMenu);
+//    mappingMenuItem.addActionListener(this);
+//    viewMenu.add(chainMenu);
+//    menuBar.add(coloursMenu);
+//    menuBar.add(helpMenu);
+//
+//    charge.addActionListener(this);
+//    hydro.addActionListener(this);
+//    chain.addActionListener(this);
+//    seqColour.addItemListener(this);
+//    jmolColour.addItemListener(this);
+//    zappo.addActionListener(this);
+//    taylor.addActionListener(this);
+//    helix.addActionListener(this);
+//    strand.addActionListener(this);
+//    turn.addActionListener(this);
+//    buried.addActionListener(this);
+//    purinepyrimidine.addActionListener(this);
+//    user.addActionListener(this);
+//
+//    jmolHelp.addActionListener(this);
+//
+//    coloursMenu.add(seqColour);
+//    coloursMenu.add(chain);
+//    coloursMenu.add(charge);
+//    coloursMenu.add(zappo);
+//    coloursMenu.add(taylor);
+//    coloursMenu.add(hydro);
+//    coloursMenu.add(helix);
+//    coloursMenu.add(strand);
+//    coloursMenu.add(turn);
+//    coloursMenu.add(buried);
+//    coloursMenu.add(purinepyrimidine);
+//    coloursMenu.add(user);
+//    coloursMenu.add(jmolColour);
+//    helpMenu.add(jmolHelp);
+//    this.setLayout(new BorderLayout());
+//
+//    setMenuBar(menuBar);
+//
+//    renderPanel = new RenderPanel();
+//    embedMenuIfNeeded(renderPanel);
+//    this.add(renderPanel, BorderLayout.CENTER);
+//    scriptWindow = new Panel();
+//    scriptWindow.setVisible(false);
+//    // this.add(scriptWindow, BorderLayout.SOUTH);
+//
+//    try
+//    {
+//      jmb.allocateViewer(renderPanel, true, ap.av.applet.getName()
+//              + "_jmol_", ap.av.applet.getDocumentBase(),
+//              ap.av.applet.getCodeBase(), "-applet", scriptWindow, null);
+//    } catch (Exception e)
+//    {
+//      System.err
+//              .println("Couldn't create a jmol viewer. Args to allocate viewer were:\nDocumentBase="
+//                      + ap.av.applet.getDocumentBase()
+//                      + "\nCodebase="
+//                      + ap.av.applet.getCodeBase());
+//      e.printStackTrace();
+//      dispose();
+//      return;
+//    }
+//    // jmb.newJmolPopup(true, "Jmol", true);
+//
+//    this.addWindowListener(new WindowAdapter()
+//    {
+//      public void windowClosing(WindowEvent evt)
+//      {
+//        closeViewer();
+//      }
+//    });
+//    if (pdbentry.getProperty() == null)
+//    {
+//      pdbentry.setProperty(new Hashtable());
+//      pdbentry.getProperty().put("protocol", protocol);
+//    }
+//    if (pdbentry.getFile() != null)
+//    {
+//      // import structure data from pdbentry.getFile based on given protocol
+//      if (protocol.equals(AppletFormatAdapter.PASTE))
+//      {
+//        // TODO: JAL-623 : correctly record file contents for matching up later
+//        // pdbentry.getProperty().put("pdbfilehash",""+pdbentry.getFile().hashCode());
+//        loadInline(pdbentry.getFile());
+//      }
+//      else if (protocol.equals(AppletFormatAdapter.FILE)
+//              || protocol.equals(AppletFormatAdapter.URL))
+//      {
+//        jmb.viewer.openFile(pdbentry.getFile());
+//      }
+//      else
+//      {
+//        // probably CLASSLOADER based datasource..
+//        // Try and get a reader on the datasource, and pass that to Jmol
+//        try
+//        {
+//          java.io.Reader freader = null;
+//          if (reader != null)
+//          {
+//            if (JalviewLite.debug)
+//            {
+//              System.err
+//                      .println("AppletJmol:Trying to reuse existing PDBfile IO parser.");
+//            }
+//            // re-use the one we opened earlier
+//            freader = reader.getReader();
+//          }
+//          if (freader == null)
+//          {
+//            if (JalviewLite.debug)
+//            {
+//              System.err
+//                      .println("AppletJmol:Creating new PDBfile IO parser.");
+//            }
+//            FileParse fp = new FileParse(pdbentry.getFile(), protocol);
+//            fp.mark();
+//            // reader = new MCview.PDBfile(fp);
+//            // could set ID, etc.
+//            // if (!reader.isValid())
+//            // {
+//            // throw new Exception("Invalid datasource.
+//            // "+reader.getWarningMessage());
+//            // }
+//            // fp.reset();
+//            freader = fp.getReader();
+//          }
+//          if (freader == null)
+//          {
+//            throw new Exception(MessageManager.getString("exception.invalid_datasource_couldnt_obtain_reader"));
+//          }
+//          jmb.viewer.openReader(pdbentry.getFile(), pdbentry.getId(),
+//                  freader);
+//        } catch (Exception e)
+//        {
+//          // give up!
+//          System.err.println("Couldn't access pdbentry id="
+//                  + pdbentry.getId() + " and file=" + pdbentry.getFile()
+//                  + " using protocol=" + protocol);
+//          e.printStackTrace();
+//        }
+//      }
+//    }
+//
+//    JalviewLite.addFrame(this, jmb.getViewerTitle(), 400, 400);
+//  }
+//
+//  public void loadInline(String string)
+//  {
+//    loadedInline = true;
+//    jmb.loadInline(string);
+//  }
+//
+//  void setChainMenuItems(Vector<String> chains)
+//  {
+//    chainMenu.removeAll();
+//
+//    MenuItem menuItem = new MenuItem(MessageManager.getString("label.all"));
+//    menuItem.addActionListener(this);
+//
+//    chainMenu.add(menuItem);
+//
+//    CheckboxMenuItem menuItemCB;
+//    for (String ch : chains)
+//    {
+//      menuItemCB = new CheckboxMenuItem(ch, true);
+//      menuItemCB.addItemListener(this);
+//      chainMenu.add(menuItemCB);
+//    }
+//  }
+//
+//  boolean allChainsSelected = false;
+//
+//  void centerViewer()
+//  {
+//    Vector<String> toshow = new Vector<String>();
+//    for (int i = 0; i < chainMenu.getItemCount(); i++)
+//    {
+//      if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
+//      {
+//        CheckboxMenuItem item = (CheckboxMenuItem) chainMenu.getItem(i);
+//        if (item.getState())
+//        {
+//          toshow.addElement(item.getLabel());
+//        }
+//      }
+//    }
+//    jmb.centerViewer(toshow);
+//  }
+//
+//  void closeViewer()
+//  {
+//    jmb.closeViewer();
+//    jmb = null;
+//    this.setVisible(false);
+//  }
+//
+//  public void actionPerformed(ActionEvent evt)
+//  {
+//    if (evt.getSource() == mappingMenuItem)
+//    {
+//      CutAndPasteTransfer cap = new CutAndPasteTransfer(
+//              false, null);
+//      Frame frame = new Frame();
+//      frame.add(cap);
+//
+//      StringBuffer sb = new StringBuffer();
+//      try
+//      {
+//        cap.setText(jmb.printMappings());
+//      } catch (OutOfMemoryError ex)
+//      {
+//        frame.dispose();
+//        System.err
+//                .println("Out of memory when trying to create dialog box with sequence-structure mapping.");
+//        return;
+//      }
+//      JalviewLite.addFrame(frame,
+//              MessageManager.getString("label.pdb_sequence_mapping"), 550,
+//              600);
+//    }
+//    else if (evt.getSource() == charge)
+//    {
+//      setEnabled(charge);
+//      jmb.colourByCharge();
+//    }
+//
+//    else if (evt.getSource() == chain)
+//    {
+//      setEnabled(chain);
+//      jmb.colourByChain();
+//    }
+//    else if (evt.getSource() == zappo)
+//    {
+//      setEnabled(zappo);
+//      jmb.setJalviewColourScheme(new ZappoColourScheme());
+//    }
+//    else if (evt.getSource() == taylor)
+//    {
+//      setEnabled(taylor);
+//      jmb.setJalviewColourScheme(new TaylorColourScheme());
+//    }
+//    else if (evt.getSource() == hydro)
+//    {
+//      setEnabled(hydro);
+//      jmb.setJalviewColourScheme(new HydrophobicColourScheme());
+//    }
+//    else if (evt.getSource() == helix)
+//    {
+//      setEnabled(helix);
+//      jmb.setJalviewColourScheme(new HelixColourScheme());
+//    }
+//    else if (evt.getSource() == strand)
+//    {
+//      setEnabled(strand);
+//      jmb.setJalviewColourScheme(new StrandColourScheme());
+//    }
+//    else if (evt.getSource() == turn)
+//    {
+//      setEnabled(turn);
+//      jmb.setJalviewColourScheme(new TurnColourScheme());
+//    }
+//    else if (evt.getSource() == buried)
+//    {
+//      setEnabled(buried);
+//      jmb.setJalviewColourScheme(new BuriedColourScheme());
+//    }
+//    else if (evt.getSource() == purinepyrimidine)
+//    {
+//      jmb.setJalviewColourScheme(new PurinePyrimidineColourScheme());
+//    }
+//    else if (evt.getSource() == user)
+//    {
+//      setEnabled(user);
+//      new UserDefinedColours(this);
+//    }
+//    else if (evt.getSource() == jmolHelp)
+//    {
+//      try
+//      {
+//        ap.av.applet.getAppletContext().showDocument(
+//                new java.net.URL(
+//                        "http://jmol.sourceforge.net/docs/JmolUserGuide/"),
+//                "jmolHelp");
+//      } catch (java.net.MalformedURLException ex)
+//      {
+//      }
+//    }
+//    else
+//    {
+//      allChainsSelected = true;
+//      for (int i = 0; i < chainMenu.getItemCount(); i++)
+//      {
+//        if (chainMenu.getItem(i) instanceof CheckboxMenuItem)
+//        {
+//          ((CheckboxMenuItem) chainMenu.getItem(i)).setState(true);
+//        }
+//      }
+//
+//      centerViewer();
+//      allChainsSelected = false;
+//    }
+//  }
+//
+//  /**
+//   * tick or untick the seqColour menu entry or jmoColour entry depending upon
+//   * if it was selected or not.
+//   * 
+//   * @param itm
+//   */
+//  private void setEnabled(Object itm) // BH MenuItem not superclass of CheckBoxMenuItem
+//  {
+//    jmolColour.setState(itm == jmolColour);
+//    seqColour.setState(itm == seqColour);
+//    jmb.setColourBySequence(itm == seqColour);
+//  }
+//
+//  public void itemStateChanged(ItemEvent evt)
+//  {
+//    if (evt.getSource() == jmolColour)
+//    {
+//      setEnabled(jmolColour);
+//      jmb.setColourBySequence(false);
+//    }
+//    else if (evt.getSource() == seqColour)
+//    {
+//      setEnabled(seqColour);
+//      jmb.colourBySequence(ap);
+//    }
+//    else if (!allChainsSelected)
+//    {
+//      centerViewer();
+//    }
+//  }
+//
+//  public void keyPressed(KeyEvent evt)
+//  {
+//    if (evt.getKeyCode() == KeyEvent.VK_ENTER && scriptWindow.isVisible())
+//    {
+//      jmb.eval(inputLine.getText());
+//      history.append("\n$ " + inputLine.getText());
+//      inputLine.setText("");
+//    }
+//
+//  }
+//
+//  public void keyTyped(KeyEvent evt)
+//  {
+//  }
+//
+//  public void keyReleased(KeyEvent evt)
+//  {
+//  }
+//
+//  public void updateColours(Object source)
+//  {
+//    AlignmentPanel panel = (AlignmentPanel) source;
+//    jmb.colourBySequence(panel);
+//  }
+//
+//  public void updateTitleAndMenus()
+//  {
+//    if (jmb.fileLoadingError != null && jmb.fileLoadingError.length() > 0)
+//    {
+//      repaint();
+//      return;
+//    }
+//    setChainMenuItems(jmb.chainNames);
+//    jmb.colourBySequence(ap);
+//
+//    setTitle(jmb.getViewerTitle());
+//  }
+//
+//  public void showUrl(String url)
+//  {
+//    try
+//    {
+//      ap.av.applet.getAppletContext().showDocument(new java.net.URL(url),
+//              "jmolOutput");
+//    } catch (java.net.MalformedURLException ex)
+//    {
+//    }
+//  }
+//
+//  Panel splitPane = null;
+//
+//  public void showConsole(boolean showConsole)
+//  {
+//    if (showConsole)
+//    {
+//      remove(renderPanel);
+//      splitPane = new Panel();
+//
+//      splitPane.setLayout(new java.awt.GridLayout(2, 1));
+//      splitPane.add(renderPanel);
+//      splitPane.add(scriptWindow);
+//      scriptWindow.setVisible(true);
+//      this.add(splitPane, BorderLayout.CENTER);
+//      splitPane.setVisible(true);
+//      splitPane.validate();
+//    }
+//    else
+//    {
+//      scriptWindow.setVisible(false);
+//      remove(splitPane);
+//      add(renderPanel, BorderLayout.CENTER);
+//      splitPane = null;
+//    }
+//    validate();
+//  }
+//
+//  public float[][] functionXY(String functionName, int x, int y)
+//  {
+//    return null;
+//  }
+//
+//  // /End JmolStatusListener
+//  // /////////////////////////////
+//
   class RenderPanel extends Panel
   {
     Dimension currentSize = new Dimension();
@@ -647,59 +660,59 @@ public class AppletJmol extends EmbmenuFrame implements
       paint(g);
     }
 
-    public void paint(Graphics g)
+    public void PaintComponent(Graphics g)
     {
       currentSize = this.getSize();
 
-      if (jmb.viewer == null)
-      {
-        g.setColor(Color.black);
-        g.fillRect(0, 0, currentSize.width, currentSize.height);
-        g.setColor(Color.white);
-        g.setFont(new Font("Verdana", Font.BOLD, 14));
-        g.drawString(MessageManager.getString("label.retrieving_pdb_data"),
-                20, currentSize.height / 2);
-      }
-      else
-      {
-        jmb.viewer.renderScreenImage(g, currentSize.width,
-                currentSize.height);
-      }
-    }
-  }
-
-  /*
-   * @Override public Color getColour(int atomIndex, int pdbResNum, String
-   * chain, String pdbId) { return jmb.getColour(atomIndex, pdbResNum, chain,
-   * pdbId); }
-   * 
-   * @Override public String[] getPdbFile() { return jmb.getPdbFile(); }
-   * 
-   * @Override public void highlightAtom(int atomIndex, int pdbResNum, String
-   * chain, String pdbId) { jmb.highlightAtom(atomIndex, pdbResNum, chain,
-   * pdbId);
-   * 
-   * }
-   * 
-   * @Override public void mouseOverStructure(int atomIndex, String strInfo) {
-   * jmb.mouseOverStructure(atomIndex, strInfo);
-   * 
-   * }
-   */
-  public void setJalviewColourScheme(UserColourScheme ucs)
-  {
-    jmb.setJalviewColourScheme(ucs);
-  }
-
-  public AlignmentPanel getAlignmentPanelFor(AlignmentI alignment)
-  {
-    for (int i = 0; i < _aps.size(); i++)
-    {
-      if (_aps.get(i).av.getAlignment() == alignment)
-      {
-        return (_aps.get(i));
-      }
+//      if (jmb.viewer == null)
+//      {
+//        g.setColor(Color.black);
+//        g.fillRect(0, 0, currentSize.width, currentSize.height);
+//        g.setColor(Color.white);
+//        g.setFont(new Font("Verdana", Font.BOLD, 14));
+//        g.drawString(MessageManager.getString("label.retrieving_pdb_data"),
+//                20, currentSize.height / 2);
+//      }
+//      else
+//      {
+//        jmb.viewer.renderScreenImage(g, currentSize.width,
+//                currentSize.height);
+//      }
     }
-    return ap;
   }
+//
+//  /*
+//   * @Override public Color getColour(int atomIndex, int pdbResNum, String
+//   * chain, String pdbId) { return jmb.getColour(atomIndex, pdbResNum, chain,
+//   * pdbId); }
+//   * 
+//   * @Override public String[] getPdbFile() { return jmb.getPdbFile(); }
+//   * 
+//   * @Override public void highlightAtom(int atomIndex, int pdbResNum, String
+//   * chain, String pdbId) { jmb.highlightAtom(atomIndex, pdbResNum, chain,
+//   * pdbId);
+//   * 
+//   * }
+//   * 
+//   * @Override public void mouseOverStructure(int atomIndex, String strInfo) {
+//   * jmb.mouseOverStructure(atomIndex, strInfo);
+//   * 
+//   * }
+//   */
+//  public void setJalviewColourScheme(UserColourScheme ucs)
+//  {
+//    jmb.setJalviewColourScheme(ucs);
+//  }
+//
+//  public AlignmentPanel getAlignmentPanelFor(AlignmentI alignment)
+//  {
+//    for (int i = 0; i < _aps.size(); i++)
+//    {
+//      if (_aps.get(i).av.getAlignment() == alignment)
+//      {
+//        return (_aps.get(i));
+//      }
+//    }
+//    return ap;
+//  }
 }
index 7035058..d23d164 100644 (file)
@@ -23,7 +23,7 @@ package jalview.appletgui;
 import jalview.api.AlignmentViewPanel;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
-import jalview.ext.jmol.JalviewJmolBinding;
+//import jalview.ext.jmol.JalviewJmolBinding;
 import jalview.structure.StructureSelectionManager;
 
 import java.awt.Container;
@@ -31,168 +31,168 @@ import java.util.Map;
 
 import javajs.awt.Dimension;
 
-import org.jmol.api.JmolAppConsoleInterface;
-import org.jmol.console.AppletConsole;
-import org.jmol.java.BS;
+//import org.jmol.api.JmolAppConsoleInterface;
+//import org.jmol.console.AppletConsole;
+//import org.jmol.java.BS;
 
-class AppletJmolBinding extends JalviewJmolBinding
+class AppletJmolBinding //extends JalviewJmolBinding
 {
 
-  /**
-   * Window that contains the bound Jmol instance
-   */
-  private AppletJmol appletJmolBinding;
-
-  public AppletJmolBinding(AppletJmol appletJmol,
-          StructureSelectionManager sSm, PDBEntry[] pdbentry,
-          SequenceI[][] seq, String[][] chains, String protocol)
-  {
-    super(sSm, pdbentry, seq, chains, protocol);
-    appletJmolBinding = appletJmol;
-  }
-
-  @Override
-  public jalview.api.FeatureRenderer getFeatureRenderer(
-          AlignmentViewPanel alignment)
-  {
-    AlignmentPanel ap = (AlignmentPanel) alignment;
-    if (appletJmolBinding.ap.av.isShowSequenceFeatures())
-    {
-      if (appletJmolBinding.fr == null)
-      {
-        appletJmolBinding.fr = new jalview.appletgui.FeatureRenderer(
-                appletJmolBinding.ap.av);
-      }
-
-      appletJmolBinding.fr
-              .transferSettings(appletJmolBinding.ap.seqPanel.seqCanvas
-                      .getFeatureRenderer());
-    }
-
-    return appletJmolBinding.fr;
-  }
-
-  @Override
-  public jalview.api.SequenceRenderer getSequenceRenderer(
-          AlignmentViewPanel alignment)
-  {
-    return new SequenceRenderer(((AlignmentPanel) alignment).av);
-  }
-
-  @Override
-  public void sendConsoleEcho(String strEcho)
-  {
-    if (appletJmolBinding.scriptWindow == null)
-    {
-      appletJmolBinding.showConsole(true);
-    }
-
-    appletJmolBinding.history.append("\n" + strEcho);
-  }
-
-  @Override
-  public void sendConsoleMessage(String strStatus)
-  {
-    if (appletJmolBinding.history != null && strStatus != null
-            && !strStatus.equals("Script completed"))
-    {
-      appletJmolBinding.history.append("\n" + strStatus);
-    }
-  }
-
-  @Override
-  public void showUrl(String url, String target)
-  {
-    appletJmolBinding.ap.alignFrame.showURL(url, target);
-
-  }
-
-  @Override
-  public void refreshGUI()
-  {
-    appletJmolBinding.updateTitleAndMenus();
-  }
-
-  public void updateColours(Object source)
-  {
-    AlignmentPanel ap = (AlignmentPanel) source;
-    colourBySequence(ap);
-  }
-
-  public void showUrl(String url)
-  {
-    try
-    {
-      appletJmolBinding.ap.av.applet.getAppletContext().showDocument(
-              new java.net.URL(url), "jmol");
-    } catch (java.net.MalformedURLException ex)
-    {
-    }
-  }
-
-  public void newJmolPopup(boolean translateLocale, String menuName,
-          boolean asPopup)
-  {
-    // jmolpopup = new JmolAwtPopup(); // is this used?
-    // jmolpopup.jpiInitialize((viewer), menuName);
-  }
-
-  @Override
-  public void notifyScriptTermination(String strStatus, int msWalltime)
-  {
-    // do nothing.
-  }
-
-  public void selectionChanged(BS arg0)
-  {
-    // TODO Auto-generated method stub
-
-  }
-
-  @Override
-  public void refreshPdbEntries()
-  {
-    // noop
-  }
-
-  @Override
-  public void showConsole(boolean show)
-  {
-    appletJmolBinding.showConsole(show);
-  }
-
-  @Override
-  protected JmolAppConsoleInterface createJmolConsole(
-          Container consolePanel, String buttonsToShow)
-  {
-    JmolAppConsoleInterface appc = new AppletConsole();
-    appc.start(viewer);
-    return appc;
-  }
-
-  @Override
-  protected void releaseUIResources()
-  {
-    appletJmolBinding = null;
-    closeConsole();
-  }
-
-  @Override
-  public void releaseReferences(Object svl)
-  {
-  }
-
-  @Override
-  public Dimension resizeInnerPanel(String data)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  public Map<String, Object> getJSpecViewProperty(String arg0)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
+//  /**
+//   * Window that contains the bound Jmol instance
+//   */
+//  private AppletJmol appletJmolBinding;
+//
+//  public AppletJmolBinding(AppletJmol appletJmol,
+//          StructureSelectionManager sSm, PDBEntry[] pdbentry,
+//          SequenceI[][] seq, String[][] chains, String protocol)
+//  {
+//    super(sSm, pdbentry, seq, chains, protocol);
+//    appletJmolBinding = appletJmol;
+//  }
+//
+//  @Override
+//  public jalview.api.FeatureRenderer getFeatureRenderer(
+//          AlignmentViewPanel alignment)
+//  {
+//    AlignmentPanel ap = (AlignmentPanel) alignment;
+//    if (appletJmolBinding.ap.av.isShowSequenceFeatures())
+//    {
+//      if (appletJmolBinding.fr == null)
+//      {
+//        appletJmolBinding.fr = new jalview.appletgui.FeatureRenderer(
+//                appletJmolBinding.ap.av);
+//      }
+//
+//      appletJmolBinding.fr
+//              .transferSettings(appletJmolBinding.ap.seqPanel.seqCanvas
+//                      .getFeatureRenderer());
+//    }
+//
+//    return appletJmolBinding.fr;
+//  }
+//
+//  @Override
+//  public jalview.api.SequenceRenderer getSequenceRenderer(
+//          AlignmentViewPanel alignment)
+//  {
+//    return new SequenceRenderer(((AlignmentPanel) alignment).av);
+//  }
+//
+//  @Override
+//  public void sendConsoleEcho(String strEcho)
+//  {
+//    if (appletJmolBinding.scriptWindow == null)
+//    {
+//      appletJmolBinding.showConsole(true);
+//    }
+//
+//    appletJmolBinding.history.append("\n" + strEcho);
+//  }
+//
+//  @Override
+//  public void sendConsoleMessage(String strStatus)
+//  {
+//    if (appletJmolBinding.history != null && strStatus != null
+//            && !strStatus.equals("Script completed"))
+//    {
+//      appletJmolBinding.history.append("\n" + strStatus);
+//    }
+//  }
+//
+//  @Override
+//  public void showUrl(String url, String target)
+//  {
+//    appletJmolBinding.ap.alignFrame.showURL(url, target);
+//
+//  }
+//
+//  @Override
+//  public void refreshGUI()
+//  {
+//    appletJmolBinding.updateTitleAndMenus();
+//  }
+//
+//  public void updateColours(Object source)
+//  {
+//    AlignmentPanel ap = (AlignmentPanel) source;
+//    colourBySequence(ap);
+//  }
+//
+//  public void showUrl(String url)
+//  {
+//    try
+//    {
+//      appletJmolBinding.ap.av.applet.getAppletContext().showDocument(
+//              new java.net.URL(url), "jmol");
+//    } catch (java.net.MalformedURLException ex)
+//    {
+//    }
+//  }
+//
+//  public void newJmolPopup(boolean translateLocale, String menuName,
+//          boolean asPopup)
+//  {
+//    // jmolpopup = new JmolAwtPopup(); // is this used?
+//    // jmolpopup.jpiInitialize((viewer), menuName);
+//  }
+//
+//  @Override
+//  public void notifyScriptTermination(String strStatus, int msWalltime)
+//  {
+//    // do nothing.
+//  }
+//
+//  public void selectionChanged(BS arg0)
+//  {
+//    // TODO Auto-generated method stub
+//
+//  }
+//
+//  @Override
+//  public void refreshPdbEntries()
+//  {
+//    // noop
+//  }
+//
+//  @Override
+//  public void showConsole(boolean show)
+//  {
+//    appletJmolBinding.showConsole(show);
+//  }
+//
+//  @Override
+//  protected JmolAppConsoleInterface createJmolConsole(
+//          Container consolePanel, String buttonsToShow)
+//  {
+//    JmolAppConsoleInterface appc = new AppletConsole();
+//    appc.start(viewer);
+//    return appc;
+//  }
+//
+//  @Override
+//  protected void releaseUIResources()
+//  {
+//    appletJmolBinding = null;
+//    closeConsole();
+//  }
+//
+//  @Override
+//  public void releaseReferences(Object svl)
+//  {
+//  }
+//
+//  @Override
+//  public Dimension resizeInnerPanel(String data)
+//  {
+//    // TODO Auto-generated method stub
+//    return null;
+//  }
+//
+//  @Override
+//  public Map<String, Object> getJSpecViewProperty(String arg0)
+//  {
+//    // TODO Auto-generated method stub
+//    return null;
+//  }
 }
index 20f61b5..a286a44 100644 (file)
@@ -32,19 +32,21 @@ import jalview.io.AppletFormatAdapter;
 import jalview.io.FileParse;
 import jalview.io.IdentifyFile;
 import jalview.io.NewickFile;
+import jalview.io.AlignFile;
 import jalview.io.TCoffeeScoreFile;
+import jalview.jsdev.GenericFileAdapter;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
+import awt2swing.Button;
 import java.awt.Dialog;
 import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.TextArea;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Panel;
+import awt2swing.TextArea;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseEvent;
@@ -357,7 +359,7 @@ public class CutAndPasteTransfer extends Panel implements ActionListener,
     TCoffeeScoreFile tcf = null;
     try
     {
-      tcf = new TCoffeeScoreFile(textarea.getText(),
+      tcf = (TCoffeeScoreFile) GenericFileAdapter.getFile("TCoffeeScoreFile", textarea.getText(),
               AppletFormatAdapter.PASTE);
       if (tcf.isValid())
       {
@@ -426,16 +428,16 @@ public class CutAndPasteTransfer extends Panel implements ActionListener,
     PDBEntry pdb = new PDBEntry();
     pdb.setFile(text);
 
-    if (alignFrame.alignPanel.av.applet.jmolAvailable)
-    {
+//    if (alignFrame.alignPanel.av.applet.jmolAvailable)
+//    {
       new AppletJmol(pdb, new SequenceI[]
       { seq }, null, alignFrame.alignPanel, AppletFormatAdapter.PASTE);
-    }
-    else
-    {
-      new MCview.AppletPDBViewer(pdb, new SequenceI[]
-      { seq }, null, alignFrame.alignPanel, AppletFormatAdapter.PASTE);
-    }
+//    }
+//    else
+//    {
+//      new MCview.AppletPDBViewer(pdb, new SequenceI[]
+//      { seq }, null, alignFrame.alignPanel, AppletFormatAdapter.PASTE);
+//    }
   }
 
   protected void cancel()
index 2f6469b..1e984be 100644 (file)
@@ -22,10 +22,10 @@ package jalview.appletgui;
 
 import java.awt.BorderLayout;
 import java.awt.Font;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.TextField;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Panel;
+import awt2swing.TextField;
 
 public class EditNameDialog extends JVDialog
 {
index a26202b..afb2c1e 100644 (file)
@@ -26,18 +26,21 @@ import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.Font;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.HeadlessException;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.Panel;
-import java.awt.PopupMenu;
+import awt2swing.Label;
+import awt2swing.Menu;
+import awt2swing.MenuBar;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.PopupMenu;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.swing.JMenuItem;
+
 /**
  * This class implements a pattern for embedding toolbars as a panel with popups
  * for situations where the system menu bar is either invisible or
@@ -91,7 +94,7 @@ public class EmbmenuFrame extends Frame implements MouseListener
    */
   protected boolean embedMenuIfNeeded(Panel tobeAdjusted)
   {
-    MenuBar topMenuBar = getMenuBar();
+    MenuBar topMenuBar = (MenuBar) getJMenuBar();
     if (topMenuBar == null)
     {
       return false;
@@ -101,7 +104,7 @@ public class EmbmenuFrame extends Frame implements MouseListener
     {
       // Build the embedded menu panel, allowing override with system font
       embeddedMenu = makeEmbeddedPopupMenu(topMenuBar, true, false);
-      setMenuBar(null);
+      unsetMenuBar();
       // add the components to the Panel area.
       add(embeddedMenu, BorderLayout.NORTH);
       tobeAdjusted.setSize(getSize().width,
@@ -162,6 +165,7 @@ public class EmbmenuFrame extends Frame implements MouseListener
           Panel embeddedMenu,
           MouseListener clickHandler)
   {
+  
     if (overrideFonts)
     {
       Font mbf = menuBar.getFont();
@@ -180,7 +184,7 @@ public class EmbmenuFrame extends Frame implements MouseListener
     // loop thru
     for (int mbi = 0, nMbi = menuBar.getMenuCount(); mbi < nMbi; mbi++)
     {
-      Menu mi = menuBar.getMenu(mbi);
+      Menu mi = (Menu) menuBar.getMenu(mbi);
       Label elab = new Label(mi.getLabel());
       elab.setFont(font);
       // add the menu entries
@@ -188,7 +192,11 @@ public class EmbmenuFrame extends Frame implements MouseListener
       int m, mSize = mi.getItemCount();
       for (m = 0; m < mSize; m++)
       {
-        popup.add(mi.getItem(m));
+       // BH slight difference in Swing -- no actual item separator, just null
+       if (mi.getItem(m) == null)
+               popup.addSeparator();
+       else
+               popup.add(mi.getItem(m));
         mSize--;
         m--;
       }
index c1035bd..3f5a436 100644 (file)
@@ -25,7 +25,10 @@ import jalview.api.FeatureRenderer;
 import jalview.api.SequenceRenderer;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
-import jalview.ext.jmol.JalviewJmolBinding;
+//import jalview.ext.jmol.JalviewJmolBinding;
+import jalview.structure.AtomSpec;
+import jalview.structure.StructureSelectionManager;
+import jalview.structures.models.AAStructureBindingModel;
 
 import java.awt.Container;
 import java.util.ArrayList;
@@ -33,8 +36,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
-import org.jmol.api.JmolAppConsoleInterface;
-import org.jmol.java.BS;
+//import org.jmol.api.JmolAppConsoleInterface;
+//import org.jmol.java.BS;
 import org.jmol.viewer.Viewer;
 
 /**
@@ -43,165 +46,195 @@ import org.jmol.viewer.Viewer;
  * @author JimP
  * 
  */
-public class ExtJmol extends JalviewJmolBinding
+public class ExtJmol  extends AAStructureBindingModel //extends JalviewJmolBinding
 {
 
-  private AlignmentPanel ap;
-
-  protected ExtJmol(jalview.appletgui.AlignFrame alframe,
-          PDBEntry[] pdbentry, SequenceI[][] seq, String[][] chains,
-          String protocol)
-  {
-    super(alframe.alignPanel.getStructureSelectionManager(), pdbentry, seq,
-            chains, protocol);
-  }
-
-  public ExtJmol(Viewer viewer, AlignmentPanel alignPanel,
-          SequenceI[][] seqs)
-  {
-    super(alignPanel.getStructureSelectionManager(), seqs, viewer);
-    ap = alignPanel;
-    notifyFileLoaded(null, null, null, null, 0);
-  }
-
-  public void updateColours(Object source)
-  {
-
-    // TODO Auto-generated method stub
-
-  }
-
-  public void showUrl(String arg0)
-  {
-    showUrl(arg0, "jmol");
-  }
-
-  @Override
-  public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
-  {
-    AlignmentPanel ap = (AlignmentPanel) alignment;
-    if (ap.av.isShowSequenceFeatures())
-    {
-      return ap.getFeatureRenderer();
-    }
-    else
-    {
-      return null;
-    }
-  }
-
-  @Override
-  public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
-  {
-    return ((AlignmentPanel) alignment).getSequenceRenderer();
-  }
-
-  @Override
-  public void notifyScriptTermination(String strStatus, int msWalltime)
-  {
-    // ignore
-  }
-
-  @Override
-  public void sendConsoleEcho(String strEcho)
-  {
-    // ignore
-  }
-
-  @Override
-  public void sendConsoleMessage(String strStatus)
-  {
-    // ignore
-  }
-
-  @Override
-  public void showUrl(String url, String target)
-  {
-    ap.alignFrame.showURL(url, target);
-  }
-
-  @Override
-  public void refreshGUI()
-  {
-    // ignore
-  }
-
-  public void selectionChanged(BS arg0)
-  {
-    System.out.println(arg0);
-  }
-
-  @Override
-  public void refreshPdbEntries()
-  {
-    List<PDBEntry> pdbe = new ArrayList<PDBEntry>();
-    List<String> fileids = new ArrayList<String>();
-    SequenceI[] sq = ap.av.getAlignment().getSequencesArray();
-    for (int s = 0; s < sq.length; s++)
-    {
-      Vector<PDBEntry> pdbids = sq[s].getPDBId();
-      if (pdbids != null)
-      {
-        for (int pe = 0, peSize = pdbids.size(); pe < peSize; pe++)
-        {
-          PDBEntry pentry = pdbids.elementAt(pe);
-          if (!fileids.contains(pentry.getId()))
-          {
-            pdbe.add(pentry);
-          }
-          else
-          {
-            fileids.add(pentry.getId());
-          }
-        }
-      }
-    }
-    PDBEntry[] newEntries = new PDBEntry[pdbe.size()];
-    for (int pe = 0; pe < pdbe.size(); pe++)
-    {
-      newEntries[pe] = pdbe.get(pe);
-    }
-    setPdbentry(newEntries);
-  }
-
-  @Override
-  public void showConsole(boolean show)
-  {
-    // This never gets called because we haven't overriden the associated Jmol's
-    // console
-    System.err
-            .println("WARNING: unexpected call to ExtJmol's showConsole method. (showConsole="
-                    + show);
-  }
-
-  @Override
-  protected JmolAppConsoleInterface createJmolConsole(
-          Container consolePanel, String buttonsToShow)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
-  @Override
-  protected void releaseUIResources()
-  {
-    ap = null;
-    closeConsole();
-
-  }
-
-  @Override
-  public void releaseReferences(Object svl)
-  {
-    // TODO Auto-generated method stub
-
-  }
-
-  @Override
-  public Map<String, Object> getJSpecViewProperty(String arg0)
-  {
-    // TODO Auto-generated method stub
-    return null;
-  }
-
+       public ExtJmol(StructureSelectionManager ssm, PDBEntry[] pdbentry,
+                       SequenceI[][] sequenceIs, String[][] chains, String protocol) {
+               super(ssm, pdbentry, sequenceIs, chains, protocol);
+               // TODO Auto-generated constructor stub
+       }
+
+       @Override
+       public String[] getPdbFile() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public void updateColours(Object source) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       public void releaseReferences(Object svl) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       public void highlightAtoms(List<AtomSpec> atoms) {
+               // TODO Auto-generated method stub
+               
+       }
+
+//  private AlignmentPanel ap;
+//
+//  protected ExtJmol(jalview.appletgui.AlignFrame alframe,
+//          PDBEntry[] pdbentry, SequenceI[][] seq, String[][] chains,
+//          String protocol)
+//  {
+//    super(alframe.alignPanel.getStructureSelectionManager(), pdbentry, seq,
+//            chains, protocol);
+//  }
+//
+//  public ExtJmol(Viewer viewer, AlignmentPanel alignPanel,
+//          SequenceI[][] seqs)
+//  {
+//    super(alignPanel.getStructureSelectionManager(), seqs, viewer);
+//    ap = alignPanel;
+//    notifyFileLoaded(null, null, null, null, 0);
+//  }
+//
+//  public void updateColours(Object source)
+//  {
+//
+//    // TODO Auto-generated method stub
+//
+//  }
+//
+//  public void showUrl(String arg0)
+//  {
+//    showUrl(arg0, "jmol");
+//  }
+//
+//  @Override
+//  public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+//  {
+//    AlignmentPanel ap = (AlignmentPanel) alignment;
+//    if (ap.av.isShowSequenceFeatures())
+//    {
+//      return ap.getFeatureRenderer();
+//    }
+//    else
+//    {
+//      return null;
+//    }
+//  }
+//
+//  @Override
+//  public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
+//  {
+//    return ((AlignmentPanel) alignment).getSequenceRenderer();
+//  }
+//
+//  @Override
+//  public void notifyScriptTermination(String strStatus, int msWalltime)
+//  {
+//    // ignore
+//  }
+//
+//  @Override
+//  public void sendConsoleEcho(String strEcho)
+//  {
+//    // ignore
+//  }
+//
+//  @Override
+//  public void sendConsoleMessage(String strStatus)
+//  {
+//    // ignore
+//  }
+//
+//  @Override
+//  public void showUrl(String url, String target)
+//  {
+//    ap.alignFrame.showURL(url, target);
+//  }
+//
+//  @Override
+//  public void refreshGUI()
+//  {
+//    // ignore
+//  }
+//
+//  public void selectionChanged(BS arg0)
+//  {
+//    System.out.println(arg0);
+//  }
+//
+//  @Override
+//  public void refreshPdbEntries()
+//  {
+//    List<PDBEntry> pdbe = new ArrayList<PDBEntry>();
+//    List<String> fileids = new ArrayList<String>();
+//    SequenceI[] sq = ap.av.getAlignment().getSequencesArray();
+//    for (int s = 0; s < sq.length; s++)
+//    {
+//      Vector<PDBEntry> pdbids = sq[s].getPDBId();
+//      if (pdbids != null)
+//      {
+//        for (int pe = 0, peSize = pdbids.size(); pe < peSize; pe++)
+//        {
+//          PDBEntry pentry = pdbids.elementAt(pe);
+//          if (!fileids.contains(pentry.getId()))
+//          {
+//            pdbe.add(pentry);
+//          }
+//          else
+//          {
+//            fileids.add(pentry.getId());
+//          }
+//        }
+//      }
+//    }
+//    PDBEntry[] newEntries = new PDBEntry[pdbe.size()];
+//    for (int pe = 0; pe < pdbe.size(); pe++)
+//    {
+//      newEntries[pe] = pdbe.get(pe);
+//    }
+//    setPdbentry(newEntries);
+//  }
+//
+//  @Override
+//  public void showConsole(boolean show)
+//  {
+//    // This never gets called because we haven't overriden the associated Jmol's
+//    // console
+//    System.err
+//            .println("WARNING: unexpected call to ExtJmol's showConsole method. (showConsole="
+//                    + show);
+//  }
+//
+//  @Override
+//  protected JmolAppConsoleInterface createJmolConsole(
+//          Container consolePanel, String buttonsToShow)
+//  {
+//    // TODO Auto-generated method stub
+//    return null;
+//  }
+//
+//  @Override
+//  protected void releaseUIResources()
+//  {
+//    ap = null;
+//    closeConsole();
+//
+//  }
+//
+//  @Override
+//  public void releaseReferences(Object svl)
+//  {
+//    // TODO Auto-generated method stub
+//
+//  }
+//
+//  @Override
+//  public Map<String, Object> getJSpecViewProperty(String arg0)
+//  {
+//    // TODO Auto-generated method stub
+//    return null;
+//  }
+//
 }
index 915d27f..fbc47c3 100644 (file)
@@ -25,18 +25,18 @@ import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.GraduatedColor;
 import jalview.util.MessageManager;
 
-import java.awt.Checkbox;
-import java.awt.Choice;
+import awt2swing.Checkbox;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.GridLayout;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.Scrollbar;
-import java.awt.TextField;
+import awt2swing.Label;
+import awt2swing.Panel;
+import awt2swing.Scrollbar;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
index 8a0e528..2d996c7 100644 (file)
@@ -31,18 +31,18 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Choice;
+import awt2swing.Button;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.GridLayout;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.ScrollPane;
-import java.awt.TextArea;
-import java.awt.TextField;
+import awt2swing.Label;
+import awt2swing.Panel;
+import awt2swing.ScrollPane;
+import awt2swing.TextArea;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Hashtable;
@@ -156,7 +156,7 @@ public class FeatureRenderer extends
       super(null);
     }
 
-    public void paint(Graphics g)
+    public void PaintComponent(Graphics g)
     {
       Dimension d = getSize();
       if (isGcol)
index 8984390..d8a6140 100755 (executable)
@@ -29,23 +29,23 @@ import jalview.schemes.GraduatedColor;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Checkbox;
+import awt2swing.Button;
+import awt2swing.Checkbox;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
 import java.awt.GridLayout;
 import java.awt.Image;
-import java.awt.Label;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.PopupMenu;
-import java.awt.ScrollPane;
-import java.awt.Scrollbar;
+import awt2swing.Label;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.PopupMenu;
+import awt2swing.ScrollPane;
+import awt2swing.Scrollbar;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
@@ -184,7 +184,7 @@ public class FeatureSettings extends Panel implements ItemListener,
             height);
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     g.setColor(Color.black);
     g.drawString(MessageManager
@@ -202,10 +202,10 @@ public class FeatureSettings extends Panel implements ItemListener,
   {
     final String type = check.type;
     final Object typeCol = fr.getFeatureStyle(type);
-    java.awt.PopupMenu men = new PopupMenu(MessageManager.formatMessage(
+    awt2swing.PopupMenu men = new PopupMenu(MessageManager.formatMessage(
             "label.settings_for_type", new String[]
             { type }));
-    java.awt.MenuItem scr = new MenuItem(
+    awt2swing.MenuItem scr = new MenuItem(
             MessageManager.getString("label.sort_by_score"));
     men.add(scr);
     final FeatureSettings me = this;
@@ -236,8 +236,8 @@ public class FeatureSettings extends Panel implements ItemListener,
     {
       final Object typeMinMax = minmax.get(type);
       /*
-       * final java.awt.CheckboxMenuItem chb = new
-       * java.awt.CheckboxMenuItem("Vary Height"); // this is broken at the
+       * final awt2swing.CheckboxMenuItem chb = new
+       * awt2swing.CheckboxMenuItem("Vary Height"); // this is broken at the
        * moment chb.setState(minmax.get(type) != null);
        * chb.addActionListener(new ActionListener() {
        * 
@@ -756,7 +756,7 @@ public class FeatureSettings extends Panel implements ItemListener,
       updateColor(featureStyle);
     }
 
-    public void paint(Graphics g)
+    public void PaintComponent(Graphics g)
     {
       Dimension d = getSize();
       if (gcol != null)
index 7315eea..885f877 100644 (file)
@@ -27,15 +27,15 @@ import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
 import jalview.viewmodel.AlignmentViewport;
 
-import java.awt.Button;
-import java.awt.Checkbox;
+import awt2swing.Button;
+import awt2swing.Checkbox;
 import java.awt.Font;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.GridLayout;
-import java.awt.Label;
-import java.awt.Panel;
+import awt2swing.Label;
+import awt2swing.Panel;
 import java.awt.Rectangle;
-import java.awt.TextField;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
index 739eeb2..f867afa 100644 (file)
@@ -25,16 +25,16 @@ import jalview.bin.JalviewLite;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Checkbox;
-import java.awt.Choice;
+import awt2swing.Button;
+import awt2swing.Checkbox;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.FontMetrics;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Panel;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Panel;
 import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
index 5204094..62cc3a0 100755 (executable)
@@ -26,7 +26,7 @@ import java.awt.Color;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.util.List;
 
 public class IdCanvas extends Panel
@@ -144,7 +144,7 @@ public class IdCanvas extends Panel
     paint(g);
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     if (getSize().height < 0 || getSize().width < 0)
     {
index c4b9651..ffd7f8e 100755 (executable)
@@ -28,7 +28,7 @@ import jalview.util.UrlLink;
 import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.BorderLayout;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
index b537112..c1b8198 100755 (executable)
@@ -24,7 +24,7 @@ import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
@@ -120,7 +120,7 @@ public class IdwidthAdjuster extends Panel implements MouseListener,
   {
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     g.setColor(Color.white);
     g.fillRect(0, 0, getSize().width, getSize().height);
index 58c4feb..fc71393 100644 (file)
 package jalview.appletgui;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
+import awt2swing.Button;
 import java.awt.Dialog;
 import java.awt.FlowLayout;
-import java.awt.Frame;
-import java.awt.Panel;
+import awt2swing.Frame;
+import awt2swing.Panel;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 
index 5c5ae84..8bc0da8 100755 (executable)
@@ -25,10 +25,10 @@ import jalview.datamodel.SequenceI;
 
 import java.awt.Color;
 import java.awt.Dimension;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.event.ComponentAdapter;
 import java.awt.event.ComponentEvent;
 import java.awt.event.MouseEvent;
@@ -467,7 +467,7 @@ public class OverviewPanel extends Panel implements Runnable,
   }
 
   @Override
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
     Graphics og = offscreen.getGraphics();
     if (miniMe != null)
index 1746736..c7e9a69 100644 (file)
@@ -30,17 +30,17 @@ import jalview.util.MessageManager;
 import jalview.viewmodel.PCAModel;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.CheckboxMenuItem;
-import java.awt.Choice;
+import awt2swing.Button;
+import awt2swing.CheckboxMenuItem;
+import awt2swing.Choice;
 import java.awt.Color;
 import java.awt.FlowLayout;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.Panel;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Menu;
+import awt2swing.MenuBar;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
index 5548795..4d6038f 100644 (file)
@@ -28,10 +28,10 @@ import jalview.util.Format;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Panel;
-import java.awt.ScrollPane;
-import java.awt.TextArea;
+import awt2swing.Button;
+import awt2swing.Panel;
+import awt2swing.ScrollPane;
+import awt2swing.TextArea;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.util.Vector;
index 9ce4f26..5611460 100644 (file)
@@ -30,7 +30,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.util.MessageManager;
 
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.event.ActionEvent;
 import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
index 63dcde0..2602e89 100755 (executable)
@@ -34,7 +34,7 @@ import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseEvent;
@@ -326,7 +326,7 @@ public class RotatableCanvas extends Panel implements MouseListener,
     paint(g);
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     if (points == null)
     {
index 3bb676f..4466238 100755 (executable)
@@ -27,9 +27,9 @@ import jalview.util.MessageManager;
 import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
-import java.awt.MenuItem;
-import java.awt.Panel;
-import java.awt.PopupMenu;
+import awt2swing.MenuItem;
+import awt2swing.Panel;
+import awt2swing.PopupMenu;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.InputEvent;
@@ -351,7 +351,7 @@ public class ScalePanel extends Panel implements MouseMotionListener,
     paint(g);
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     drawScale(g, av.getStartRes(), av.getEndRes(), getSize().width,
             getSize().height);
index 0057194..90f7745 100755 (executable)
@@ -31,7 +31,7 @@ import java.awt.Color;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
 import java.awt.Image;
-import java.awt.Panel;
+import awt2swing.Panel;
 
 public class SeqCanvas extends Panel
 {
@@ -283,7 +283,7 @@ public class SeqCanvas extends Panel
   }
 
   @Override
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
 
     if (img != null
index 348a921..1ff723a 100644 (file)
@@ -44,7 +44,7 @@ import jalview.viewmodel.AlignmentViewport;
 import java.awt.BorderLayout;
 import java.awt.Font;
 import java.awt.FontMetrics;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.Point;
 import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
index b267678..dbc94e8 100644 (file)
@@ -26,15 +26,15 @@ import jalview.schemes.ColourSchemeI;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.Button;
-import java.awt.Checkbox;
+import awt2swing.Button;
+import awt2swing.Checkbox;
 import java.awt.Color;
 import java.awt.FlowLayout;
-import java.awt.Frame;
-import java.awt.Label;
-import java.awt.Panel;
-import java.awt.Scrollbar;
-import java.awt.TextField;
+import awt2swing.Frame;
+import awt2swing.Label;
+import awt2swing.Panel;
+import awt2swing.Scrollbar;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
index 3d30800..ceab348 100644 (file)
@@ -11,7 +11,9 @@ import jalview.viewmodel.AlignmentViewport;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.GridLayout;
-import java.awt.Panel;
+
+import awt2swing.MenuBar;
+import awt2swing.Panel;
 
 public class SplitFrame extends EmbmenuFrame
 {
@@ -83,7 +85,7 @@ public class SplitFrame extends EmbmenuFrame
    */
   protected void constructSplit()
   {
-    setMenuBar(null);
+    unsetMenuBar();
     outermost = new Panel(new GridLayout(2, 1));
 
     Panel topPanel = new Panel();
@@ -95,7 +97,7 @@ public class SplitFrame extends EmbmenuFrame
     addAlignFrameComponents(bottomFrame, bottomPanel);
   }
 
-  /**
+       /**
    * Make any adjustments to the layout
    */
   protected void adjustLayout()
@@ -150,7 +152,7 @@ public class SplitFrame extends EmbmenuFrame
   {
     panel.setLayout(new BorderLayout());
     Panel menuPanel = af
-            .makeEmbeddedPopupMenu(af.getMenuBar(), true, false);
+            .makeEmbeddedPopupMenu((MenuBar) af.getJMenuBar(), true, false);
     panel.add(menuPanel, BorderLayout.NORTH);
     panel.add(af.statusBar, BorderLayout.SOUTH);
     panel.add(af.alignPanel, BorderLayout.CENTER);
index 1ae36f4..4594ba2 100644 (file)
@@ -1,10 +1,10 @@
 package jalview.appletgui;
 
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.Graphics;
 import java.awt.Insets;
-import java.awt.Label;
-import java.awt.Panel;
+import awt2swing.Label;
+import awt2swing.Panel;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 
@@ -30,9 +30,9 @@ public class TitledPanel extends Panel
     return insets;
   }
 
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
-    super.paint(g);
+    super.paintComponent(g);
     g.setColor(getForeground());
     g.drawRect(5, 5, getWidth() - 10, getHeight() - 10);
     int width = g.getFontMetrics().stringWidth(getTitle());
@@ -42,6 +42,11 @@ public class TitledPanel extends Panel
     g.drawString(getTitle(), 10, 10);
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String[] args)
   {
     Frame f = new Frame("TitledPanel Tester");
index 7a65ec3..50f90ff 100755 (executable)
 package jalview.appletgui;
 
 import java.applet.Applet;
-import java.awt.Canvas;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.FontMetrics;
-import java.awt.Frame;
 import java.awt.Graphics;
 import java.awt.Image;
 import java.awt.LayoutManager;
@@ -35,6 +33,9 @@ import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
 import java.util.StringTokenizer;
 
+import awt2swing.Canvas;
+import awt2swing.Frame;
+
 public class Tooltip extends Canvas implements MouseListener,
         MouseMotionListener
 {
@@ -76,7 +77,7 @@ public class Tooltip extends Canvas implements MouseListener,
     }
   }
 
-  public void paint(Graphics g)
+  public void PaintComponent(Graphics g)
   {
     int w = getSize().width;
     int h = getSize().height;
index 64dd412..3f149d0 100755 (executable)
@@ -40,10 +40,10 @@ import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.FontMetrics;
 import java.awt.Graphics;
-import java.awt.Panel;
+import awt2swing.Panel;
 import java.awt.Point;
 import java.awt.Rectangle;
-import java.awt.ScrollPane;
+import awt2swing.ScrollPane;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
@@ -421,7 +421,7 @@ public class TreeCanvas extends Panel implements MouseListener,
   }
 
   @Override
-  public void paint(Graphics g)
+  public void paintComponent(Graphics g)
   {
     if (tree == null)
     {
index e5971e5..4cc7fab 100644 (file)
@@ -33,12 +33,12 @@ import jalview.schemes.ResidueProperties;
 import jalview.util.MessageManager;
 
 import java.awt.BorderLayout;
-import java.awt.CheckboxMenuItem;
+import awt2swing.CheckboxMenuItem;
 import java.awt.Color;
-import java.awt.Menu;
-import java.awt.MenuBar;
-import java.awt.MenuItem;
-import java.awt.ScrollPane;
+import awt2swing.Menu;
+import awt2swing.MenuBar;
+import awt2swing.MenuItem;
+import awt2swing.ScrollPane;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.ItemEvent;
@@ -334,7 +334,7 @@ public class TreePanel extends EmbmenuFrame implements ActionListener,
     String output = fout.print(false, true);
     CutAndPasteTransfer cap = new CutAndPasteTransfer(false, null);
     cap.setText(output);
-    java.awt.Frame frame = new java.awt.Frame();
+    awt2swing.Frame frame = new awt2swing.Frame();
     frame.add(cap);
     JalviewLite.addFrame(frame, type + " " + pwtype, 500, 100);
   }
index afea10d..af8a155 100644 (file)
@@ -28,19 +28,19 @@ import jalview.schemes.ResidueProperties;
 import jalview.schemes.UserColourScheme;
 import jalview.util.MessageManager;
 
-import java.awt.Button;
+import awt2swing.Button;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dialog;
 import java.awt.Font;
-import java.awt.Frame;
+import awt2swing.Frame;
 import java.awt.GridLayout;
-import java.awt.Label;
-import java.awt.Panel;
+import awt2swing.Label;
+import awt2swing.Panel;
 import java.awt.Rectangle;
-import java.awt.Scrollbar;
-import java.awt.TextField;
+import awt2swing.Scrollbar;
+import awt2swing.TextField;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
@@ -66,7 +66,7 @@ public class UserDefinedColours extends Panel implements ActionListener,
 
   Frame frame;
 
-  MCview.AppletPDBCanvas pdbcanvas;
+//  MCview.AppletPDBCanvas pdbcanvas;
 
   AppletJmol jmol;
 
@@ -103,11 +103,11 @@ public class UserDefinedColours extends Panel implements ActionListener,
     init();
   }
 
-  public UserDefinedColours(MCview.AppletPDBCanvas pdb)
-  {
-    this.pdbcanvas = pdb;
-    init();
-  }
+//  public UserDefinedColours(MCview.AppletPDBCanvas pdb)
+//  {
+//    this.pdbcanvas = pdb;
+//    init();
+//  }
 
   public UserDefinedColours(AppletJmol jmol)
   {
@@ -515,10 +515,10 @@ public class UserDefinedColours extends Panel implements ActionListener,
     {
       jmol.setJalviewColourScheme(ucs);
     }
-    else if (pdbcanvas != null)
-    {
-      pdbcanvas.setColours(ucs);
-    }
+//    else if (pdbcanvas != null)
+//    {
+//      pdbcanvas.setColours(ucs);
+//    }
   }
 
   protected void cancelButton_actionPerformed()
@@ -596,10 +596,10 @@ public class UserDefinedColours extends Panel implements ActionListener,
     {
       jmol.setJalviewColourScheme(ucs);
     }
-    else if (pdbcanvas != null)
-    {
-      pdbcanvas.pdb.setColours(ucs);
-    }
+//    else if (pdbcanvas != null)
+//    {
+//      pdbcanvas.pdb.setColours(ucs);
+//    }
 
     frame.setVisible(false);
   }
index 4ed6e1a..49bbf6c 100755 (executable)
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- * 
- * This file is part of Jalview.
- * 
- * Jalview 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 3
- * of the License, or (at your option) any later version.
- *  
- * Jalview 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 Jalview.  If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
 package jalview.bin;
 
-import jalview.gui.UserDefinedColours;
-import jalview.io.PIRFile;
-import jalview.jbgui.GDesktop;
-import jalview.schemes.ColourSchemeProperty;
-import jalview.schemes.UserColourScheme;
-import jalview.util.Format;
-import jalview.ws.dbsources.das.api.DasSourceRegistryI;
-import jalview.ws.dbsources.das.datamodel.DasSourceRegistry;
-
-import java.awt.Color;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.TreeSet;
-
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.SimpleLayout;
-
-/**
- * Stores and retrieves Jalview Application Properties Lists and fields within
- * list entries are separated by '|' symbols unless otherwise stated (|) clauses
- * are alternative values for a tag. <br>
- * <br>
- * Current properties include:
- * <ul>
- * <br>
- * logs.Axis.Level - one of the stringified Levels for log4j controlling the
- * logging level for axis (used for web services) <br>
- * </li>
- * <li>logs.Castor.Level - one of the stringified Levels for log4j controlling
- * the logging level for castor (used for serialization) <br>
- * </li>
- * <li>logs.Jalview.Level - Cache.log stringified level. <br>
- * </li>
- * <li>SCREEN_WIDTH</li>
- * <li>SCREEN_HEIGHT</li>
- * <li>SCREEN_Y=285</li>
- * <li>SCREEN_X=371</li>
- * <li>SHOW_FULLSCREEN boolean</li>
- * <li>FONT_NAME java font name for alignment text display</li>
- * <li>FONT_SIZE size of displayed alignment text</li>
- * <li>FONT_STYLE style of font displayed (sequence labels are always italic)</li>
- * <li>GAP_SYMBOL character to treat as gap symbol (usually -,.,' ')</li>
- * <li>LAST_DIRECTORY last directory for browsing alignment</li>
- * <li>USER_DEFINED_COLOURS list of user defined colour scheme files</li>
- * <li>SHOW_FULL_ID show id with '/start-end' numbers appended</li>
- * <li>SHOW_IDENTITY show percentage identity annotation</li>
- * <li>SHOW_QUALITY show alignment quality annotation</li>
- * <li>SHOW_ANNOTATIONS show alignment annotation rows</li>
- * <li>SHOW_CONSERVATION show alignment conservation annotation</li>
- * <li>SORT_ANNOTATIONS currently either SEQUENCE_AND_LABEL or
- * LABEL_AND_SEQUENCE</li>
- * <li>SHOW_AUTOCALC_ABOVE true to show autocalculated annotations above
- * sequence annotations</li>
- * <li>CENTRE_COLUMN_LABELS centre the labels at each column in a displayed
- * annotation row</li>
- * <li>DEFAULT_COLOUR default colour scheme to apply for a new alignment</li>
- * <li>DEFAULT_FILE_FORMAT file format used to save</li>
- * <li>STARTUP_FILE file loaded on startup (may be a fully qualified url)</li>
- * <li>SHOW_STARTUP_FILE flag to control loading of startup file</li>
- * <li>VERSION the version of the jalview build</li>
- * <li>BUILD_DATE date of this build</li>
- * <li>LATEST_VERSION the latest jalview version advertised on the
- * www.jalview.org</li>
- * <li>PIR_MODELLER boolean indicating if PIR files are written with MODELLER
- * descriptions</li>
- * <li>(FASTA,MSF,PILEUP,CLUSTAL,BLC,PIR,PFAM)_JVSUFFIX boolean for adding jv
- * suffix to file</li>
- * <li>RECENT_URL list of recently retrieved URLs</li>
- * <li>RECENT_FILE list of recently opened files</li>
- * <li>USE_PROXY flag for whether a http proxy is to be used</li>
- * <li>PROXY_SERVER the proxy</li>
- * <li>PROXY_PORT</li>
- * <li>NOQUESTIONNAIRES true to prevent jalview from checking the questionnaire
- * service</li>
- * <li>QUESTIONNAIRE last questionnaire:responder id string from questionnaire
- * service</li>
- * <li>USAGESTATS (false - user prompted) Enable google analytics tracker for
- * collecting usage statistics</li>
- * <li>DAS_LOCAL_SOURCE list of local das sources</li>
- * <li>SHOW_OVERVIEW boolean for overview window display</li>
- * <li>ANTI_ALIAS boolean for smooth fonts</li>
- * <li>RIGHT_ALIGN_IDS boolean</li>
- * <li>AUTO_CALC_CONSENSUS boolean for automatic recalculation of consensus</li>
- * <li>PAD_GAPS boolean</li>
- * <li>ID_ITALICS boolean</li>
- * <li>SHOW_JV_SUFFIX</li>
- * <li>WRAP_ALIGNMENT</li>
- * <li>EPS_RENDERING (Prompt each time|Lineart|Text) default for EPS rendering
- * style check</li>
- * <li>SORT_ALIGNMENT (No sort|Id|Pairwise Identity)</li>
- * <li>SEQUENCE_LINKS list of name|URL pairs for opening a url with
- * $SEQUENCE_ID$</li>
- * <li>GROUP_LINKS list of name|URL[|&lt;separator&gt;] tuples - see
- * jalview.utils.GroupURLLink for more info</li>
- * <li>DAS_REGISTRY_URL the registry to query</li>
- * <li>DEFAULT_BROWSER for unix</li>
- * <li>DAS_ACTIVE_SOURCE list of active sources</li>
- * <li>SHOW_MEMUSAGE boolean show memory usage and warning indicator on desktop
- * (false)</li>
- * <li>VERSION_CHECK (true) check for the latest release version from
- * www.jalview.org (or the alias given by the www.jalview.org property)</li>
- * <li>SHOW_NPFEATS_TOOLTIP (true) show non-positional features in the Sequence
- * ID tooltip</li>
- * <li>SHOW_DBREFS_TOOLTIP (true) show Database Cross References in the Sequence
- * ID tooltip</li>
- * <li>SHOW_UNCONSERVED (false) only render unconserved residues - conserved
- * displayed as '.'</li>
- * <li>SORT_BY_TREE (false) sort the current alignment view according to the
- * order of a newly displayed tree</li>
- * <li>DBFETCH_USEPICR (false) use PICR to recover valid DB references from
- * sequence ID strings before attempting retrieval from any datasource</li>
- * <li>SHOW_GROUP_CONSENSUS (false) Show consensus annotation for groups in the
- * alignment.</li>
- * <li>SHOW_GROUP_CONSERVATION (false) Show conservation annotation for groups
- * in the alignment.</li>
- * <li>SHOW_CONSENSUS_HISTOGRAM (false) Show consensus annotation row's
- * histogram.</li>
- * <li>SHOW_CONSENSUS_LOGO (false) Show consensus annotation row's sequence
- * logo.</li>
- * <li>NORMALISE_CONSENSUS_LOGO (false) Show consensus annotation row's sequence
- * logo normalised to row height rather than histogram height.</li>
- * <li>FOLLOW_SELECTIONS (true) Controls whether a new alignment view should
- * respond to selections made in other alignments containing the same sequences.
- * </li>
- * <li>JWS2HOSTURLS comma-separated list of URLs to try for JABAWS services</li>
- * <li>SHOW_WSDISCOVERY_ERRORS (true) Controls if the web service URL discovery
- * warning dialog box is displayed.</li>
- * <li>ANNOTATIONCOLOUR_MIN (orange) Shade used for minimum value of annotation
- * when shading by annotation</li>
- * <li>ANNOTATIONCOLOUR_MAX (red) Shade used for maximum value of annotation
- * when shading by annotation</li>
- * <li>www.jalview.org (http://www.jalview.org) a property enabling all HTTP
- * requests to be redirected to a mirror of http://www.jalview.org</li>
- * <li>FIGURE_AUTOIDWIDTH (false) Expand the left hand column of an exported
- * alignment figure to accommodate even the longest sequence ID or annotation
- * label.</li>
- * <li>FIGURE_FIXEDIDWIDTH Specifies the width to use for the left-hand column
- * when exporting an alignment as a figure (setting FIGURE_AUTOIDWIDTH to true
- * will override this).</li>
- * <li>STRUCT_FROM_PDB (false) derive secondary structure annotation from PDB
- * record</li>
- * <li>USE_RNAVIEW (false) use RNAViewer to derive secondary structure</li>
- * <li>ADD_SS_ANN (false) add secondary structure annotation to alignment
- * display</li>
- * <li>ADD_TEMPFACT_ANN (false) add Temperature Factor annotation to alignment
- * display</li>
- * <li>STRUCTURE_DISPLAY choose from JMOL (default) or CHIMERA for 3D structure
- * display</li>
- * <li>CHIMERA_PATH specify full path to Chimera program (if non-standard)</li>
- * 
- * </ul>
- * Deprecated settings:
- * <ul>
- * *
- * <li>DISCOVERY_START - Boolean - controls if discovery services are queried on
- * startup (JWS1 services only)</li>
- * <li>DISCOVERY_URLS - comma separated list of Discovery Service endpoints.
- * (JWS1 services only)</li>
- * <li>SHOW_JWS1_SERVICES (true) enable or disable the original Jalview 2
- * services in the desktop GUI</li>
- * <li>ENABLE_RSBS_EDITOR (false for 2.7 release) enable or disable RSBS editing
- * panel in web service preferences</li>
- * </ul>
- * 
- * @author $author$
- * @version $Revision$
- */
-public class Cache
-{
-  /**
-   * property giving log4j level for CASTOR loggers
-   */
-  public static final String CASTORLOGLEVEL = "logs.Castor.level";
-
-  /**
-   * property giving log4j level for AXIS loggers
-   */
-  public static final String AXISLOGLEVEL = "logs.Axis.level";
-
-  /**
-   * property giving log4j level for Jalview Log
-   */
-  public static final String JALVIEWLOGLEVEL = "logs.Jalview.level";
-
-  public static final String DAS_LOCAL_SOURCE = "DAS_LOCAL_SOURCE";
-
-  public static final String DAS_REGISTRY_URL = "DAS_REGISTRY_URL";
-
-  public static final String DAS_ACTIVE_SOURCE = "DAS_ACTIVE_SOURCE";
-
-  /**
-   * Initialises the Jalview Application Log
-   */
-  public static Logger log;
-
-  /** Jalview Properties */
-  public static Properties applicationProperties = new Properties() {
-    // override results in properties output in alphabetical order
-    @Override
-    public synchronized Enumeration<Object> keys() {
-        return Collections.enumeration(new TreeSet<Object>(super.keySet()));
-    }
-  };
-
-  /** Default file is ~/.jalview_properties */
-  static String propertiesFile;
-
-  private static boolean propsAreReadOnly = false;
-
-  public static void initLogger()
-  {
-    if (log != null)
-    {
-      return;
-    }
-    try
-    {
-      // TODO: redirect stdout and stderr here in order to grab the output of
-      // the log
-
-      ConsoleAppender ap = new ConsoleAppender(new SimpleLayout(),
-              "System.err");
-      ap.setName("JalviewLogger");
-      org.apache.log4j.Logger.getRootLogger().addAppender(ap); // catch all for
-      // log output
-      Logger laxis = Logger.getLogger("org.apache.axis");
-      Logger lcastor = Logger.getLogger("org.exolab.castor");
-      Cache.log = Logger.getLogger("jalview.bin.Jalview");
-
-      laxis.setLevel(Level.toLevel(Cache.getDefault("logs.Axis.Level",
-              Level.INFO.toString())));
-      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-              Level.INFO.toString())));
-      lcastor = Logger.getLogger("org.exolab.castor.xml");
-      lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-              Level.INFO.toString())));
-      // lcastor = Logger.getLogger("org.exolab.castor.xml.Marshaller");
-      // lcastor.setLevel(Level.toLevel(Cache.getDefault("logs.Castor.Level",
-      // Level.INFO.toString())));
-      Cache.log.setLevel(Level.toLevel(Cache.getDefault(
-              "logs.Jalview.level", Level.INFO.toString())));
-      // laxis.addAppender(ap);
-      // lcastor.addAppender(ap);
-      // Cache.log.addAppender(ap);
-      // Tell the user that debug is enabled
-      Cache.log.debug("Jalview Debugging Output Follows.");
-    } catch (Exception ex)
-    {
-      System.err.println("Problems initializing the log4j system\n");
-      ex.printStackTrace(System.err);
-    }
-  }
-
-  /** Called when Jalview is started */
-  public static void loadProperties(String propsFile)
-  {
-    propertiesFile = propsFile;
-    if (propsFile == null)
-    {
-      propertiesFile = System.getProperty("user.home") + File.separatorChar
-              + ".jalview_properties";
-    }
-    else
-    {
-      // don't corrupt the file we've been given.
-      propsAreReadOnly = true;
-    }
-
-    try
-    {
-      InputStream fis;
-      try
-      {
-        fis = new java.net.URL(propertiesFile).openStream();
-        System.out.println("Loading jalview properties from : "
-                + propertiesFile);
-        System.out
-                .println("Disabling Jalview writing to user's local properties file.");
-        propsAreReadOnly = true;
-
-      } catch (Exception ex)
-      {
-        fis = null;
-      }
-      if (fis == null)
-      {
-        fis = new FileInputStream(propertiesFile);
-      }
-      applicationProperties.load(fis);
-      
-      // remove any old build properties
-      
-      deleteBuildProperties();
-      fis.close();
-    } catch (Exception ex)
-    {
-      System.out.println("Error reading properties file: " + ex);
-    }
-
-    if (getDefault("USE_PROXY", false))
-    {
-      String proxyServer = getDefault("PROXY_SERVER", ""), proxyPort = getDefault(
-              "PROXY_PORT", "8080");
-
-      System.out.println("Using proxyServer: " + proxyServer
-              + " proxyPort: " + proxyPort);
-
-      System.setProperty("http.proxyHost", proxyServer);
-      System.setProperty("http.proxyPort", proxyPort);
-    }
-
-    // LOAD THE AUTHORS FROM THE authors.props file
-    try
-    {
-      String authorDetails = "jar:".concat(Cache.class
-              .getProtectionDomain().getCodeSource().getLocation()
-              .toString().concat("!/authors.props"));
-
-      java.net.URL localJarFileURL = new java.net.URL(authorDetails);
-
-      InputStream in = localJarFileURL.openStream();
-      applicationProperties.load(in);
-      in.close();
-    } catch (Exception ex)
-    {
-      System.out.println("Error reading author details: " + ex);
-      applicationProperties.remove("AUTHORS");
-      applicationProperties.remove("AUTHORFNAMES");
-      applicationProperties.remove("YEAR");
-    }
-
-    // FIND THE VERSION NUMBER AND BUILD DATE FROM jalview.jar
-    // MUST FOLLOW READING OF LOCAL PROPERTIES FILE AS THE
-    // VERSION MAY HAVE CHANGED SINCE LAST USING JALVIEW
-    try
-    {
-      String buildDetails = "jar:".concat(Cache.class.getProtectionDomain()
-              .getCodeSource().getLocation().toString()
-              .concat("!/.build_properties"));
-
-      java.net.URL localJarFileURL = new java.net.URL(buildDetails);
-
-      InputStream in = localJarFileURL.openStream();
-      applicationProperties.load(in);
-      in.close();
-    } catch (Exception ex)
-    {
-      System.out.println("Error reading build details: " + ex);
-      applicationProperties.remove("VERSION");
-    }
-
-    String jnlpVersion = System.getProperty("jalview.version");
-    String codeVersion = getProperty("VERSION");
-    String codeInstallation = getProperty("INSTALLATION");
-    if (codeVersion == null)
-    {
-      // THIS SHOULD ONLY BE THE CASE WHEN TESTING!!
-      codeVersion = "Test";
-      jnlpVersion = "Test";
-      codeInstallation = "";
-    }
-    else
-    {
-      codeInstallation = " (" + codeInstallation + ")";
-    }
-
-    System.out
-            .println("Jalview Version: " + codeVersion + codeInstallation);
-
-    // jnlpVersion will be null if we're using InstallAnywhere
-    // Dont do this check if running in headless mode
-    if (jnlpVersion == null
-            && getDefault("VERSION_CHECK", true)
-            && (System.getProperty("java.awt.headless") == null || System
-                    .getProperty("java.awt.headless").equals("false")))
-    {
-
-      class VersionChecker extends Thread
-      {
-        public void run()
-        {
-          String orgtimeout = System
-                  .getProperty("sun.net.client.defaultConnectTimeout");
-          if (orgtimeout == null)
-          {
-            orgtimeout = "30";
-            System.out.println("# INFO: Setting default net timeout to "
-                    + orgtimeout + " seconds.");
-          }
-          String jnlpVersion = null;
-          try
-          {
-            System.setProperty("sun.net.client.defaultConnectTimeout",
-                    "5000");
-            java.net.URL url = new java.net.URL(Cache.getDefault(
-                    "www.jalview.org", "http://www.jalview.org")
-                    + "/webstart/jalview.jnlp");
-            BufferedReader in = new BufferedReader(new InputStreamReader(
-                    url.openStream()));
-            String line = null;
-            while ((line = in.readLine()) != null)
-            {
-              if (line.indexOf("jalview.version") == -1)
-              {
-                continue;
-              }
-
-              line = line.substring(line.indexOf("value=") + 7);
-              line = line.substring(0, line.lastIndexOf("\""));
-              jnlpVersion = line;
-              break;
-            }
-          } catch (Exception ex)
-          {
-            System.out
-                    .println("Non-fatal exceptions when checking version at www.jalview.org :");
-            System.out.println(ex);
-            jnlpVersion = getProperty("VERSION");
-          }
-          System.setProperty("sun.net.client.defaultConnectTimeout",
-                  orgtimeout);
-
-          setProperty("LATEST_VERSION", jnlpVersion);
-        }
-      }
-
-      VersionChecker vc = new VersionChecker();
-      vc.start();
-    }
-    else
-    {
-      if (jnlpVersion != null)
-      {
-        setProperty("LATEST_VERSION", jnlpVersion);
-      }
-      else
-      {
-        applicationProperties.remove("LATEST_VERSION");
-      }
-    }
-
-    setProperty("VERSION", codeVersion);
-
-    // LOAD USERDEFINED COLOURS
-    UserDefinedColours
-            .initUserColourSchemes(getProperty("USER_DEFINED_COLOURS"));
-    PIRFile.useModellerOutput = Cache.getDefault("PIR_MODELLER",
-            false);
-  }
-
-  private static void deleteBuildProperties()
-  {
-    applicationProperties.remove("LATEST_VERSION");
-    applicationProperties.remove("VERSION");
-    applicationProperties.remove("AUTHORS");
-    applicationProperties.remove("AUTHORFNAMES");
-    applicationProperties.remove("YEAR");
-    applicationProperties.remove("BUILD_DATE");
-    applicationProperties.remove("INSTALLATION");
-  }
-
-  /**
-   * Gets Jalview application property of given key. Returns null if key not
-   * found
-   * 
-   * @param key
-   *          Name of property
-   * 
-   * @return Property value
-   */
-  public static String getProperty(String key)
-  {
-    return applicationProperties.getProperty(key);
-  }
-
-  /**
-   * These methods are used when checking if the saved preference is different
-   * to the default setting
-   */
-
-  public static boolean getDefault(String property, boolean def)
-  {
-    String string = getProperty(property);
-    if (string != null)
-    {
-      def = Boolean.valueOf(string).booleanValue();
-    }
-
-    return def;
-  }
-
-  /**
-   * These methods are used when checking if the saved preference is different
-   * to the default setting
-   */
-  public static String getDefault(String property, String def)
-  {
-    String string = getProperty(property);
-    if (string != null)
-    {
-      return string;
-    }
-
-    return def;
-  }
-
-  /**
-   * Stores property in the file "HOME_DIR/.jalview_properties"
-   * 
-   * @param key
-   *          Name of object
-   * @param obj
-   *          String value of property
-   * 
-   * @return String value of property
-   */
-  public static String setProperty(String key, String obj)
-  {
-
-    try
-    {
-      applicationProperties.setProperty(key, obj);
-      if (!propsAreReadOnly)
-      {
-        FileOutputStream out = new FileOutputStream(propertiesFile);
-        applicationProperties.store(out, "---JalviewX Properties File---");
-        out.close();
-      }
-    } catch (Exception ex)
-    {
-      System.out.println("Error setting property: " + key + " " + obj
-              + "\n" + ex);
-    }
-    return obj;
-  }
-
-  /**
-   * remove the specified property from the jalview properties file
-   * 
-   * @param string
-   */
-  public static void removeProperty(String string)
-  {
-    applicationProperties.remove(string);
-    saveProperties();
-  }
-
-  /**
-   * save the properties to the jalview properties path
-   */
-  public static void saveProperties()
-  {
-    if (!propsAreReadOnly)
-    {
-      try
-      {
-        FileOutputStream out = new FileOutputStream(propertiesFile);
-        applicationProperties.store(out, "---JalviewX Properties File---");
-        out.close();
-      } catch (Exception ex)
-      {
-        System.out.println("Error saving properties: " + ex);
-      }
-    }
-  }
-
-  /**
-   * internal vamsas class discovery state
-   */
-  private static int vamsasJarsArePresent = -1;
-
-  /**
-   * Searches for vamsas client classes on class path.
-   * 
-   * @return true if vamsas client is present on classpath
-   */
-  public static boolean vamsasJarsPresent()
-  {
-    if (vamsasJarsArePresent == -1)
-    {
-      try
-      {
-        if (GDesktop.class.getClassLoader().loadClass(
-                "uk.ac.vamsas.client.VorbaId") != null)
-        {
-          Cache.log
-                  .debug("Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)");
-          vamsasJarsArePresent = 1;
-          Logger lvclient = Logger.getLogger("uk.ac.vamsas");
-          lvclient.setLevel(Level.toLevel(Cache.getDefault(
-                  "logs.Vamsas.Level", Level.INFO.toString())));
-
-          lvclient.addAppender(log.getAppender("JalviewLogger"));
-          // Tell the user that debug is enabled
-          lvclient.debug("Jalview Vamsas Client Debugging Output Follows.");
-        }
-      } catch (Exception e)
-      {
-        vamsasJarsArePresent = 0;
-        Cache.log.debug("Vamsas Classes are not present");
-      }
-    }
-    return (vamsasJarsArePresent > 0);
-  }
-
-  /**
-   * internal vamsas class discovery state
-   */
-  private static int groovyJarsArePresent = -1;
-
-  /**
-   * Searches for vamsas client classes on class path.
-   * 
-   * @return true if vamsas client is present on classpath
-   */
-  public static boolean groovyJarsPresent()
-  {
-    if (groovyJarsArePresent == -1)
-    {
-      try
-      {
-        if (Cache.class.getClassLoader().loadClass(
-                "groovy.lang.GroovyObject") != null)
-        {
-          Cache.log
-                  .debug("Found Groovy (groovy.lang.GroovyObject can be loaded)");
-          groovyJarsArePresent = 1;
-          Logger lgclient = Logger.getLogger("groovy");
-          lgclient.setLevel(Level.toLevel(Cache.getDefault(
-                  "logs.Groovy.Level", Level.INFO.toString())));
-
-          lgclient.addAppender(log.getAppender("JalviewLogger"));
-          // Tell the user that debug is enabled
-          lgclient.debug("Jalview Groovy Client Debugging Output Follows.");
-        }
-      } catch (Error e)
-      {
-        groovyJarsArePresent = 0;
-        Cache.log.debug("Groovy Classes are not present", e);
-      } catch (Exception e)
-      {
-        groovyJarsArePresent = 0;
-        Cache.log.debug("Groovy Classes are not present");
-      }
-    }
-    return (groovyJarsArePresent > 0);
-  }
-
-  /**
-   * GA tracker object - actually JGoogleAnalyticsTracker null if tracking not
-   * enabled.
-   */
-  protected static Object tracker = null;
-
-  protected static Class trackerfocus = null;
-
-  protected static Class jgoogleanalyticstracker = null;
-
-  /**
-   * Initialise the google tracker if it is not done already.
-   */
-  public static void initGoogleTracker()
-  {
-    if (tracker == null)
-    {
-      if (jgoogleanalyticstracker == null)
-      {
-        // try to get the tracker class
-        try
-        {
-          jgoogleanalyticstracker = Cache.class
-                  .getClassLoader()
-                  .loadClass(
-                          "com.boxysystems.jgoogleanalytics.JGoogleAnalyticsTracker");
-          trackerfocus = Cache.class.getClassLoader().loadClass(
-                  "com.boxysystems.jgoogleanalytics.FocusPoint");
-        } catch (Exception e)
-        {
-          log.debug("com.boxysystems.jgoogleanalytics package is not present - tracking not enabled.");
-          tracker = null;
-          jgoogleanalyticstracker = null;
-          trackerfocus = null;
-          return;
-        }
-      }
-      // now initialise tracker
-      Exception re = null, ex = null;
-      Error err = null;
-      String vrs = "No Version Accessible";
-      try
-      {
-        // Google analytics tracking code for Library Finder
-        tracker = jgoogleanalyticstracker.getConstructor(new Class[]
-        { String.class, String.class, String.class }).newInstance(
-                new Object[]
-                {
-                    "Jalview Desktop",
-                    (vrs = Cache.getProperty("VERSION")
-                            + "_"
-                            + Cache.getDefault("BUILD_DATE",
-                                    "unknown")), "UA-9060947-1" });
-        jgoogleanalyticstracker.getMethod("trackAsynchronously",
-                new Class[]
-                { trackerfocus }).invoke(tracker, new Object[]
-        { trackerfocus.getConstructor(new Class[]
-        { String.class }).newInstance(new Object[]
-        { "Application Started." }) });
-      } catch (RuntimeException e)
-      {
-        re = e;
-      } catch (Exception e)
-      {
-        ex = e;
-      } catch (Error e)
-      {
-        err = e;
-      }
-      if (re != null || ex != null || err != null)
-      {
-        if (log != null)
-        {
-          if (re != null)
-          {
-            log.debug("Caught runtime exception in googletracker init:", re);
-          }
-          if (ex != null)
-          {
-            log.warn(
-                    "Failed to initialise GoogleTracker for Jalview Desktop with version "
-                            + vrs, ex);
-          }
-          if (err != null)
-          {
-            log.error(
-                    "Whilst initing GoogleTracker for Jalview Desktop version "
-                            + vrs, err);
-          }
-        }
-        else
-        {
-          if (re != null)
-          {
-            System.err
-                    .println("Debug: Caught runtime exception in googletracker init:"
-                            + vrs);
-            re.printStackTrace();
-          }
-          if (ex != null)
-          {
-            System.err
-                    .println("Warning:  Failed to initialise GoogleTracker for Jalview Desktop with version "
-                            + vrs);
-            ex.printStackTrace();
-          }
-
-          if (err != null)
-          {
-            System.err
-                    .println("ERROR: Whilst initing GoogleTracker for Jalview Desktop version "
-                            + vrs);
-            err.printStackTrace();
-          }
-        }
-      }
-      else
-      {
-        log.debug("Successfully initialised tracker.");
-      }
-    }
-  }
-
-  /**
-   * get the user's default colour if available
-   * 
-   * @param property
-   * @param defcolour
-   * @return
-   */
-  public static Color getDefaultColour(String property, Color defcolour)
-  {
-    String colprop = getProperty(property);
-    if (colprop == null)
-    {
-      return defcolour;
-    }
-    Color col = ColourSchemeProperty.getAWTColorFromName(colprop);
-    if (col == null)
-    {
-      try
-      {
-        col = new UserColourScheme(colprop).findColour('A');
-      } catch (Exception ex)
-      {
-        log.warn("Couldn't parse '" + colprop + "' as a colour for "
-                + property);
-        col = null;
-      }
-    }
-    return (col == null) ? defcolour : col;
-  }
-
-  /**
-   * store a colour as a Jalview user default property
-   * 
-   * @param property
-   * @param colour
-   */
-  public static void setColourProperty(String property, Color colour)
-  {
-    setProperty(property, Format.getHexString(colour));
-  }
-
-  public static final DateFormat date_format = SimpleDateFormat
-          .getDateTimeInstance();
-
-  /**
-   * store a date in a jalview property
-   * 
-   * @param string
-   * @param time
-   */
-  public static void setDateProperty(String property, Date time)
-  {
-    setProperty(property, date_format.format(time));
-  }
-
-  /**
-   * read a date stored in a jalview property
-   * 
-   * @param property
-   * @return valid date as stored by setDateProperty, or null
-   * 
-   */
-  public static Date getDateProperty(String property)
-  {
-    String val = getProperty(property);
-    if (val != null)
-    {
-      try
-      {
-        return date_format.parse(val);
-      } catch (Exception ex)
-      {
-        System.err.println("Invalid or corrupt date in property '"
-                + property + "' : value was '" + val + "'");
-      }
-    }
-    return null;
-  }
-
-  /**
-   * get and parse a property as an integer. send any parsing problems to
-   * System.err
-   * 
-   * @param property
-   * @return null or Integer
-   */
-  public static Integer getIntegerProperty(String property)
-  {
-    String val = getProperty(property);
-    if (val != null && (val = val.trim()).length() > 0)
-    {
-      try
-      {
-        return Integer.valueOf(val);
-      } catch (NumberFormatException x)
-      {
-        System.err.println("Invalid integer in property '" + property
-                + "' (value was '" + val + "')");
-      }
-    }
-    return null;
-  }
-
-  private static DasSourceRegistryI sourceRegistry = null;
-
-  /**
-   * initialise and ..
-   * 
-   * @return instance of the das source registry
-   */
-  public static DasSourceRegistryI getDasSourceRegistry()
-  {
-    if (sourceRegistry == null)
-    {
-      sourceRegistry = new DasSourceRegistry();
-    }
-    return sourceRegistry;
-  }
-
-  /**
-   * Set the specified value, or remove it if null or empty. Does not save the
-   * properties file.
-   * 
-   * @param propName
-   * @param value
-   */
-  public static void setOrRemove(String propName, String value)
-  {
-    if (propName == null)
-    {
-      return;
-    }
-    if (value == null || value.trim().length() < 1)
-    {
-      Cache.applicationProperties.remove(propName);
-    }
-    else
-    {
-      Cache.applicationProperties.setProperty(propName, value);
-    }
-  }
+public class Cache {
+  public static final String CASTORLOGLEVEL = null;
+       public static Log log;
+       
+       public class Log {
+
+               public void error(String string) {
+                       // TODO Auto-generated method stub
+                       
+               }
+
+               public boolean isDebugEnabled() {
+                       // TODO Auto-generated method stub
+                       return false;
+               }
+               
+       }
+
+       public static String getDefault(String string, String string2) {
+               // TODO Auto-generated method stub
+               return null;
+       }
 }
index 5d1f0b0..3ec841a 100644 (file)
@@ -27,6 +27,10 @@ import jalview.appletgui.AlignViewport;
 import jalview.appletgui.EmbmenuFrame;
 import jalview.appletgui.FeatureSettings;
 import jalview.appletgui.SplitFrame;
+//import jalview.appletgui.AlignViewport;
+//import jalview.appletgui.EmbmenuFrame;
+//import jalview.appletgui.FeatureSettings;
+//import jalview.appletgui.SplitFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
@@ -35,12 +39,14 @@ import jalview.datamodel.PDBEntry;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.io.AlignFile;
 import jalview.io.AnnotationFile;
 import jalview.io.AppletFormatAdapter;
 import jalview.io.FileParse;
 import jalview.io.IdentifyFile;
-import jalview.io.JPredFile;
 import jalview.io.JnetAnnotationMaker;
+//import jalview.io.JPredFile;
+//import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
 import jalview.javascript.JSFunctionExec;
 import jalview.javascript.JalviewLiteJsApi;
@@ -48,19 +54,19 @@ import jalview.javascript.JsCallBack;
 import jalview.javascript.JsSelectionSender;
 import jalview.javascript.MouseOverListener;
 import jalview.javascript.MouseOverStructureListener;
+import jalview.jsdev.GenericFileAdapter;
+//import jalview.javascript.MouseOverListener;
+//import jalview.javascript.MouseOverStructureListener;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.UserColourScheme;
 import jalview.structure.SelectionListener;
 import jalview.structure.StructureSelectionManager;
 import jalview.util.MessageManager;
 
-import java.applet.Applet;
-import java.awt.Button;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.EventQueue;
 import java.awt.Font;
-import java.awt.Frame;
 import java.awt.Graphics;
 import java.awt.event.ActionEvent;
 import java.awt.event.WindowAdapter;
@@ -75,16 +81,21 @@ import java.util.List;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
-import netscape.javascript.JSException;
+import javax.swing.JApplet;
+import javax.swing.JButton;
+import javax.swing.JFrame;
+
 import netscape.javascript.JSObject;
 
+//import netscape.javascript.JSObject;
+
 /**
  * Jalview Applet. Runs in Java 1.18 runtime
  * 
  * @author $author$
  * @version $Revision: 1.92 $
  */
-public class JalviewLite extends Applet implements
+public class JalviewLite extends JApplet implements
         StructureSelectionManagerProvider, JalviewLiteJsApi
 {
 
@@ -1213,7 +1224,7 @@ public class JalviewLite extends Applet implements
   public void scrollViewToColumnIn(final AlignFrame alf,
           final String leftHandColumn)
   {
-    java.awt.EventQueue.invokeLater(new Runnable()
+    EventQueue.invokeLater(new Runnable()
     {
 
       @Override
@@ -1248,7 +1259,7 @@ public class JalviewLite extends Applet implements
 
   String file2 = null;
 
-  Button launcher = new Button(
+  JButton launcher = new JButton(
           MessageManager.getString("label.start_jalview"));
 
   /**
@@ -1378,6 +1389,7 @@ public class JalviewLite extends Applet implements
      * turn on extra applet debugging
      */
     debug = TRUE.equalsIgnoreCase(getParameter("debug"));
+    
     if (debug)
     {
 
@@ -1472,7 +1484,14 @@ public class JalviewLite extends Applet implements
     if (embedded)
     {
       LoadingThread loader = new LoadingThread(file, file2, this);
-      loader.start();
+      /**
+       * @j2sNative
+       * 
+       * loader.run();
+       */
+      {
+       loader.start();
+      }
     }
     else if (file != null)
     {
@@ -1537,7 +1556,7 @@ public class JalviewLite extends Applet implements
         {
           notFailed = true;
         }
-      } catch (JSException jsex)
+      } catch (Exception jsex)
       {
         System.err.println("Attempt " + tries
                 + " to access LiveConnect javascript failed.");
@@ -1601,7 +1620,7 @@ public class JalviewLite extends Applet implements
    * @param height
    *          height of new frame
    */
-  public static void addFrame(final Frame frame, String title, int width,
+  public static void addFrame(final JFrame frame, String title, int width,
           int height)
   {
     frame.setLocation(lastFrameX, lastFrameY);
@@ -1822,23 +1841,29 @@ public class JalviewLite extends Applet implements
       applet = _applet;
     }
 
-    public void run()
-    {
-      LoadJmolThread jmolchecker = new LoadJmolThread();
-      jmolchecker.start();
-      while (jmolchecker.notFinished())
-      {
-        // wait around until the Jmol check is complete.
-        try
-        {
-          Thread.sleep(2);
-        } catch (Exception e)
-        {
-        }
-      }
-      startLoading();
-      // applet.callInitCallback();
-    }
+               public void run() {
+                       /**
+                        * 
+                        * @j2sNative
+                        * 
+                        * 
+                        * System.out.println("BYPASSING JMOL LOADING FOR NOW. THIS WILL BE DONE ANOTHER WAY")
+                        * 
+                        */
+                       {
+                               LoadJmolThread jmolchecker = new LoadJmolThread();
+                               jmolchecker.start();
+                               while (jmolchecker.notFinished()) {
+                                       // wait around until the Jmol check is complete.
+                                       try {
+                                               Thread.sleep(2);
+                                       } catch (Exception e) {
+                                       }
+                               }
+                       }
+                       startLoading();
+                       // applet.callInitCallback();
+               }
 
     /**
      * Load the alignment and any related files as specified by applet
@@ -2162,7 +2187,7 @@ public class JalviewLite extends Applet implements
         try
         {
           param = setProtocolState(param);
-          JPredFile predictions = new JPredFile(param, protocol);
+          AlignFile predictions = GenericFileAdapter.getFile("JPredFile", param, protocol);
           JnetAnnotationMaker.add_annotation(predictions,
                   alignFrame.viewport.getAlignment(), 0, false);
           // false == do not add sequence profile from concise output
@@ -2898,17 +2923,19 @@ public class JalviewLite extends Applet implements
   private String resolveUrlForLocalOrAbsolute(String url, URL localref)
   {
     String codebase = localref.toString();
-    if (url.indexOf("/") == 0)
-    {
-      url = codebase.substring(0, codebase.length()
-              - localref.getFile().length())
-              + url;
-    }
-    else
-    {
-      url = localref + url;
-    }
-    return url;
+    // BH removing file name and query
+    int pt = codebase.indexOf("?");
+    if (pt < 0)
+       pt = codebase.length();
+    codebase = codebase.substring(0, pt);
+    codebase = codebase.substring(0, codebase.lastIndexOf("/") + 1);
+    // codebase is now http://...xxx/
+    if (url.indexOf("/") == 0 && !localref.getProtocol().equals("file"))
+    { //  http://  https://   we do NOT allow going to the root file system directory!
+       pt = codebase.indexOf("/", 8); 
+      return codebase.substring(0, pt) + url;
+    }
+    return codebase + url;
   }
 
   /**
index e44068d..de80576 100644 (file)
@@ -64,57 +64,79 @@ import java.util.Map;
  */
 public class EditCommand implements CommandI
 {
-  public enum Action
+  public enum Action 
   {
     INSERT_GAP
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return DELETE_GAP;
-      }
-    },
+//    {
+//      @Override
+//      public Action getUndoAction()
+//      {
+//        return DELETE_GAP;
+//      }
+//    }
+    ,
     DELETE_GAP
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return INSERT_GAP;
-      }
-    },
+//    {
+//      @Override
+//      public Action getUndoAction()
+//      {
+//        return INSERT_GAP;
+//      }
+//    }
+    ,
     CUT
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return PASTE;
-      }
-    },
+//    {
+//      @Override
+//      public Action getUndoAction()
+//      {
+//        return PASTE;
+//      }
+//    }
+    ,
     PASTE
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return CUT;
-      }
-    },
+//    {
+//      @Override
+//      public Action getUndoAction()
+//      {
+//        return CUT;
+//      }
+//    }
+    ,
     REPLACE
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return REPLACE;
-      }
-    },
+//    {
+//      @Override
+//      public Action getUndoAction()
+//      {
+//        return REPLACE;
+//      }
+//    }
+    ,
     INSERT_NUC
-    {
-      @Override
-      public Action getUndoAction()
-      {
-        return null;
-      }
-    };
-    public abstract Action getUndoAction();
+//    {
+//     @Override
+//      public Action getUndoAction()
+//      {
+//        return null;
+//      }
+//    }
+    ;
+    public Action getUndoAction() {
+       switch (this) {
+       case INSERT_GAP:
+               return  DELETE_GAP;
+                       case CUT:
+                               return PASTE;
+                       case DELETE_GAP:
+                               return INSERT_GAP;
+                       case INSERT_NUC:
+                               return null;
+                       case PASTE:
+                               return CUT;
+                       case REPLACE:
+                               return REPLACE;
+       }
+       return null;
+    }
   };
 
   private List<Edit> edits = new ArrayList<Edit>();
index 363ad0d..47e1127 100755 (executable)
@@ -22,6 +22,7 @@ package jalview.datamodel;
 
 import jalview.analysis.AlignmentUtils;
 import jalview.io.FastaFile;
+import jalview.jsdev.GenericFileAdapter;
 import jalview.util.Comparison;
 import jalview.util.MessageManager;
 
@@ -117,16 +118,21 @@ public class Alignment implements AlignmentI
   /**
    * Make an alignment from an array of Sequences.
    * 
+   *  
    * @param sequences
    */
   public Alignment(SequenceI[] seqs)
   {
     initAlignment(seqs);
   }
-
+  
   /**
    * Make a new alignment from an array of SeqCigars
    * 
+   * no references in jalview?
+   * 
+   * @j2sIgnore
+   * 
    * @param seqs
    *          SeqCigar[]
    */
@@ -1713,16 +1719,6 @@ public class Alignment implements AlignmentI
   }
 
   /**
-   * Returns the alignment in Fasta format. Behaviour of this method is not
-   * guaranteed between versions.
-   */
-  @Override
-  public String toString()
-  {
-    return new FastaFile().print(getSequencesArray());
-  }
-
-  /**
    * Returns the set of distinct sequence names. No ordering is guaranteed.
    */
   @Override
@@ -1735,4 +1731,23 @@ public class Alignment implements AlignmentI
     }
     return names;
   }
+
+  /**
+   * Returns the alignment in Fasta format. Behaviour of this method is not
+   * guaranteed between versions.
+   */
+  @Override
+  public String toString()
+  {
+       SequenceI[] seq = this.getSequencesArray();
+       /**
+        * @j2sNative
+        * 
+        *   return "" + JSON.stringify(seq);
+        */
+       {
+    return ((FastaFile) GenericFileAdapter.getFile("FastaFile")).print(seq);
+       }
+  }
+
 }
index 5457fbc..ae8816d 100644 (file)
@@ -626,7 +626,7 @@ public class AlignmentView
     }
     else
     {
-      smsa = new SequenceI[1][];
+       smsa = new SequenceI[1][]; // BH this is fine; it's just int[n][], float[n][], etc. that are the problem.
       smsa[0] = new SequenceI[sequences.length];
       for (int s = 0; s < sequences.length; s++)
       {
index 1506cee..c44cc69 100644 (file)
@@ -80,7 +80,7 @@ public abstract class CigarBase
   public Object[] getSequenceAndDeletions(String reference, char GapChar)
   {
     int rlength = 0;
-    int[][] deletions = new int[length][];
+    int[][] deletions = javajs.util.AU.newInt2(length);// BH new int[length][];
     int[][] trunc_deletions = null;
     StringBuffer sq = new StringBuffer();
     int cursor = 0, alcursor = 0, start = 0, startpos = 0, end = 0, endpos = 0, delcount = -1;
index e1f9d00..1bc559a 100755 (executable)
@@ -21,6 +21,8 @@
 package jalview.datamodel;
 
 import jalview.analysis.AlignSeq;
+import jalview.jsdev.api.RegExpInterface;
+import jalview.jsdev.api.VarnaRNA;
 import jalview.schemes.ResidueProperties;
 import jalview.util.Comparison;
 import jalview.util.StringUtils;
@@ -30,9 +32,9 @@ import java.util.Enumeration;
 import java.util.List;
 import java.util.Vector;
 
-import com.stevesoft.pat.Regex;
+import jalview.jsdev.RegExp;
 
-import fr.orsay.lri.varna.models.rna.RNA;
+//import fr.orsay.lri.varna.models.rna.RNA;
 
 /**
  * 
@@ -61,7 +63,7 @@ public class Sequence extends ASequence implements SequenceI
 
   DBRefEntry[] dbrefs;
 
-  RNA rna;
+  VarnaRNA rna;
 
 
   /**
@@ -123,9 +125,9 @@ public class Sequence extends ASequence implements SequenceI
     checkValidRange();
   }
 
-  Regex limitrx = new Regex("[/][0-9]{1,}[-][0-9]{1,}$");
+  RegExpInterface limitrx = RegExp.newRegex("[/][0-9]{1,}[-][0-9]{1,}$");
 
-  Regex endrx = new Regex("[0-9]{1,}$");
+  RegExpInterface endrx = RegExp.newRegex("[0-9]{1,}$");
 
   void parseId()
   {
@@ -1276,12 +1278,12 @@ public class Sequence extends ASequence implements SequenceI
     index = value;
   }
 
-  public void setRNA(RNA r)
+  public void setRNA(VarnaRNA r)
   {
     rna = r;
   }
 
-  public RNA getRNA()
+  public VarnaRNA getRNA()
   {
     return rna;
   }
@@ -1305,5 +1307,4 @@ public class Sequence extends ASequence implements SequenceI
     return result;
   }
 
-
 }
index f69c8b6..55215a6 100755 (executable)
  */
 package jalview.datamodel;
 
+import jalview.jsdev.api.VarnaRNA;
+
 import java.util.List;
 import java.util.Vector;
 
-import fr.orsay.lri.varna.models.rna.RNA;
+//import fr.orsay.lri.varna.models.rna.RNA;
 
 /**
  * Methods for manipulating a sequence, its metadata and related annotation in
@@ -406,13 +408,13 @@ public interface SequenceI extends ASequenceI
    * @return The RNA of the sequence in the alignment
    */
 
-  public RNA getRNA();
+  public VarnaRNA getRNA();
 
   /**
    * @param rna
    *          The RNA.
    */
-  public void setRNA(RNA rna);
+  public void setRNA(VarnaRNA rna);
 
   /**
    * 
index cb4b7ad..6ba0b7f 100644 (file)
@@ -20,8 +20,7 @@
  */
 package jalview.io;
 
-import java.io.PrintWriter;
-import java.io.StringWriter;
+import java.io.File;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
@@ -50,7 +49,7 @@ public class AlignmentProperties
    * @param pw
    * @param html
    */
-  public void writeProperties(PrintWriter pw, boolean html)
+  public void writeProperties(StringBuffer sb, boolean html)
   {
     final String nl = html ? "<br>" : System.getProperty("line.separator");
     float avg = 0;
@@ -70,22 +69,22 @@ public class AlignmentProperties
       }
     }
     avg = avg / alignment.getHeight();
-    pw.print(nl);
-    pw.print("Sequences: " + alignment.getHeight());
-    pw.print(nl);
-    pw.print("Minimum Sequence Length: " + min);
-    pw.print(nl);
-    pw.print("Maximum Sequence Length: " + max);
-    pw.print(nl);
-    pw.print("Average Length: " + (int) avg);
+    sb.append(nl);
+    sb.append("Sequences: " + alignment.getHeight());
+    sb.append(nl);
+    sb.append("Minimum Sequence Length: " + min);
+    sb.append(nl);
+    sb.append("Maximum Sequence Length: " + max);
+    sb.append(nl);
+    sb.append("Average Length: " + (int) avg);
 
     if (((Alignment) alignment).alignmentProperties != null)
     {
-      pw.print(nl);
-      pw.print(nl);
+      sb.append(nl);
+      sb.append(nl);
       if (html)
       {
-        pw.print("<table border=\"1\">");
+        sb.append("<table border=\"1\">");
       }
       Hashtable props = ((Alignment) alignment).alignmentProperties;
       Enumeration en = props.keys();
@@ -112,16 +111,16 @@ public class AlignmentProperties
             }
             pos = npos + 1;
           } while (npos != -1);
-          pw.print("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
+          sb.append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
         }
         else
         {
-          pw.print(nl + key + "\t" + vals);
+          sb.append(nl + key + "\t" + vals);
         }
       }
       if (html)
       {
-        pw.print("</table>");
+        sb.append("</table>");
       }
     }
   }
@@ -138,9 +137,9 @@ public class AlignmentProperties
 
   protected StringBuffer formatReport(boolean html)
   {
-    StringWriter content = new StringWriter();
-    writeProperties(new PrintWriter(content), html);
-    return content.getBuffer();
+       StringBuffer sb = new StringBuffer(); // BH was PrintBuffer
+    writeProperties(sb, html);
+    return sb;
   }
 
   /**
@@ -152,5 +151,5 @@ public class AlignmentProperties
   {
     return formatReport(true);
   }
-
+       
 }
index 8706ad5..0042141 100755 (executable)
@@ -30,6 +30,7 @@ import jalview.datamodel.GraphLine;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.GenericFileAdapter;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemeProperty;
 import jalview.schemes.ResidueProperties;
@@ -38,10 +39,8 @@ import jalview.util.Comparison;
 import jalview.util.Format;
 
 import java.io.BufferedReader;
-import java.io.FileReader;
 import java.io.InputStreamReader;
 import java.io.StringReader;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Enumeration;
@@ -694,12 +693,11 @@ public class AnnotationFile
     {
       if (protocol.equals(AppletFormatAdapter.FILE))
       {
-        in = new BufferedReader(new FileReader(file));
+       in = GenericFileAdapter.getReader(file, false);
       }
       else if (protocol.equals(AppletFormatAdapter.URL))
       {
-        URL url = new URL(file);
-        in = new BufferedReader(new InputStreamReader(url.openStream()));
+       in = GenericFileAdapter.getReader(file, true);
       }
       else if (protocol.equals(AppletFormatAdapter.PASTE))
       {
@@ -710,7 +708,7 @@ public class AnnotationFile
         java.io.InputStream is = getClass().getResourceAsStream("/" + file);
         if (is != null)
         {
-          in = new BufferedReader(new java.io.InputStreamReader(is));
+          in = new BufferedReader(new InputStreamReader(is));
         }
       }
       if (in != null)
index e4c4f3d..c908b15 100755 (executable)
@@ -32,6 +32,11 @@ import java.io.File;
 import java.io.InputStream;
 import java.util.List;
 
+import javajs.J2SIgnoreImport;
+
+import jalview.jsdev.Constants;
+import jalview.jsdev.GenericFileAdapter;
+
 /**
  * A low level class for alignment and feature IO with alignment formatting
  * methods used by both applet and application for generating flat alignment
@@ -41,6 +46,7 @@ import java.util.List;
  * @author $author$
  * @version $Revision$
  */
+@J2SIgnoreImport({java.io.File.class})
 public class AppletFormatAdapter
 {
   private AlignmentViewPanel viewpanel;
@@ -84,7 +90,7 @@ public class AppletFormatAdapter
    */
   public static final String[] READABLE_FORMATS = new String[]
   { "BLC", "CLUSTAL", "FASTA", "MSF", "PileUp", "PIR", "PFAM", "STH",
-      "PDB", "JnetFile", "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC, IdentifyFile.GFF3File,
+      "PDB", "JnetFile", "RNAML", Constants.Phylip_FILE_DESC, Constants.JSON_FILE_DESC, IdentifyFile.GFF3File,
       "HTML" };
 
   /**
@@ -93,9 +99,9 @@ public class AppletFormatAdapter
    */
   public static final String[] READABLE_EXTENSIONS = new String[]
   { "fa, fasta, mfa, fastq", "aln", "pfam", "msf", "pir", "blc", "amsa",
-      "sto,stk", "xml,rnaml", PhylipFile.FILE_EXT, JSONFile.FILE_EXT,
+      "sto,stk", "xml,rnaml", Constants.Phylip_FILE_EXT, Constants.JSON_FILE_EXT,
       ".gff2,gff3",
-      "jar,jvp", HtmlFile.FILE_EXT };
+      "jar,jvp", Constants.Html_FILE_EXT };
 
   /**
    * List of readable formats by application in order corresponding to
@@ -103,8 +109,8 @@ public class AppletFormatAdapter
    */
   public static final String[] READABLE_FNAMES = new String[]
   { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "Stockholm",
-      "RNAML", PhylipFile.FILE_DESC, JSONFile.FILE_DESC, IdentifyFile.GFF3File, "Jalview",
-      HtmlFile.FILE_DESC };
+      "RNAML", Constants.Phylip_FILE_DESC, Constants.JSON_FILE_DESC, IdentifyFile.GFF3File, "Jalview",
+      Constants.Html_FILE_DESC };
 
   /**
    * List of valid format strings for use by callers of the formatSequences
@@ -112,7 +118,7 @@ public class AppletFormatAdapter
    */
   public static final String[] WRITEABLE_FORMATS = new String[]
           { "BLC", "CLUSTAL", "FASTA", "MSF", "PileUp", "PIR", "PFAM", "AMSA",
-    "STH", PhylipFile.FILE_DESC, JSONFile.FILE_DESC };
+    "STH", Constants.Phylip_FILE_DESC, Constants.JSON_FILE_DESC };
 
   /**
    * List of extensions corresponding to file format types in WRITABLE_FNAMES
@@ -120,7 +126,7 @@ public class AppletFormatAdapter
    */
   public static final String[] WRITABLE_EXTENSIONS = new String[]
   { "fa, fasta, mfa, fastq", "aln", "pfam", "msf", "pir", "blc", "amsa",
-      "sto,stk", PhylipFile.FILE_EXT, JSONFile.FILE_EXT, "jvp" };
+      "sto,stk", Constants.Phylip_FILE_EXT, Constants.JSON_FILE_EXT, "jvp" };
 
   /**
    * List of writable formats by the application. Order must correspond with the
@@ -128,7 +134,7 @@ public class AppletFormatAdapter
    */
   public static final String[] WRITABLE_FNAMES = new String[]
   { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "AMSA", "STH",
-      PhylipFile.FILE_DESC, JSONFile.FILE_DESC, "Jalview" };
+      Constants.Phylip_FILE_DESC, Constants.JSON_FILE_DESC, "Jalview" };
 
   public static String INVALID_CHARACTERS = "Contains invalid characters";
 
@@ -241,35 +247,35 @@ public class AppletFormatAdapter
     {
       if (format.equals("FASTA"))
       {
-        alignFile = new FastaFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("FastaFile", inFile, type);
       }
       else if (format.equals("MSF"))
       {
-        alignFile = new MSFfile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("MSFfile", inFile, type);
       }
       else if (format.equals("PileUp"))
       {
-        alignFile = new PileUpfile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("PileUpfile", inFile, type);
       }
       else if (format.equals("CLUSTAL"))
       {
-        alignFile = new ClustalFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("ClustalFile", inFile, type);
       }
       else if (format.equals("BLC"))
       {
-        alignFile = new BLCFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("BLCFile", inFile, type);
       }
       else if (format.equals("PIR"))
       {
-        alignFile = new PIRFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("PIRFile", inFile, type);
       }
       else if (format.equals("PFAM"))
       {
-        alignFile = new PfamFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("PfamFile", inFile, type);
       }
       else if (format.equals("JnetFile"))
       {
-        alignFile = new JPredFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("JPredFile", inFile, type);
         ((JPredFile) alignFile).removeNonSequences();
       }
       else if (format.equals("PDB"))
@@ -281,31 +287,31 @@ public class AppletFormatAdapter
       }
       else if (format.equals("STH"))
       {
-        alignFile = new StockholmFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("StockholmFile", inFile, type);
       }
       else if (format.equals("SimpleBLAST"))
       {
-        alignFile = new SimpleBlastFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("SimpleBlastFile", inFile, type);
       }
       else if (format.equals(PhylipFile.FILE_DESC))
       {
-        alignFile = new PhylipFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("PhylipFile", inFile, type);
       }
-      else if (format.equals(JSONFile.FILE_DESC))
+      else if (format.equals(Constants.JSON_FILE_DESC))
       {
-        alignFile = new JSONFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("JSONFile", inFile, type);
       }
-      else if (format.equals(HtmlFile.FILE_DESC))
+      else if (format.equals(Constants.Html_FILE_DESC))
       {
-        alignFile = new HtmlFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("HtmlFile", inFile, type);
       }
       else if (format.equals("RNAML"))
       {
-        alignFile = new RnamlFile(inFile, type);
+        alignFile = GenericFileAdapter.getFile("RnamlFile", inFile, type);
       }
       else if (format.equals(IdentifyFile.GFF3File))
       {
-        alignFile = new Gff3File(inFile, type);
+        alignFile = GenericFileAdapter.getFile("Gff3File", inFile, type);
       }
       return buildAlignmentFrom(alignFile);
     } catch (Exception e)
@@ -326,7 +332,7 @@ public class AppletFormatAdapter
         try
         {
           // Possible sequence is just residues with no label
-          alignFile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
+          alignFile = GenericFileAdapter.getFile("FastaFile", ">UNKNOWN\n" + inFile, "Paste");
           return buildAlignmentFrom(alignFile);
 
         } catch (Exception ex)
@@ -368,35 +374,35 @@ public class AppletFormatAdapter
     {
       if (format.equals("FASTA"))
       {
-        alignFile = new FastaFile(source);
+        alignFile = GenericFileAdapter.getFile("FastaFile", source);
       }
       else if (format.equals("MSF"))
       {
-        alignFile = new MSFfile(source);
+        alignFile = GenericFileAdapter.getFile("MSFfile", source);
       }
       else if (format.equals("PileUp"))
       {
-        alignFile = new PileUpfile(source);
+        alignFile = GenericFileAdapter.getFile("PileUpfile", source);
       }
       else if (format.equals("CLUSTAL"))
       {
-        alignFile = new ClustalFile(source);
+        alignFile = GenericFileAdapter.getFile("ClustalFile", source);
       }
       else if (format.equals("BLC"))
       {
-        alignFile = new BLCFile(source);
+        alignFile = GenericFileAdapter.getFile("BLCFile", source);
       }
       else if (format.equals("PIR"))
       {
-        alignFile = new PIRFile(source);
+        alignFile = GenericFileAdapter.getFile("PIRFile", source);
       }
       else if (format.equals("PFAM"))
       {
-        alignFile = new PfamFile(source);
+        alignFile = GenericFileAdapter.getFile("PfamFile", source);
       }
       else if (format.equals("JnetFile"))
       {
-        alignFile = new JPredFile(source);
+        alignFile = GenericFileAdapter.getFile("JPredFile", source);
         ((JPredFile) alignFile).removeNonSequences();
       }
       else if (format.equals("PDB"))
@@ -406,31 +412,31 @@ public class AppletFormatAdapter
       }
       else if (format.equals("STH"))
       {
-        alignFile = new StockholmFile(source);
+        alignFile = GenericFileAdapter.getFile("StockholmFile", source);
       }
       else if (format.equals("RNAML"))
       {
-        alignFile = new RnamlFile(source);
+        alignFile = GenericFileAdapter.getFile("RnamlFile", source);
       }
       else if (format.equals("SimpleBLAST"))
       {
-        alignFile = new SimpleBlastFile(source);
+        alignFile = GenericFileAdapter.getFile("SimpleBlastFile", source);
       }
-      else if (format.equals(PhylipFile.FILE_DESC))
+      else if (format.equals(Constants.Phylip_FILE_DESC))
       {
-        alignFile = new PhylipFile(source);
+        alignFile = GenericFileAdapter.getFile("PhylipFile", source);
       }
       else if (format.equals(IdentifyFile.GFF3File))
       {
-        alignFile = new Gff3File(inFile, type);
+        alignFile = GenericFileAdapter.getFile("Gff3File", inFile, type);
       }
-      else if (format.equals(JSONFile.FILE_DESC))
+      else if (format.equals(Constants.JSON_FILE_DESC))
       {
-        alignFile = new JSONFile(source);
+        alignFile = GenericFileAdapter.getFile("JSONFile", source);
       }
-      else if (format.equals(HtmlFile.FILE_DESC))
+      else if (format.equals(Constants.Html_FILE_DESC))
       {
-        alignFile = new HtmlFile(source);
+        alignFile = GenericFileAdapter.getFile("HtmlFile", source);
       }
 
       return buildAlignmentFrom(alignFile);
@@ -453,7 +459,7 @@ public class AppletFormatAdapter
         try
         {
           // Possible sequence is just residues with no label
-          alignFile = new FastaFile(">UNKNOWN\n" + inFile, "Paste");
+          alignFile = GenericFileAdapter.getFile("FastaFile", ">UNKNOWN\n" + inFile, "Paste");
           return buildAlignmentFrom(alignFile);
 
         } catch (Exception ex)
@@ -546,51 +552,51 @@ public class AppletFormatAdapter
       AlignFile afile = null;
       if (format.equalsIgnoreCase("FASTA"))
       {
-        afile = new FastaFile();
+        afile = GenericFileAdapter.getFile("FastaFile");
       }
       else if (format.equalsIgnoreCase("MSF"))
       {
-        afile = new MSFfile();
+        afile = GenericFileAdapter.getFile("MSFfile");
       }
       else if (format.equalsIgnoreCase("PileUp"))
       {
-        afile = new PileUpfile();
+        afile = GenericFileAdapter.getFile("PileUpfile"); // BH NOTE LOWER CASE "file"
       }
       else if (format.equalsIgnoreCase("CLUSTAL"))
       {
-        afile = new ClustalFile();
+        afile = GenericFileAdapter.getFile("ClustalFile");
       }
       else if (format.equalsIgnoreCase("BLC"))
       {
-        afile = new BLCFile();
+        afile = GenericFileAdapter.getFile("BLCFile");
       }
       else if (format.equalsIgnoreCase("PIR"))
       {
-        afile = new PIRFile();
+        afile = GenericFileAdapter.getFile("PIRFile");
       }
       else if (format.equalsIgnoreCase("PFAM"))
       {
-        afile = new PfamFile();
+        afile = GenericFileAdapter.getFile("PfamFile");
       }
       else if (format.equalsIgnoreCase("STH"))
       {
-        afile = new StockholmFile(alignment);
+        afile = GenericFileAdapter.getFile("StockholmFile", alignment);
       }
       else if (format.equalsIgnoreCase("AMSA"))
       {
-        afile = new AMSAFile(alignment);
+        afile = GenericFileAdapter.getFile("AMSAFile", alignment);
       }
-      else if (format.equalsIgnoreCase(PhylipFile.FILE_DESC))
+      else if (format.equalsIgnoreCase(Constants.Phylip_FILE_DESC))
       {
-        afile = new PhylipFile();
+        afile = GenericFileAdapter.getFile("PhylipFile");
       }
-       else if (format.equalsIgnoreCase(JSONFile.FILE_DESC))
+       else if (format.equalsIgnoreCase(Constants.JSON_FILE_DESC))
        {
-        afile = new JSONFile();
+        afile = GenericFileAdapter.getFile("JSONFile");
        }
       else if (format.equalsIgnoreCase("RNAML"))
       {
-        afile = new RnamlFile();
+        afile = GenericFileAdapter.getFile("RnamlFile");
       }
 
       else
@@ -644,6 +650,11 @@ public class AppletFormatAdapter
     return protocol;
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String[] args)
   {
     int i = 0;
index 8dbfbfd..b867ba4 100755 (executable)
  */
 package jalview.io;
 
-import java.io.*;
+import jalview.datamodel.Alignment;
+import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.Annotation;
+import jalview.datamodel.Sequence;
+import jalview.datamodel.SequenceI;
 
-import jalview.datamodel.*;
+import java.io.IOException;
 
 /**
  * DOCUMENT ME!
index f965d23..750c984 100755 (executable)
@@ -26,6 +26,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceDummy;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.GenericFileAdapter;
 import jalview.schemes.AnnotationColourGradient;
 import jalview.schemes.GraduatedColor;
 import jalview.schemes.UserColourScheme;
@@ -777,7 +778,7 @@ public class FeaturesFile extends AlignFile
     } catch (IOException q)
     {
     }
-    FastaFile parser = new FastaFile(this);
+    AlignFile parser = GenericFileAdapter.getFile("FastaFile");
     List<SequenceI> includedseqs = parser.getSeqs();
     SequenceIdMatcher smatcher = new SequenceIdMatcher(newseqs);
     // iterate over includedseqs, and replacing matching ones with newseqs
index 9228257..153067d 100755 (executable)
@@ -38,10 +38,13 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.zip.GZIPInputStream;
 
+import javajs.J2SIgnoreImport;
+
 /**
  * implements a random access wrapper around a particular datasource, for
  * passing to identifyFile and AlignFile objects.
  */
+@J2SIgnoreImport({java.io.File.class, java.io.FileReader.class, java.io.FileInputStream.class })
 public class FileParse
 {
   /**
@@ -149,6 +152,10 @@ public class FileParse
    * Attempt to open a file as a datasource. Sets error and errormessage if
    * fileStr was invalid.
    * 
+   * Not used by applet
+   * 
+   * @j2sIgnore
+   * 
    * @param fileStr
    * @return this.error (true if the source was invalid)
    */
@@ -191,13 +198,18 @@ public class FileParse
         }
         ;
       }
-
       dataIn = new BufferedReader(new FileReader(fileStr));
       dataName = fileStr;
     }
     return error;
   }
 
+  /**
+   * 
+   * @param inputStream
+   * @return
+   * @throws Exception
+   */
   private BufferedReader tryAsGzipSource(InputStream inputStream)
           throws Exception
   {
@@ -279,110 +291,89 @@ public class FileParse
    * @throws MalformedURLException
    * @throws IOException
    */
-  public FileParse(String fileStr, String type)
-          throws MalformedURLException, IOException
-  {
-    this.type = type;
-    error = false;
-
-    if (type.equals(AppletFormatAdapter.FILE))
-    {
-      if (checkFileSource(fileStr))
-      {
-        String suffixLess = extractSuffix(fileStr);
-        if (suffixLess != null)
-        {
-          if (checkFileSource(suffixLess))
-          {
-            throw new IOException(MessageManager.formatMessage("exception.problem_opening_file_also_tried", new String[]{inFile.getName(),suffixLess,errormessage}));
-          }
-        }
-        else
-        {
-          throw new IOException(MessageManager.formatMessage("exception.problem_opening_file", new String[]{inFile.getName(),errormessage}));
-        }
-      }
-    }
-    else if (type.equals(AppletFormatAdapter.URL))
-    {
-      try
-      {
-        try
-        {
-          checkURLSource(fileStr);
-          if (suffixSeparator == '#')
-           {
-            extractSuffix(fileStr); // URL lref is stored for later reference.
-          }
-        } catch (IOException e)
-        {
-          String suffixLess = extractSuffix(fileStr);
-          if (suffixLess == null)
-          {
-            throw (e);
-          }
-          else
-          {
-            try
-            {
-              checkURLSource(suffixLess);
-            } catch (IOException e2)
-            {
-              errormessage = "BAD URL WITH OR WITHOUT SUFFIX";
-              throw (e); // just pass back original - everything was wrong.
-            }
-          }
-        }
-      } catch (Exception e)
-      {
-        errormessage = "CANNOT ACCESS DATA AT URL '" + fileStr + "' ("
-                + e.getMessage() + ")";
-        error = true;
-      }
-    }
-    else if (type.equals(AppletFormatAdapter.PASTE))
-    {
-      errormessage = "PASTE INACCESSIBLE!";
-      dataIn = new BufferedReader(new StringReader(fileStr));
-      dataName = "Paste";
-    }
-    else if (type.equals(AppletFormatAdapter.CLASSLOADER))
-    {
-      errormessage = "RESOURCE CANNOT BE LOCATED";
-      java.io.InputStream is = getClass()
-              .getResourceAsStream("/" + fileStr);
-      if (is == null)
-      {
-        String suffixLess = extractSuffix(fileStr);
-        if (suffixLess != null)
-        {
-          is = getClass().getResourceAsStream("/" + suffixLess);
-        }
-      }
-      if (is != null)
-      {
-        dataIn = new BufferedReader(new java.io.InputStreamReader(is));
-        dataName = fileStr;
-      }
-      else
-      {
-        error = true;
-      }
-    }
-    else
-    {
-      errormessage = "PROBABLE IMPLEMENTATION ERROR : Datasource Type given as '"
-              + (type != null ? type : "null") + "'";
-      error = true;
-    }
-    if (dataIn == null || error)
-    {
-      // pass up the reason why we have no source to read from
-      throw new IOException(MessageManager.formatMessage("exception.failed_to_read_data_from_source", new String[]{errormessage}));
-    }
-    error = false;
-    dataIn.mark(READAHEAD_LIMIT);
-  }
+  public FileParse(String fileStr, String type) throws MalformedURLException, IOException {
+               this.type = type;
+               error = false;
+
+               if (type.equals(AppletFormatAdapter.FILE)) {
+                       /**
+                        * @j2sIgnore
+                        * 
+                        */
+                       {
+                               if (checkFileSource(fileStr)) {
+                                       String suffixLess = extractSuffix(fileStr);
+                                       if (suffixLess != null) {
+                                               if (checkFileSource(suffixLess)) {
+                                                       throw new IOException(MessageManager.formatMessage(
+                                                                       "exception.problem_opening_file_also_tried", new String[] {
+                                                                                       inFile.getName(), suffixLess, errormessage }));
+                                               }
+                                       } else {
+                                               throw new IOException(MessageManager.formatMessage(
+                                                               "exception.problem_opening_file",
+                                                               new String[] { inFile.getName(), errormessage }));
+                                       }
+                               }
+                       }
+               } else if (type.equals(AppletFormatAdapter.URL)) {
+                       try {
+                               try {
+                                       checkURLSource(fileStr);
+                                       if (suffixSeparator == '#') {
+                                               extractSuffix(fileStr); // URL lref is stored for later reference.
+                                       }
+                               } catch (IOException e) {
+                                       String suffixLess = extractSuffix(fileStr);
+                                       if (suffixLess == null) {
+                                               throw (e);
+                                       } else {
+                                               try {
+                                                       checkURLSource(suffixLess);
+                                               } catch (IOException e2) {
+                                                       errormessage = "BAD URL WITH OR WITHOUT SUFFIX";
+                                                       throw (e); // just pass back original - everything was wrong.
+                                               }
+                                       }
+                               }
+                       } catch (Exception e) {
+                               errormessage = "CANNOT ACCESS DATA AT URL '" + fileStr + "' ("
+                                               + e.getMessage() + ")";
+                               error = true;
+                       }
+               } else if (type.equals(AppletFormatAdapter.PASTE)) {
+                       errormessage = "PASTE INACCESSIBLE!";
+                       dataIn = new BufferedReader(new StringReader(fileStr));
+                       dataName = "Paste";
+               } else if (type.equals(AppletFormatAdapter.CLASSLOADER)) {
+                       errormessage = "RESOURCE CANNOT BE LOCATED";
+                       java.io.InputStream is = getClass().getResourceAsStream("/" + fileStr);
+                       if (is == null) {
+                               String suffixLess = extractSuffix(fileStr);
+                               if (suffixLess != null) {
+                                       is = getClass().getResourceAsStream("/" + suffixLess);
+                               }
+                       }
+                       if (is != null) {
+                               dataIn = new BufferedReader(new java.io.InputStreamReader(is));
+                               dataName = fileStr;
+                       } else {
+                               error = true;
+                       }
+               } else {
+                       errormessage = "PROBABLE IMPLEMENTATION ERROR : Datasource Type given as '"
+                                       + (type != null ? type : "null") + "'";
+                       error = true;
+               }
+               if (dataIn == null || error) {
+                       // pass up the reason why we have no source to read from
+                       throw new IOException(MessageManager.formatMessage(
+                                       "exception.failed_to_read_data_from_source",
+                                       new String[] { errormessage }));
+               }
+               error = false;
+               dataIn.mark(READAHEAD_LIMIT);
+       }
 
   /**
    * mark the current position in the source as start for the purposes of it
index 4c83ac1..14848c7 100755 (executable)
@@ -20,6 +20,9 @@
  */
 package jalview.io;
 
+import jalview.jsdev.Constants;
+import jalview.jsdev.GenericFileAdapter;
+
 import java.io.IOException;
 
 /**
@@ -143,13 +146,13 @@ public class IdentifyFile
           break;
         }
         // if (data.matches("<(\"[^\"]*\"|'[^']*'|[^'\">])*>"))
-        if (data.matches("<(?i)html(\"[^\"]*\"|'[^']*'|[^'\">])*>"))
+        if (data.matches("<HTML(\"[^\"]*\"|'[^']*'|[^'\">])*>")) // BH was (?i)rnaml, but JavaScript regex does not support (?i); data is already upper case
         {
-          reply = HtmlFile.FILE_DESC;
+          reply = Constants.Html_FILE_DESC;
           break;
         }
 
-        if (data.matches("<(?i)rnaml (\"[^\"]*\"|'[^']*'|[^'\">])*>"))
+        if (data.matches("<RNAML (\"[^\"]*\"|'[^']*'|[^'\">])*>")) // BH was (?i)rnaml, but JavaScript regex does not support (?i); data is already upper case
         {
           reply = "RNAML";
           break;
@@ -157,7 +160,7 @@ public class IdentifyFile
 
          if (data.indexOf("{\"") > -1)
          {
-         reply = JSONFile.FILE_DESC;
+         reply = Constants.JSON_FILE_DESC;
          break;
          }
         if ((data.length() < 1) || (data.indexOf("#") == 0))
@@ -287,7 +290,7 @@ public class IdentifyFile
         }
         else if (data.matches("\\s*\\d+\\s+\\d+\\s*"))
         {
-          reply = PhylipFile.FILE_DESC;
+          reply = Constants.Phylip_FILE_DESC;
           break;
         }
 
@@ -335,6 +338,11 @@ public class IdentifyFile
     return reply;
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String[] args)
   {
 
index e944720..f5e94f0 100755 (executable)
@@ -28,10 +28,10 @@ import jalview.util.MessageManager;
 
 public class JnetAnnotationMaker
 {
-  public static void add_annotation(JPredFile prediction, AlignmentI al,
+  public static void add_annotation(AlignFile prediction, AlignmentI al,
           int firstSeq, boolean noMsa) throws Exception
   {
-    JnetAnnotationMaker.add_annotation(prediction, al, firstSeq, noMsa,
+    add_annotation(prediction, al, firstSeq, noMsa,
             (int[]) null);
   }
 
@@ -51,7 +51,7 @@ public class JnetAnnotationMaker
    *          mapping from columns in JPredFile prediction to residue number in
    *          al.getSequence(firstSeq)
    */
-  public static void add_annotation(JPredFile prediction, AlignmentI al,
+  public static void add_annotation(AlignFile prediction, AlignmentI al,
           int firstSeq, boolean noMsa, int[] delMap) throws Exception
   {
     int i = 0;
index 9a3453f..49fc1f1 100755 (executable)
@@ -23,8 +23,10 @@ package jalview.io;
 import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class ModellerDescription
 {
@@ -99,16 +101,16 @@ public class ModellerDescription
   private resCode validResidueCode(String field)
   {
     Integer val = null;
-    Regex r = new Regex("\\s*((([-0-9]+).?)|FIRST|LAST|@)");
+    RegExpInterface r = RegExp.newRegex("\\s*((([-0-9]+).?)|FIRST|LAST|@)");
 
     if (!r.search(field))
     {
       return null; // invalid
     }
-    String value = r.stringMatched(3);
+    String value = r.stringMatchedI(3);
     if (value == null)
     {
-      value = r.stringMatched(1);
+      value = r.stringMatchedI(1);
     }
     // Cache.log.debug("from '" + field + "' matched '" + value +
     // "'");
index 90f7faf..94f4ea7 100755 (executable)
@@ -27,6 +27,8 @@
 package jalview.io;
 
 import jalview.datamodel.SequenceNode;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 import jalview.util.MessageManager;
 
 import java.io.BufferedReader;
@@ -35,7 +37,9 @@ import java.io.FileReader;
 import java.io.IOException;
 import java.util.StringTokenizer;
 
-import com.stevesoft.pat.Regex;
+import javajs.J2SIgnoreImport;
+
+//import com.stevesoft.pat.Regex;
 
 /**
  * Parse a new hanpshire style tree Caveats: NHX files are NOT supported and the
@@ -74,6 +78,7 @@ import com.stevesoft.pat.Regex;
  * @author Jim Procter
  * @version $Revision$
  */
+@J2SIgnoreImport({java.io.File.class, java.io.FileReader.class})
 public class NewickFile extends FileParse
 {
   SequenceNode root;
@@ -89,13 +94,13 @@ public class NewickFile extends FileParse
 
   boolean printRootInfo = true;
 
-  private Regex[] NodeSafeName = new Regex[]
-  { new Regex().perlCode("m/[\\[,:'()]/"), // test for
+  private RegExpInterface[] NodeSafeName = new RegExpInterface[]
+  { RegExp.perlCode("m/[\\[,:'()]/"), // test for
       // requiring
       // quotes
-      new Regex().perlCode("s/'/''/"), // escaping quote
+      RegExp.perlCode("s/'/''/"), // escaping quote
       // characters
-      new Regex().perlCode("s/\\/w/_/") // unqoted whitespace
+      RegExp.perlCode("s/\\/w/_/") // unqoted whitespace
   // transformation
   };
 
@@ -250,388 +255,317 @@ public class NewickFile extends FileParse
     return RootHasDistance;
   }
 
-  /**
-   * parse the filesource as a newick file (new hampshire and/or extended)
-   * 
-   * @throws IOException
-   *           with a line number and character position for badly formatted NH
-   *           strings
-   */
-  public void parse() throws IOException
-  {
-    String nf;
-
-    { // fill nf with complete tree file
-
-      StringBuffer file = new StringBuffer();
-
-      while ((nf = nextLine()) != null)
-      {
-        file.append(nf);
-      }
-
-      nf = file.toString();
-    }
-
-    root = new SequenceNode();
-
-    SequenceNode realroot = null;
-    SequenceNode c = root;
-
-    int d = -1;
-    int cp = 0;
-    // int flen = nf.length();
-
-    String Error = null;
-    String nodename = null;
-    String commentString2 = null; // comments after simple node props
-
-    float DefDistance = (float) 0.001; // @param Default distance for a node -
-    // very very small
-    int DefBootstrap = -1; // @param Default bootstrap for a node
-
-    float distance = DefDistance;
-    int bootstrap = DefBootstrap;
-
-    boolean ascending = false; // flag indicating that we are leaving the
-    // current node
-
-    Regex majorsyms = new Regex(
-            "[(\\['),;]");
-
-    int nextcp = 0;
-    int ncp = cp;
-    boolean parsednodename = false;
-    while (majorsyms.searchFrom(nf, cp) && (Error == null))
-    {
-      int fcp = majorsyms.matchedFrom();
-      char schar;
-      switch (schar = nf.charAt(fcp))
-      {
-      case '(':
-
-        // ascending should not be set
-        // New Internal node
-        if (ascending)
-        {
-          Error = ErrorStringrange(Error, "Unexpected '('", 7, fcp, nf);
-
-          continue;
-        }
-
-        ;
-        d++;
-
-        if (c.right() == null)
-        {
-          c.setRight(new SequenceNode(null, c, null, DefDistance,
-                  DefBootstrap, false));
-          c = (SequenceNode) c.right();
-        }
-        else
-        {
-          if (c.left() != null)
-          {
-            // Dummy node for polytomy - keeps c.left free for new node
-            SequenceNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
-            tmpn.SetChildren(c.left(), c.right());
-            c.setRight(tmpn);
-          }
-
-          c.setLeft(new SequenceNode(null, c, null, DefDistance,
-                  DefBootstrap, false));
-          c = (SequenceNode) c.left();
-        }
-
-        if (realroot == null)
-        {
-          realroot = c;
-        }
-
-        nodename = null;
-        distance = DefDistance;
-        bootstrap = DefBootstrap;
-        cp = fcp + 1;
-
-        break;
-
-      // Deal with quoted fields
-      case '\'':
-
-        Regex qnodename = new Regex(
-                "'([^']|'')+'");
-
-        if (qnodename.searchFrom(nf, fcp))
-        {
-          int nl = qnodename.stringMatched().length();
-          nodename = new String(qnodename.stringMatched().substring(1,
-                  nl - 1));
-          // unpack any escaped colons
-          Regex xpandquotes = Regex
-                  .perlCode("s/''/'/");
-          String widernodename = xpandquotes.replaceAll(nodename);
-          nodename = widernodename;
-          // jump to after end of quoted nodename
-          nextcp = fcp + nl + 1;
-          parsednodename = true;
-        }
-        else
-        {
-          Error = ErrorStringrange(Error,
-                  "Unterminated quotes for nodename", 7, fcp, nf);
-        }
-
-        break;
-
-      default:
-        if (schar == ';')
-        {
-          if (d != -1)
-          {
-            Error = ErrorStringrange(Error, "Wayward semicolon (depth=" + d
-                    + ")", 7, fcp, nf);
-          }
-          // cp advanced at the end of default
-        }
-        if (schar == '[')
-        {
-          // node string contains Comment or structured/extended NH format info
-          /*
-           * if ((fcp-cp>1 && nf.substring(cp,fcp).trim().length()>1)) { // will
-           * process in remains System.err.println("skipped text:
-           * '"+nf.substring(cp,fcp)+"'"); }
-           */
-          // verify termination.
-          Regex comment = new Regex("]");
-          if (comment.searchFrom(nf, fcp))
-          {
-            // Skip the comment field
-            nextcp = comment.matchedFrom() + 1;
-            warningMessage = "Tree file contained comments which may confuse input algorithm.";
-            break;
-
-            // cp advanced at the end of default to nextcp, ncp is unchanged so
-            // any node info can be read.
-          }
-          else
-          {
-            Error = ErrorStringrange(Error, "Unterminated comment", 3, fcp,
-                    nf);
-          }
-
-          ;
-        }
-        // Parse simpler field strings
-        String fstring = nf.substring(ncp, fcp);
-        // remove any comments before we parse the node info
-        // TODO: test newick file with quoted square brackets in node name (is
-        // this allowed?)
-        while (fstring.indexOf(']') > -1)
-        {
-          int cstart = fstring.indexOf('[');
-          int cend = fstring.indexOf(']');
-          commentString2 = fstring.substring(cstart + 1, cend);
-          fstring = fstring.substring(0, cstart)
-                  + fstring.substring(cend + 1);
-
-        }
-        Regex uqnodename = new Regex(
-                "\\b([^' :;\\](),]+)");
-        Regex nbootstrap = new Regex(
-                "\\s*([0-9+]+)\\s*:");
-        Regex ndist = new Regex(
-                ":([-0-9Ee.+]+)");
-
-        if (!parsednodename
-                && uqnodename.search(fstring)
-                && ((uqnodename.matchedFrom(1) == 0) || (fstring
-                        .charAt(uqnodename.matchedFrom(1) - 1) != ':'))) // JBPNote
-        // HACK!
-        {
-          if (nodename == null)
-          {
-            if (ReplaceUnderscores)
-            {
-              nodename = uqnodename.stringMatched(1).replace('_', ' ');
-            }
-            else
-            {
-              nodename = uqnodename.stringMatched(1);
-            }
-          }
-          else
-          {
-            Error = ErrorStringrange(Error,
-                    "File has broken algorithm - overwritten nodename", 10,
-                    fcp, nf);
-          }
-        }
-        // get comment bootstraps
-
-        if (nbootstrap.search(fstring))
-        {
-          if (nbootstrap.stringMatched(1).equals(
-                  uqnodename.stringMatched(1)))
-          {
-            nodename = null; // no nodename here.
-          }
-          if (nodename == null
-                  || nodename.length() == 0
-                  || nbootstrap.matchedFrom(1) > (uqnodename.matchedFrom(1) + uqnodename
-                          .stringMatched().length()))
-          {
-            try
-            {
-              bootstrap = (new Integer(nbootstrap.stringMatched(1)))
-                      .intValue();
-              HasBootstrap = true;
-            } catch (Exception e)
-            {
-              Error = ErrorStringrange(Error,
-                      "Can't parse bootstrap value", 4,
-                      ncp + nbootstrap.matchedFrom(), nf);
-            }
-          }
-        }
-
-        boolean nodehasdistance = false;
-
-        if (ndist.search(fstring))
-        {
-          try
-          {
-            distance = (new Float(ndist.stringMatched(1))).floatValue();
-            HasDistances = true;
-            nodehasdistance = true;
-          } catch (Exception e)
-          {
-            Error = ErrorStringrange(Error,
-                    "Can't parse node distance value", 7,
-                    ncp + ndist.matchedFrom(), nf);
-          }
-        }
-
-        if (ascending)
-        {
-          // Write node info here
-          c.setName(nodename);
-          // Trees without distances still need a render distance
-          c.dist = (HasDistances) ? distance : DefDistance;
-          // be consistent for internal bootstrap defaults too
-          c.setBootstrap((HasBootstrap) ? bootstrap : DefBootstrap);
-          if (c == realroot)
-          {
-            RootHasDistance = nodehasdistance; // JBPNote This is really
-            // UGLY!!! Ensure root node gets
-            // its given distance
-          }
-          parseNHXNodeProps(c, commentString2);
-          commentString2 = null;
-        }
-        else
-        {
-          // Find a place to put the leaf
-          SequenceNode newnode = new SequenceNode(null, c, nodename,
-                  (HasDistances) ? distance : DefDistance,
-                  (HasBootstrap) ? bootstrap : DefBootstrap, false);
-          parseNHXNodeProps(c, commentString2);
-          commentString2 = null;
-
-          if (c.right() == null)
-          {
-            c.setRight(newnode);
-          }
-          else
-          {
-            if (c.left() == null)
-            {
-              c.setLeft(newnode);
-            }
-            else
-            {
-              // Insert a dummy node for polytomy
-              // dummy nodes have distances
-              SequenceNode newdummy = new SequenceNode(null, c, null,
-                      (HasDistances ? 0 : DefDistance), 0, true);
-              newdummy.SetChildren(c.left(), newnode);
-              c.setLeft(newdummy);
-            }
-          }
-        }
-
-        if (ascending)
-        {
-          // move back up the tree from preceding closure
-          c = c.AscendTree();
-
-          if ((d > -1) && (c == null))
-          {
-            Error = ErrorStringrange(
-                    Error,
-                    "File broke algorithm: Lost place in tree (is there an extra ')' ?)",
-                    7, fcp, nf);
-          }
-        }
-
-        if (nf.charAt(fcp) == ')')
-        {
-          d--;
-          ascending = true;
-        }
-        else
-        {
-          if (nf.charAt(fcp) == ',')
-          {
-            if (ascending)
-            {
-              ascending = false;
-            }
-            else
-            {
-              // Just advance focus, if we need to
-              if ((c.left() != null) && (!c.left().isLeaf()))
-              {
-                c = (SequenceNode) c.left();
-              }
-            }
-          }
-        }
-
-        // Reset new node properties to obvious fakes
-        nodename = null;
-        distance = DefDistance;
-        bootstrap = DefBootstrap;
-        commentString2 = null;
-        parsednodename = false;
-      }
-      if (nextcp == 0)
-      {
-        ncp = cp = fcp + 1;
-      }
-      else
-      {
-        cp = nextcp;
-        nextcp = 0;
-      }
-    }
-
-    if (Error != null)
-    {
-      throw (new IOException(MessageManager.formatMessage("exception.newfile", new String[]{Error.toString()})));
-    }
-    if (root == null)
-    {
-        throw (new IOException(MessageManager.formatMessage("exception.newfile", new String[]{MessageManager.getString("label.no_tree_read_in")})));
-    }
-    // THe next line is failing for topali trees - not sure why yet. if
-    // (root.right()!=null && root.isDummy())
-    root = (SequenceNode) root.right().detach(); // remove the imaginary root.
-
-    if (!RootHasDistance)
-    {
-      root.dist = (HasDistances) ? 0 : DefDistance;
-    }
-  }
+       /**
+        * parse the filesource as a newick file (new hampshire and/or extended)
+        * 
+        * @throws IOException
+        *           with a line number and character position for badly formatted NH
+        *           strings
+        */
+       public void parse() throws IOException {
+               String nf;
+
+               { // fill nf with complete tree file
+
+                       StringBuffer file = new StringBuffer();
+
+                       while ((nf = nextLine()) != null) {
+                               file.append(nf);
+                       }
+
+                       nf = file.toString();
+               }
+
+               root = new SequenceNode();
+
+               SequenceNode realroot = null;
+               SequenceNode c = root;
+
+               int d = -1;
+               int cp = 0;
+               // int flen = nf.length();
+
+               String Error = null;
+               String nodename = null;
+               String commentString2 = null; // comments after simple node props
+
+               float DefDistance = (float) 0.001; // @param Default distance for a node -
+               // very very small
+               int DefBootstrap = -1; // @param Default bootstrap for a node
+
+               float distance = DefDistance;
+               int bootstrap = DefBootstrap;
+
+               boolean ascending = false; // flag indicating that we are leaving the
+               // current node
+
+               RegExpInterface majorsyms = RegExp.newRegex("[(\\['),;]");
+
+               int nextcp = 0;
+               int ncp = cp;
+               boolean parsednodename = false;
+               while (majorsyms.searchFrom(nf, cp) && (Error == null)) {
+                       int fcp = majorsyms.matchedFrom();
+                       char schar;
+                       switch (schar = nf.charAt(fcp)) {
+                       case '(':
+
+                               // ascending should not be set
+                               // New Internal node
+                               if (ascending) {
+                                       Error = ErrorStringrange(Error, "Unexpected '('", 7, fcp, nf);
+
+                                       continue;
+                               }
+
+                               ;
+                               d++;
+
+                               if (c.right() == null) {
+                                       c.setRight(new SequenceNode(null, c, null, DefDistance, DefBootstrap,
+                                                       false));
+                                       c = (SequenceNode) c.right();
+                               } else {
+                                       if (c.left() != null) {
+                                               // Dummy node for polytomy - keeps c.left free for new node
+                                               SequenceNode tmpn = new SequenceNode(null, c, null, 0, 0, true);
+                                               tmpn.SetChildren(c.left(), c.right());
+                                               c.setRight(tmpn);
+                                       }
+
+                                       c.setLeft(new SequenceNode(null, c, null, DefDistance, DefBootstrap,
+                                                       false));
+                                       c = (SequenceNode) c.left();
+                               }
+
+                               if (realroot == null) {
+                                       realroot = c;
+                               }
+
+                               nodename = null;
+                               distance = DefDistance;
+                               bootstrap = DefBootstrap;
+                               cp = fcp + 1;
+
+                               break;
+
+                       // Deal with quoted fields
+                       case '\'':
+
+                               RegExpInterface qnodename = RegExp.newRegex("'([^']|'')+'");
+
+                               if (qnodename.searchFrom(nf, fcp)) {
+                                       int nl = qnodename.stringMatched().length();
+                                       nodename = new String(qnodename.stringMatched().substring(1, nl - 1));
+                                       // unpack any escaped colons
+                                       RegExpInterface xpandquotes = RegExp.perlCode("s/''/'/");
+                                       String widernodename = xpandquotes.replaceAll(nodename);
+                                       nodename = widernodename;
+                                       // jump to after end of quoted nodename
+                                       nextcp = fcp + nl + 1;
+                                       parsednodename = true;
+                               } else {
+                                       Error = ErrorStringrange(Error, "Unterminated quotes for nodename",
+                                                       7, fcp, nf);
+                               }
+
+                               break;
+
+                       default:
+                               if (schar == ';') {
+                                       if (d != -1) {
+                                               Error = ErrorStringrange(Error, "Wayward semicolon (depth=" + d
+                                                               + ")", 7, fcp, nf);
+                                       }
+                                       // cp advanced at the end of default
+                               }
+                               if (schar == '[') {
+                                       // node string contains Comment or structured/extended NH format info
+                                       /*
+                                        * if ((fcp-cp>1 && nf.substring(cp,fcp).trim().length()>1)) { // will
+                                        * process in remains System.err.println("skipped text:
+                                        * '"+nf.substring(cp,fcp)+"'"); }
+                                        */
+                                       // verify termination.
+                                       RegExpInterface comment = RegExp.newRegex("]");
+                                       if (comment.searchFrom(nf, fcp)) {
+                                               // Skip the comment field
+                                               nextcp = comment.matchedFrom() + 1;
+                                               warningMessage = "Tree file contained comments which may confuse input algorithm.";
+                                               break;
+
+                                               // cp advanced at the end of default to nextcp, ncp is unchanged so
+                                               // any node info can be read.
+                                       } else {
+                                               Error = ErrorStringrange(Error, "Unterminated comment", 3, fcp, nf);
+                                       }
+
+                                       ;
+                               }
+                               // Parse simpler field strings
+                               String fstring = nf.substring(ncp, fcp);
+                               // remove any comments before we parse the node info
+                               // TODO: test newick file with quoted square brackets in node name (is
+                               // this allowed?)
+                               while (fstring.indexOf(']') > -1) {
+                                       int cstart = fstring.indexOf('[');
+                                       int cend = fstring.indexOf(']');
+                                       commentString2 = fstring.substring(cstart + 1, cend);
+                                       fstring = fstring.substring(0, cstart) + fstring.substring(cend + 1);
+
+                               }
+                               RegExpInterface uqnodename = RegExp.newRegex("\\b([^' :;\\](),]+)");
+                               RegExpInterface nbootstrap = RegExp.newRegex("\\s*([0-9+]+)\\s*:");
+                               RegExpInterface ndist = RegExp.newRegex(":([-0-9Ee.+]+)");
+
+                               if (!parsednodename
+                                               && uqnodename.search(fstring)
+                                               && ((uqnodename.matchedFromI(1) == 0) || (fstring.charAt(uqnodename
+                                                               .matchedFromI(1) - 1) != ':'))) // JBPNote
+                               // HACK!
+                               {
+                                       if (nodename == null) {
+                                               if (ReplaceUnderscores) {
+                                                       nodename = uqnodename.stringMatchedI(1).replace('_', ' ');
+                                               } else {
+                                                       nodename = uqnodename.stringMatchedI(1);
+                                               }
+                                       } else {
+                                               Error = ErrorStringrange(Error,
+                                                               "File has broken algorithm - overwritten nodename", 10, fcp, nf);
+                                       }
+                               }
+                               // get comment bootstraps
+
+                               if (nbootstrap.search(fstring)) {
+                                       if (nbootstrap.stringMatchedI(1).equals(uqnodename.stringMatchedI(1))) {
+                                               nodename = null; // no nodename here.
+                                       }
+                                       if (nodename == null
+                                                       || nodename.length() == 0
+                                                       || nbootstrap.matchedFromI(1) > (uqnodename.matchedFromI(1) + uqnodename
+                                                                       .stringMatched().length())) {
+                                               try {
+                                                       bootstrap = (new Integer(nbootstrap.stringMatchedI(1)))
+                                                                       .intValue();
+                                                       HasBootstrap = true;
+                                               } catch (Exception e) {
+                                                       Error = ErrorStringrange(Error, "Can't parse bootstrap value", 4,
+                                                                       ncp + nbootstrap.matchedFrom(), nf);
+                                               }
+                                       }
+                               }
+
+                               boolean nodehasdistance = false;
+
+                               if (ndist.search(fstring)) {
+                                       try {
+                                               distance = (new Float(ndist.stringMatchedI(1))).floatValue();
+                                               HasDistances = true;
+                                               nodehasdistance = true;
+                                       } catch (Exception e) {
+                                               Error = ErrorStringrange(Error, "Can't parse node distance value",
+                                                               7, ncp + ndist.matchedFrom(), nf);
+                                       }
+                               }
+
+                               if (ascending) {
+                                       // Write node info here
+                                       c.setName(nodename);
+                                       // Trees without distances still need a render distance
+                                       c.dist = (HasDistances) ? distance : DefDistance;
+                                       // be consistent for internal bootstrap defaults too
+                                       c.setBootstrap((HasBootstrap) ? bootstrap : DefBootstrap);
+                                       if (c == realroot) {
+                                               RootHasDistance = nodehasdistance; // JBPNote This is really
+                                               // UGLY!!! Ensure root node gets
+                                               // its given distance
+                                       }
+                                       parseNHXNodeProps(c, commentString2);
+                                       commentString2 = null;
+                               } else {
+                                       // Find a place to put the leaf
+                                       SequenceNode newnode = new SequenceNode(null, c, nodename,
+                                                       (HasDistances) ? distance : DefDistance,
+                                                       (HasBootstrap) ? bootstrap : DefBootstrap, false);
+                                       parseNHXNodeProps(c, commentString2);
+                                       commentString2 = null;
+
+                                       if (c.right() == null) {
+                                               c.setRight(newnode);
+                                       } else {
+                                               if (c.left() == null) {
+                                                       c.setLeft(newnode);
+                                               } else {
+                                                       // Insert a dummy node for polytomy
+                                                       // dummy nodes have distances
+                                                       SequenceNode newdummy = new SequenceNode(null, c, null,
+                                                                       (HasDistances ? 0 : DefDistance), 0, true);
+                                                       newdummy.SetChildren(c.left(), newnode);
+                                                       c.setLeft(newdummy);
+                                               }
+                                       }
+                               }
+
+                               if (ascending) {
+                                       // move back up the tree from preceding closure
+                                       c = c.AscendTree();
+
+                                       if ((d > -1) && (c == null)) {
+                                               Error = ErrorStringrange(
+                                                               Error,
+                                                               "File broke algorithm: Lost place in tree (is there an extra ')' ?)",
+                                                               7, fcp, nf);
+                                       }
+                               }
+
+                               if (nf.charAt(fcp) == ')') {
+                                       d--;
+                                       ascending = true;
+                               } else {
+                                       if (nf.charAt(fcp) == ',') {
+                                               if (ascending) {
+                                                       ascending = false;
+                                               } else {
+                                                       // Just advance focus, if we need to
+                                                       if ((c.left() != null) && (!c.left().isLeaf())) {
+                                                               c = (SequenceNode) c.left();
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // Reset new node properties to obvious fakes
+                               nodename = null;
+                               distance = DefDistance;
+                               bootstrap = DefBootstrap;
+                               commentString2 = null;
+                               parsednodename = false;
+                       }
+                       if (nextcp == 0) {
+                               ncp = cp = fcp + 1;
+                       } else {
+                               cp = nextcp;
+                               nextcp = 0;
+                       }
+               }
+
+               if (Error != null) {
+                       throw (new IOException(MessageManager.formatMessage("exception.newfile",
+                                       new String[] { Error.toString() })));
+               }
+               if (root == null) {
+                       throw (new IOException(MessageManager.formatMessage("exception.newfile",
+                                       new String[] { MessageManager.getString("label.no_tree_read_in") })));
+               }
+               // THe next line is failing for topali trees - not sure why yet. if
+               // (root.right()!=null && root.isDummy())
+               root = (SequenceNode) root.right().detach(); // remove the imaginary root.
+
+               if (!RootHasDistance) {
+                       root.dist = (HasDistances) ? 0 : DefDistance;
+               }
+       }
 
   /**
    * parse NHX codes in comment strings and update NewickFile state flags for
@@ -940,6 +874,10 @@ public class NewickFile extends FileParse
   }
 
   // Test
+  /**
+   * @J2SIgnore
+   * @param args
+   */
   public static void main(String[] args)
   {
     try
@@ -969,7 +907,7 @@ public class NewickFile extends FileParse
       trf.parse();
       System.out.println("Original file :\n");
 
-      Regex nonl = new Regex("\n+", "");
+      RegExpInterface nonl = RegExp.newRegex("\n+", "");
       System.out.println(nonl.replaceAll(newickfile.toString()) + "\n");
 
       System.out.println("Parsed file.\n");
index cd9ca88..61dccef 100644 (file)
@@ -177,7 +177,7 @@ public class JSFunctionExec implements Runnable
           ;
           if (scriptObject != null)
           {
-            if (jvlite.debug && dbgMsg != null)
+            if (JalviewLite.debug && dbgMsg != null)
             {
               System.err.println(dbgMsg);
             }
index a028f61..d0bca37 100644 (file)
@@ -28,6 +28,8 @@ import jalview.datamodel.SequenceGroup;
 import jalview.structure.SelectionListener;
 import jalview.structure.SelectionSource;
 
+import netscape.javascript.JSException;
+
 public class JsSelectionSender extends JSFunctionExec implements
         SelectionListener, JsCallBack
 {
diff --git a/src/jalview/jsdev/Constants.java b/src/jalview/jsdev/Constants.java
new file mode 100644 (file)
index 0000000..2bae93d
--- /dev/null
@@ -0,0 +1,31 @@
+package jalview.jsdev;
+
+/**
+ * note: not all file openers have corresponding String inFile and FileParse source options. Why not?
+ * 
+ * @author RM
+ *
+ */
+abstract public class Constants {
+
+  public final static String TCOFFEE_SCORE = "TCoffeeScore";
+
+  public static final int Phylip_FILE = 1;
+
+       public static final String Phylip_FILE_EXT = "phy";
+
+       public static final String Phylip_FILE_DESC = "PHYLIP";
+
+       public static final int JSON_FILE = 2;
+
+       public static final String JSON_FILE_EXT = "json";
+
+       public static final String JSON_FILE_DESC = "JSON";
+
+       public static final int Html_FILE = 3;
+
+       public static final String Html_FILE_EXT = "html";
+
+       public static final String Html_FILE_DESC = "HTML";
+
+}
diff --git a/src/jalview/jsdev/GenericFileAdapter.java b/src/jalview/jsdev/GenericFileAdapter.java
new file mode 100644 (file)
index 0000000..f112ebf
--- /dev/null
@@ -0,0 +1,130 @@
+package jalview.jsdev;
+
+import jalview.datamodel.AlignmentI;
+import jalview.io.AlignFile;
+import jalview.io.FileParse;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URL;
+
+import javajs.J2SIgnoreImport;
+/**
+ * A class to open files via reflection so that their classes are only loaded as necessary
+ * 
+ * note: not all file openers have corresponding String inFile and FileParse
+ * source options. Why not?
+ * 
+ * note: Pileupfile does not have a capital "F"; the method below requires that,
+ * so if that file name gets changed, so too does the reflection code here.
+ * 
+ * @author Bob Hanson
+ * 
+ */
+
+@J2SIgnoreImport({java.io.FileReader.class})
+abstract public class GenericFileAdapter extends AlignFile {
+
+       /**
+        * inFileOrSource class type
+        * 
+        * @param inFileOrSource
+        *          type will determine constructor -- [], [AlignmentI],
+        *          [inFile,type], or [source]
+        * @param type
+        * @param fileName
+        * @return
+        */
+       public static AlignFile getFile(String fileType, Object... params) {
+               Class<?> cl = null;
+               try {
+                       cl = Class.forName("jalview.io." + fileType);
+               } catch (ClassNotFoundException e) {
+                       System.err.println("did not find file jalview.io." + fileType);
+                       return null;
+               }
+               Constructor<?> m;
+               Throwable ex = null;
+               try {
+                       switch (params.length) {
+                       case 0:
+                               return (AlignFile) cl.newInstance();
+                       case 1:
+                               m = (params[0] instanceof FileParse ? cl
+                                               .getConstructor(FileParse.class) : cl
+                                               .getConstructor(AlignmentI.class));
+                               break;
+                       case 2:
+                               m = cl.getConstructor(String.class, String.class);
+                               break;
+                       default:
+                               return null;
+                       }
+                       return (AlignFile) m.newInstance(params);
+               } catch (InstantiationException e) {
+                       ex = e;
+               } catch (IllegalAccessException e) {
+                       ex = e;
+               } catch (NoSuchMethodException e) {
+                       ex = e;
+               } catch (SecurityException e) {
+                       ex = e;
+               } catch (IllegalArgumentException e) {
+                       ex = e;
+               } catch (InvocationTargetException e) {
+                       ex = e;
+               }
+               if (ex != null) {
+                       System.err.println("Error in GenericFileAdapter: " + ex);
+                       /**
+                        * @j2sNative
+                        * 
+                        *            alert(ex)
+                        * 
+                        */
+                       {
+                               ex.printStackTrace();
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Determines whether or not we have a JavaScript applet.
+        * 
+        * @return
+        */
+       public static boolean isJS() {
+       /**
+        * @j2sNative 
+        * 
+        * return true;
+        * 
+        */
+       {
+               return false;
+       } 
+       }
+
+       /**
+        * opens a file for line-oriented reading via File() or URL()
+        * 
+        * @param fileName
+        * @param forceURL
+        * @return
+        * @throws IOException
+        */
+       public static BufferedReader getReader(String fileName, boolean forceURL) throws IOException {
+       if (!forceURL && !isJS())
+               return new BufferedReader(new FileReader(fileName));            
+               if (fileName.indexOf("//") < 0)
+                       fileName = "file://" + fileName;
+    return new BufferedReader(new InputStreamReader(new URL(fileName).openStream()));
+       }
+       
+
+}
diff --git a/src/jalview/jsdev/JSRegex.java b/src/jalview/jsdev/JSRegex.java
new file mode 100644 (file)
index 0000000..9437339
--- /dev/null
@@ -0,0 +1,91 @@
+package jalview.jsdev;
+
+import jalview.jsdev.api.RegExpInterface;
+
+/**
+ * The JavaScript RegEx methods
+ * 
+ * @author Bob Hanson
+ * 
+ */
+public class JSRegex implements RegExpInterface {
+
+       @Override
+       public int charsMatched() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public String left() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public int matchedFrom() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public int matchedFromI(int pos) {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public int matchedTo() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public int matchedToI(int pos) {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public int numSubs() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+
+       @Override
+       public String replaceAll(String string) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public boolean search(String str) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       @Override
+       public boolean searchFrom(String string, int rematchat) {
+               // TODO Auto-generated method stub
+               return false;
+       }
+
+       @Override
+       public void setIgnoreCase(boolean b) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       @Override
+       public String stringMatched() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public String stringMatchedI(int i) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+}
diff --git a/src/jalview/jsdev/JavaScriptRegExp.java b/src/jalview/jsdev/JavaScriptRegExp.java
new file mode 100644 (file)
index 0000000..fc43637
--- /dev/null
@@ -0,0 +1,17 @@
+package jalview.jsdev;
+
+/**
+ * The JavaScript RegEx methods
+ * 
+ * @author Bob Hanson
+ * 
+ */
+public interface JavaScriptRegExp {
+       
+       String[] exec(String str);
+       
+       boolean test(String str);
+       
+       String[] match(String str);
+       
+}
diff --git a/src/jalview/jsdev/RegExp.java b/src/jalview/jsdev/RegExp.java
new file mode 100644 (file)
index 0000000..a36ebd8
--- /dev/null
@@ -0,0 +1,26 @@
+package jalview.jsdev;
+
+import com.stevesoft.pat.Regex;
+
+import jalview.jsdev.api.RegExpInterface;
+
+/**
+ * an intermediary working class allowing options other than com.stevesoft.pat.Regex
+ * 
+ * @author Bob Hanson
+ * 
+ */
+public class RegExp {
+
+       RegExpInterface rg;
+       
+       public static RegExpInterface newRegex(String... params) {
+               return new Regex(params.length < 1 ? null : params[0],
+                               params.length < 2 ? "" : params[1]);
+       }
+
+       public static RegExpInterface perlCode(String s) {
+               return Regex.perlCode(s);
+       }
+
+}
diff --git a/src/jalview/jsdev/api/RegExpInterface.java b/src/jalview/jsdev/api/RegExpInterface.java
new file mode 100644 (file)
index 0000000..44bc865
--- /dev/null
@@ -0,0 +1,37 @@
+package jalview.jsdev.api;
+
+/**
+ * all methods of com.stevesoft.pat.Regex called within Jalview
+ * 
+ * @author Bob Hanson
+ *
+ */
+public interface RegExpInterface {
+
+       public abstract int charsMatched();
+
+       public abstract String left();
+
+       public abstract int matchedFrom();
+
+       public abstract int matchedFromI(int pos);
+
+       public abstract int matchedTo();
+
+       public abstract int matchedToI(int pos);
+
+       public abstract int numSubs();
+
+       public abstract String replaceAll(String string);
+
+       public abstract boolean search(String str);
+
+       public abstract boolean searchFrom(String string, int rematchat);
+
+       public abstract void setIgnoreCase(boolean b);
+
+       public abstract String stringMatched();
+
+       public abstract String stringMatchedI(int i);
+
+}
\ No newline at end of file
diff --git a/src/jalview/jsdev/api/VarnaRNA.java b/src/jalview/jsdev/api/VarnaRNA.java
new file mode 100644 (file)
index 0000000..a392dc6
--- /dev/null
@@ -0,0 +1,5 @@
+package jalview.jsdev.api;
+
+public interface VarnaRNA {
+
+}
index fb8d295..e4b4fb2 100755 (executable)
@@ -781,10 +781,9 @@ public class Matrix
   }
 
   /**
-   * DOCUMENT ME!
+   * @j2sIgnore
    * 
    * @param args
-   *          DOCUMENT ME!
    */
   public static void main(String[] args) throws Exception
   {
index 9d92645..44f4374 100755 (executable)
@@ -253,10 +253,9 @@ public class RotatableMatrix
   }
 
   /**
-   * DOCUMENT ME!
+   * @j2sIgnore
    * 
    * @param args
-   *          DOCUMENT ME!
    */
   public static void main(String[] args)
   {
index ca02c29..debbf9a 100644 (file)
@@ -27,6 +27,8 @@ import jalview.api.AlignViewportI;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.ColumnSelection;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.NucleotideColourScheme;
 import jalview.schemes.ResidueProperties;
@@ -46,7 +48,7 @@ import java.awt.image.ImageObserver;
 import java.util.BitSet;
 import java.util.Hashtable;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class AnnotationRenderer
 {
@@ -80,7 +82,7 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("(\\))");
+    RegExpInterface closeparen = RegExp.newRegex("(\\))");
 
     char dc = (column == 0 || row_annotations[column - 1] == null) ? ' '
             : row_annotations[column - 1].secondaryStructure;
@@ -204,7 +206,7 @@ public class AnnotationRenderer
     int sCol = (lastSSX / charWidth) + startRes;
     int x1 = lastSSX;
     int x2 = (x * charWidth);
-    Regex closeparen = new Regex("}|]|<|[a-z]");
+    RegExpInterface closeparen = RegExp.newRegex("}|]|<|[a-z]");
 
     String dc = (column == 0 || row_annotations[column - 1] == null) ? ""
             : row_annotations[column - 1].displayCharacter;
index b0822ca..e65d5f5 100755 (executable)
@@ -246,110 +246,82 @@ public class AnnotationColourGradient extends FollowerColourScheme
     return Color.red;
   }
 
-  /**
-   * DOCUMENT ME!
-   * 
-   * @param n
-   *          DOCUMENT ME!
-   * @param j
-   *          DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
-   */
-  @Override
-  public Color findColour(char c, int j, SequenceI seq)
-  {
-    Color currentColour = Color.white;
-    AlignmentAnnotation annotation = (seqAssociated && seqannot!=null ? seqannot.get(seq)
-            : this.annotation);
-    if (annotation == null)
-    {
-      return currentColour;
-    }
-    if ((threshold == 0) || aboveThreshold(c, j))
-    {
-      if (annotation.annotations != null
-              && j < annotation.annotations.length
-              && annotation.annotations[j] != null
-              && !Comparison.isGap(c))
-      {
-        Annotation aj = annotation.annotations[j];
-        // 'use original colours' => colourScheme != null
-        // -> look up colour to be used
-        // predefined colours => preconfigured shading
-        // -> only use original colours reference if thresholding enabled &
-        // minmax exists
-        // annotation.hasIcons => null or black colours replaced with glyph
-        // colours
-        // -> reuse original colours if present
-        // -> if thresholding enabled then return colour on non-whitespace glyph
-
-        if (aboveAnnotationThreshold == NO_THRESHOLD
-                || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
-                        : aj.value <= annotationThreshold.value)))
-        {
-          if (predefinedColours && aj.colour != null
-                  && !aj.colour.equals(Color.black))
-          {
-            currentColour = aj.colour;
-          }
-          else if (annotation.hasIcons
-                  && annotation.graph == AlignmentAnnotation.NO_GRAPH)
-          {
-            if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
-                    && aj.secondaryStructure != '-')
-            {
-              if (colourScheme != null)
-              {
-                currentColour = colourScheme.findColour(c, j, seq);
-              }
-              else
-              {
-                if (annotation.isRNA())
-                {
-                  currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
-                }
-                else
-                {
-                  currentColour = annotation.annotations[j].secondaryStructure == 'H' ? AnnotationRenderer.HELIX_COLOUR
-                          : annotation.annotations[j].secondaryStructure == 'E' ? AnnotationRenderer.SHEET_COLOUR
-                                  : AnnotationRenderer.STEM_COLOUR;
-                }
-              }
-            }
-            else
-            {
-              //
-              return Color.white;
-            }
-          }
-          else if (noGradient)
-          {
-            if (colourScheme != null)
-            {
-              currentColour = colourScheme.findColour(c, j, seq);
-            }
-            else
-            {
-              if (aj.colour != null)
-              {
-                currentColour = aj.colour;
-              }
-            }
-          }
-          else
-          {
-            currentColour = shadeCalculation(annotation, j);
-          }
-        }
-        if (conservationColouring)
-        {
-          currentColour = applyConservation(currentColour, j);
-        }
-      }
-    }
-    return currentColour;
-  }
+       /**
+        * DOCUMENT ME!
+        * 
+        * @param n
+        *          DOCUMENT ME!
+        * @param j
+        *          DOCUMENT ME!
+        * 
+        * @return DOCUMENT ME!
+        */
+       @Override
+       public Color findColour(char c, int j, SequenceI seq) {
+               Color currentColour = Color.white;
+               AlignmentAnnotation annotation = (seqAssociated && seqannot != null ? seqannot
+                               .get(seq) : this.annotation);
+               if (annotation == null) {
+                       return currentColour;
+               }
+               if ((threshold == 0) || aboveThreshold(c, j)) {
+                       if (annotation.annotations != null && j < annotation.annotations.length
+                                       && annotation.annotations[j] != null && !Comparison.isGap(c)) {
+                               Annotation aj = annotation.annotations[j];
+                               // 'use original colours' => colourScheme != null
+                               // -> look up colour to be used
+                               // predefined colours => preconfigured shading
+                               // -> only use original colours reference if thresholding enabled &
+                               // minmax exists
+                               // annotation.hasIcons => null or black colours replaced with glyph
+                               // colours
+                               // -> reuse original colours if present
+                               // -> if thresholding enabled then return colour on non-whitespace glyph
+
+                               if (aboveAnnotationThreshold == NO_THRESHOLD
+                                               || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
+                                                               : aj.value <= annotationThreshold.value))) {
+                                       if (predefinedColours && aj.colour != null
+                                                       && !aj.colour.equals(Color.black)) {
+                                               currentColour = aj.colour;
+                                       } else if (annotation.hasIcons
+                                                       && annotation.graph == AlignmentAnnotation.NO_GRAPH) {
+                                               if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
+                                                               && aj.secondaryStructure != '-') {
+                                                       if (colourScheme != null) {
+                                                               currentColour = colourScheme.findColour(c, j, seq);
+                                                       } else {
+                                                               if (annotation.isRNA()) {
+                                                                       currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
+                                                               } else {
+                                                                       currentColour = annotation.annotations[j].secondaryStructure == 'H' ? AnnotationRenderer.HELIX_COLOUR
+                                                                                       : annotation.annotations[j].secondaryStructure == 'E' ? AnnotationRenderer.SHEET_COLOUR
+                                                                                                       : AnnotationRenderer.STEM_COLOUR;
+                                                               }
+                                                       }
+                                               } else {
+                                                       //
+                                                       return Color.white;
+                                               }
+                                       } else if (noGradient) {
+                                               if (colourScheme != null) {
+                                                       currentColour = colourScheme.findColour(c, j, seq);
+                                               } else {
+                                                       if (aj.colour != null) {
+                                                               currentColour = aj.colour;
+                                                       }
+                                               }
+                                       } else {
+                                               currentColour = shadeCalculation(annotation, j);
+                                       }
+                               }
+                               if (conservationColouring) {
+                                       currentColour = applyConservation(currentColour, j);
+                               }
+                       }
+               }
+               return currentColour;
+       }
 
   private Color shadeCalculation(AlignmentAnnotation annotation, int j)
   {
index 662a77e..d5c542c 100755 (executable)
@@ -29,10 +29,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Vector;
 
+import javajs.J2SRequireImport;
+
 import jalview.analysis.scoremodels.FeatureScoreModel;
 import jalview.analysis.scoremodels.PIDScoreModel;
 import jalview.api.analysis.ScoreModelI;
 
+// required because of the static defs
+
+@J2SRequireImport({ScoreMatrix.class, PIDScoreModel.class, FeatureScoreModel.class})
 public class ResidueProperties
 {
   public static Hashtable<String, ScoreModelI> scoreMatrices = new Hashtable();
@@ -869,6 +874,8 @@ public class ResidueProperties
     }
     // and programmatically add in the ambiguity codes that yield the same amino
     // acid
+    
+    
     String[] unambcodons = codonHash2.keySet().toArray(
             new String[codonHash2.size()]);
     for (String codon : unambcodons)
@@ -1739,6 +1746,12 @@ public class ResidueProperties
 
   // main method generates perl representation of residue property hash
   // / cut here
+  
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String[] args)
   {
     Hashtable aa = new Hashtable();
index 48c52f1..9e8feea 100644 (file)
  */
 package jalview.schemes;
 
-import jalview.analysis.SequenceIdMatcher;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AnnotatedCollectionI;
 import jalview.datamodel.Annotation;
 import jalview.datamodel.SequenceCollectionI;
 import jalview.datamodel.SequenceI;
-import jalview.io.TCoffeeScoreFile;
+import jalview.jsdev.Constants;
 
 import java.awt.Color;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
 import java.util.Map;
-import java.util.TreeMap;
+//import jalview.io.TCoffeeScoreFile;
+//import java.util.TreeMap;
 
 /**
  * Defines the color score for T-Coffee MSA
@@ -91,7 +91,7 @@ public class TCoffeeColourScheme extends ResidueColourScheme
             : alignment.getContext();
     int w = 0;
     for (AlignmentAnnotation al : alcontext
-            .findAnnotation(TCoffeeScoreFile.TCOFFEE_SCORE))
+            .findAnnotation(Constants.TCOFFEE_SCORE))
     {
       if (al.sequenceRef != null && !al.belowAlignment)
       {
index e77a23c..efa951a 100644 (file)
@@ -109,7 +109,7 @@ public abstract class AAStructureBindingModel extends
   {
     this.ssm = ssm;
     this.sequence = sequenceIs;
-    this.nucleotide = Comparison.isNucleotide(sequenceIs);
+    this.nucleotide = Comparison.isNucleotide2(sequenceIs);
     this.chains = chains;
     this.pdbEntry = pdbentry;
     this.protocol = protocol;
index 3b95f8a..f664c61 100644 (file)
@@ -244,6 +244,11 @@ public class AWTConsole extends WindowAdapter implements WindowListener,
     return input;
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String[] arg)
   {
     new AWTConsole(); // create console with not reference
index 835a1b4..db120ff 100644 (file)
@@ -311,7 +311,7 @@ public class Comparison
    * @param seqs
    * @return
    */
-  public static boolean isNucleotide(SequenceI[][] seqs)
+  public static boolean isNucleotide2(SequenceI[][] seqs)
   {
     if (seqs == null)
     {
index 0349ff2..290db47 100755 (executable)
@@ -24,6 +24,8 @@ import jalview.datamodel.DBRefEntry;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -31,7 +33,7 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class DBRefUtils
 {
@@ -430,12 +432,12 @@ public class DBRefUtils
          * Check for PFAM style stockhom PDB accession id citation e.g.
          * "1WRI A; 7-80;"
          */
-        Regex r = new Regex(
+        RegExpInterface r = RegExp.newRegex(
                 "([0-9][0-9A-Za-z]{3})\\s*(.?)\\s*;\\s*([0-9]+)-([0-9]+)");
         if (r.search(acn.trim()))
         {
-          String pdbid = r.stringMatched(1);
-          String chaincode = r.stringMatched(2);
+          String pdbid = r.stringMatchedI(1);
+          String chaincode = r.stringMatchedI(2);
           if (chaincode==null)
           {
             chaincode = " ";
index 026e289..d103e67 100644 (file)
@@ -22,10 +22,12 @@ package jalview.util;
 
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceI;
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
 
 import java.util.Hashtable;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class GroupUrlLink
 {
@@ -218,7 +220,7 @@ public class GroupUrlLink
         regexReplace[pass] = link.substring(ptok[pass] + mlength, p);
         try
         {
-          Regex rg = Regex.perlCode("/"
+          RegExpInterface rg = RegExp.perlCode("/"
                   + regexReplace[pass] + "/");
           if (rg == null)
           {
@@ -502,13 +504,13 @@ public class GroupUrlLink
     // iterate through input, collating segments to be inserted into url
     StringBuffer matched[] = new StringBuffer[idseq.length];
     // and precompile regexes
-    Regex[] rgxs = new Regex[matched.length];
+    RegExpInterface[] rgxs = new RegExpInterface[matched.length];
     for (pass = 0; pass < matched.length; pass++)
     {
       matched[pass] = new StringBuffer();
       if (regexReplace[pass] != null)
       {
-        rgxs[pass] = Regex.perlCode("/"
+        rgxs[pass] = RegExp.perlCode("/"
                 + regexReplace[pass] + "/");
       }
       else
@@ -547,7 +549,7 @@ public class GroupUrlLink
         }
         if (rgxs[pass] != null)
         {
-          Regex rg = rgxs[pass];
+          RegExpInterface rg = rgxs[pass];
           int rematchat = 0;
           // concatenate all matches of re in the given string!
           while (rg.searchFrom(idseq[pass][sq], rematchat))
@@ -595,19 +597,19 @@ public class GroupUrlLink
               int s = 0; // 1;
               while (s <= ns)
               {
-                if (s + 1 <= ns && rg.matchedTo(s) > -1
-                        && rg.matchedTo(s + 1) > -1
-                        && rg.matchedTo(s + 1) < rg.matchedTo(s))
+                if (s + 1 <= ns && rg.matchedToI(s) > -1
+                        && rg.matchedToI(s + 1) > -1
+                        && rg.matchedToI(s + 1) < rg.matchedToI(s))
                 {
                   // s is top level submatch. search for submatches enclosed by
                   // this one
                   int r = s + 1;
                   StringBuffer rmtch = new StringBuffer();
-                  while (r <= ns && rg.matchedTo(r) <= rg.matchedTo(s))
+                  while (r <= ns && rg.matchedToI(r) <= rg.matchedToI(s))
                   {
-                    if (rg.matchedFrom(r) > -1)
+                    if (rg.matchedFromI(r) > -1)
                     {
-                      rmtch.append(rg.stringMatched(r));
+                      rmtch.append(rg.stringMatchedI(r));
                     }
                     r++;
                   }
@@ -619,9 +621,9 @@ public class GroupUrlLink
                 }
                 else
                 {
-                  if (rg.matchedFrom(s) > -1)
+                  if (rg.matchedFromI(s) > -1)
                   {
-                    subs.append(rg.stringMatched(s)); // concatenate
+                    subs.append(rg.stringMatchedI(s)); // concatenate
                   }
                   s++;
                 }
@@ -817,6 +819,11 @@ public class GroupUrlLink
     }
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String argv[])
   {
     // note - JAL-1383 - these services are all dead
index 4001cb2..5a5c70f 100644 (file)
@@ -26,6 +26,8 @@ import java.util.ResourceBundle;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
+import javajs.J2SRequireImport;
+
 /**
  * 
  * @author David Roldan Martinez
@@ -33,6 +35,7 @@ import java.util.logging.Logger;
  * 
  * 
  */
+@J2SRequireImport ({java.text.MessageFormat.class})
 public class MessageManager
 {
 
@@ -53,7 +56,8 @@ public class MessageManager
       /* Getting messages for GV */
       log.info("Getting messages for lang: " + loc);
       rb = ResourceBundle.getBundle("lang.Messages", loc);
-      if (log.isLoggable(Level.FINEST))
+      // BH rb == null just throws the exception 
+      if (rb == null || log.isLoggable(Level.FINEST))
       {
         // this might take a while, so we only do it if it will be shown
         log.finest("Language keys: " + rb.keySet());
@@ -92,12 +96,12 @@ public class MessageManager
 
   public static String formatMessage(String key, Object... params)
   {
-    return MessageFormat.format(rb.getString(key), params);
+    return MessageFormat.format(getString(key), params); // BH not rb.getString
   }
 
   public static String formatMessage(String key, String[] params)
   {
-    return MessageFormat.format(rb.getString(key), (Object[]) params);
+    return MessageFormat.format(getString(key), (Object[]) params); // BH not rb.getString
   }
 
   /**
index b0e75be..2a464c6 100755 (executable)
@@ -45,7 +45,7 @@ public class QuickSort
     @Override
     public int compare(Integer o1, Integer o2)
     {
-      return Float.compare(values[o1], values[o2]);
+      return Float.compare(values[o1.intValue()], values[o2]);
     }
     
   }
@@ -87,7 +87,7 @@ public class QuickSort
    * @param arr
    * @param s
    */
-  public static void sortFloat(float[] arr, Object[] s)
+  public static void sortFloatObject(float[] arr, Object[] s)
   {
     sortFloat(arr, 0, arr.length - 1, s);
   }
@@ -116,7 +116,7 @@ public class QuickSort
     stringSort(arr, 0, arr.length - 1, s);
   }
 
-  static void stringSort(String[] arr, int p, int r, Object[] s)
+  private static void stringSort(String[] arr, int p, int r, Object[] s)
   {
     int q;
 
@@ -128,7 +128,7 @@ public class QuickSort
     }
   }
 
-  static void sortFloat(float[] arr, int p, int r, Object[] s)
+  private static void sortFloat(float[] arr, int p, int r, Object[] s)
   {
     int q;
 
@@ -140,7 +140,17 @@ public class QuickSort
     }
   }
 
-  static void sortDouble(double[] arr, int p, int r, Object[] s)
+  /**
+   * We don't need both of these
+   * 
+   * @j2sIgnore
+   * 
+   * @param arr
+   * @param p
+   * @param r
+   * @param s
+   */
+         private static void sortDouble(double[] arr, int p, int r, Object[] s)
   {
     int q;
 
@@ -152,7 +162,7 @@ public class QuickSort
     }
   }
 
-  static void sortInt(int[] arr, int p, int r, Object[] s)
+  private static void sortInt(int[] arr, int p, int r, Object[] s)
   {
     int q;
 
@@ -164,7 +174,7 @@ public class QuickSort
     }
   }
 
-  static int partitionFloat(float[] arr, int p, int r, Object[] s)
+  private static int partitionFloat(float[] arr, int p, int r, Object[] s)
   {
     float x = arr[p];
     int i = p - 1;
@@ -199,7 +209,7 @@ public class QuickSort
     }
   }
 
-  static int partitionFloat(float[] arr, int p, int r, char[] s)
+  private static int partitionFloatChar(float[] arr, int p, int r, char[] s)
   {
     float x = arr[p];
     int i = p - 1;
@@ -234,7 +244,7 @@ public class QuickSort
     }
   }
 
-  static int partitionInt(int[] arr, int p, int r, Object[] s)
+  private static int partitionInt(int[] arr, int p, int r, Object[] s)
   {
     int x = arr[p];
     int i = p - 1;
@@ -269,7 +279,7 @@ public class QuickSort
     }
   }
 
-  static int partitionDouble(double[] arr, int p, int r, Object[] s)
+  private static int partitionDouble(double[] arr, int p, int r, Object[] s)
   {
     double x = arr[p];
     int i = p - 1;
@@ -304,7 +314,7 @@ public class QuickSort
     }
   }
 
-  static int stringPartition(String[] arr, int p, int r, Object[] s)
+  private static int stringPartition(String[] arr, int p, int r, Object[] s)
   {
     String x = arr[p];
     int i = p - 1;
@@ -346,7 +356,7 @@ public class QuickSort
    * @param arr
    * @param s
    */
-  public static void sortFloat(float[] arr, char[] s)
+  public static void sortFloatChar(float[] arr, char[] s)
   {
     /*
      * Sort all zero values to the front
@@ -388,7 +398,7 @@ public class QuickSort
     float[] nonZeroFloats = Arrays
             .copyOfRange(f1, nextZeroValue, f1.length);
     char[] nonZeroChars = Arrays.copyOfRange(s1, nextZeroValue, s1.length);
-    externalSort(nonZeroFloats, nonZeroChars);
+    externalSortFloat(nonZeroFloats, nonZeroChars);
     // sort(nonZeroFloats, 0, nonZeroFloats.length - 1, nonZeroChars);
 
     /*
@@ -409,7 +419,7 @@ public class QuickSort
    * @param arr
    * @param s
    */
-  protected static void externalSort(float[] arr, char[] s)
+  private static void externalSortFloat(float[] arr, char[] s)
   {
     final int length = arr.length;
     Integer[] indices = makeIndexArray(length);
@@ -439,7 +449,7 @@ public class QuickSort
    * @param length
    * @return
    */
-  protected static Integer[] makeIndexArray(final int length)
+  private  static Integer[] makeIndexArray(final int length)
   {
     Integer[] indices = new Integer[length];
     for (int i = 0; i < length; i++)
@@ -449,17 +459,17 @@ public class QuickSort
     return indices;
   }
 
-  static void sortFloat(float[] arr, int p, int r, char[] s)
-  {
-    int q;
-    if (p < r)
-    {
-      q = partitionFloat(arr, p, r, s);
-      sortFloat(arr, p, q, s);
-      sortFloat(arr, q + 1, r, s);
-    }
-  }
-
+//  private static void sortFloat(float[] arr, int p, int r, char[] s)
+//  {
+//    int q;
+//    if (p < r)
+//    {
+//      q = partitionFloatChar(arr, p, r, s);
+//      sortFloat(arr, p, q, s);
+//      sortFloat(arr, q + 1, r, s);
+//    }
+//  }
+//
   /**
    * Sorts both arrays to give ascending order in the first array, by first
    * partitioning into zero and non-zero values before sorting the latter.
@@ -467,7 +477,7 @@ public class QuickSort
    * @param arr
    * @param s
    */
-  public static void sortInt(int[] arr, char[] s)
+  public static void sortIntChar(int[] arr, char[] s)
   {
     /*
      * Sort all zero values to the front
@@ -509,7 +519,7 @@ public class QuickSort
     int[] nonZeroInts = Arrays
             .copyOfRange(f1, nextZeroValue, f1.length);
     char[] nonZeroChars = Arrays.copyOfRange(s1, nextZeroValue, s1.length);
-    externalSort(nonZeroInts, nonZeroChars);
+    externalSortInt(nonZeroInts, nonZeroChars);
     // sort(nonZeroFloats, 0, nonZeroFloats.length - 1, nonZeroChars);
   
     /*
@@ -529,7 +539,7 @@ public class QuickSort
    * @param arr
    * @param s
    */
-  protected static void externalSort(int[] arr, char[] s)
+  private static void externalSortInt(int[] arr, char[] s)
   {
     final int length = arr.length;
     Integer[] indices = makeIndexArray(length);
index c0cf821..cf0d466 100644 (file)
  */
 package jalview.util;
 
+import jalview.jsdev.RegExp;
+import jalview.jsdev.api.RegExpInterface;
+
 import java.util.Vector;
 
-import com.stevesoft.pat.Regex;
+//import com.stevesoft.pat.Regex;
 
 public class UrlLink
 {
@@ -86,7 +89,7 @@ public class UrlLink
         regexReplace = link.substring(psqid + 14, p);
         try
         {
-          Regex rg = Regex.perlCode("/"
+          RegExpInterface rg = RegExp.perlCode("/"
                   + regexReplace + "/");
           if (rg == null)
           {
@@ -201,7 +204,7 @@ public class UrlLink
     {
       if (regexReplace != null)
       {
-        Regex rg = Regex.perlCode("/" + regexReplace + "/");
+        RegExpInterface rg = RegExp.perlCode("/" + regexReplace + "/");
         if (rg.search(idstring))
         {
           int ns = rg.numSubs();
@@ -209,7 +212,7 @@ public class UrlLink
           {
             // take whole regex
             return new String[]
-            { rg.stringMatched(),
+            { rg.stringMatchedI(ns),
                 url_prefix + rg.stringMatched() + url_suffix };
           } /*
              * else if (ns==1) { // take only subgroup match return new String[]
@@ -221,9 +224,9 @@ public class UrlLink
             // debug
             for (int s = 0; s <= rg.numSubs(); s++)
             {
-              System.err.println("Sub " + s + " : " + rg.matchedFrom(s)
-                      + " : " + rg.matchedTo(s) + " : '"
-                      + rg.stringMatched(s) + "'");
+              System.err.println("Sub " + s + " : " + rg.matchedFromI(s)
+                      + " : " + rg.matchedToI(s) + " : '"
+                      + rg.stringMatchedI(s) + "'");
             }
             // try to collate subgroup matches
             Vector subs = new Vector();
@@ -232,19 +235,19 @@ public class UrlLink
             int s = 0; // 1;
             while (s <= ns)
             {
-              if (s + 1 <= ns && rg.matchedTo(s) > -1
-                      && rg.matchedTo(s + 1) > -1
-                      && rg.matchedTo(s + 1) < rg.matchedTo(s))
+              if (s + 1 <= ns && rg.matchedToI(s) > -1
+                      && rg.matchedToI(s + 1) > -1
+                      && rg.matchedToI(s + 1) < rg.matchedToI(s))
               {
                 // s is top level submatch. search for submatches enclosed by
                 // this one
                 int r = s + 1;
                 String mtch = "";
-                while (r <= ns && rg.matchedTo(r) <= rg.matchedTo(s))
+                while (r <= ns && rg.matchedToI(r) <= rg.matchedToI(s))
                 {
-                  if (rg.matchedFrom(r) > -1)
+                  if (rg.matchedFromI(r) > -1)
                   {
-                    mtch += rg.stringMatched(r);
+                    mtch += rg.stringMatchedI(r);
                   }
                   r++;
                 }
@@ -257,10 +260,10 @@ public class UrlLink
               }
               else
               {
-                if (rg.matchedFrom(s) > -1)
+                if (rg.matchedFromI(s) > -1)
                 {
-                  subs.addElement(rg.stringMatched(s));
-                  subs.addElement(url_prefix + rg.stringMatched(s)
+                  subs.addElement(rg.stringMatchedI(s));
+                  subs.addElement(url_prefix + rg.stringMatchedI(s)
                           + url_suffix);
                 }
                 s++;
@@ -327,6 +330,11 @@ public class UrlLink
     }
   }
 
+  /**
+   * @j2sIgnore
+   * 
+   * @param args
+   */
   public static void main(String argv[])
   {
     String[] links = new String[]
index 63faab9..d3f150b 100644 (file)
@@ -5,7 +5,6 @@ import jalview.api.FeaturesDisplayedI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceFeature;
 import jalview.datamodel.SequenceI;
-import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.schemes.GraduatedColor;
 import jalview.schemes.UserColourScheme;
 import jalview.util.QuickSort;
@@ -72,7 +71,7 @@ public abstract class FeatureRendererModel implements
    */
   public void transferSettings(jalview.api.FeatureRenderer _fr)
   {
-    FeatureRenderer fr = (FeatureRenderer) _fr;
+    FeatureRendererModel fr = (FeatureRendererModel) _fr;
     FeatureRendererSettings frs = new FeatureRendererSettings(fr);
     this.renderOrder = frs.renderOrder;
     this.featureGroups = frs.featureGroups;
@@ -508,7 +507,7 @@ public abstract class FeatureRendererModel implements
     }
     if (iSize > 1 && sort)
     {
-      QuickSort.sortFloat(sortOrder, newf);
+      QuickSort.sortFloatObject(sortOrder, newf);
     }
     sortOrder = null;
     System.arraycopy(newf, 0, renderOrder, opos, newf.length);
index f244242..e12c5b8 100644 (file)
@@ -44,6 +44,7 @@ public class ConsensusThread extends AlignCalcWorker implements
   @Override
   public void run()
   {
+       
     if (calcMan.isPending(this))
     {
       return;
diff --git a/src/javajs/J2SIgnoreImport.java b/src/javajs/J2SIgnoreImport.java
new file mode 100644 (file)
index 0000000..b92c82b
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs;
+
+public @interface J2SIgnoreImport {
+
+       Class<?>[] value();
+
+}
diff --git a/src/javajs/J2SRequireImport.java b/src/javajs/J2SRequireImport.java
new file mode 100644 (file)
index 0000000..646cebd
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs;
+
+public @interface J2SRequireImport {
+
+       Class<?>[] value();
+
+}
diff --git a/src/javajs/api/BytePoster.java b/src/javajs/api/BytePoster.java
new file mode 100644 (file)
index 0000000..0b0f29a
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.api;
+
+public interface BytePoster {
+
+  String postByteArray(String fileName, byte[] bytes);
+
+}
diff --git a/src/javajs/api/EigenInterface.java b/src/javajs/api/EigenInterface.java
new file mode 100644 (file)
index 0000000..4a1b592
--- /dev/null
@@ -0,0 +1,15 @@
+package javajs.api;
+
+import javajs.util.V3;
+
+public interface EigenInterface {
+
+  EigenInterface setM(double[][] n);
+
+  double[] getEigenvalues();
+
+  void fillFloatArrays(V3[] eigenVectors, float[] eigenValues);
+
+  float[][] getEigenvectorsFloatTransposed();
+
+}
diff --git a/src/javajs/api/EventManager.java b/src/javajs/api/EventManager.java
new file mode 100644 (file)
index 0000000..a2994be
--- /dev/null
@@ -0,0 +1,16 @@
+package javajs.api;
+
+public interface EventManager {
+
+  boolean keyPressed(int keyCode, int modifiers);
+
+  boolean keyTyped(int keyChar, int modifiers);
+
+  void keyReleased(int keyCode);
+
+  void mouseEnterExit(long time, int x, int y, boolean isExit);
+  
+  void mouseAction(int mode, long time, int x, int y, int count,
+                   int buttonMods);
+
+}
diff --git a/src/javajs/api/FontManager.java b/src/javajs/api/FontManager.java
new file mode 100644 (file)
index 0000000..cc442c4
--- /dev/null
@@ -0,0 +1,23 @@
+package javajs.api;
+
+import javajs.awt.Font;
+
+/**
+ * A generic interface for font queries.
+ * In JSmol it is handled by org.jmol.api.ApiPlatform
+ */
+
+public interface FontManager {
+
+  int fontStringWidth(Font font, String text);
+
+  int getFontAscent(Object fontMetrics);
+
+  int getFontDescent(Object fontMetrics);
+
+  Object getFontMetrics(Font font, Object graphics);
+
+  Object newFont(String fontFace, boolean isBold, boolean isItalic, float fontSize);
+
+
+}
diff --git a/src/javajs/api/GenericBinaryDocument.java b/src/javajs/api/GenericBinaryDocument.java
new file mode 100644 (file)
index 0000000..3cf4739
--- /dev/null
@@ -0,0 +1,53 @@
+package javajs.api;
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.util.Map;
+
+
+import javajs.util.OC;
+import javajs.util.SB;
+
+public interface GenericBinaryDocument {
+
+  void setStream(GenericZipTools jzt, BufferedInputStream bis, boolean isBigEndian);
+
+  void setStreamData(DataInputStream dataInputStream, boolean isBigEndian);
+
+  long getPosition();
+
+  SB getAllDataFiles(String binaryFileList, String firstFile);
+
+  void getAllDataMapped(String replace, String string, Map<String, String> fileData);
+
+  int swapBytesI(int nx);
+
+  short swapBytesS(short s);
+
+  void seek(long i);
+
+  byte readByte() throws Exception;
+
+  int readInt() throws Exception;
+
+  int readIntLE() throws Exception;
+
+  long readLong() throws Exception;
+
+  float readFloat() throws Exception;
+
+  double readDouble() throws Exception;
+
+  short readShort() throws Exception;
+
+  int readUnsignedShort() throws Exception;
+
+  String readString(int i) throws Exception;
+
+  int readByteArray(byte[] b, int off, int len) throws Exception;
+
+  void close();
+
+  void setOutputChannel(OC out);
+
+}
diff --git a/src/javajs/api/GenericCifDataParser.java b/src/javajs/api/GenericCifDataParser.java
new file mode 100644 (file)
index 0000000..8dc0091
--- /dev/null
@@ -0,0 +1,45 @@
+package javajs.api;
+
+import java.io.BufferedReader;
+import java.util.Map;
+
+
+public interface GenericCifDataParser {
+
+  static final int NONE = -1;
+
+  String fullTrim(String str);
+
+  Map<String, Object> getAllCifData();
+
+  boolean getData() throws Exception;
+
+  String getField(int i);
+
+  int getFieldCount();
+
+  String getFileHeader();
+
+  String getLoopData(int i);
+
+  String getNextDataToken() throws Exception;
+
+  String getNextToken() throws Exception;
+
+  String getTokenPeeked();
+
+  int parseLoopParameters(String[] fields, int[] fieldOf, int[] propertyOf) throws Exception;
+
+  String peekToken() throws Exception;
+
+  String readLine();
+
+  GenericCifDataParser set(GenericLineReader reader, BufferedReader br);
+
+  String toUnicode(String data);
+
+  String skipLoop(boolean doReport) throws Exception;
+
+  String fixKey(String key);
+
+}
diff --git a/src/javajs/api/GenericColor.java b/src/javajs/api/GenericColor.java
new file mode 100644 (file)
index 0000000..57cf169
--- /dev/null
@@ -0,0 +1,19 @@
+package javajs.api;
+
+/**
+ * GenericColor allows both java.awt.Color and javajs.awt.Color to be
+ * handled by methods that need not distinguish between them. It is used
+ * in the javajs package for the background color of a javajs.swing.JComponent
+ * 
+ * @author hansonr
+ *
+ */
+public interface GenericColor {
+
+       int getRGB();
+
+       int getOpacity255();
+
+       void setOpacity255(int a);
+       
+}
diff --git a/src/javajs/api/GenericFileInterface.java b/src/javajs/api/GenericFileInterface.java
new file mode 100644 (file)
index 0000000..2a32b51
--- /dev/null
@@ -0,0 +1,15 @@
+package javajs.api;
+
+public interface GenericFileInterface {
+
+  String getFullPath();
+
+  String getName();
+
+  long length();
+
+  boolean isDirectory();
+
+  GenericFileInterface getParentAsFile();
+
+}
diff --git a/src/javajs/api/GenericImageDialog.java b/src/javajs/api/GenericImageDialog.java
new file mode 100644 (file)
index 0000000..54d8503
--- /dev/null
@@ -0,0 +1,9 @@
+package javajs.api;
+
+public interface GenericImageDialog {
+
+  void closeMe();
+
+  void setImage(Object image);
+
+}
diff --git a/src/javajs/api/GenericImageEncoder.java b/src/javajs/api/GenericImageEncoder.java
new file mode 100644 (file)
index 0000000..9aa7477
--- /dev/null
@@ -0,0 +1,12 @@
+package javajs.api;
+
+import java.util.Map;
+
+import javajs.util.OC;
+
+public interface GenericImageEncoder {
+
+  public boolean createImage(String type, OC out,
+                             Map<String, Object> params) throws Exception;
+
+}
diff --git a/src/javajs/api/GenericLineReader.java b/src/javajs/api/GenericLineReader.java
new file mode 100644 (file)
index 0000000..f113a8b
--- /dev/null
@@ -0,0 +1,5 @@
+package javajs.api;
+
+public interface GenericLineReader {
+  public String readNextLine() throws Exception;
+}
diff --git a/src/javajs/api/GenericMenuInterface.java b/src/javajs/api/GenericMenuInterface.java
new file mode 100644 (file)
index 0000000..b4017ee
--- /dev/null
@@ -0,0 +1,18 @@
+package javajs.api;
+
+
+public interface GenericMenuInterface {
+
+  public void jpiDispose();
+  public Object jpiGetMenuAsObject();
+  public String jpiGetMenuAsString(String string);
+  public void jpiInitialize(PlatformViewer vwr, String menu);
+  public void jpiShow(int x, int y);
+  public void jpiUpdateComputedMenus();
+  
+  public void menuClickCallback(SC source, String actionCommand);
+  public void menuFocusCallback(String name, String actionCommand, boolean b);
+  public void menuCheckBoxCallback(SC source);
+
+}
diff --git a/src/javajs/api/GenericMouseInterface.java b/src/javajs/api/GenericMouseInterface.java
new file mode 100644 (file)
index 0000000..2b468e4
--- /dev/null
@@ -0,0 +1,13 @@
+package javajs.api;
+
+public interface GenericMouseInterface {
+
+  boolean processEvent(int id, int x, int y, int modifiers, long time);
+
+  void clear();
+
+  void dispose();
+
+       void processTwoPointGesture(float[][][] touches);
+
+}
diff --git a/src/javajs/api/GenericPlatform.java b/src/javajs/api/GenericPlatform.java
new file mode 100644 (file)
index 0000000..9c99e41
--- /dev/null
@@ -0,0 +1,141 @@
+package javajs.api;
+
+
+import java.net.URL;
+import java.util.Map;
+
+
+import javajs.awt.Font;
+import javajs.util.P3;
+
+public interface GenericPlatform extends FontManager {
+
+  public final static int CURSOR_DEFAULT = 0;
+  public final static int CURSOR_CROSSHAIR = 1;
+  public final static int CURSOR_WAIT = 3;
+  public final static int CURSOR_ZOOM = 8;
+  public final static int CURSOR_HAND = 12;
+  public final static int CURSOR_MOVE = 13;
+
+  void setViewer(PlatformViewer vwr, Object display);
+  
+  /////// Display
+
+  boolean isHeadless();
+  
+  void convertPointFromScreen(Object display, P3 ptTemp);
+
+  void getFullScreenDimensions(Object display, int[] widthHeight);
+  
+  boolean hasFocus(Object display);
+
+  String prompt(String label, String data, String[] list, boolean asButtons);
+
+  void repaint(Object display);
+
+  void requestFocusInWindow(Object display);
+
+  void setCursor(int i, Object display);
+
+  void setTransparentCursor(Object display);
+
+  ////  Mouse 
+
+  GenericMouseInterface getMouseManager(double privateKey, Object display);
+
+  ///// core Image handling
+  
+  Object allocateRgbImage(int windowWidth, int windowHeight, int[] pBuffer,
+                          int windowSize, boolean backgroundTransparent, boolean isImageWrite);
+
+  void disposeGraphics(Object graphicForText);
+
+  void drawImage(Object g, Object img, int x, int y, int width, int height);
+
+  int[] drawImageToBuffer(Object gObj, Object imageOffscreen,
+                          Object image, int width, int height, int bgcolor);
+
+  void flushImage(Object imagePixelBuffer);
+
+  Object getStaticGraphics(Object image, boolean backgroundTransparent);
+
+  Object getGraphics(Object image);
+
+  int getImageWidth(Object image);
+
+  int getImageHeight(Object image);
+
+  Object newBufferedImage(Object image, int i, int height);
+
+  Object newOffScreenImage(int w, int h);
+  
+  @Deprecated
+  void renderScreenImage(Object g, Object currentSize);
+
+  int[] getTextPixels(String text, Font font3d, Object gObj,
+                      Object image, int mapWidth, int height,
+                      int ascent);
+
+  ///// Image creation for export (optional for any platform)
+
+  /**
+   * can be ignored (return null) if platform cannot save images
+   * 
+   * @param ret
+   * @return     null only if this platform cannot save images
+   */
+  Object createImage(Object ret);
+
+  /**
+   * 
+   * @param image
+   * @param width
+   * @param height
+   * @param pixels 
+   * @param startRow 
+   * @param nRows 
+   * @return         pixels
+   */
+  int[] grabPixels(Object image, int width, int height, 
+                   int[] pixels, int startRow, int nRows);
+
+  /**
+   * can be ignored (return false) if platform cannot save images
+   * 
+   * @param boolIsEcho
+   * @param image
+   * @return        false only if this platform cannot save images
+   * @throws InterruptedException
+   */
+  boolean waitForDisplay(Object boolIsEcho, Object image) throws InterruptedException;
+
+  GenericMenuInterface getMenuPopup(String menuStructure, char type);
+
+  Object getJsObjectInfo(Object[] jsObject, String method, Object[] args);
+
+  boolean isSingleThreaded();
+
+  void notifyEndOfRendering();
+
+  String getDateFormat(String isoType);
+  
+  GenericFileInterface newFile(String name);
+  
+  Object getBufferedFileInputStream(String name);
+  
+  /**
+   * 
+   * @param url
+   * @param outputBytes
+   * @param post
+   * @param asString
+   * @return may be javajs.util.SB or byte[] or java.io.InputStream
+   */
+  Object getURLContents(URL url, byte[] outputBytes, String post, boolean asString);
+
+  String getLocalUrl(String fileName);
+
+  GenericImageDialog getImageDialog(String title,
+                                 Map<String, GenericImageDialog> imageMap);
+
+}
diff --git a/src/javajs/api/GenericZipInputStream.java b/src/javajs/api/GenericZipInputStream.java
new file mode 100644 (file)
index 0000000..e2e8018
--- /dev/null
@@ -0,0 +1,13 @@
+package javajs.api;
+
+
+import java.io.InputStream;
+import java.util.zip.ZipInputStream;
+
+public class GenericZipInputStream extends ZipInputStream implements ZInputStream {
+  
+  public GenericZipInputStream(InputStream in) {
+    super(in);
+  }
+  
+}
\ No newline at end of file
diff --git a/src/javajs/api/GenericZipTools.java b/src/javajs/api/GenericZipTools.java
new file mode 100644 (file)
index 0000000..2fcaa10
--- /dev/null
@@ -0,0 +1,45 @@
+package javajs.api;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.util.Map;
+
+
+public interface GenericZipTools {
+
+  public ZInputStream newZipInputStream(InputStream is);
+  
+  public String getZipDirectoryAsStringAndClose(BufferedInputStream t);
+
+  public InputStream newGZIPInputStream(InputStream bis) throws IOException;
+
+  public Object getZipFileDirectory(BufferedInputStream bis,
+                                          String[] subFileList, int listPtr, boolean asBufferedInputStream);
+
+  public String[] getZipDirectoryAndClose(BufferedInputStream t,
+                                                 String manifestID);
+
+  public void getAllZipData(InputStream bis, String[] subFileList,
+                                String replace, String string,
+                                Map<String, String> fileData);
+
+  public Object getZipFileContentsAsBytes(BufferedInputStream bis,
+                                                 String[] subFileList, int i);
+
+  public void addZipEntry(Object zos, String fileName) throws IOException;
+
+  public void closeZipEntry(Object zos) throws IOException;
+
+  public Object getZipOutputStream(Object bos);
+
+  public int getCrcValue(byte[] bytes);
+
+  public void readFileAsMap(BufferedInputStream is, Map<String, Object> bdata, String name);
+
+  public String cacheZipContents(BufferedInputStream bis, String shortName,
+                                 Map<String, Object> cache, boolean asByteArray);
+
+  BufferedInputStream getUnGzippedInputStream(byte[] bytes);
+}
diff --git a/src/javajs/api/HTMLElement.java b/src/javajs/api/HTMLElement.java
new file mode 100644 (file)
index 0000000..ad67114
--- /dev/null
@@ -0,0 +1,5 @@
+package javajs.api;
+
+public interface HTMLElement {
+
+}
diff --git a/src/javajs/api/HTMLWindowEvent.java b/src/javajs/api/HTMLWindowEvent.java
new file mode 100644 (file)
index 0000000..0321e36
--- /dev/null
@@ -0,0 +1,10 @@
+package javajs.api;
+
+/** 
+ * The window.Event in HTML5
+ * See SwingController.
+ * 
+ */
+public interface HTMLWindowEvent {
+
+}
diff --git a/src/javajs/api/Interface.java b/src/javajs/api/Interface.java
new file mode 100644 (file)
index 0000000..a4c9e3f
--- /dev/null
@@ -0,0 +1,40 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2006  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.api;
+
+public class Interface {
+
+  public static Object getInterface(String name) {
+    try {
+      Class<?> x = Class.forName(name);
+      return (x == null ? null : x.newInstance());
+    } catch (Exception e) {
+      System.out.println("Interface.java Error creating instance for " + name + ": \n" + e);
+      return null;
+    }
+  }
+
+}
diff --git a/src/javajs/api/JSInterface.java b/src/javajs/api/JSInterface.java
new file mode 100644 (file)
index 0000000..0f785fa
--- /dev/null
@@ -0,0 +1,30 @@
+package javajs.api;
+
+/** 
+ * called by JSmol JavaScript methods using
+ * 
+ *  this._applet.xxxx()
+ *  
+ */
+public interface JSInterface {
+
+  int cacheFileByName(String fileName, boolean isAdd);
+  void cachePut(String key, Object data);
+  void destroy();
+  String getFullName();
+  void openFileAsyncSpecial(String fileName, int flags);
+  boolean processMouseEvent(int id, int x, int y, int modifiers, long time);
+  void processTwoPointGesture(float[][][] touches);
+  void setDisplay(Object canvas);
+  void setScreenDimension(int width, int height);
+  boolean setStatusDragDropped(int mode, int x, int y, String fileName);
+       void startHoverWatcher(boolean enable);
+       void update();
+
+       // these are not general methods
+//Object getGLmolView();
+//String loadInlineString(String mol, String script, boolean isAppend);
+//String openFile(String fileName);
+
+}
+
diff --git a/src/javajs/api/JSONEncodable.java b/src/javajs/api/JSONEncodable.java
new file mode 100644 (file)
index 0000000..b013279
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.api;
+
+public interface JSONEncodable {
+
+  String toJSON();
+
+}
diff --git a/src/javajs/api/JmolObjectInterface.java b/src/javajs/api/JmolObjectInterface.java
new file mode 100644 (file)
index 0000000..e1872ee
--- /dev/null
@@ -0,0 +1,12 @@
+package javajs.api;
+
+/**
+ * methods in JSmol JavaScript accessed in Jmol 
+ */
+public interface JmolObjectInterface {
+
+  Object _doAjax(Object url, String postOut, Object bytesOrStringOut);
+
+  void _apply(Object func, Object data);
+
+}
diff --git a/src/javajs/api/PlatformViewer.java b/src/javajs/api/PlatformViewer.java
new file mode 100644 (file)
index 0000000..cd308bf
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.api;
+
+public interface PlatformViewer {
+
+// a placeholder for a class that might be used within classes called by Platform.java
+  
+}
diff --git a/src/javajs/api/SC.java b/src/javajs/api/SC.java
new file mode 100644 (file)
index 0000000..1c6da16
--- /dev/null
@@ -0,0 +1,65 @@
+package javajs.api;
+
+/**
+ * SwingComponent interface common to javax.swing and javajs.swing
+ * 
+ * Can be augmented as needed, provided classes of javajs.swing are also
+ * updated. (SwingComponents in javajs are subclasses of AbstractButton.)
+ * 
+ */
+
+public interface SC {
+
+  void add(SC item);
+
+  void addActionListener(Object owner);
+
+  void addItemListener(Object owner);
+
+  void addMouseListener(Object owner);
+
+  String getActionCommand();
+
+  Object getComponent(int i);
+
+  int getComponentCount();
+
+  Object[] getComponents();
+
+  String getName();
+
+  Object getParent();
+
+  Object getPopupMenu();
+
+  Object getIcon();
+
+  String getText();
+
+  void init(String text, Object icon, String actionCommand, SC popupMenu);
+
+  void insert(SC subMenu, int index);
+
+  boolean isEnabled();
+
+  boolean isSelected();
+
+  void remove(int i);
+
+  void removeAll();
+
+  void setActionCommand(String script);
+
+  void setAutoscrolls(boolean b);
+
+  void setEnabled(boolean enable);
+
+  void setIcon(Object icon);
+
+  void setName(String string);
+
+  void setSelected(boolean state);
+
+  void setText(String entry);
+
+}
diff --git a/src/javajs/api/SwingController.java b/src/javajs/api/SwingController.java
new file mode 100644 (file)
index 0000000..68aace5
--- /dev/null
@@ -0,0 +1,136 @@
+package javajs.api;
+
+import javajs.awt.Component;
+import javajs.awt.Dimension;
+
+/**
+ * SwingController is an interface that javajs.swing classes will need.
+ * It must be implemented as a JavaScript object PRIOR to 
+ * any calls to create any components.
+ * 
+ * In JSmol it is Jmol.Swing (see JsmolCore.js)
+ * 
+ * There should be one and only one SwingController on a page. 
+ * It is called by its class name "SwingController" directly. 
+ * 
+ * @author hansonr
+ * 
+ */
+public interface SwingController {
+  
+  /**
+   * Fired from clicking an element such as a button or 
+   * check box or table entry, or from entering text in a text box.
+   * 
+   * SwingController should make the changes in the underlying 
+   * "Java" object directly, then send notification of the event to the manager.
+   * For instance:
+   * 
+   *   var component = Jmol.Swing.htDialogs[element.id];
+   *   var info = component.toString();
+   *   
+   * if (info.indexOf("JCheck") >= 0)
+   *     component.selected = element.checked;
+   * var id = $("div.JDialog:has(#" + element.id + ")")[0].id
+   * var dialog = Jmol.Swing.htDialogs[id];
+   * dialog.manager.actionPerformed(component ? component.name :  dialog.registryKey + "/" + element.id);
+   * 
+   * @param element
+   * @param event 
+   */
+  void click(HTMLElement element, HTMLWindowEvent event);
+  
+
+  /**
+   * Remove this component's HTML5 equivalent and clear references to it.
+   * 
+   * @param dialog
+   */
+  void dispose(Component dialog);
+  
+  /**
+   * Return the width and height of the window in d.
+   * For example:
+   * 
+   * d.width = $(window).width();
+   * d.height = $(window).height();
+   *
+   * @param d
+   */
+  void getScreenDimensions(Dimension d);
+  
+  /**
+   * Set c's id to a unique identifier
+   * and add it to an associative array that will
+   * associate that id with c.
+   * 
+   * @param c
+   * @param type
+   */
+  void register(Component c, String type);
+  
+  /**
+   * The HTML for this dialog has been generated.
+   * Now create the HTML on the page for this dialog
+   * based on dialog.html and wrap it appropriately.
+   * 
+   * @param dialog
+   */
+  void setDialog(Component dialog);
+  
+  /**
+   * Convey to the HTML object that this check box's selection
+   * has been changed.
+   * 
+   *  $("#" + chk.id).prop('checked', !!chk.selected);
+   *  
+   * @param chk
+   */
+  void setSelected(Component chk);
+  
+  /**
+   * Convey to the HTML object that this combo box's selected item
+   * has been changed.
+   * 
+   *  $("#" + cmb.id).prop('selectedIndex', cmb.selectedIndex);
+   *  
+   * @param cmb
+   */
+  void setSelectedIndex(Component cmb);
+  
+  /**
+   * Convey to the HTML object that this component's text
+   * has been changed.
+   * 
+   *  $("#" + btn.id).prop('value', btn.text);
+   *  
+   * @param text
+   */
+  void setText(String text);
+  
+  /**
+   * Convey to the HTML object that this component's text
+   * has been changed.
+   * 
+   *   if (c.visible)
+   *     $("#" + c.id).show();
+   *   else
+   *     $("#" + c.id).hide();  
+   *
+   * @param c
+   */  
+  void setVisible(Component c);
+  
+  /**
+   * Called by clicking the [x] in the corner of the dialog;
+   * send a notification back to the manager via processWindowClosing(key)
+   * 
+   *   var id = $("div.JDialog:has(#" + element.id + ")")[0].id
+   *   var dialog = Jmol.Swing.htDialogs[id];
+   *   dialog.manager.processWindowClosing(dialog.registryKey);
+   * 
+   * @param element
+   */
+  void windowClosing(HTMLElement element);
+}
diff --git a/src/javajs/api/ZInputStream.java b/src/javajs/api/ZInputStream.java
new file mode 100644 (file)
index 0000000..a3310f6
--- /dev/null
@@ -0,0 +1,6 @@
+package javajs.api;
+
+public interface ZInputStream {
+  // placeholder for ZipInputStream not requiring direct access to java.util.zip
+
+}
diff --git a/src/javajs/awt/BorderLayout.java b/src/javajs/awt/BorderLayout.java
new file mode 100644 (file)
index 0000000..0ee97db
--- /dev/null
@@ -0,0 +1,12 @@
+package javajs.awt;
+
+
+public class BorderLayout extends LayoutManager {
+
+       public static final String CENTER = "Center";
+       public static final String NORTH = "North";
+       public static final String SOUTH = "South";
+       public static final String EAST = "East";
+       public static final String WEST = "West";
+       
+}
diff --git a/src/javajs/awt/Color.java b/src/javajs/awt/Color.java
new file mode 100644 (file)
index 0000000..82c27f2
--- /dev/null
@@ -0,0 +1,53 @@
+package javajs.awt;
+
+import javajs.api.GenericColor;
+
+public class Color implements GenericColor {
+
+       public int argb;
+
+
+  @Override
+  public int getRGB() {
+               return argb & 0x00FFFFFF;
+       }
+
+
+  @Override
+  public int getOpacity255() {
+               return ((argb >> 24) & 0xFF);
+       }
+
+       
+  @Override
+  public void setOpacity255(int a) {
+               argb = argb & 0xFFFFFF | ((a & 0xFF) << 24);
+       }
+
+       public static GenericColor get1(int rgb) {
+               Color c = new Color();
+               c.argb = rgb | 0xFF000000;
+               return c;
+       }
+
+       public static GenericColor get3(int r, int g, int b) {
+               return new Color().set4(r, g, b, 0xFF);
+       }
+
+       public static GenericColor get4(int r, int g, int b, int a) {
+               return new Color().set4(r, g, b, a);
+       }
+
+       private GenericColor set4(int r, int g, int b, int a) {
+               argb = ((a << 24) | (r << 16) | (g << 8) | b) & 0xFFFFFFFF;
+               return this;
+       }
+
+  @Override
+  public String toString() {
+    String s = ("00000000" + Integer.toHexString(argb));
+    return "[0x" + s.substring(s.length() - 8, s.length()) + "]";
+  }
+
+       
+}
diff --git a/src/javajs/awt/Component.java b/src/javajs/awt/Component.java
new file mode 100644 (file)
index 0000000..505d0b3
--- /dev/null
@@ -0,0 +1,155 @@
+package javajs.awt;
+
+import javajs.api.GenericColor;
+import javajs.util.CU;
+
+abstract public class Component {
+
+  protected boolean visible;  
+  protected boolean enabled = true;
+  protected String text;    
+  protected String name;
+  protected int width;
+  protected int height;
+  protected String id;
+
+  protected Object parent;
+  
+  public void setParent(Object p) {
+    parent = p;
+  }
+
+  protected Object mouseListener;
+
+  private GenericColor bgcolor;
+
+  protected Component(String type) {
+    id = newID(type);
+    if (type == null)
+      return;
+    /**
+     * @j2sNative
+     *            SwingController.register(this, type);
+     */
+    {
+    }
+
+  }
+  
+  public static String newID(String type) {
+    return type + ("" + Math.random()).substring(3, 10);
+  }
+
+  abstract public String toHTML();
+  
+  public void setBackground(GenericColor color) {
+    bgcolor = color;
+  }
+
+  public void setText(String text) {
+    this.text = text;
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setText(this);
+     * 
+     */
+    {
+    }
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public String getName() {
+    return name;
+  }
+  
+  public Object getParent() {
+    return parent;
+  }
+  
+  public void setPreferredSize(Dimension dimension) {
+    this.width = dimension.width;
+    this.height = dimension.height;   
+  }
+
+  public void addMouseListener(Object listener) {
+    mouseListener = listener;
+  }
+
+  public String getText() {
+    return text;
+  }
+
+  public boolean isEnabled() {
+    return enabled;
+  }
+  
+  public void setEnabled(boolean enabled) {
+    this.enabled = enabled;
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setEnabled(this);
+     * 
+     */
+    {}
+  }
+
+  public boolean isVisible() {
+    return visible;
+  }
+
+  public void setVisible(boolean visible) {
+    this.visible = visible;
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setVisible(this);
+     * 
+     */
+    {}
+  }
+
+  public int getHeight() {
+    return height;
+  }
+
+  public int getWidth() {
+    return width;
+  }
+
+  protected int minWidth = 30;
+  protected int minHeight = 30;
+
+  public void setMinimumSize(Dimension d) {
+    minWidth = d.width;
+    minHeight = d.height;
+  }
+
+  public int getSubcomponentWidth() {
+    return width;
+  }
+  
+  public int getSubcomponentHeight() {
+    return height;
+  }
+  
+  protected int renderWidth;
+  protected int renderHeight;
+
+  protected String getCSSstyle(int defaultPercentW, int defaultPercentH) {
+    int width = (renderWidth > 0 ? renderWidth : getSubcomponentWidth());
+    int height = (renderHeight > 0 ? renderHeight : getSubcomponentHeight());
+    return (width > 0 ? "width:" + width +"px;" : defaultPercentW > 0 ? "width:"+defaultPercentW+"%;" : "")
+    + (height > 0 ?"height:" + height + "px;" : defaultPercentH > 0 ? "height:"+defaultPercentH+"%;" : "")
+    + (bgcolor == null ? "" : "background-color:" + CU.toCSSString(bgcolor) + ";");
+  }
+  
+  public void repaint() {
+    // for inheritance
+  }
+
+}
diff --git a/src/javajs/awt/Container.java b/src/javajs/awt/Container.java
new file mode 100644 (file)
index 0000000..7ef6e90
--- /dev/null
@@ -0,0 +1,79 @@
+package javajs.awt;
+
+import javajs.util.Lst;
+  
+abstract public class Container extends Component {
+  
+  protected Lst<Component> list;
+  
+  private Component[] cList;
+
+  protected Container(String type) {
+    super(type);
+  }
+  
+  public Component getComponent(int i) {
+    return list.get(i);
+  }
+  
+  public int getComponentCount() {
+    return (list == null ? 0 : list.size());
+  }
+
+  public Component[] getComponents() {
+    if (cList == null) {
+      if (list == null)
+        return new Component[0];
+      cList = (Component[]) list.toArray();
+    }
+    return cList;
+  }
+
+  public Component add(Component component) {
+    return addComponent(component);
+  }
+
+  protected Component addComponent(Component component) {
+    if (list == null)
+      list = new Lst<Component>();
+    list.addLast(component);
+    cList = null;
+    component.parent = this;
+    return component;
+  }
+
+  protected Component insertComponent(Component component, int index) {
+    if (list == null)
+      return addComponent(component);
+    list.add(index, component);
+    cList = null;
+    component.parent = this;
+    return component;
+  }
+
+  public void remove(int i) {
+    Component c = list.remove(i);
+    c.parent = null;
+    cList = null;
+  }
+  
+  public void removeAll() {
+    if (list != null) {
+      for (int i = list.size(); --i >= 0;)
+        list.get(i).parent = null;
+      list.clear();
+    }
+    cList = null;
+  }
+
+  @Override
+  public int getSubcomponentWidth() {
+    return (list != null && list.size() == 1 ? list.get(0).getSubcomponentWidth() : 0);
+  }
+  
+  @Override
+  public int getSubcomponentHeight() {
+    return (list != null && list.size() == 1 ? list.get(0).getSubcomponentHeight() : 0);
+  }
+
+}
diff --git a/src/javajs/awt/Dimension.java b/src/javajs/awt/Dimension.java
new file mode 100644 (file)
index 0000000..02d9935
--- /dev/null
@@ -0,0 +1,18 @@
+package javajs.awt;
+
+public class Dimension {
+
+  public int width;
+  public int height;
+
+  public Dimension(int w, int h) {
+    set(w, h);
+  }
+
+  public Dimension set(int w, int h) {
+    width = w;
+    height = h;
+    return this;
+  }
+
+}
diff --git a/src/javajs/awt/Font.java b/src/javajs/awt/Font.java
new file mode 100644 (file)
index 0000000..416089b
--- /dev/null
@@ -0,0 +1,170 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2013-10-30 13:47:37 -0500 (Wed, 30 Oct 2013) $
+ * $Revision: 18874 $
+ *
+ * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.awt;
+
+
+import javajs.api.FontManager;
+import javajs.util.AU;
+
+
+/**
+ *<p>
+ * Provides font support using a byte fid
+ * (<strong>F</strong>ont <strong>ID</strong>) as an index into font table.
+ *</p>
+ *<p>
+ * Supports standard font faces, font styles, and font sizes.
+ *</p>
+ *
+ * @author Miguel, miguel@jmol.org
+ */
+final public class Font {
+
+  public final byte fid;
+  public final String fontFace;
+  public final String fontStyle;
+  public final float fontSizeNominal;
+  public final int idFontFace;
+  public final int idFontStyle;
+  public final float fontSize;
+  public final Object font;
+  private final Object fontMetrics;
+  private FontManager manager;
+  private int ascent;
+  private int descent;
+  private boolean isBold;
+  private boolean isItalic;
+  
+  private Font(FontManager manager, byte fid, int idFontFace,
+      int idFontStyle, float fontSize, float fontSizeNominal, Object graphics) {
+    this.manager = manager;
+    this.fid = fid;
+    this.fontFace = fontFaces[idFontFace];
+    this.fontStyle = fontStyles[idFontStyle];
+    this.idFontFace = idFontFace;
+    this.idFontStyle = idFontStyle;
+    this.fontSize = fontSize;
+    this.isBold = (idFontStyle & FONT_STYLE_BOLD) == FONT_STYLE_BOLD;
+    this.isItalic = (idFontStyle & FONT_STYLE_ITALIC) == FONT_STYLE_ITALIC;
+    this.fontSizeNominal = fontSizeNominal;
+    font = manager.newFont(fontFaces[idFontFace], isBold, isItalic,
+        fontSize);
+    fontMetrics = manager.getFontMetrics(this, graphics);
+    descent = manager.getFontDescent(fontMetrics);
+    ascent = manager.getFontAscent(fontMetrics);
+
+    //System.out.println("font3d constructed for fontsizeNominal=" + fontSizeNominal + "  and fontSize=" + fontSize);
+  }
+
+  ////////////////////////////////////////////////////////////////
+  
+  private final static int FONT_ALLOCATION_UNIT = 8;
+  private static int fontkeyCount = 1;
+  private static int[] fontkeys = new int[FONT_ALLOCATION_UNIT];
+  private static Font[] font3ds = new Font[FONT_ALLOCATION_UNIT];
+
+  public static Font getFont3D(byte fontID) {
+    return font3ds[fontID & 0xFF];
+  }
+  
+  public static synchronized Font createFont3D(int fontface, int fontstyle,
+                                       float fontsize, float fontsizeNominal,
+                                       FontManager manager, Object graphicsForMetrics) {
+    //if (graphicsForMetrics == null)
+     // return null;
+    if (fontsize > 0xFF)
+      fontsize = 0xFF;
+    int fontsizeX16 = ((int) fontsize) << 4;
+    int fontkey = ((fontface & 3) | ((fontstyle & 3) << 2) | (fontsizeX16 << 4));
+    // watch out for race condition here!
+    for (int i = fontkeyCount; --i > 0;)
+      if (fontkey == fontkeys[i]
+          && font3ds[i].fontSizeNominal == fontsizeNominal)
+        return font3ds[i];
+    int fontIndexNext = fontkeyCount++;
+    if (fontIndexNext == fontkeys.length)
+      fontkeys = AU.arrayCopyI(fontkeys, fontIndexNext + FONT_ALLOCATION_UNIT);
+      font3ds = (Font[]) AU.arrayCopyObject(font3ds, fontIndexNext + FONT_ALLOCATION_UNIT);
+    Font font3d = new Font(manager, (byte) fontIndexNext, fontface, fontstyle,
+        fontsize, fontsizeNominal, graphicsForMetrics);
+    // you must set the font3d before setting the fontkey in order
+    // to prevent a race condition with getFont3D
+    font3ds[fontIndexNext] = font3d;
+    fontkeys[fontIndexNext] = fontkey;
+    return font3d;
+  }
+
+  public final static int FONT_FACE_SANS  = 0;
+  public final static int FONT_FACE_SERIF = 1;
+  public final static int FONT_FACE_MONO  = 2;
+  
+  private final static String[] fontFaces =
+  {"SansSerif", "Serif", "Monospaced", ""};
+
+  public final static int FONT_STYLE_PLAIN      = 0;
+  public final static int FONT_STYLE_BOLD       = 1;
+  public final static int FONT_STYLE_ITALIC     = 2;
+  public final static int FONT_STYLE_BOLDITALIC = 3;
+  
+  private final static String[] fontStyles =
+  {"Plain", "Bold", "Italic", "BoldItalic"};
+  
+  public static int getFontFaceID(String fontface) {
+    return ("Monospaced".equalsIgnoreCase(fontface) ? FONT_FACE_MONO 
+        : "Serif".equalsIgnoreCase(fontface) ? FONT_FACE_SERIF 
+        : FONT_FACE_SANS);
+  }
+
+  public static int getFontStyleID(String fontstyle) {
+    for (int i = 4; --i >= 0; )
+      if (fontStyles[i].equalsIgnoreCase(fontstyle))
+       return i;
+    return -1;
+  }
+
+  public int getAscent() {
+    return ascent;
+  }
+  
+  public int getDescent() {
+    return descent;
+  }
+  
+  public int getHeight() {
+    return getAscent() + getDescent();
+  }
+
+  public Object getFontMetrics() {
+    return fontMetrics;
+  }
+  
+  public int stringWidth(String text) {
+    return manager.fontStringWidth(this, text);
+  }
+
+  public String getInfo() {
+    return  fontSizeNominal + " " + fontFace + " " + fontStyle;
+  }
+}
+
diff --git a/src/javajs/awt/LayoutManager.java b/src/javajs/awt/LayoutManager.java
new file mode 100644 (file)
index 0000000..00e989e
--- /dev/null
@@ -0,0 +1,5 @@
+package javajs.awt;
+
+public class LayoutManager {
+
+}
diff --git a/src/javajs/awt/event/ActionEvent.java b/src/javajs/awt/event/ActionEvent.java
new file mode 100644 (file)
index 0000000..e24ea13
--- /dev/null
@@ -0,0 +1,12 @@
+package javajs.awt.event;
+
+
+public class ActionEvent extends Event {
+
+  private String actionCommand;
+
+  public String getActionCommand() {
+    return actionCommand;
+  }
+  
+}
diff --git a/src/javajs/awt/event/ActionListener.java b/src/javajs/awt/event/ActionListener.java
new file mode 100644 (file)
index 0000000..8137e7d
--- /dev/null
@@ -0,0 +1,8 @@
+package javajs.awt.event;
+
+
+public interface ActionListener {
+  
+  public abstract void actionPerformed(ActionEvent event);
+  
+}
diff --git a/src/javajs/awt/event/Event.java b/src/javajs/awt/event/Event.java
new file mode 100644 (file)
index 0000000..1a54403
--- /dev/null
@@ -0,0 +1,59 @@
+package javajs.awt.event;
+
+public class Event {
+
+  private Object source;
+
+  public Object getSource() {
+    return source;
+  }
+
+  public static final int MOUSE_LEFT   =  16;
+  public static final int MOUSE_MIDDLE =   8; //Event.ALT_MASK;
+  public static final int MOUSE_RIGHT  =   4; //Event.META_MASK;
+  public static final int MOUSE_WHEEL  =  32;
+  
+  public final static int MAC_COMMAND = MOUSE_LEFT | MOUSE_RIGHT;
+  public final static int BUTTON_MASK = MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT;
+
+  public static final int MOUSE_DOWN   = 501; //InputEvent.MOUSE_DOWN;
+  public static final int MOUSE_UP     = 502; //Event.MOUSE_UP;
+  public static final int MOUSE_MOVE   = 503; //Event.MOUSE_MOVE;
+  public static final int MOUSE_ENTER  = 504; //Event.MOUSE_ENTER;
+  public static final int MOUSE_EXIT   = 505; //Event.MOUSE_EXIT;
+  public static final int MOUSE_DRAG   = 506; //Event.MOUSE_DRAG;
+    
+  
+  public static final int SHIFT_MASK =  1;//InputEvent.SHIFT_MASK;
+  public static final int ALT_MASK   =  8;//InputEvent.ALT_MASK;
+  public static final int CTRL_MASK  =  2;//InputEvent.CTRL_MASK;
+  
+  public final static int CTRL_ALT = CTRL_MASK | ALT_MASK;
+  public final static int CTRL_SHIFT = CTRL_MASK | SHIFT_MASK;
+
+  public static final int META_MASK  =  4;//InputEvent.META_MASK;
+  public static final int VK_SHIFT   = 16;//KeyEvent.VK_SHIFT;
+  public static final int VK_ALT     = 18;//KeyEvent.VK_ALT;
+  public static final int VK_CONTROL = 17;//KeyEvent.VK_CONTROL;
+  public static final int VK_META    = 157; // KeyEvent.VK_META;
+  public static final int VK_LEFT    = 37;//KeyEvent.VK_LEFT;
+  public static final int VK_RIGHT   = 39;//KeyEvent.VK_RIGHT;
+  public static final int VK_PERIOD  = 46;//KeyEvent.VK_PERIOD;
+  public static final int VK_SPACE   = 32;//KeyEvent.VK_SPACE;
+  public static final int VK_DOWN    = 40;//KeyEvent.VK_DOWN;
+  public static final int VK_UP      = 38;//KeyEvent.VK_UP;
+  public static final int VK_ESCAPE  = 27;//KeyEvent.VK_ESCAPE;
+  public static final int VK_DELETE  = 127;//KeyEvent.VK_DELETE;
+  public static final int VK_BACK_SPACE = 8;//KeyEvent.VK_BACK_SPACE;
+  public static final int VK_PAGE_DOWN = 34;//KeyEvent.VK_PAGE_DOWN;
+  public static final int VK_PAGE_UP   = 33;//KeyEvent.VK_PAGE_UP;
+
+  // for status messages:
+  public final static int MOVED = 0;
+  public final static int DRAGGED = 1;
+  public final static int CLICKED = 2;
+  public final static int WHEELED = 3;
+  public final static int PRESSED = 4;
+  public final static int RELEASED = 5;
+
+}
diff --git a/src/javajs/awt/event/ItemEvent.java b/src/javajs/awt/event/ItemEvent.java
new file mode 100644 (file)
index 0000000..0592121
--- /dev/null
@@ -0,0 +1,6 @@
+package javajs.awt.event;
+
+
+public class ItemEvent extends Event {
+
+}
diff --git a/src/javajs/awt/event/WindowEvent.java b/src/javajs/awt/event/WindowEvent.java
new file mode 100644 (file)
index 0000000..739526d
--- /dev/null
@@ -0,0 +1,6 @@
+package javajs.awt.event;
+
+
+public class WindowEvent extends Event {
+
+}
diff --git a/src/javajs/awt/event/WindowListener.java b/src/javajs/awt/event/WindowListener.java
new file mode 100644 (file)
index 0000000..f60b076
--- /dev/null
@@ -0,0 +1,9 @@
+package javajs.awt.event;
+
+import javajs.awt.event.WindowEvent;
+
+public interface WindowListener {
+  
+  public void windowClosing(WindowEvent e);
+  
+}
diff --git a/src/javajs/export/PDFCreator.java b/src/javajs/export/PDFCreator.java
new file mode 100644 (file)
index 0000000..8ffc540
--- /dev/null
@@ -0,0 +1,364 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2009-06-30 18:58:33 -0500 (Tue, 30 Jun 2009) $
+ * $Revision: 11158 $
+ *
+ * Copyright (C) 2002-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.export;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javajs.util.Lst;
+import javajs.util.SB;
+
+
+
+public class PDFCreator {
+  private OutputStream os;
+  private Lst<PDFObject> indirectObjects;
+  private PDFObject root;
+  private PDFObject graphics; 
+//  private PDFObject pageResources;
+//  private PDFObject graphicsResources;
+
+  private int pt;
+  private int xrefPt;
+  private int count;
+
+  private int height;
+  private int width;
+  
+  private Map<String, PDFObject>fonts;
+
+  public PDFCreator() {
+   // for Class.forName  
+  }
+
+  public void setOutputStream(OutputStream os) {
+    this.os = os;
+  }
+
+  public void newDocument(int paperWidth, int paperHeight, boolean isLandscape) {
+    width = (isLandscape ? paperHeight : paperWidth);
+    height = (isLandscape ? paperWidth : paperHeight);
+    System.out.println("Creating PDF with width=" + width + " and height=" + height);
+    fonts = new Hashtable<String, PDFObject>();
+    indirectObjects = new Lst<PDFObject>();
+    //graphicsResources = newObject(null);
+    //pageResources = newObject(null); // will set this to compressed stream later
+    root = newObject("Catalog");
+    PDFObject pages = newObject("Pages");
+    PDFObject page = newObject("Page");
+    PDFObject pageContents = newObject(null);
+    graphics = newObject("XObject");
+    
+    root.addDef("Pages", pages.getRef());
+    pages.addDef("Count", "1");
+    pages.addDef("Kids", "[ " + page.getRef() +" ]");
+    page.addDef("Parent", pages.getRef());
+    page.addDef("MediaBox", "[ 0 0 " + paperWidth + " " + paperHeight + " ]");
+    if (isLandscape)
+      page.addDef("Rotate", "90");
+
+    pageContents.addDef("Length", "?");
+    pageContents.append((isLandscape ? "q 0 1 1 0 0 0 " : "q 1 0 0 -1 0 "+(paperHeight))+" cm /" + graphics.getID() + " Do Q");
+    page.addDef("Contents", pageContents.getRef());   
+    addProcSet(page);
+    addProcSet(graphics);
+    // will add fonts as well as they are needed
+    graphics.addDef("Subtype", "/Form");
+    graphics.addDef("FormType", "1");
+    graphics.addDef("BBox", "[0 0 " + width + " " + height + "]");
+    graphics.addDef("Matrix", "[1 0 0 1 0 0]");
+    graphics.addDef("Length", "?");
+    page.addResource("XObject", graphics.getID(), graphics.getRef());   
+    g("q 1 w 1 J 1 j 10 M []0 d q "); // line width 1, line cap circle, line join circle, miter limit 10, solid
+    clip(0, 0, width, height);
+  }   
+
+  private void addProcSet(PDFObject o) {
+    o.addResource(null, "ProcSet", "[/PDF /Text /ImageB /ImageC /ImageI]");
+  }
+
+  private void clip(int x1, int y1, int x2, int y2) {
+    moveto(x1, y1);
+    lineto(x2, y1);
+    lineto(x2, y2);
+    lineto(x1, y2);
+    g("h W n");
+  }
+
+  public void moveto(int x, int y) {
+    g(x + " " + y  + " m");
+  }
+
+  public void lineto(int x, int y) {
+    g(x + " " + y  + " l");
+  }
+
+  private PDFObject newObject(String type) {
+    PDFObject o = new PDFObject(++count);
+    if (type != null)
+      o.addDef("Type", "/" + type);
+    indirectObjects.addLast(o);
+    return o;
+  }
+
+  public void addInfo(Map<String, String> data) {
+    Hashtable<String, Object> info = new Hashtable<String, Object>();
+    for (Entry<String, String> e: data.entrySet()) {
+      String value = "(" + e.getValue().replace(')','_').replace('(','_')+ ")";
+      info.put(e.getKey(), value);      
+    }
+    root.addDef("Info", info);
+  }
+
+  private PDFObject addFontResource(String fname) {
+    PDFObject f = newObject("Font");
+    fonts.put(fname, f);
+    f.addDef("BaseFont", fname);
+    f.addDef("Encoding", "/WinAnsiEncoding");
+    f.addDef("Subtype", "/Type1");
+    graphics.addResource("Font", f.getID(), f.getRef());
+    return f;
+  }
+
+  private Map<Object, PDFObject> images;
+  
+  public void addImageResource(Object newImage, int width, int height, int[] buffer, boolean isRGB) {
+    PDFObject imageObj = newObject("XObject");
+    if (images == null)
+      images = new Hashtable<Object, PDFObject>();
+    images.put(newImage, imageObj);   
+    imageObj.addDef("Subtype", "/Image");
+    imageObj.addDef("Length", "?");
+    imageObj.addDef("ColorSpace", isRGB ? "/DeviceRGB" : "/DeviceGray");
+    imageObj.addDef("BitsPerComponent", "8");
+    imageObj.addDef("Width", "" + width);
+    imageObj.addDef("Height", "" + height);
+    graphics.addResource("XObject", imageObj.getID(), imageObj.getRef());
+    int n = buffer.length;
+    byte[] stream = new byte[n * (isRGB ? 3 : 1)];
+    if (isRGB) {
+      for (int i = 0, pt = 0; i < n; i++) {
+        stream[pt++] = (byte) ((buffer[i] >> 16) & 0xFF);
+        stream[pt++] = (byte) ((buffer[i] >> 8) & 0xFF);
+        stream[pt++] = (byte) (buffer[i] & 0xFF);
+      }
+    } else {
+      for (int i = 0; i < n; i++)
+        stream[i] = (byte) buffer[i];
+    }
+    imageObj.setStream(stream);
+    graphics.addResource("XObject", imageObj.getID(), imageObj.getRef());
+  }
+
+  public void g(String cmd) {
+    graphics.append(cmd).appendC('\n');
+  }
+
+  private void output(String s) throws IOException {
+   byte[] b = s.getBytes();
+   os.write(b, 0, b.length);
+   pt += b.length;
+  }
+
+  public void closeDocument() throws IOException {
+    g("Q Q");
+    outputHeader();
+    writeObjects();
+    writeXRefTable();
+    writeTrailer();
+    os.flush();
+    os.close();
+  }
+
+  private void outputHeader() throws IOException {
+    output("%PDF-1.3\n%");
+    byte[] b = new byte[] {-1, -1, -1, -1};
+    os.write(b, 0, b.length);
+    pt += 4;
+    output("\n");
+  }
+
+  private void writeTrailer() throws IOException {
+    PDFObject trailer = new PDFObject(-2);
+    output("trailer");
+    trailer.addDef("Size", "" + indirectObjects.size());
+    trailer.addDef("Root", root.getRef());
+    trailer.output(os);
+    output("startxref\n");
+    output("" + xrefPt + "\n");
+    output("%%EOF\n");
+  }
+
+  /**
+   * Write Font objects first.
+   * 
+   * @throws IOException
+   */
+  private void writeObjects() throws IOException {
+    int nObj = indirectObjects.size();
+    for (int i = 0; i < nObj; i++) {
+      PDFObject o = indirectObjects.get(i);
+      if (!o.isFont())
+        continue;
+      o.pt = pt;
+      pt += o.output(os);
+    }
+    for (int i = 0; i < nObj; i++) {
+      PDFObject o = indirectObjects.get(i);
+      if (o.isFont())
+        continue;
+      o.pt = pt;
+      pt += o.output(os);
+    }
+  }
+
+  private void writeXRefTable() throws IOException {
+    xrefPt = pt;
+    int nObj = indirectObjects.size();
+    SB sb = new SB();
+    // note trailing space, needed because \n is just one character
+    sb.append("xref\n0 " + (nObj + 1) 
+        + "\n0000000000 65535 f\r\n");
+    for (int i = 0; i < nObj; i++) {
+      PDFObject o = indirectObjects.get(i);
+      String s = "0000000000" + o.pt;
+      sb.append(s.substring(s.length() - 10));
+      sb.append(" 00000 n\r\n");
+    }
+    output(sb.toString());
+  }
+
+  public boolean canDoLineTo() {
+    return true;
+  }
+
+  public void fill() {
+    g("f");   
+  }
+
+  public void stroke() {
+    g("S");   
+  }
+
+  public void doCircle(int x, int y, int r, boolean doFill) {
+    double d = r*4*(Math.sqrt(2)-1)/3;
+    double dx = x;
+    double dy = y;
+    g((dx + r) + " " + dy + " m");
+    g((dx + r) + " " + (dy + d) + " " + (dx + d) + " " + (dy + r) + " " + (dx) + " " + (dy + r) + " "  + " c");
+    g((dx - d) + " " + (dy + r) + " " + (dx - r) + " " + (dy + d) + " " + (dx - r) + " " + (dy) + " c");
+    g((dx - r) + " " + (dy - d) + " " + (dx - d) + " " + (dy - r) + " " + (dx) + " " + (dy - r) + " c");
+    g((dx + d) + " " + (dy - r) + " " + (dx + r) + " " + (dy - d) + " " + (dx + r) + " " + (dy) + " c");
+    g(doFill ? "f" : "s");
+  }
+
+  public void doPolygon(int[] axPoints, int[] ayPoints, int nPoints, boolean doFill) {
+    moveto(axPoints[0], ayPoints[0]);
+    for (int i = 1; i < nPoints; i++)
+      lineto(axPoints[i], ayPoints[i]);
+    g(doFill ? "f" : "s");
+  }
+
+  public void doRect(int x, int y, int width, int height, boolean doFill) {
+    g(x + " " + y + " " + width + " " + height + " re " + (doFill ? "f" : "s"));
+  }
+
+  public void drawImage(Object image, int destX0, int destY0,
+      int destX1, int destY1, int srcX0, int srcY0, int srcX1, int srcY1) {
+    PDFObject imageObj = images.get(image);
+    if (imageObj == null)
+      return;
+    g("q");
+    clip(destX0, destY0, destX1, destY1);
+    double iw = Double.parseDouble((String) imageObj.getDef("Width"));
+    double ih = Double.parseDouble((String) imageObj.getDef("Height"));   
+    double dw = (destX1 - destX0 + 1);
+    double dh  = (destY1 - destY0 + 1);
+    double sw = (srcX1 - srcX0 + 1);
+    double sh = (srcY1 - srcY0 + 1);
+    double scaleX = dw / sw;
+    double scaleY = dh / sh;
+    double transX = destX0 - srcX0 * scaleX;
+    double transY = destY0 + (ih - srcY0) * scaleY;
+    g(scaleX*iw + " 0 0 " + -scaleY*ih + " " + transX + " " + transY + " cm");
+    g("/" + imageObj.getID() + " Do");
+    g("Q");
+  }
+
+  public void drawStringRotated(String s, int x, int y, int angle) {
+    g("q " + getRotation(angle) + " " + x + " " + y
+        + " cm BT(" + s + ")Tj ET Q");
+  }
+
+  public String getRotation(int angle) {    
+    float cos = 0, sin = 0;
+    switch (angle) {
+    case 0:
+      cos = 1;
+      break;
+    case 90:
+      sin = 1;
+      break;
+    case -90:
+      sin = -1;
+      break;
+    case 180:
+      cos = -1;
+      break;
+    default:
+      float a = (float) (angle / 180.0 * Math.PI);
+      cos = (float) Math.cos(a);
+      sin = (float) Math.sin(a);
+      if (Math.abs(cos) < 0.0001)
+        cos = 0;
+      if (Math.abs(sin) < 0.0001)
+        sin = 0;
+    }
+    return  cos + " " + sin + " " + sin + " " + -cos;
+  }
+
+  public void setColor(float[] rgb, boolean isFill) {
+    g(rgb[0] + " " + rgb[1] + " " + rgb[2] + (isFill ? " rg" : " RG"));
+  }
+
+  public void setFont(String fname, float size) {
+    PDFObject f = fonts.get(fname);
+    if (f == null)
+      f = addFontResource(fname);
+    g("/" + f.getID() + " " + size + " Tf");
+  }
+
+  public void setLineWidth(float width) {
+    g(width + " w");    
+  }
+
+  public void translateScale(float x, float y, float scale) {
+    g(scale + " 0 0 " + scale + " " + x + " " + y + " cm");
+  }
+
+}
diff --git a/src/javajs/export/PDFObject.java b/src/javajs/export/PDFObject.java
new file mode 100644 (file)
index 0000000..176dc19
--- /dev/null
@@ -0,0 +1,152 @@
+package javajs.export;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+import javajs.util.SB;
+
+
+/**
+ * A rudimentary class for working with PDF document creation.
+ * Written from scratch based on PDF Reference 13.
+ * 
+ * @author hansonr  Bob Hanson hansonr@stolaf.edu  10/28/2013
+ * 
+ */
+class PDFObject extends SB {   
+       private Map<String, Object> dictionary;
+       private byte[] stream;
+       private int index;
+       String type;
+       int len;
+       int pt;
+       
+       PDFObject(int index) {
+               this.index = index;
+       }
+
+       String getRef() {
+               return index + " 0 R";
+       }
+       
+       String getID() {
+               return type.substring(0, 1) + index;
+       }
+       
+       boolean isFont() {
+               return "Font".equals(type);
+       }
+
+       void setStream(byte[] stream) {
+               this.stream = stream;
+       }
+
+       Object getDef(String key) {
+               return dictionary.get(key);
+       }
+       
+       void addDef(String key, Object value) {
+               if (dictionary  == null)
+                       dictionary = new Hashtable<String, Object>();
+               dictionary.put(key, value);
+               if (key.equals("Type"))
+                       type = ((String) value).substring(1);
+       }
+       
+       void setAsStream() {
+               stream = toBytes(0, -1);
+               setLength(0);
+       }
+       
+       int output(OutputStream os) throws IOException {
+               if (index > 0) {
+                       String s = index + " 0 obj\n";
+                       write(os, s.getBytes(), 0);
+               }
+               int streamLen = 0;
+               if (dictionary != null) {
+                       if (dictionary.containsKey("Length")) {
+                               if (stream == null)
+                                       setAsStream();
+                               streamLen = stream.length;
+                               boolean doDeflate = (streamLen > 1000);
+        if (doDeflate) {
+          Deflater deflater = new Deflater(9);
+          ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
+          DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes,
+              deflater);
+          compBytes.write(stream, 0, streamLen);
+          compBytes.finish();
+          stream = outBytes.toByteArray();
+          dictionary.put("Filter", "/FlateDecode");
+          streamLen = stream.length;
+        }
+                               dictionary.put("Length", "" + streamLen);
+                       }
+                       write(os, getDictionaryText(dictionary, "\n").getBytes(), 0);
+               }
+               if (length() > 0)
+                       write(os, this.toString().getBytes(), 0);
+               if (stream != null) {
+                       write(os, "stream\r\n".getBytes(), 0);
+                       write(os, stream, streamLen);
+                       write(os, "\r\nendstream\r\n".getBytes(), 0);
+               }
+               if (index > 0)
+                       write(os, "endobj\n".getBytes(), 0);
+               return len;
+       }
+
+       private void write(OutputStream os, byte[] bytes, int nBytes) throws IOException {
+               if (nBytes == 0)
+                       nBytes = bytes.length;
+               len += nBytes;
+               os.write(bytes, 0, nBytes);
+       }
+
+       @SuppressWarnings("unchecked")
+       private String getDictionaryText(Map<String, Object> d, String nl) {
+               SB sb = new SB();
+               sb.append("<<");
+               if (d.containsKey("Type"))
+                       sb.append("/Type").appendO(d.get("Type"));
+               for (Entry<String, Object> e : d.entrySet()) {
+                       String s = e.getKey();
+                       if (s.equals("Type") || s.startsWith("!"))
+                               continue;
+                       sb.append("/" + s);
+                       Object o = e.getValue();
+                       if (o instanceof Map<?, ?>) {
+                               sb.append((getDictionaryText((Map<String, Object>) o, "")));
+                               continue;
+                       }
+                       s = (String) e.getValue();
+                       if (!s.startsWith("/"))
+                               sb.append(" ");
+                       sb.appendO(s);
+               }
+               return (sb.length() > 3 ? sb.append(">>").append(nl).toString() : "");
+       }
+
+       @SuppressWarnings("unchecked")
+       private Map<String, Object> createSubdict(Map<String, Object> d0, String dict) {
+               Map<String, Object> d = (Map<String, Object>) d0.get(dict);
+               if (d == null)
+                       d0.put(dict, d = new Hashtable<String, Object>());
+               return d;
+       }
+
+       void addResource(String type, String key, String value) {
+               Map<String, Object> r = createSubdict(dictionary, "Resources");
+               if (type != null)
+                       r = createSubdict(r, type);
+               r.put(key, value);
+       }
+       
+}
diff --git a/src/javajs/img/BMPDecoder.java b/src/javajs/img/BMPDecoder.java
new file mode 100644 (file)
index 0000000..68fb24d
--- /dev/null
@@ -0,0 +1,208 @@
+/* $RCSfile$
+ * $Author: nicove $
+ * $Date: 2007-03-30 12:26:16 -0500 (Fri, 30 Mar 2007) $
+ * $Revision: 7275 $
+ *
+ * Copyright (C) 2002-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.img;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+
+import javajs.util.Rdr;
+
+/**
+ * src: http://www.javaworld.com/article/2077542/learn-java/java-tip-43--how-to-
+ * read-8--and-24-bit-microsoft-windows-bitmaps-in-java-applications.html
+ *
+ * see also: http://en.wikipedia.org/wiki/BMP_file_format
+ * 
+ * Modified by Bob Hanson hansonr@stolaf.edu
+ * 
+ * @author Bob Hanson (hansonr@stolaf.edu)
+ * 
+ */
+public class BMPDecoder {
+
+  public BMPDecoder() {
+    // for reflection
+  }
+  
+  private BufferedInputStream bis;
+
+  /**
+   * original comment:
+   * 
+   * loadbitmap() method converted from Windows C code. Reads only uncompressed
+   * 24- and 8-bit images. Tested with images saved using Microsoft Paint in
+   * Windows 95. If the image is not a 24- or 8-bit image, the program refuses
+   * to even try. I guess one could include 4-bit images by masking the byte by
+   * first 1100 and then 0011. I am not really interested in such images. If a
+   * compressed image is attempted, the routine will probably fail by generating
+   * an IOException. Look for variable ncompression to be different from 0 to
+   * indicate compression is present.
+   * 
+   * @param bytes
+   * @return [image byte array, width, height]
+   */
+  public Object[] decodeWindowsBMP(byte[] bytes) {
+    try {
+      bis = Rdr.getBIS(bytes);
+      temp = new byte[4];
+      // read BITMAPFILEHEADER
+      if (readByte() != 'B' || readByte() != 'M')
+        return null;
+      readInt(); // file size; ignored
+      readShort(); // reserved
+      readShort(); // reserved
+      readInt(); // ptr to pixel array; ignored
+      int imageWidth, imageHeight, bitsPerPixel, nColors = 0, imageSize = 0;
+      // read BITMAP header
+      int headerSize = readInt();
+      switch (headerSize) {
+      case 12:
+        // BITMAPCOREHEADER
+        imageWidth = readShort();
+        imageHeight = readShort();
+        readShort(); // planes
+        bitsPerPixel = readShort();
+        break;
+      case 40:
+        // BITMAPINFOHEADER
+        imageWidth = readInt();
+        imageHeight = readInt();
+        readShort(); // planes
+        bitsPerPixel = readShort();
+        int ncompression = readInt();
+        if (ncompression != 0) {
+          System.out.println("BMP Compression is :" + ncompression
+              + " -- aborting");
+          return null;
+        }
+        imageSize = readInt();
+        readInt(); // hres
+        readInt(); // vres
+        nColors = readInt();
+        readInt(); // colors used
+        break;
+      default:
+        System.out.println("BMP Header unrecognized, length=" + headerSize
+            + " -- aborting");
+        return null;
+      }
+      boolean isYReversed = (imageHeight < 0);
+      if (isYReversed)
+        imageHeight = -imageHeight;
+      int nPixels = imageHeight * imageWidth;
+      int bytesPerPixel = bitsPerPixel / 8;
+      nColors = (nColors > 0 ? nColors : 1 << bitsPerPixel);
+      int npad = (bytesPerPixel == 4 ? 0
+          : imageSize == 0 ? 4 - (imageWidth % 4) : (imageSize / imageHeight)
+              - imageWidth * bytesPerPixel) % 4;
+      int[] palette;
+      int[] buf = new int[nPixels];
+      int dpt = (isYReversed ? imageWidth : -imageWidth);
+      int pt0 = (isYReversed ? 0 : nPixels + dpt);
+      int pt1 = (isYReversed ? nPixels : dpt);
+      switch (bitsPerPixel) {
+      case 32:
+      case 24:
+        for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
+          for (int i = 0; i < imageWidth; i++)
+            buf[pt + i] = readColor(bytesPerPixel);
+        break;
+      case 8:
+        palette = new int[nColors];
+        for (int i = 0; i < nColors; i++)
+          palette[i] = readColor(4);
+        for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
+          for (int i = 0; i < imageWidth; i++)
+            buf[pt + i] = palette[readByte()];
+        break;
+      case 4:
+        npad = (4 - (((imageWidth + 1) / 2) % 4)) % 4;
+        palette = new int[nColors];
+        for (int i = 0; i < nColors; i++)
+          palette[i] = readColor(4);
+        int b4 = 0;
+        for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
+          for (int i = 0, shift = 4; i < imageWidth; i++, shift = 4 - shift)
+            buf[pt + i] = palette[((shift == 4 ? (b4 = readByte()) : b4) >> shift) & 0xF];
+        break;
+      case 1:
+        int color1 = readColor(3);
+        int color2 = readColor(3);
+        npad = (4 - (((imageWidth + 7) / 8) % 4)) % 4;
+        int b = 0;
+        for (int pt = pt0; pt != pt1; pt += dpt, pad(npad))
+          for (int i = 0, bpt = -1; i < imageWidth; i++, bpt--) {
+            if (bpt < 0) {
+              b = readByte();
+              bpt = 7;
+            }
+            buf[pt + i] = ((b & (1 << bpt)) == 0 ? color1 : color2);
+          }
+        break;
+      case 64:
+      case 2:
+      default:
+        System.out
+            .println("Not a 32-, 24-, 8-, 4-, or 1-bit Windows Bitmap, aborting...");
+        return null;
+      }
+      return new Object[] { buf, Integer.valueOf(imageWidth),
+          Integer.valueOf(imageHeight) };
+    } catch (Exception e) {
+      System.out.println("Caught exception in loadbitmap!");
+    }
+    return null;
+  }
+
+  private boolean pad(int npad) throws IOException {
+    for (int i = 0; i < npad; i++)
+      readByte();
+    return true;
+  }
+
+  private byte[] temp;
+  
+  private int readColor(int n) throws IOException {
+    bis.read(temp, 0, n);
+    return 0xff << 24 | ((temp[2] & 0xff) << 16)
+        | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
+  }
+
+  private int readInt() throws IOException {
+    bis.read(temp, 0, 4);
+    return ((temp[3] & 0xff) << 24) | ((temp[2] & 0xff) << 16)
+        | ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
+  }
+
+  private int readShort() throws IOException {
+    bis.read(temp, 0, 2);
+    return ((temp[1] & 0xff) << 8) | temp[0] & 0xff;
+  }
+
+  private int readByte() throws IOException {
+    bis.read(temp, 0, 1);
+    return temp[0] & 0xff;
+  }
+
+}
diff --git a/src/javajs/img/CRCEncoder.java b/src/javajs/img/CRCEncoder.java
new file mode 100644 (file)
index 0000000..77ed11e
--- /dev/null
@@ -0,0 +1,110 @@
+package javajs.img;
+
+import java.util.zip.CRC32;
+
+
+import javajs.util.AU;
+
+abstract class CRCEncoder extends ImageEncoder {
+
+  protected int startPos, bytePos;
+  
+  private CRC32 crc;  
+  protected byte[] pngBytes;  
+  protected int dataLen;
+  private byte[] int2 = new byte[2];
+  private byte[] int4 = new byte[4];
+
+  CRCEncoder() {
+    pngBytes = new byte[250];
+    crc = new CRC32();
+  }
+
+  protected void setData(byte[] b, int pt) {
+    pngBytes = b;
+    dataLen = b.length;
+    startPos = bytePos = pt;
+  }
+
+  protected byte[] getBytes() {
+    return (dataLen == pngBytes.length ? pngBytes : AU.arrayCopyByte(
+        pngBytes, dataLen));
+  }
+
+  protected void writeCRC() {
+    crc.reset();
+    crc.update(pngBytes, startPos, bytePos - startPos);
+    writeInt4((int) crc.getValue());
+  }
+
+  /**
+   * Write a two-byte integer into the pngBytes array at a given position.
+   *
+   * @param n The integer to be written into pngBytes.
+   */
+  protected void writeInt2(int n) {
+    int2[0] = (byte) ((n >> 8) & 0xff);
+    int2[1] = (byte) (n & 0xff);
+    writeBytes(int2);
+  }
+
+  /**
+   * Write a four-byte integer into the pngBytes array at a given position.
+   *
+   * @param n The integer to be written into pngBytes.
+   */
+  protected void writeInt4(int n) {
+    getInt4(n, int4);
+    writeBytes(int4);
+  }
+
+  protected static void getInt4(int n, byte[] int4) {
+    int4[0] = (byte) ((n >> 24) & 0xff);
+    int4[1] = (byte) ((n >> 16) & 0xff);
+    int4[2] = (byte) ((n >> 8) & 0xff);
+    int4[3] = (byte) (n & 0xff);
+  }
+
+  /**
+   * Write a single byte into the pngBytes array at a given position.
+   *
+   * @param b The byte to be written into pngBytes.
+   */
+  protected void writeByte(int b) {
+    byte[] temp = {
+      (byte) b
+    };
+    writeBytes(temp);
+  }
+
+  /**
+   * Write a string into the pngBytes array at a given position.
+   * This uses the getBytes method, so the encoding used will
+   * be its default.
+   *
+   * @param s The string to be written into pngBytes.
+   * @see java.lang.String#getBytes()
+   */
+  protected void writeString(String s) {
+    writeBytes(s.getBytes());
+  }
+
+  /**
+   * Write an array of bytes into the pngBytes array. 
+   * Both dataLen and bytePos are updated. If we don't have 
+   * enough room, this is certainly in image data writing,
+   * so we add just enough for CRC END CRC
+   * 
+   * @param data
+   *        The data to be written into pngBytes.
+   */
+  protected void writeBytes(byte[] data) {
+    int newPos = bytePos + data.length;
+    dataLen = Math.max(dataLen, newPos);
+    if (newPos > pngBytes.length)
+      pngBytes = AU.arrayCopyByte(pngBytes, newPos + 16);
+    System.arraycopy(data, 0, pngBytes, bytePos, data.length);
+    bytePos = newPos;
+  }
+
+}
diff --git a/src/javajs/img/GifEncoder.java b/src/javajs/img/GifEncoder.java
new file mode 100644 (file)
index 0000000..89c9579
--- /dev/null
@@ -0,0 +1,1132 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-06-02 12:14:13 -0500 (Sat, 02 Jun 2007) $
+ * $Revision: 7831 $
+ *
+ * Copyright (C) 2000-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+//  Final encoding code from http://acme.com/resources/classes/Acme/JPM/Encoders/GifEncoder.java
+//
+//  GifEncoder - write out an image as a GIF
+// 
+// 
+//  Transparency handling and variable bit size courtesy of Jack Palevich.
+//  
+//  Copyright (C)1996,1998 by Jef Poskanzer <jef@mail.acme.com>. All rights reserved.
+//  
+//  Redistribution and use in source and binary forms, with or without
+//  modification, are permitted provided that the following conditions
+//  are met:
+//  1. Redistributions of source code must retain the above copyright
+//     notice, this list of conditions and the following disclaimer.
+//  2. Redistributions in binary form must reproduce the above copyright
+//     notice, this list of conditions and the following disclaimer in the
+//     documentation and/or other materials provided with the distribution.
+// 
+//  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+//  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+//  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+//  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+//  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+//  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+//  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+//  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+//  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+//  SUCH DAMAGE.
+// 
+//  Visit the ACME Labs Java page for up-to-date versions of this and other
+//  fine Java utilities: http://www.acme.com/java/
+// 
+/// Write out an image as a GIF.
+// <P>
+// <A HREF="/resources/classes/Acme/JPM/Encoders/GifEncoder.java">Fetch the software.</A><BR>
+// <A HREF="/resources/classes/Acme.tar.gz">Fetch the entire Acme package.</A>
+// <P>
+// @see ToGif
+
+package javajs.img;
+
+import javajs.util.CU;
+import javajs.util.Lst;
+import javajs.util.M3;
+import javajs.util.P3;
+
+import java.util.Hashtable;
+import java.util.Map;
+import java.io.IOException;
+
+/**
+ * 
+ * GifEncoder extensively adapted for Jmol by Bob Hanson
+ * 
+ * Color quantization roughly follows the GIMP method
+ * "dither Floyd-Steinberg (normal)" but with some twists. (For example, we
+ * exclude the background color.)
+ * 
+ * Note that although GIMP code annotation refers to "median-cut", it is really
+ * using MEAN-cut. That is what I use here as well.
+ * 
+ * -- commented code allows visualization of the color space using Jmol. Very
+ * enlightening!
+ * 
+ * -- much simplified interface with ImageEncoder
+ * 
+ * -- uses simple Hashtable with Integer() to catalog colors
+ * 
+ * -- allows progressive production of animated GIF via Jmol CAPTURE command
+ * 
+ * -- uses general purpose javajs.util.OutputChannel for byte-handling options
+ * such as posting to a server, writing to disk, and retrieving bytes.
+ * 
+ * -- allows JavaScript port
+ * 
+ * -- Bob Hanson, first try: 24 Sep 2013; final coding: 9 Nov 2014
+ * 
+ * 
+ * @author Bob Hanson hansonr@stolaf.edu
+ */
+
+public class GifEncoder extends ImageEncoder {
+
+  private Map<String, Object> params;
+  private P3[] palette;
+  private int backgroundColor;
+
+  private boolean interlaced;
+  private boolean addHeader = true;
+  private boolean addImage = true;
+  private boolean addTrailer = true;
+  private boolean isTransparent;
+  private boolean floydSteinberg = true;
+  private boolean capturing;
+  private boolean looping;
+
+  private int delayTime100ths = -1;
+  private int bitsPerPixel = 1;
+
+  private int byteCount;
+
+  /**
+   * we allow for animated GIF by being able to re-enter the code with different
+   * parameters held in params
+   * 
+   * 
+   */
+  @Override
+  protected void setParams(Map<String, Object> params) {
+    this.params = params;
+    Integer ic = (Integer) params.get("transparentColor");
+    if (ic == null) {
+      ic = (Integer) params.get("backgroundColor");
+      if (ic != null)
+        backgroundColor = ic.intValue();
+    } else {
+      backgroundColor = ic.intValue();
+      isTransparent = true;
+    }
+
+    interlaced = (Boolean.TRUE == params.get("interlaced"));
+    if (params.containsKey("captureRootExt") // file0000.gif 
+        || !params.containsKey("captureMode")) // animated gif
+      return;
+    interlaced = false;
+    capturing = true;
+    try {
+      byteCount = ((Integer) params.get("captureByteCount")).intValue();
+    } catch (Exception e) {
+      // ignore
+    }
+    switch ("maec"
+        .indexOf(((String) params.get("captureMode")).substring(0, 1))) {
+    case 0: //"movie"
+      params.put("captureMode", "add");
+      addImage = false;
+      addTrailer = false;
+      break;
+    case 1: // add 
+      addHeader = false;
+      addTrailer = false;
+      int fps = Math.abs(((Integer) params.get("captureFps")).intValue());
+      delayTime100ths = (fps == 0 ? 0 : 100 / fps);
+      looping = (Boolean.FALSE != params.get("captureLooping"));
+      break;
+    case 2: // end
+      addHeader = false;
+      addImage = false;
+      break;
+    case 3: // cancel
+      addHeader = false;
+      addImage = false;
+      out.cancel();
+      break;
+    }
+  }
+
+  @Override
+  protected void generate() throws IOException {
+    if (addHeader)
+      writeHeader();
+    addHeader = false; // only one header
+    if (addImage) {
+      createPalette();
+      writeGraphicControlExtension();
+      if (delayTime100ths >= 0 && looping)
+        writeNetscapeLoopExtension();
+      writeImage();
+    }
+  }
+
+  @Override
+  protected void close() {
+    if (addTrailer) {
+      writeTrailer();
+    } else {
+      doClose = false;
+    }
+    if (capturing)
+      params.put("captureByteCount", Integer.valueOf(byteCount));
+  }
+
+  //////////////  256-color quantization  //////////////
+
+  /**
+   * a color point in normalized L*a*b space with a flag indicating whether it
+   * is the background color
+   */
+  private class ColorItem extends P3 {
+    protected boolean isBackground;
+
+    ColorItem(int rgb, boolean isBackground) {
+      this.isBackground = isBackground;
+      setT(toLABnorm(rgb));
+    }
+  }
+
+  /**
+   * A list of normalized L*a*b points with an index and a center and volume
+   * 
+   */
+  private class ColorCell extends Lst<P3> {
+
+    protected int index;
+    protected P3 center;
+
+    private float volume;
+
+    ColorCell(int index) {
+      this.index = index;
+    }
+
+    /**
+     * @param doVisualize
+     *        debugging only
+     * @return volume in normalized L*a*b space
+     */
+    public float getVolume(boolean doVisualize) {
+      if (volume != 0)
+        return volume;
+      if (size() < 2)
+        return -1;
+      //if (true)
+      //return lst.size();
+      //float d;
+      float maxx = -Integer.MAX_VALUE;
+      float minx = Integer.MAX_VALUE;
+      float maxy = -Integer.MAX_VALUE;
+      float miny = Integer.MAX_VALUE;
+      float maxz = -Integer.MAX_VALUE;
+      float minz = Integer.MAX_VALUE;
+      int n = size();
+      for (int i = n; --i >= 0;) {
+        P3 xyz = get(i);
+        if (xyz.x < minx)
+          minx = xyz.x;
+        if (xyz.y < miny)
+          miny = xyz.y;
+        if (xyz.z < minz)
+          minz = xyz.z;
+        if (xyz.x > maxx)
+          maxx = xyz.x;
+        if (xyz.y > maxy)
+          maxy = xyz.y;
+        if (xyz.z > maxz)
+          maxz = xyz.z;
+      }
+      float dx = (maxx - minx);
+      float dy = (maxy - miny);
+      float dz = (maxz - minz);
+      // Jmol visualization only
+      //      if (doVisualize) {
+      //        P3 ptRGB = toRGB(center);
+      //        drawPt(index, -size(), ptRGB);
+      //        //for (int i = n; --i >= 0;)
+      //        //drawPt(index, i, toRGB(get(i)));
+      //        P3 pt0 = toRGB(P3.new3(Math.max(minx, 0), Math.max(miny, 0),
+      //            Math.max(minz, 0)));
+      //        P3 pt1 = toRGB(P3.new3(Math.min(maxx, 100), Math.min(maxy, 100),
+      //            Math.min(maxz, 100)));
+      //        rgbToXyz(pt0, pt0);
+      //        xyzToLab(pt0, pt0);
+      //        rgbToXyz(pt1, pt1);
+      //        xyzToLab(pt1, pt1);
+      //        System.out.println("boundbox corners " + pt0 + " " + pt1);
+      //        System.out.println("draw d" + index + " boundbox color " + ptRGB
+      //            + " mesh nofill");
+      //      }
+      return volume = dx * dx + dy * dy + dz * dz;
+    }
+
+    //    // Jmol visualization only
+    //      private void drawPt(int index, int i, P3 rgb) {
+    //        boolean isMain = (i < 0);
+    //      P3 lab = rgbToXyz(rgb, null);
+    //      xyzToLab(lab, lab);
+    //      System.out.println("draw d" + index + (isMain ? "_" : "_" + i) + " width "
+    //          + (isMain ? 1.0 : 0.2) + " " + lab
+    //          + " color " + rgb + (isMain ? " '" + -i + "'" : ""));
+    //      }
+
+    /**
+     * Set the average normalized L*a*b value for this cell and return its RGB point
+     * 
+     * @return RGB point
+     * 
+     */
+    protected P3 setColor() {
+      int count = size();
+      center = new P3();
+      for (int i = count; --i >= 0;)
+        center.add(get(i));
+      center.scale(1f / count);
+      // Jmol visualization only
+      //volume = 0;
+      //getVolume(true); 
+      return toRGB(center);
+    }
+
+    /**
+     * use median_cut algorithm to split the cell, creating a doubly linked
+     * list.
+     * 
+     * Paul Heckbert, MIT thesis COLOR IMAGE QUANTIZATION FOR FRAME BUFFER
+     * DISPLAY https://www.cs.cmu.edu/~ph/ciq_thesis
+     * 
+     * except, as in GIMP, we use center (not median) here.
+     * 
+     * @param cells
+     * @return true if split
+     */
+    protected boolean splitCell(Lst<ColorCell> cells) {
+      int n = size();
+      if (n < 2)
+        return false;
+      int newIndex = cells.size();
+      ColorCell newCell = new ColorCell(newIndex);
+      cells.addLast(newCell);
+      float[][] ranges = new float[3][3];
+      for (int ic = 0; ic < 3; ic++) {
+        float low = Float.MAX_VALUE;
+        float high = -Float.MAX_VALUE;
+        for (int i = n; --i >= 0;) {
+          P3 lab = get(i);
+          float v = (ic == 0 ? lab.x : ic == 1 ? lab.y : lab.z);
+          if (low > v)
+            low = v;
+          if (high < v)
+            high = v;
+        }
+        ranges[0][ic] = low;
+        ranges[1][ic] = high;
+        ranges[2][ic] = high - low;
+      }
+      float[] r = ranges[2];
+      int mode = (r[0] >= r[1] ? (r[0] >= r[2] ? 0 : 2) : r[1] >= r[2] ? 1 : 2);
+      float val = ranges[0][mode] + ranges[2][mode] / 2;
+      volume = 0; // recalculate volume if needed
+      switch (mode) {
+      case 0:
+        for (int i = n; --i >= 0;)
+          if (get(i).x >= val)
+            newCell.addLast(remove(i));
+        break;
+      case 1:
+        for (int i = n; --i >= 0;)
+          if (get(i).y >= val)
+            newCell.addLast(remove(i));
+        break;
+      case 2:
+        for (int i = size(); --i >= 0;)
+          if (get(i).z >= val)
+            newCell.addLast(remove(i));
+        break;
+      }
+      return true;
+    }
+  }
+
+  /**
+   * Quantize all colors and create the final palette;
+   * replace pixels[] with an array of color indices.
+   * 
+   */
+  private void createPalette() {
+
+    // catalog all pixel colors
+
+    Lst<ColorItem> tempColors = new Lst<ColorItem>();
+    Map<Integer, ColorItem> ciHash = new Hashtable<Integer, ColorItem>();
+    for (int i = 0, n = pixels.length; i < n; i++) {
+      int rgb = pixels[i];
+      Integer key = Integer.valueOf(rgb);
+      ColorItem item = ciHash.get(key);
+      if (item == null) {
+        item = new ColorItem(rgb, rgb == backgroundColor);
+        ciHash.put(key, item);
+        tempColors.addLast(item);
+      }
+    }
+    int nColors = tempColors.size();
+    System.out.println("GIF total image colors: " + nColors);
+    ciHash = null;
+
+    // create a set of <= 256 color cells
+
+    Lst<ColorCell> cells = quantizeColors(tempColors);
+    nColors = cells.size();
+    System.out.println("GIF final color count: " + nColors);
+
+    // generate the palette and map each cell's rgb color to itself
+
+    Map<Integer, ColorCell> colorMap = new Hashtable<Integer, ColorCell>();
+    bitsPerPixel = (nColors <= 2 ? 1 : nColors <= 4 ? 2 : nColors <= 16 ? 4 : 8);
+    palette = new P3[1 << bitsPerPixel];
+    for (int i = 0; i < nColors; i++) {
+      ColorCell c = cells.get(i);
+      colorMap.put(
+          Integer.valueOf(CU.colorPtToFFRGB(palette[i] = c.setColor())), c);
+    }
+
+    // index all pixels to a pallete color
+
+    pixels = indexPixels(cells, colorMap);
+  }
+
+  /**
+   * Quantize colors by generating a set of cells in normalized L*a*b space
+   * containing all colors. Start with just two cells -- fixed background color
+   * and all others. Keep splitting cells while there are fewer than 256 and
+   * some with multiple colors in them.
+   * 
+   * It is possible that we will end up with fewer than 256 colors.
+   * 
+   * @param tempColors
+   * @return final list of colors
+   */
+  private Lst<ColorCell> quantizeColors(Lst<ColorItem> tempColors) {
+    int n = tempColors.size();
+    Lst<ColorCell> cells = new Lst<ColorCell>();
+    ColorCell cc = new ColorCell(0);
+    cc.addLast(new ColorItem(backgroundColor, true));
+    cells.addLast(cc);
+    cc = new ColorCell(1);
+    if (n > 256)
+      cells.addLast(cc);
+    for (int i = 0; i < n; i++) {
+      ColorItem c = tempColors.get(i);
+      if (c.isBackground)
+        continue;
+      cc.addLast(c);
+      if (n <= 256) {
+        cells.addLast(cc);
+        cc = new ColorCell(cells.size());
+      }
+    }
+    tempColors.clear();
+    if (n > 256)
+      while ((n = cells.size()) < 256) {
+        float maxVol = 0;
+        ColorCell maxCell = null;
+        for (int i = n; --i >= 1;) {
+          ColorCell c = cells.get(i);
+          float v = c.getVolume(false);
+          if (v > maxVol) {
+            maxVol = v;
+            maxCell = c;
+          }
+        }
+        if (maxCell == null || !maxCell.splitCell(cells))
+          break;
+      }
+    return cells;
+  }
+
+  /**
+   * 
+   * Assign all colors to their closest approximation and return an array of
+   * color indexes.
+   * 
+   * Uses Floyd-Steinberg dithering, finding the closest known color and then
+   * spreading out the error over four leading pixels. Limits error to +/- 75
+   * percent in normalized L*a*b space.
+   * 
+   * @param cells
+   *        quantized color cells
+   * @param colorMap
+   *        map of quantized rgb to its cell
+   * @return array of color indexes, one for each pixel
+   * 
+   */
+  private int[] indexPixels(Lst<ColorCell> cells,
+                            Map<Integer, ColorCell> colorMap) {
+    // We need a strip only width+2 wide to process all the errors.
+    // Errors are added to the next pixel and the next row's pixels 
+    // only through p + width + 1:
+    //         p  +1
+    //   +w-1 +w  +w+1
+    // so including p as well, we need a total of width + 2 errors.
+    //
+    // as p moves through the pixels, we just use mod to cycle through
+    // this strip.
+    //
+    int w2 = width + 2;
+    P3[] errors = new P3[w2];
+    // We should replace, not overwrite, pixels 
+    // as this may be the raw canvas.buf32.
+    int[] newPixels = new int[pixels.length];
+    P3 err = new P3();
+    P3 lab;
+    int rgb;
+    Map<Integer, ColorCell> nearestCell = new Hashtable<Integer, ColorCell>();
+    for (int i = 0, p = 0; i < height; ++i) {
+      boolean notLastRow = (i != height - 1);
+      for (int j = 0; j < width; ++j, p++) {
+        if (pixels[p] == backgroundColor) {
+          // leave as 0
+          continue;
+        }
+        P3 pe = errors[p % w2];
+        if (pe == null || pe.x == Float.MAX_VALUE) {
+          lab = null;
+          rgb = pixels[p];
+        } else {
+          lab = toLABnorm(pixels[p]);
+          err = pe;
+          // important not to round the clamp here -- full floating precision
+          err.x = clamp(err.x, -75, 75);
+          err.y = clamp(err.y, -75, 75);
+          err.z = clamp(err.z, -75, 75);
+          lab.add(err);
+          rgb = CU.colorPtToFFRGB(toRGB(lab));
+        }
+        Integer key = Integer.valueOf(rgb);
+        ColorCell cell = colorMap.get(key);
+        if (cell == null) {
+          // critical to generate normalized L*a*b from RGB here for nearestCell mapping.
+          // otherwise future RGB keys may match the wrong cell
+          lab = toLABnorm(rgb);
+          cell = nearestCell.get(key);
+          if (cell == null) {
+            // find nearest cell
+            float maxerr = Float.MAX_VALUE;
+            // skip 0 0 0
+            for (int ib = cells.size(); --ib >= 1;) {
+              ColorCell c = cells.get(ib);
+              err.sub2(lab, c.center);
+              float d = err.lengthSquared();
+              if (d < maxerr) {
+                maxerr = d;
+                cell = c;
+              }
+            }
+            nearestCell.put(key, cell);
+          }
+          if (floydSteinberg) {
+            // dither
+            err.sub2(lab, cell.center);
+            boolean notLastCol = (j < width - 1);
+            if (notLastCol)
+              addError(err, 7, errors, p + 1, w2);
+            if (notLastRow) {
+              if (j > 0)
+                addError(err, 3, errors, p + width - 1, w2);
+              addError(err, 5, errors, p + width, w2);
+              if (notLastCol)
+                addError(err, 1, errors, p + width + 1, w2);
+            }
+          }
+          err.x = Float.MAX_VALUE; // used; flag for resetting to 0
+        }
+        newPixels[p] = cell.index;
+      }
+    }
+    return newPixels;
+  }
+
+  private void addError(P3 err, int f, P3[] errors, int p, int w2) {
+    // GIMP will allow changing the background color.
+    if (pixels[p] == backgroundColor)
+      return;
+    p %= w2;
+    P3 errp = errors[p];
+    if (errp == null)
+      errp = errors[p] = new P3();
+    else if (errp.x == Float.MAX_VALUE) // reuse
+      errp.set(0, 0, 0);
+    errp.scaleAdd2(f / 16f, err, errp);
+  }
+
+  ///////////////////////// CIE L*a*b / XYZ / sRGB conversion methods /////////
+
+  // these could be static, but that just makes for more JavaScript code
+
+  protected P3 toLABnorm(int rgb) {
+    P3 lab = CU.colorPtFromInt(rgb, null);
+    rgbToXyz(lab, lab);
+    xyzToLab(lab, lab);
+    // normalize to 0-100
+    lab.y = (lab.y + 86.185f) / (98.254f + 86.185f) * 100f;
+    lab.z = (lab.z + 107.863f) / (94.482f + 107.863f) * 100f;
+    return lab;
+  }
+
+  protected P3 toRGB(P3 lab) {
+    P3 xyz = P3.newP(lab);
+    // normalized to 0-100
+    xyz.y = xyz.y / 100f * (98.254f + 86.185f) - 86.185f;
+    xyz.z = xyz.z / 100f * (94.482f + 107.863f) - 107.863f;
+    labToXyz(xyz, xyz);
+    return xyzToRgb(xyz, xyz);
+  }
+
+  private static M3 xyz2rgb;
+  private static M3 rgb2xyz;
+
+  static {
+    rgb2xyz = M3.newA9(new float[] { 0.4124f, 0.3576f, 0.1805f, 0.2126f,
+        0.7152f, 0.0722f, 0.0193f, 0.1192f, 0.9505f });
+
+    xyz2rgb = M3.newA9(new float[] { 3.2406f, -1.5372f, -0.4986f, -0.9689f,
+        1.8758f, 0.0415f, 0.0557f, -0.2040f, 1.0570f });
+  }
+
+  public P3 rgbToXyz(P3 rgb, P3 xyz) {
+    // http://en.wikipedia.org/wiki/CIE_1931_color_space
+    // http://rsb.info.nih.gov/ij/plugins/download/Color_Space_Converter.java
+    if (xyz == null)
+      xyz = new P3();
+    xyz.x = sxyz(rgb.x);
+    xyz.y = sxyz(rgb.y);
+    xyz.z = sxyz(rgb.z);
+    rgb2xyz.rotate(xyz);
+    return xyz;
+  }
+
+  private float sxyz(float x) {
+    x /= 255;
+    return (float) (x <= 0.04045 ? x / 12.92 : Math.pow(((x + 0.055) / 1.055),
+        2.4)) * 100;
+  }
+
+  public P3 xyzToRgb(P3 xyz, P3 rgb) {
+    // http://en.wikipedia.org/wiki/CIE_1931_color_space
+    // http://rsb.info.nih.gov/ij/plugins/download/Color_Space_Converter.java
+    if (rgb == null)
+      rgb = new P3();
+    rgb.setT(xyz);
+    rgb.scale(0.01f);
+    xyz2rgb.rotate(rgb);
+    rgb.x = clamp(srgb(rgb.x), 0, 255);
+    rgb.y = clamp(srgb(rgb.y), 0, 255);
+    rgb.z = clamp(srgb(rgb.z), 0, 255);
+    return rgb;
+  }
+
+  private float srgb(float x) {
+    return (float) (x > 0.0031308f ? (1.055 * Math.pow(x, 1.0 / 2.4)) - 0.055
+        : x * 12.92) * 255;
+  }
+
+  public P3 xyzToLab(P3 xyz, P3 lab) {
+    // http://en.wikipedia.org/wiki/Lab_color_space
+    // http://rsb.info.nih.gov/ij/plugins/download/Color_Space_Converter.java
+    // Lab([0..100], [-86.185..98.254], [-107.863..94.482])
+    // XYZn = D65 = {95.0429, 100.0, 108.8900};
+    if (lab == null)
+      lab = new P3();
+    float x = flab(xyz.x / 95.0429f);
+    float y = flab(xyz.y / 100);
+    float z = flab(xyz.z / 108.89f);
+    lab.x = (116 * y) - 16;
+    lab.y = 500 * (x - y);
+    lab.z = 200 * (y - z);
+    return lab;
+  }
+
+  private float flab(float t) {
+    return (float) (t > 8.85645168E-3 /* (24/116)^3 */? Math.pow(t,
+        0.333333333) : 7.78703704 /* 1/3*116/24*116/24 */* t + 0.137931034 /* 16/116 */
+    );
+  }
+
+  public P3 labToXyz(P3 lab, P3 xyz) {
+    // http://en.wikipedia.org/wiki/Lab_color_space
+    // http://rsb.info.nih.gov/ij/plugins/download/Color_Space_Converter.java
+    // XYZn = D65 = {95.0429, 100.0, 108.8900};
+    if (xyz == null)
+      xyz = new P3();
+
+    xyz.setT(lab);
+    float y = (xyz.x + 16) / 116;
+    float x = xyz.y / 500 + y;
+    float z = y - xyz.z / 200;
+    xyz.x = fxyz(x) * 95.0429f;
+    xyz.y = fxyz(y) * 100;
+    xyz.z = fxyz(z) * 108.89f;
+
+    return xyz;
+  }
+
+  private float fxyz(float t) {
+    return (float) (t > 0.206896552 /* (24/116) */? t * t * t
+        : 0.128418549 /* 3*24/116*24/116 */* (t - 0.137931034 /* 16/116 */));
+  }
+
+  private float clamp(float c, float min, float max) {
+    c = (c < min ? min : c > max ? max : c);
+    return (min == 0 ? Math.round(c) : c);
+  }
+
+  ///////////////////////// GifEncoder writing methods ////////////////////////
+
+  /**
+   * includes logical screen descriptor
+   * 
+   * @throws IOException
+   */
+  private void writeHeader() throws IOException {
+    putString("GIF89a");
+    putWord(width);
+    putWord(height);
+    putByte(0); // no global color table -- using local instead
+    putByte(0); // no background
+    putByte(0); // no pixel aspect ratio given
+  }
+
+  private void writeGraphicControlExtension() {
+    if (isTransparent || delayTime100ths >= 0) {
+      putByte(0x21); // graphic control extension
+      putByte(0xf9); // graphic control label
+      putByte(4); // block size
+      putByte((isTransparent ? 9 : 0) | (delayTime100ths > 0 ? 2 : 0)); // packed bytes 
+      putWord(delayTime100ths > 0 ? delayTime100ths : 0);
+      putByte(0); // transparent index
+      putByte(0); // end-of-block
+    }
+  }
+
+  // see  http://www.vurdalakov.net/misc/gif/netscape-looping-application-extension
+  //      +---------------+
+  //   0  |     0x21      |  Extension Label
+  //      +---------------+
+  //   1  |     0xFF      |  Application Extension Label
+  //      +---------------+
+  //   2  |     0x0B      |  Block Size
+  //      +---------------+
+  //   3  |               | 
+  //      +-             -+
+  //   4  |               | 
+  //      +-             -+
+  //   5  |               | 
+  //      +-             -+
+  //   6  |               | 
+  //      +-  NETSCAPE   -+  Application Identifier (8 bytes)
+  //   7  |               | 
+  //      +-             -+
+  //   8  |               | 
+  //      +-             -+
+  //   9  |               | 
+  //      +-             -+
+  //  10  |               | 
+  //      +---------------+
+  //  11  |               | 
+  //      +-             -+
+  //  12  |      2.0      |  Application Authentication Code (3 bytes)
+  //      +-             -+
+  //  13  |               | 
+  //      +===============+                      --+
+  //  14  |     0x03      |  Sub-block Data Size   |
+  //      +---------------+                        |
+  //  15  |     0x01      |  Sub-block ID          |
+  //      +---------------+                        | Application Data Sub-block
+  //  16  |               |                        |
+  //      +-             -+  Loop Count (2 bytes)  |
+  //  17  |               |                        |
+  //      +===============+                      --+
+  //  18  |     0x00      |  Block Terminator
+  //      +---------------+
+
+  private void writeNetscapeLoopExtension() {
+    putByte(0x21); // graphic control extension
+    putByte(0xff); // netscape loop extension
+    putByte(0x0B); // block size
+    putString("NETSCAPE2.0");
+    putByte(3);
+    putByte(1);
+    putWord(0); // loop indefinitely
+    putByte(0); // end-of-block
+
+  }
+
+  private int initCodeSize;
+  private int curpt;
+
+  private void writeImage() {
+    putByte(0x2C);
+    putWord(0); //left
+    putWord(0); //top
+    putWord(width);
+    putWord(height);
+
+    //    <Packed Fields>  =      LISx xZZZ
+
+    //    L Local Color Table Flag
+    //    I Interlace Flag
+    //    S Sort Flag
+    //    x Reserved
+    //    ZZZ Size of Local Color Table
+
+    int packedFields = 0x80 | (interlaced ? 0x40 : 0) | (bitsPerPixel - 1);
+    putByte(packedFields);
+    int colorMapSize = 1 << bitsPerPixel;
+    P3 p = new P3();
+    for (int i = 0; i < colorMapSize; i++) {
+      if (palette[i] != null)
+        p = palette[i];
+      putByte((int) p.x);
+      putByte((int) p.y);
+      putByte((int) p.z);
+    }
+    putByte(initCodeSize = (bitsPerPixel <= 1 ? 2 : bitsPerPixel));
+    compress();
+    putByte(0);
+  }
+
+  private void writeTrailer() {
+    // Write the GIF file terminator
+    putByte(0x3B);
+  }
+
+  ///// compression routines /////
+
+  private static final int EOF = -1;
+
+  // Return the next pixel from the image
+  private int nextPixel() {
+    if (countDown-- == 0)
+      return EOF;
+    int colorIndex = pixels[curpt];
+    // Bump the current X position
+    ++curx;
+    if (curx == width) {
+      // If we are at the end of a scan line, set curx back to the beginning
+      // If we are interlaced, bump the cury to the appropriate spot,
+      // otherwise, just increment it.
+      curx = 0;
+      if (interlaced)
+        updateY(INTERLACE_PARAMS[pass], INTERLACE_PARAMS[pass + 4]);
+      else
+        ++cury;
+    }
+    curpt = cury * width + curx;
+    return colorIndex & 0xff;
+  }
+
+  private static final int[] INTERLACE_PARAMS = { 8, 8, 4, 2, 4, 2, 1, 0 };
+
+  /**
+   * 
+   * Group 1 : Every 8th. row, starting with row 0. (Pass 1)
+   * 
+   * Group 2 : Every 8th. row, starting with row 4. (Pass 2)
+   * 
+   * Group 3 : Every 4th. row, starting with row 2. (Pass 3)
+   * 
+   * Group 4 : Every 2nd. row, starting with row 1. (Pass 4)
+   * 
+   * @param yNext
+   * @param yNew
+   */
+  private void updateY(int yNext, int yNew) {
+    cury += yNext;
+    if (yNew >= 0 && cury >= height) {
+      cury = yNew;
+      ++pass;
+    }
+  }
+
+  // Write out a word to the GIF file
+  private void putWord(int w) {
+    putByte(w);
+    putByte(w >> 8);
+  }
+
+  // GIFCOMPR.C       - GIF Image compression routines
+  //
+  // Lempel-Ziv compression based on 'compress'.  GIF modifications by
+  // David Rowley (mgardi@watdcsu.waterloo.edu)
+
+  // General DEFINEs
+
+  private static final int BITS = 12;
+
+  private static final int HSIZE = 5003; // 80% occupancy
+
+  // GIF Image compression - modified 'compress'
+  //
+  // Based on: compress.c - File compression ala IEEE Computer, June 1984.
+  //
+  // By Authors:  Spencer W. Thomas      (decvax!harpo!utah-cs!utah-gr!thomas)
+  //              Jim McKie              (decvax!mcvax!jim)
+  //              Steve Davies           (decvax!vax135!petsd!peora!srd)
+  //              Ken Turkowski          (decvax!decwrl!turtlevax!ken)
+  //              James A. Woods         (decvax!ihnp4!ames!jaw)
+  //              Joe Orost              (decvax!vax135!petsd!joe)
+
+  private int nBits; // number of bits/code
+  private int maxbits = BITS; // user settable max # bits/code
+  private int maxcode; // maximum code, given n_bits
+  private int maxmaxcode = 1 << BITS; // should NEVER generate this code
+
+  private final static int MAXCODE(int nBits) {
+    return (1 << nBits) - 1;
+  }
+
+  private int[] htab = new int[HSIZE];
+  private int[] codetab = new int[HSIZE];
+
+  private int hsize = HSIZE; // for dynamic table sizing
+
+  private int freeEnt = 0; // first unused entry
+
+  // block compression parameters -- after all codes are used up,
+  // and compression rate changes, start over.
+  private boolean clearFlag = false;
+
+  // Algorithm:  use open addressing double hashing (no chaining) on the
+  // prefix code / next character combination.  We do a variant of Knuth's
+  // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+  // secondary probe.  Here, the modular division first probe is gives way
+  // to a faster exclusive-or manipulation.  Also do block compression with
+  // an adaptive reset, whereby the code table is cleared when the compression
+  // ratio decreases, but after the table fills.  The variable-length output
+  // codes are re-sized at this point, and a special CLEAR code is generated
+  // for the decompressor.  Late addition:  construct the table according to
+  // file size for noticeable speed improvement on small files.  Please direct
+  // questions about this implementation to ames!jaw.
+
+  private int clearCode;
+  private int EOFCode;
+
+  private int countDown;
+  private int pass = 0;
+  private int curx, cury;
+
+  private void compress() {
+
+    // Calculate number of bits we are expecting
+    countDown = width * height;
+
+    // Indicate which pass we are on (if interlace)
+    pass = 0;
+    // Set up the current x and y position
+    curx = 0;
+    cury = 0;
+
+    // Set up the necessary values
+    clearFlag = false;
+    nBits = initCodeSize + 1;
+    maxcode = MAXCODE(nBits);
+
+    clearCode = 1 << initCodeSize;
+    EOFCode = clearCode + 1;
+    freeEnt = clearCode + 2;
+
+    // Set up the 'byte output' routine
+    bufPt = 0;
+
+    int ent = nextPixel();
+
+    int hshift = 0;
+    int fcode;
+    for (fcode = hsize; fcode < 65536; fcode *= 2)
+      ++hshift;
+    hshift = 8 - hshift; // set hash code range bound
+
+    int hsizeReg = hsize;
+    clearHash(hsizeReg); // clear hash table
+
+    output(clearCode);
+
+    int c;
+    outer_loop: while ((c = nextPixel()) != EOF) {
+      fcode = (c << maxbits) + ent;
+      int i = (c << hshift) ^ ent; // xor hashing
+
+      if (htab[i] == fcode) {
+        ent = codetab[i];
+        continue;
+      } else if (htab[i] >= 0) // non-empty slot
+      {
+        int disp = hsizeReg - i; // secondary hash (after G. Knott)
+        if (i == 0)
+          disp = 1;
+        do {
+          if ((i -= disp) < 0)
+            i += hsizeReg;
+
+          if (htab[i] == fcode) {
+            ent = codetab[i];
+            continue outer_loop;
+          }
+        } while (htab[i] >= 0);
+      }
+      output(ent);
+      ent = c;
+      if (freeEnt < maxmaxcode) {
+        codetab[i] = freeEnt++; // code -> hashtable
+        htab[i] = fcode;
+      } else {
+        clearBlock();
+      }
+    }
+    // Put out the final code.
+    output(ent);
+    output(EOFCode);
+  }
+
+  // output
+  //
+  // Output the given code.
+  // Inputs:
+  //      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
+  //              that n_bits =< wordsize - 1.
+  // Outputs:
+  //      Outputs code to the file.
+  // Assumptions:
+  //      Chars are 8 bits long.
+  // Algorithm:
+  //      Maintain a BITS character long buffer (so that 8 codes will
+  // fit in it exactly).  Use the VAX insv instruction to insert each
+  // code in turn.  When the buffer fills up empty it and start over.
+
+  private int curAccum = 0;
+  private int curBits = 0;
+
+  private int masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F,
+      0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF,
+      0x7FFF, 0xFFFF };
+
+  private void output(int code) {
+    curAccum &= masks[curBits];
+
+    if (curBits > 0)
+      curAccum |= (code << curBits);
+    else
+      curAccum = code;
+
+    curBits += nBits;
+
+    while (curBits >= 8) {
+      byteOut((byte) (curAccum & 0xff));
+      curAccum >>= 8;
+      curBits -= 8;
+    }
+
+    // If the next entry is going to be too big for the code size,
+    // then increase it, if possible.
+    if (freeEnt > maxcode || clearFlag) {
+      if (clearFlag) {
+        maxcode = MAXCODE(nBits = initCodeSize + 1);
+        clearFlag = false;
+      } else {
+        ++nBits;
+        if (nBits == maxbits)
+          maxcode = maxmaxcode;
+        else
+          maxcode = MAXCODE(nBits);
+      }
+    }
+
+    if (code == EOFCode) {
+      // At EOF, write the rest of the buffer.
+      while (curBits > 0) {
+        byteOut((byte) (curAccum & 0xff));
+        curAccum >>= 8;
+        curBits -= 8;
+      }
+      flushBytes();
+    }
+  }
+
+  // Clear out the hash table
+
+  // table clear for block compress
+  private void clearBlock() {
+    clearHash(hsize);
+    freeEnt = clearCode + 2;
+    clearFlag = true;
+
+    output(clearCode);
+  }
+
+  // reset code table
+  private void clearHash(int hsize) {
+    for (int i = 0; i < hsize; ++i)
+      htab[i] = -1;
+  }
+
+  // GIF-specific routines (byte array buffer)
+
+  // Number of bytes so far in this 'packet'
+  private int bufPt;
+
+  // Define the storage for the packet accumulator
+  final private byte[] buf = new byte[256];
+
+  // Add a byte to the end of the current packet, and if it is 254
+  // byte, flush the packet to disk.
+  private void byteOut(byte c) {
+    buf[bufPt++] = c;
+    if (bufPt >= 254)
+      flushBytes();
+  }
+
+  // Flush the packet to disk, and reset the accumulator
+  protected void flushBytes() {
+    if (bufPt > 0) {
+      putByte(bufPt);
+      out.write(buf, 0, bufPt);
+      byteCount += bufPt;
+      bufPt = 0;
+    }
+  }
+
+}
diff --git a/src/javajs/img/ImageEncoder.java b/src/javajs/img/ImageEncoder.java
new file mode 100644 (file)
index 0000000..91a91fc
--- /dev/null
@@ -0,0 +1,124 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-06-02 12:14:13 -0500 (Sat, 02 Jun 2007) $
+ * $Revision: 7831 $
+ *
+ * Copyright (C) 2000-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+// ImageEncoder - abstract class for writing out an image
+//
+// Copyright (C) 1996 by Jef Poskanzer <jef@mail.acme.com>.  All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+package javajs.img;
+
+import java.util.Map;
+
+import javajs.api.GenericImageEncoder;
+import javajs.util.OC;
+
+
+
+/**
+ * Generic abstract image creator:
+ * 
+ *   (1) set parameters
+ *   
+ *   (2) encode the image bytes, if necessary
+ *   
+ *   (3) generate the image 
+ * @author Bob Hanson hansonr@stolaf.edu
+ */
+
+public abstract class ImageEncoder implements GenericImageEncoder {
+
+  protected OC out;
+
+  protected int width = -1;
+  protected int height = -1;
+  protected int quality = -1;
+  protected String date;
+  protected boolean logging;
+  protected boolean doClose = true;
+
+  /**
+   * @param type
+   * @param out
+   * @param params
+   */
+  @Override
+  public boolean createImage(String type, OC out, Map<String, Object> params)
+      throws Exception {
+    this.out = out;
+    logging = (Boolean.TRUE == params.get("logging"));
+    width = ((Integer) params.get("imageWidth")).intValue();
+    height = ((Integer) params.get("imageHeight")).intValue();
+    pixels = (int[]) params.get("imagePixels");
+    date = (String) params.get("date");
+    Integer q = (Integer) params.get("quality");
+    quality = (q == null ? -1 : q.intValue());
+    setParams(params);
+    generate();
+    close(); // GIF will override this and not close
+    return doClose;
+  }
+
+  abstract protected void setParams(Map<String, Object> params);
+  abstract protected void generate() throws Exception;
+
+  protected int[] pixels;
+
+  protected void putString(String s) {
+    byte[] b = s.getBytes();
+    out.write(b, 0, b.length);
+  }
+
+  protected void putByte(int b) {
+    out.writeByteAsInt(b);
+  }
+  
+  protected void close() {
+    // your responsibility to close the output channel
+  }
+
+}
diff --git a/src/javajs/img/Jpg64Encoder.java b/src/javajs/img/Jpg64Encoder.java
new file mode 100644 (file)
index 0000000..796972f
--- /dev/null
@@ -0,0 +1,64 @@
+// Version 1.0a
+// Copyright (C) 1998, James R. Weeks and BioElectroMech.
+// Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.
+
+// See license.txt for details about the allowed used of this software.
+// This software is based in part on the work of the Independent JPEG Group.
+// See IJGreadme.txt for details about the Independent JPEG Group's license.
+
+// This encoder is inspired by the Java Jpeg encoder by Florian Raemy,
+// studwww.eurecom.fr/~raemy.
+// It borrows a great deal of code and structure from the Independent
+// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.
+// See license.txt for details 
+
+/*
+ * JpegEncoder and its associated classes are Copyright (c) 1998, James R. Weeks and BioElectroMech
+ * see(Jmol/src/com/obrador/license.txt)
+ * 
+ * javajs.img.JpegEncoder.java was adapted by Bob Hanson
+ * for Jmol in the following ways:
+ * 
+ * 1) minor coding efficiencies were made in some for() loops.
+ * 2) methods not used by Jmol were commented out
+ * 3) method and variable signatures were modified to provide 
+ *    more appropriate method privacy.
+ * 4) additions for Java2Script compatibility 
+ * 
+ * Original files are maintained in the Jmol.src.com.obrador package, but
+ * these original files are not distributed with Jmol.
+ *   
+*/
+
+package javajs.img;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javajs.util.Base64;
+import javajs.util.OC;
+
+
+public class Jpg64Encoder extends JpgEncoder {
+
+  private OC outTemp;
+
+  @Override
+  protected void setParams(Map<String, Object> params) {
+    defaultQuality = 75;
+    outTemp = (OC) params.remove("outputChannelTemp");
+    super.setParams(params);
+  }
+
+  @Override
+  protected void generate() throws IOException {
+    OC out0 = out;
+    out = outTemp;
+    super.generate();
+    byte[] bytes = Base64.getBytes64(out.toByteArray());
+    outTemp = null;
+    out = out0;
+    out.write(bytes, 0, bytes.length);
+  }
+
+}
diff --git a/src/javajs/img/JpgEncoder.java b/src/javajs/img/JpgEncoder.java
new file mode 100644 (file)
index 0000000..5c128d6
--- /dev/null
@@ -0,0 +1,1208 @@
+// Version 1.0a
+// Copyright (C) 1998, James R. Weeks and BioElectroMech.
+// Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.
+
+// See license.txt for details about the allowed used of this software.
+// This software is based in part on the work of the Independent JPEG Group.
+// See IJGreadme.txt for details about the Independent JPEG Group's license.
+
+// This encoder is inspired by the Java Jpeg encoder by Florian Raemy,
+// studwww.eurecom.fr/~raemy.
+// It borrows a great deal of code and structure from the Independent
+// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.
+// See license.txt for details 
+
+/*
+ * JpegEncoder and its associated classes are Copyright (c) 1998, James R. Weeks and BioElectroMech
+ * see(Jmol/src/com/obrador/license.txt)
+ * 
+ * javjs.img.JpegEncoder.java was adapted by Bob Hanson
+ * 
+ * for Jmol in the following ways:
+ * 
+ * 1) minor coding efficiencies were made in some for() loops.
+ * 2) methods not used by Jmol were commented out
+ * 3) method and variable signatures were modified to provide 
+ *    more appropriate method privacy.
+ * 4) additions for Java2Script compatibility 
+ * 
+ * Original files are maintained in the Jmol.src.com.obrador package, but
+ * these original files are not distributed with Jmol.
+ *   
+*/
+
+package javajs.img;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javajs.img.ImageEncoder;
+import javajs.util.AU;
+import javajs.util.OC;
+
+/**
+ * JpegEncoder - The JPEG main program which performs a jpeg compression of an
+ * image.
+ * 
+ *  A system to allow the full Jmol state -- regardless of length -- 
+ *  to be encoded in a set of APP1 (FFE1) tags.
+ *  But we have to be careful about line ends for backward compatibility. 
+ *  This solution is not 100% effective, because some data lines may in principle be 
+ *  Very large and may not contain new lines for more than 65500 characters, 
+ *  But that would be very unusual. Perhaps a huge data set loaded from a 
+ *  string. Introduced in Jmol 12.1.36. Bob Hanson
+ *  
+ * See org.com.obrador.license.txt
+ * 
+ */
+
+public class JpgEncoder extends ImageEncoder {
+
+  // this string will GENERALLY appear at the end of lines and be escaped 
+  private static final int CONTINUE_MAX = 65500; // some room to spare here. 
+  private static final int CONTINUE_MAX_BUFFER = CONTINUE_MAX + 10; // never break up last 10 bytes
+
+  private JpegObj jpegObj;
+  private Huffman huf;
+  private DCT dct;
+  protected int defaultQuality = 100;
+  private String applicationTag;
+
+  public JpgEncoder() {
+
+  }
+
+  @Override
+  protected void setParams(Map<String, Object> params) {
+    if (quality <= 0)
+      quality = (params.containsKey("qualityJPG") ? ((Integer) params.get("qualityJPG")).intValue() : defaultQuality);
+    jpegObj = new JpegObj();
+    jpegObj.comment = (String) params.get("comment");
+    applicationTag = (String) params.get("jpgAppTag");
+  }
+
+  @Override
+  protected void generate() throws IOException {
+    jpegObj.imageWidth = width;
+    jpegObj.imageHeight = height;
+    dct = new DCT(quality);
+    huf = new Huffman(width, height);
+    if (jpegObj == null)
+      return;
+    jpegObj.getYCCArray(pixels);
+    String longState = writeHeaders(jpegObj, dct);
+    writeCompressedData(jpegObj, dct, huf);
+    writeMarker(eoi);
+    if (longState != null) {
+      byte[] b = longState.getBytes();
+      out.write(b, 0, b.length);
+    }
+  }
+
+  private void writeCompressedData(JpegObj jpegObj, DCT dct, Huffman huf) {
+    int i, j, r, c, a, b;
+    int comp, xpos, ypos, xblockoffset, yblockoffset;
+    float inputArray[][];
+    float dctArray1[][] = new float[8][8];
+    double dctArray2[][] = new double[8][8];
+    int dctArray3[] = new int[8 * 8];
+
+    /*
+     * This method controls the compression of the image.
+     * Starting at the upper left of the image, it compresses 8x8 blocks
+     * of data until the entire image has been compressed.
+     */
+
+    int lastDCvalue[] = new int[jpegObj.numberOfComponents];
+    //int zeroArray[] = new int[64]; // initialized to hold all zeros
+    //int Width = 0, Height = 0;
+    //int nothing = 0, not;
+    int minBlockWidth, minBlockHeight;
+    // This initial setting of MinBlockWidth and MinBlockHeight is done to
+    // ensure they start with values larger than will actually be the case.
+    minBlockWidth = ((huf.imageWidth % 8 != 0) ? (int) (Math
+        .floor(huf.imageWidth / 8.0) + 1) * 8 : huf.imageWidth);
+    minBlockHeight = ((huf.imageHeight % 8 != 0) ? (int) (Math
+        .floor(huf.imageHeight / 8.0) + 1) * 8 : huf.imageHeight);
+    for (comp = 0; comp < jpegObj.numberOfComponents; comp++) {
+      minBlockWidth = Math.min(minBlockWidth, jpegObj.blockWidth[comp]);
+      minBlockHeight = Math.min(minBlockHeight, jpegObj.blockHeight[comp]);
+    }
+    xpos = 0;
+    for (r = 0; r < minBlockHeight; r++) {
+      for (c = 0; c < minBlockWidth; c++) {
+        xpos = c * 8;
+        ypos = r * 8;
+        for (comp = 0; comp < jpegObj.numberOfComponents; comp++) {
+          //Width = JpegObj.BlockWidth[comp];
+          //Height = JpegObj.BlockHeight[comp];
+          inputArray = jpegObj.components[comp];
+          int vsampF = jpegObj.vsampFactor[comp];
+          int hsampF = jpegObj.hsampFactor[comp];
+          int qNumber = jpegObj.qtableNumber[comp];
+          int dcNumber = jpegObj.dctableNumber[comp];
+          int acNumber = jpegObj.actableNumber[comp];
+
+          for (i = 0; i < vsampF; i++) {
+            for (j = 0; j < hsampF; j++) {
+              xblockoffset = j * 8;
+              yblockoffset = i * 8;
+              for (a = 0; a < 8; a++) {
+                for (b = 0; b < 8; b++) {
+
+                  // I believe this is where the dirty line at the bottom of
+                  // the image is coming from.
+                  // I need to do a check here to make sure I'm not reading past
+                  // image data.
+                  // This seems to not be a big issue right now. (04/04/98)
+
+                  dctArray1[a][b] = inputArray[ypos + yblockoffset + a][xpos
+                      + xblockoffset + b];
+                }
+              }
+              // The following code commented out because on some images this technique
+              // results in poor right and bottom borders.
+              // if ((!JpegObj.lastColumnIsDummy[comp] || c < Width - 1) &&
+              //       (!JpegObj.lastRowIsDummy[comp] || r < Height - 1)) {
+              dctArray2 = DCT.forwardDCT(dctArray1);
+              dctArray3 = DCT.quantizeBlock(dctArray2, dct.divisors[qNumber]);
+              // }
+              // else {
+              //   zeroArray[0] = dctArray3[0];
+              //   zeroArray[0] = lastDCvalue[comp];
+              //   dctArray3 = zeroArray;
+              // }
+              huf.HuffmanBlockEncoder(out, dctArray3, lastDCvalue[comp],
+                  dcNumber, acNumber);
+              lastDCvalue[comp] = dctArray3[0];
+            }
+          }
+        }
+      }
+    }
+    huf.flushBuffer(out);
+  }
+
+  private static byte[] eoi = { (byte) 0xFF, (byte) 0xD9 };
+
+  private static byte[] jfif = new byte[] {
+  /* JFIF[0] =*/(byte) 0xff,
+  /* JFIF[1] =*/(byte) 0xe0,
+  /* JFIF[2] =*/0,
+  /* JFIF[3] =*/16,
+  /* JFIF[4] =*/(byte) 0x4a, //'J'
+      /* JFIF[5] =*/(byte) 0x46, //'F'
+      /* JFIF[6] =*/(byte) 0x49, //'I'
+      /* JFIF[7] =*/(byte) 0x46, //'F'
+      /* JFIF[8] =*/0,
+      /* JFIF[9] =*/1,
+      /* JFIF[10] =*/0,
+      /* JFIF[11] =*/0,
+      /* JFIF[12] =*/0,
+      /* JFIF[13] =*/1,
+      /* JFIF[14] =*/0,
+      /* JFIF[15] =*/1,
+      /* JFIF[16] =*/0,
+      /* JFIF[17] =*/0 };
+
+  private static byte[] soi = { (byte) 0xFF, (byte) 0xD8 };
+
+  private String writeHeaders(JpegObj jpegObj, DCT dct) {
+    int i, j, index, offset;
+    int tempArray[];
+
+    // the SOI marker
+    writeMarker(soi);
+
+    // The order of the following headers is quite inconsequential.
+    // the JFIF header
+    writeArray(jfif);
+
+    // Comment Header
+    String comment = null;
+    if (jpegObj.comment.length() > 0)
+      writeString(jpegObj.comment, (byte) 0xE1); // App data 1
+    writeString(
+        "JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech.\n\n",
+        (byte) 0xFE);
+
+    // The DQT header
+    // 0 is the luminance index and 1 is the chrominance index
+    byte dqt[] = new byte[134];
+    dqt[0] = (byte) 0xFF;
+    dqt[1] = (byte) 0xDB;
+    dqt[2] = 0;
+    dqt[3] = (byte) 132;
+    offset = 4;
+    for (i = 0; i < 2; i++) {
+      dqt[offset++] = (byte) ((0 << 4) + i);
+      tempArray = dct.quantum[i];
+      for (j = 0; j < 64; j++) {
+        dqt[offset++] = (byte) tempArray[Huffman.jpegNaturalOrder[j]];
+      }
+    }
+    writeArray(dqt);
+
+    // Start of Frame Header
+    byte sof[] = new byte[19];
+    sof[0] = (byte) 0xFF;
+    sof[1] = (byte) 0xC0;
+    sof[2] = 0;
+    sof[3] = 17;
+    sof[4] = (byte) jpegObj.precision;
+    sof[5] = (byte) ((jpegObj.imageHeight >> 8) & 0xFF);
+    sof[6] = (byte) ((jpegObj.imageHeight) & 0xFF);
+    sof[7] = (byte) ((jpegObj.imageWidth >> 8) & 0xFF);
+    sof[8] = (byte) ((jpegObj.imageWidth) & 0xFF);
+    sof[9] = (byte) jpegObj.numberOfComponents;
+    index = 10;
+    for (i = 0; i < sof[9]; i++) {
+      sof[index++] = (byte) jpegObj.compID[i];
+      sof[index++] = (byte) ((jpegObj.hsampFactor[i] << 4) + jpegObj.vsampFactor[i]);
+      sof[index++] = (byte) jpegObj.qtableNumber[i];
+    }
+    writeArray(sof);
+
+    WriteDHTHeader(Huffman.bitsDCluminance, Huffman.valDCluminance);
+    WriteDHTHeader(Huffman.bitsACluminance, Huffman.valACluminance);
+    WriteDHTHeader(Huffman.bitsDCchrominance, Huffman.valDCchrominance);
+    WriteDHTHeader(Huffman.bitsACchrominance, Huffman.valACchrominance);
+
+    // Start of Scan Header
+    byte sos[] = new byte[14];
+    sos[0] = (byte) 0xFF;
+    sos[1] = (byte) 0xDA;
+    sos[2] = 0;
+    sos[3] = 12;
+    sos[4] = (byte) jpegObj.numberOfComponents;
+    index = 5;
+    for (i = 0; i < sos[4]; i++) {
+      sos[index++] = (byte) jpegObj.compID[i];
+      sos[index++] = (byte) ((jpegObj.dctableNumber[i] << 4) + jpegObj.actableNumber[i]);
+    }
+    sos[index++] = (byte) jpegObj.ss;
+    sos[index++] = (byte) jpegObj.se;
+    sos[index++] = (byte) ((jpegObj.ah << 4) + jpegObj.al);
+    writeArray(sos);
+    return comment;
+  }
+
+  private void writeString(String s, byte id) {
+    int len = s.length();
+    int i0 = 0;
+    String suffix = applicationTag;
+    while (i0 < len) {
+      int nBytes = len - i0;
+      if (nBytes > CONTINUE_MAX_BUFFER) {
+        nBytes = CONTINUE_MAX;
+        // but break only at line breaks
+        int pt = s.lastIndexOf('\n', i0 + nBytes);
+        if (pt > i0 + 1)
+          nBytes = pt - i0;
+      }
+      if (i0 + nBytes == len)
+        suffix = "";
+      writeTag(nBytes + suffix.length(), id);
+      writeArray(s.substring(i0, i0 + nBytes).getBytes());
+      if (suffix.length() > 0)
+        writeArray(suffix.getBytes());
+      i0 += nBytes;
+    }
+  }
+
+  private void writeTag(int length, byte id) {
+    length += 2;
+    byte com[] = new byte[4];
+    com[0] = (byte) 0xFF;
+    com[1] = id;
+    com[2] = (byte) ((length >> 8) & 0xFF);
+    com[3] = (byte) (length & 0xFF);
+    writeArray(com);
+  }
+
+  void WriteDHTHeader(int[] bits, int[] val) {
+    // hansonr@stolaf.edu: simplified code.
+    byte[] dht;
+    int bytes = 0;
+    for (int j = 1; j < 17; j++)
+      bytes += bits[j];
+    dht = new byte[21 + bytes];
+    dht[0] = (byte) 0xFF;
+    dht[1] = (byte) 0xC4;
+    int index = 4;
+    for (int j = 0; j < 17; j++)
+      dht[index++] = (byte) bits[j];
+    for (int j = 0; j < bytes; j++)
+      dht[index++] = (byte) val[j];
+    dht[2] = (byte) (((index - 2) >> 8) & 0xFF);
+    dht[3] = (byte) ((index - 2) & 0xFF);
+    writeArray(dht);
+  }
+
+  void writeMarker(byte[] data) {
+    out.write(data, 0, 2);
+  }
+
+  void writeArray(byte[] data) {
+    out.write(data, 0, data.length);
+  }
+
+}
+
+// This class incorporates quality scaling as implemented in the JPEG-6a
+// library.
+
+/*
+ * DCT - A Java implementation of the Discreet Cosine Transform
+ */
+
+class DCT {
+
+  /**
+   * DCT Block Size - default 8
+   */
+  private final static int N = 8;
+  private final static int NN = N * N;
+
+  /**
+   * Image Quality (0-100) - default 80 (good image / good compression)
+   */
+  //public int QUALITY = 80;
+
+  int[][] quantum = AU.newInt2(2);
+  double[][] divisors = AU.newDouble2(2);
+
+  /**
+   * Quantitization Matrix for luminace.
+   */
+  private int quantum_luminance[] = new int[NN];
+  private double DivisorsLuminance[] = new double[NN];
+
+  /**
+   * Quantitization Matrix for chrominance.
+   */
+  private int quantum_chrominance[] = new int[NN];
+  private double DivisorsChrominance[] = new double[NN];
+
+  /**
+   * Constructs a new DCT object. Initializes the cosine transform matrix these
+   * are used when computing the DCT and it's inverse. This also initializes the
+   * run length counters and the ZigZag sequence. Note that the image quality
+   * can be worse than 25 however the image will be extemely pixelated, usually
+   * to a block size of N.
+   * 
+   * @param quality
+   *        The quality of the image (0 worst - 100 best)
+   * 
+   */
+  DCT(int quality) {
+    initMatrix(quality);
+  }
+
+  /*
+   * This method sets up the quantization matrix for luminance and
+   * chrominance using the Quality parameter.
+   */
+  private void initMatrix(int quality) {
+    // converting quality setting to that specified in the jpeg_quality_scaling
+    // method in the IJG Jpeg-6a C libraries
+
+    quality = (quality < 1 ? 1 : quality > 100 ? 100 : quality);
+    quality = (quality < 50 ? 5000 / quality : 200 - quality * 2);
+
+    // Creating the luminance matrix
+
+    quantum_luminance[0] = 16;
+    quantum_luminance[1] = 11;
+    quantum_luminance[2] = 10;
+    quantum_luminance[3] = 16;
+    quantum_luminance[4] = 24;
+    quantum_luminance[5] = 40;
+    quantum_luminance[6] = 51;
+    quantum_luminance[7] = 61;
+    quantum_luminance[8] = 12;
+    quantum_luminance[9] = 12;
+    quantum_luminance[10] = 14;
+    quantum_luminance[11] = 19;
+    quantum_luminance[12] = 26;
+    quantum_luminance[13] = 58;
+    quantum_luminance[14] = 60;
+    quantum_luminance[15] = 55;
+    quantum_luminance[16] = 14;
+    quantum_luminance[17] = 13;
+    quantum_luminance[18] = 16;
+    quantum_luminance[19] = 24;
+    quantum_luminance[20] = 40;
+    quantum_luminance[21] = 57;
+    quantum_luminance[22] = 69;
+    quantum_luminance[23] = 56;
+    quantum_luminance[24] = 14;
+    quantum_luminance[25] = 17;
+    quantum_luminance[26] = 22;
+    quantum_luminance[27] = 29;
+    quantum_luminance[28] = 51;
+    quantum_luminance[29] = 87;
+    quantum_luminance[30] = 80;
+    quantum_luminance[31] = 62;
+    quantum_luminance[32] = 18;
+    quantum_luminance[33] = 22;
+    quantum_luminance[34] = 37;
+    quantum_luminance[35] = 56;
+    quantum_luminance[36] = 68;
+    quantum_luminance[37] = 109;
+    quantum_luminance[38] = 103;
+    quantum_luminance[39] = 77;
+    quantum_luminance[40] = 24;
+    quantum_luminance[41] = 35;
+    quantum_luminance[42] = 55;
+    quantum_luminance[43] = 64;
+    quantum_luminance[44] = 81;
+    quantum_luminance[45] = 104;
+    quantum_luminance[46] = 113;
+    quantum_luminance[47] = 92;
+    quantum_luminance[48] = 49;
+    quantum_luminance[49] = 64;
+    quantum_luminance[50] = 78;
+    quantum_luminance[51] = 87;
+    quantum_luminance[52] = 103;
+    quantum_luminance[53] = 121;
+    quantum_luminance[54] = 120;
+    quantum_luminance[55] = 101;
+    quantum_luminance[56] = 72;
+    quantum_luminance[57] = 92;
+    quantum_luminance[58] = 95;
+    quantum_luminance[59] = 98;
+    quantum_luminance[60] = 112;
+    quantum_luminance[61] = 100;
+    quantum_luminance[62] = 103;
+    quantum_luminance[63] = 99;
+
+    AANscale(DivisorsLuminance, quantum_luminance, quality);
+
+    // Creating the chrominance matrix
+
+    for (int i = 4; i < 64; i++)
+      quantum_chrominance[i] = 99;
+
+    quantum_chrominance[0] = 17;
+    quantum_chrominance[1] = 18;
+    quantum_chrominance[2] = 24;
+    quantum_chrominance[3] = 47;
+
+    quantum_chrominance[8] = 18;
+    quantum_chrominance[9] = 21;
+    quantum_chrominance[10] = 26;
+    quantum_chrominance[11] = 66;
+
+    quantum_chrominance[16] = 24;
+    quantum_chrominance[17] = 26;
+    quantum_chrominance[18] = 56;
+
+    quantum_chrominance[24] = 47;
+    quantum_chrominance[25] = 66;
+
+    AANscale(DivisorsChrominance, quantum_chrominance, quality);
+
+    // quantum and Divisors are objects used to hold the appropriate matices
+
+    quantum[0] = quantum_luminance;
+    quantum[1] = quantum_chrominance;
+
+    divisors[0] = DivisorsLuminance;
+    divisors[1] = DivisorsChrominance;
+
+  }
+
+  private final static double[] AANscaleFactor = { 1.0, 1.387039845,
+      1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379 };
+
+  static private void AANscale(double[] divisors, int[] values, int quality) {
+
+    for (int j = 0; j < 64; j++) {
+      int temp = (values[j] * quality + 50) / 100;
+      values[j] = (temp < 1 ? 1 : temp > 255 ? 255 : temp);
+    }
+
+    for (int i = 0, index = 0; i < 8; i++)
+      for (int j = 0; j < 8; j++, index++)
+        // The divisors for the LL&M method (the slow integer method used in
+        // jpeg 6a library).  This method is currently (04/04/98) incompletely
+        // implemented.
+        // DivisorsLuminance[index] = ((double) quantum_luminance[index]) << 3;
+        // The divisors for the AAN method (the float method used in jpeg 6a library.
+        divisors[index] = (0.125 / (values[index] * AANscaleFactor[i] * AANscaleFactor[j]));
+  }
+
+  /*
+   * This method preforms forward DCT on a block of image data using
+   * the literal method specified for a 2-D Discrete Cosine Transform.
+   * It is included as a curiosity and can give you an idea of the
+   * difference in the compression result (the resulting image quality)
+   * by comparing its output to the output of the AAN method below.
+   * It is ridiculously inefficient.
+   */
+
+  // For now the final output is unusable.  The associated quantization step
+  // needs some tweaking.  If you get this part working, please let me know.
+  /*
+    public double[][] forwardDCTExtreme(float input[][])
+    {
+      double output[][] = new double[N][N];
+      int v, u, x, y;
+      for (v = 0; v < 8; v++) {
+        for (u = 0; u < 8; u++) {
+          for (x = 0; x < 8; x++) {
+            for (y = 0; y < 8; y++) {
+              output[v][u] += input[x][y] * 
+                  Math.cos(((double)(2*x + 1)*(double)u*Math.PI)/16)*
+                  Math.cos(((double)(2*y + 1)*(double)v*Math.PI)/16);
+            }
+          }
+          output[v][u] *= (0.25)*((u == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0)*((v == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0);
+        }
+      }
+      return output;
+    }
+    
+  */
+  /*
+   * This method preforms a DCT on a block of image data using the AAN
+   * method as implemented in the IJG Jpeg-6a library.
+   */
+  static double[][] forwardDCT(float input[][]) {
+    double output[][] = new double[N][N];
+    double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+    double tmp10, tmp11, tmp12, tmp13;
+    double z1, z2, z3, z4, z5, z11, z13;
+    // Subtracts 128 from the input values
+    for (int i = 0; i < 8; i++)
+      for (int j = 0; j < 8; j++)
+        output[i][j] = (input[i][j] - 128.0);
+    // input[i][j] -= 128;
+
+    for (int i = 0; i < 8; i++) {
+      tmp0 = output[i][0] + output[i][7];
+      tmp7 = output[i][0] - output[i][7];
+      tmp1 = output[i][1] + output[i][6];
+      tmp6 = output[i][1] - output[i][6];
+      tmp2 = output[i][2] + output[i][5];
+      tmp5 = output[i][2] - output[i][5];
+      tmp3 = output[i][3] + output[i][4];
+      tmp4 = output[i][3] - output[i][4];
+
+      tmp10 = tmp0 + tmp3;
+      tmp13 = tmp0 - tmp3;
+      tmp11 = tmp1 + tmp2;
+      tmp12 = tmp1 - tmp2;
+
+      output[i][0] = tmp10 + tmp11;
+      output[i][4] = tmp10 - tmp11;
+
+      z1 = (tmp12 + tmp13) * 0.707106781;
+      output[i][2] = tmp13 + z1;
+      output[i][6] = tmp13 - z1;
+
+      tmp10 = tmp4 + tmp5;
+      tmp11 = tmp5 + tmp6;
+      tmp12 = tmp6 + tmp7;
+
+      z5 = (tmp10 - tmp12) * 0.382683433;
+      z2 = 0.541196100 * tmp10 + z5;
+      z4 = 1.306562965 * tmp12 + z5;
+      z3 = tmp11 * 0.707106781;
+
+      z11 = tmp7 + z3;
+      z13 = tmp7 - z3;
+
+      output[i][5] = z13 + z2;
+      output[i][3] = z13 - z2;
+      output[i][1] = z11 + z4;
+      output[i][7] = z11 - z4;
+    }
+
+    for (int i = 0; i < 8; i++) {
+      tmp0 = output[0][i] + output[7][i];
+      tmp7 = output[0][i] - output[7][i];
+      tmp1 = output[1][i] + output[6][i];
+      tmp6 = output[1][i] - output[6][i];
+      tmp2 = output[2][i] + output[5][i];
+      tmp5 = output[2][i] - output[5][i];
+      tmp3 = output[3][i] + output[4][i];
+      tmp4 = output[3][i] - output[4][i];
+
+      tmp10 = tmp0 + tmp3;
+      tmp13 = tmp0 - tmp3;
+      tmp11 = tmp1 + tmp2;
+      tmp12 = tmp1 - tmp2;
+
+      output[0][i] = tmp10 + tmp11;
+      output[4][i] = tmp10 - tmp11;
+
+      z1 = (tmp12 + tmp13) * 0.707106781;
+      output[2][i] = tmp13 + z1;
+      output[6][i] = tmp13 - z1;
+
+      tmp10 = tmp4 + tmp5;
+      tmp11 = tmp5 + tmp6;
+      tmp12 = tmp6 + tmp7;
+
+      z5 = (tmp10 - tmp12) * 0.382683433;
+      z2 = 0.541196100 * tmp10 + z5;
+      z4 = 1.306562965 * tmp12 + z5;
+      z3 = tmp11 * 0.707106781;
+
+      z11 = tmp7 + z3;
+      z13 = tmp7 - z3;
+
+      output[5][i] = z13 + z2;
+      output[3][i] = z13 - z2;
+      output[1][i] = z11 + z4;
+      output[7][i] = z11 - z4;
+    }
+
+    return output;
+  }
+
+  /*
+   * This method quantitizes data and rounds it to the nearest integer.
+   */
+  static int[] quantizeBlock(double inputData[][], double[] divisorsCode) {
+    int outputData[] = new int[NN];
+    for (int i = 0, index = 0; i < 8; i++)
+      for (int j = 0; j < 8; j++, index++)
+        // The second line results in significantly better compression.
+        outputData[index] = (int) (Math.round(inputData[i][j]
+            * divisorsCode[index]));
+    //                        outputData[index] = (int)(((inputData[i][j] * (((double[]) (Divisors[code]))[index])) + 16384.5) -16384);
+    return outputData;
+  }
+
+  /*
+   * This is the method for quantizing a block DCT'ed with forwardDCTExtreme
+   * This method quantitizes data and rounds it to the nearest integer.
+   */
+
+  /*
+
+    public double[][] forwardDCTExtreme(float input[][])
+    {
+      double output[][] = new double[N][N];
+      int v, u, x, y;
+      for (v = 0; v < 8; v++) {
+        for (u = 0; u < 8; u++) {
+          for (x = 0; x < 8; x++) {
+            for (y = 0; y < 8; y++) {
+              output[v][u] += input[x][y] * 
+                  Math.cos(((double)(2*x + 1)*(double)u*Math.PI)/16)*
+                  Math.cos(((double)(2*y + 1)*(double)v*Math.PI)/16);
+            }
+          }
+          output[v][u] *= (0.25)*((u == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0)*((v == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0);
+        }
+      }
+      return output;
+    }
+
+   */
+  /*
+    public int[] quantizeBlockExtreme(double inputData[][], int code)
+    {
+      int outputData[] = new int[NN];
+      int i, j;
+      int index;
+      index = 0;
+      for (i = 0; i < 8; i++) {
+        for (j = 0; j < 8; j++) {
+          outputData[index] = (int)(Math.round(inputData[i][j] / (((int[]) (quantum[code]))[index])));
+          index++;
+        }
+      }
+      
+      return outputData;
+    }
+  */
+}
+
+// This class was modified by James R. Weeks on 3/27/98.
+// It now incorporates Huffman table derivation as in the C jpeg library
+// from the IJG, Jpeg-6a.
+
+class Huffman {
+  private int bufferPutBits, bufferPutBuffer;
+  int imageHeight;
+  int imageWidth;
+  private int dc_matrix0[][];
+  private int ac_matrix0[][];
+  private int dc_matrix1[][];
+  private int ac_matrix1[][];
+  private int[][][] dc_matrix;
+  private int[][][] ac_matrix;
+  //private int code;
+  int numOfDCTables;
+  int numOfACTables;
+  final static int[] bitsDCluminance = { 0x00, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0,
+      0, 0, 0, 0, 0 };
+  final static int[] valDCluminance = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  final static int[] bitsDCchrominance = { 0x01, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+      1, 0, 0, 0, 0, 0 };
+  final static int[] valDCchrominance = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };
+  final static int[] bitsACluminance = { 0x10, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4,
+      4, 0, 0, 1, 0x7d };
+  final static int[] valACluminance = { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,
+      0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,
+      0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,
+      0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18,
+      0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,
+      0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,
+      0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,
+      0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,
+      0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+      0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
+      0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+      0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+      0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,
+      0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
+  final static int[] bitsACchrominance = { 0x11, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5,
+      4, 4, 0, 1, 2, 0x77 };
+  final static int[] valACchrominance = { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,
+      0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,
+      0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,
+      0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,
+      0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,
+      0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,
+      0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,
+      0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,
+      0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,
+      0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+      0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,
+      0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+      0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+      0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };
+
+  /*
+   * jpegNaturalOrder[i] is the natural-order position of the i'th element
+   * of zigzag order.
+   */
+  final static int[] jpegNaturalOrder = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32,
+      25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14,
+      21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+      58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, };
+
+  Huffman(int width, int height) {
+    initHuf();
+    imageWidth = width;
+    imageHeight = height;
+
+  }
+
+  /**
+   * HuffmanBlockEncoder run length encodes and Huffman encodes the quantized
+   * data.
+   * 
+   * @param out
+   * @param zigzag
+   * @param prec
+   * @param dcCode
+   * @param acCode
+   **/
+
+  void HuffmanBlockEncoder(OC out, int zigzag[], int prec,
+                           int dcCode, int acCode) {
+    int temp, temp2, nbits, k, r, i;
+
+    numOfDCTables = 2;
+    numOfACTables = 2;
+
+    int[][] matrixDC = dc_matrix[dcCode];
+    int[][] matrixAC = ac_matrix[acCode];
+
+    // The DC portion
+
+    temp = temp2 = zigzag[0] - prec;
+    if (temp < 0) {
+      temp = -temp;
+      temp2--;
+    }
+    nbits = 0;
+    while (temp != 0) {
+      nbits++;
+      temp >>= 1;
+    }
+    //        if (nbits > 11) nbits = 11;
+    bufferIt(out, matrixDC[nbits][0], matrixDC[nbits][1]);
+    // The arguments in bufferIt are code and size.
+    if (nbits != 0) {
+      bufferIt(out, temp2, nbits);
+    }
+
+    // The AC portion
+
+    r = 0;
+
+    for (k = 1; k < 64; k++) {
+      if ((temp = zigzag[jpegNaturalOrder[k]]) == 0) {
+        r++;
+      } else {
+        while (r > 15) {
+          bufferIt(out, matrixAC[0xF0][0], matrixAC[0xF0][1]);
+          r -= 16;
+        }
+        temp2 = temp;
+        if (temp < 0) {
+          temp = -temp;
+          temp2--;
+        }
+        nbits = 1;
+        while ((temp >>= 1) != 0) {
+          nbits++;
+        }
+        i = (r << 4) + nbits;
+        bufferIt(out, matrixAC[i][0], matrixAC[i][1]);
+        bufferIt(out, temp2, nbits);
+
+        r = 0;
+      }
+    }
+
+    if (r > 0) {
+      bufferIt(out, matrixAC[0][0], matrixAC[0][1]);
+    }
+
+  }
+
+  // Uses an integer long (32 bits) buffer to store the Huffman encoded bits
+  // and sends them to out by the byte.
+
+  void bufferIt(OC out, int code, int size) {
+    int putBuffer = code;
+    int putBits = bufferPutBits;
+
+    putBuffer &= (1 << size) - 1;
+    putBits += size;
+    putBuffer <<= 24 - putBits;
+    putBuffer |= bufferPutBuffer;
+
+    while (putBits >= 8) {
+      int c = ((putBuffer >> 16) & 0xFF);
+      out.writeByteAsInt(c);
+      if (c == 0xFF) {
+        out.writeByteAsInt(0);
+      }
+      putBuffer <<= 8;
+      putBits -= 8;
+    }
+    bufferPutBuffer = putBuffer;
+    bufferPutBits = putBits;
+
+  }
+
+  void flushBuffer(OC out) {
+    int putBuffer = bufferPutBuffer;
+    int putBits = bufferPutBits;
+    while (putBits >= 8) {
+      int c = ((putBuffer >> 16) & 0xFF);
+      out.writeByteAsInt(c);
+      if (c == 0xFF) {
+        out.writeByteAsInt(0);
+      }
+      putBuffer <<= 8;
+      putBits -= 8;
+    }
+    if (putBits > 0) {
+      int c = ((putBuffer >> 16) & 0xFF);
+      out.writeByteAsInt(c);
+    }
+  }
+
+  /*
+   * Initialisation of the Huffman codes for Luminance and Chrominance.
+   * This code results in the same tables created in the IJG Jpeg-6a
+   * library.
+   */
+
+  private void initHuf() {
+    dc_matrix0 = new int[12][2];
+    dc_matrix1 = new int[12][2];
+    ac_matrix0 = new int[255][2];
+    ac_matrix1 = new int[255][2];
+    dc_matrix = AU.newInt3(2, -1);
+    ac_matrix = AU.newInt3(2, -1);
+    int p, l, i, lastp, si, code;
+    int[] huffsize = new int[257];
+    int[] huffcode = new int[257];
+
+    /*
+     * init of the DC values for the chrominance
+     * [][0] is the code   [][1] is the number of bit
+     */
+
+    p = 0;
+    for (l = 1; l <= 16; l++) {
+      //      for (i = 1; i <= bitsDCchrominance[l]; i++)
+      for (i = bitsDCchrominance[l]; --i >= 0;) {
+        huffsize[p++] = l; //that's an "el", not a "one"
+      }
+    }
+    huffsize[p] = 0;
+    lastp = p;
+
+    code = 0;
+    si = huffsize[0];
+    p = 0;
+    while (huffsize[p] != 0) {
+      while (huffsize[p] == si) {
+        huffcode[p++] = code;
+        code++;
+      }
+      code <<= 1;
+      si++;
+    }
+
+    for (p = 0; p < lastp; p++) {
+      dc_matrix1[valDCchrominance[p]][0] = huffcode[p];
+      dc_matrix1[valDCchrominance[p]][1] = huffsize[p];
+    }
+
+    /*
+     * Init of the AC huffman code for the chrominance
+     * matrix [][][0] is the code & matrix[][][1] is the number of bit needed
+     */
+
+    p = 0;
+    for (l = 1; l <= 16; l++) {
+      for (i = bitsACchrominance[l]; --i >= 0;)
+      //      for (i = 1; i <= bitsACchrominance[l]; i++)
+      {
+        huffsize[p++] = l;
+      }
+    }
+    huffsize[p] = 0;
+    lastp = p;
+
+    code = 0;
+    si = huffsize[0];
+    p = 0;
+    while (huffsize[p] != 0) {
+      while (huffsize[p] == si) {
+        huffcode[p++] = code;
+        code++;
+      }
+      code <<= 1;
+      si++;
+    }
+
+    for (p = 0; p < lastp; p++) {
+      ac_matrix1[valACchrominance[p]][0] = huffcode[p];
+      ac_matrix1[valACchrominance[p]][1] = huffsize[p];
+    }
+
+    /*
+     * init of the DC values for the luminance
+     * [][0] is the code   [][1] is the number of bit
+     */
+    p = 0;
+    for (l = 1; l <= 16; l++) {
+      //      for (i = 1; i <= bitsDCluminance[l]; i++)
+      for (i = bitsDCluminance[l]; --i >= 0;) {
+        huffsize[p++] = l;
+      }
+    }
+    huffsize[p] = 0;
+    lastp = p;
+
+    code = 0;
+    si = huffsize[0];
+    p = 0;
+    while (huffsize[p] != 0) {
+      while (huffsize[p] == si) {
+        huffcode[p++] = code;
+        code++;
+      }
+      code <<= 1;
+      si++;
+    }
+
+    for (p = 0; p < lastp; p++) {
+      dc_matrix0[valDCluminance[p]][0] = huffcode[p];
+      dc_matrix0[valDCluminance[p]][1] = huffsize[p];
+    }
+
+    /*
+     * Init of the AC huffman code for luminance
+     * matrix [][][0] is the code & matrix[][][1] is the number of bit
+     */
+
+    p = 0;
+    for (l = 1; l <= 16; l++) {
+      //      for (i = 1; i <= bitsACluminance[l]; i++)
+      for (i = bitsACluminance[l]; --i >= 0;) {
+        huffsize[p++] = l;
+      }
+    }
+    huffsize[p] = 0;
+    lastp = p;
+
+    code = 0;
+    si = huffsize[0];
+    p = 0;
+    while (huffsize[p] != 0) {
+      while (huffsize[p] == si) {
+        huffcode[p++] = code;
+        code++;
+      }
+      code <<= 1;
+      si++;
+    }
+    for (int q = 0; q < lastp; q++) {
+      ac_matrix0[valACluminance[q]][0] = huffcode[q];
+      ac_matrix0[valACluminance[q]][1] = huffsize[q];
+    }
+
+    dc_matrix[0] = dc_matrix0;
+    dc_matrix[1] = dc_matrix1;
+    ac_matrix[0] = ac_matrix0;
+    ac_matrix[1] = ac_matrix1;
+  }
+
+}
+
+/*
+ * JpegInfo - Given an image, sets default information about it and divides
+ * it into its constituant components, downsizing those that need to be.
+ */
+
+class JpegObj {
+  String comment;
+  int imageHeight;
+  int imageWidth;
+  int blockWidth[];
+  int blockHeight[];
+
+  int precision = 8;
+  int numberOfComponents = 3;
+  float[][][] components;
+  int[] compID = { 1, 2, 3 };
+  int[] hsampFactor = { 1, 1, 1 };
+  int[] vsampFactor = { 1, 1, 1 };
+  int[] qtableNumber = { 0, 1, 1 };
+  int[] dctableNumber = { 0, 1, 1 };
+  int[] actableNumber = { 0, 1, 1 };
+  private boolean[] lastColumnIsDummy = { false, false, false };
+  private boolean[] lastRowIsDummy = { false, false, false };
+  int ss = 0;
+  int se = 63;
+  int ah = 0;
+  int al = 0;
+  private int compWidth[];
+  private int compHeight[];
+  private int maxHsampFactor;
+  private int maxVsampFactor;
+
+  public JpegObj() {
+    components = AU.newFloat3(numberOfComponents, -1);
+    compWidth = new int[numberOfComponents];
+    compHeight = new int[numberOfComponents];
+    blockWidth = new int[numberOfComponents];
+    blockHeight = new int[numberOfComponents];
+  }
+
+  /*
+   * This method creates and fills three arrays, Y, Cb, and Cr using the
+   * input image.
+   */
+
+  void getYCCArray(int[] pixels) {
+    // In order to minimize the chance that grabPixels will throw an exception
+    // it may be necessary to grab some pixels every few scanlines and process
+    // those before going for more.  The time expense may be prohibitive.
+    // However, for a situation where memory overhead is a concern, this may be
+    // the only choice.
+    maxHsampFactor = 1;
+    maxVsampFactor = 1;
+    for (int y = 0; y < numberOfComponents; y++) {
+      maxHsampFactor = Math.max(maxHsampFactor, hsampFactor[y]);
+      maxVsampFactor = Math.max(maxVsampFactor, vsampFactor[y]);
+    }
+    for (int y = 0; y < numberOfComponents; y++) {
+      compWidth[y] = (((imageWidth % 8 != 0) ? ((int) Math
+          .ceil(imageWidth / 8.0)) * 8 : imageWidth) / maxHsampFactor)
+          * hsampFactor[y];
+      if (compWidth[y] != ((imageWidth / maxHsampFactor) * hsampFactor[y])) {
+        lastColumnIsDummy[y] = true;
+      }
+      // results in a multiple of 8 for compWidth
+      // this will make the rest of the program fail for the unlikely
+      // event that someone tries to compress an 16 x 16 pixel image
+      // which would of course be worse than pointless
+      blockWidth[y] = (int) Math.ceil(compWidth[y] / 8.0);
+      compHeight[y] = (((imageHeight % 8 != 0) ? ((int) Math
+          .ceil(imageHeight / 8.0)) * 8 : imageHeight) / maxVsampFactor)
+          * vsampFactor[y];
+      if (compHeight[y] != ((imageHeight / maxVsampFactor) * vsampFactor[y])) {
+        lastRowIsDummy[y] = true;
+      }
+      blockHeight[y] = (int) Math.ceil(compHeight[y] / 8.0);
+    }
+    float Y[][] = new float[compHeight[0]][compWidth[0]];
+    float Cr1[][] = new float[compHeight[0]][compWidth[0]];
+    float Cb1[][] = new float[compHeight[0]][compWidth[0]];
+    //float Cb2[][] = new float[compHeight[1]][compWidth[1]];
+    //float Cr2[][] = new float[compHeight[2]][compWidth[2]];
+    for (int pt = 0, y = 0; y < imageHeight; ++y) {
+      for (int x = 0; x < imageWidth; ++x, pt++) {
+        int p = pixels[pt];
+        int r = ((p >> 16) & 0xff);
+        int g = ((p >> 8) & 0xff);
+        int b = (p & 0xff);
+        // The following three lines are a more correct color conversion but
+        // the current conversion technique is sufficient and results in a higher
+        // compression rate.
+        // Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b ));
+        // Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 * (float)g + 0.5 * (float)b));
+        // Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g - 0.08131 * (float)b));
+        Y[y][x] = (float) ((0.299 * r + 0.587 * g + 0.114 * b));
+        Cb1[y][x] = 128 + (float) ((-0.16874 * r - 0.33126 * g + 0.5 * b));
+        Cr1[y][x] = 128 + (float) ((0.5 * r - 0.41869 * g - 0.08131 * b));
+      }
+    }
+
+    // Need a way to set the H and V sample factors before allowing downsampling.
+    // For now (04/04/98) downsampling must be hard coded.
+    // Until a better downsampler is implemented, this will not be done.
+    // Downsampling is currently supported.  The downsampling method here
+    // is a simple box filter.
+
+    components[0] = Y;
+    //        Cb2 = DownSample(Cb1, 1);
+    components[1] = Cb1;
+    //        Cr2 = DownSample(Cr1, 2);
+    components[2] = Cr1;
+  }
+  /*  
+    float[][] DownSample(float[][] C, int comp)
+    {
+      int inrow, incol;
+      int outrow, outcol;
+      float output[][];
+      int bias;
+      inrow = 0;
+      incol = 0;
+      int cHeight = compHeight[comp];
+      int cWidth = compWidth[comp];
+      output = new float[cHeight][cWidth];
+      
+      for (outrow = 0; outrow < cHeight; outrow++) {
+        bias = 1;
+        for (outcol = 0; outcol < cWidth; outcol++) {
+          output[outrow][outcol] = (C[inrow][incol++] + C[inrow++][incol--] 
+                   + C[inrow][incol++] + C[inrow--][incol++] + bias)/(float)4.0;
+          bias ^= 3;
+        }
+        inrow += 2;
+        incol = 0;
+      }
+      return output;
+    }
+  */
+
+}
diff --git a/src/javajs/img/PdfEncoder.java b/src/javajs/img/PdfEncoder.java
new file mode 100644 (file)
index 0000000..c75b032
--- /dev/null
@@ -0,0 +1,105 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2009-06-30 18:58:33 -0500 (Tue, 30 Jun 2009) $
+ * $Revision: 11158 $
+ *
+ * Copyright (C) 2002-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.img;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import javajs.export.PDFCreator;
+
+/**
+ * A relatively primitive PDF generator that just makes a document with an image
+ * in it.
+ * 
+ */
+public class PdfEncoder extends ImageEncoder {
+
+  private boolean isLandscape;
+  private PDFCreator pdf;
+  private String comment;
+
+  public PdfEncoder() {
+    // for Class.forName  
+  }
+
+  @Override
+  protected void setParams(Map<String, Object> params) {
+       isLandscape = (quality > 1);
+    comment = "Jmol " + (String) params.get("comment");
+  }
+
+  @Override
+  protected void generate() throws Exception {
+    pdf = new PDFCreator();
+    int pageWidth = 8 * 72;
+    int pageHeight = 11 * 72;
+    pdf.setOutputStream(out);
+    pdf.newDocument(pageWidth, pageHeight, isLandscape); // A4 or Letter
+    addMyImage(pageWidth, pageHeight);
+    Map<String, String> ht = new Hashtable<String, String>();
+    if (comment != null)
+      ht.put("Producer", comment);
+    ht.put("Author", "JMol");
+    ht.put("CreationDate", date);
+    pdf.addInfo(ht);
+    pdf.closeDocument();
+  }
+
+  
+  /**
+   * centered on the page
+   * 
+   * @param pageWidth
+   * @param pageHeight
+   */
+  private void addMyImage(int pageWidth, int pageHeight) {
+    pdf.addImageResource("img1", width, height, pixels, true);
+    int w = (isLandscape ? pageHeight : pageWidth);
+    int h = (isLandscape ? pageWidth : pageHeight);
+    int iw = width;
+    int ih = height;
+    if (iw > 0.9 * w) {
+      ih = (int) (ih * 0.9 * w / iw);
+      iw = (int) (w * 0.9);
+    }
+    if (ih > 0.9 * h) {
+      iw = (int) (iw * 0.9 * h / ih);
+      ih = (int) (h * 0.9);
+    }
+    int x = 0;
+    int y = 0;
+    int x1 = iw;
+    int y1 = ih;
+    if (w > iw) {
+      x = (w - iw) / 2;
+      x1 = iw + x;
+    }
+    if (h > ih) {
+      y = (h - ih) / 2;
+      y1 = ih + y;
+    }
+    pdf.drawImage("img1", x, y, x1, y1, 0, 0, width, height);
+  }
+
+}
diff --git a/src/javajs/img/PngEncoder.java b/src/javajs/img/PngEncoder.java
new file mode 100644 (file)
index 0000000..7c583a1
--- /dev/null
@@ -0,0 +1,453 @@
+/* $RCSfile$
+ * $Author: nicove $
+ * $Date: 2007-03-30 12:26:16 -0500 (Fri, 30 Mar 2007) $
+ * $Revision: 7275 $
+ *
+ * Copyright (C) 2002-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.img;
+
+import java.util.Map;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+
+
+/**
+ * 
+ * Modified by Bob Hanson hansonr@stolaf.edu to be a subclass of ImageEncoder
+ * and to use javajs.util.OutputChannel instead of just returning bytes. Also includes: 
+ *  
+ * -- JavaScript-compatible image processing
+ *  
+ * -- transparent background option
+ *  
+ * -- more efficient calculation of needs for pngBytes 
+ * 
+ * -- option to use pre-created PNGJ image data (3/19/14; Jmol 14.1.12)
+ * 
+ * -- PNGJ format:
+ * 
+ * // IHDR chunk 
+ * 
+ * // tEXt chunk "Jmol type - <PNG0|PNGJ><0000000pt>+<000000len>" 
+ * 
+ * // tEXt chunk "Software - Jmol <version>"
+ * 
+ * // tEXt chunk "Creation Time - <date>"
+ * 
+ * // tRNS chunk transparent color, if desired
+ *
+ * // IDAT chunk (image data)
+ * 
+ * // IEND chunk 
+ * 
+ * // [JMOL ZIP FILE APPENDIX]
+ * 
+ * Original Comment:
+ * 
+ * PngEncoder takes a Java Image object and creates a byte string which can be
+ * saved as a PNG file. The Image is presumed to use the DirectColorModel.
+ * 
+ * Thanks to Jay Denny at KeyPoint Software http://www.keypoint.com/ who let me
+ * develop this code on company time.
+ * 
+ * You may contact me with (probably very-much-needed) improvements, comments,
+ * and bug fixes at:
+ * 
+ * david@catcode.com
+ * 
+ * @author J. David Eisenberg
+ * @author http://catcode.com/pngencoder/
+ * @author Christian Ribeaud (christian.ribeaud@genedata.com)
+ * @author Bob Hanson (hansonr@stolaf.edu)
+ * 
+ * @version 1.4, 31 March 2000
+ */
+public class PngEncoder extends CRCEncoder {
+
+  /** Constants for filters */
+  public static final int FILTER_NONE = 0;
+  public static final int FILTER_SUB = 1;
+  public static final int FILTER_UP = 2;
+  public static final int FILTER_LAST = 2;
+  
+  private static final int PT_FIRST_TAG = 37;
+
+  private boolean encodeAlpha;
+  private int filter = FILTER_NONE;
+  private int bytesPerPixel;
+  private int compressionLevel;
+  private String type;
+  private Integer transparentColor;
+
+  private byte[] appData;
+  private String appPrefix;
+  private String comment;
+  private byte[] bytes;
+
+  
+  public PngEncoder() {
+    super();
+  }
+
+  @Override
+  protected void setParams(Map<String, Object> params) {
+    if (quality < 0)
+      quality = (params.containsKey("qualityPNG") ? ((Integer) params
+          .get("qualityPNG")).intValue() : 2);
+    if (quality > 9)
+      quality = 9;
+    encodeAlpha = false;
+    filter = FILTER_NONE;
+    compressionLevel = quality;
+    transparentColor = (Integer) params.get("transparentColor");
+    comment = (String) params.get("comment");
+    type = (params.get("type") + "0000").substring(0, 4);
+    bytes = (byte[]) params.get("pngImgData");
+    appData = (byte[]) params.get("pngAppData");
+    appPrefix = (String) params.get("pngAppPrefix");
+  }
+
+  
+
+  @Override
+  protected void generate() throws IOException {
+    if (bytes == null) {
+      if (!pngEncode()) {
+        out.cancel();
+        return;
+      }
+      bytes = getBytes();
+    } else {
+      dataLen = bytes.length;
+    }
+    int len = dataLen;
+    if (appData != null) {
+      setJmolTypeText(appPrefix, bytes, len, appData.length,
+          type);
+      out.write(bytes, 0, len);
+      len = (bytes = appData).length;
+    }
+    out.write(bytes, 0, len);
+  }
+
+
+  /**
+   * Creates an array of bytes that is the PNG equivalent of the current image,
+   * specifying whether to encode alpha or not.
+   * 
+   * @return        true if successful
+   * 
+   */
+  private boolean pngEncode() {
+
+    byte[] pngIdBytes = { -119, 80, 78, 71, 13, 10, 26, 10 };
+
+    writeBytes(pngIdBytes);
+    //hdrPos = bytePos;
+    writeHeader();
+    writeText(getApplicationText(appPrefix, type, 0, 0));
+
+    writeText("Software\0Jmol " + comment);
+    writeText("Creation Time\0" + date);
+
+    if (!encodeAlpha && transparentColor != null)
+      writeTransparentColor(transparentColor.intValue());
+    //dataPos = bytePos;
+    return writeImageData();
+  }
+
+  /**
+   * Fill in the Jmol type text area with number of bytes of PNG data and number
+   * of bytes of Jmol state data and fix checksum.
+   * 
+   * If we do not do this, then the checksum will be wrong, and Jmol and some
+   * other programs may not be able to read the PNG image.
+   * 
+   * This was corrected for Jmol 12.3.30. Between 12.3.7 and 12.3.29, PNG files
+   * created by Jmol have incorrect checksums.
+   * 
+   * @param prefix 
+   * 
+   * @param b
+   * @param nPNG
+   * @param nState
+   * @param type
+   */
+  private static void setJmolTypeText(String prefix, byte[] b, int nPNG, int nState, String type) {
+    String s = "tEXt" + getApplicationText(prefix, type, nPNG, nState);
+    CRCEncoder encoder = new PngEncoder();
+    byte[] test = s.substring(0, 4 + prefix.length()).getBytes();
+    for (int i = test.length; -- i >= 0;) 
+      if (b[i + PT_FIRST_TAG] != test[i]) {
+        System.out.println("image is not of the right form; appending data, but not adding tEXt tag.");
+        return;
+      }
+    encoder.setData(b, PT_FIRST_TAG);
+    encoder.writeString(s);
+    encoder.writeCRC();
+  }
+
+  private static String getApplicationText(String prefix, String type, int nPNG, int nState) {
+    String sPNG = "000000000" + nPNG;
+    sPNG = sPNG.substring(sPNG.length() - 9);
+    String sState = "000000000" + nState;
+    sState = sState.substring(sState.length() - 9);
+    return prefix + "\0" + type + (type.equals("PNG") ? "0" : "") + sPNG + "+"
+        + sState;
+  }
+
+  //  /**
+  //   * Set the filter to use
+  //   *
+  //   * @param whichFilter from constant list
+  //   */
+  //  public void setFilter(int whichFilter) {
+  //    this.filter = (whichFilter <= FILTER_LAST ? whichFilter : FILTER_NONE);
+  //  }
+
+  //  /**
+  //   * Retrieve filtering scheme
+  //   *
+  //   * @return int (see constant list)
+  //   */
+  //  public int getFilter() {
+  //    return filter;
+  //  }
+
+  //  /**
+  //   * Set the compression level to use
+  //   *
+  //   * @param level 0 through 9
+  //   */
+  //  public void setCompressionLevel(int level) {
+  //    if ((level >= 0) && (level <= 9)) {
+  //      this.compressionLevel = level;
+  //    }
+  //  }
+
+  //  /**
+  //   * Retrieve compression level
+  //   *
+  //   * @return int in range 0-9
+  //   */
+  //  public int getCompressionLevel() {
+  //    return compressionLevel;
+  //  }
+
+  /**
+   * Write a PNG "IHDR" chunk into the pngBytes array.
+   */
+  private void writeHeader() {
+
+    writeInt4(13);
+    startPos = bytePos;
+    writeString("IHDR");
+    writeInt4(width);
+    writeInt4(height);
+    writeByte(8); // bit depth
+    writeByte(encodeAlpha ? 6 : 2); // color type or direct model
+    writeByte(0); // compression method
+    writeByte(0); // filter method
+    writeByte(0); // no interlace
+    writeCRC();
+  }
+
+  private void writeText(String msg) {
+    writeInt4(msg.length());
+    startPos = bytePos;
+    writeString("tEXt" + msg);
+    writeCRC();
+  }
+
+  /**
+   * Write a PNG "tRNS" chunk into the pngBytes array.
+   * 
+   * @param icolor
+   */
+  private void writeTransparentColor(int icolor) {
+
+    writeInt4(6);
+    startPos = bytePos;
+    writeString("tRNS");
+    writeInt2((icolor >> 16) & 0xFF);
+    writeInt2((icolor >> 8) & 0xFF);
+    writeInt2(icolor & 0xFF);
+    writeCRC();
+  }
+
+  private byte[] scanLines; // the scan lines to be compressed
+  private int byteWidth; // width * bytesPerPixel
+
+  //private int hdrPos, dataPos, endPos;
+  //private byte[] priorRow;
+  //private byte[] leftBytes;
+
+
+  /**
+   * Write the image data into the pngBytes array. This will write one or more
+   * PNG "IDAT" chunks. In order to conserve memory, this method grabs as many
+   * rows as will fit into 32K bytes, or the whole image; whichever is less.
+   * 
+   * 
+   * @return true if no errors; false if error grabbing pixels
+   */
+  private boolean writeImageData() {
+
+    bytesPerPixel = (encodeAlpha ? 4 : 3);
+    byteWidth = width * bytesPerPixel;
+
+    int scanWidth = byteWidth + 1; // the added 1 is for the filter byte
+
+    //boolean doFilter = (filter != FILTER_NONE);
+
+    int rowsLeft = height; // number of rows remaining to write
+    //int startRow = 0; // starting row to process this time through
+    int nRows; // how many rows to grab at a time
+
+    int scanPos; // where we are in the scan lines
+
+    Deflater deflater = new Deflater(compressionLevel);
+    ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
+
+    DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes,
+        deflater);
+
+    int pt = 0; // overall image byte pointer
+    
+    // Jmol note: The entire image has been stored in pixels[] already
+    
+    try {
+      while (rowsLeft > 0) {
+        nRows = Math.max(1, Math.min(32767 / scanWidth, rowsLeft));
+        scanLines = new byte[scanWidth * nRows];
+        //        if (doFilter)
+        //          switch (filter) {
+        //          case FILTER_SUB:
+        //            leftBytes = new byte[16];
+        //            break;
+        //          case FILTER_UP:
+        //            priorRow = new byte[scanWidth - 1];
+        //            break;
+        //          }
+        int nPixels = width * nRows;
+        scanPos = 0;
+        //startPos = 1;
+        for (int i = 0; i < nPixels; i++, pt++) {
+          if (i % width == 0) {
+            scanLines[scanPos++] = (byte) filter;
+            //startPos = scanPos;
+          }
+          scanLines[scanPos++] = (byte) ((pixels[pt] >> 16) & 0xff);
+          scanLines[scanPos++] = (byte) ((pixels[pt] >> 8) & 0xff);
+          scanLines[scanPos++] = (byte) ((pixels[pt]) & 0xff);
+          if (encodeAlpha) {
+            scanLines[scanPos++] = (byte) ((pixels[pt] >> 24) & 0xff);
+          }
+          //          if (doFilter && i % width == width - 1) {
+          //            switch (filter) {
+          //            case FILTER_SUB:
+          //              filterSub();
+          //              break;
+          //            case FILTER_UP:
+          //              filterUp();
+          //              break;
+          //            }
+          //          }
+        }
+
+        /*
+         * Write these lines to the output area
+         */
+        compBytes.write(scanLines, 0, scanPos);
+
+        //startRow += nRows;
+        rowsLeft -= nRows;
+      }
+      compBytes.close();
+
+      /*
+       * Write the compressed bytes
+       */
+      byte[] compressedLines = outBytes.toByteArray();
+      writeInt4(compressedLines.length);
+      startPos = bytePos;
+      writeString("IDAT");
+      writeBytes(compressedLines);
+      writeCRC();
+      writeEnd();
+      deflater.finish();
+      return true;
+    } catch (IOException e) {
+      System.err.println(e.toString());
+      return false;
+    }
+  }
+
+  /**
+   * Write a PNG "IEND" chunk into the pngBytes array.
+   */
+  private void writeEnd() {
+    writeInt4(0);
+    startPos = bytePos;
+    writeString("IEND");
+    writeCRC();
+  }
+
+  ///**
+  //* Perform "sub" filtering on the given row.
+  //* Uses temporary array leftBytes to store the original values
+  //* of the previous pixels.  The array is 16 bytes long, which
+  //* will easily hold two-byte samples plus two-byte alpha.
+  //*
+  //*/
+  //private void filterSub() {
+  // int offset = bytesPerPixel;
+  // int actualStart = startPos + offset;
+  // int leftInsert = offset;
+  // int leftExtract = 0;
+  // //byte current_byte;
+  //
+  // for (int i = actualStart; i < startPos + byteWidth; i++) {
+  //   leftBytes[leftInsert] = scanLines[i];
+  //   scanLines[i] = (byte) ((scanLines[i] - leftBytes[leftExtract]) % 256);
+  //   leftInsert = (leftInsert + 1) % 0x0f;
+  //   leftExtract = (leftExtract + 1) % 0x0f;
+  // }
+  //}
+  //
+  ///**
+  //* Perform "up" filtering on the given row. Side effect: refills the prior row
+  //* with current row
+  //* 
+  //*/
+  //private void filterUp() {
+  // int nBytes = width * bytesPerPixel;
+  // for (int i = 0; i < nBytes; i++) {
+  //   int pt = startPos + i;
+  //   byte b = scanLines[pt];
+  //   scanLines[pt] = (byte) ((scanLines[pt] - priorRow[i]) % 256);
+  //   priorRow[i] = b;
+  // }
+  //}
+
+}
diff --git a/src/javajs/img/PpmEncoder.java b/src/javajs/img/PpmEncoder.java
new file mode 100644 (file)
index 0000000..4bdc980
--- /dev/null
@@ -0,0 +1,60 @@
+// PpmEncoder - write out an image as a PPM
+//
+// Copyright (C)1996,1998 by Jef Poskanzer <jef@mail.acme.com>. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// 1. Redistributions of source code must retain the above copyright
+//    notice, this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright
+//    notice, this list of conditions and the following disclaimer in the
+//    documentation and/or other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+// SUCH DAMAGE.
+//
+// Visit the ACME Labs Java page for up-to-date versions of this and other
+// fine Java utilities: http://www.acme.com/java/
+
+package javajs.img;
+
+import java.util.Map;
+
+
+/**
+ * see http://netpbm.sourceforge.net/doc/ppm.html
+ */
+public class PpmEncoder extends ImageEncoder {
+
+  @Override
+  protected void setParams(Map<String, Object> params) {
+    // no params
+  }
+
+  @Override
+  protected void generate() {
+    putString("P6\n");
+    putString(width + " " + height + "\n");
+    putString("255\n");
+    byte[] ppmPixels = new byte[width * 3];
+    for (int pt = 0, row = 0; row < height; ++row) {
+      for (int col = 0, j = 0; col < width; ++col, pt++) {
+        int p = pixels[pt];
+        ppmPixels[j++] = (byte) ((p >> 16) & 0xff);
+        ppmPixels[j++] = (byte) ((p >> 8) & 0xff);
+        ppmPixels[j++] = (byte) (p & 0xff);
+      }
+      out.write(ppmPixels, 0, ppmPixels.length);
+    }
+  }
+}
diff --git a/src/javajs/swing/AbstractButton.java b/src/javajs/swing/AbstractButton.java
new file mode 100644 (file)
index 0000000..3ea6ab9
--- /dev/null
@@ -0,0 +1,118 @@
+package javajs.swing;
+
+import javajs.awt.Component;
+
+import javajs.api.SC;
+
+public abstract class AbstractButton extends JComponent implements SC {
+
+  Object itemListener;
+  Object applet;
+  String htmlName;
+  boolean selected;
+  
+  private SC popupMenu;
+
+  private String icon;
+
+  protected AbstractButton(String type) {
+    super(type);
+    enabled = true;
+  }
+  
+  @Override
+  public void setSelected(boolean selected) {
+    this.selected = selected;
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setSelected(this);
+     * 
+     */
+    {
+    }
+  }
+
+  @Override
+  public boolean isSelected() {
+    return selected;
+  }
+  
+  @Override
+  public void addItemListener(Object listener) {
+    itemListener = listener;
+  }
+  
+  @Override
+  public Object getIcon() {
+    return icon;
+  }
+  
+  @Override
+  public void setIcon(Object icon) {
+    this.icon = (String) icon;
+  }
+
+  @Override
+  public void init(String text, Object icon, String actionCommand, SC popupMenu) {
+    this.text = text;
+    this.icon = (String) icon;
+    this.actionCommand = actionCommand;
+    this.popupMenu = popupMenu;
+    /**
+     * @j2sNative
+     * 
+     *  SwingController.initMenuItem(this);
+     *  
+     */
+    {
+    }
+  }
+  public SC getTopPopupMenu() {
+    // note that JMenu.getPopupMenu refers to ITSELF, not the main one)
+    return popupMenu;
+  }
+  
+  @Override
+  public void add(SC item) {
+    addComponent((Component) item);
+  }
+
+  @Override
+  public void insert(SC subMenu, int index) {
+    // JMenu, JPopupMenu only, but implemented here as well
+    // for simplicity
+    insertComponent((Component) subMenu, index);
+  }
+
+  @Override
+  public Object getPopupMenu() {
+    // JMenu only
+    return null;
+  }
+
+  protected String getMenuHTML() {
+    String label = (this.icon != null ? this.icon
+        : this.text != null ? this.text 
+         : null);
+    String s = (label == null ? "" : "<li><a>" + label + "</a>"
+      + htmlMenuOpener("ul"));
+    int n = getComponentCount();
+    if (n > 0)
+      for(int i = 0; i < n; i++)
+        s += getComponent(i).toHTML();
+    if (label != null)
+      s += "</ul></li>";
+    return s;
+  }
+
+  protected String htmlMenuOpener(String type) {
+    return "<" + type + " id=\"" + this.id + "\"" + (this.enabled ? "" : getHtmlDisabled()) + ">";
+  }
+
+  protected String getHtmlDisabled() {
+    return " disabled=\"disabled\"";
+  }  
+
+}
diff --git a/src/javajs/swing/AbstractTableModel.java b/src/javajs/swing/AbstractTableModel.java
new file mode 100644 (file)
index 0000000..a7c3540
--- /dev/null
@@ -0,0 +1,13 @@
+package javajs.swing;
+
+import javajs.util.BS;
+import javajs.util.SB;
+
+
+abstract public interface AbstractTableModel extends TableColumn {
+
+       TableColumn getColumn(int i);
+
+       void toHTML(SB sb, String id, BS bsSelectedRows);
+
+}
diff --git a/src/javajs/swing/ButtonGroup.java b/src/javajs/swing/ButtonGroup.java
new file mode 100644 (file)
index 0000000..e457616
--- /dev/null
@@ -0,0 +1,18 @@
+package javajs.swing;
+
+import javajs.api.SC;
+import javajs.awt.Component;
+
+public class ButtonGroup {
+  
+  private String id;
+  
+  public ButtonGroup() {
+    id = Component.newID("bg");
+  }
+  
+  public void add(SC item) {
+    ((AbstractButton) item).htmlName = this.id;
+  }
+
+}
diff --git a/src/javajs/swing/Cell.java b/src/javajs/swing/Cell.java
new file mode 100644 (file)
index 0000000..dd53025
--- /dev/null
@@ -0,0 +1,25 @@
+package javajs.swing;
+
+public class Cell {
+
+       private JComponent component;
+       private int colspan;
+       private int rowspan;
+       int textAlign;
+       private GridBagConstraints c;
+
+       public Cell(JComponent btn, GridBagConstraints c) {
+               this.component = btn;
+               colspan = c.gridwidth;
+               rowspan = c.gridheight;  // ignoring for now
+               this.c = c;
+       }
+
+       public String toHTML(String id) {
+               String style = c.getStyle(false); 
+               return "<td id='" + id +"' " + (colspan < 2 ? "" : "colspan='" + colspan + "' ") 
+               + style + "><span " + c.getStyle(true) + ">" + component.toHTML() + "</span></td>";
+       }
+
+
+}
diff --git a/src/javajs/swing/ColumnSelectionModel.java b/src/javajs/swing/ColumnSelectionModel.java
new file mode 100644 (file)
index 0000000..ee3738c
--- /dev/null
@@ -0,0 +1,9 @@
+package javajs.swing;
+
+public interface ColumnSelectionModel {
+
+       ListSelectionModel getSelectionModel();
+
+       TableColumn getColumn(int i);
+
+}
diff --git a/src/javajs/swing/Document.java b/src/javajs/swing/Document.java
new file mode 100644 (file)
index 0000000..5abfa9b
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+public interface Document {
+
+       void insertString(int i, String text, Object object);
+
+}
diff --git a/src/javajs/swing/FlowLayout.java b/src/javajs/swing/FlowLayout.java
new file mode 100644 (file)
index 0000000..301d9a8
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+import javajs.awt.LayoutManager;
+
+public class FlowLayout extends LayoutManager {
+
+}
diff --git a/src/javajs/swing/Grid.java b/src/javajs/swing/Grid.java
new file mode 100644 (file)
index 0000000..516110f
--- /dev/null
@@ -0,0 +1,54 @@
+package javajs.swing;
+
+import javajs.util.AU;
+import javajs.util.SB;
+
+
+public class Grid {
+
+       private int nrows;
+       private int ncols;
+
+       private Cell[][] grid;
+       private String renderer;
+       
+
+       Grid(int rows, int cols) {
+               grid = new Cell[0][0];
+       }
+
+       public void add(JComponent btn, GridBagConstraints c) {
+               if (c.gridx >= ncols) {
+                       ncols = c.gridx + 1;
+                       for (int i = 0; i < nrows; i++) {
+                               grid[i] = (Cell[]) AU.ensureLength(grid[i], ncols * 2);
+                       }
+               }
+               if (c.gridy >= nrows) {
+                       Cell[][] g = new Cell[c.gridy * 2 + 1][];
+                       for (int i = 0; i < nrows; i++)
+                               g[i] = grid[i];
+                       for (int i = g.length; --i >= nrows;)
+                               g[i] = new Cell[ncols * 2 + 1];
+                       grid = g;
+                       nrows = c.gridy + 1;
+               }
+               grid[c.gridy][c.gridx] = new Cell(btn, c);
+       }
+
+       public String toHTML(String id) {
+               SB sb = new SB();
+               id += "_grid";
+               sb.append("\n<table id='" + id + "' class='Grid' style='width:100%;height:100%'><tr><td style='height:20%;width:20%'></td></tr>");              
+               for (int i = 0; i < nrows; i++) {
+                       String rowid = id + "_" + i;
+                       sb.append("\n<tr id='" + rowid + "'><td></td>");
+                       for (int j = 0; j < ncols; j++)
+                               if (grid[i][j] != null)
+                                       sb.append(grid[i][j].toHTML(rowid + "_" + j));
+                       sb.append("</tr>");
+               }
+               sb.append("\n<tr><td style='height:20%;width:20%'></td></tr></table>\n");
+               return sb.toString();
+       }
+}
diff --git a/src/javajs/swing/GridBagConstraints.java b/src/javajs/swing/GridBagConstraints.java
new file mode 100644 (file)
index 0000000..578edc3
--- /dev/null
@@ -0,0 +1,47 @@
+package javajs.swing;
+
+public class GridBagConstraints {
+
+       public static final int NONE = 0;
+       public static final int CENTER = 10;
+       public static final int WEST = 17;
+       public static final int EAST = 13;
+
+       public int gridx;
+       public int gridy;
+       public int gridwidth;
+       public int gridheight;
+       double weightx;
+       double weighty;
+       public int anchor;
+       public int fill;
+       Insets insets;
+       public int ipadx;
+       public int ipady;
+       
+       public GridBagConstraints(int gridx, int gridy, int gridwidth,
+                       int gridheight, double weightx, double weighty, int anchor, int fill,
+                       Insets insets, int ipadx, int ipady) {
+               this.gridx = gridx;
+               this.gridy = gridy;
+               this.gridwidth = gridwidth;
+               this.gridheight = gridheight;
+               this.weightx = weightx;
+               this.weighty = weighty;
+               this.anchor = anchor;
+               this.fill = fill;
+               if (insets == null)
+                       insets = new Insets(0, 0, 0, 0);
+               this.insets = insets;
+               this.ipadx = ipadx;
+               this.ipady = ipady;
+       }
+
+       String getStyle(boolean margins) {
+               return "style='" + (margins ? 
+                               "margin:" + insets.top + "px " + (ipady + insets.right) + "px "
+                               + insets.bottom + "px " + (ipadx + insets.left) + "px;"
+                               : "text-align:" + (anchor == EAST ? "right" : anchor == WEST? "left" : "center")) + "'";
+       }
+
+}
diff --git a/src/javajs/swing/GridBagLayout.java b/src/javajs/swing/GridBagLayout.java
new file mode 100644 (file)
index 0000000..35b459a
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+import javajs.awt.LayoutManager;
+
+public class GridBagLayout extends LayoutManager {
+
+}
diff --git a/src/javajs/swing/Insets.java b/src/javajs/swing/Insets.java
new file mode 100644 (file)
index 0000000..1ebed19
--- /dev/null
@@ -0,0 +1,14 @@
+package javajs.swing;
+
+public class Insets {
+
+       int top, left, bottom, right;
+       
+       public Insets(int top, int left, int bottom, int right) {
+               this.top = top;
+               this.left = left;
+               this.bottom = bottom;
+               this.right = right;
+       }
+
+}
diff --git a/src/javajs/swing/JButton.java b/src/javajs/swing/JButton.java
new file mode 100644 (file)
index 0000000..77118b7
--- /dev/null
@@ -0,0 +1,16 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+public class JButton extends AbstractButton {
+
+  public JButton() {
+    super("btnJB");
+  }
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("<input type=button id='" + id + "' class='JButton' style='" + getCSSstyle(80, 0) + "' onclick='SwingController.click(this)' value='"+ text + "'/>");
+               return sb.toString();
+       }
+}
diff --git a/src/javajs/swing/JCheckBox.java b/src/javajs/swing/JCheckBox.java
new file mode 100644 (file)
index 0000000..4cd97e7
--- /dev/null
@@ -0,0 +1,19 @@
+package javajs.swing;
+
+public class JCheckBox extends AbstractButton {
+
+       public JCheckBox() {
+               super("chkJCB");
+       }
+
+  @Override
+  public String toHTML() {
+    String s = "<label><input type=checkbox id='" + id
+        + "' class='JCheckBox' style='" + getCSSstyle(0, 0) + "' "
+        + (selected ? "checked='checked' " : "")
+        + "onclick='SwingController.click(this)'>" + text + "</label>";
+    return s;
+  }
+
+
+}
diff --git a/src/javajs/swing/JCheckBoxMenuItem.java b/src/javajs/swing/JCheckBoxMenuItem.java
new file mode 100644 (file)
index 0000000..4f0fecb
--- /dev/null
@@ -0,0 +1,10 @@
+package javajs.swing;
+
+public class JCheckBoxMenuItem extends JMenuItem {
+
+
+  public JCheckBoxMenuItem() {
+    super("chk", TYPE_CHECKBOX);
+  }
+
+}
diff --git a/src/javajs/swing/JComboBox.java b/src/javajs/swing/JComboBox.java
new file mode 100644 (file)
index 0000000..73c6db5
--- /dev/null
@@ -0,0 +1,47 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+public class JComboBox<T>  extends AbstractButton {
+
+       private String[] info;
+       private int selectedIndex;
+
+       public JComboBox(String[] info){
+               super("cmbJCB");
+               this.info = info;
+       }
+
+       public void setSelectedIndex(int i) {
+               selectedIndex = i;
+               /**
+                * @j2sNative
+                * 
+                * SwingController.setSelectedIndex(this);
+                * 
+                */
+               {
+               }
+       }
+
+       public int getSelectedIndex() {
+               return selectedIndex;
+       }
+
+       public Object getSelectedItem() {
+               return (selectedIndex < 0 ? null : info[selectedIndex]);
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("\n<select id='" + id + "' class='JComboBox' onchange='SwingController.click(this)'>\n");             
+               for (int i = 0; i < info.length; i++)
+                       sb.append("\n<option class='JComboBox_option'" + (i == selectedIndex ? "selected":"") + ">" + info[i] + "</option>");
+               sb.append("\n</select>\n");
+               return sb.toString();
+       }
+
+
+
+}
diff --git a/src/javajs/swing/JComponent.java b/src/javajs/swing/JComponent.java
new file mode 100644 (file)
index 0000000..2f17ba0
--- /dev/null
@@ -0,0 +1,45 @@
+package javajs.swing;
+
+import javajs.awt.Container;
+
+public abstract class JComponent extends Container {
+
+  protected boolean autoScrolls;
+  protected String actionCommand;
+  protected Object actionListener;
+
+  protected JComponent(String type) {
+    super(type);
+  }
+  
+  public void setAutoscrolls(boolean b) {
+    autoScrolls = b;
+  }
+  
+  /** 
+   * Note that it will be the job of the JavaScript on the 
+   * page to do with actionListener what is desired.
+   * 
+   * In javax.swing, these methods are in AbstractButton, but
+   * this is better for javajs.swing, reducing the duplication
+   * of JTextField's actionListener business. 
+   * 
+   * @param listener 
+   * 
+   */
+  public void addActionListener(Object listener) {
+    actionListener = listener;
+  }
+
+  public String getActionCommand() {
+    return actionCommand;
+  }
+
+  public void setActionCommand(String actionCommand) {
+    this.actionCommand = actionCommand;
+  }
+
+
+
+  
+}
diff --git a/src/javajs/swing/JComponentImp.java b/src/javajs/swing/JComponentImp.java
new file mode 100644 (file)
index 0000000..7693fc4
--- /dev/null
@@ -0,0 +1,18 @@
+package javajs.swing;
+
+/**
+ *  implementation of a JComponent
+ * 
+ */
+class JComponentImp extends JComponent {
+
+  protected JComponentImp(String type) {
+    super(type);
+  }
+
+  @Override
+  public String toHTML() {
+    return null;
+  }
+
+}
diff --git a/src/javajs/swing/JContentPane.java b/src/javajs/swing/JContentPane.java
new file mode 100644 (file)
index 0000000..b118fb1
--- /dev/null
@@ -0,0 +1,23 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+public class JContentPane extends JComponent {
+
+       public JContentPane() {
+               super("JCP");
+       }
+
+  @Override
+  public String toHTML() {
+    SB sb = new SB();
+    sb.append("\n<div id='" + id + "' class='JContentPane' style='"
+        + getCSSstyle(100, 100) + "'>\n");
+    if (list != null)
+      for (int i = 0; i < list.size(); i++)
+        sb.append(list.get(i).toHTML());
+    sb.append("\n</div>\n");
+    return sb.toString();
+  }
+
+}
diff --git a/src/javajs/swing/JDialog.java b/src/javajs/swing/JDialog.java
new file mode 100644 (file)
index 0000000..1720214
--- /dev/null
@@ -0,0 +1,126 @@
+package javajs.swing;
+
+import javajs.awt.Color;
+import javajs.awt.Container;
+import javajs.util.SB;
+
+
+/**
+ * There is really no need here for awt.Dialog.
+ * We would not use FileDialog in an HTML5 context anyway.
+ * 
+ */
+public class JDialog extends Container {
+
+  private static final int headerHeight = 25;
+  private int defaultWidth = 600;
+  private int defaultHeight = 300;
+  
+  private JContentPane contentPane;
+  private String title;
+  private String html;
+  private int zIndex = 9000;
+  
+  public void setZIndex(int zIndex) {
+    this.zIndex = zIndex;
+  }
+  
+  int[] loc;
+
+  public JDialog() {
+    super("JD");
+    add(contentPane = new JContentPane());
+    setBackground(Color.get3(210, 210, 240));
+    contentPane.setBackground(Color.get3(230, 230, 230));
+  }
+  
+  public void setLocation(int[] loc) {
+    this.loc = loc;
+  }
+  
+  public JContentPane getContentPane() {
+    return contentPane;
+  }
+
+  public void setTitle(String title) {
+    this.title = title;
+  }
+
+  public void pack() {
+    html = null;
+  }
+
+  public void validate() {
+    html = null;
+  }
+
+  @Override
+  public void setVisible(boolean tf) {
+    if (tf && html == null)
+      setDialog();
+    super.setVisible(tf);
+  }
+
+  public void dispose() {
+    {
+      
+      /**
+       * @j2sNative
+       * 
+       * SwingController.dispose(this);
+       * 
+       */
+      {
+      }
+      
+    }
+  }
+
+  @Override
+  public void repaint() {
+    setDialog();
+  }
+  
+  /**
+   * Set it into DOM, but don't show it yet.
+   * this.loc, this.manager, this.id, etc.
+   * 
+   */
+  private void setDialog() {
+    html = toHTML();
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setDialog(this);
+     * 
+     * 
+     */
+    {
+      System.out.println(html);
+    }
+  }
+  
+  @Override
+  public String toHTML() {
+    renderWidth = getSubcomponentWidth();
+    if (renderWidth == 0)
+      renderWidth = defaultWidth;
+    renderHeight = contentPane.getSubcomponentHeight();
+    if (renderHeight == 0)
+      renderHeight = defaultHeight;
+    int h = renderHeight - headerHeight;
+    SB sb = new SB();
+    sb.append("\n<div id='" + id + "' class='JDialog' style='" + getCSSstyle(0, 0) + "z-index:" + zIndex + ";position:relative;top:0px;left:0px;reize:both;'>\n");
+    sb.append("\n<div id='" + id + "_title' class='JDialogTitle' style='width:100%;height:25px;padding:5px 5px 5px 5px;height:"+headerHeight+"px'>"
+        +"<span style='text-align:center;'>" + title + "</span><span style='position:absolute;text-align:right;right:1px;'>"
+        + "<input type=button id='" + id + "_closer' onclick='SwingController.windowClosing(this)' value='x' /></span></div>\n");
+    sb.append("\n<div id='" + id + "_body' class='JDialogBody' style='width:100%;height:"+h+"px;"
+        +"position: relative;left:0px;top:0px'>\n");
+    sb.append(contentPane.toHTML());
+    sb.append("\n</div></div>\n");
+    return sb.toString();
+  }
+
+
+
+}
diff --git a/src/javajs/swing/JEditorPane.java b/src/javajs/swing/JEditorPane.java
new file mode 100644 (file)
index 0000000..c0e365b
--- /dev/null
@@ -0,0 +1,26 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+/**
+ * A simple implementation of a Swing JTextPane. 
+ * Operates as its own Document; no attributes
+ * 
+ * @author hansonr
+ *
+ */
+public class JEditorPane extends JComponent {
+
+       public JEditorPane() {
+               super("txtJEP");
+               text = "";
+       }
+       
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("<textarea type=text id='" + id + "' class='JEditorPane' style='" + getCSSstyle(98, 98) + "'>"+ text + "</textarea>");
+               return sb.toString();
+       }
+
+}
diff --git a/src/javajs/swing/JLabel.java b/src/javajs/swing/JLabel.java
new file mode 100644 (file)
index 0000000..70080f5
--- /dev/null
@@ -0,0 +1,22 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+public class JLabel extends JComponent {
+
+       public JLabel(String text) {
+               super("lblJL");
+               this.text = text;
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("<span id='" + id + "' class='JLabel' style='" + getCSSstyle(0, 0) + "'>");
+               sb.append(text);
+               sb.append("</span>");
+               return sb.toString();
+       }
+
+
+}
diff --git a/src/javajs/swing/JMenu.java b/src/javajs/swing/JMenu.java
new file mode 100644 (file)
index 0000000..57bfade
--- /dev/null
@@ -0,0 +1,28 @@
+package javajs.swing;
+
+import javajs.awt.Component;
+
+public class JMenu extends JMenuItem {
+
+  public JMenu() {
+    super("mnu",TYPE_MENU);
+  }
+
+  public int getItemCount() {
+    return getComponentCount();
+  }
+
+  public Component getItem(int i) {
+    return getComponent(i);
+  }
+
+  @Override
+  public Object getPopupMenu() {
+    return this;
+  }
+
+  @Override
+  public String toHTML() {
+    return getMenuHTML();
+  }
+}
diff --git a/src/javajs/swing/JMenuItem.java b/src/javajs/swing/JMenuItem.java
new file mode 100644 (file)
index 0000000..643da95
--- /dev/null
@@ -0,0 +1,46 @@
+package javajs.swing;
+
+public class JMenuItem extends AbstractButton {
+
+  public final int btnType;
+  
+  public static final int TYPE_SEPARATOR = 0;
+  public static final int TYPE_BUTTON = 1;
+  public static final int TYPE_CHECKBOX = 2;
+  public static final int TYPE_RADIO = 3;
+  public static final int TYPE_MENU = 4;
+
+
+  public JMenuItem(String text) {
+    super("btn");
+    setText(text);
+    btnType = (text == null ? 0 : 1);
+  }
+
+  public JMenuItem(String type, int i) {
+    super(type);
+    btnType = i;
+  }
+
+  @Override
+  public String toHTML() {
+    return htmlMenuOpener("li")
+        + (text == null ? "" : "<a>" + htmlLabel() + "</a>") + "</li>";
+  }
+
+  @Override
+  protected String getHtmlDisabled() {
+    return " class=\"ui-state-disabled\"";  
+  }
+
+  private String htmlLabel() {
+    return (btnType == TYPE_BUTTON ? text 
+        : "<label><input id=\"" + id + "-" + (btnType == TYPE_RADIO ? "r" : "c") 
+        + "b\" type=\""
+        + (btnType == TYPE_RADIO ? "radio\" name=\"" + htmlName : "checkbox")
+        + "\" " + (selected ? "checked" : "") + " />" 
+        + text + "</label>");
+  }
+
+
+}
diff --git a/src/javajs/swing/JPanel.java b/src/javajs/swing/JPanel.java
new file mode 100644 (file)
index 0000000..64f08a2
--- /dev/null
@@ -0,0 +1,67 @@
+package javajs.swing;
+
+import javajs.awt.BorderLayout;
+import javajs.awt.LayoutManager;
+import javajs.util.SB;
+
+public class JPanel extends JComponent {
+
+       //private LayoutManager layoutManager;
+
+       private Grid grid;
+
+       private int nElements;
+       private JComponent last;
+       
+       
+       /**
+        * @param manager  ignored. we just use the layout designations with a grid
+        */
+       public JPanel(LayoutManager manager) {
+               super("JP");
+               //this.layoutManager = manager;
+               grid = new Grid(10,10);
+       }
+
+       public void add(JComponent btn, Object c) {
+               last = (++nElements == 1 ? btn : null);
+               if (c instanceof String) {
+                       if (c.equals(BorderLayout.NORTH))
+                               c = new GridBagConstraints(0, 0, 3, 1, 0, 0, GridBagConstraints.CENTER,
+                                               0, null, 0, 0);
+                       else if (c.equals(BorderLayout.SOUTH))
+                               c = new GridBagConstraints(0, 2, 3, 1, 0, 0, GridBagConstraints.CENTER,
+                                               0, null, 0, 0);
+                       else if (c.equals(BorderLayout.EAST))
+                               c = new GridBagConstraints(2, 1, 1, 1, 0, 0, GridBagConstraints.EAST,
+                                               0, null, 0, 0);
+                       else if (c.equals(BorderLayout.WEST))
+                               c = new GridBagConstraints(0, 1, 1, 1, 0, 0, GridBagConstraints.WEST,
+                                               0, null, 0, 0);
+                       else
+                               c = new GridBagConstraints(1, 1, 1, 1, 0, 0, GridBagConstraints.CENTER,
+                                               0, null, 0, 0);
+               }
+               grid.add(btn, (GridBagConstraints) c);
+       }
+       
+       @Override
+       public String toHTML() {
+               if (last != null) {
+                       // only one element
+                       grid = new Grid(1, 1);
+                       grid.add(last, new GridBagConstraints(0, 0, 1, 1, 0, 0,
+                                       GridBagConstraints.CENTER, 0, null, 0, 0));
+                       last = null;
+               }
+               SB sb = new SB();
+               sb.append("\n<div id='" + id + "' class='JPanel' style='"
+                               + getCSSstyle(100, 100) + "'>\n");
+               sb.append("\n<span id='" + id + "_minimizer' style='width:" + minWidth
+                               + "px;height:" + minHeight + "px;'>");
+               sb.append(grid.toHTML(id));
+               sb.append("</span>");
+               sb.append("\n</div>\n");
+               return sb.toString();
+       }
+}
diff --git a/src/javajs/swing/JPopupMenu.java b/src/javajs/swing/JPopupMenu.java
new file mode 100644 (file)
index 0000000..47983c7
--- /dev/null
@@ -0,0 +1,70 @@
+package javajs.swing;
+
+import javajs.awt.Component;
+
+public class JPopupMenu extends AbstractButton {
+  
+  // note that in Java Swing JPopupMenu extends 
+  // JComponent, but here we extend AbstractButton
+  // so that it shares the SwingComponent interface
+  
+  boolean tainted = true;
+
+  static {
+    /**
+     * @j2sNative
+     * 
+     *            SwingController.setDraggable(javajs.swing.JPopupMenu); 
+     */
+    {
+    }
+  }
+  
+  public JPopupMenu(String name) {
+    super("mnu");
+    this.name = name;
+  }
+
+  public void setInvoker(Object applet) {
+    this.applet = applet;
+    /**
+     * @j2sNative
+     * 
+     * SwingController.setMenu(this);
+     * 
+     */
+    {}
+  }
+  
+  /**
+   * @param applet  
+   * @param x 
+   * @param y 
+   */
+  public void show(Component applet, int x, int y) {
+    /**
+     * @j2sNative
+     * 
+     * if (applet != null)
+     *   this.tainted = true;
+     * SwingController.showMenu(this, x, y);
+     * 
+     */
+    {}
+  }
+
+  public void disposeMenu() {
+    /**
+     * @j2sNative
+     * 
+     * SwingController.disposeMenu(this);
+     */
+    {}
+  }
+  
+  @Override
+  public String toHTML() {
+    return getMenuHTML();
+  }
+
+}
diff --git a/src/javajs/swing/JRadioButtonMenuItem.java b/src/javajs/swing/JRadioButtonMenuItem.java
new file mode 100644 (file)
index 0000000..7187725
--- /dev/null
@@ -0,0 +1,11 @@
+package javajs.swing;
+
+public class JRadioButtonMenuItem extends JMenuItem {
+
+  protected boolean isRadio = true;
+  
+  public JRadioButtonMenuItem() {
+    super("rad",TYPE_RADIO);
+  }
+
+}
diff --git a/src/javajs/swing/JScrollPane.java b/src/javajs/swing/JScrollPane.java
new file mode 100644 (file)
index 0000000..a7c1e27
--- /dev/null
@@ -0,0 +1,32 @@
+package javajs.swing;
+
+import javajs.awt.Component;
+import javajs.awt.Dimension;
+import javajs.util.SB;
+
+public class JScrollPane extends JComponent {
+
+       public JScrollPane(JComponent component) {
+               super("JScP");
+               add(component);
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("\n<div id='" + id + "' class='JScrollPane' style='" + getCSSstyle(98, 98) + "overflow:auto'>\n");
+               if (list != null) {
+                 Component c = list.get(0);
+                 sb.append(c.toHTML());
+               }
+               sb.append("\n</div>\n");
+               return sb.toString();
+       }
+       
+  @Override
+  public void setMinimumSize(Dimension dimension) {
+               // TODO Auto-generated method stub
+               
+       }
+
+}
diff --git a/src/javajs/swing/JSplitPane.java b/src/javajs/swing/JSplitPane.java
new file mode 100644 (file)
index 0000000..3662cf9
--- /dev/null
@@ -0,0 +1,88 @@
+package javajs.swing;
+
+import javajs.awt.Container;
+import javajs.util.SB;
+
+public class JSplitPane extends JComponent {
+
+       public static final int HORIZONTAL_SPLIT = 1;
+       boolean isH = true;
+       private int split = 1;
+       private Container right;
+       private Container left;
+
+       public JSplitPane(int split) {
+               super("JSpP");
+               this.split = split;
+               isH = (split == HORIZONTAL_SPLIT);
+       }
+       
+       public void setRightComponent(JComponent r) {
+               right = new JComponentImp(null);
+               right.add(r); 
+       }
+
+       public void setLeftComponent(JComponent l) {
+               left = new JComponentImp(null);
+               left.add(l);
+       }
+
+       @Override
+       public int getSubcomponentWidth() {
+               int w = this.width;
+               if (w == 0) {
+                       int wleft = left.getSubcomponentWidth();
+                       int wright = right.getSubcomponentWidth();
+                       if (wleft > 0 && wright > 0) {
+                               if (isH)
+                                       w = wleft + wright;
+                               else
+                                       w = Math.max(wleft, wright);
+                       }
+               }
+               return w;
+       }
+       
+       @Override
+       public int getSubcomponentHeight() {
+               int h = this.height;
+               if (h == 0) {
+                       int hleft = left.getSubcomponentHeight();
+                       int hright = right.getSubcomponentHeight();
+                       if (hleft > 0 && hright > 0) {
+                               if (isH)
+                                       h = Math.max(hleft, hright);
+                               else
+                                       h = hleft + hright;
+                       }
+               }
+               return h;
+       }
+       
+       @Override
+       public String toHTML() {
+               if (left == null || right == null)
+                       return "";
+               boolean isH = (split == HORIZONTAL_SPLIT);
+               if (width == 0)
+                 width = getSubcomponentWidth();
+               if (height == 0)
+                 height = getSubcomponentHeight();
+               SB sb = new SB();
+               sb.append("<div id='" + id + "' class='JSplitPane' style='" + getCSSstyle(100, 100) + "'>");
+               if (isH) 
+                       sb.append("<div id='" + id + "_left' style='width:50%;height:100%;position:absolute;top:0%;left:0%'>");
+               else
+                       sb.append("<div id='" + id + "_top' style='width:100%;height:50%;position:absolute;top:0%;left:0%'>");
+               sb.append(left.getComponents()[0].toHTML());
+               if (isH) 
+                       sb.append("</div><div id='" + id + "_right' style='width:50%;height:100%;position:absolute;top:0%;left:50%'>");
+               else
+                       sb.append("</div><div id='" + id + "_bottom' style='width:100%;height:50%;position:absolute;top:50%;left:0%'>");
+               sb.append(right.getComponents()[0].toHTML());
+               sb.append("</div></div>\n");
+               return sb.toString();
+       }
+
+
+}
diff --git a/src/javajs/swing/JTable.java b/src/javajs/swing/JTable.java
new file mode 100644 (file)
index 0000000..afa6c03
--- /dev/null
@@ -0,0 +1,83 @@
+package javajs.swing;
+
+import javajs.awt.Dimension;
+import javajs.util.BS;
+import javajs.util.SB;
+
+
+public class JTable extends JComponent implements ListSelectionModel, ColumnSelectionModel {
+
+       private AbstractTableModel tableModel;
+       private BS bsSelectedCells;
+       private BS bsSelectedRows;
+       
+       boolean rowSelectionAllowed;
+       boolean cellSelectionEnabled;
+  Object selectionListener;
+
+       public JTable(AbstractTableModel tableModel) {
+               super("JT");
+               this.tableModel = tableModel;
+               this.bsSelectedCells = new BS();
+               this.bsSelectedRows = new BS();
+       }
+
+       @Override
+  public ListSelectionModel getSelectionModel() {
+               return this;
+       }
+
+       public ColumnSelectionModel getColumnModel() {
+               return this;
+       }
+
+       public void setPreferredScrollableViewportSize(Dimension dimension) {
+               this.width = dimension.width;
+               this.height = dimension.height;
+       }
+
+       public void clearSelection() {
+               bsSelectedCells.clearAll();
+               bsSelectedRows.clearAll();
+       }
+
+       public void setRowSelectionAllowed(boolean b) {
+               rowSelectionAllowed = b;
+       }
+
+       public void setRowSelectionInterval(int i, int j) {
+               bsSelectedRows.clearAll();
+               bsSelectedRows.setBits(i, j);
+               bsSelectedCells.clearAll();
+       }
+
+       public void setCellSelectionEnabled(boolean enabled) {
+               cellSelectionEnabled = enabled;
+       }
+
+       /** 
+        * It will be the function of the JavaScript on the 
+        * page to do with selectionListener what is desired.
+        * 
+        * @param listener 
+        * 
+        */
+       @Override
+  public void addListSelectionListener(Object listener) {
+               selectionListener = listener;
+       }
+
+       @Override
+  public TableColumn getColumn(int i) {
+               return tableModel.getColumn(i);
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("\n<table id='" + id + "_table' class='JTable' >");
+               tableModel.toHTML(sb, id, bsSelectedRows);
+               sb.append("\n</table>\n");
+               return sb.toString();
+       }
+}
diff --git a/src/javajs/swing/JTextField.java b/src/javajs/swing/JTextField.java
new file mode 100644 (file)
index 0000000..069f646
--- /dev/null
@@ -0,0 +1,21 @@
+
+package javajs.swing;
+
+import javajs.util.SB;
+
+public class JTextField extends JComponent {
+
+       public JTextField(String value) {
+               super("txtJT");
+               text = value;
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("<input type=text id='" + id + "' class='JTextField' style='" + getCSSstyle(0, 0) + "' value='"+ text + "' onkeyup    =SwingController.click(this,event)      >");
+               return sb.toString();
+       }
+
+
+}
diff --git a/src/javajs/swing/JTextPane.java b/src/javajs/swing/JTextPane.java
new file mode 100644 (file)
index 0000000..fd3eeb8
--- /dev/null
@@ -0,0 +1,36 @@
+package javajs.swing;
+
+import javajs.util.SB;
+
+/**
+ * A simple implementation of a Swing JTextPane. 
+ * Operates as its own Document; no attributes
+ * 
+ * @author hansonr
+ *
+ */
+public class JTextPane extends JComponent implements Document {
+
+       public JTextPane() {
+               super("txtJTP");
+               text = "";
+       }
+       
+       public Document getDocument() {
+               return this;
+       }
+
+       @Override
+  public void insertString(int i, String s, Object object) {
+               i = Math.min(i, text.length());
+               text = text.substring(0, i) + s + text.substring(i);
+       }
+
+       @Override
+       public String toHTML() {
+               SB sb = new SB();
+               sb.append("<textarea type=text id='" + id + "' class='JTextPane' style='" + getCSSstyle(98, 98) + "'>"+ text + "</textarea>");
+               return sb.toString();
+       }
+
+}
diff --git a/src/javajs/swing/ListSelectionModel.java b/src/javajs/swing/ListSelectionModel.java
new file mode 100644 (file)
index 0000000..f1afd74
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+public interface ListSelectionModel {
+
+       void addListSelectionListener(Object listener);
+
+}
diff --git a/src/javajs/swing/SwingConstants.java b/src/javajs/swing/SwingConstants.java
new file mode 100644 (file)
index 0000000..7211cac
--- /dev/null
@@ -0,0 +1,9 @@
+package javajs.swing;
+
+public class SwingConstants {
+       
+       public static final int LEFT = 2;
+       public static final int CENTER = 0;
+       public static final int RIGHT = 4;
+
+}
diff --git a/src/javajs/swing/TableCellRenderer.java b/src/javajs/swing/TableCellRenderer.java
new file mode 100644 (file)
index 0000000..f8679f0
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+public interface TableCellRenderer {
+
+       String getCellStyle(int iRow, int iCol, GridBagConstraints c);
+
+}
diff --git a/src/javajs/swing/TableColumn.java b/src/javajs/swing/TableColumn.java
new file mode 100644 (file)
index 0000000..bd4e3a0
--- /dev/null
@@ -0,0 +1,7 @@
+package javajs.swing;
+
+public interface TableColumn {
+
+       void setPreferredWidth(int n);
+
+}
diff --git a/src/javajs/util/A4.java b/src/javajs/util/A4.java
new file mode 100644 (file)
index 0000000..f27c02e
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+import java.io.Serializable;
+
+import javajs.api.JSONEncodable;
+import javajs.util.T3;
+
+
+
+/**
+ * A 4 element axis angle represented by single precision floating point
+ * x,y,z,angle components. An axis angle is a rotation of angle (radians) about
+ * the vector (x,y,z).
+ * 
+ * @version specification 1.1, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public class A4 implements JSONEncodable, Serializable {
+
+  /*
+   * I assumed that the length of the axis vector is not significant.
+   */
+
+  /**
+   * The x coordinate.
+   */
+  public float x;
+
+  /**
+   * The y coordinate.
+   */
+  public float y;
+
+  /**
+   * The z coordinate.
+   */
+  public float z;
+
+  /**
+   * The angle.
+   */
+  public float angle;
+
+  /**
+   * Constructs and initializes a AxisAngle4f to (0,0,1,0).
+   */
+  public A4() {
+    z = 1.0f;
+  }
+
+  /**
+   * Constructs and initializes an AxisAngle4f from the specified x, y, z, and
+   * angle.
+   * 
+   * @param x
+   *        the x coordinate
+   * @param y
+   *        the y coordinate
+   * @param z
+   *        the z coordinate
+   * @param angle
+   *        the angle.
+   * @return a
+   */
+  public static A4 new4(float x, float y, float z, float angle) {
+    A4 a = new A4();
+    a.set4(x, y, z, angle);
+    return a;
+  }
+
+  /**
+   * Constructs and initializes a AxisAngle4f from the specified AxisAngle4f.
+   * 
+   * @param a1
+   *        the AxisAngle4f containing the initialization x y z angle data
+   * @return a
+   */
+  public static A4 newAA(A4 a1) {
+    A4 a = new A4();
+    a.set4(a1.x, a1.y, a1.z, a1.angle);
+    return a;
+  }
+
+  /**
+   * Constructs and initializes an AxisAngle4f from the specified axis and
+   * angle.
+   * 
+   * @param axis
+   *        the axis
+   * @param angle
+   *        the angle
+   * @return a
+   */
+  public static A4 newVA(V3 axis, float angle) {
+    A4 a = new A4();
+    a.setVA(axis, angle);
+    return a;
+  }
+
+  /**
+   * Sets the value of this AxisAngle4f to the specified axis and angle.
+   * 
+   * @param axis
+   *        the axis
+   * @param angle
+   *        the angle
+   * @since Java 3D 1.2
+   */
+  public final void setVA(V3 axis, float angle) {
+    x = axis.x;
+    y = axis.y;
+    z = axis.z;
+    this.angle = angle;
+  }
+
+  /**
+   * Sets the value of this axis angle to the specified x,y,z,angle.
+   * 
+   * @param x
+   *        the x coordinate
+   * @param y
+   *        the y coordinate
+   * @param z
+   *        the z coordinate
+   * @param angle
+   *        the angle
+   */
+  public final void set4(float x, float y, float z, float angle) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+    this.angle = angle;
+  }
+
+  /**
+   * Sets the value of this axis angle to the value of axis angle t1.
+   * 
+   * @param a
+   *        the axis angle to be copied
+   */
+  public final void setAA(A4 a) {
+    x = a.x;
+    y = a.y;
+    z = a.z;
+    angle = a.angle;
+  }
+
+
+  /**
+   * Sets the value of this axis-angle to the rotational component of the passed
+   * matrix.
+   * 
+   * @param m1
+   *        the matrix3f
+   */
+  public final void setM(M3 m1) {
+    setFromMat(m1.m00, m1.m01, m1.m02, m1.m10, m1.m11, m1.m12, m1.m20, m1.m21,
+        m1.m22);
+  }
+
+  // helper method
+  private void setFromMat(double m00, double m01, double m02, double m10,
+                          double m11, double m12, double m20, double m21,
+                          double m22) {
+    // assuming M is normalized.
+
+    double cos = (m00 + m11 + m22 - 1.0) * 0.5;
+    x = (float) (m21 - m12);
+    y = (float) (m02 - m20);
+    z = (float) (m10 - m01);
+    double sin = 0.5 * Math.sqrt(x * x + y * y + z * z);
+    if (sin == 0 && cos == 1) {
+      x = y = 0;
+      z = 1;
+      angle = 0;
+    } else {
+      angle = (float) Math.atan2(sin, cos);
+    }
+
+    // no need to normalize
+    // x /= n;
+    // y /= n;
+    // z /= n;
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different AxisAngle4f objects with identical data values (ie, returns true
+   * for equals(AxisAngle4f) ) will return the same hash number. Two vectors
+   * with different data members may return the same hash value, although this
+   * is not likely.
+   */
+  @Override
+  public int hashCode() {
+    return T3.floatToIntBits0(x) ^ T3.floatToIntBits0(y)
+        ^ T3.floatToIntBits0(z) ^ T3.floatToIntBits0(angle);
+  }
+
+  /**
+   * Returns true if the Object o is of type AxisAngle4f and all of the data
+   * members of o1 are equal to the corresponding data members in this
+   * AxisAngle4f.
+   * 
+   * @param o
+   *        the object with which the comparison is made.
+   * @return T/F
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof A4))
+      return false;
+    A4 a1 = (A4) o;
+    return x == a1.x && y == a1.y && z == a1.z && angle == a1.angle;
+  }
+
+  /**
+   * Returns a string that contains the values of this AxisAngle4f. The form is
+   * (x,y,z,angle).
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "(" + x + ", " + y + ", " + z + ", " + angle + ")";
+  }
+
+  @Override
+  public String toJSON() {
+    return "[" + x + "," + y + "," + z + "," + (float) (angle * 180.0 / Math.PI) + "]";
+  }
+}
diff --git a/src/javajs/util/AU.java b/src/javajs/util/AU.java
new file mode 100644 (file)
index 0000000..50c5912
--- /dev/null
@@ -0,0 +1,655 @@
+/* $RCSfile$
+ * $Author: egonw $
+ * $Date: 2005-11-10 09:52:44 -0600 (Thu, 10 Nov 2005) $
+ * $Revision: 4255 $
+ *
+ * Copyright (C) 2003-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+// 4/23/15 BH getComponentType fix
+
+import java.lang.reflect.Array;
+
+import java.util.Arrays;
+import java.util.Hashtable;
+import java.util.Map;
+
+
+final public class AU {
+
+  /**
+   * Very important that this not be used with Int32Array or Float32Array,
+   * because it is not initialized to all zeros in MSIE 9.
+   * 
+   * @param array
+   * @param minimumLength
+   * @return array
+   */
+  public static Object ensureLength(Object array, int minimumLength) {
+    if (array != null && getLength(array) >= minimumLength)
+      return array;
+    return arrayCopyObject(array, minimumLength);
+  }
+
+  public static String[] ensureLengthS(String[] array, int minimumLength) {
+    if (array != null && array.length >= minimumLength)
+      return array;
+    return arrayCopyS(array, minimumLength);
+  }
+
+  public static float[] ensureLengthA(float[] array, int minimumLength) {
+    if (array != null && array.length >= minimumLength)
+      return array;
+    return arrayCopyF(array, minimumLength);
+  }
+
+  public static int[] ensureLengthI(int[] array, int minimumLength) {
+    if (array != null && array.length >= minimumLength)
+      return array;
+    return arrayCopyI(array, minimumLength);
+  }
+
+  public static short[] ensureLengthShort(short[] array, int minimumLength) {
+    if (array != null && array.length >= minimumLength)
+      return array;
+    return arrayCopyShort(array, minimumLength);
+  }
+
+  public static byte[] ensureLengthByte(byte[] array, int minimumLength) {
+    if (array != null && array.length >= minimumLength)
+      return array;
+    return arrayCopyByte(array, minimumLength);
+  }
+
+  /**
+   * Very important that this not be used with Int32Array or Float32Array,
+   * because it is not initialized to all zeros in MSIE 9.
+   * 
+   * @param array
+   * @return array
+   */
+  public static Object doubleLength(Object array) {
+    return arrayCopyObject(array, (array == null ? 16 : 2 * getLength(array)));
+  }
+
+  public static String[] doubleLengthS(String[] array) {
+    return arrayCopyS(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static float[] doubleLengthF(float[] array) {
+    return arrayCopyF(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static int[] doubleLengthI(int[] array) {
+    return arrayCopyI(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static short[] doubleLengthShort(short[] array) {
+    return arrayCopyShort(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static byte[] doubleLengthByte(byte[] array) {
+    return arrayCopyByte(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static boolean[] doubleLengthBool(boolean[] array) {
+    return arrayCopyBool(array, (array == null ? 16 : 2 * array.length));
+  }
+
+  public static Object deleteElements(Object array, int firstElement,
+                                     int nElements) {
+    if (nElements == 0 || array == null)
+      return array;
+    int oldLength = getLength(array);
+    if (firstElement >= oldLength)
+      return array;
+    int n = oldLength - (firstElement + nElements);
+    if (n < 0)
+      n = 0;
+    Object t = newInstanceO(array, firstElement + n);
+    if (firstElement > 0)
+      System.arraycopy(array, 0, t, 0, firstElement);
+    if (n > 0)
+      System.arraycopy(array, firstElement + nElements, t, firstElement, n);
+    return t;
+  }
+
+  /**
+   * note -- cannot copy if array is null!
+   * 
+   * @param array
+   * @param newLength
+   * @return array
+   */
+  public static Object arrayCopyObject(Object array, int newLength) {
+    //System.out.println("ArrayUtil.copy " + newLength + " " + array + "  ");
+    if (array == null) {
+      return null; // We can't allocate since we don't know the type of array
+    }
+    int oldLength = getLength(array);
+    if (newLength == oldLength)
+      return array;
+    Object t = newInstanceO(array, newLength);
+    System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+        : newLength);
+    return t;
+
+  }
+
+  /**
+   * Very important that this not be used with Int32Array or Float32Array,
+   * because those need to be initialized to all zeros in MSIE 9, and
+   * MSIE 9 cannot distinguish Int32Array or Float32Array from Array.
+   * 
+   * @param array
+   * @param n
+   * @return array
+   */
+  private static Object newInstanceO(Object array, int n) {
+    /**
+     * @j2sNative
+     * 
+     * if (!array.getClass().getComponentType)
+     *          return new Array(n);
+     * 
+     */
+    {
+      return Array.newInstance(array.getClass().getComponentType(), n);
+    }
+  }
+
+  public static int getLength(Object array) {
+    /**
+     * @j2sNative
+     * 
+     *  return array.length
+     *   
+     */
+    {
+      return Array.getLength(array);
+    }
+  }
+
+  public static String[] arrayCopyS(String[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    String[] t = new String[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static int[][] arrayCopyII(int[][] array, int newLength) {
+    int[][] t = newInt2(newLength);
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static T3[] arrayCopyPt(T3[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    T3[] t = new T3[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static float[] arrayCopyF(float[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    float[] t = new float[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static int[] arrayCopyI(int[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    int[] t = new int[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  /**
+   * a specialized method that allows copying from a starting point either
+   * to the end or to the middle (color schemes, especially)
+   * @param array
+   * @param i0
+   * @param n
+   * @return array or null
+   */
+  public static int[] arrayCopyRangeI(int[] array, int i0, int n) {
+    if (array == null)
+      return null;
+    int oldLength = array.length;
+    if (n == -1) n = oldLength;
+    if (n == -2) n = oldLength / 2;
+    n = n - i0;
+    int[] t = new int[n];
+    System.arraycopy(array, i0, t, 0, n);
+    return t;
+  }
+
+  public static int[] arrayCopyRangeRevI(int[] array, int i0, int n) {
+    if (array == null)
+      return null;
+    int[] t = arrayCopyRangeI(array, i0, n);
+    if (n < 0)
+      n = array.length;
+    for (int i = n / 2; --i >= 0;)
+      swapInt(t, i, n - 1 - i);
+    return t;
+  }
+
+  public static short[] arrayCopyShort(short[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    short[] t = new short[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static byte[] arrayCopyByte(byte[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    byte[] t = new byte[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static boolean[] arrayCopyBool(boolean[] array, int newLength) {
+    if (newLength < 0)
+      newLength = array.length;
+    boolean[] t = new boolean[newLength];
+    if (array != null) {
+      int oldLength = array.length;
+      System.arraycopy(array, 0, t, 0, oldLength < newLength ? oldLength
+          : newLength);
+    }
+    return t;
+  }
+
+  public static void swapInt(int[] array, int indexA, int indexB) {
+    int t = array[indexA];
+    array[indexA] = array[indexB];
+    array[indexB] = t;
+  }
+
+  /*
+  public static void swap(short[] array, int indexA, int indexB) {
+    short t = array[indexA];
+    array[indexA] = array[indexB];
+    array[indexB] = t;
+  }
+
+  public static void swap(float[] array, int indexA, int indexB) {
+    float t = array[indexA];
+    array[indexA] = array[indexB];
+    array[indexB] = t;
+  }
+  */
+  
+  public static String dumpArray(String msg, float[][] A, int x1, int x2, int y1, int y2) {
+    String s = "dumpArray: " + msg + "\n";
+    for (int x = x1; x <= x2; x++)
+      s += "\t*" + x + "*";
+    for (int y = y2; y >= y1; y--) {
+      s += "\n*" + y + "*";
+      for (int x = x1; x <= x2; x++)
+        s += "\t" + (x < A.length && y < A[x].length ? A[x][y] : Float.NaN);
+    }
+    return s;
+  }
+
+  public static String dumpIntArray(int[] A, int n) {
+    String str = "";
+    for (int i = 0; i < n; i++)
+      str += " " + A[i];
+    return str;
+  }
+
+  public static String sortedItem(Lst<String> v, int n) {
+    if (v.size() == 0)
+      return null;
+    if (v.size() == 1)
+      return v.get(0);
+    String[] keys = v.toArray(new String[v.size()]);
+    Arrays.sort(keys);
+    return keys[n % keys.length];
+  }
+
+  /**
+   * Helper method for creating a List<Tx>[] without warnings.
+   * 
+   * @param <type> Type of objects in the list.
+   * @param size Array size.
+   * @return Array of List<type>
+   */
+  @SuppressWarnings("unchecked")
+  public static <type> Lst<type>[] createArrayOfArrayList(int size) {
+    return new Lst[size];
+  }
+
+  /**
+   * Helper method for creating a Map<K, V>[] without warnings.
+   * 
+   * @param <K> Type of object for the keys in the map.
+   * @param <V> Type of object for the values in the map.
+   * @param size Array size.
+   * @return Array of Map<K, V>
+   */
+  @SuppressWarnings("unchecked")
+  public static <K, V> Map<K, V>[] createArrayOfHashtable(int size) {
+    return new Hashtable[size];
+  }
+
+  public static void swap(Object[] o, int i, int j) {
+    Object oi = o[i];
+    o[i] = o[j];
+    o[j] = oi;
+  }
+
+  public static float[][] newFloat2(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new float[n][];
+    }
+  }
+
+  public static int[][] newInt2(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new int[n][];
+    }
+  }
+
+  public static int[][][] newInt3(int nx, int ny) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(nx, null);
+     * 
+     */
+    {
+      return (ny < 0 ? new int[nx][][] : new int[nx][ny][]);
+    }
+  }
+
+  public static float[][][] newFloat3(int nx, int ny) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(nx, null);
+     * 
+     */
+    {
+      return (ny < 0 ? new float[nx][][] : new float[nx][ny][]);
+    }
+  }
+
+  public static int[][][][] newInt4(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new int[n][][][];
+    }
+  }
+
+  public static short[][] newShort2(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new short[n][];
+    }
+  }
+
+  public static byte[][] newByte2(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new byte[n][];
+    }
+  }
+
+  public static double[][] newDouble2(int n) {
+    /**
+     * @j2sNative
+     * 
+     * return Clazz.newArray(n, null);
+     * 
+     */
+    {
+    return new double[n][];
+    }
+  }
+
+  /**
+   * remove all keys from a map that start with given root
+   * @param map
+   * @param root
+   * @return number removed
+   */
+  public static int removeMapKeys(Map<String, ?> map, String root) {
+    Lst<String> list = new Lst<String>();
+    for (String key: map.keySet())
+      if (key.startsWith(root))
+        list.addLast(key);
+    for (int i = list.size(); --i >= 0;)
+      map.remove(list.get(i));
+    return list.size();
+  }
+
+       public static boolean isAS(Object x) {
+         /**
+          * 
+          * look also for array with first null element
+          * so untypable -- just call it a String[]
+          * (group3Lists, created in ModelLoader)
+          * 
+          * @j2sNative
+          *  return Clazz.isAS(x);
+          */
+         {
+         return x instanceof String[];
+         }
+       }
+
+       public static boolean isASS(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isASS(x);
+          */
+         {
+         return x instanceof String[][];
+         }
+       }
+
+       public static boolean isAP(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAP(x);
+          */
+         {
+         return x instanceof T3[];
+         }
+       }
+
+       public static boolean isAF(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAF(x);
+          */
+         {
+         return x instanceof float[];
+         }
+       }
+
+       public static boolean isAFloat(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAFloat(x);
+          */
+         {
+         return x instanceof Float[];
+         }
+       }
+
+       public static boolean isAD(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAF(x);
+          */
+         {
+         return x instanceof double[];
+         }
+       }
+
+       public static boolean isADD(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAFF(x);
+          */
+         {
+         return x instanceof double[][];
+         }
+       }
+
+       public static boolean isAB(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAI(x);
+          */
+         {
+         return x instanceof byte[];
+         }
+       }
+
+       public static boolean isAI(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAI(x);
+          */
+         {
+         return x instanceof int[];
+         }
+       }
+
+       public static boolean isAII(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAII(x);
+          */
+         {
+         return (x instanceof int[][]);
+         }
+       }
+
+       public static boolean isAFF(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAFF(x);
+          */
+         {
+         return x instanceof float[][];
+         }
+       }
+
+       public static boolean isAFFF(Object x) {
+         /**
+          * @j2sNative
+          *  return Clazz.isAFFF(x);
+          */
+         {
+         return x instanceof float[][][];
+         }
+       }
+       
+       /**
+        * Ensure that we have signed and not unsigned bytes
+        * coming out of any process, but particularly out of 
+        * file reading. 
+        * 
+        * @param b
+        */
+       public static void ensureSignedBytes(byte[] b) {
+         /**
+          * @j2sNative
+          * 
+          * for (var i = b.length; --i >= 0;) {
+          *   var j = b[i] & 0xFF;
+          *   if (j >= 0x80) j -= 0x100;
+          *   b[i] = j;
+          * }
+          * 
+          */
+         {
+         }
+       }
+
+
+}
diff --git a/src/javajs/util/AjaxURLConnection.java b/src/javajs/util/AjaxURLConnection.java
new file mode 100644 (file)
index 0000000..1122bc9
--- /dev/null
@@ -0,0 +1,89 @@
+package javajs.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+
+import javajs.api.JmolObjectInterface;
+
+/**
+ * 
+ * A method to allow a JavaScript Ajax 
+ * 
+ */
+public class AjaxURLConnection extends URLConnection {
+
+  protected AjaxURLConnection(URL url) {
+    super(url);
+  }
+
+  byte[] bytesOut;
+  String postOut = "";
+
+  /**
+   * 
+   * doAjax() is where the synchronous call to AJAX is to happen. or at least
+   * where we wait for the asynchronous call to return. This method should fill
+   * the dataIn field with either a string or byte array, or null if you want to
+   * throw an error.
+   * 
+   * url, bytesOut, and postOut are all available for use
+   * 
+   * the method is "private", but in JavaScript that can still be overloaded.
+   * Just set something to org.jmol.awtjs.JmolURLConnection.prototype.doAjax
+   * 
+   * @return file data as a javajs.util.SB or byte[] depending upon the file
+   *         type.
+   * 
+   * 
+   */
+  @SuppressWarnings("null")
+  private Object doAjax() {
+    JmolObjectInterface jmol = null;
+    /**
+     * @j2sNative
+     * 
+     *            jmol = Jmol;
+     * 
+     */
+    {
+    }
+    return jmol._doAjax(url, postOut, bytesOut);
+  }
+
+  @Override
+  public void connect() throws IOException {
+    // not expected to be used. 
+  }
+
+  public void outputBytes(byte[] bytes) {
+    //      type = "application/octet-stream;";
+    bytesOut = bytes;
+  }
+
+  public void outputString(String post) {
+    postOut = post;
+    //     type = "application/x-www-form-urlencoded";
+  }
+
+  @Override
+  public InputStream getInputStream() {
+    InputStream is = null;
+    Object o = doAjax();
+    if (AU.isAB(o))
+      is = Rdr.getBIS((byte[]) o);
+    else if (o instanceof SB) 
+      is = Rdr.getBIS(Rdr.getBytesFromSB((SB)o));
+    else if (o instanceof String)
+      is = Rdr.getBIS(((String) o).getBytes());
+    return is;
+  }
+  /**
+   * @return javajs.util.SB or byte[], depending upon the file type
+   */
+  public Object getContents() {
+    return doAjax();
+  }
+
+}
diff --git a/src/javajs/util/AjaxURLStreamHandler.java b/src/javajs/util/AjaxURLStreamHandler.java
new file mode 100644 (file)
index 0000000..3d6d4d7
--- /dev/null
@@ -0,0 +1,53 @@
+package javajs.util;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+
+
+/**
+ * 
+ * A method to allow a JavaScript AJAX adapter to 
+ * deliver web content to JSmol. This handler is just a formality.
+ * 
+ */
+public class AjaxURLStreamHandler extends URLStreamHandler {
+
+       String protocol;
+
+       public AjaxURLStreamHandler(String protocol) {
+               this.protocol = protocol;
+       }
+
+       @Override
+       protected URLConnection openConnection(URL url) throws IOException {
+               return new AjaxURLConnection(url);
+       }
+
+
+  @Override
+  protected String toExternalForm(URL u) {
+    SB result = new SB();
+    result.append(u.getProtocol());
+    result.append(":");
+    if (u.getAuthority() != null && u.getAuthority().length() > 0) {
+      result.append("//");
+      result.append(u.getAuthority());
+    }
+    if (u.getPath() != null) {
+      result.append(u.getPath());
+    }
+    if (u.getQuery() != null) {
+      result.append("?");
+      result.append(u.getQuery());
+    }
+    if (u.getRef() != null) {
+      result.append("#");
+      result.append(u.getRef());
+    }
+    return result.toString();
+  }
+
+}
diff --git a/src/javajs/util/AjaxURLStreamHandlerFactory.java b/src/javajs/util/AjaxURLStreamHandlerFactory.java
new file mode 100644 (file)
index 0000000..a050653
--- /dev/null
@@ -0,0 +1,27 @@
+package javajs.util;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.util.Hashtable;
+import java.util.Map;
+
+
+/**
+ * 
+ * For handling URL file IO via AJAX in JavaScript version
+ * 
+ */
+
+public class AjaxURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+       Map<String, AjaxURLStreamHandler> htFactories = new Hashtable<String, AjaxURLStreamHandler>();
+       
+       @Override
+  public URLStreamHandler createURLStreamHandler(String protocol) {
+               AjaxURLStreamHandler fac = htFactories.get(protocol);
+               if (fac == null)
+                       htFactories.put(protocol, fac = new AjaxURLStreamHandler(protocol));
+               return (fac.protocol == null ? null : fac);
+       }
+
+}
diff --git a/src/javajs/util/ArrayDataReader.java b/src/javajs/util/ArrayDataReader.java
new file mode 100644 (file)
index 0000000..737a6ab
--- /dev/null
@@ -0,0 +1,57 @@
+package javajs.util;
+
+import java.io.IOException;
+
+
+
+
+
+
+/**
+ * 
+ * ArrayDataReader subclasses BufferedReader and overrides its
+ * read, readLine, mark, and reset methods so that JmolAdapter 
+ * works with String[] arrays without any further adaptation. 
+ * 
+ */
+
+public class ArrayDataReader extends DataReader {
+  private String[] data;
+  private int pt;
+  private int len;
+
+  public ArrayDataReader() {
+    super();
+  }
+  
+  @Override
+  public DataReader setData(Object data) {
+    this.data = (String[]) data;
+    len = this.data.length;
+    return this;
+  }
+
+  @Override
+  public int read(char[] buf, int off, int len) throws IOException {
+    return readBuf(buf, off, len);
+  }
+
+  @Override
+  public String readLine() {
+    return (pt < len ? data[pt++] : null);
+  }
+
+  /**
+   * 
+   * @param ptr
+   */
+  public void mark(long ptr) {
+    //ignore ptr.
+    ptMark = pt;
+  }
+
+  @Override
+  public void reset() {
+    pt = ptMark;
+  }
+}
\ No newline at end of file
diff --git a/src/javajs/util/BArray.java b/src/javajs/util/BArray.java
new file mode 100644 (file)
index 0000000..f09d272
--- /dev/null
@@ -0,0 +1,33 @@
+package javajs.util;
+
+public class BArray {
+  public byte[] data;
+  
+  public BArray(byte[] data) {
+    this.data = data;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o instanceof BArray) {
+      byte[] d = ((BArray) o).data;
+      if (d.length == data.length){
+        for (int i = 0; i < d.length; i++)
+          if (d[i] != data[i])
+            return false;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public int hashCode() {
+    return data.hashCode();
+  }
+  
+  @Override
+  public String toString() {
+    return new String(data);
+  }
+}
diff --git a/src/javajs/util/BC.java b/src/javajs/util/BC.java
new file mode 100644 (file)
index 0000000..1648f9e
--- /dev/null
@@ -0,0 +1,163 @@
+package javajs.util;
+
+public class BC {
+
+  public BC() {
+    // unnecessary to instantialize unless subclassed
+  }
+  
+  public static float bytesToFloat(byte[] bytes, int j, boolean isBigEndian) throws Exception {
+    return intToFloat(bytesToInt(bytes, j, isBigEndian));
+  }
+
+  public static int bytesToInt(byte[] bytes, int j, boolean isBigEndian) {
+    int n = (isBigEndian ? (bytes[j + 3] & 0xff) | (bytes[j + 2] & 0xff) << 8
+        | (bytes[j + 1] & 0xff) << 16 | (bytes[j] & 0xff) << 24
+        : (bytes[j++] & 0xff) | (bytes[j++] & 0xff) << 8
+            | (bytes[j++] & 0xff) << 16 | (bytes[j++] & 0xff) << 24);
+    /**
+     * @j2sNative
+     * 
+     * return (n > 0x7FFFFFFF ? n - 0x100000000 : n);
+     *   
+     */
+    {
+      return n;
+    }
+  }
+
+  public static float intToFloat(int x) throws Exception {
+    /**
+     * see http://en.wikipedia.org/wiki/Binary32
+     * 
+     * [sign]      [8 bits power] [23 bits fraction]
+     * 0x80000000  0x7F800000      0x7FFFFF
+     * 
+     * (untested)
+     * 
+     * @j2sNative
+     * 
+     *       if (x == 0) return 0;
+     *       var o = javajs.util.BC;
+     *       if (o.fracIEEE == null)
+     *         o.setFracIEEE();
+     *       var m = ((x & 0x7F800000) >> 23);
+     *       return ((x & 0x80000000) == 0 ? 1 : -1) * o.shiftIEEE((x & 0x7FFFFF) | 0x800000, m - 149);
+     *  
+     */
+    {
+    return Float.intBitsToFloat(x);
+    }
+  }
+
+  /**
+   * see http://en.wikipedia.org/wiki/Binary64
+   *  
+   * not concerning ourselves with very small or very large numbers and getting
+   * this exactly right. Just need a float here.
+   * 
+   * @param bytes
+   * @param j
+   * @param isBigEndian
+   * @return float
+   */
+  public static float bytesToDoubleToFloat(byte[] bytes, int j, boolean isBigEndian) {
+    {
+      // IEEE754: sign (1 bit), exponent (11 bits), fraction (52 bits).
+      // seeeeeee eeeeffff ffffffff ffffffff ffffffff xxxxxxxx xxxxxxxx xxxxxxxx
+      //     b1      b2       b3       b4       b5    ---------float ignores----
+
+        if (fracIEEE == null)
+           setFracIEEE();
+        
+      /**
+       * @j2sNative
+       *       var o = javajs.util.BC;
+       *       var b1, b2, b3, b4, b5;
+       *       
+       *       if (isBigEndian) {
+       *       b1 = bytes[j] & 0xFF;
+       *       b2 = bytes[j + 1] & 0xFF;
+       *       b3 = bytes[j + 2] & 0xFF;
+       *       b4 = bytes[j + 3] & 0xFF;
+       *       b5 = bytes[j + 4] & 0xFF;
+       *       } else {
+       *       b1 = bytes[j + 7] & 0xFF;
+       *       b2 = bytes[j + 6] & 0xFF;
+       *       b3 = bytes[j + 5] & 0xFF;
+       *       b4 = bytes[j + 4] & 0xFF;
+       *       b5 = bytes[j + 3] & 0xFF;
+       *       }
+       *       var s = ((b1 & 0x80) == 0 ? 1 : -1);
+       *       var e = (((b1 & 0x7F) << 4) | (b2 >> 4)) - 1026;
+       *       b2 = (b2 & 0xF) | 0x10;
+       *       return s * (o.shiftIEEE(b2, e) + o.shiftIEEE(b3, e - 8) + o.shiftIEEE(b4, e - 16)
+       *         + o.shiftIEEE(b5, e - 24));
+       */
+      {
+        double d;
+        
+        if (isBigEndian)
+          d = Double.longBitsToDouble((((long) bytes[j]) & 0xff) << 56
+             | (((long) bytes[j + 1]) & 0xff) << 48
+             | (((long) bytes[j + 2]) & 0xff) << 40
+             | (((long) bytes[j + 3]) & 0xff) << 32
+             | (((long) bytes[j + 4]) & 0xff) << 24
+             | (((long) bytes[j + 5]) & 0xff) << 16
+             | (((long) bytes[j + 6]) & 0xff) << 8 
+             | (((long) bytes[7]) & 0xff));
+        else
+          d = Double.longBitsToDouble((((long) bytes[j + 7]) & 0xff) << 56
+             | (((long) bytes[j + 6]) & 0xff) << 48
+             | (((long) bytes[j + 5]) & 0xff) << 40
+             | (((long) bytes[j + 4]) & 0xff) << 32
+             | (((long) bytes[j + 3]) & 0xff) << 24
+             | (((long) bytes[j + 2]) & 0xff) << 16
+             | (((long) bytes[j + 1]) & 0xff) << 8 
+             | (((long) bytes[j]) & 0xff));
+        return (float) d;
+      }
+
+    }
+  }
+
+  private static float[] fracIEEE;
+
+  private static void setFracIEEE() {
+    fracIEEE = new float[270];
+    for (int i = 0; i < 270; i++)
+      fracIEEE[i] = (float) Math.pow(2, i - 141);
+    //    System.out.println(fracIEEE[0] + "  " + Parser.FLOAT_MIN_SAFE);
+    //    System.out.println(fracIEEE[269] + "  " + Float.MAX_VALUE);
+  }
+
+  /**
+   * only concerned about reasonable float values here -- private but not designated; called by JavaScript
+   * 
+   * @param f
+   * @param i
+   * @return f * 2^i
+   */
+  static double shiftIEEE(double f, int i) {
+    if (f == 0 || i < -140)
+      return 0;
+    if (i > 128)
+      return Float.MAX_VALUE;
+    return f * fracIEEE[i + 140];
+  }
+
+//  static {
+//    setFracIEEE();
+//    for (int i = -50; i < 50; i++) {
+//      float f = i * (float) (Math.random() * Math.pow(2, Math.random() * 100 - 50));
+//      int x = Float.floatToIntBits(f);
+//      int m = ((x & 0x7F800000) >> 23);
+//      float f1 = (float) (f == 0 ? 0 : ((x & 0x80000000) == 0 ? 1 : -1) * shiftIEEE((x & 0x7FFFFF) | 0x800000, m - 149));
+//      System.out.println(f + "  " + f1);
+//    }
+//    System.out.println("binarydo");
+//  }
+
+
+
+}
diff --git a/src/javajs/util/BS.java b/src/javajs/util/BS.java
new file mode 100644 (file)
index 0000000..89c9a2b
--- /dev/null
@@ -0,0 +1,934 @@
+/*
+ * Copyright 1995-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package javajs.util;
+
+import javajs.api.JSONEncodable;
+
+
+
+/**
+ * 
+ * a fast 32-bit BitSet optimized for Java2Script -- about 25 times faster than
+ * java.util.BitSet
+ * 
+ * @author Bob Hanson hansonr@stolaf.edu
+ * 
+ *         Additions by Bob Hanson to allow for JavaScript mix of int/long Note
+ *         that Firefox (Sept 2012) does not really treat "Int32Array" as such,
+ *         because any element can be pushed into being a 64-bit number, which
+ *         really isn't because the last 8 bits are not usable.
+ * 
+ *         This class implements a vector of bits that grows as needed. Each
+ *         component of the bit set has a {@code boolean} value. The bits of a
+ *         {@code BitSet} are indexed by nonnegative integers. Individual
+ *         indexed bits can be examined, set, or cleared. One {@code BitSet} may
+ *         be used to modify the contents of another {@code BitSet} through
+ *         logical AND, logical inclusive OR, and logical exclusive OR
+ *         operations.
+ * 
+ *         <p>
+ *         By default, all bits in the set initially have the value {@code
+ *         false}.
+ * 
+ *         <p>
+ *         Every bit set has a current size, which is the number of bits of
+ *         space currently in use by the bit set. Note that the size is related
+ *         to the implementation of a bit set, so it may change with
+ *         implementation. The length of a bit set relates to logical length of
+ *         a bit set and is defined independently of implementation.
+ * 
+ *         <p>
+ *         Unless otherwise noted, passing a null parameter to any of the
+ *         methods in a {@code BitSet} will result in a {@code
+ *         NullPointerException}.
+ * 
+ *         <p>
+ *         A {@code BitSet} is not safe for multithreaded use without external
+ *         synchronization.
+ * 
+ * @author Arthur van Hoff
+ * @author Michael McCloskey
+ * @author Martin Buchholz
+ * @since JDK1.0
+ */
+public class BS implements Cloneable, JSONEncodable {
+  /*
+   * BitSets are packed into arrays of "words."
+   * 
+   * An int, which consists of 32 bits, requiring 5 address bits, is used for
+   * the JavaScript port.
+   */
+  private final static int ADDRESS_BITS_PER_WORD = 5;
+  private final static int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
+
+  /* Used to shift left or right for a partial word mask */
+  private static final int WORD_MASK = 0xffffffff;
+
+
+  /**
+   * The internal field corresponding to the serialField "bits".
+   */
+  private int[] words;
+
+  /**
+   * The number of words in the logical size of this BitSet.
+   */
+  private transient int wordsInUse = 0;
+
+  /**
+   * Whether the size of "words" is user-specified. If so, we assume the user
+   * knows what he's doing and try harder to preserve it.
+   */
+  private transient boolean sizeIsSticky = false;
+
+  /* use serialVersionUID from JDK 1.0.2 for interoperability */
+  //private static final long serialVersionUID = 7997698588986878753L;
+
+  /**
+   * Given a bit index, return word index containing it.
+   * @param bitIndex 
+   * @return b
+   */
+  private static int wordIndex(int bitIndex) {
+    return bitIndex >> ADDRESS_BITS_PER_WORD;
+  }
+
+  /**
+   * Sets the field wordsInUse to the logical size in words of the bit set.
+   * WARNING:This method assumes that the number of words actually in use is
+   * less than or equal to the current value of wordsInUse!
+   */
+  private void recalculateWordsInUse() {
+    // Traverse the bitset until a used word is found
+    int i;
+    for (i = wordsInUse - 1; i >= 0; i--)
+      if (words[i] != 0)
+        break;
+
+    wordsInUse = i + 1; // The new logical size
+  }
+
+  /**
+   * Creates a new bit set. All bits are initially {@code false}.
+   */
+  public BS() {
+    initWords(BITS_PER_WORD);
+    sizeIsSticky = false;
+  }
+
+  /**
+   * Creates a bit set whose initial size is large enough to explicitly
+   * represent bits with indices in the range {@code 0} through {@code nbits-1}.
+   * All bits are initially {@code false}.
+   * 
+   * @param nbits
+   *          the initial size of the bit set
+   * @return bs
+   * @throws NegativeArraySizeException
+   *           if the specified initial size is negative
+   */
+  public static BS newN(int nbits) {
+    BS bs = new BS();
+    bs.init(nbits);
+    return bs;
+  }
+
+  private void init(int nbits) {
+    // nbits can't be negative; size 0 is OK
+    if (nbits < 0)
+      throw new NegativeArraySizeException("nbits < 0: " + nbits);
+    initWords(nbits);
+    sizeIsSticky = true;
+  }
+
+  private void initWords(int nbits) {
+    words = new int[wordIndex(nbits - 1) + 1];
+  }
+
+  /**
+   * Ensures that the BitSet can hold enough words.
+   * 
+   * @param wordsRequired
+   *          the minimum acceptable number of words.
+   */
+  private void ensureCapacity(int wordsRequired) {
+    if (words.length < wordsRequired) {
+      // Allocate larger of doubled size or required size
+      int request = Math.max(2 * words.length, wordsRequired);
+      setLength(request);
+      sizeIsSticky = false;
+    }
+  }
+
+  /**
+   * Ensures that the BitSet can accommodate a given wordIndex, temporarily
+   * violating the invariants. The caller must restore the invariants before
+   * returning to the user, possibly using recalculateWordsInUse().
+   * 
+   * @param wordIndex
+   *          the index to be accommodated.
+   */
+  private void expandTo(int wordIndex) {
+    int wordsRequired = wordIndex + 1;
+    if (wordsInUse < wordsRequired) {
+      ensureCapacity(wordsRequired);
+      wordsInUse = wordsRequired;
+    }
+  }
+
+
+  /**
+   * Sets the bit at the specified index to {@code true}.
+   * 
+   * @param bitIndex
+   *          a bit index
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   * @since JDK1.0
+   */
+  public void set(int bitIndex) {
+    if (bitIndex < 0)
+      throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+    int wordIndex = wordIndex(bitIndex);
+    expandTo(wordIndex);
+
+    words[wordIndex] |= (1 << bitIndex); // Restores invariants
+
+  }
+
+  /**
+   * Sets the bit at the specified index to the specified value.
+   * 
+   * @param bitIndex
+   *          a bit index
+   * @param value
+   *          a boolean value to set
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   * @since 1.4
+   */
+  public void setBitTo(int bitIndex, boolean value) {
+    if (value)
+      set(bitIndex);
+    else
+      clear(bitIndex);
+  }
+
+  /**
+   * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+   * specified {@code toIndex} (exclusive) to {@code true}.
+   * 
+   * @param fromIndex
+   *          index of the first bit to be set
+   * @param toIndex
+   *          index after the last bit to be set
+   * @throws IndexOutOfBoundsException
+   *           if {@code fromIndex} is negative, or {@code toIndex} is negative,
+   *           or {@code fromIndex} is larger than {@code toIndex}
+   * @since 1.4
+   */
+  public void setBits(int fromIndex, int toIndex) {
+
+    if (fromIndex == toIndex)
+      return;
+
+    // Increase capacity if necessary
+    int startWordIndex = wordIndex(fromIndex);
+    int endWordIndex = wordIndex(toIndex - 1);
+    expandTo(endWordIndex);
+
+    int firstWordMask = WORD_MASK << fromIndex;
+    int lastWordMask = WORD_MASK >>> -toIndex;
+    if (startWordIndex == endWordIndex) {
+      // Case 1: One word
+      words[startWordIndex] |= (firstWordMask & lastWordMask);
+    } else {
+      // Case 2: Multiple words
+      // Handle first word
+      words[startWordIndex] |= firstWordMask;
+
+      // Handle intermediate words, if any
+      for (int i = startWordIndex + 1; i < endWordIndex; i++)
+        words[i] = WORD_MASK;
+
+      // Handle last word (restores invariants)
+      words[endWordIndex] |= lastWordMask;
+    }
+  }
+
+  /**
+   * Sets the bit specified by the index to {@code false}.
+   * 
+   * @param bitIndex
+   *          the index of the bit to be cleared
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   * @since JDK1.0
+   */
+  public void clear(int bitIndex) {
+    if (bitIndex < 0)
+      throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+    int wordIndex = wordIndex(bitIndex);
+    if (wordIndex >= wordsInUse)
+      return;
+
+    words[wordIndex] &= ~(1 << bitIndex);
+
+    recalculateWordsInUse();
+  }
+
+  /**
+   * Sets the bits from the specified {@code fromIndex} (inclusive) to the
+   * specified {@code toIndex} (exclusive) to {@code false}.
+   * 
+   * @param fromIndex
+   *          index of the first bit to be cleared
+   * @param toIndex
+   *          index after the last bit to be cleared
+   * @throws IndexOutOfBoundsException
+   *           if {@code fromIndex} is negative, or {@code toIndex} is negative,
+   *           or {@code fromIndex} is larger than {@code toIndex}
+   * @since 1.4
+   */
+  public void clearBits(int fromIndex, int toIndex) {
+    if (fromIndex == toIndex)
+      return;
+
+    int startWordIndex = wordIndex(fromIndex);
+    if (startWordIndex >= wordsInUse)
+      return;
+
+    int endWordIndex = wordIndex(toIndex - 1);
+    if (endWordIndex >= wordsInUse) {
+      toIndex = length();
+      endWordIndex = wordsInUse - 1;
+    }
+
+    int firstWordMask = WORD_MASK << fromIndex;
+    int lastWordMask = WORD_MASK >>> -toIndex;
+    if (startWordIndex == endWordIndex) {
+      // Case 1: One word
+      words[startWordIndex] &= ~(firstWordMask & lastWordMask);
+    } else {
+      // Case 2: Multiple words
+      // Handle first word
+      words[startWordIndex] &= ~firstWordMask;
+
+      // Handle intermediate words, if any
+      for (int i = startWordIndex + 1; i < endWordIndex; i++)
+        words[i] = 0;
+
+      // Handle last word
+      words[endWordIndex] &= ~lastWordMask;
+    }
+
+    recalculateWordsInUse();
+  }
+
+  /**
+   * Sets all of the bits in this BitSet to {@code false}.
+   * 
+   * @since 1.4
+   */
+  public void clearAll() {
+    while (wordsInUse > 0)
+      words[--wordsInUse] = 0;
+  }
+
+  /**
+   * Returns the value of the bit with the specified index. The value is {@code
+   * true} if the bit with the index {@code bitIndex} is currently set in this
+   * {@code BitSet}; otherwise, the result is {@code false}.
+   * 
+   * @param bitIndex
+   *          the bit index
+   * @return the value of the bit with the specified index
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   */
+  public boolean get(int bitIndex) {
+    if (bitIndex < 0)
+      throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
+
+    int wordIndex = wordIndex(bitIndex);
+    return (wordIndex < wordsInUse)
+        && ((words[wordIndex] & (1 << bitIndex)) != 0);
+  }
+
+  /**
+   * Returns the index of the first bit that is set to {@code true} that occurs
+   * on or after the specified starting index. If no such bit exists then
+   * {@code -1} is returned.
+   * 
+   * <p>
+   * To iterate over the {@code true} bits in a {@code BitSet}, use the
+   * following loop:
+   * 
+   * <pre>
+   * @code
+   * for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
+   *     // operate on index i here
+   * }}
+   * </pre>
+   * 
+   * @param fromIndex
+   *          the index to start checking from (inclusive)
+   * @return the index of the next set bit, or {@code -1} if there is no such
+   *         bit
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   * @since 1.4
+   */
+  public int nextSetBit(int fromIndex) {
+    if (fromIndex < 0)
+      throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+    int u = wordIndex(fromIndex);
+    if (u >= wordsInUse)
+      return -1;
+
+    int word = words[u] & (WORD_MASK << fromIndex);
+
+    while (true) {
+      if (word != 0)
+        return (u * BITS_PER_WORD) + Integer.numberOfTrailingZeros(word);
+      if (++u == wordsInUse)
+        return -1;
+      word = words[u];
+    }
+  }
+
+  /**
+   * Returns the index of the first bit that is set to {@code false} that occurs
+   * on or after the specified starting index.
+   * 
+   * @param fromIndex
+   *          the index to start checking from (inclusive)
+   * @return the index of the next clear bit
+   * @throws IndexOutOfBoundsException
+   *           if the specified index is negative
+   * @since 1.4
+   */
+  public int nextClearBit(int fromIndex) {
+    // Neither spec nor implementation handle bitsets of maximal length.
+    // See 4816253.
+    if (fromIndex < 0)
+      throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
+
+    int u = wordIndex(fromIndex);
+    if (u >= wordsInUse)
+      return fromIndex;
+
+    int word = ~words[u] & (WORD_MASK << fromIndex);
+
+    while (true) {
+      if (word != 0)
+        return (u * BITS_PER_WORD) + Integer.numberOfTrailingZeros(word);
+      if (++u == wordsInUse)
+        return wordsInUse * BITS_PER_WORD;
+      word = ~words[u];
+    }
+  }
+
+  /**
+   * Returns the "logical size" of this {@code BitSet}: the index of the highest
+   * set bit in the {@code BitSet} plus one. Returns zero if the {@code BitSet}
+   * contains no set bits.
+   * 
+   * @return the logical size of this {@code BitSet}
+   * @since 1.2
+   */
+  public int length() {
+    if (wordsInUse == 0)
+      return 0;
+
+    return BITS_PER_WORD * (wordsInUse - 1)
+        + (BITS_PER_WORD - Integer.numberOfLeadingZeros(words[wordsInUse - 1]));
+  }
+
+  /**
+   * Returns true if this {@code BitSet} contains no bits that are set to
+   * {@code true}.
+   * 
+   * @return boolean indicating whether this {@code BitSet} is empty
+   * @since 1.4
+   */
+  public boolean isEmpty() {
+    return wordsInUse == 0;
+  }
+
+  /**
+   * Returns true if the specified {@code BitSet} has any bits set to {@code
+   * true} that are also set to {@code true} in this {@code BitSet}.
+   * 
+   * @param set
+   *          {@code BitSet} to intersect with
+   * @return boolean indicating whether this {@code BitSet} intersects the
+   *         specified {@code BitSet}
+   * @since 1.4
+   */
+  public boolean intersects(BS set) {
+    for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+      if ((words[i] & set.words[i]) != 0)
+        return true;
+    return false;
+  }
+
+  /**
+   * Returns the number of bits set to {@code true} in this {@code BitSet}.
+   * 
+   * @return the number of bits set to {@code true} in this {@code BitSet}
+   * @since 1.4
+   */
+  public int cardinality() {
+    int sum = 0;
+    for (int i = 0; i < wordsInUse; i++)
+      sum += Integer.bitCount(words[i]);
+    return sum;
+  }
+
+  /**
+   * Performs a logical <b>AND</b> of this target bit set with the argument bit
+   * set. This bit set is modified so that each bit in it has the value {@code
+   * true} if and only if it both initially had the value {@code true} and the
+   * corresponding bit in the bit set argument also had the value {@code true}.
+   * 
+   * @param set
+   *          a bit set
+   */
+  public void and(BS set) {
+    if (this == set)
+      return;
+
+    while (wordsInUse > set.wordsInUse)
+      words[--wordsInUse] = 0;
+
+    // Perform logical AND on words in common
+    for (int i = 0; i < wordsInUse; i++)
+      words[i] &= set.words[i];
+
+    recalculateWordsInUse();
+  }
+
+  /**
+   * Performs a logical <b>OR</b> of this bit set with the bit set argument.
+   * This bit set is modified so that a bit in it has the value {@code true} if
+   * and only if it either already had the value {@code true} or the
+   * corresponding bit in the bit set argument has the value {@code true}.
+   * 
+   * @param set
+   *          a bit set
+   */
+  public void or(BS set) {
+    if (this == set)
+      return;
+
+    int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+    if (wordsInUse < set.wordsInUse) {
+      ensureCapacity(set.wordsInUse);
+      wordsInUse = set.wordsInUse;
+    }
+
+    // Perform logical OR on words in common
+    for (int i = 0; i < wordsInCommon; i++)
+      words[i] |= set.words[i];
+
+    // Copy any remaining words
+    if (wordsInCommon < set.wordsInUse)
+      System.arraycopy(set.words, wordsInCommon, words, wordsInCommon,
+          wordsInUse - wordsInCommon);
+
+  }
+
+  /**
+   * Performs a logical <b>XOR</b> of this bit set with the bit set argument.
+   * This bit set is modified so that a bit in it has the value {@code true} if
+   * and only if one of the following statements holds:
+   * <ul>
+   * <li>The bit initially has the value {@code true}, and the corresponding bit
+   * in the argument has the value {@code false}.
+   * <li>The bit initially has the value {@code false}, and the corresponding
+   * bit in the argument has the value {@code true}.
+   * </ul>
+   * 
+   * @param set
+   *          a bit set
+   */
+  public void xor(BS set) {
+    int wordsInCommon = Math.min(wordsInUse, set.wordsInUse);
+
+    if (wordsInUse < set.wordsInUse) {
+      ensureCapacity(set.wordsInUse);
+      wordsInUse = set.wordsInUse;
+    }
+
+    // Perform logical XOR on words in common
+    for (int i = 0; i < wordsInCommon; i++)
+      words[i] ^= set.words[i];
+
+    // Copy any remaining words
+    if (wordsInCommon < set.wordsInUse)
+      System.arraycopy(set.words, wordsInCommon, words, wordsInCommon,
+          set.wordsInUse - wordsInCommon);
+
+    recalculateWordsInUse();
+  }
+
+  /**
+   * Clears all of the bits in this {@code BitSet} whose corresponding bit is
+   * set in the specified {@code BitSet}.
+   * 
+   * @param set
+   *          the {@code BitSet} with which to mask this {@code BitSet}
+   * @since 1.2
+   */
+  public void andNot(BS set) {
+    // Perform logical (a & !b) on words in common
+    for (int i = Math.min(wordsInUse, set.wordsInUse) - 1; i >= 0; i--)
+      words[i] &= ~set.words[i];
+
+    recalculateWordsInUse();
+  }
+
+  /**
+   * Returns a hash code value for this bit set. The hash code depends only on
+   * which bits have been set within this <code>BitSet</code>. The algorithm
+   * used to compute it may be described as follows.
+   * <p>
+   * Suppose the bits in the <code>BitSet</code> were to be stored in an array
+   * of <code>long</code> integers called, say, <code>words</code>, in such a
+   * manner that bit <code>k</code> is set in the <code>BitSet</code> (for
+   * nonnegative values of <code>k</code>) if and only if the expression
+   * 
+   * <pre>
+   * ((k &gt;&gt; 6) &lt; words.length) &amp;&amp; ((words[k &gt;&gt; 6] &amp; (1 &lt;&lt; (bit &amp; 0x3F))) != 0)
+   * </pre>
+   * 
+   * is true. Then the following definition of the <code>hashCode</code> method
+   * would be a correct implementation of the actual algorithm:
+   * 
+   * <pre>
+   * public int hashCode() {
+   *  long h = 1234;
+   *  for (int i = words.length; --i &gt;= 0;) {
+   *    h &circ;= words[i] * (i + 1);
+   *  }
+   *  return (int) ((h &gt;&gt; 32) &circ; h);
+   * }
+   * </pre>
+   * 
+   * Note that the hash code values change if the set of bits is altered.
+   * <p>
+   * Overrides the <code>hashCode</code> method of <code>Object</code>.
+   * 
+   * @return a hash code value for this bit set.
+   */
+  @Override
+  public int hashCode() {
+    long h = 1234;
+    for (int i = wordsInUse; --i >= 0;)
+      h ^= words[i] * (i + 1);
+
+    return (int) ((h >> 32) ^ h);
+  }
+
+  /**
+   * Returns the number of bits of space actually in use by this {@code BitSet}
+   * to represent bit values. The maximum element in the set is the size - 1st
+   * element.
+   * 
+   * @return the number of bits currently in this bit set
+   */
+  public int size() {
+    return words.length * BITS_PER_WORD;
+  }
+
+  /**
+   * Compares this object against the specified object. The result is {@code
+   * true} if and only if the argument is not {@code null} and is a {@code
+   * Bitset} object that has exactly the same set of bits set to {@code true} as
+   * this bit set. That is, for every nonnegative {@code int} index {@code k},
+   * 
+   * <pre>
+   * ((BitSet) obj).get(k) == this.get(k)
+   * </pre>
+   * 
+   * must be true. The current sizes of the two bit sets are not compared.
+   * 
+   * @param obj
+   *          the object to compare with
+   * @return {@code true} if the objects are the same; {@code false} otherwise
+   * @see #size()
+   */
+  @Override
+  public boolean equals(Object obj) {
+    if (!(obj instanceof BS))
+      return false;
+    if (this == obj)
+      return true;
+
+    BS set = (BS) obj;
+
+    if (wordsInUse != set.wordsInUse)
+      return false;
+
+    // Check words in use by both BitSets
+    for (int i = 0; i < wordsInUse; i++)
+      if (words[i] != set.words[i])
+        return false;
+
+    return true;
+  }
+
+  /**
+   * Cloning this {@code BitSet} produces a new {@code BitSet} that is equal to
+   * it. The clone of the bit set is another bit set that has exactly the same
+   * bits set to {@code true} as this bit set.
+   * 
+   * @return a clone of this bit set
+   * @see #size()
+   */
+  @Override
+  public Object clone() {
+    if (!sizeIsSticky && wordsInUse != words.length)
+      setLength(wordsInUse);
+    return copy(this);
+  }
+
+  /**
+   * Attempts to reduce internal storage used for the bits in this bit set.
+   * Calling this method may, but is not required to, affect the value returned
+   * by a subsequent call to the {@link #size()} method.
+   * @param n 
+   */
+  private void setLength(int n) {
+    int[] a = new int[n];
+    System.arraycopy(words, 0, a, 0, Math.min(wordsInUse, n));
+    words = a;
+  }
+
+  /**
+   * Returns a string representation of this bit set. For every index for which
+   * this {@code BitSet} contains a bit in the set state, the decimal
+   * representation of that index is included in the result. Such indices are
+   * listed in order from lowest to highest, separated by ",&nbsp;" (a comma and
+   * a space) and surrounded by braces, resulting in the usual mathematical
+   * notation for a set of integers.
+   * 
+   * <p>
+   * Example:
+   * 
+   * <pre>
+   * BitSet drPepper = new BitSet();
+   * </pre>
+   * 
+   * Now {@code drPepper.toString()} returns "{}".
+   * <p>
+   * 
+   * <pre>
+   * drPepper.set(2);
+   * </pre>
+   * 
+   * Now {@code drPepper.toString()} returns "{2}".
+   * <p>
+   * 
+   * <pre>
+   * drPepper.set(4);
+   * drPepper.set(10);
+   * </pre>
+   * 
+   * Now {@code drPepper.toString()} returns "{2, 4, 10}".
+   * 
+   * @return a string representation of this bit set
+   */
+  @Override
+  public String toString() {
+    return escape(this, '{', '}');
+  }
+  
+  private final static int[] emptyBitmap = new int[0];
+
+  /**
+   * fast copy
+   * 
+   * @param bitsetToCopy
+   * @return bs
+   */
+  public static BS copy(BS bitsetToCopy) {
+    BS bs;
+    /**
+     * Clazz.clone will copy wordsInUse and sizeIsSticky, 
+     * but just a pointer to the words array.
+     * 
+     * @j2sNative
+     * 
+     *            bs = Clazz.clone(bitsetToCopy);
+     * 
+     */
+    {
+      bs = new BS();
+    }
+    int wordCount = bitsetToCopy.wordsInUse;
+    if (wordCount == 0) {
+      bs.words = emptyBitmap;
+    } else {
+      bs.words = new int[bs.wordsInUse = wordCount];
+      System.arraycopy(bitsetToCopy.words, 0, bs.words, 0, wordCount);
+    }
+    return bs;
+  }
+
+  /**
+   * 
+   * @param max
+   * @return n bits below max
+   */
+  public int cardinalityN(int max) {
+    int n = cardinality();
+    for (int i = length(); --i >= max;)
+      if (get(i))
+        n--;
+    return n;
+  }
+
+  @Override
+  public String toJSON() {
+
+    int numBits = (wordsInUse > 128) ? cardinality() : wordsInUse
+        * BITS_PER_WORD;
+    SB b = SB.newN(6 * numBits + 2);
+    b.appendC('[');
+
+    int i = nextSetBit(0);
+    if (i != -1) {
+      b.appendI(i);
+      for (i = nextSetBit(i + 1); i >= 0; i = nextSetBit(i + 1)) {
+        int endOfRun = nextClearBit(i);
+        do {
+          b.append(", ").appendI(i);
+        } while (++i < endOfRun);
+      }
+    }
+
+    b.appendC(']');
+    return b.toString();
+  }
+
+  public static String escape(BS bs, char chOpen, char chClose) {
+    if (bs == null)
+      return chOpen + "{}" + chClose;
+    SB s = new SB();
+    s.append(chOpen + "{");
+    int imax = bs.length();
+    int iLast = -1;
+    int iFirst = -2;
+    int i = -1;
+    while (++i <= imax) {
+      boolean isSet = bs.get(i);
+      if (i == imax || iLast >= 0 && !isSet) {
+        if (iLast >= 0 && iFirst != iLast)
+          s.append((iFirst == iLast - 1 ? " " : ":") + iLast);
+        if (i == imax)
+          break;
+        iLast = -1;
+      }
+      if (bs.get(i)) {
+        if (iLast < 0) {
+          s.append((iFirst == -2 ? "" : " ") + i);
+          iFirst = i;
+        }
+        iLast = i;
+      }
+    }
+    s.append("}").appendC(chClose);
+    return s.toString();
+  }
+
+  public static BS unescape(String str) {
+    char ch;
+    int len;
+    if (str == null || (len = (str = str.trim()).length()) < 4
+        || str.equalsIgnoreCase("({null})") 
+        || (ch = str.charAt(0)) != '(' && ch != '[' 
+        || str.charAt(len - 1) != (ch == '(' ? ')' : ']')
+        || str.charAt(1) != '{' || str.indexOf('}') != len - 2)
+      return null;
+    len -= 2;
+    for (int i = len; --i >= 2;)
+      if (!PT.isDigit(ch = str.charAt(i)) && ch != ' ' && ch != '\t'
+          && ch != ':')
+        return null;
+    int lastN = len;
+    while (PT.isDigit(str.charAt(--lastN))) {
+      // loop
+    }
+    if (++lastN == len)
+      lastN = 0;
+    else
+      try {
+        lastN = Integer.parseInt(str.substring(lastN, len));
+      } catch (NumberFormatException e) {
+        return null;
+      }
+    BS bs = BS.newN(lastN);
+    lastN = -1;
+    int iPrev = -1;
+    int iThis = -2;
+    for (int i = 2; i <= len; i++) {
+      switch (ch = str.charAt(i)) {
+      case '\t':
+      case ' ':
+      case '}':
+        if (iThis < 0)
+          break;
+        if (iThis < lastN)
+          return null;
+        lastN = iThis;
+        if (iPrev < 0)
+          iPrev = iThis;
+        bs.setBits(iPrev, iThis + 1);
+        iPrev = -1;
+        iThis = -2;
+        break;
+      case ':':
+        iPrev = lastN = iThis;
+        iThis = -2;
+        break;
+      default:
+        if (PT.isDigit(ch)) {
+          if (iThis < 0)
+            iThis = 0;
+          iThis = (iThis * 10) + (ch - 48);
+        }
+      }
+    }
+    return (iPrev >= 0 ? null : bs);
+  }
+
+}
diff --git a/src/javajs/util/Base64.java b/src/javajs/util/Base64.java
new file mode 100644 (file)
index 0000000..a7ac3a9
--- /dev/null
@@ -0,0 +1,120 @@
+// Version 1.0a
+// Copyright (C) 1998, James R. Weeks and BioElectroMech.
+// Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.
+
+// See license.txt for details about the allowed used of this software.
+// This software is based in part on the work of the Independent JPEG Group.
+// See IJGreadme.txt for details about the Independent JPEG Group's license.
+
+// This encoder is inspired by the Java Jpeg encoder by Florian Raemy,
+// studwww.eurecom.fr/~raemy.
+// It borrows a great deal of code and structure from the Independent
+// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.
+// See license.txt for details.
+
+package javajs.util;
+
+
+public class Base64 {
+
+  //                              0         1         2         3         4         5         6
+  //                              0123456789012345678901234567890123456789012345678901234567890123
+  private static String base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  //                              41----------------------5A
+  //                                                        61----------------------7A
+  //                                                                                  30------39    
+  //                                                                                            2B  
+  //                                                                                             2F
+  //                                                 alternative "URL-SAFE"     2D and 5F       -_
+  
+  private static int[] decode64 = new int[] {
+    0,0,0,0,     0,0,0,0,     0,0,0,0,     0,0,0,0,      //0x00-0x0F
+    0,0,0,0,     0,0,0,0,     0,0,0,0,     0,0,0,0,      //0x10-0x1F
+    0,0,0,0,     0,0,0,0,     0,0,0,62,    0,62,0,63,    //0x20-0x2F
+    52,53,54,55, 56,57,58,59, 60,61,0,0,   0,0,0,0,      //0x30-0x3F
+    0,0,1,2,     3,4,5,6,     7,8,9,10,    11,12,13,14,  //0x40-0x4F
+    15,16,17,18, 19,20,21,22, 23,24,25,0,  0,0,0,63,     //0x50-0x5F
+    0,26,27,28,  29,30,31,32, 33,34,35,36, 37,38,39,40,  //0x60-0x6F
+    41,42,43,44, 45,46,47,48, 49,50,51,0,  0,0,0,0,      //0x70-0x7F
+  };
+    
+//  public static void write(byte[] bytes, OutputChannel out) {
+//    SB sb = getBase64(bytes);
+//    int len = sb.length();
+//    byte[] b = new byte[1];
+//    for (int i = 0; i < len; i++) {
+//      b[0] = (byte) sb.charAt(i);
+//      out.write(b, 0, 1);
+//    }
+//  }
+
+  public static byte[] getBytes64(byte[] bytes) {
+    return getBase64(bytes).toBytes(0, -1);
+  }
+
+  /**
+   * 
+   * @param bytes
+   * @return BASE64-encoded string, without ";base64,"
+   */
+  public static SB getBase64(byte[] bytes) {
+    long nBytes = bytes.length;
+    SB sout = new SB();
+    if (nBytes == 0)
+      return sout;
+    for (int i = 0, nPad = 0; i < nBytes && nPad == 0;) {
+      if (i % 75 == 0 && i != 0)
+        sout.append("\r\n");
+      nPad = (i + 2 == nBytes ? 1 : i + 1 == nBytes ? 2 : 0);
+      int outbytes = ((bytes[i++] << 16) & 0xFF0000)
+          | ((nPad == 2 ? 0 : bytes[i++] << 8) & 0x00FF00)
+          | ((nPad >= 1 ? 0 : (int) bytes[i++]) & 0x0000FF);
+      //System.out.println(Integer.toHexString(outbytes));
+      sout.appendC(base64.charAt((outbytes >> 18) & 0x3F));
+      sout.appendC(base64.charAt((outbytes >> 12) & 0x3F));
+      sout.appendC(nPad == 2 ? '=' : base64.charAt((outbytes >> 6) & 0x3F));
+      sout.appendC(nPad >= 1 ? '=' : base64.charAt(outbytes & 0x3F));
+    }
+    return sout;
+  }
+
+  //Note: Just a simple decoder here. Nothing fancy at all
+  //      Because of the 0s in decode64, this is not a VERIFIER
+  //      Rather, it may decode even bad Base64-encoded data
+  //
+  // Bob Hanson 4/2007
+  
+  public static byte[] decodeBase64(String strBase64) {
+    int nBytes = 0;
+    int ch;
+    int pt0 = strBase64.indexOf(";base64,") + 1;
+    if (pt0 > 0)
+      pt0 += 7;
+    char[] chars64 = strBase64.toCharArray();
+    int len64 = chars64.length;
+    if (len64 == 0)
+      return new byte[0];
+    for (int i = len64; --i >= pt0;)
+      nBytes += ((ch = chars64[i] & 0x7F) == 'A' || decode64[ch] > 0 ? 3 : 0);
+    nBytes = nBytes >> 2;
+    byte[] bytes = new byte[nBytes];
+    int offset = 18;
+    for (int i = pt0, pt = 0, b = 0; i < len64; i++) {
+      if (decode64[ch = chars64[i] & 0x7F] > 0 || ch == 'A' || ch == '=') {
+        b |= decode64[ch] << offset;
+        //System.out.println(chars64[i] + " " + decode64[ch] + " " + offset + " " + Integer.toHexString(b));
+        offset -= 6;
+        if (offset < 0) {
+          bytes[pt++] = (byte) ((b & 0xFF0000) >> 16);
+          if (pt < nBytes)
+            bytes[pt++] = (byte) ((b & 0xFF00) >> 8);
+          if (pt < nBytes)
+            bytes[pt++] = (byte) (b & 0xFF);
+          offset = 18;
+          b =  0;
+        }
+      }
+    }
+    return bytes;
+  }    
+}
\ No newline at end of file
diff --git a/src/javajs/util/BinaryDocument.java b/src/javajs/util/BinaryDocument.java
new file mode 100644 (file)
index 0000000..172ed7c
--- /dev/null
@@ -0,0 +1,360 @@
+/* $RCSfile$
+ * $Author: egonw $
+ * $Date: 2006-03-18 15:59:33 -0600 (Sat, 18 Mar 2006) $
+ * $Revision: 4652 $
+ *
+ * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
+ *
+ * Contact: hansonr@stolaf.edu
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+
+import java.io.BufferedInputStream;
+import java.io.DataInputStream;
+import java.util.Map;
+
+
+import javajs.api.GenericBinaryDocument;
+import javajs.api.GenericZipTools;
+
+
+//import java.io.RandomAccessFile;
+
+/* a basic binary file reader (extended by CompoundDocument). 
+ * 
+ * random access file info: 
+ * http://java.sun.com/docs/books/tutorial/essential/io/rafs.html
+ * 
+ * SHOOT! random access is only for applications, not applets!
+ * 
+ * Note that YOU are responsible for determining whether a file
+ * is bigEndian or littleEndian; the default is bigEndian.
+ * 
+ * JavaScript note: readShort() malfunctioned because (short) (xx << 8) 
+ * isn't the same as (int) (xx << 8); same problem in java.io.DataStream
+ * 
+ * 
+ */
+
+public class BinaryDocument extends BC implements GenericBinaryDocument {
+
+  /**
+   * @j2sIgnore
+   */
+  public BinaryDocument() {  
+  }
+
+
+  // called by reflection
+  
+  protected DataInputStream stream;
+  protected boolean isRandom = false;
+  public boolean isBigEndian = true;
+  protected GenericZipTools jzt;
+
+  @Override
+  public void close() {
+    if (stream != null)
+      try {
+        stream.close();
+      } catch (Exception e) {
+        // ignore
+      }
+    if (out != null)
+       out.closeChannel();
+  }
+  
+  @Override
+  public void setStream(GenericZipTools jzt, BufferedInputStream bis, boolean isBigEndian) {
+    if (jzt != null)
+      this.jzt = jzt;
+    if (bis != null)
+      stream = new DataInputStream(bis);
+    this.isBigEndian = isBigEndian;
+  }
+  
+  @Override
+  public void setStreamData(DataInputStream stream, boolean isBigEndian) {
+    if (stream != null)
+      this.stream = stream;
+    this.isBigEndian = isBigEndian;
+  }
+  
+  public void setRandom(boolean TF) {
+    isRandom = TF;
+    //CANNOT be random for web 
+  }
+  
+  @Override
+  public byte readByte() throws Exception {
+    nBytes++;
+    return ioReadByte();
+  }
+
+  private byte ioReadByte() throws Exception {
+    byte b = stream.readByte();
+    if (out != null)
+      out.writeByteAsInt(b);
+    return b;
+  }
+
+  @Override
+  public int readByteArray(byte[] b, int off, int len) throws Exception {
+    int n = ioRead(b, off, len);
+    nBytes += n;
+    return n;
+  }
+
+  private int ioRead(byte[] b, int off, int len) throws Exception {
+    int m = 0;
+    while (len > 0) {
+      int n = stream.read(b, off, len);
+      m += n;
+      if (n > 0 && out != null)
+        writeBytes(b, off, n);
+      if (n >= len)
+        break;
+      off += n;
+      len -= n;
+    }
+    return m;
+  }
+
+  public void writeBytes(byte[] b, int off, int n) throws Exception {
+    out.write(b, off, n);
+  }
+
+  @Override
+  public String readString(int nChar) throws Exception {
+    byte[] temp = new byte[nChar];
+    int n = readByteArray(temp, 0, nChar);
+    return new String(temp, 0, n, "UTF-8");
+  }
+  
+  @Override
+  public short readShort() throws Exception {
+    nBytes += 2;
+    short n = (isBigEndian ? ioReadShort()
+        : (short) ((ioReadByte() & 0xff) 
+                 | (ioReadByte() & 0xff) << 8));
+    /**
+     * @j2sNative
+     *
+     * return (n > 0x7FFF ? n - 0x10000 : n);
+     */
+    {
+      return n;
+    }
+  }
+
+  private short ioReadShort() throws Exception {
+    short b = stream.readShort();
+    if (out != null)
+      writeShort(b);
+    return b;
+  }
+
+
+  public void writeShort(short i) throws Exception {
+    out.writeByteAsInt(i >> 8);
+    out.writeByteAsInt(i);
+  }
+
+  @Override
+  public int readIntLE() throws Exception {
+    nBytes += 4;
+    return readLEInt();
+  }
+  
+  @Override
+  public int readInt() throws Exception {
+    nBytes += 4;
+    return (isBigEndian ? ioReadInt() : readLEInt());
+  }
+  
+  private int ioReadInt() throws Exception {
+    int i = stream.readInt();
+    if (out != null)
+      writeInt(i);
+    return i;
+  }
+
+  public void writeInt(int i) throws Exception {
+    out.writeByteAsInt(i >> 24);
+    out.writeByteAsInt(i >> 16);
+    out.writeByteAsInt(i >> 8);
+    out.writeByteAsInt(i);
+  }
+
+  @Override
+  public int swapBytesI(int n) {
+    return (((n >> 24) & 0xff)
+        | ((n >> 16) & 0xff) << 8
+        | ((n >> 8) & 0xff) << 16 
+        | (n & 0xff) << 24);
+  }
+
+  @Override
+  public short swapBytesS(short n) {
+    return (short) ((((n >> 8) & 0xff)
+        | (n & 0xff) << 8));
+  }
+
+  
+  @Override
+  public int readUnsignedShort() throws Exception {
+    nBytes += 2;
+    int a = (ioReadByte() & 0xff);
+    int b = (ioReadByte() & 0xff);
+    return (isBigEndian ? (a << 8) + b : (b << 8) + a);
+  }
+  
+  @Override
+  public long readLong() throws Exception {
+    nBytes += 8;
+    return (isBigEndian ? ioReadLong()
+       : ((((long) ioReadByte()) & 0xff)
+        | (((long) ioReadByte()) & 0xff) << 8
+        | (((long) ioReadByte()) & 0xff) << 16
+        | (((long) ioReadByte()) & 0xff) << 24
+        | (((long) ioReadByte()) & 0xff) << 32
+        | (((long) ioReadByte()) & 0xff) << 40
+        | (((long) ioReadByte()) & 0xff) << 48 
+        | (((long) ioReadByte()) & 0xff) << 54));
+  }
+
+  private long ioReadLong() throws Exception {
+    long b = stream.readLong();
+    if (out != null)
+      writeLong(b);
+    return b;
+  }
+
+  public void writeLong(long b) throws Exception {
+    writeInt((int)((b >> 32) & 0xFFFFFFFFl));
+    writeInt((int)(b & 0xFFFFFFFFl));
+  }
+
+  private int readLEInt() throws Exception {
+    ioRead(t8, 0, 4);
+    return bytesToInt(t8, 0, false);
+  }
+
+  byte[] t8 = new byte[8];
+  
+  @Override
+  public float readFloat() throws Exception {
+    return intToFloat(readInt());
+  }
+
+  @Override
+  public double readDouble() throws Exception {
+    /**
+     * 
+     * reading the float equivalent here in JavaScript
+     * 
+     * @j2sNative
+     * 
+     * this.readByteArray(this.t8, 0, 8);
+     * return this.bytesToDoubleToFloat(this.t8, 0, this.isBigEndian);
+     *  
+     */
+    {
+      nBytes += 8;
+      return (isBigEndian ? ioReadDouble() : Double.longBitsToDouble(readLELong()));  
+    }
+  }
+  
+  private double ioReadDouble() throws Exception {
+    double d = stream.readDouble();
+    if (out != null)
+      writeLong(Double.doubleToRawLongBits(d));
+    return d;
+  }
+
+  private long readLELong() throws Exception {
+    return ((((long) ioReadByte()) & 0xff)
+          | (((long) ioReadByte()) & 0xff) << 8
+          | (((long) ioReadByte()) & 0xff) << 16 
+          | (((long) ioReadByte()) & 0xff) << 24
+          | (((long) ioReadByte()) & 0xff) << 32
+          | (((long) ioReadByte()) & 0xff) << 40
+          | (((long) ioReadByte()) & 0xff) << 48
+          | (((long) ioReadByte()) & 0xff) << 56);
+  }
+
+  @Override
+  public void seek(long offset) {
+    // slower, but all that is available using the applet
+    try {
+      if (offset == nBytes)
+        return;
+      if (offset < nBytes) {
+        stream.reset();
+        if (out != null && nBytes != 0)
+          out.reset();
+        nBytes = 0;
+      } else {
+        offset -= nBytes;
+      }
+      if (out == null) {
+        stream.skipBytes((int)offset);
+      } else {
+        readByteArray(new byte[(int)offset], 0, (int) offset);
+      }
+      nBytes += offset;
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+  }
+
+  long nBytes;
+  
+  @Override
+  public long getPosition() {
+    return nBytes;
+  }
+
+  OC out;
+  @Override
+  public void setOutputChannel(OC out) {
+      this.out = out;
+  }
+
+  @Override
+  public SB getAllDataFiles(String binaryFileList, String firstFile) {
+    return null;
+  }
+
+  @Override
+  public void getAllDataMapped(String replace, String string,
+                               Map<String, String> fileData) {
+  }
+
+
+/*  random access -- application only:
+ * 
+    void seekFile(long offset) {
+    try {
+      file.seek(offset);
+    } catch (Exception e) {
+      System.out.println(e.getMessage());
+    }
+  }
+*/
+}
diff --git a/src/javajs/util/CU.java b/src/javajs/util/CU.java
new file mode 100644 (file)
index 0000000..f28657a
--- /dev/null
@@ -0,0 +1,550 @@
+package javajs.util;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import javajs.api.GenericColor;
+
+/**
+ * ColorUtility 
+ * 
+ */
+
+public class CU {
+
+  public static String toRGBHexString(GenericColor c) {
+    int rgb = c.getRGB();    
+    if (rgb == 0)
+      return "000000";
+    String r  = "00" + Integer.toHexString((rgb >> 16) & 0xFF);
+    r = r.substring(r.length() - 2);
+    String g  = "00" + Integer.toHexString((rgb >> 8) & 0xFF);
+    g = g.substring(g.length() - 2);
+    String b  = "00" + Integer.toHexString(rgb & 0xFF);
+    b = b.substring(b.length() - 2);
+    return r + g + b;
+  }
+
+  public static String toCSSString(GenericColor c) {
+    int opacity = c.getOpacity255();
+    if (opacity == 255)
+      return "#" + toRGBHexString(c);
+    int rgb = c.getRGB();
+    return "rgba(" + ((rgb>>16)&0xFF) + "," + ((rgb>>8)&0xff) + "," + (rgb&0xff) + "," + opacity/255f  + ")"; 
+  }
+  
+  private final static String[] colorNames = {
+    "black",                // 000000
+    "pewhite",              // ffffff
+    "pecyan",               // 00ffff
+    "pepurple",             // d020ff
+    "pegreen",              // 00ff00
+    "peblue",               // 6060ff
+    "peviolet",             // ff80c0
+    "pebrown",              // a42028
+    "pepink",               // ffd8d8
+    "peyellow",             // ffff00
+    "pedarkgreen",          // 00c000
+    "peorange",             // ffb000
+    "pelightblue",          // b0b0ff
+    "pedarkcyan",           // 00a0a0
+    "pedarkgray",           // 606060
+  
+    "aliceblue",            // F0F8FF
+    "antiquewhite",         // FAEBD7
+    "aqua",                 // 00FFFF
+    "aquamarine",           // 7FFFD4
+    "azure",                // F0FFFF
+    "beige",                // F5F5DC
+    "bisque",               // FFE4C4
+    "blanchedalmond",       // FFEBCD
+    "blue",                 // 0000FF
+    "blueviolet",           // 8A2BE2
+    "brown",                // A52A2A
+    "burlywood",            // DEB887
+    "cadetblue",            // 5F9EA0
+    "chartreuse",           // 7FFF00
+    "chocolate",            // D2691E
+    "coral",                // FF7F50
+    "cornflowerblue",       // 6495ED
+    "cornsilk",             // FFF8DC
+    "crimson",              // DC143C
+    "cyan",                 // 00FFFF
+    "darkblue",             // 00008B
+    "darkcyan",             // 008B8B
+    "darkgoldenrod",        // B8860B
+    "darkgray",             // A9A9A9
+    "darkgreen",            // 006400
+    "darkkhaki",            // BDB76B
+    "darkmagenta",          // 8B008B
+    "darkolivegreen",       // 556B2F
+    "darkorange",           // FF8C00
+    "darkorchid",           // 9932CC
+    "darkred",              // 8B0000
+    "darksalmon",           // E9967A
+    "darkseagreen",         // 8FBC8F
+    "darkslateblue",        // 483D8B
+    "darkslategray",        // 2F4F4F
+    "darkturquoise",        // 00CED1
+    "darkviolet",           // 9400D3
+    "deeppink",             // FF1493
+    "deepskyblue",          // 00BFFF
+    "dimgray",              // 696969
+    "dodgerblue",           // 1E90FF
+    "firebrick",            // B22222
+    "floralwhite",          // FFFAF0 16775920
+    "forestgreen",          // 228B22
+    "fuchsia",              // FF00FF
+    "gainsboro",            // DCDCDC
+    "ghostwhite",           // F8F8FF
+    "gold",                 // FFD700
+    "goldenrod",            // DAA520
+    "gray",                 // 808080
+    "green",                // 008000
+    "greenyellow",          // ADFF2F
+    "honeydew",             // F0FFF0
+    "hotpink",              // FF69B4
+    "indianred",            // CD5C5C
+    "indigo",               // 4B0082
+    "ivory",                // FFFFF0
+    "khaki",                // F0E68C
+    "lavender",             // E6E6FA
+    "lavenderblush",        // FFF0F5
+    "lawngreen",            // 7CFC00
+    "lemonchiffon",         // FFFACD
+    "lightblue",            // ADD8E6
+    "lightcoral",           // F08080
+    "lightcyan",            // E0FFFF
+    "lightgoldenrodyellow", // FAFAD2
+    "lightgreen",           // 90EE90
+    "lightgrey",            // D3D3D3
+    "lightpink",            // FFB6C1
+    "lightsalmon",          // FFA07A
+    "lightseagreen",        // 20B2AA
+    "lightskyblue",         // 87CEFA
+    "lightslategray",       // 778899
+    "lightsteelblue",       // B0C4DE
+    "lightyellow",          // FFFFE0
+    "lime",                 // 00FF00
+    "limegreen",            // 32CD32
+    "linen",                // FAF0E6
+    "magenta",              // FF00FF
+    "maroon",               // 800000
+    "mediumaquamarine",     // 66CDAA
+    "mediumblue",           // 0000CD
+    "mediumorchid",         // BA55D3
+    "mediumpurple",         // 9370DB
+    "mediumseagreen",       // 3CB371
+    "mediumslateblue",      // 7B68EE
+    "mediumspringgreen",    // 00FA9A
+    "mediumturquoise",      // 48D1CC
+    "mediumvioletred",      // C71585
+    "midnightblue",         // 191970
+    "mintcream",            // F5FFFA
+    "mistyrose",            // FFE4E1
+    "moccasin",             // FFE4B5
+    "navajowhite",          // FFDEAD
+    "navy",                 // 000080
+    "oldlace",              // FDF5E6
+    "olive",                // 808000
+    "olivedrab",            // 6B8E23
+    "orange",               // FFA500
+    "orangered",            // FF4500
+    "orchid",               // DA70D6
+    "palegoldenrod",        // EEE8AA
+    "palegreen",            // 98FB98
+    "paleturquoise",        // AFEEEE
+    "palevioletred",        // DB7093
+    "papayawhip",           // FFEFD5
+    "peachpuff",            // FFDAB9
+    "peru",                 // CD853F
+    "pink",                 // FFC0CB
+    "plum",                 // DDA0DD
+    "powderblue",           // B0E0E6
+    "purple",               // 800080
+    "red",                  // FF0000
+    "rosybrown",            // BC8F8F
+    "royalblue",            // 4169E1
+    "saddlebrown",          // 8B4513
+    "salmon",               // FA8072
+    "sandybrown",           // F4A460
+    "seagreen",             // 2E8B57
+    "seashell",             // FFF5EE
+    "sienna",               // A0522D
+    "silver",               // C0C0C0
+    "skyblue",              // 87CEEB
+    "slateblue",            // 6A5ACD
+    "slategray",            // 708090
+    "snow",                 // FFFAFA 16775930
+    "springgreen",          // 00FF7F
+    "steelblue",            // 4682B4
+    "tan",                  // D2B48C
+    "teal",                 // 008080
+    "thistle",              // D8BFD8
+    "tomato",               // FF6347
+    "turquoise",            // 40E0D0
+    "violet",               // EE82EE
+    "wheat",                // F5DEB3
+    "white",                // FFFFFF 16777215
+    "whitesmoke",           // F5F5F5
+    "yellow",               // FFFF00
+    "yellowgreen",          // 9ACD32
+    // plus a few rasmol names/values
+    "bluetint",             // AFD7FF
+    "greenblue",            // 2E8B57
+    "greentint",            // 98FFB3
+    "grey",                 // 808080
+    "pinktint",             // FFABBB
+    "redorange",            // FF4500
+    "yellowtint",           // F6F675
+  };
+  
+  private final static int[] colorArgbs = {
+  //#FFFFC3 hover
+    0xFF000000, // black
+    // plus the PE chain colors
+    0xFFffffff, // pewhite
+    0xFF00ffff, // pecyan
+    0xFFd020ff, // pepurple
+    0xFF00ff00, // pegreen
+    0xFF6060ff, // peblue
+    0xFFff80c0, // peviolet
+    0xFFa42028, // pebrown
+    0xFFffd8d8, // pepink
+    0xFFffff00, // peyellow
+    0xFF00c000, // pedarkgreen
+    0xFFffb000, // peorange
+    0xFFb0b0ff, // pelightblue
+    0xFF00a0a0, // pedarkcyan
+    0xFF606060, // pedarkgray
+    // standard JavaScript
+    0xFFF0F8FF, // aliceblue
+    0xFFFAEBD7, // antiquewhite
+    0xFF00FFFF, // aqua
+    0xFF7FFFD4, // aquamarine
+    0xFFF0FFFF, // azure
+    0xFFF5F5DC, // beige
+    0xFFFFE4C4, // bisque
+    0xFFFFEBCD, // blanchedalmond
+    0xFF0000FF, // blue
+    0xFF8A2BE2, // blueviolet
+    0xFFA52A2A, // brown
+    0xFFDEB887, // burlywood
+    0xFF5F9EA0, // cadetblue
+    0xFF7FFF00, // chartreuse
+    0xFFD2691E, // chocolate
+    0xFFFF7F50, // coral
+    0xFF6495ED, // cornflowerblue
+    0xFFFFF8DC, // cornsilk
+    0xFFDC143C, // crimson
+    0xFF00FFFF, // cyan
+    0xFF00008B, // darkblue
+    0xFF008B8B, // darkcyan
+    0xFFB8860B, // darkgoldenrod
+    0xFFA9A9A9, // darkgray
+    0xFF006400, // darkgreen
+  
+    0xFFBDB76B, // darkkhaki
+    0xFF8B008B, // darkmagenta
+    0xFF556B2F, // darkolivegreen
+    0xFFFF8C00, // darkorange
+    0xFF9932CC, // darkorchid
+    0xFF8B0000, // darkred
+    0xFFE9967A, // darksalmon
+    0xFF8FBC8F, // darkseagreen
+    0xFF483D8B, // darkslateblue
+    0xFF2F4F4F, // darkslategray
+    0xFF00CED1, // darkturquoise
+    0xFF9400D3, // darkviolet
+    0xFFFF1493, // deeppink
+    0xFF00BFFF, // deepskyblue
+    0xFF696969, // dimgray
+    0xFF1E90FF, // dodgerblue
+    0xFFB22222, // firebrick
+    0xFFFFFAF0, // floralwhite
+    0xFF228B22, // forestgreen
+    0xFFFF00FF, // fuchsia
+    0xFFDCDCDC, // gainsboro
+    0xFFF8F8FF, // ghostwhite
+    0xFFFFD700, // gold
+    0xFFDAA520, // goldenrod
+    0xFF808080, // gray
+    0xFF008000, // green
+    0xFFADFF2F, // greenyellow
+    0xFFF0FFF0, // honeydew
+    0xFFFF69B4, // hotpink
+    0xFFCD5C5C, // indianred
+    0xFF4B0082, // indigo
+    0xFFFFFFF0, // ivory
+    0xFFF0E68C, // khaki
+    0xFFE6E6FA, // lavender
+    0xFFFFF0F5, // lavenderblush
+    0xFF7CFC00, // lawngreen
+    0xFFFFFACD, // lemonchiffon
+    0xFFADD8E6, // lightblue
+    0xFFF08080, // lightcoral
+    0xFFE0FFFF, // lightcyan
+    0xFFFAFAD2, // lightgoldenrodyellow
+    0xFF90EE90, // lightgreen
+    0xFFD3D3D3, // lightgrey
+    0xFFFFB6C1, // lightpink
+    0xFFFFA07A, // lightsalmon
+    0xFF20B2AA, // lightseagreen
+    0xFF87CEFA, // lightskyblue
+    0xFF778899, // lightslategray
+    0xFFB0C4DE, // lightsteelblue
+    0xFFFFFFE0, // lightyellow
+    0xFF00FF00, // lime
+    0xFF32CD32, // limegreen
+    0xFFFAF0E6, // linen
+    0xFFFF00FF, // magenta
+    0xFF800000, // maroon
+    0xFF66CDAA, // mediumaquamarine
+    0xFF0000CD, // mediumblue
+    0xFFBA55D3, // mediumorchid
+    0xFF9370DB, // mediumpurple
+    0xFF3CB371, // mediumseagreen
+    0xFF7B68EE, // mediumslateblue
+    0xFF00FA9A, // mediumspringgreen
+    0xFF48D1CC, // mediumturquoise
+    0xFFC71585, // mediumvioletred
+    0xFF191970, // midnightblue
+    0xFFF5FFFA, // mintcream
+    0xFFFFE4E1, // mistyrose
+    0xFFFFE4B5, // moccasin
+    0xFFFFDEAD, // navajowhite
+    0xFF000080, // navy
+    0xFFFDF5E6, // oldlace
+    0xFF808000, // olive
+    0xFF6B8E23, // olivedrab
+    0xFFFFA500, // orange
+    0xFFFF4500, // orangered
+    0xFFDA70D6, // orchid
+    0xFFEEE8AA, // palegoldenrod
+    0xFF98FB98, // palegreen
+    0xFFAFEEEE, // paleturquoise
+    0xFFDB7093, // palevioletred
+    0xFFFFEFD5, // papayawhip
+    0xFFFFDAB9, // peachpuff
+    0xFFCD853F, // peru
+    0xFFFFC0CB, // pink
+    0xFFDDA0DD, // plum
+    0xFFB0E0E6, // powderblue
+    0xFF800080, // purple
+    0xFFFF0000, // red
+    0xFFBC8F8F, // rosybrown
+    0xFF4169E1, // royalblue
+    0xFF8B4513, // saddlebrown
+    0xFFFA8072, // salmon
+    0xFFF4A460, // sandybrown
+    0xFF2E8B57, // seagreen
+    0xFFFFF5EE, // seashell
+    0xFFA0522D, // sienna
+    0xFFC0C0C0, // silver
+    0xFF87CEEB, // skyblue
+    0xFF6A5ACD, // slateblue
+    0xFF708090, // slategray
+    0xFFFFFAFA, // snow
+    0xFF00FF7F, // springgreen
+    0xFF4682B4, // steelblue
+    0xFFD2B48C, // tan
+    0xFF008080, // teal
+    0xFFD8BFD8, // thistle
+    0xFFFF6347, // tomato
+    0xFF40E0D0, // turquoise
+    0xFFEE82EE, // violet
+    0xFFF5DEB3, // wheat
+    0xFFFFFFFF, // white
+    0xFFF5F5F5, // whitesmoke
+    0xFFFFFF00, // yellow
+    0xFF9ACD32, // yellowgreen
+    // plus a few rasmol names/values
+    0xFFAFD7FF, // bluetint
+    0xFF2E8B57, // greenblue
+    0xFF98FFB3, // greentint
+    0xFF808080, // grey
+    0xFFFFABBB, // pinktint
+    0xFFFF4500, // redorange
+    0xFFF6F675, // yellowtint
+  };
+
+  private static final Map<String, Integer> mapJavaScriptColors = new Hashtable<String, Integer>();
+
+  static {
+    for (int i = colorNames.length; --i >= 0; )
+      mapJavaScriptColors.put(colorNames[i], Integer.valueOf(colorArgbs[i]));
+  }
+
+  /**
+   * accepts [xRRGGBB] or [0xRRGGBB] or [0xFFRRGGBB] or #RRGGBB or
+   * [red,green,blue] or a valid JavaScript color
+   * 
+   * @param strColor
+   * @return 0 if invalid or integer color
+   */
+  public static int getArgbFromString(String strColor) {
+    int len = 0;
+    if (strColor == null || (len = strColor.length()) == 0)
+      return 0;
+    if (strColor.charAt(0) == '[' && strColor.charAt(len - 1) == ']') {
+      String check;
+      if (strColor.indexOf(",") >= 0) {
+        String[] tokens = PT.split(strColor.substring(1, strColor
+            .length() - 1), ",");
+        if (tokens.length != 3)
+          return 0;
+        float red = PT.parseFloat(tokens[0]);
+        float grn = PT.parseFloat(tokens[1]);
+        float blu = PT.parseFloat(tokens[2]);
+        return colorTriadToFFRGB(red, grn, blu);
+      }
+      switch (len) {
+      case 9:
+        check = "x";
+        break;
+      case 10:
+        check = "0x";
+        break;
+      default:
+        return 0;
+      }
+      if (strColor.indexOf(check) != 1)
+        return 0;
+      strColor = "#" + strColor.substring(len - 7, len - 1);
+      len = 7;
+    }
+    if (len == 7 && strColor.charAt(0) == '#') {
+      try {
+        return PT.parseIntRadix(strColor.substring(1, 7), 16) | 0xFF000000;
+      } catch (Exception e) {
+        return 0;
+      }
+    }
+    Integer boxedArgb = mapJavaScriptColors.get(strColor.toLowerCase());
+    return (boxedArgb == null ? 0 : boxedArgb.intValue());
+  }
+
+  public static int colorTriadToFFRGB(float x, float y, float z) {
+    if (x <= 1 && y <= 1 && z <= 1) {
+      if (x > 0)
+        x = x * 256 - 1;
+      if (y > 0)
+        y = y * 256 - 1;
+      if (z > 0)
+        z = z * 256 - 1;
+    }
+    return rgb((int) x, (int) y, (int) z);
+  }
+
+  public static int rgb(int red, int grn, int blu) {
+    return 0xFF000000 | (red << 16) | (grn << 8) | blu;
+  }
+
+  public final static P3 colorPtFromString(String colorName) {
+    return colorPtFromInt(getArgbFromString(colorName), null);
+  }
+
+  public final static P3 colorPtFromInt(int color, P3 pt) {
+    if (pt == null)
+      pt = new P3();
+    pt.set((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF);
+    return pt;
+  }
+
+  public static int colorPtToFFRGB(T3 pt) {
+    return colorTriadToFFRGB(pt.x, pt.y, pt.z);
+  }
+
+  public static void toRGB3f(int c, float[] f) {
+    f[0] = ((c >> 16) & 0xFF) / 255f; // red
+    f[1] = ((c >> 8) & 0xFF) / 255f;
+    f[2] = (c & 0xFF) / 255f;
+  }
+
+  /**
+   * Return a greyscale rgb value 0-FF using NTSC color lightness algorithm
+   *<p>
+   * the alpha component is set to 0xFF. If you want a value in the
+   * range 0-255 then & the result with 0xFF;
+   *
+   * @param rgb the rgb value
+   * @return a grayscale value in the range 0 - 255 decimal
+   */
+  public static int toFFGGGfromRGB(int rgb) {
+    int grey = (((2989 * ((rgb >> 16) & 0xFF)) +
+                (5870 * ((rgb >> 8) & 0xFF)) +
+                (1140 * (rgb & 0xFF)) + 5000) / 10000) & 0xFFFFFF;
+    return rgb(grey, grey, grey);
+  }
+  
+  
+  /**
+   * Convert RGB values to HSL (hue/saturation/lightness)
+   * 
+   * @param rgb
+   *        range 255 255 255
+   * @param doRound
+   *        set to false when just using this for 
+   *        for RGB -- HSL -- HSL' -- RGB' conversion
+   * 
+   * @return the HSL as P3 range 360 100 100
+   * @author hansonr
+   */
+
+  public static P3 rgbToHSL(P3 rgb, boolean doRound) {
+    // adapted from http://tips4java.wordpress.com/2009/07/05/hsl-color/
+    // see http://en.wikipedia.org/wiki/HSL_color_space
+    float r = rgb.x / 255;
+    float g = rgb.y / 255;
+    float b = rgb.z / 255;
+    float min = Math.min(r, Math.min(g, b));
+    float max = Math.max(r, Math.max(g, b));
+
+    //  lightness is just p * 50
+
+    float p = (max + min);
+    float q = (max - min);
+
+    float h = (60 * ((q == 0 ? 0 : max == r ? ((g - b) / q + 6)
+        : max == g ? (b - r) / q + 2 : (r - g) / q + 4))) % 360;
+
+    float s = q / (q == 0 ? 1 : p <= 1 ? p : 2 - p);
+
+    // we round to tenths for HSL so that we can  return enough
+    // precision to get back 1-255 in RGB
+    return (doRound ? P3.new3(Math.round(h*10)/10f, Math.round(s * 1000)/10f,
+        Math.round(p * 500)/10f) : P3.new3(h, s * 100, p * 50));
+  }
+
+  /**
+   * Convert HSL (hue/saturation/luninance) values to RGB
+   *
+   * @param hsl in the range 360, 100, 100
+   * @return the RGB as P3 range 0 to 255
+   * @author hansonr
+   */
+  public static P3 hslToRGB(P3 hsl) {
+    // adapted from http://tips4java.wordpress.com/2009/07/05/hsl-color/
+    // see http://en.wikipedia.org/wiki/HSL_color_space
+    
+    // highly condensed
+    
+    float h = Math.max(0,  Math.min(360, hsl.x)) / 60;
+    float s = Math.max(0,  Math.min(100, hsl.y)) / 100;
+    float l = Math.max(0,  Math.min(100, hsl.z)) / 100;
+
+    float p = l - (l < 0.5 ? l : 1 - l) * s;    
+    float q = 2 * (l - p); 
+        
+    float r = toRGB(p, q, h + 2);
+    float g = toRGB(p, q, h);
+    float b = toRGB(p, q, h - 2);
+    return P3.new3(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255));
+  }
+
+  private static float toRGB(float p, float q, float h) {
+    return ((h = (h + (h < 0 ? 6 : h > 6 ? -6 : 0))) < 1 ? p + q * h
+        : h < 3 ? p + q : h < 4 ? p + q * (4 - h) : p);
+  }
+
+}
diff --git a/src/javajs/util/CifDataParser.java b/src/javajs/util/CifDataParser.java
new file mode 100644 (file)
index 0000000..d0cb3fd
--- /dev/null
@@ -0,0 +1,633 @@
+package javajs.util;
+
+import java.io.BufferedReader;
+
+import java.util.Hashtable;
+
+import java.util.Map;
+
+import javajs.api.GenericCifDataParser;
+import javajs.api.GenericLineReader;
+
+
+
+public class CifDataParser implements GenericCifDataParser {
+  /**
+   *
+   * A special tokenizer class for dealing with quoted strings in CIF files.
+   * 
+   * Greek letters implemented in Jmol 13.3.9 and only for 
+   * titles and space groups. All other mark ups ignored.
+   * 
+   *<p>
+   * regarding the treatment of single quotes vs. primes in
+   * cif file, PMR wrote:
+   *</p>
+   *<p>
+   *   * There is a formal grammar for CIF
+   * (see http://www.iucr.org/iucr-top/cif/index.html)
+   * which confirms this. The textual explanation is
+   *<p />
+   *<p>
+   * 14. Matching single or double quote characters (' or ") may
+   * be used to bound a string representing a non-simple data value
+   * provided the string does not extend over more than one line.
+   *<p />
+   *<p>
+   * 15. Because data values are invariably separated from other
+   * tokens in the file by white space, such a quote-delimited
+   * character string may contain instances of the character used
+   * to delimit the string provided they are not followed by white
+   * space. For example, the data item
+   *<code>
+   *  _example  'a dog's life'
+   *</code>
+   * is legal; the data value is a dog's life.
+   *</p>
+   *<p>
+   * [PMR - the terminating character(s) are quote+whitespace.
+   * That would mean that:
+   *<code>
+   *  _example 'Jones' life'
+   *</code>
+   * would be an error
+   *</p>
+   *<p>
+   * The CIF format was developed in that late 1980's under the aegis of the
+   * International Union of Crystallography (I am a consultant to the COMCIFs 
+   * committee). It was ratified by the Union and there have been several 
+   * workshops. mmCIF is an extension of CIF which includes a relational 
+   * structure. The formal publications are:
+   *</p>
+   *<p>
+   * Hall, S. R. (1991). "The STAR File: A New Format for Electronic Data 
+   * Transfer and Archiving", J. Chem. Inform. Comp. Sci., 31, 326-333.
+   * Hall, S. R., Allen, F. H. and Brown, I. D. (1991). "The Crystallographic
+   * Information File (CIF): A New Standard Archive File for Crystallography",
+   * Acta Cryst., A47, 655-685.
+   * Hall, S.R. & Spadaccini, N. (1994). "The STAR File: Detailed 
+   * Specifications," J. Chem. Info. Comp. Sci., 34, 505-508.
+   *</p>
+   */
+  private GenericLineReader reader;
+  private BufferedReader br;
+
+  private String line;  
+  private String str;
+  private int ich;
+  private int cch;
+  private boolean wasUnQuoted;
+  private String strPeeked;
+  private int ichPeeked;
+  private int fieldCount;
+  private String[] loopData;
+  private SB fileHeader = new SB();
+  private boolean isHeader = true;
+  private String nullString = "\0";
+
+  /**
+   * Set the string value of what is returned for "." and "?"
+   * 
+   * @param nullString null here returns "." and "?"; default is "\0"
+   * 
+   */
+  public void setNullValue(String nullString) {
+    this.nullString  = nullString;    
+  }
+
+  /**
+   * A global, static map that contains field information. The assumption is that
+   * if we read a set of fields for, say, atom_site, once in a lifetime, then
+   * that should be good forever. Those are static lists. Or should be....
+   */
+  private static Map<String, Integer> htFields = new Hashtable<String, Integer>();
+  
+  ////////////////////////////////////////////////////////////////
+  // special tokenizer class
+  ////////////////////////////////////////////////////////////////
+
+  public CifDataParser() {
+    // for reflection
+  }
+    
+  private String[] fields;
+
+  @Override
+  public String getLoopData(int i) {
+    return loopData[i];
+  }
+
+  @Override
+  public int getFieldCount() {
+    return fieldCount;
+  }
+
+  @Override
+  public String getField(int i) {
+    return fields[i];
+  }
+
+  /**
+   * A Chemical Information File data parser.
+   * 
+   * Should be called immediately upon construction.
+   *  
+   * Two options; one of reader or br should be null, or reader will be
+   * ignored. Just simpler this way...
+   * 
+   * @param reader  Anything that can deliver a line of text or null
+   * @param br      A standard BufferedReader.
+   *  
+   */
+  @Override
+  public CifDataParser set(GenericLineReader reader, BufferedReader br) {
+    this.reader = reader;
+    this.br = br;
+    return this;
+  }
+
+  /**
+   * 
+   * @return commented-out section at the start of a CIF file.
+   * 
+   */
+  @Override
+  public String getFileHeader() {
+    return fileHeader.toString();
+  }
+  
+  
+  /**
+   * Parses all CIF data for a reader defined in the constructor
+   * into a standard Map structure and close the BufferedReader if
+   * it exists. 
+   * 
+   * @return Hashtable of models Vector of Hashtable data
+   */
+  @Override
+  public Map<String, Object> getAllCifData() {
+    line = "";
+    String key;
+    Map<String, Object> data = null;
+    Map<String, Object> allData = new Hashtable<String, Object>();
+    Lst<Map<String, Object>> models = new  Lst<Map<String,Object>>();
+    allData.put("models", models);
+    try {
+      while ((key = getNextToken()) != null) {
+        if (key.startsWith("global_") || key.startsWith("data_")) {
+          models.addLast(data = new Hashtable<String, Object>());
+          data.put("name", key);
+          continue;
+        }
+        if (key.startsWith("loop_")) {
+          getAllCifLoopData(data);
+          continue;
+        }
+        if (key.charAt(0) != '_') {
+          System.out.println("CIF ERROR ? should be an underscore: " + key);
+        } else {
+          String value = getNextToken();
+          if (value == null) {
+            System.out.println("CIF ERROR ? end of file; data missing: " + key);
+          } else {
+            data.put(fixKey(key), value);
+          }
+        }
+      }
+    } catch (Exception e) {
+      // ?
+    }
+    try {
+      if (br != null)
+        br.close();
+    } catch (Exception e) {
+      // ?
+    }
+    return allData;
+  }
+
+  /**
+   * create our own list of keywords and for each one create a list
+   * of data associated with that keyword. For example, a list of all 
+   * x coordinates, then a list of all y coordinates, etc.
+   * 
+   * @param data
+   * @throws Exception
+   */
+  @SuppressWarnings("unchecked")
+  private void getAllCifLoopData(Map<String, Object> data) throws Exception {
+    String key;
+    Lst<String> keyWords = new  Lst<String>();
+    while ((key = peekToken()) != null && key.charAt(0) == '_') {
+      key = fixKey(getTokenPeeked());
+      keyWords.addLast(key);
+      data.put(key, new  Lst<String>());
+    }
+    fieldCount = keyWords.size();
+    if (fieldCount == 0)
+      return;
+    loopData = new String[fieldCount];
+    while (getData())
+      for (int i = 0; i < fieldCount; i++)
+        ((Lst<String>)data.get(keyWords.get(i))).addLast(loopData[i]);
+  }
+
+  @Override
+  public String readLine() {
+    try {
+      line = (reader == null ? br.readLine() : reader.readNextLine());
+      if (line == null)
+        return null;
+      if (isHeader) {
+        if (line.startsWith("#"))
+          fileHeader.append(line).appendC('\n');
+        else
+          isHeader = false;
+      }
+      return line;
+    } catch (Exception e) {
+      return null;
+    }
+  }
+  
+  /**
+   * The work horse; a general reader for loop data.
+   * Fills loopData with fieldCount fields.
+   * 
+   * @return false if EOF
+   * @throws Exception
+   */
+  @Override
+  public boolean getData() throws Exception {
+    // line is already present, and we leave with the next line to parse
+    for (int i = 0; i < fieldCount; ++i)
+      if ((loopData[i] = getNextDataToken()) == null)
+        return false;
+    return (fieldCount > 0);
+  }
+
+  /**
+   * 
+   * Skips all associated loop data. (Skips to next control word.)
+   * 
+   * @throws Exception
+   */
+  @Override
+  public String skipLoop(boolean doReport) throws Exception {
+    String str;
+    SB ret = (doReport ? new SB() : null);
+    int n = 0;
+    while ((str = peekToken()) != null && str.charAt(0) == '_') {
+      if (ret != null)
+        ret.append(str).append("\n");
+      getTokenPeeked();
+      n++;
+    }
+    int m = 0;
+    while ((str = getNextDataToken()) != null) {
+      if (ret == null)
+        continue; 
+      ret.append(str).append(" ");
+      if ((++m % n) == 0)
+        ret.append("\n");
+    }
+    return (ret == null ? null : ret.toString());
+  }
+
+  /**
+   * 
+   * @return the next token of any kind, or null
+   * @throws Exception
+   */
+  @Override
+  public String getNextToken() throws Exception {
+    while (!strHasMoreTokens())
+      if (setStringNextLine() == null)
+        return null;
+    return nextStrToken();
+  }
+
+  /**
+   * 
+   * first checks to see if the next token is an unquoted
+   * control code, and if so, returns null 
+   * 
+   * @return next data token or null
+   * @throws Exception
+   */
+  @Override
+  public String getNextDataToken() throws Exception { 
+    String str = peekToken();
+    if (str == null)
+      return null;
+    if (wasUnQuoted)
+      if (str.charAt(0) == '_' || str.startsWith("loop_")
+          || str.startsWith("data_")
+          || str.startsWith("stop_")
+          || str.startsWith("global_"))
+        return null;
+    return getTokenPeeked();
+  }
+  
+  /**
+   * Just look at the next token. Saves it for retrieval 
+   * using getTokenPeeked()
+   * 
+   * @return next token or null if EOF
+   * @throws Exception
+   */
+  @Override
+  public String peekToken() throws Exception {
+    while (!strHasMoreTokens())
+      if (setStringNextLine() == null)
+        return null;
+    int ich = this.ich;
+    strPeeked = nextStrToken();
+    ichPeeked= this.ich;
+    this.ich = ich;
+    return strPeeked;
+  }
+  
+  /**
+   * 
+   * @return the token last acquired; may be null
+   */
+  @Override
+  public String getTokenPeeked() {
+    ich = ichPeeked;
+    return strPeeked;
+  }
+  
+  /**
+   * Used especially for data that might be multi-line data that
+   * might have unwanted white space at start or end.
+   * 
+   * @param str
+   * @return str without any leading/trailing white space, and no '\n'
+   */
+  @Override
+  public String fullTrim(String str) {
+    int pt0 = -1;
+    int pt1 = str.length();
+    while (++pt0 < pt1 && PT.isWhitespace(str.charAt(pt0))) {
+    }
+    while (--pt1 > pt0 && PT.isWhitespace(str.charAt(pt1))) {      
+    }
+    return str.substring(pt0, pt1 + 1);
+  }
+
+  private final static String grABC =
+      "ABX\u0394E\u03A6\u0393H"   // ABCDEFGH
+      + "I_K\u039BMNO\u03A0"      // I_KLMNOP
+      + "\u0398P\u03A3TY_\u03A9\u039E\u03A5Z"; // QRSTU_WXYZ
+  private final static String grabc =
+      "\u03B1\u03B2\u03C7\u03A4\u03A5\u03C6\u03B3\u03B7" // abcdefgh
+      + "\u03B9_\u03BA\u03BB\u03BC\u03BD\u03BF\u03C0"    // i_klmnop
+      + "\u03B8\u03C1\u03C3\u03C4\u03C5_\u03C9\u03BE\u03C5\u03B6"; // qrstu_wxyz
+
+  /**
+   * Only translating the basic Greek set here, not all the other stuff. See
+   * http://www.iucr.org/resources/cif/spec/version1.1/semantics#markup
+   * 
+   * @param data
+   * @return cleaned string
+   */
+  @Override
+  public String toUnicode(String data) {
+    int pt;
+    try {
+      while ((pt = data.indexOf('\\')) >= 0) {
+        int c = data.charAt(pt + 1);
+        String ch = (c >= 65 && c <= 90 ? grABC.substring(c - 65, c - 64)
+            : c >= 97 && c <= 122 ? grabc.substring(c - 97, c - 96) : "_");
+        data = data.substring(0, pt) + ch + data.substring(pt + 2);
+      }
+    } catch (Exception e) {
+      // ignore
+    }
+
+    return data;
+  }
+
+  /**
+   * Passing an array of field names, this method fills two arrays. 
+   * The first, fieldOf, identifies 
+   * It does this by first creating a map of names to their indices in fields[].
+   * 
+   * Alternatively, if fields is null, then a private array is filled, in order, 
+   * with key data. This is used in cases such as matrices for which there are simply
+   * too many possibilities to list, and the key name itself contains the x-y 
+   * information that we need.
+   * 
+   */
+   @Override
+  public int parseLoopParameters(String[] fields, int[] fieldOf, int[] propertyOf) throws Exception {
+     int propertyCount = 0;
+     if (fields == null) {
+       // for reading full list of keys, as for matrices
+       this.fields = new String[100];
+     } else {
+       if (!htFields.containsKey(fields[0]))
+         for (int i = fields.length; --i >= 0;)
+           htFields.put(fields[i], Integer.valueOf(i));
+       for (int i = fields.length; --i >= 0;)
+         fieldOf[i] = NONE;
+       propertyCount = fields.length;
+     }
+     fieldCount = 0;
+     while (true) {
+       String str = peekToken();
+       if (str == null) {
+         // we are PREMATURELY done; reset
+         fieldCount = 0;
+         break;
+       }
+       // end of the loop is a new token starting with underscore
+       if (str.charAt(0) != '_')
+         break;
+       
+       int pt = fieldCount++;
+       str = fixKey(getTokenPeeked());
+       if (fields == null) {
+         // just make a linear model, saving the list
+         this.fields[propertyOf[pt] = fieldOf[pt] = pt] = str;
+         continue;
+       }
+       Integer iField = htFields.get(str);
+       int i = (iField == null ? NONE : iField.intValue());
+       if ((propertyOf[pt] = i) != NONE)
+         fieldOf[i] = pt;
+     }
+     if (fieldCount > 0)
+       loopData = new String[fieldCount];
+     return propertyCount;
+  }
+
+  @Override
+  public String fixKey(String key) {
+    // PRELIMINARY -- BilBao _magnetic
+    // PRELIMINARY -- Jana2006
+    return (PT.rep(
+        key.startsWith("_magnetic") ? key.substring(9) 
+            : key.startsWith("_jana") ? key.substring(5) 
+            : key, ".", "_").toLowerCase());
+  }
+
+  //////////////////// private methods ////////////////////
+  
+  
+  /**
+   * sets a string to be parsed from the beginning
+   * 
+   * @param str
+   */
+  private void setString(String str) {
+    this.str = line = str;
+    cch = (str == null ? 0 : str.length());
+    ich = 0;
+  }
+
+  /*
+   * http://www.iucr.org/resources/cif/spec/version1.1/cifsyntax
+   * 
+   * 17. The special sequence of end-of-line followed 
+   * immediately by a semicolon in column one (denoted "<eol>;") 
+   * may also be used as a delimiter at the beginning and end 
+   * of a character string comprising a data value. The complete 
+   * bounded string is called a text field, and may be used to 
+   * convey multi-line values. The end-of-line associated with 
+   * the closing semicolon does not form part of the data value. 
+   * Within a multi-line text field, leading white space within 
+   * text lines must be retained as part of the data value; trailing 
+   * white space on a line may however be elided.
+   * 
+   * 18. A text field delimited by the <eol>; digraph may not 
+   * include a semicolon at the start of a line of text as 
+   * part of its value.
+   * 
+   * 20. For example, the data value foo may be expressed 
+   * equivalently as an unquoted string foo, as a quoted 
+   * string 'foo' or as a text field
+   *
+   *;foo
+   *;
+   *
+   * By contrast the value of the text field
+   *
+   *; foo
+   *  bar
+   *;
+   *
+   * is  foo<eol>  bar (where <eol> represents an end-of-line); 
+   * the embedded space characters are significant.
+   * 
+   * 
+   * I (BH) note, however, that we sometimes have:
+   * 
+   * _some_name
+   * ;
+   * the name here
+   * ;
+   * 
+   * so this should actually be
+   * 
+   * ;the name here
+   * ;
+   * 
+   * for this, we use fullTrim();
+   * 
+   */
+  
+  /**
+   * 
+   * sets the string for parsing to be from the next line 
+   * when the token buffer is empty, and if ';' is at the 
+   * beginning of that line, extends the string to include
+   * that full multiline string. Uses \1 to indicate that 
+   * this is a special quotation. 
+   * 
+   * @return  the next line or null if EOF
+   * @throws Exception
+   */
+  private String setStringNextLine() throws Exception {
+    setString(readLine());
+    if (line == null || line.length() == 0)
+      return line;
+    if (line.charAt(0) != ';') {
+      if (str.startsWith("###non-st#"))
+        ich = 10;
+      return line;
+    }
+    ich = 1;
+    String str = '\1' + line.substring(1) + '\n';
+    while (readLine() != null) {
+      if (line.startsWith(";")) {
+        // remove trailing <eol> only, and attach rest of next line
+        str = str.substring(0, str.length() - 1)
+          + '\1' + line.substring(1);
+        break;
+      }
+      str += line + '\n';
+    }
+    setString(str);
+    return str;
+  }
+
+  /**
+   * @return TRUE if there are more tokens in the line buffer
+   * 
+   */
+  private boolean strHasMoreTokens() {
+    if (str == null)
+      return false;
+    char ch = '#';
+    while (ich < cch && ((ch = str.charAt(ich)) == ' ' || ch == '\t'))
+      ++ich;
+    return (ich < cch && ch != '#');
+  }
+
+  /**
+   * assume that hasMoreTokens() has been called and that
+   * ich is pointing at a non-white character. Also sets
+   * boolean wasUnQuoted, because we need to know if we should 
+   * be checking for a control keyword. 'loop_' is different from just 
+   * loop_ without the quotes.
+   *
+   * @return null if no more tokens, "\0" if '.' or '?', or next token 
+   */
+  private String nextStrToken() {
+    if (ich == cch)
+      return null;
+    int ichStart = ich;
+    char ch = str.charAt(ichStart);
+    if (ch != '\'' && ch != '"' && ch != '\1') {
+      wasUnQuoted = true;
+      while (ich < cch && (ch = str.charAt(ich)) != ' ' && ch != '\t')
+        ++ich;
+      if (ich == ichStart + 1)
+        if (nullString != null && (str.charAt(ichStart) == '.' || str.charAt(ichStart) == '?'))
+          return nullString;
+      String s = str.substring(ichStart, ich);
+      return s;
+    }
+    wasUnQuoted = false;
+    char chOpeningQuote = ch;
+    boolean previousCharacterWasQuote = false;
+    while (++ich < cch) {
+      ch = str.charAt(ich);
+      if (previousCharacterWasQuote && (ch == ' ' || ch == '\t'))
+        break;
+      previousCharacterWasQuote = (ch == chOpeningQuote);
+    }
+    if (ich == cch) {
+      if (previousCharacterWasQuote) // close quote was last char of string
+        return str.substring(ichStart + 1, ich - 1);
+      // reached the end of the string without finding closing '
+      return str.substring(ichStart, ich);
+    }
+    ++ich; // throw away the last white character
+    return str.substring(ichStart + 1, ich - 2);
+  }
+
+  
+}
\ No newline at end of file
diff --git a/src/javajs/util/CompoundDocDirEntry.java b/src/javajs/util/CompoundDocDirEntry.java
new file mode 100644 (file)
index 0000000..3eaab5e
--- /dev/null
@@ -0,0 +1,93 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2011  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+
+class CompoundDocDirEntry {
+
+  private final CompoundDocument cd;
+
+  /**
+   * @param compoundDocument
+   */
+  CompoundDocDirEntry(CompoundDocument compoundDocument) {
+    cd = compoundDocument;
+  }
+
+  // 128 bytes
+  //offset 0:
+  byte[] unicodeName64 = new byte[64];
+  short nBytesUnicodeName; // twice the ascii length, including terminating 0
+  byte entryType; // 0 empty; 1 storage; 2 stream; 5 root storage
+  //byte entryColor; // 0 red or 1 black
+  //int DIDchildLeft;
+  //int DIDchildRight;
+  //int DIDstorageRoot;
+  byte[] uniqueID16 = new byte[16];
+  byte[] userflags4 = new byte[4];
+  //long timeStamp1;
+  //long timeStamp2;
+  //offset 116:
+  int SIDfirstSector; // either SAT or SSAT
+  int lenStream;
+  byte[] unused = new byte[8];
+
+  // derived:
+
+  String entryName;
+  boolean isStandard;
+  boolean isEmpty;
+
+  final boolean readData() {
+    try {
+      cd.readByteArray(unicodeName64, 0, 64);
+      nBytesUnicodeName = cd.readShort();
+      entryType = cd.readByte();
+      /*entryColor = */cd.readByte();
+      /*DIDchildLeft = */cd.readInt();
+      /*DIDchildRight = */cd.readInt();
+      /*DIDstorageRoot = */cd.readInt();
+      cd.readByteArray(uniqueID16, 0, 16);
+      cd.readByteArray(userflags4, 0, 4);
+      /*timeStamp1 = */      cd.readByteArray(unused, 0, 8);//cd.readLong();
+      /*timeStamp2 = */      cd.readByteArray(unused, 0, 8);//cd.readLong();
+      //offset 116:
+      SIDfirstSector = cd.readInt();
+      lenStream = cd.readInt();
+      cd.readByteArray(unused, 0, 4);
+    } catch (Exception e) {
+      System.out.println(e.toString());
+      return false;
+    }
+    entryName = "";
+    for (int i = 0; i < nBytesUnicodeName - 2; i += 2)
+      entryName += (char) unicodeName64[i];
+    isStandard = (entryType == 5 || lenStream >= cd.header.minBytesStandardStream);
+    isEmpty = (entryType == 0 || lenStream <= 0);
+    //System.out.println(entryName + " type " + entryType);
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/src/javajs/util/CompoundDocHeader.java b/src/javajs/util/CompoundDocHeader.java
new file mode 100644 (file)
index 0000000..e81c79e
--- /dev/null
@@ -0,0 +1,112 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2011  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+
+class CompoundDocHeader {
+
+  /**
+   * 
+   */
+  private final CompoundDocument cd;
+
+  /**
+   * @param compoundDocument
+   */
+  CompoundDocHeader(CompoundDocument compoundDocument) {
+    cd = compoundDocument;
+  }
+
+  //512 bytes
+  //offset 0:
+  byte[] magicNumbers = new byte[8]; // D0CF11E0A1B11AE1
+  byte[] uniqueID16 = new byte[16];
+  byte revNumber; // 3E = 62
+  //byte unusedb1;
+  byte verNumber; // 3
+  //byte unusedb2;
+  //short byteOrder; // -2 littleEndian
+  short sectorPower; // 2^sectorPower = sector size; 512 = 2^9
+  short shortSectorPower; // 2^shortSectorPower = short sector size; 64 = 2^6
+  byte[] unused = new byte[10];
+  int nSATsectors; // number of sectors for sector allocation table
+  int SID_DIR_start; // sector identifier of start of directory sector
+  //offset 56:
+  int minBytesStandardStream; // less than this (and not DIR) will be "short"
+  int SID_SSAT_start; // start of short sector allocation table (SSAT)
+  int nSSATsectors; // number of sectors allocated to SSAT
+  int SID_MSAT_next; // pointer to next master sector allocation table sector
+  int nAdditionalMATsectors; // number of sectors allocated to more MSAT sectors
+  //offset 76; 436 bytes:      
+  int[] MSAT0 = new int[109]; // beginning of master allocation table 
+
+  /*
+   *  Sector 0 is first sector AFTER this header
+   *  
+   *  If sectorPower = 9, then this allows for 109 PAGES
+   *  of sector allocation tables, with 127 pointers per
+   *  page (plus 1 pointer to the next SAT page), each 
+   *  pointing to a sector of 512 bytes. Thus, with no additional
+   *  MSAT pages, the header allows for 109*128*512 = 7.1 Mb file
+   *  
+   */
+
+  final boolean readData() {
+    try {
+      cd.readByteArray(magicNumbers, 0, 8);
+      if (magicNumbers[0] != (byte) 0xD0 || magicNumbers[1] != (byte) 0xCF
+          || magicNumbers[2] != (byte) 0x11 || magicNumbers[3] != (byte) 0xE0
+          || magicNumbers[4] != (byte) 0xA1 || magicNumbers[5] != (byte) 0xB1
+          || magicNumbers[6] != (byte) 0x1A || magicNumbers[7] != (byte) 0xE1)
+        return false;
+      cd.readByteArray(uniqueID16, 0, 16);
+      revNumber = cd.readByte();
+      cd.readByte();
+      verNumber = cd.readByte();
+      cd.readByte();
+      byte b1 = cd.readByte();
+      byte b2 = cd.readByte();
+      cd.isBigEndian = (b1 == -1 && b2 == -2);
+      sectorPower = cd.readShort();
+      shortSectorPower = cd.readShort();
+      cd.readByteArray(unused, 0, 10);
+      nSATsectors = cd.readInt();
+      SID_DIR_start = cd.readInt();
+      cd.readByteArray(unused, 0, 4);
+      minBytesStandardStream = cd.readInt();
+      SID_SSAT_start = cd.readInt();
+      nSSATsectors = cd.readInt();
+      SID_MSAT_next = cd.readInt();
+      nAdditionalMATsectors = cd.readInt();
+      for (int i = 0; i < 109; i++)
+        MSAT0[i] = cd.readInt();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+      return false;
+    }
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/src/javajs/util/CompoundDocument.java b/src/javajs/util/CompoundDocument.java
new file mode 100644 (file)
index 0000000..15168a5
--- /dev/null
@@ -0,0 +1,395 @@
+/* $RCSfile$
+ * $Author: egonw $
+ * $Date: 2006-03-18 15:59:33 -0600 (Sat, 18 Mar 2006) $
+ * $Revision: 4652 $
+ *
+ * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
+ *
+ * Contact: hansonr@stolaf.edu
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+
+import java.io.DataInputStream;
+import java.io.BufferedInputStream;
+
+
+import java.util.Map;
+
+import javajs.api.GenericZipTools;
+
+
+
+/* a simple compound document reader. 
+ * See http://sc.openoffice.org/compdocfileformat.pdf
+ * 
+ * random access file info: 
+ * http://java.sun.com/docs/books/tutorial/essential/io/rafs.html
+ * 
+ * SHOOT! random access is only for applications, not applets!
+ * 
+ * With a bit more work, this could be set up to deliver binary files, but
+ * right now I've only implemented it for string-based data. All Jmol is using
+ * is getAllData().
+ * 
+ */
+
+public class CompoundDocument extends BinaryDocument{
+
+//  RandomAccessFile file;
+  CompoundDocHeader header = new CompoundDocHeader(this);
+  Lst<CompoundDocDirEntry> directory = new  Lst<CompoundDocDirEntry>();
+  CompoundDocDirEntry rootEntry;
+
+  int[] SAT;
+  int[] SSAT;
+  int sectorSize;
+  int shortSectorSize;
+  int nShortSectorsPerStandardSector;
+  int nIntPerSector;
+  int nDirEntriesperSector;
+
+  // called by reflection
+  
+  public CompoundDocument(){
+    super();
+    this.isBigEndian = true;
+  }
+  
+  @Override
+  public void setStream(GenericZipTools jzt, BufferedInputStream bis, boolean isBigEndian) {
+    // isBigEndian is ignored here; it must be true
+    /*    try {
+     file = new RandomAccessFile(fileName, "r");
+     isRandom = true;
+     } catch (Exception e) {
+     // probably an applet
+     }
+     */
+    this.jzt = jzt;
+    if (!isRandom) {
+      stream = new DataInputStream(bis);
+    }
+    stream.mark(Integer.MAX_VALUE);
+    if (!readHeader())
+      return;
+    getSectorAllocationTable();
+    getShortSectorAllocationTable();
+    getDirectoryTable();
+  }
+
+  public Lst<CompoundDocDirEntry> getDirectory() {
+    return directory;
+  }
+
+  public String getDirectoryListing(String separator) {
+    String str = "";
+    for (int i = 0; i < directory.size(); i++) {
+      CompoundDocDirEntry thisEntry = directory.get(i);
+      if (!thisEntry.isEmpty)
+        str += separator
+            + thisEntry.entryName
+            + "\tlen="
+            + thisEntry.lenStream
+            + "\tSID="
+            + thisEntry.SIDfirstSector
+            + (thisEntry.isStandard ? "\tfileOffset="
+                + getOffset(thisEntry.SIDfirstSector) : "");
+    }
+    return str;
+  }
+
+  SB data;
+  
+  public SB getAllData() {
+    return getAllDataFiles(null, null);
+  }
+
+  /**
+   * reads a compound document directory and saves all data in a Hashtable
+   * so that the files may be organized later in a different order. Also adds
+   * a #Directory_Listing entry.
+   * 
+   * Files are bracketed by BEGIN Directory Entry and END Directory Entry lines, 
+   * similar to ZipUtil.getAllData.
+   * 
+   * @param prefix
+   * @param binaryFileList   |-separated list of files that should be saved
+   *                         as xx xx xx hex byte strings. The directory listing
+   *                         is appended with ":asBinaryString"
+   * @param fileData
+   */
+  @Override
+  public void getAllDataMapped(String prefix, 
+                         String binaryFileList, Map<String, String> fileData) {
+    fileData.put("#Directory_Listing", getDirectoryListing("|"));
+    binaryFileList = "|" + binaryFileList + "|";
+    for (int i = 0; i < directory.size(); i++) {
+      CompoundDocDirEntry thisEntry = directory.get(i);
+      if (!thisEntry.isEmpty && thisEntry.entryType != 5) {
+        String name = thisEntry.entryName;
+        System.out.println("CompoundDocument file " + name);
+        boolean isBinary = (binaryFileList.indexOf("|" + name + "|") >= 0);
+        if (isBinary)
+          name += ":asBinaryString";
+        SB data = new SB();
+        data.append("BEGIN Directory Entry ").append(name).append("\n"); 
+        data.appendSB(getEntryAsString(thisEntry, isBinary));
+        data.append("\nEND Directory Entry ").append(name).append("\n");
+        fileData.put(prefix + "/" + name, data.toString());
+      }
+    }
+    close();
+  }
+
+  @Override
+  public SB getAllDataFiles(String binaryFileList, String firstFile) {
+    if (firstFile != null) {
+      for (int i = 0; i < directory.size(); i++) {
+        CompoundDocDirEntry thisEntry = directory.get(i);
+        if (thisEntry.entryName.equals(firstFile)) {
+          directory.remove(i);
+          directory.add(1, thisEntry); // after ROOT_ENTRY
+          break;
+        }
+      }
+    }
+    data = new SB();
+    data.append("Compound Document File Directory: ");
+    data.append(getDirectoryListing("|"));
+    data.append("\n");
+    binaryFileList = "|" + binaryFileList + "|";
+    for (int i = 0; i < directory.size(); i++) {
+      CompoundDocDirEntry thisEntry = directory.get(i);
+      //System.out.println("CompoundDocument reading " + thisEntry.entryName);
+      if (!thisEntry.isEmpty && thisEntry.entryType != 5) {
+        String name = thisEntry.entryName;
+        if (name.endsWith(".gz"))
+          name = name.substring(0, name.length() - 3);
+        data.append("BEGIN Directory Entry ").append(name).append("\n");            
+        data.appendSB(getEntryAsString(thisEntry, binaryFileList.indexOf("|" + thisEntry.entryName + "|") >= 0));
+        data.append("\n");
+        data.append("END Directory Entry ").append(thisEntry.entryName).append("\n");            
+      }
+    }
+    close();
+    return data;
+  }
+
+  public SB getFileAsString(String entryName) {
+    for (int i = 0; i < directory.size(); i++) {
+      CompoundDocDirEntry thisEntry = directory.get(i);
+      if (thisEntry.entryName.equals(entryName))
+        return getEntryAsString(thisEntry, false);
+    }
+    return new SB();
+  }
+
+  private long getOffset(int SID) {
+    return (SID + 1) * sectorSize;
+  }
+
+  private void gotoSector(int SID) {
+    seek(getOffset(SID));
+  }
+
+  private boolean readHeader() {
+    if (!header.readData())
+      return false;
+    sectorSize = 1 << header.sectorPower;
+    shortSectorSize = 1 << header.shortSectorPower;
+    nShortSectorsPerStandardSector = sectorSize / shortSectorSize; // e.g. 512 / 64 = 8
+    nIntPerSector = sectorSize / 4; // e.g. 512 / 4 = 128
+    nDirEntriesperSector = sectorSize / 128; // e.g. 512 / 128 = 4
+//    System.out.println(
+//          "compound document: revNum=" + header.revNumber +
+//          " verNum=" + header.verNumber + " isBigEndian=" + isBigEndian +
+//          " bytes per standard/short sector=" + sectorSize + "/" + shortSectorSize);
+    return true;
+  }
+
+  private void getSectorAllocationTable() {
+    int nSID = 0;
+    int thisSID;
+    SAT = new int[header.nSATsectors * nIntPerSector + 109];
+
+    try {
+      for (int i = 0; i < 109; i++) {
+        thisSID = header.MSAT0[i];
+        if (thisSID < 0)
+          break;
+        gotoSector(thisSID);
+        for (int j = 0; j < nIntPerSector; j++) {
+          SAT[nSID++] = readInt();
+          //Logger.debug(thisSID+"."+j + "/" + (nSID - 1) + " : " + SAT[nSID - 1]);
+        }
+      }
+      int nMaster = header.nAdditionalMATsectors;
+      thisSID = header.SID_MSAT_next;
+      int[] MSAT = new int[nIntPerSector];
+      out: while (nMaster-- > 0 && thisSID >= 0) {
+        // read a page of sector identifiers pointing to SAT sectors
+        gotoSector(thisSID);
+        for (int i = 0; i < nIntPerSector; i++)
+          MSAT[i] = readInt();
+        // read each page of SAT sector identifiers 
+        // last entry is pointer to next master sector allocation table page
+        for (int i = 0; i < nIntPerSector - 1; i++) {
+          thisSID = MSAT[i];
+          if (thisSID < 0)
+            break out;
+          gotoSector(thisSID);
+          for (int j = nIntPerSector; --j >= 0;)
+            SAT[nSID++] = readInt();
+        }
+        thisSID = MSAT[nIntPerSector - 1];
+      }
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+  }
+
+  private void getShortSectorAllocationTable() {
+    int nSSID = 0;
+    int thisSID = header.SID_SSAT_start;
+    int nMax = header.nSSATsectors * nIntPerSector;
+    SSAT = new int[nMax];
+    try {
+      while (thisSID > 0 && nSSID < nMax) {
+        gotoSector(thisSID);
+        for (int j = 0; j < nIntPerSector; j++) {
+          SSAT[nSSID++] = readInt();
+          //System.out.println("short: " + thisSID+"."+j+" SSID=" +(nSSID-1)+" "+SSAT[nSSID-1]);
+        }
+        thisSID = SAT[thisSID];
+      }
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+  }
+
+  private void getDirectoryTable() {
+    int thisSID = header.SID_DIR_start;
+    CompoundDocDirEntry thisEntry;
+    rootEntry = null;
+    try {
+      while (thisSID > 0) {
+        gotoSector(thisSID);
+        for (int j = nDirEntriesperSector; --j >= 0;) {
+          thisEntry = new CompoundDocDirEntry(this);
+          thisEntry.readData();
+          if (thisEntry.lenStream > 0) {
+            directory.addLast(thisEntry);
+            //System.out.println(thisEntry.entryName);
+          }
+          if (thisEntry.entryType == 5)
+            rootEntry = thisEntry;
+        }
+        thisSID = SAT[thisSID];
+      }
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+//    System.out.println("CompoundDocument directory entry: \n"
+//        + getDirectoryListing("\n"));
+  }
+
+  private SB getEntryAsString(CompoundDocDirEntry thisEntry, boolean asBinaryString) {
+    if(thisEntry.isEmpty)
+      return new SB();
+    //System.out.println(thisEntry.entryName + " " + thisEntry.entryType + " " + thisEntry.lenStream + " " + thisEntry.isStandard + " " + thisEntry.SIDfirstSector);
+    return (thisEntry.isStandard ? getStandardStringData(
+            thisEntry.SIDfirstSector, thisEntry.lenStream, asBinaryString)
+            : getShortStringData(thisEntry.SIDfirstSector, thisEntry.lenStream, asBinaryString));
+  }
+  private SB getStandardStringData(int thisSID, int nBytes,
+                                             boolean asBinaryString) {
+    SB data = new SB();
+    byte[] byteBuf = new byte[sectorSize];
+    ZipData gzipData = new ZipData(nBytes);
+    try {
+      while (thisSID > 0 && nBytes > 0) {
+        gotoSector(thisSID);
+        nBytes = getSectorData(data, byteBuf, sectorSize, nBytes, asBinaryString, gzipData);
+        thisSID = SAT[thisSID];
+      }
+      if (nBytes == -9999)
+        return new SB();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+    if (gzipData.isEnabled)
+      gzipData.addTo(jzt, data);
+    return data;
+  }
+
+  private int getSectorData(SB data, byte[] byteBuf,
+                            int nSectorBytes, int nBytes, 
+                            boolean asBinaryString, ZipData gzipData)
+      throws Exception {
+    readByteArray(byteBuf, 0, byteBuf.length);
+    int n = gzipData.addBytes(byteBuf, nSectorBytes, nBytes);
+    if (n >= 0)
+      return n;
+    if (asBinaryString) {
+      for (int i = 0; i < nSectorBytes; i++) {
+        data.append(Integer.toHexString(byteBuf[i] & 0xFF)).appendC(' ');
+        if (--nBytes < 1)
+          break;
+      }
+    } else {
+      for (int i = 0; i < nSectorBytes; i++) {
+        if (byteBuf[i] == 0)
+          return -9999; // don't allow binary data
+        data.appendC((char) byteBuf[i]);
+        if (--nBytes < 1)
+          break;
+      }
+    }
+    return nBytes;
+  }
+
+  private SB getShortStringData(int shortSID, int nBytes, boolean asBinaryString) {
+    SB data = new SB();
+    if (rootEntry == null)
+      return data;
+    int thisSID = rootEntry.SIDfirstSector;
+    int ptShort = 0;
+    byte[] byteBuf = new byte[shortSectorSize];
+    ZipData gzipData = new ZipData(nBytes);
+    try {
+      //System.out.println("CD shortSID=" + shortSID);
+      // point to correct short data sector, 512/64 = 4 per page
+      while (thisSID >= 0 && shortSID >= 0 && nBytes > 0) {
+        while (shortSID - ptShort >= nShortSectorsPerStandardSector) {
+          ptShort += nShortSectorsPerStandardSector;
+          thisSID = SAT[thisSID];
+        }
+        seek(getOffset(thisSID) + (shortSID - ptShort) * shortSectorSize);
+        nBytes = getSectorData(data, byteBuf, shortSectorSize, nBytes, asBinaryString, gzipData);
+        shortSID = SSAT[shortSID];
+        //System.out.println("CD shortSID=" + shortSID);
+      }
+    } catch (Exception e) {
+      System.out.println(data.toString());
+      System.out.println("reader error in CompoundDocument " + e.toString());
+    }
+    if (gzipData.isEnabled)
+      gzipData.addTo(jzt, data);
+    return data;
+  }  
+}
diff --git a/src/javajs/util/DF.java b/src/javajs/util/DF.java
new file mode 100644 (file)
index 0000000..ccff3e2
--- /dev/null
@@ -0,0 +1,161 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-04-26 16:57:51 -0500 (Thu, 26 Apr 2007) $
+ * $Revision: 7502 $
+ *
+ * Copyright (C) 2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package javajs.util;
+
+/**
+ * created to remove ambiguities and make a simpler DecimalFormat
+ */
+public class DF {
+
+  private final static String[] formattingStrings = { "0", "0.0", "0.00",
+      "0.000", "0.0000", "0.00000", "0.000000", "0.0000000", "0.00000000",
+      "0.000000000" };
+  private final static String zeros = "0000000000000000000000000000000000000000";
+
+  private final static float[] formatAdds = { 0.5f, 0.05f, 0.005f, 0.0005f,
+      0.00005f, 0.000005f, 0.0000005f, 0.00000005f, 0.000000005f, 0.0000000005f };
+
+  private final static Boolean[] useNumberLocalization = new Boolean[] { Boolean.TRUE };
+
+  public static void setUseNumberLocalization(boolean TF) {
+    useNumberLocalization[0] = (TF ? Boolean.TRUE : Boolean.FALSE);
+  }
+
+  public static String formatDecimalDbl(double value, int decimalDigits) {
+    if (decimalDigits == Integer.MAX_VALUE 
+        || value == Double.NEGATIVE_INFINITY
+        || value == Double.POSITIVE_INFINITY 
+        || Double.isNaN(value))
+      return "" + value;
+    return DF.formatDecimal((float) value, decimalDigits);
+  }
+
+  /**
+   * a simple alternative to DecimalFormat (which Java2Script does not have
+   * and which is quite too complex for our use here.)
+   * 
+   * @param value
+   * @param decimalDigits
+   * @return  formatted decimal
+   */
+  public static String formatDecimal(float value, int decimalDigits) {
+    if (decimalDigits == Integer.MAX_VALUE 
+        || value == Float.NEGATIVE_INFINITY || value == Float.POSITIVE_INFINITY || Float.isNaN(value))
+      return "" + value;
+    int n;
+    if (decimalDigits < 0) {
+      decimalDigits = -decimalDigits;
+      if (decimalDigits > formattingStrings.length)
+        decimalDigits = formattingStrings.length;
+      if (value == 0)
+        return formattingStrings[decimalDigits] + "E+0";
+      //scientific notation
+      n = 0;
+      double d;
+      if (Math.abs(value) < 1) {
+        n = 10;
+        d = value * 1e-10;
+      } else {
+        n = -10;
+        d = value * 1e10;
+      }
+      String s = ("" + d).toUpperCase();
+      int i = s.indexOf("E");
+      n = PT.parseInt(s.substring(i + 1)) + n;
+      return (i < 0 ? "" + value : formatDecimal(PT.parseFloat(s.substring(
+          0, i)), decimalDigits - 1)
+          + "E" + (n >= 0 ? "+" : "") + n);
+    }
+  
+    if (decimalDigits >= formattingStrings.length)
+      decimalDigits = formattingStrings.length - 1;
+    String s1 = ("" + value).toUpperCase();
+    int pt = s1.indexOf(".");
+    if (pt < 0) // specifically JavaScript "-2" not "-2.0"
+      return s1 + formattingStrings[decimalDigits].substring(1);
+    boolean isNeg = s1.startsWith("-");
+    if (isNeg) {
+      s1 = s1.substring(1);
+      pt--;
+    }
+    int pt1 = s1.indexOf("E-");
+    if (pt1 > 0) {
+      n = PT.parseInt(s1.substring(pt1 + 1));
+      // 3.567E-2
+      // 0.03567
+      s1 = "0." + zeros.substring(0, -n - 1) + s1.substring(0, 1) + s1.substring(2, pt1);
+      pt = 1; 
+    }
+  
+    pt1 = s1.indexOf("E");
+    // 3.5678E+3
+    // 3567.800000000
+    // 1.234E10 %3.8f -> 12340000000.00000000
+    if (pt1 > 0) {
+      n = PT.parseInt(s1.substring(pt1 + 1));
+      s1 = s1.substring(0, 1) + s1.substring(2, pt1) + zeros;
+      s1 = s1.substring(0, n + 1) + "." + s1.substring(n + 1);
+      pt = s1.indexOf(".");
+    } 
+    // "234.345667  len == 10; pt = 3
+    // "  0.0 "  decimalDigits = 1
+    
+    int len = s1.length();
+    int pt2 = decimalDigits + pt + 1;
+    if (pt2 < len && s1.charAt(pt2) >= '5') {
+      return formatDecimal(
+          value + (isNeg ? -1 : 1) * formatAdds[decimalDigits], decimalDigits);
+    }
+  
+    SB sb = SB.newS(s1.substring(0, (decimalDigits == 0 ? pt
+        : ++pt)));
+    for (int i = 0; i < decimalDigits; i++, pt++) {
+      if (pt < len)
+        sb.appendC(s1.charAt(pt));
+      else
+        sb.appendC('0');
+    }
+    s1 = (isNeg ? "-" : "") + sb;
+    return (Boolean.TRUE.equals(useNumberLocalization[0]) ? s1 : s1.replace(',',
+        '.'));
+  }
+
+  /**
+   * an alternative to DecimalFormat "0.#"
+   * 
+   * @param x
+   * @param precision
+   * @return  formatted number 
+   */
+  public static String formatDecimalTrimmed(double x, int precision) {
+    String str = formatDecimalDbl(x, precision);
+    int m = str.length() - 1;
+    char zero = '0';
+    while (m >= 0 && str.charAt(m) == zero)
+      m--;
+    return str.substring(0, m + 1); // 0.##...
+  }
+
+}
diff --git a/src/javajs/util/DataReader.java b/src/javajs/util/DataReader.java
new file mode 100644 (file)
index 0000000..1eb8ade
--- /dev/null
@@ -0,0 +1,56 @@
+package javajs.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+
+/**
+ * Just a simple abstract class to join a String reader and a String[]
+ * reader under the same BufferedReader umbrella.
+ * 
+ * Subclassed as StringDataReader, ArrayDataReader, and ListDataReader
+ * 
+ */
+
+public abstract class DataReader extends BufferedReader {
+
+  public abstract DataReader setData(Object data);
+  
+  protected int ptMark;
+
+  public DataReader() {
+    super(new StringReader(""));
+  }
+
+  protected DataReader(Reader in) {
+    super(in);
+  }
+
+  public BufferedReader getBufferedReader() {
+    return this;
+  }
+
+  protected int readBuf(char[] buf, int off, int len) throws IOException {
+    // not used by StringDataReader
+    int nRead = 0;
+    String line = readLine();
+    if (line == null)
+      return 0;
+    int linept = 0;
+    int linelen = line.length();
+    for (int i = off; i < len && linelen >= 0; i++) {
+      if (linept >= linelen) {
+        linept = 0;
+        buf[i] = '\n';
+        line = readLine();
+        linelen = (line == null ? -1 : line.length());
+      } else {
+        buf[i] = line.charAt(linept++);
+      }
+      nRead++;
+    }
+    return nRead;
+  }
+
+}
\ No newline at end of file
diff --git a/src/javajs/util/Eigen.java b/src/javajs/util/Eigen.java
new file mode 100644 (file)
index 0000000..f7b5adf
--- /dev/null
@@ -0,0 +1,1060 @@
+/* $RCSfile$
+ * $Author: egonw $
+ * $Date: 2005-11-10 09:52:44f -0600 (Thu, 10 Nov 2005) $
+ * $Revision: 4255 $
+ *
+ * Copyright (C) 2003-2005  Miguel, Jmol Development, www.jmol.org
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package javajs.util;
+
+import javajs.api.EigenInterface;
+
+
+/**
+ * Eigenvalues and eigenvectors of a real matrix.
+ * See javajs.api.EigenInterface() as well.
+ * 
+ * adapted by Bob Hanson from http://math.nist.gov/javanumerics/jama/ (public
+ * domain); adding quaternion superimposition capability; removing
+ * nonsymmetric reduction to Hessenberg form, which we do not need in Jmol.
+ * 
+ * Output is as a set of double[n] columns, but for the EigenInterface
+ * we return them as V3[3] and float[3] (or double[3]) values.
+ * 
+ * Eigenvalues and eigenvectors are sorted from smallest to largest eigenvalue.
+ * 
+ * <P>
+ * If A is symmetric, then A = V*D*V' where the eigenvalue matrix D is diagonal
+ * and the eigenvector matrix V is orthogonal. I.e. A =
+ * V.times(D.times(V.transpose())) and V.times(V.transpose()) equals the
+ * identity matrix.
+ * <P>
+ * If A is not symmetric, then the eigenvalue matrix D is block diagonal with
+ * the real eigenvalues in 1-by-1 blocks and any complex eigenvalues, lambda +
+ * i*mu, in 2-by-2 blocks, [lambda, mu; -mu, lambda]. The columns of V represent
+ * the eigenvectors in the sense that A*V = V*D, i.e. A.times(V) equals
+ * V.times(D). The matrix V may be badly conditioned, or even singular, so the
+ * validity of the equation A = V*D*inverse(V) depends upon V.cond().
+ **/
+
+public class Eigen implements EigenInterface {
+
+  /* ------------------------
+  Public Methods
+  * ------------------------ */
+
+  public Eigen() {}
+  
+  public Eigen set(int n) {
+    this.n = n;
+    V = new double[n][n];
+    d = new double[n];
+    e = new double[n];
+    return this;
+  }
+
+  @Override
+  public Eigen setM(double[][] m) {
+    set(m.length);
+    calc(m);
+    return this;
+  }
+
+  /**
+   * return values sorted from smallest to largest value.
+   */
+  @Override
+  public double[] getEigenvalues() {
+    return d;
+  }
+
+  /**
+   * Specifically for 3x3 systems, returns eigenVectors as V3[3]
+   * and values as float[3]; sorted from smallest to largest value.
+   * 
+   * @param eigenVectors  returned vectors
+   * @param eigenValues   returned values
+   * 
+   */
+  @Override
+  public void fillFloatArrays(V3[] eigenVectors, float[] eigenValues) {
+    for (int i = 0; i < 3; i++) {
+      if (eigenVectors != null) {
+        if (eigenVectors[i] == null)
+          eigenVectors[i] = new V3();
+        eigenVectors[i].set((float) V[0][i], (float) V[1][i], (float) V[2][i]);
+      }
+      if (eigenValues != null)
+        eigenValues[i] = (float) d[i];
+    }
+  }
+
+  /**
+   * Transpose V and turn into floats; sorted from smallest to largest value.
+   * 
+   * @return ROWS of eigenvectors f[0], f[1], f[2], etc.
+   */
+  @Override
+  public float[][] getEigenvectorsFloatTransposed() {
+    float[][] f = new float[n][n];
+    for (int i = n; --i >= 0;)
+      for (int j = n; --j >= 0;)
+        f[j][i] = (float) V[i][j];
+    return f;
+  }
+
+
+  /**
+   * Check for symmetry, then construct the eigenvalue decomposition
+   * 
+   * @param A
+   *        Square matrix
+   */
+
+  public void calc(double[][] A) {
+
+    /* Jmol only has need of symmetric solutions 
+     * 
+    issymmetric = true;
+    
+    for (int j = 0; (j < n) & issymmetric; j++) {
+      for (int i = 0; (i < n) & issymmetric; i++) {
+        issymmetric = (A[i][j] == A[j][i]);
+      }
+    }
+
+    if (issymmetric) {
+     */
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        V[i][j] = A[i][j];
+      }
+    }
+
+    // Tridiagonalize.
+    tred2();
+
+    // Diagonalize.
+    tql2();
+    /*
+      } else {
+        H = new double[n][n];
+        ort = new double[n];
+
+        for (int j = 0; j < n; j++) {
+          for (int i = 0; i < n; i++) {
+            H[i][j] = A[i][j];
+          }
+        }
+
+        // Reduce to Hessenberg form.
+        orthes();
+
+        // Reduce Hessenberg to real Schur form.
+        hqr2();
+      }
+    */
+
+  }
+
+  /**
+   * Return the real parts of the eigenvalues
+   * 
+   * @return real(diag(D))
+   */
+
+  public double[] getRealEigenvalues() {
+    return d;
+  }
+
+  /**
+   * Return the imaginary parts of the eigenvalues
+   * 
+   * @return imag(diag(D))
+   */
+
+  public double[] getImagEigenvalues() {
+    return e;
+  }
+
+  /* ------------------------
+     Class variables
+   * ------------------------ */
+
+  /**
+   * Row and column dimension (square matrix).
+   * 
+   * @serial matrix dimension.
+   */
+  private int n = 3;
+
+  /**
+   * Symmetry flag.
+   * 
+   * @serial internal symmetry flag.
+   */
+  //private boolean issymmetric = true;
+
+  /**
+   * Arrays for internal storage of eigenvalues.
+   * 
+   * @serial internal storage of eigenvalues.
+   */
+  private double[] d, e;
+
+  /**
+   * Array for internal storage of eigenvectors.
+   * 
+   * @serial internal storage of eigenvectors.
+   */
+  private double[][] V;
+
+  /**
+   * Array for internal storage of nonsymmetric Hessenberg form.
+   * 
+   * @serial internal storage of nonsymmetric Hessenberg form.
+   */
+  //private double[][] H;
+
+  /**
+   * Working storage for nonsymmetric algorithm.
+   * 
+   * @serial working storage for nonsymmetric algorithm.
+   */
+  //private double[] ort;
+
+  /* ------------------------
+     Private Methods
+   * ------------------------ */
+
+  // Symmetric Householder reduction to tridiagonal form.
+
+  private void tred2() {
+
+    //  This is derived from the Algol procedures tred2 by
+    //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+    //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+    //  Fortran subroutine in EISPACK.
+
+    for (int j = 0; j < n; j++) {
+      d[j] = V[n - 1][j];
+    }
+
+    // Householder reduction to tridiagonal form.
+
+    for (int i = n - 1; i > 0; i--) {
+
+      // Scale to avoid under/overflow.
+
+      double scale = 0.0;
+      double h = 0.0;
+      for (int k = 0; k < i; k++) {
+        scale = scale + Math.abs(d[k]);
+      }
+      if (scale == 0.0) {
+        e[i] = d[i - 1];
+        for (int j = 0; j < i; j++) {
+          d[j] = V[i - 1][j];
+          V[i][j] = 0.0;
+          V[j][i] = 0.0;
+        }
+      } else {
+
+        // Generate Householder vector.
+
+        for (int k = 0; k < i; k++) {
+          d[k] /= scale;
+          h += d[k] * d[k];
+        }
+        double f = d[i - 1];
+        double g = Math.sqrt(h);
+        if (f > 0) {
+          g = -g;
+        }
+        e[i] = scale * g;
+        h = h - f * g;
+        d[i - 1] = f - g;
+        for (int j = 0; j < i; j++) {
+          e[j] = 0.0;
+        }
+
+        // Apply similarity transformation to remaining columns.
+
+        for (int j = 0; j < i; j++) {
+          f = d[j];
+          V[j][i] = f;
+          g = e[j] + V[j][j] * f;
+          for (int k = j + 1; k <= i - 1; k++) {
+            g += V[k][j] * d[k];
+            e[k] += V[k][j] * f;
+          }
+          e[j] = g;
+        }
+        f = 0.0;
+        for (int j = 0; j < i; j++) {
+          e[j] /= h;
+          f += e[j] * d[j];
+        }
+        double hh = f / (h + h);
+        for (int j = 0; j < i; j++) {
+          e[j] -= hh * d[j];
+        }
+        for (int j = 0; j < i; j++) {
+          f = d[j];
+          g = e[j];
+          for (int k = j; k <= i - 1; k++) {
+            V[k][j] -= (f * e[k] + g * d[k]);
+          }
+          d[j] = V[i - 1][j];
+          V[i][j] = 0.0;
+        }
+      }
+      d[i] = h;
+    }
+
+    // Accumulate transformations.
+
+    for (int i = 0; i < n - 1; i++) {
+      V[n - 1][i] = V[i][i];
+      V[i][i] = 1.0;
+      double h = d[i + 1];
+      if (h != 0.0) {
+        for (int k = 0; k <= i; k++) {
+          d[k] = V[k][i + 1] / h;
+        }
+        for (int j = 0; j <= i; j++) {
+          double g = 0.0;
+          for (int k = 0; k <= i; k++) {
+            g += V[k][i + 1] * V[k][j];
+          }
+          for (int k = 0; k <= i; k++) {
+            V[k][j] -= g * d[k];
+          }
+        }
+      }
+      for (int k = 0; k <= i; k++) {
+        V[k][i + 1] = 0.0;
+      }
+    }
+    for (int j = 0; j < n; j++) {
+      d[j] = V[n - 1][j];
+      V[n - 1][j] = 0.0;
+    }
+    V[n - 1][n - 1] = 1.0;
+    e[0] = 0.0;
+  }
+
+  // Symmetric tridiagonal QL algorithm.
+
+  private void tql2() {
+
+    //  This is derived from the Algol procedures tql2, by
+    //  Bowdler, Martin, Reinsch, and Wilkinson, Handbook for
+    //  Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
+    //  Fortran subroutine in EISPACK.
+
+    for (int i = 1; i < n; i++) {
+      e[i - 1] = e[i];
+    }
+    e[n - 1] = 0.0;
+
+    double f = 0.0;
+    double tst1 = 0.0;
+    double eps = Math.pow(2.0, -52.0);
+    for (int l = 0; l < n; l++) {
+
+      // Find small subdiagonal element
+
+      tst1 = Math.max(tst1, Math.abs(d[l]) + Math.abs(e[l]));
+      int m = l;
+      while (m < n) {
+        if (Math.abs(e[m]) <= eps * tst1) {
+          break;
+        }
+        m++;
+      }
+
+      // If m == l, d[l] is an eigenvalue,
+      // otherwise, iterate.
+
+      if (m > l) {
+        int iter = 0;
+        do {
+          iter = iter + 1; // (Could check iteration count here.)
+
+          // Compute implicit shift
+
+          double g = d[l];
+          double p = (d[l + 1] - g) / (2.0 * e[l]);
+          double r = hypot(p, 1.0);
+          if (p < 0) {
+            r = -r;
+          }
+          d[l] = e[l] / (p + r);
+          d[l + 1] = e[l] * (p + r);
+          double dl1 = d[l + 1];
+          double h = g - d[l];
+          for (int i = l + 2; i < n; i++) {
+            d[i] -= h;
+          }
+          f = f + h;
+
+          // Implicit QL transformation.
+
+          p = d[m];
+          double c = 1.0;
+          double c2 = c;
+          double c3 = c;
+          double el1 = e[l + 1];
+          double s = 0.0;
+          double s2 = 0.0;
+          for (int i = m - 1; i >= l; i--) {
+            c3 = c2;
+            c2 = c;
+            s2 = s;
+            g = c * e[i];
+            h = c * p;
+            r = hypot(p, e[i]);
+            e[i + 1] = s * r;
+            s = e[i] / r;
+            c = p / r;
+            p = c * d[i] - s * g;
+            d[i + 1] = h + s * (c * g + s * d[i]);
+
+            // Accumulate transformation.
+
+            for (int k = 0; k < n; k++) {
+              h = V[k][i + 1];
+              V[k][i + 1] = s * V[k][i] + c * h;
+              V[k][i] = c * V[k][i] - s * h;
+            }
+          }
+          p = -s * s2 * c3 * el1 * e[l] / dl1;
+          e[l] = s * p;
+          d[l] = c * p;
+
+          // Check for convergence.
+
+        } while (Math.abs(e[l]) > eps * tst1);
+      }
+      d[l] = d[l] + f;
+      e[l] = 0.0;
+    }
+
+    // Sort eigenvalues and corresponding vectors.
+
+    for (int i = 0; i < n - 1; i++) {
+      int k = i;
+      double p = d[i];
+      for (int j = i + 1; j < n; j++) {
+        if (d[j] < p) {
+          k = j;
+          p = d[j];
+        }
+      }
+      if (k != i) {
+        d[k] = d[i];
+        d[i] = p;
+        for (int j = 0; j < n; j++) {
+          p = V[j][i];
+          V[j][i] = V[j][k];
+          V[j][k] = p;
+        }
+      }
+    }
+  }
+
+  private static double hypot(double a, double b) {
+
+    // sqrt(a^2 + b^2) without under/overflow. 
+
+    double r;
+    if (Math.abs(a) > Math.abs(b)) {
+      r = b / a;
+      r = Math.abs(a) * Math.sqrt(1 + r * r);
+    } else if (b != 0) {
+      r = a / b;
+      r = Math.abs(b) * Math.sqrt(1 + r * r);
+    } else {
+      r = 0.0;
+    }
+    return r;
+  }
+
+  // Nonsymmetric reduction to Hessenberg form.
+
+  /*
+  private void orthes() {
+
+    //  This is derived from the Algol procedures orthes and ortran,
+    //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+    //  Vol.ii-Linear Algebra, and the corresponding
+    //  Fortran subroutines in EISPACK.
+
+    int low = 0;
+    int high = n - 1;
+
+    for (int m = low + 1; m <= high - 1; m++) {
+
+      // Scale column.
+
+      double scale = 0.0;
+      for (int i = m; i <= high; i++) {
+        scale = scale + Math.abs(H[i][m - 1]);
+      }
+      if (scale != 0.0) {
+
+        // Compute Householder transformation.
+
+        double h = 0.0;
+        for (int i = high; i >= m; i--) {
+          ort[i] = H[i][m - 1] / scale;
+          h += ort[i] * ort[i];
+        }
+        double g = Math.sqrt(h);
+        if (ort[m] > 0) {
+          g = -g;
+        }
+        h = h - ort[m] * g;
+        ort[m] = ort[m] - g;
+
+        // Apply Householder similarity transformation
+        // H = (I-u*u'/h)*H*(I-u*u')/h)
+
+        for (int j = m; j < n; j++) {
+          double f = 0.0;
+          for (int i = high; i >= m; i--) {
+            f += ort[i] * H[i][j];
+          }
+          f = f / h;
+          for (int i = m; i <= high; i++) {
+            H[i][j] -= f * ort[i];
+          }
+        }
+
+        for (int i = 0; i <= high; i++) {
+          double f = 0.0;
+          for (int j = high; j >= m; j--) {
+            f += ort[j] * H[i][j];
+          }
+          f = f / h;
+          for (int j = m; j <= high; j++) {
+            H[i][j] -= f * ort[j];
+          }
+        }
+        ort[m] = scale * ort[m];
+        H[m][m - 1] = scale * g;
+      }
+    }
+
+    // Accumulate transformations (Algol's ortran).
+
+    for (int i = 0; i < n; i++) {
+      for (int j = 0; j < n; j++) {
+        V[i][j] = (i == j ? 1.0 : 0.0);
+      }
+    }
+
+    for (int m = high - 1; m >= low + 1; m--) {
+      if (H[m][m - 1] != 0.0) {
+        for (int i = m + 1; i <= high; i++) {
+          ort[i] = H[i][m - 1];
+        }
+        for (int j = m; j <= high; j++) {
+          double g = 0.0;
+          for (int i = m; i <= high; i++) {
+            g += ort[i] * V[i][j];
+          }
+          // Double division avoids possible underflow
+          g = (g / ort[m]) / H[m][m - 1];
+          for (int i = m; i <= high; i++) {
+            V[i][j] += g * ort[i];
+          }
+        }
+      }
+    }
+  }
+
+  // Complex scalar division.
+
+  private transient double cdivr, cdivi;
+
+  private void cdiv(double xr, double xi, double yr, double yi) {
+    double r, d;
+    if (Math.abs(yr) > Math.abs(yi)) {
+      r = yi / yr;
+      d = yr + r * yi;
+      cdivr = (xr + r * xi) / d;
+      cdivi = (xi - r * xr) / d;
+    } else {
+      r = yr / yi;
+      d = yi + r * yr;
+      cdivr = (r * xr + xi) / d;
+      cdivi = (r * xi - xr) / d;
+    }
+  }
+
+  // Nonsymmetric reduction from Hessenberg to real Schur form.
+
+  private void hqr2() {
+
+    //  This is derived from the Algol procedure hqr2,
+    //  by Martin and Wilkinson, Handbook for Auto. Comp.,
+    //  Vol.ii-Linear Algebra, and the corresponding
+    //  Fortran subroutine in EISPACK.
+
+    // Initialize
+
+    int nn = this.n;
+    int n = nn - 1;
+    int low = 0;
+    int high = nn - 1;
+    double eps = Math.pow(2.0, -52.0);
+    double exshift = 0.0;
+    double p = 0, q = 0, r = 0, s = 0, z = 0, t, w, x, y;
+
+    // Store roots isolated by balanc and compute matrix norm
+
+    double norm = 0.0;
+    for (int i = 0; i < nn; i++) {
+      if (i < low || i > high) {
+        d[i] = H[i][i];
+        e[i] = 0.0;
+      }
+      for (int j = Math.max(i - 1, 0); j < nn; j++) {
+        norm = norm + Math.abs(H[i][j]);
+      }
+    }
+
+    // Outer loop over eigenvalue index
+
+    int iter = 0;
+    while (n >= low) {
+
+      // Look for single small sub-diagonal element
+
+      int l = n;
+      while (l > low) {
+        s = Math.abs(H[l - 1][l - 1]) + Math.abs(H[l][l]);
+        if (s == 0.0) {
+          s = norm;
+        }
+        if (Math.abs(H[l][l - 1]) < eps * s) {
+          break;
+        }
+        l--;
+      }
+
+      // Check for convergence
+      // One root found
+
+      if (l == n) {
+        H[n][n] = H[n][n] + exshift;
+        d[n] = H[n][n];
+        e[n] = 0.0;
+        n--;
+        iter = 0;
+
+        // Two roots found
+
+      } else if (l == n - 1) {
+        w = H[n][n - 1] * H[n - 1][n];
+        p = (H[n - 1][n - 1] - H[n][n]) / 2.0;
+        q = p * p + w;
+        z = Math.sqrt(Math.abs(q));
+        H[n][n] = H[n][n] + exshift;
+        H[n - 1][n - 1] = H[n - 1][n - 1] + exshift;
+        x = H[n][n];
+
+        // Real pair
+
+        if (q >= 0) {
+          if (p >= 0) {
+            z = p + z;
+          } else {
+            z = p - z;
+          }
+          d[n - 1] = x + z;
+          d[n] = d[n - 1];
+          if (z != 0.0) {
+            d[n] = x - w / z;
+          }
+          e[n - 1] = 0.0;
+          e[n] = 0.0;
+          x = H[n][n - 1];
+          s = Math.abs(x) + Math.abs(z);
+          p = x / s;
+          q = z / s;
+          r = Math.sqrt(p * p + q * q);
+          p = p / r;
+          q = q / r;
+
+          // Row modification
+
+          for (int j = n - 1; j < nn; j++) {
+            z = H[n - 1][j];
+            H[n - 1][j] = q * z + p * H[n][j];
+            H[n][j] = q * H[n][j] - p * z;
+          }
+
+          // Column modification
+
+          for (int i = 0; i <= n; i++) {
+            z = H[i][n - 1];
+            H[i][n - 1] = q * z + p * H[i][n];
+            H[i][n] = q * H[i][n] - p * z;
+          }
+
+          // Accumulate transformations
+
+          for (int i = low; i <= high; i++) {
+            z = V[i][n - 1];
+            V[i][n - 1] = q * z + p * V[i][n];
+            V[i][n] = q * V[i][n] - p * z;
+          }
+
+          // Complex pair
+
+        } else {
+          d[n - 1] = x + p;
+          d[n] = x + p;
+          e[n - 1] = z;
+          e[n] = -z;
+        }
+        n = n - 2;
+        iter = 0;
+
+        // No convergence yet
+
+      } else {
+
+        // Form shift
+
+        x = H[n][n];
+        y = 0.0;
+        w = 0.0;
+        if (l < n) {
+          y = H[n - 1][n - 1];
+          w = H[n][n - 1] * H[n - 1][n];
+        }
+
+        // Wilkinson's original ad hoc shift
+
+        if (iter == 10) {
+          exshift += x;
+          for (int i = low; i <= n; i++) {
+            H[i][i] -= x;
+          }
+          s = Math.abs(H[n][n - 1]) + Math.abs(H[n - 1][n - 2]);
+          x = y = 0.75 * s;
+          w = -0.4375 * s * s;
+        }
+
+        // MATLAB's new ad hoc shift
+
+        if (iter == 30) {
+          s = (y - x) / 2.0;
+          s = s * s + w;
+          if (s > 0) {
+            s = Math.sqrt(s);
+            if (y < x) {
+              s = -s;
+            }
+            s = x - w / ((y - x) / 2.0 + s);
+            for (int i = low; i <= n; i++) {
+              H[i][i] -= s;
+            }
+            exshift += s;
+            x = y = w = 0.964;
+          }
+        }
+
+        iter = iter + 1; // (Could check iteration count here.)
+
+        // Look for two consecutive small sub-diagonal elements
+
+        int m = n - 2;
+        while (m >= l) {
+          z = H[m][m];
+          r = x - z;
+          s = y - z;
+          p = (r * s - w) / H[m + 1][m] + H[m][m + 1];
+          q = H[m + 1][m + 1] - z - r - s;
+          r = H[m + 2][m + 1];
+          s = Math.abs(p) + Math.abs(q) + Math.abs(r);
+          p = p / s;
+          q = q / s;
+          r = r / s;
+          if (m == l) {
+            break;
+          }
+          if (Math.abs(H[m][m - 1]) * (Math.abs(q) + Math.abs(r)) < eps
+              * (Math.abs(p) * (Math.abs(H[m - 1][m - 1]) + Math.abs(z) + Math
+                  .abs(H[m + 1][m + 1])))) {
+            break;
+          }
+          m--;
+        }
+
+        for (int i = m + 2; i <= n; i++) {
+          H[i][i - 2] = 0.0;
+          if (i > m + 2) {
+            H[i][i - 3] = 0.0;
+          }
+        }
+
+        // Double QR step involving rows l:n and columns m:n
+
+        for (int k = m; k <= n - 1; k++) {
+          boolean notlast = (k != n - 1);
+          if (k != m) {
+            p = H[k][k - 1];
+            q = H[k + 1][k - 1];
+            r = (notlast ? H[k + 2][k - 1] : 0.0);
+            x = Math.abs(p) + Math.abs(q) + Math.abs(r);
+            if (x != 0.0) {
+              p = p / x;
+              q = q / x;
+              r = r / x;
+            }
+          }
+          if (x == 0.0) {
+            break;
+          }
+          s = Math.sqrt(p * p + q * q + r * r);
+          if (p < 0) {
+            s = -s;
+          }
+          if (s != 0) {
+            if (k != m) {
+              H[k][k - 1] = -s * x;
+            } else if (l != m) {
+              H[k][k - 1] = -H[k][k - 1];
+            }
+            p = p + s;
+            x = p / s;
+            y = q / s;
+            z = r / s;
+            q = q / p;
+            r = r / p;
+
+            // Row modification
+
+            for (int j = k; j < nn; j++) {
+              p = H[k][j] + q * H[k + 1][j];
+              if (notlast) {
+                p = p + r * H[k + 2][j];
+                H[k + 2][j] = H[k + 2][j] - p * z;
+              }
+              H[k][j] = H[k][j] - p * x;
+              H[k + 1][j] = H[k + 1][j] - p * y;
+            }
+
+            // Column modification
+
+            for (int i = 0; i <= Math.min(n, k + 3); i++) {
+              p = x * H[i][k] + y * H[i][k + 1];
+              if (notlast) {
+                p = p + z * H[i][k + 2];
+                H[i][k + 2] = H[i][k + 2] - p * r;
+              }
+              H[i][k] = H[i][k] - p;
+              H[i][k + 1] = H[i][k + 1] - p * q;
+            }
+
+            // Accumulate transformations
+
+            for (int i = low; i <= high; i++) {
+              p = x * V[i][k] + y * V[i][k + 1];
+              if (notlast) {
+                p = p + z * V[i][k + 2];
+                V[i][k + 2] = V[i][k + 2] - p * r;
+              }
+              V[i][k] = V[i][k] - p;
+              V[i][k + 1] = V[i][k + 1] - p * q;
+            }
+          } // (s != 0)
+        } // k loop
+      } // check convergence
+    } // while (n >= low)
+
+    // Backsubstitute to find vectors of upper triangular form
+
+    if (norm == 0.0) {
+      return;
+    }
+
+    for (n = nn - 1; n >= 0; n--) {
+      p = d[n];
+      q = e[n];
+
+      // Real vector
+
+      if (q == 0) {
+        int l = n;
+        H[n][n] = 1.0;
+        for (int i = n - 1; i >= 0; i--) {
+          w = H[i][i] - p;
+          r = 0.0;
+          for (int j = l; j <= n; j++) {
+            r = r + H[i][j] * H[j][n];
+          }
+          if (e[i] < 0.0) {
+            z = w;
+            s = r;
+          } else {
+            l = i;
+            if (e[i] == 0.0) {
+              if (w != 0.0) {
+                H[i][n] = -r / w;
+              } else {
+                H[i][n] = -r / (eps * norm);
+              }
+
+              // Solve real equations
+
+            } else {
+              x = H[i][i + 1];
+              y = H[i + 1][i];
+              q = (d[i] - p) * (d[i] - p) + e[i] * e[i];
+              t = (x * s - z * r) / q;
+              H[i][n] = t;
+              if (Math.abs(x) > Math.abs(z)) {
+                H[i + 1][n] = (-r - w * t) / x;
+              } else {
+                H[i + 1][n] = (-s - y * t) / z;
+              }
+            }
+
+            // Overflow control
+
+            t = Math.abs(H[i][n]);
+            if ((eps * t) * t > 1) {
+              for (int j = i; j <= n; j++) {
+                H[j][n] = H[j][n] / t;
+              }
+            }
+          }
+        }
+
+        // Complex vector
+
+      } else if (q < 0) {
+        int l = n - 1;
+
+        // Last vector component imaginary so matrix is triangular
+
+        if (Math.abs(H[n][n - 1]) > Math.abs(H[n - 1][n])) {
+          H[n - 1][n - 1] = q / H[n][n - 1];
+          H[n - 1][n] = -(H[n][n] - p) / H[n][n - 1];
+        } else {
+          cdiv(0.0, -H[n - 1][n], H[n - 1][n - 1] - p, q);
+          H[n - 1][n - 1] = cdivr;
+          H[n - 1][n] = cdivi;
+        }
+        H[n][n - 1] = 0.0;
+        H[n][n] = 1.0;
+        for (int i = n - 2; i >= 0; i--) {
+          double ra, sa, vr, vi;
+          ra = 0.0;
+          sa = 0.0;
+          for (int j = l; j <= n; j++) {
+            ra = ra + H[i][j] * H[j][n - 1];
+            sa = sa + H[i][j] * H[j][n];
+          }
+          w = H[i][i] - p;
+
+          if (e[i] < 0.0) {
+            z = w;
+            r = ra;
+            s = sa;
+          } else {
+            l = i;
+            if (e[i] == 0) {
+              cdiv(-ra, -sa, w, q);
+              H[i][n - 1] = cdivr;
+              H[i][n] = cdivi;
+            } else {
+
+              // Solve complex equations
+
+              x = H[i][i + 1];
+              y = H[i + 1][i];
+              vr = (d[i] - p) * (d[i] - p) + e[i] * e[i] - q * q;
+              vi = (d[i] - p) * 2.0 * q;
+              if (vr == 0.0 & vi == 0.0) {
+                vr = eps
+                    * norm
+                    * (Math.abs(w) + Math.abs(q) + Math.abs(x) + Math.abs(y) + Math
+                        .abs(z));
+              }
+              cdiv(x * r - z * ra + q * sa, x * s - z * sa - q * ra, vr, vi);
+              H[i][n - 1] = cdivr;
+              H[i][n] = cdivi;
+              if (Math.abs(x) > (Math.abs(z) + Math.abs(q))) {
+                H[i + 1][n - 1] = (-ra - w * H[i][n - 1] + q * H[i][n]) / x;
+                H[i + 1][n] = (-sa - w * H[i][n] - q * H[i][n - 1]) / x;
+              } else {
+                cdiv(-r - y * H[i][n - 1], -s - y * H[i][n], z, q);
+                H[i + 1][n - 1] = cdivr;
+                H[i + 1][n] = cdivi;
+              }
+            }
+
+            // Overflow control
+
+            t = Math.max(Math.abs(H[i][n - 1]), Math.abs(H[i][n]));
+            if ((eps * t) * t > 1) {
+              for (int j = i; j <= n; j++) {
+                H[j][n - 1] = H[j][n - 1] / t;
+                H[j][n] = H[j][n] / t;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // Vectors of isolated roots
+
+    for (int i = 0; i < nn; i++) {
+      if (i < low || i > high) {
+        for (int j = i; j < nn; j++) {
+          V[i][j] = H[i][j];
+        }
+      }
+    }
+
+    // Back transformation to get eigenvectors of original matrix
+
+    for (int j = nn - 1; j >= low; j--) {
+      for (int i = low; i <= high; i++) {
+        z = 0.0;
+        for (int k = low; k <= Math.min(j, high); k++) {
+          z = z + V[i][k] * H[k][j];
+        }
+        V[i][j] = z;
+      }
+    }
+  }
+     */
+
+
+}
diff --git a/src/javajs/util/Encoding.java b/src/javajs/util/Encoding.java
new file mode 100644 (file)
index 0000000..11e0180
--- /dev/null
@@ -0,0 +1,30 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2011  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+public enum Encoding {
+  NONE, UTF8, UTF_16BE, UTF_16LE, UTF_32BE, UTF_32LE
+}
\ No newline at end of file
diff --git a/src/javajs/util/LimitedLineReader.java b/src/javajs/util/LimitedLineReader.java
new file mode 100644 (file)
index 0000000..e1d973f
--- /dev/null
@@ -0,0 +1,48 @@
+package javajs.util;
+
+import java.io.BufferedReader;
+
+/**
+ *  A simple class to read a designated number of bytes from a 
+ *  file and then return them line by line, skipping lines that
+ *  start with #, and including the \n or \r characters at line ends.
+ *  
+ *  Generally useful for determining what sort of data a file contains.
+ *   
+ */
+public class LimitedLineReader {
+  private char[] buf;
+  private int cchBuf;
+  private int ichCurrent;
+
+  public LimitedLineReader(BufferedReader bufferedReader, int readLimit)
+    throws Exception {  
+    bufferedReader.mark(readLimit + 1);
+    buf = new char[readLimit];
+    cchBuf = Math.max(bufferedReader.read(buf, 0, readLimit), 0);
+    ichCurrent = 0;
+    bufferedReader.reset();
+  }
+
+  public String getHeader(int n) {
+    return (n == 0 ? new String(buf) : new String(buf, 0, Math.min(cchBuf, n)));
+  }
+  
+  public String readLineWithNewline() {
+    while (ichCurrent < cchBuf) {
+      int ichBeginningOfLine = ichCurrent;
+      char ch = 0;
+      while (ichCurrent < cchBuf &&
+             (ch = buf[ichCurrent++]) != '\r' && ch != '\n') {
+      }
+      if (ch == '\r' && ichCurrent < cchBuf && buf[ichCurrent] == '\n')
+        ++ichCurrent;
+      int cchLine = ichCurrent - ichBeginningOfLine;
+      if (buf[ichBeginningOfLine] == '#')
+        continue; // flush comment lines;
+      return new String(buf, ichBeginningOfLine, cchLine);
+    }
+    return "";
+  }
+}
+
diff --git a/src/javajs/util/ListDataReader.java b/src/javajs/util/ListDataReader.java
new file mode 100644 (file)
index 0000000..7814977
--- /dev/null
@@ -0,0 +1,57 @@
+package javajs.util;
+
+import java.io.IOException;
+
+
+
+
+
+/**
+ * 
+ * VectorDataReader subclasses BufferedReader and overrides its
+ * read, readLine, mark, and reset methods so that JmolAdapter 
+ * works with Vector<String> arrays without any further adaptation. 
+ * 
+ */
+
+public class ListDataReader extends DataReader {
+  private Lst<String> data;
+  private int pt;
+  private int len;
+
+  public ListDataReader() {
+    super();
+  }
+  
+  @SuppressWarnings("unchecked")
+  @Override
+  public DataReader setData(Object data) {
+    this.data = (Lst<String>) data;
+    len = this.data.size();
+    return this;
+  }
+
+  @Override
+  public int read(char[] buf, int off, int len) throws IOException {
+    return readBuf(buf, off, len);
+  }
+
+  @Override
+  public String readLine() {
+    return (pt < len ? data.get(pt++) : null);
+  }
+
+  /**
+   * 
+   * @param ptr
+   */
+  public void mark(long ptr) {
+    //ignore ptr.
+    ptMark = pt;
+  }
+
+  @Override
+  public void reset() {
+    pt = ptMark;
+  }
+}
\ No newline at end of file
diff --git a/src/javajs/util/Lst.java b/src/javajs/util/Lst.java
new file mode 100644 (file)
index 0000000..8d5d62c
--- /dev/null
@@ -0,0 +1,88 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-04-26 16:57:51 -0500 (Thu, 26 Apr 2007) $
+ * $Revision: 7502 $
+ *
+ * Copyright (C) 2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package javajs.util;
+
+import java.util.ArrayList;
+
+/**
+ * created to remove ambiguities in add and remove
+ * 
+ * @param <V>
+ */
+public class Lst<V> extends ArrayList<V> {
+
+  public Lst() {
+    super();  
+  }
+  
+  /**
+   * @j2sIgnore
+   * 
+   */
+  @Override
+  @Deprecated
+  public boolean add(V v) {
+    throw new NullPointerException("use addLast(value), not add(value) in List for JavaScript compatibility");
+  }
+  
+  public boolean addLast(V v) {
+    /**
+     * no overloading of add(Object) in JavaScript
+     * 
+     * @j2sNative
+     * 
+     * return this.add1(v);
+     *  
+     */
+    {
+      return super.add(v);
+    }
+  }
+  
+  /**
+   * @j2sIgnore
+   * 
+   */
+  @Override
+  @Deprecated
+  public boolean remove(Object v) {
+    throw new NullPointerException("use removeObj(obj), not remove(obj) in List for JavaScript compatibility");
+  }
+  
+  public boolean removeObj(Object v) {
+    /**
+     * no overloading of remove(Object) in JavaScript
+     * 
+     * @j2sNative
+     * 
+     * return this.removeObject(v);
+     *  
+     */
+    {
+      return super.remove(v);
+    }
+  }
+  
+}
diff --git a/src/javajs/util/M3.java b/src/javajs/util/M3.java
new file mode 100644 (file)
index 0000000..8d46569
--- /dev/null
@@ -0,0 +1,638 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+import java.io.Serializable;
+
+
+
+/**
+ * A single precision floating point 3 by 3 matrix.
+ * 
+ * @author Kenji hiranabe
+ * 
+ *         additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique
+ *         constructor and method names for the optimization of compiled
+ *         JavaScript using Java2Script
+ *         
+ *         
+ */
+public class M3 extends M34 implements Serializable {
+
+  /**
+   * Constructs and initializes a Matrix3f to all zeros.
+   * @j2sIgnore
+   */
+  public M3() {
+  }
+
+  /**
+   * Constructs and initializes a Matrix3f from the specified 9 element array.
+   * this.m00 =v[0], this.m01=v[1], etc.
+   * 
+   * @param v
+   *        the array of length 9 containing in order
+   * @return m
+   */
+  public static M3 newA9(float[] v) {
+    M3 m = new M3();
+    m.setA(v);
+    return m;
+  }
+  
+  /**
+   * Constructs a new matrix with the same values as the Matrix3f parameter.
+   * 
+   * @param m1
+   *        The source matrix.
+   * @return m
+   */
+  public static M3 newM3(M3 m1) {
+    M3 m = new M3();
+    if (m1 == null) {
+      m.setScale(1);
+      return m;
+    }
+    m.m00 = m1.m00;
+    m.m01 = m1.m01;
+    m.m02 = m1.m02;
+
+    m.m10 = m1.m10;
+    m.m11 = m1.m11;
+    m.m12 = m1.m12;
+
+    m.m20 = m1.m20;
+    m.m21 = m1.m21;
+    m.m22 = m1.m22;
+    return m;
+  }
+
+  /**
+   * Sets this Matrix3f to a scalar * Identity.
+   * @param scale 
+   */
+  public void setScale(float scale) {
+    clear33();
+    m00 = m11 = m22 = scale;
+  }
+
+  /**
+   * Sets the value of this matrix to the double value of the Matrix3f argument.
+   * 
+   * @param m1
+   *        the matrix3f
+   */
+  public void setM3(M34 m1) {
+    setM33(m1);
+  }
+  /**
+   * Sets the values in this Matrix3f equal to the row-major array parameter
+   * (ie, the first four elements of the array will be copied into the first row
+   * of this matrix, etc.).
+   * 
+   * @param m
+   */
+  public void setA(float m[]) {
+    m00 = m[0];
+    m01 = m[1];
+    m02 = m[2];
+    m10 = m[3];
+    m11 = m[4];
+    m12 = m[5];
+    m20 = m[6];
+    m21 = m[7];
+    m22 = m[8];
+  }
+
+  /**
+   * Sets the specified element of this matrix3d to the value provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param col
+   *        the column number to be modified (zero indexed)
+   * @param v
+   *        the new value
+   */
+  public void setElement(int row, int col, float v) {
+    set33(row, col, v);
+  }
+
+  /**
+   * Retrieves the value at the specified row and column of this matrix.
+   * 
+   * @param row
+   *        the row number to be retrieved (zero indexed)
+   * @param col
+   *        the column number to be retrieved (zero indexed)
+   * @return the value at the indexed element
+   */
+  public float getElement(int row, int col) {
+    return get33(row, col);
+  }
+
+  /**
+   * Sets the specified row of this matrix3d to the three values provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param x
+   *        the first column element
+   * @param y
+   *        the second column element
+   * @param z
+   *        the third column element
+   */
+  public void setRow(int row, float x, float y, float z) {
+    switch (row) {
+    case 0:
+      m00 = x;
+      m01 = y;
+      m02 = z;
+      return;
+    case 1:
+      m10 = x;
+      m11 = y;
+      m12 = z;
+      return;
+    case 2:
+      m20 = x;
+      m21 = y;
+      m22 = z;
+      return;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Sets the specified row of this matrix3d to the Vector provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param v
+   *        the replacement row
+   */
+  public void setRowV(int row, T3 v) {
+    switch (row) {
+    case 0:
+      m00 = v.x;
+      m01 = v.y;
+      m02 = v.z;
+      return;
+    case 1:
+      m10 = v.x;
+      m11 = v.y;
+      m12 = v.z;
+      return;
+    case 2:
+      m20 = v.x;
+      m21 = v.y;
+      m22 = v.z;
+      return;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Sets the specified row of this matrix3d to the four values provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param v
+   *        the replacement row
+   */
+  public void setRowA(int row, float v[]) {
+    setRow33(row, v);
+  }
+
+  /**
+   * Copies the matrix values in the specified row into the array parameter.
+   * 
+   * @param row
+   *        the matrix row
+   * @param v
+   *        The array into which the matrix row values will be copied
+   */
+  @Override
+  public void getRow(int row, float v[]) {
+    getRow33(row, v);
+  }
+
+  /**
+   * Sets the specified column of this matrix3d to the three values provided.
+   * 
+   * @param column
+   *        the column number to be modified (zero indexed)
+   * @param x
+   *        the first row element
+   * @param y
+   *        the second row element
+   * @param z
+   *        the third row element
+   */
+  public void setColumn3(int column, float x, float y, float z) {
+    switch (column) {
+    case 0:
+      m00 = x;
+      m10 = y;
+      m20 = z;
+      break;
+    case 1:
+      m01 = x;
+      m11 = y;
+      m21 = z;
+      break;
+    case 2:
+      m02 = x;
+      m12 = y;
+      m22 = z;
+      break;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Sets the specified column of this matrix3d to the vector provided.
+   * 
+   * @param column
+   *        the column number to be modified (zero indexed)
+   * @param v
+   *        the replacement column
+   */
+  public void setColumnV(int column, T3 v) {
+    switch (column) {
+    case 0:
+      m00 = v.x;
+      m10 = v.y;
+      m20 = v.z;
+      break;
+    case 1:
+      m01 = v.x;
+      m11 = v.y;
+      m21 = v.z;
+      break;
+    case 2:
+      m02 = v.x;
+      m12 = v.y;
+      m22 = v.z;
+      break;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Copies the matrix values in the specified column into the vector parameter.
+   * 
+   * @param column
+   *        the matrix column
+   * @param v
+   *        The vector into which the matrix row values will be copied
+   */
+  public void getColumnV(int column, T3 v) {
+    switch (column) {
+    case 0:
+      v.x = m00;
+      v.y = m10;
+      v.z = m20;
+      break;
+    case 1:
+      v.x = m01;
+      v.y = m11;
+      v.z = m21;
+      break;
+    case 2:
+      v.x = m02;
+      v.y = m12;
+      v.z = m22;
+      break;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Sets the specified column of this matrix3d to the four values provided.
+   * 
+   * @param column
+   *        the column number to be modified (zero indexed)
+   * @param v
+   *        the replacement column
+   */
+  public void setColumnA(int column, float v[]) {
+    setColumn33(column, v);
+  }
+
+  /**
+   * Copies the matrix values in the specified column into the array parameter.
+   * 
+   * @param column
+   *        the matrix column
+   * @param v
+   *        The array into which the matrix row values will be copied
+   */
+  public void getColumn(int column, float v[]) {
+    getColumn33(column, v);
+  }
+
+  /**
+   * Sets the value of this matrix to sum of itself and matrix m1.
+   * 
+   * @param m1
+   *        the other matrix
+   */
+  public void add(M3 m1) {
+    add33(m1);
+  }
+
+  /**
+   * Sets the value of this matrix to the matrix difference of itself and matrix
+   * m1 (this = this - m1).
+   * 
+   * @param m1
+   *        the other matrix
+   */
+  public void sub(M3 m1) {
+    sub33(m1);
+  }
+
+  /**
+   * Sets the value of this matrix to its transpose.
+   */
+  public void transpose() {
+    transpose33();
+  }
+
+  /**
+   * Sets the value of this matrix to the transpose of the argument matrix
+   * 
+   * @param m1
+   *        the matrix to be transposed
+   */
+  public void transposeM(M3 m1) {
+    // alias-safe
+    setM33(m1);
+    transpose33();
+  }
+
+  /**
+   * Sets the value of this matrix to the matrix inverse of the passed matrix
+   * m1.
+   * 
+   * @param m1
+   *        the matrix to be inverted
+   */
+  public void invertM(M3 m1) {
+    setM33(m1);
+    invert();
+  }
+
+  /**
+   * Sets the value of this matrix to its inverse.
+   */
+  public void invert() {
+    double s = determinant3();
+    if (s == 0.0)
+      return;
+    s = 1 / s;
+    // alias-safe way.
+    set9(m11 * m22 - m12 * m21, m02 * m21 - m01 * m22, m01 * m12 - m02 * m11,
+        m12 * m20 - m10 * m22, m00 * m22 - m02 * m20, m02 * m10 - m00 * m12,
+        m10 * m21 - m11 * m20, m01 * m20 - m00 * m21, m00 * m11 - m01 * m10);
+    scale((float) s);
+  }
+
+  /**
+   * Sets the value of this matrix to a rotation matrix about the x axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the X axis in radians
+   * @return this
+   */
+  public M3 setAsXRotation(float angle) {
+    setXRot(angle);
+    return this;
+  }
+  
+  /**
+   * Sets the value of this matrix to a rotation matrix about the y axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the Y axis in radians
+   * @return this
+   */
+  public M3 setAsYRotation(float angle) {
+    setYRot(angle);
+    return this;
+  }
+
+  /**
+   * Sets the value of this matrix to a rotation matrix about the z axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the Z axis in radians
+   * @return this
+   */
+  public M3 setAsZRotation(float angle) {
+    setZRot(angle);
+    return this;
+  }
+
+  /**
+   * Multiplies each element of this matrix by a scalar.
+   * 
+   * @param scalar
+   *        The scalar multiplier.
+   */
+  public void scale(float scalar) {
+    mul33(scalar);
+  }
+
+  /**
+   * Sets the value of this matrix to the result of multiplying itself with
+   * matrix m1.
+   * 
+   * @param m1
+   *        the other matrix
+   */
+  public void mul(M3 m1) {
+    mul2(this, m1);
+  }
+
+  /**
+   * Sets the value of this matrix to the result of multiplying the two argument
+   * matrices together.
+   * 
+   * @param m1
+   *        the first matrix
+   * @param m2
+   *        the second matrix
+   */
+  public void mul2(M3 m1, M3 m2) {
+    // alias-safe way.
+    set9(m1.m00 * m2.m00 + m1.m01 * m2.m10 + m1.m02 * m2.m20, m1.m00 * m2.m01
+        + m1.m01 * m2.m11 + m1.m02 * m2.m21, m1.m00 * m2.m02 + m1.m01 * m2.m12
+        + m1.m02 * m2.m22,
+
+    m1.m10 * m2.m00 + m1.m11 * m2.m10 + m1.m12 * m2.m20, m1.m10 * m2.m01
+        + m1.m11 * m2.m11 + m1.m12 * m2.m21, m1.m10 * m2.m02 + m1.m11 * m2.m12
+        + m1.m12 * m2.m22,
+
+    m1.m20 * m2.m00 + m1.m21 * m2.m10 + m1.m22 * m2.m20, m1.m20 * m2.m01
+        + m1.m21 * m2.m11 + m1.m22 * m2.m21, m1.m20 * m2.m02 + m1.m21 * m2.m12
+        + m1.m22 * m2.m22);
+  }
+
+  /**
+   * Returns true if the Object o is of type Matrix3f and all of the data
+   * members of t1 are equal to the corresponding data members in this Matrix3f.
+   * 
+   * @param o
+   *        the object with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof M3))
+      return false;
+    M3 m = (M3) o;
+    return m00 == m.m00 && m01 == m.m01 && m02 == m.m02 && m10 == m.m10
+        && m11 == m.m11 && m12 == m.m12 && m20 == m.m20 && m21 == m.m21
+        && m22 == m.m22;
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Matrix3f objects with identical data values (ie, returns true for
+   * equals(Matrix3f) ) will return the same hash number. Two objects with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   * 
+   * @return the integer hash value
+   */
+  @Override
+  public int hashCode() {
+    return T3.floatToIntBits0(m00) ^ T3.floatToIntBits0(m01)
+        ^ T3.floatToIntBits0(m02) ^ T3.floatToIntBits0(m10)
+        ^ T3.floatToIntBits0(m11) ^ T3.floatToIntBits0(m12)
+        ^ T3.floatToIntBits0(m20) ^ T3.floatToIntBits0(m21)
+        ^ T3.floatToIntBits0(m22);
+  }
+
+  /**
+   * Sets this matrix to all zeros.
+   */
+  public void setZero() {
+    clear33();
+  }
+
+  /**
+   * Sets 9 values
+   * 
+   * @param m00
+   * @param m01
+   * @param m02
+   * @param m10
+   * @param m11
+   * @param m12
+   * @param m20
+   * @param m21
+   * @param m22
+   */
+  private void set9(float m00, float m01, float m02, float m10, float m11,
+                   float m12, float m20, float m21, float m22) {
+    this.m00 = m00;
+    this.m01 = m01;
+    this.m02 = m02;
+    this.m10 = m10;
+    this.m11 = m11;
+    this.m12 = m12;
+    this.m20 = m20;
+    this.m21 = m21;
+    this.m22 = m22;
+  }
+
+  /**
+   * Returns a string that contains the values of this Matrix3f.
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "[\n  [" + m00 + "\t" + m01 + "\t" + m02 + "]" + "\n  [" + m10
+        + "\t" + m11 + "\t" + m12 + "]" + "\n  [" + m20 + "\t" + m21 + "\t"
+        + m22 + "] ]";
+  }
+
+  /**
+   * Sets the value of this matrix to the matrix conversion of the single
+   * precision axis and angle argument.
+   * 
+   * @param a
+   *        the axis and angle to be converted
+   * @return this
+   */
+  public M3 setAA(A4 a) {
+    setAA33(a);
+    return this;
+  }
+
+  /**
+   * 3D ball rotation from dx dy in-plane mouse motion
+   * adapted from Andrew Hanson
+   * Computer Graphics beyond the Third Dimension:
+   * Geometry, Orientation Control, and Rendering for
+   * Graphics in Dimensions Greater than Three
+   * Course Notes for SIGGRAPH â€™98
+   * http://www.cse.ohio-state.edu/~hwshen/888_su02/hanson_note.pdf
+   * 
+   * @param responseFactor Jmol uses 0.02 here
+   * @param dx
+   * @param dy
+   * @return true if successful; false if not;
+   */
+  public boolean setAsBallRotation(float responseFactor, float dx, float dy) {
+    float r = (float) Math.sqrt(dx * dx + dy * dy);
+    float th =  r * responseFactor;
+    if (th == 0) {
+      setScale(1);
+      return false;
+    }
+    float c = (float) Math.cos(th);
+    float s = (float) Math.sin(th);
+    float nx = -dy / r;
+    float ny = dx / r;
+    float c1 = c - 1;
+    m00 = 1 + c1 * nx * nx;
+    m01 = m10 = c1 * nx * ny;
+    m20 = -(m02 = s * nx);
+    m11 = 1 + c1 * ny * ny;
+    m21 = -(m12 = s * ny);
+    m22 = c;
+    return true;
+  }
+
+  public boolean isRotation() {
+    return (Math.abs(determinant3() - 1) < 0.001f);
+  }
+
+}
diff --git a/src/javajs/util/M34.java b/src/javajs/util/M34.java
new file mode 100644 (file)
index 0000000..260a82c
--- /dev/null
@@ -0,0 +1,416 @@
+package javajs.util;
+
+/**
+ * A base class for both M3 and M4 to conserve code size.
+ * 
+ * @author Kenji hiranabe
+ * 
+ *         additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique
+ *         constructor and method names for the optimization of compiled
+ *         JavaScript using Java2Script and for subclassing to M3 and M4
+ * 
+ */
+public abstract class M34 {
+
+  /**
+   * The first element of the first row
+   */
+  public float m00;
+
+  /**
+   * The second element of the first row.
+   */
+  public float m01;
+
+  /**
+   * third element of the first row.
+   */
+  public float m02;
+
+  /**
+   * The first element of the second row.
+   */
+  public float m10;
+
+  /**
+   * The second element of the second row.
+   */
+  public float m11;
+
+  /**
+   * The third element of the second row.
+   */
+  public float m12;
+
+  /**
+   * The first element of the third row.
+   */
+  public float m20;
+
+  /**
+   * The second element of the third row.
+   */
+  public float m21;
+
+  /**
+   * The third element of the third row.
+   */
+  public float m22;
+
+  protected void setAA33(A4 a) {
+    double x = a.x;
+    double y = a.y;
+    double z = a.z;
+    double angle = a.angle;
+    // Taken from Rick's which is taken from Wertz. pg. 412
+    // Bug Fixed and changed into right-handed by hiranabe
+    double n = Math.sqrt(x * x + y * y + z * z);
+    // zero-div may occur
+    n = 1 / n;
+    x *= n;
+    y *= n;
+    z *= n;
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    double omc = 1.0 - c;
+    m00 = (float) (c + x * x * omc);
+    m11 = (float) (c + y * y * omc);
+    m22 = (float) (c + z * z * omc);
+
+    double tmp1 = x * y * omc;
+    double tmp2 = z * s;
+    m01 = (float) (tmp1 - tmp2);
+    m10 = (float) (tmp1 + tmp2);
+
+    tmp1 = x * z * omc;
+    tmp2 = y * s;
+    m02 = (float) (tmp1 + tmp2);
+    m20 = (float) (tmp1 - tmp2);
+
+    tmp1 = y * z * omc;
+    tmp2 = x * s;
+    m12 = (float) (tmp1 - tmp2);
+    m21 = (float) (tmp1 + tmp2);
+  }
+
+  public void rotate(T3 t) {
+    // alias-safe
+    rotate2(t, t);
+  }
+
+  /**
+   * Transform the vector vec using this Matrix3f and place the result into
+   * vecOut.
+   * 
+   * @param t
+   *        the single precision vector to be transformed
+   * @param result
+   *        the vector into which the transformed values are placed
+   */
+  public void rotate2(T3 t, T3 result) {
+    // alias-safe
+    result.set(m00 * t.x + m01 * t.y + m02 * t.z, m10 * t.x + m11 * t.y + m12
+        * t.z, m20 * t.x + m21 * t.y + m22 * t.z);
+  }
+
+
+  /**
+   * Sets the value of this matrix to the double value of the Matrix3f argument.
+   * 
+   * @param m1
+   *        the matrix3f
+   */
+  protected void setM33(M34 m1) {
+    m00 = m1.m00;
+    m01 = m1.m01;
+    m02 = m1.m02;
+    m10 = m1.m10;
+    m11 = m1.m11;
+    m12 = m1.m12;
+    m20 = m1.m20;
+    m21 = m1.m21;
+    m22 = m1.m22;
+  }
+
+  protected void clear33() {
+    m00 = m01 = m02 = m10 = m11 = m12 = m20 = m21 = m22 = 0.0f;
+  }
+
+  protected void set33(int row, int col, float v) {
+    switch (row) {
+    case 0:
+      switch (col) {
+      case 0:
+        m00 = v;
+        return;
+      case 1:
+        m01 = v;
+        return;
+      case 2: 
+        m02 = v;
+        return;
+      }
+      break;
+    case 1:
+      switch (col) {
+      case 0:
+        m10 = v;
+        return;
+      case 1:
+        m11 = v;
+        return;
+      case 2: 
+        m12 = v;
+        return;
+      }
+      break;
+    case 2: 
+      switch (col) {
+      case 0:
+        m20 = v;
+        return;
+      case 1:
+        m21 = v;
+        return;
+      case 2: 
+        m22 = v;
+        return;
+      }
+      break;
+    }
+    err();
+  }
+
+  protected float get33(int row, int col) {
+    switch (row) {
+    case 0:
+      switch (col) {
+      case 0:
+        return m00;
+      case 1:
+        return m01;
+      case 2:
+        return m02;
+      }
+      break;
+    case 1:
+      switch (col) {
+      case 0:
+        return m10;
+      case 1:
+        return m11;
+      case 2:
+        return m12;
+      }
+      break;
+    case 2:
+      switch (col) {
+      case 0:
+        return m20;
+      case 1:
+        return m21;
+      case 2:
+        return m22;
+      }
+      break;
+    }
+    err();
+    return 0;
+  }
+
+  protected void setRow33(int row, float v[]) {
+    switch (row) {
+    case 0:
+      m00 = v[0];
+      m01 = v[1];
+      m02 = v[2];
+      return;
+    case 1:
+      m10 = v[0];
+      m11 = v[1];
+      m12 = v[2];
+      return;
+    case 2:
+      m20 = v[0];
+      m21 = v[1];
+      m22 = v[2];
+      return;
+    default:
+      err();
+    }
+  }
+  
+  public abstract void getRow(int row, float v[]);
+
+  protected void getRow33(int row, float v[]) {
+    switch (row) {
+    case 0:
+      v[0] = m00;
+      v[1] = m01;
+      v[2] = m02;
+      return;
+    case 1:
+      v[0] = m10;
+      v[1] = m11;
+      v[2] = m12;
+      return;
+    case 2:
+      v[0] = m20;
+      v[1] = m21;
+      v[2] = m22;
+      return;
+    }
+    err();
+  }
+
+  protected void setColumn33(int column, float v[]) {
+    switch(column) {
+    case 0:
+      m00 = v[0];
+      m10 = v[1];
+      m20 = v[2];
+      break;
+    case 1:
+      m01 = v[0];
+      m11 = v[1];
+      m21 = v[2];
+      break;
+    case 2:
+      m02 = v[0];
+      m12 = v[1];
+      m22 = v[2];
+      break;
+     default:
+      err();
+    }
+  }
+
+  protected void getColumn33(int column, float v[]) {
+    switch(column) {
+    case 0:
+      v[0] = m00;
+      v[1] = m10;
+      v[2] = m20;
+      break;
+    case 1:
+      v[0] = m01;
+      v[1] = m11;
+      v[2] = m21;
+      break;
+    case 2:
+      v[0] = m02;
+      v[1] = m12;
+      v[2] = m22;
+      break;
+    default:
+      err();
+    }
+  }
+
+  protected void add33(M34 m1) {
+    m00 += m1.m00;
+    m01 += m1.m01;
+    m02 += m1.m02;
+    m10 += m1.m10;
+    m11 += m1.m11;
+    m12 += m1.m12;
+    m20 += m1.m20;
+    m21 += m1.m21;
+    m22 += m1.m22;
+  }
+
+  protected void sub33(M34 m1) {
+    m00 -= m1.m00;
+    m01 -= m1.m01;
+    m02 -= m1.m02;
+    m10 -= m1.m10;
+    m11 -= m1.m11;
+    m12 -= m1.m12;
+    m20 -= m1.m20;
+    m21 -= m1.m21;
+    m22 -= m1.m22;
+  }
+
+  protected void mul33(float x) {
+    m00 *= x;
+    m01 *= x;
+    m02 *= x;
+    m10 *= x;
+    m11 *= x;
+    m12 *= x;
+    m20 *= x;
+    m21 *= x;
+    m22 *= x;
+  }
+
+  protected void transpose33() {
+    float tmp = m01;
+    m01 = m10;
+    m10 = tmp;
+
+    tmp = m02;
+    m02 = m20;
+    m20 = tmp;
+
+    tmp = m12;
+    m12 = m21;
+    m21 = tmp;
+  }
+
+  protected void setXRot(float angle) {
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m00 = 1.0f;
+    m01 = 0.0f;
+    m02 = 0.0f;
+    m10 = 0.0f;
+    m11 = (float) c;
+    m12 = (float) -s;
+    m20 = 0.0f;
+    m21 = (float) s;
+    m22 = (float) c;
+  }
+
+  protected void setYRot(float angle) {
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m00 = (float) c;
+    m01 = 0.0f;
+    m02 = (float) s;
+    m10 = 0.0f;
+    m11 = 1.0f;
+    m12 = 0.0f;
+    m20 = (float) -s;
+    m21 = 0.0f;
+    m22 = (float) c;
+  }
+  
+  protected void setZRot(float angle) {
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m00 = (float) c;
+    m01 = (float) -s;
+    m02 = 0.0f;
+    m10 = (float) s;
+    m11 = (float) c;
+    m12 = 0.0f;
+    m20 = 0.0f;
+    m21 = 0.0f;
+    m22 = 1.0f;
+  }
+  
+  /**
+   * @return 3x3 determinant
+   */
+  public float determinant3() {
+    return m00 * (m11 * m22 - m21 * m12) - m01 * (m10 * m22 - m20 * m12) + m02
+        * (m10 * m21 - m20 * m11);
+  }
+  
+  protected void err() {
+    throw new ArrayIndexOutOfBoundsException(
+        "matrix column/row out of bounds");
+  }
+
+
+}
diff --git a/src/javajs/util/M4.java b/src/javajs/util/M4.java
new file mode 100644 (file)
index 0000000..c19ed88
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+/**
+ * A single precision floating point 4 by 4 matrix.
+ * 
+ * @author Kenji hiranabe
+ * 
+ *         additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique
+ *         constructor and method names for the optimization of compiled
+ *         JavaScript using Java2Script
+ */
+public class M4 extends M34 {
+
+  /**
+   * The fourth element of the first row.
+   */
+  public float m03;
+
+  /**
+   * The fourth element of the second row.
+   */
+  public float m13;
+
+  /**
+   * The fourth element of the third row.
+   */
+  public float m23;
+
+  /**
+   * The first element of the fourth row.
+   */
+  public float m30;
+
+  /**
+   * The second element of the fourth row.
+   */
+  public float m31;
+
+  /**
+   * The third element of the fourth row.
+   */
+  public float m32;
+
+  /**
+   * The fourth element of the fourth row.
+   */
+  public float m33 = 0;
+
+  /**
+   * all zeros
+   * @j2sIgnore
+   */
+  public M4() {
+  }
+  /**
+   * Constructs and initializes a Matrix4f from the specified 16 element array.
+   * this.m00 =v[0], this.m01=v[1], etc.
+   * 
+   * @param v
+   *        the array of length 16 containing in order
+   * @return m
+   */
+  public static M4 newA16(float[] v) {
+    M4 m = new M4();
+    m.m00 = v[0];
+    m.m01 = v[1];
+    m.m02 = v[2];
+    m.m03 = v[3];
+
+    m.m10 = v[4];
+    m.m11 = v[5];
+    m.m12 = v[6];
+    m.m13 = v[7];
+
+    m.m20 = v[8];
+    m.m21 = v[9];
+    m.m22 = v[10];
+    m.m23 = v[11];
+
+    m.m30 = v[12];
+    m.m31 = v[13];
+    m.m32 = v[14];
+    m.m33 = v[15];
+
+    return m;
+  }
+
+  /**
+   * Constructs a new matrix with the same values as the Matrix4f parameter.
+   * 
+   * @param m1
+   *        the source matrix
+   * @return m
+   */
+  public static M4 newM4(M4 m1) {
+    M4 m = new M4();
+    if (m1 == null) {
+      m.setIdentity();
+      return m;
+    }
+    m.setToM3(m1);
+    m.m03 = m1.m03;
+    m.m13 = m1.m13;
+    m.m23 = m1.m23;
+    m.m30 = m1.m30;
+    m.m31 = m1.m31;
+    m.m32 = m1.m32;
+    m.m33 = m1.m33;
+    return m;
+  }
+
+  /**
+   * Constructs and initializes a Matrix4f from the rotation matrix and
+   * translation.
+   * 
+   * @param m1
+   *        The rotation matrix representing the rotational components
+   * @param t
+   *        The translational components of the matrix
+   * @return m
+   */
+  public static M4 newMV(M3 m1, T3 t) {
+    M4 m = new M4();
+    m.setMV(m1, t);
+    return m;
+  }
+
+  /**
+   * Sets this matrix to all zeros.
+   */
+  public void setZero() {
+    clear33();
+    m03 = m13 = m23 = m30 = m31 = m32 = m33 = 0.0f;
+  }
+
+  /**
+   * Sets this Matrix4f to identity.
+   */
+  public void setIdentity() {
+    setZero();
+    m00 = m11 = m22 = m33 = 1.0f;
+  }
+
+  /**
+   * Sets the value of this matrix to a copy of the passed matrix m1.
+   * 
+   * @param m1
+   *        the matrix to be copied
+   * @return this
+   */
+  public M4 setM4(M4 m1) {
+    setM33(m1);
+    m03 = m1.m03;
+    m13 = m1.m13;
+    m23 = m1.m23;
+    m30 = m1.m30;
+    m31 = m1.m31;
+    m32 = m1.m32;
+    m33 = m1.m33;
+    return this;
+  }
+
+  /**
+   * Initializes a Matrix4f from the rotation matrix and translation.
+   * 
+   * @param m1
+   *        The rotation matrix representing the rotational components
+   * @param t
+   *        The translational components of the matrix
+   */
+  public void setMV(M3 m1, T3 t) {
+    setM33(m1);
+    setTranslation(t);
+    m33 = 1;
+  }
+
+  /**
+   * Sets the rotational component (upper 3x3) of this matrix to the matrix
+   * values in the single precision Matrix3f argument; the other elements of
+   * this matrix are initialized as if this were an identity matrix (ie, affine
+   * matrix with no translational component).
+   * 
+   * @param m1
+   *        the 3x3 matrix
+   */
+  public void setToM3(M34 m1) {
+    setM33(m1);
+    m03 = m13 = m23 = m30 = m31 = m32 = 0.0f;
+    m33 = 1.0f;
+  }
+
+  /**
+   * Sets the rotational component (upper 3x3) of this matrix 
+   * to a rotation given by an axis angle
+   * 
+   * @param a
+   *        the axis and angle to be converted
+   */
+  public void setToAA(A4 a) {
+    setIdentity();
+    setAA33(a);
+  }
+
+  /**
+   * Sets the values in this Matrix4f equal to the row-major array parameter
+   * (ie, the first four elements of the array will be copied into the first row
+   * of this matrix, etc.).
+   * 
+   * @param m
+   */
+  public void setA(float m[]) {
+    m00 = m[0];
+    m01 = m[1];
+    m02 = m[2];
+    m03 = m[3];
+    m10 = m[4];
+    m11 = m[5];
+    m12 = m[6];
+    m13 = m[7];
+    m20 = m[8];
+    m21 = m[9];
+    m22 = m[10];
+    m23 = m[11];
+    m30 = m[12];
+    m31 = m[13];
+    m32 = m[14];
+    m33 = m[15];
+  }
+
+  /**
+   * Modifies the translational components of this matrix to the values of the
+   * Vector3f argument; the other values of this matrix are not modified.
+   * 
+   * @param trans
+   *        the translational component
+   */
+  public void setTranslation(T3 trans) {
+    m03 = trans.x;
+    m13 = trans.y;
+    m23 = trans.z;
+  }
+
+  /**
+   * Sets the specified element of this matrix4f to the value provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param col
+   *        the column number to be modified (zero indexed)
+   * @param v
+   *        the new value
+   */
+  public void setElement(int row, int col, float v) {
+    if (row < 3 && col < 3) {
+      set33(row, col, v);
+      return;
+    }
+    if (row > 3 || col > 3)
+      err();
+    switch (row) {
+    case 0:
+      m03 = v;
+      return;
+    case 1:
+      m13 = v;
+      return;
+    case 2:
+      m23 = v;
+      return;
+    }
+    switch (col) {
+    case 0:
+      m30 = v;
+      return;
+    case 1:
+      m31 = v;
+      return;
+    case 2:
+      m32 = v;
+      return;
+    case 3:
+      m33 = v;
+      return;
+    }
+  }
+
+  /**
+   * Retrieves the value at the specified row and column of this matrix.
+   * 
+   * @param row
+   *        the row number to be retrieved (zero indexed)
+   * @param col
+   *        the column number to be retrieved (zero indexed)
+   * @return the value at the indexed element
+   */
+  public float getElement(int row, int col) {
+    if (row < 3 && col < 3)
+      return get33(row, col);
+    if (row > 3 || col > 3) {
+      err();
+      return 0;
+    }
+    switch (row) {
+    case 0:
+      return m03;
+    case 1:
+      return m13;
+    case 2:
+      return m23;
+    default:
+      switch (col) {
+      case 0:
+        return m30;
+      case 1:
+        return m31;
+      case 2:
+        return m32;
+      default:
+        return m33;
+      }
+    }
+  }
+
+  /**
+   * Retrieves the translational components of this matrix.
+   * 
+   * @param trans
+   *        the vector that will receive the translational component
+   */
+  public void getTranslation(T3 trans) {
+    trans.x = m03;
+    trans.y = m13;
+    trans.z = m23;
+  }
+
+  /**
+   * Gets the upper 3x3 values of this matrix and places them into the matrix
+   * m1.
+   * 
+   * @param m1
+   *        The matrix that will hold the values
+   */
+  public void getRotationScale(M3 m1) {
+    m1.m00 = m00;
+    m1.m01 = m01;
+    m1.m02 = m02;
+    m1.m10 = m10;
+    m1.m11 = m11;
+    m1.m12 = m12;
+    m1.m20 = m20;
+    m1.m21 = m21;
+    m1.m22 = m22;
+  }
+
+  /**
+   * Replaces the upper 3x3 matrix values of this matrix with the values in the
+   * matrix m1.
+   * 
+   * @param m1
+   *        The matrix that will be the new upper 3x3
+   */
+  public void setRotationScale(M3 m1) {
+    m00 = m1.m00;
+    m01 = m1.m01;
+    m02 = m1.m02;
+    m10 = m1.m10;
+    m11 = m1.m11;
+    m12 = m1.m12;
+    m20 = m1.m20;
+    m21 = m1.m21;
+    m22 = m1.m22;
+  }
+
+  /**
+   * Sets the specified row of this matrix4f to the four values provided.
+   * 
+   * @param row
+   *        the row number to be modified (zero indexed)
+   * @param v
+   *        the replacement row
+   */
+  public void setRowA(int row, float v[]) {
+    if (row < 3)
+      setRow33(row, v);
+    switch (row) {
+    case 0:
+      m03 = v[3];
+      return;
+    case 1:
+      m13 = v[3];
+      return;
+    case 2:
+      m23 = v[3];
+      return;
+    case 3:
+      m30 = v[0];
+      m31 = v[1];
+      m32 = v[2];
+      m33 = v[3];
+      return;
+    }
+    err();
+  }
+
+  /**
+   * Copies the matrix values in the specified row into the array parameter.
+   * 
+   * @param row
+   *        the matrix row
+   * @param v
+   *        The array into which the matrix row values will be copied
+   */
+  @Override
+  public void getRow(int row, float v[]) {
+    if (row < 3)
+      getRow33(row, v);
+    switch (row) {
+    case 0:
+      v[3] = m03;
+      return;
+    case 1:
+      v[3] = m13;
+      return;
+    case 2:
+      v[3] = m23;
+      return;
+    case 3:
+      v[0] = m30;
+      v[1] = m31;
+      v[2] = m32;
+      v[3] = m33;
+      return;
+    }
+    err();
+  }
+
+  /**
+   * Sets the specified column of this matrix4f to the four values provided.
+   * 
+   * @param column
+   *        the column number to be modified (zero indexed)
+   * @param x
+   *        the first row element
+   * @param y
+   *        the second row element
+   * @param z
+   *        the third row element
+   * @param w
+   *        the fourth row element
+   */
+  public void setColumn4(int column, float x, float y, float z, float w) {
+    if (column == 0) {
+      m00 = x;
+      m10 = y;
+      m20 = z;
+      m30 = w;
+    } else if (column == 1) {
+      m01 = x;
+      m11 = y;
+      m21 = z;
+      m31 = w;
+    } else if (column == 2) {
+      m02 = x;
+      m12 = y;
+      m22 = z;
+      m32 = w;
+    } else if (column == 3) {
+      m03 = x;
+      m13 = y;
+      m23 = z;
+      m33 = w;
+    } else {
+      err();
+    }
+  }
+
+  /**
+   * Sets the specified column of this matrix4f to the four values provided.
+   * 
+   * @param column
+   *        the column number to be modified (zero indexed)
+   * @param v
+   *        the replacement column
+   */
+  public void setColumnA(int column, float v[]) {
+    if (column < 3)
+      setColumn33(column, v);
+    switch (column) {
+    case 0:
+      m30 = v[3];
+      return;
+    case 1:
+      m31 = v[3];
+      return;
+    case 2:
+      m32 = v[3];
+      return;
+    case 3:
+      m03 = v[0];
+      m13 = v[1];
+      m23 = v[2];
+      m33 = v[3];
+      return;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Copies the matrix values in the specified column into the array parameter.
+   * 
+   * @param column
+   *        the matrix column
+   * @param v
+   *        The array into which the matrix column values will be copied
+   */
+  public void getColumn(int column, float v[]) {
+    if (column < 3)
+      getColumn33(column, v);
+    switch (column) {
+    case 0:
+      v[3] = m30;
+      return;
+    case 1:
+      v[3] = m31;
+      return;
+    case 2:
+      v[3] = m32;
+      return;
+    case 3:
+      v[0] = m03;
+      v[1] = m13;
+      v[2] = m23;
+      v[3] = m33;
+      return;
+    default:
+      err();
+    }
+  }
+
+  /**
+   * Sets the value of this matrix to the matrix difference of itself and matrix
+   * m1 (this = this - m1).
+   * 
+   * @param m1
+   *        the other matrix
+   */
+  public void sub(M4 m1) {
+    sub33(m1);
+    m03 -= m1.m03;
+    m13 -= m1.m13;
+    m23 -= m1.m23;
+    m30 -= m1.m30;
+    m31 -= m1.m31;
+    m32 -= m1.m32;
+    m33 -= m1.m33;
+  }
+
+  /**
+   * Sets the value of this matrix to its transpose.
+   */
+  public void transpose() {
+    transpose33();
+    float tmp = m03;
+    m03 = m30;
+    m30 = tmp;
+
+    tmp = m13;
+    m13 = m31;
+    m31 = tmp;
+
+    tmp = m23;
+    m23 = m32;
+    m32 = tmp;
+  }
+
+  /**
+   * Sets the value of this matrix to its inverse.
+   * @return this
+   */
+  public M4 invert() {
+    float s = determinant4();
+    if (s == 0.0)
+      return this;
+    s = 1 / s;
+    // alias-safe way.
+    // less *,+,- calculation than expanded expression.
+    set(m11 * (m22 * m33 - m23 * m32) + m12 * (m23 * m31 - m21 * m33) + m13
+        * (m21 * m32 - m22 * m31), m21 * (m02 * m33 - m03 * m32) + m22
+        * (m03 * m31 - m01 * m33) + m23 * (m01 * m32 - m02 * m31), m31
+        * (m02 * m13 - m03 * m12) + m32 * (m03 * m11 - m01 * m13) + m33
+        * (m01 * m12 - m02 * m11), m01 * (m13 * m22 - m12 * m23) + m02
+        * (m11 * m23 - m13 * m21) + m03 * (m12 * m21 - m11 * m22),
+
+    m12 * (m20 * m33 - m23 * m30) + m13 * (m22 * m30 - m20 * m32) + m10
+        * (m23 * m32 - m22 * m33), m22 * (m00 * m33 - m03 * m30) + m23
+        * (m02 * m30 - m00 * m32) + m20 * (m03 * m32 - m02 * m33), m32
+        * (m00 * m13 - m03 * m10) + m33 * (m02 * m10 - m00 * m12) + m30
+        * (m03 * m12 - m02 * m13), m02 * (m13 * m20 - m10 * m23) + m03
+        * (m10 * m22 - m12 * m20) + m00 * (m12 * m23 - m13 * m22),
+
+    m13 * (m20 * m31 - m21 * m30) + m10 * (m21 * m33 - m23 * m31) + m11
+        * (m23 * m30 - m20 * m33), m23 * (m00 * m31 - m01 * m30) + m20
+        * (m01 * m33 - m03 * m31) + m21 * (m03 * m30 - m00 * m33), m33
+        * (m00 * m11 - m01 * m10) + m30 * (m01 * m13 - m03 * m11) + m31
+        * (m03 * m10 - m00 * m13), m03 * (m11 * m20 - m10 * m21) + m00
+        * (m13 * m21 - m11 * m23) + m01 * (m10 * m23 - m13 * m20),
+
+    m10 * (m22 * m31 - m21 * m32) + m11 * (m20 * m32 - m22 * m30) + m12
+        * (m21 * m30 - m20 * m31), m20 * (m02 * m31 - m01 * m32) + m21
+        * (m00 * m32 - m02 * m30) + m22 * (m01 * m30 - m00 * m31), m30
+        * (m02 * m11 - m01 * m12) + m31 * (m00 * m12 - m02 * m10) + m32
+        * (m01 * m10 - m00 * m11), m00 * (m11 * m22 - m12 * m21) + m01
+        * (m12 * m20 - m10 * m22) + m02 * (m10 * m21 - m11 * m20));
+    scale(s);
+    return this;
+  }
+
+  /**
+   * Sets 16 values
+   * 
+   * @param m00
+   * @param m01
+   * @param m02
+   * @param m03
+   * @param m10
+   * @param m11
+   * @param m12
+   * @param m13
+   * @param m20
+   * @param m21
+   * @param m22
+   * @param m23
+   * @param m30
+   * @param m31
+   * @param m32
+   * @param m33
+   */
+  private void set(float m00, float m01, float m02, float m03, float m10,
+                   float m11, float m12, float m13, float m20, float m21,
+                   float m22, float m23, float m30, float m31, float m32,
+                   float m33) {
+    this.m00 = m00;
+    this.m01 = m01;
+    this.m02 = m02;
+    this.m03 = m03;
+    this.m10 = m10;
+    this.m11 = m11;
+    this.m12 = m12;
+    this.m13 = m13;
+    this.m20 = m20;
+    this.m21 = m21;
+    this.m22 = m22;
+    this.m23 = m23;
+    this.m30 = m30;
+    this.m31 = m31;
+    this.m32 = m32;
+    this.m33 = m33;
+  }
+  /**
+   * Computes the determinant of this matrix.
+   * 
+   * @return the determinant of the matrix
+   */
+  public float determinant4() {
+    // less *,+,- calculation than expanded expression.
+    return (m00 * m11 - m01 * m10) * (m22 * m33 - m23 * m32)
+        - (m00 * m12 - m02 * m10) * (m21 * m33 - m23 * m31)
+        + (m00 * m13 - m03 * m10) * (m21 * m32 - m22 * m31)
+        + (m01 * m12 - m02 * m11) * (m20 * m33 - m23 * m30)
+        - (m01 * m13 - m03 * m11) * (m20 * m32 - m22 * m30)
+        + (m02 * m13 - m03 * m12) * (m20 * m31 - m21 * m30);
+
+  }
+
+  /**
+   * Multiplies each element of this matrix by a scalar.
+   * 
+   * @param scalar
+   *        The scalar multiplier.
+   */
+  private void scale(float scalar) {
+    mul33(scalar);
+    m03 *= scalar;
+    m13 *= scalar;
+    m23 *= scalar;
+    m30 *= scalar;
+    m31 *= scalar;
+    m32 *= scalar;
+    m33 *= scalar;
+  }
+
+  /**
+   * Sets the value of this matrix to the result of multiplying itself with
+   * matrix m1.
+   * 
+   * @param m1
+   *        the other matrix
+   */
+  public void mul(M4 m1) {
+    mul2(this, m1);
+  }
+
+  /**
+   * Sets the value of this matrix to the result of multiplying the two argument
+   * matrices together.
+   * 
+   * @param m1
+   *        the first matrix
+   * @param m2
+   *        the second matrix
+   */
+  public void mul2(M4 m1, M4 m2) {
+    // alias-safe way.
+    set(m1.m00 * m2.m00 + m1.m01 * m2.m10 + m1.m02 * m2.m20 + m1.m03 * m2.m30,
+        m1.m00 * m2.m01 + m1.m01 * m2.m11 + m1.m02 * m2.m21 + m1.m03 * m2.m31,
+        m1.m00 * m2.m02 + m1.m01 * m2.m12 + m1.m02 * m2.m22 + m1.m03 * m2.m32,
+        m1.m00 * m2.m03 + m1.m01 * m2.m13 + m1.m02 * m2.m23 + m1.m03 * m2.m33,
+
+        m1.m10 * m2.m00 + m1.m11 * m2.m10 + m1.m12 * m2.m20 + m1.m13 * m2.m30,
+        m1.m10 * m2.m01 + m1.m11 * m2.m11 + m1.m12 * m2.m21 + m1.m13 * m2.m31,
+        m1.m10 * m2.m02 + m1.m11 * m2.m12 + m1.m12 * m2.m22 + m1.m13 * m2.m32,
+        m1.m10 * m2.m03 + m1.m11 * m2.m13 + m1.m12 * m2.m23 + m1.m13 * m2.m33,
+
+        m1.m20 * m2.m00 + m1.m21 * m2.m10 + m1.m22 * m2.m20 + m1.m23 * m2.m30,
+        m1.m20 * m2.m01 + m1.m21 * m2.m11 + m1.m22 * m2.m21 + m1.m23 * m2.m31,
+        m1.m20 * m2.m02 + m1.m21 * m2.m12 + m1.m22 * m2.m22 + m1.m23 * m2.m32,
+        m1.m20 * m2.m03 + m1.m21 * m2.m13 + m1.m22 * m2.m23 + m1.m23 * m2.m33,
+
+        m1.m30 * m2.m00 + m1.m31 * m2.m10 + m1.m32 * m2.m20 + m1.m33 * m2.m30,
+        m1.m30 * m2.m01 + m1.m31 * m2.m11 + m1.m32 * m2.m21 + m1.m33 * m2.m31,
+        m1.m30 * m2.m02 + m1.m31 * m2.m12 + m1.m32 * m2.m22 + m1.m33 * m2.m32,
+        m1.m30 * m2.m03 + m1.m31 * m2.m13 + m1.m32 * m2.m23 + m1.m33 * m2.m33);
+  }
+
+  /**
+   * Transform the vector vec using this Matrix4f and place the result back into
+   * vec.
+   * 
+   * @param vec
+   *        the single precision vector to be transformed
+   */
+  public void transform(T4 vec) {
+    transform2(vec, vec);
+  }
+
+  /**
+   * Transform the vector vec using this Matrix4f and place the result into
+   * vecOut.
+   * 
+   * @param vec
+   *        the single precision vector to be transformed
+   * @param vecOut
+   *        the vector into which the transformed values are placed
+   */
+  public void transform2(T4 vec, T4 vecOut) {
+    // alias-safe
+    vecOut.set4(m00 * vec.x + m01 * vec.y + m02 * vec.z + m03 * vec.w, m10
+        * vec.x + m11 * vec.y + m12 * vec.z + m13 * vec.w, m20 * vec.x + m21
+        * vec.y + m22 * vec.z + m23 * vec.w, m30 * vec.x + m31 * vec.y + m32
+        * vec.z + m33 * vec.w);
+  }
+
+  /**
+   * Transforms the point parameter with this Matrix4f and places the result
+   * back into point. The fourth element of the point input parameter is assumed
+   * to be one.
+   * 
+   * @param point
+   *        the input point to be transformed.
+   */
+  public void rotTrans(T3 point) {
+    rotTrans2(point, point);
+  }
+
+  /**
+   * Transforms the point parameter with this Matrix4f and places the result
+   * into pointOut. The fourth element of the point input parameter is assumed to
+   * be one. point may be pointOut
+   * 
+   * @param point
+   *        the input point to be transformed.
+   * @param pointOut
+   *        the transformed point
+   * @return pointOut
+   */
+  public T3 rotTrans2(T3 point, T3 pointOut) {
+      pointOut.set(
+          m00 * point.x + m01 * point.y + m02 * point.z + m03, 
+          m10 * point.x + m11 * point.y + m12 * point.z + m13, 
+          m20 * point.x + m21 * point.y + m22 * point.z + m23);
+      return pointOut;
+  }
+
+  /**
+   * Sets the value of this matrix to a rotation matrix about the w axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the W axis in radians
+   * @return this
+   */
+  public M4 setAsXYRotation(float angle) {
+    setIdentity();
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m22 = (float) c;
+    m23 = (float) -s;
+    m32 = (float) s;
+    m33 = (float) c;
+    return this;
+  }
+
+  /**
+   * Sets the value of this matrix to a rotation matrix about the w axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the W axis in radians
+   * @return this
+   */
+  public M4 setAsYZRotation(float angle) {
+    setIdentity();
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m00 = (float) c;
+    m03 = (float) -s;
+    m30 = (float) s;
+    m33 = (float) c;
+    return this;
+  }
+
+  /**
+   * Sets the value of this matrix to a rotation matrix about the w axis by the
+   * passed angle.
+   * 
+   * @param angle
+   *        the angle to rotate about the W axis in radians
+   * @return this
+   */
+  public M4 setAsXZRotation(float angle) {
+    setIdentity();
+    double c = Math.cos(angle);
+    double s = Math.sin(angle);
+    m11 = (float) c;
+    m13 = (float) -s;
+    m31 = (float) s;
+    m33 = (float) c;
+    return this;
+  }
+
+  /**
+   * Returns true if the Object o is of type Matrix4f and all of the data
+   * members of t1 are equal to the corresponding data members in this Matrix4f.
+   * 
+   * @param o
+   *        the object with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof M4))
+      return false;
+    M4 m = (M4) o;
+    return (this.m00 == m.m00 && this.m01 == m.m01 && this.m02 == m.m02
+        && this.m03 == m.m03 && this.m10 == m.m10 && this.m11 == m.m11
+        && this.m12 == m.m12 && this.m13 == m.m13 && this.m20 == m.m20
+        && this.m21 == m.m21 && this.m22 == m.m22 && this.m23 == m.m23
+        && this.m30 == m.m30 && this.m31 == m.m31 && this.m32 == m.m32 && this.m33 == m.m33);
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Matrix4f objects with identical data values (ie, returns true for
+   * equals(Matrix4f) ) will return the same hash number. Two objects with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   * 
+   * @return the integer hash value
+   */
+  @Override
+  public int hashCode() {
+    return T3.floatToIntBits0(m00) ^ T3.floatToIntBits0(m01)
+        ^ T3.floatToIntBits0(m02) ^ T3.floatToIntBits0(m03)
+        ^ T3.floatToIntBits0(m10) ^ T3.floatToIntBits0(m11)
+        ^ T3.floatToIntBits0(m12) ^ T3.floatToIntBits0(m13)
+        ^ T3.floatToIntBits0(m20) ^ T3.floatToIntBits0(m21)
+        ^ T3.floatToIntBits0(m22) ^ T3.floatToIntBits0(m23)
+        ^ T3.floatToIntBits0(m30) ^ T3.floatToIntBits0(m31)
+        ^ T3.floatToIntBits0(m32) ^ T3.floatToIntBits0(m33);
+  }
+
+  /**
+   * Returns a string that contains the values of this Matrix4f.
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "[\n  [" + m00 + "\t" + m01 + "\t" + m02 + "\t" + m03 + "]"
+        + "\n  [" + m10 + "\t" + m11 + "\t" + m12 + "\t" + m13 + "]" + "\n  ["
+        + m20 + "\t" + m21 + "\t" + m22 + "\t" + m23 + "]" + "\n  [" + m30
+        + "\t" + m31 + "\t" + m32 + "\t" + m33 + "] ]";
+  }
+  public M4 round(float f) {
+    m00 = rnd(m00, f);
+    m01 = rnd(m01, f);
+    m02 = rnd(m02, f);
+    m03 = rnd(m03, f);
+    m10 = rnd(m10, f);
+    m11 = rnd(m11, f);
+    m12 = rnd(m12, f);
+    m13 = rnd(m13, f);
+    m20 = rnd(m20, f);
+    m21 = rnd(m21, f);
+    m22 = rnd(m22, f);
+    m23 = rnd(m23, f);
+    m30 = rnd(m30, f);
+    m31 = rnd(m31, f);
+    m32 = rnd(m32, f);
+    m33 = rnd(m33, f);
+    return this;
+  }
+
+  private float rnd(float n, float f) {
+    return (Math.abs(n) < f ? 0 : n);
+  }
+}
diff --git a/src/javajs/util/Matrix.java b/src/javajs/util/Matrix.java
new file mode 100644 (file)
index 0000000..cea5a04
--- /dev/null
@@ -0,0 +1,457 @@
+package javajs.util;
+
+/**
+ * 
+ * streamlined and refined for Jmol by Bob Hanson
+ * 
+ * from http://math.nist.gov/javanumerics/jama/
+ * 
+ * Jama = Java Matrix class.
+ * 
+ * @author The MathWorks, Inc. and the National Institute of Standards and
+ *         Technology.
+ * @version 5 August 1998
+ */
+
+public class Matrix implements Cloneable {
+
+  public double[][] a;
+  protected int m, n;
+
+  /**
+   * Construct a matrix quickly without checking arguments.
+   * 
+   * @param a
+   *        Two-dimensional array of doubles or null
+   * @param m
+   *        Number of rows.
+   * @param n
+   *        Number of colums.
+   */
+
+  public Matrix(double[][] a, int m, int n) {
+    this.a = (a == null ? new double[m][n] : a);
+    this.m = m;
+    this.n = n;
+  }
+
+  /**
+   * Get row dimension.
+   * 
+   * @return m, the number of rows.
+   */
+
+  public int getRowDimension() {
+    return m;
+  }
+
+  /**
+   * Get column dimension.
+   * 
+   * @return n, the number of columns.
+   */
+
+  public int getColumnDimension() {
+    return n;
+  }
+
+  /**
+   * Access the internal two-dimensional array.
+   * 
+   * @return Pointer to the two-dimensional array of matrix elements.
+   */
+
+  public double[][] getArray() {
+    return a;
+  }
+
+  /**
+   * Copy the internal two-dimensional array.
+   * 
+   * @return Two-dimensional array copy of matrix elements.
+   */
+
+  public double[][] getArrayCopy() {
+    double[][] x = new double[m][n];
+    for (int i = m; --i >= 0;)
+      for (int j = n; --j >= 0;)
+        x[i][j] = a[i][j];
+    return x;
+  }
+
+  /**
+   * Make a deep copy of a matrix
+   * 
+   * @return copy
+   */
+
+  public Matrix copy() {
+    Matrix x = new Matrix(null, m, n);
+    double[][] c = x.a;
+    for (int i = m; --i >= 0;)
+      for (int j = n; --j >= 0;)
+        c[i][j] = a[i][j];
+    return x;
+  }
+
+  /**
+   * Clone the Matrix object.
+   */
+
+  @Override
+  public Object clone() {
+    return copy();
+  }
+
+  /**
+   * Get a submatrix.
+   * 
+   * @param i0
+   *        Initial row index
+   * @param j0
+   *        Initial column index
+   * @param nrows
+   *        Number of rows
+   * @param ncols
+   *        Number of columns
+   * @return submatrix
+   * 
+   */
+
+  public Matrix getSubmatrix(int i0, int j0, int nrows, int ncols) {
+    Matrix x = new Matrix(null, nrows, ncols);
+    double[][] xa = x.a;
+    for (int i = nrows; --i >= 0;)
+      for (int j = ncols; --j >= 0;)
+        xa[i][j] = a[i0 + i][j0 + j];
+    return x;
+  }
+
+  /**
+   * Get a submatrix for a give number of columns and selected row set.
+   * 
+   * @param r
+   *        Array of row indices.
+   * @param n
+   *        number of rows 
+   * @return submatrix
+   */
+
+  public Matrix getMatrixSelected(int[] r, int n) {
+    Matrix x = new Matrix(null, r.length, n);
+    double[][] xa = x.a;
+    for (int i = r.length; --i >= 0;) {
+      double[] b = a[r[i]];
+      for (int j = n; --j >= 0;)
+        xa[i][j] = b[j];
+    }
+    return x;
+  }
+
+  /**
+   * Matrix transpose.
+   * 
+   * @return A'
+   */
+
+  public Matrix transpose() {
+    Matrix x = new Matrix(null, n, m);
+    double[][] c = x.a;
+    for (int i = m; --i >= 0;)
+      for (int j = n; --j >= 0;)
+        c[j][i] = a[i][j];
+    return x;
+  }
+
+  /**
+   * add two matrices
+   * @param b
+   * @return new Matrix this + b
+   */
+  public Matrix add(Matrix b) {
+    return scaleAdd(b, 1);
+  }
+
+  /**
+   * subtract two matrices
+   * @param b
+   * @return new Matrix this - b
+   */
+  public Matrix sub(Matrix b) {
+    return scaleAdd(b, -1);
+  }
+  
+  /**
+   * X = A + B*scale
+   * @param b 
+   * @param scale 
+   * @return X
+   * 
+   */
+  public Matrix scaleAdd(Matrix b, double scale) {
+    Matrix x = new Matrix(null, m, n);
+    double[][] xa = x.a;
+    double[][] ba = b.a;
+    for (int i = m; --i >= 0;)
+      for (int j = n; --j >= 0;)
+        xa[i][j] = ba[i][j] * scale + a[i][j];
+    return x;
+  }
+
+  /**
+   * Linear algebraic matrix multiplication, A * B
+   * 
+   * @param b
+   *        another matrix
+   * @return Matrix product, A * B or null for wrong dimension
+   */
+
+  public Matrix mul(Matrix b) {
+    if (b.m != n)
+      return null;
+    Matrix x = new Matrix(null, m, b.n);
+    double[][] xa = x.a;
+    double[][] ba = b.a;
+    for (int j = b.n; --j >= 0;)
+      for (int i = m; --i >= 0;) {
+        double[] arowi = a[i];
+        double s = 0;
+        for (int k = n; --k >= 0;)
+          s += arowi[k] * ba[k][j];
+        xa[i][j] = s;
+      }
+    return x;
+  }
+
+  /**
+   * Matrix inverse or pseudoinverse
+   * 
+   * @return inverse (m == n) or pseudoinverse (m != n)
+   */
+
+  public Matrix inverse() {
+    return new LUDecomp(m, n).solve(identity(m, m), n);
+  }
+
+  /**
+   * Matrix trace.
+   * 
+   * @return sum of the diagonal elements.
+   */
+
+  public double trace() {
+    double t = 0;
+    for (int i = Math.min(m, n); --i >= 0;)
+      t += a[i][i];
+    return t;
+  }
+
+  /**
+   * Generate identity matrix
+   * 
+   * @param m
+   *        Number of rows.
+   * @param n
+   *        Number of columns.
+   * @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
+   */
+
+  public static Matrix identity(int m, int n) {
+    Matrix x = new Matrix(null, m, n);
+    double[][] xa = x.a;
+    for (int i = Math.min(m, n); --i >= 0;)
+      xa[i][i] = 1;
+    return x;
+  }
+
+  /**
+   * similarly to M3/M4 standard rotation/translation matrix
+   * we set a rotationTranslation matrix to be:
+   * 
+   * [   nxn rot    nx1 trans
+   * 
+   *     1xn  0     1x1 1      ]
+   * 
+   * 
+   * @return rotation matrix
+   */
+  public Matrix getRotation() {
+    return getSubmatrix(0, 0, m - 1, n - 1);
+  }
+
+  public Matrix getTranslation() {
+    return getSubmatrix(0, n - 1, m - 1, 1);
+  }
+
+  public static Matrix newT(T3 r, boolean asColumn) {
+    return (asColumn ? new Matrix(new double[][] { new double[] { r.x },
+        new double[] { r.y }, new double[] { r.z } }, 3, 1) : new Matrix(
+        new double[][] { new double[] { r.x, r.y, r.z } }, 1, 3));
+  }
+
+  @Override
+  public String toString() {
+    String s = "[\n";
+    for (int i = 0; i < m; i++) {
+      s += "  [";
+      for (int j = 0; j < n; j++)
+        s += " " + a[i][j];
+      s += "]\n";
+    }
+    s += "]";
+    return s;
+  }
+
+  /**
+   * 
+   * Edited down by Bob Hanson for minimum needed by Jmol -- just constructor
+   * and solve
+   * 
+   * LU Decomposition.
+   * <P>
+   * For an m-by-n matrix A with m >= n, the LU decomposition is an m-by-n unit
+   * lower triangular matrix L, an n-by-n upper triangular matrix U, and a
+   * permutation vector piv of length m so that A(piv,:) = L*U. If m < n, then L
+   * is m-by-m and U is m-by-n.
+   * <P>
+   * The LU decompostion with pivoting always exists, even if the matrix is
+   * singular, so the constructor will never fail. The primary use of the LU
+   * decomposition is in the solution of square systems of simultaneous linear
+   * equations. This will fail if isNonsingular() returns false.
+   */
+
+  private class LUDecomp {
+
+    /* ------------------------
+       Class variables
+     * ------------------------ */
+
+    /**
+     * Array for internal storage of decomposition.
+     * 
+     */
+    private double[][] LU;
+
+    /**
+     * Internal storage of pivot vector.
+     * 
+     */
+    private int[] piv;
+
+    private int pivsign;
+
+    /* ------------------------
+       Constructor
+     * ------------------------ */
+
+    /**
+     * LU Decomposition Structure to access L, U and piv.
+     * @param m 
+     * @param n 
+     * 
+     */
+
+    protected LUDecomp(int m, int n) {
+      
+      // Use a "left-looking", dot-product, Crout/Doolittle algorithm.
+
+      LU = getArrayCopy();
+      piv = new int[m];
+      for (int i = m; --i >= 0;)
+        piv[i] = i;
+      pivsign = 1;
+      double[] LUrowi;
+      double[] LUcolj = new double[m];
+
+      // Outer loop.
+
+      for (int j = 0; j < n; j++) {
+
+        // Make a copy of the j-th column to localize references.
+
+        for (int i = m; --i >= 0;)
+          LUcolj[i] = LU[i][j];
+
+        // Apply previous transformations.
+
+        for (int i = m; --i >= 0;) {
+          LUrowi = LU[i];
+
+          // Most of the time is spent in the following dot product.
+
+          int kmax = Math.min(i, j);
+          double s = 0.0;
+          for (int k = kmax; --k >= 0;)
+            s += LUrowi[k] * LUcolj[k];
+
+          LUrowi[j] = LUcolj[i] -= s;
+        }
+
+        // Find pivot and exchange if necessary.
+
+        int p = j;
+        for (int i = m; --i > j;)
+          if (Math.abs(LUcolj[i]) > Math.abs(LUcolj[p]))
+            p = i;
+        if (p != j) {
+          for (int k = n; --k >= 0;) {
+            double t = LU[p][k];
+            LU[p][k] = LU[j][k];
+            LU[j][k] = t;
+          }
+          int k = piv[p];
+          piv[p] = piv[j];
+          piv[j] = k;
+          pivsign = -pivsign;
+        }
+
+        // Compute multipliers.
+
+        if (j < m & LU[j][j] != 0.0)
+          for (int i = m; --i > j;)
+            LU[i][j] /= LU[j][j];
+      }
+    }
+
+    /* ------------------------
+       default Methods
+     * ------------------------ */
+
+    /**
+     * Solve A*X = B
+     * 
+     * @param b
+     *        A Matrix with as many rows as A and any number of columns.
+     * @param n 
+     * @return X so that L*U*X = B(piv,:) or null for wrong size or singular matrix
+     */
+
+    protected Matrix solve(Matrix b, int n) {
+      for (int j = 0; j < n; j++)
+        if (LU[j][j] == 0)
+          return null; // matrix is singular
+
+      // Copy right hand side with pivoting
+      int nx = b.n;
+      Matrix x = b.getMatrixSelected(piv, nx);
+      double[][] a = x.a;
+
+      // Solve L*Y = B(piv,:)
+      for (int k = 0; k < n; k++)
+        for (int i = k + 1; i < n; i++)
+          for (int j = 0; j < nx; j++)
+            a[i][j] -= a[k][j] * LU[i][k];
+
+      // Solve U*X = Y;
+      for (int k = n; --k >= 0;) {
+        for (int j = nx; --j >= 0;)
+          a[k][j] /= LU[k][k];
+        for (int i = k; --i >= 0;)
+          for (int j = nx; --j >= 0;)
+            a[i][j] -= a[k][j] * LU[i][k];
+      }
+      return x;
+    }
+  }
+
+}
diff --git a/src/javajs/util/Measure.java b/src/javajs/util/Measure.java
new file mode 100644 (file)
index 0000000..09b9807
--- /dev/null
@@ -0,0 +1,733 @@
+/* $RCSfile$
+ * $Author: egonw $
+ * $Date: 2005-11-10 09:52:44 -0600 (Thu, 10 Nov 2005) $
+ * $Revision: 4255 $
+ *
+ * Copyright (C) 2003-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+import javajs.api.EigenInterface;
+
+import javajs.api.Interface;
+
+
+
+
+//import org.jmol.script.T;
+
+final public class Measure {
+
+  public final static float radiansPerDegree = (float) (2 * Math.PI / 360);
+  
+  public static float computeAngle(T3 pointA, T3 pointB, T3 pointC, V3 vectorBA, V3 vectorBC, boolean asDegrees) {
+    vectorBA.sub2(pointA, pointB);
+    vectorBC.sub2(pointC, pointB);
+    float angle = vectorBA.angle(vectorBC);
+    return (asDegrees ? angle / radiansPerDegree : angle);
+  }
+
+  public static float computeAngleABC(T3 pointA, T3 pointB, T3 pointC, boolean asDegrees) {
+    V3 vectorBA = new V3();
+    V3 vectorBC = new V3();        
+    return computeAngle(pointA, pointB, pointC, vectorBA, vectorBC, asDegrees);
+  }
+
+  public static float computeTorsion(T3 p1, T3 p2, T3 p3, T3 p4, boolean asDegrees) {
+  
+    float ijx = p1.x - p2.x;
+    float ijy = p1.y - p2.y;
+    float ijz = p1.z - p2.z;
+  
+    float kjx = p3.x - p2.x;
+    float kjy = p3.y - p2.y;
+    float kjz = p3.z - p2.z;
+  
+    float klx = p3.x - p4.x;
+    float kly = p3.y - p4.y;
+    float klz = p3.z - p4.z;
+  
+    float ax = ijy * kjz - ijz * kjy;
+    float ay = ijz * kjx - ijx * kjz;
+    float az = ijx * kjy - ijy * kjx;
+    float cx = kjy * klz - kjz * kly;
+    float cy = kjz * klx - kjx * klz;
+    float cz = kjx * kly - kjy * klx;
+  
+    float ai2 = 1f / (ax * ax + ay * ay + az * az);
+    float ci2 = 1f / (cx * cx + cy * cy + cz * cz);
+  
+    float ai = (float) Math.sqrt(ai2);
+    float ci = (float) Math.sqrt(ci2);
+    float denom = ai * ci;
+    float cross = ax * cx + ay * cy + az * cz;
+    float cosang = cross * denom;
+    if (cosang > 1) {
+      cosang = 1;
+    }
+    if (cosang < -1) {
+      cosang = -1;
+    }
+  
+    float torsion = (float) Math.acos(cosang);
+    float dot = ijx * cx + ijy * cy + ijz * cz;
+    float absDot = Math.abs(dot);
+    torsion = (dot / absDot > 0) ? torsion : -torsion;
+    return (asDegrees ? torsion / radiansPerDegree : torsion);
+  }
+
+  /**
+   * This method calculates measures relating to two points in space 
+   * with related quaternion frame difference. It is used in Jmol for
+   * calculating straightness and many other helical quantities.
+   * 
+   * @param a
+   * @param b
+   * @param dq
+   * @return  new T3[] { pt_a_prime, n, r, P3.new3(theta, pitch, residuesPerTurn), pt_b_prime };
+   */
+  public static T3[] computeHelicalAxis(P3 a, P3 b, Quat dq) {
+    
+    //                b
+    //           |   /|
+    //           |  / |
+    //           | /  |
+    //           |/   c
+    //         b'+   / \
+    //           |  /   \      Vcb = Vab . n
+    //         n | /     \d    Vda = (Vcb - Vab) / 2
+    //           |/theta  \
+    //         a'+---------a
+    //                r 
+
+    V3 vab = new V3();
+    vab.sub2(b, a);
+    /*
+     * testing here to see if directing the normal makes any difference -- oddly
+     * enough, it does not. When n = -n and theta = -theta vab.n is reversed,
+     * and that magnitude is multiplied by n in generating the A'-B' vector.
+     * 
+     * a negative angle implies a left-handed axis (sheets)
+     */
+    float theta = dq.getTheta();
+    V3 n = dq.getNormal();
+    float v_dot_n = vab.dot(n);
+    if (Math.abs(v_dot_n) < 0.0001f)
+      v_dot_n = 0;
+    V3 va_prime_d = new V3();
+    va_prime_d.cross(vab, n);
+    if (va_prime_d.dot(va_prime_d) != 0)
+      va_prime_d.normalize();
+    V3 vda = new V3();
+    V3 vcb = V3.newV(n);
+    if (v_dot_n == 0)
+      v_dot_n = PT.FLOAT_MIN_SAFE; // allow for perpendicular axis to vab
+    vcb.scale(v_dot_n);
+    vda.sub2(vcb, vab);
+    vda.scale(0.5f);
+    va_prime_d.scale(theta == 0 ? 0 : (float) (vda.length() / Math.tan(theta
+        / 2 / 180 * Math.PI)));
+    V3 r = V3.newV(va_prime_d);
+    if (theta != 0)
+      r.add(vda);
+    P3 pt_a_prime = P3.newP(a);
+    pt_a_prime.sub(r);
+    // already done this. ??
+    if (v_dot_n != PT.FLOAT_MIN_SAFE)
+      n.scale(v_dot_n);
+    // must calculate directed angle:
+    P3 pt_b_prime = P3.newP(pt_a_prime);
+    pt_b_prime.add(n);
+    theta = computeTorsion(a, pt_a_prime, pt_b_prime, b, true);
+    if (Float.isNaN(theta) || r.length() < 0.0001f)
+      theta = dq.getThetaDirectedV(n); // allow for r = 0
+    // anything else is an array
+    float residuesPerTurn = Math.abs(theta == 0 ? 0 : 360f / theta);
+    float pitch = Math.abs(v_dot_n == PT.FLOAT_MIN_SAFE ? 0 : n.length()
+        * (theta == 0 ? 1 : 360f / theta));
+    return new T3[] { pt_a_prime, n, r, P3.new3(theta, pitch, residuesPerTurn), pt_b_prime };
+  }
+
+  public static P4 getPlaneThroughPoints(T3 pointA,
+                                              T3 pointB,
+                                              T3 pointC, V3 vNorm,
+                                              V3 vAB, P4 plane) {
+    float w = getNormalThroughPoints(pointA, pointB, pointC, vNorm, vAB);
+    plane.set4(vNorm.x, vNorm.y, vNorm.z, w);
+    return plane;
+  }
+  
+  public static void getPlaneThroughPoint(T3 pt, V3 normal, P4 plane) {
+    plane.set4(normal.x, normal.y, normal.z, -normal.dot(pt));
+  }
+  
+  public static float distanceToPlane(P4 plane, T3 pt) {
+    return (plane == null ? Float.NaN 
+        : (plane.dot(pt) + plane.w) / (float) Math.sqrt(plane.dot(plane)));
+  }
+
+  public static float directedDistanceToPlane(P3 pt, P4 plane, P3 ptref) {
+    float f = plane.dot(pt) + plane.w;
+    float f1 = plane.dot(ptref) + plane.w;
+    return Math.signum(f1) * f /  (float) Math.sqrt(plane.dot(plane));
+  }
+
+  public static float distanceToPlaneD(P4 plane, float d, P3 pt) {
+    return (plane == null ? Float.NaN : (plane.dot(pt) + plane.w) / d);
+  }
+
+  public static float distanceToPlaneV(V3 norm, float w, P3 pt) {
+    return (norm == null ? Float.NaN 
+        : (norm.dot(pt) + w)  / (float) Math.sqrt(norm.dot(norm)));
+  }
+
+  /**
+   * note that if vAB or vAC is dispensible, vNormNorm can be one of them
+   * @param pointA
+   * @param pointB
+   * @param pointC
+   * @param vNormNorm
+   * @param vAB
+   */
+  public static void calcNormalizedNormal(T3 pointA, T3 pointB,
+         T3 pointC, V3 vNormNorm, V3 vAB) {
+    vAB.sub2(pointB, pointA);
+    vNormNorm.sub2(pointC, pointA);
+    vNormNorm.cross(vAB, vNormNorm);
+    vNormNorm.normalize();
+  }
+
+  public static float getDirectedNormalThroughPoints(T3 pointA, 
+         T3 pointB, T3 pointC, T3 ptRef, V3 vNorm, 
+         V3 vAB) {
+    // for x = plane({atomno=1}, {atomno=2}, {atomno=3}, {atomno=4})
+    float nd = getNormalThroughPoints(pointA, pointB, pointC, vNorm, vAB);
+    if (ptRef != null) {
+      P3 pt0 = P3.newP(pointA);
+      pt0.add(vNorm);
+      float d = pt0.distance(ptRef);
+      pt0.sub2(pointA, vNorm);
+      if (d > pt0.distance(ptRef)) {
+        vNorm.scale(-1);
+        nd = -nd;
+      }
+    }
+    return nd;
+  }
+  
+  /**
+   * if vAC is dispensible vNorm can be vAC
+   * @param pointA
+   * @param pointB
+   * @param pointC
+   * @param vNorm
+   * @param vTemp
+   * @return w
+   */
+  public static float getNormalThroughPoints(T3 pointA, T3 pointB,
+                                   T3 pointC, V3 vNorm, V3 vTemp) {
+    // for Polyhedra
+    calcNormalizedNormal(pointA, pointB, pointC, vNorm, vTemp);
+    // ax + by + cz + d = 0
+    // so if a point is in the plane, then N dot X = -d
+    vTemp.setT(pointA);
+    return -vTemp.dot(vNorm);
+  }
+
+  public static void getPlaneProjection(P3 pt, P4 plane, P3 ptProj, V3 vNorm) {
+    float dist = distanceToPlane(plane, pt);
+    vNorm.set(plane.x, plane.y, plane.z);
+    vNorm.normalize();
+    vNorm.scale(-dist);
+    ptProj.add2(pt, vNorm);
+  }
+
+  public final static V3 axisY = V3.new3(0, 1, 0);
+  
+  public static void getNormalToLine(P3 pointA, P3 pointB,
+                                   V3 vNormNorm) {
+    // vector in xy plane perpendicular to a line between two points RMH
+    vNormNorm.sub2(pointA, pointB);
+    vNormNorm.cross(vNormNorm, axisY);
+    vNormNorm.normalize();
+    if (Float.isNaN(vNormNorm.x))
+      vNormNorm.set(1, 0, 0);
+  }
+  
+  public static void getBisectingPlane(P3 pointA, V3 vAB,
+                                                 T3 ptTemp, V3 vTemp, P4 plane) {
+    ptTemp.scaleAdd2(0.5f, vAB, pointA);
+    vTemp.setT(vAB);
+    vTemp.normalize();
+    getPlaneThroughPoint(ptTemp, vTemp, plane);
+    }
+    
+  public static void projectOntoAxis(P3 point, P3 axisA,
+                                     V3 axisUnitVector,
+                                     V3 vectorProjection) {
+    vectorProjection.sub2(point, axisA);
+    float projectedLength = vectorProjection.dot(axisUnitVector);
+    point.scaleAdd2(projectedLength, axisUnitVector, axisA);
+    vectorProjection.sub2(point, axisA);
+  }
+  
+  public static void calcBestAxisThroughPoints(P3[] points, P3 axisA,
+                                               V3 axisUnitVector,
+                                               V3 vectorProjection,
+                                               int nTriesMax) {
+    // just a crude starting point.
+
+    int nPoints = points.length;
+    axisA.setT(points[0]);
+    axisUnitVector.sub2(points[nPoints - 1], axisA);
+    axisUnitVector.normalize();
+
+    /*
+     * We now calculate the least-squares 3D axis
+     * through the helix alpha carbons starting with Vo
+     * as a first approximation.
+     * 
+     * This uses the simple 0-centered least squares fit:
+     * 
+     * Y = M cross Xi
+     * 
+     * minimizing R^2 = SUM(|Y - Yi|^2) 
+     * 
+     * where Yi is the vector PERPENDICULAR of the point onto axis Vo
+     * and Xi is the vector PROJECTION of the point onto axis Vo
+     * and M is a vector adjustment 
+     * 
+     * M = SUM_(Xi cross Yi) / sum(|Xi|^2)
+     * 
+     * from which we arrive at:
+     * 
+     * V = Vo + (M cross Vo)
+     * 
+     * Basically, this is just a 3D version of a 
+     * standard 2D least squares fit to a line, where we would say:
+     * 
+     * y = m xi + b
+     * 
+     * D = n (sum xi^2) - (sum xi)^2
+     * 
+     * m = [(n sum xiyi) - (sum xi)(sum yi)] / D
+     * b = [(sum yi) (sum xi^2) - (sum xi)(sum xiyi)] / D
+     * 
+     * but here we demand that the line go through the center, so we
+     * require (sum xi) = (sum yi) = 0, so b = 0 and
+     * 
+     * m = (sum xiyi) / (sum xi^2)
+     * 
+     * In 3D we do the same but 
+     * instead of x we have Vo,
+     * instead of multiplication we use cross products
+     * 
+     * A bit of iteration is necessary.
+     * 
+     * Bob Hanson 11/2006
+     * 
+     */
+
+    calcAveragePointN(points, nPoints, axisA);
+
+    int nTries = 0;
+    while (nTries++ < nTriesMax
+        && findAxis(points, nPoints, axisA, axisUnitVector, vectorProjection) > 0.001) {
+    }
+
+    /*
+     * Iteration here gets the job done.
+     * We now find the projections of the endpoints onto the axis
+     * 
+     */
+
+    P3 tempA = P3.newP(points[0]);
+    projectOntoAxis(tempA, axisA, axisUnitVector, vectorProjection);
+    axisA.setT(tempA);
+  }
+
+  public static float findAxis(P3[] points, int nPoints, P3 axisA,
+                        V3 axisUnitVector, V3 vectorProjection) {
+    V3 sumXiYi = new V3();
+    V3 vTemp = new V3();
+    P3 pt = new P3();
+    P3 ptProj = new P3();
+    V3 a = V3.newV(axisUnitVector);
+
+    float sum_Xi2 = 0;
+    for (int i = nPoints; --i >= 0;) {
+      pt.setT(points[i]);
+      ptProj.setT(pt);
+      projectOntoAxis(ptProj, axisA, axisUnitVector,
+          vectorProjection);
+      vTemp.sub2(pt, ptProj);
+      //sum_Yi2 += vTemp.lengthSquared();
+      vTemp.cross(vectorProjection, vTemp);
+      sumXiYi.add(vTemp);
+      sum_Xi2 += vectorProjection.lengthSquared();
+    }
+    V3 m = V3.newV(sumXiYi);
+    m.scale(1 / sum_Xi2);
+    vTemp.cross(m, axisUnitVector);
+    axisUnitVector.add(vTemp);
+    axisUnitVector.normalize();  
+    //check for change in direction by measuring vector difference length
+    vTemp.sub2(axisUnitVector, a);
+    return vTemp.length();
+  }
+  
+  
+  public static void calcAveragePoint(P3 pointA, P3 pointB,
+                                      P3 pointC) {
+    pointC.set((pointA.x + pointB.x) / 2, (pointA.y + pointB.y) / 2,
+        (pointA.z + pointB.z) / 2);
+  }
+  
+  public static void calcAveragePointN(P3[] points, int nPoints,
+                                P3 averagePoint) {
+    averagePoint.setT(points[0]);
+    for (int i = 1; i < nPoints; i++)
+      averagePoint.add(points[i]);
+    averagePoint.scale(1f / nPoints);
+  }
+
+  public static Lst<P3> transformPoints(Lst<P3> vPts, M4 m4, P3 center) {
+    Lst<P3> v = new  Lst<P3>();
+    for (int i = 0; i < vPts.size(); i++) {
+      P3 pt = P3.newP(vPts.get(i));
+      pt.sub(center);
+      m4.rotTrans(pt);
+      pt.add(center);
+      v.addLast(pt);
+    }
+    return v;
+  }
+
+  public static boolean isInTetrahedron(P3 pt, P3 ptA, P3 ptB,
+                                        P3 ptC, P3 ptD,
+                                        P4 plane, V3 vTemp,
+                                        V3 vTemp2, boolean fullyEnclosed) {
+    boolean b = (distanceToPlane(getPlaneThroughPoints(ptC, ptD, ptA, vTemp, vTemp2, plane), pt) >= 0);
+    if (b != (distanceToPlane(getPlaneThroughPoints(ptA, ptD, ptB, vTemp, vTemp2, plane), pt) >= 0))
+      return false;
+    if (b != (distanceToPlane(getPlaneThroughPoints(ptB, ptD, ptC, vTemp, vTemp2, plane), pt) >= 0))
+      return false;
+    float d = distanceToPlane(getPlaneThroughPoints(ptA, ptB, ptC, vTemp, vTemp2, plane), pt);
+    if (fullyEnclosed)
+      return (b == (d >= 0));
+    float d1 = distanceToPlane(plane, ptD);
+    return d1 * d <= 0 || Math.abs(d1) > Math.abs(d);
+  }
+
+
+  /**
+   * 
+   * @param plane1
+   * @param plane2
+   * @return       [ point, vector ] or []
+   */
+  public static Lst<Object> getIntersectionPP(P4 plane1, P4 plane2) {
+    float a1 = plane1.x;
+    float b1 = plane1.y;
+    float c1 = plane1.z;
+    float d1 = plane1.w;
+    float a2 = plane2.x;
+    float b2 = plane2.y;
+    float c2 = plane2.z;
+    float d2 = plane2.w;
+    V3 norm1 = V3.new3(a1, b1, c1);
+    V3 norm2 = V3.new3(a2, b2, c2);
+    V3 nxn = new V3();
+    nxn.cross(norm1, norm2);
+    float ax = Math.abs(nxn.x);
+    float ay = Math.abs(nxn.y);
+    float az = Math.abs(nxn.z);
+    float x, y, z, diff;
+    int type = (ax > ay ? (ax > az ? 1 : 3) : ay > az ? 2 : 3);
+    switch(type) {
+    case 1:
+      x = 0;
+      diff = (b1 * c2 - b2 * c1);
+      if (Math.abs(diff) < 0.01) return null;
+      y = (c1 * d2 - c2 * d1) / diff;
+      z = (b2 * d1 - d2 * b1) / diff;
+      break;
+    case 2:
+      diff = (a1 * c2 - a2 * c1);
+      if (Math.abs(diff) < 0.01) return null;
+      x = (c1 * d2 - c2 * d1) / diff;
+      y = 0;
+      z = (a2 * d1 - d2 * a1) / diff;
+      break;
+    case 3:
+    default:
+      diff = (a1 * b2 - a2 * b1);
+      if (Math.abs(diff) < 0.01) return null;
+      x = (b1 * d2 - b2 * d1) / diff;
+      y = (a2 * d1 - d2 * a1) / diff;
+      z = 0;
+    }
+    Lst<Object>list = new  Lst<Object>();
+    list.addLast(P3.new3(x, y, z));
+    nxn.normalize();
+    list.addLast(nxn);
+    return list;
+  }
+
+  /**
+   * 
+   * @param pt1  point on line
+   * @param v    unit vector of line
+   * @param plane 
+   * @param ptRet  point of intersection of line with plane
+   * @param tempNorm 
+   * @param vTemp 
+   * @return       ptRtet
+   */
+  public static P3 getIntersection(P3 pt1, V3 v,
+                                               P4 plane, P3 ptRet, V3 tempNorm, V3 vTemp) {
+    getPlaneProjection(pt1, plane, ptRet, tempNorm);
+    tempNorm.set(plane.x, plane.y, plane.z);
+    tempNorm.normalize();
+    if (v == null)
+      v = V3.newV(tempNorm);
+    float l_dot_n = v.dot(tempNorm);
+    if (Math.abs(l_dot_n) < 0.01) return null;
+    vTemp.sub2(ptRet, pt1);
+    ptRet.scaleAdd2(vTemp.dot(tempNorm) / l_dot_n, v, pt1);
+    return ptRet;
+  }
+
+  /*
+    public static Point3f getTriangleIntersection(Point3f a1, Point3f a2,
+                                                 Point3f a3, Point4f plane,
+                                                 Point3f b1,
+                                                 Point3f b2, Point3f b3,
+                                                 Vector3f vNorm, Vector3f vTemp, 
+                                                 Point3f ptRet, Point3f ptTemp, Vector3f vTemp2, Point4f pTemp, Vector3f vTemp3) {
+      
+      if (getTriangleIntersection(b1, b2, a1, a2, a3, vTemp, plane, vNorm, vTemp2, vTemp3, ptRet, ptTemp))
+        return ptRet;
+      if (getTriangleIntersection(b2, b3, a1, a2, a3, vTemp, plane, vNorm, vTemp2, vTemp3, ptRet, ptTemp))
+        return ptRet;
+      if (getTriangleIntersection(b3, b1, a1, a2, a3, vTemp, plane, vNorm, vTemp2, vTemp3, ptRet, ptTemp))
+        return ptRet;
+      return null;
+    }
+  */
+  /*  
+    public static boolean getTriangleIntersection(Point3f b1, Point3f b2,
+                                                  Point3f a1, Point3f a2,
+                                                  Point3f a3, Vector3f vTemp,
+                                                  Point4f plane, Vector3f vNorm,
+                                                  Vector3f vTemp2, Vector3f vTemp3,
+                                                  Point3f ptRet,
+                                                  Point3f ptTemp) {
+      if (distanceToPlane(plane, b1) * distanceToPlane(plane, b2) >= 0)
+        return false;
+      vTemp.sub(b2, b1);
+      vTemp.normalize();
+      if (getIntersection(b1, vTemp, plane, ptRet, vNorm, vTemp2) != null) {
+        if (isInTriangle(ptRet, a1, a2, a3, vTemp, vTemp2, vTemp3))
+          return true;
+      }
+      return false;
+    }
+    private static boolean isInTriangle(Point3f p, Point3f a, Point3f b,
+                                        Point3f c, Vector3f v0, Vector3f v1,
+                                        Vector3f v2) {
+      // from http://www.blackpawn.com/texts/pointinpoly/default.html
+      // Compute barycentric coordinates
+      v0.sub(c, a);
+      v1.sub(b, a);
+      v2.sub(p, a);
+      float dot00 = v0.dot(v0);
+      float dot01 = v0.dot(v1);
+      float dot02 = v0.dot(v2);
+      float dot11 = v1.dot(v1);
+      float dot12 = v1.dot(v2);
+      float invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+      float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+      float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+      return (u > 0 && v > 0 && u + v < 1);
+    }
+  */
+
+  /**
+   * Closed-form solution of absolute orientation requiring 1:1 mapping of
+   * positions.
+   * 
+   * @param centerAndPoints
+   * @param retStddev
+   * @return unit quaternion representation rotation
+   * 
+   * @author hansonr Bob Hanson
+   * 
+   */
+  public static Quat calculateQuaternionRotation(P3[][] centerAndPoints,
+                                                 float[] retStddev) {
+
+    retStddev[1] = Float.NaN;
+    Quat q = new Quat();
+    if (centerAndPoints[0].length == 1
+        || centerAndPoints[0].length != centerAndPoints[1].length)
+      return q;
+
+    /*
+     * see Berthold K. P. Horn,
+     * "Closed-form solution of absolute orientation using unit quaternions" J.
+     * Opt. Soc. Amer. A, 1987, Vol. 4, pp. 629-642
+     * http://www.opticsinfobase.org/viewmedia.cfm?uri=josaa-4-4-629&seq=0
+     * 
+     * 
+     * A similar treatment was developed independently (and later!) 
+     * by G. Kramer, in G. R. Kramer,
+     * "Superposition of Molecular Structures Using Quaternions"
+     * Molecular Simulation, 1991, Vol. 7, pp. 113-119. 
+     * 
+     *  In that treatment there is a lot of unnecessary calculation 
+     *  along the trace of matrix M (eqn 20). 
+     *  I'm not sure why the extra x^2 + y^2 + z^2 + x'^2 + y'^2 + z'^2
+     *  is in there, but they are unnecessary and only contribute to larger
+     *  numerical averaging errors and additional processing time, as far as
+     *  I can tell. Adding aI, where a is a scalar and I is the 4x4 identity
+     *  just offsets the eigenvalues but doesn't change the eigenvectors.
+     * 
+     * and Lydia E. Kavraki, "Molecular Distance Measures"
+     * http://cnx.org/content/m11608/latest/
+     * 
+     */
+
+    int n = centerAndPoints[0].length - 1;
+    if (n < 2)
+      return q;
+
+    double Sxx = 0, Sxy = 0, Sxz = 0, Syx = 0, Syy = 0, Syz = 0, Szx = 0, Szy = 0, Szz = 0;
+    P3 ptA = new P3();
+    P3 ptB = new P3();
+    for (int i = n + 1; --i >= 1;) {
+      P3 aij = centerAndPoints[0][i];
+      P3 bij = centerAndPoints[1][i];
+      ptA.sub2(aij, centerAndPoints[0][0]);
+      ptB.sub2(bij, centerAndPoints[0][1]);
+      Sxx += (double) ptA.x * (double) ptB.x;
+      Sxy += (double) ptA.x * (double) ptB.y;
+      Sxz += (double) ptA.x * (double) ptB.z;
+      Syx += (double) ptA.y * (double) ptB.x;
+      Syy += (double) ptA.y * (double) ptB.y;
+      Syz += (double) ptA.y * (double) ptB.z;
+      Szx += (double) ptA.z * (double) ptB.x;
+      Szy += (double) ptA.z * (double) ptB.y;
+      Szz += (double) ptA.z * (double) ptB.z;
+    }
+    retStddev[0] = getRmsd(centerAndPoints, q);
+    double[][] N = new double[4][4];
+    N[0][0] = Sxx + Syy + Szz;
+    N[0][1] = N[1][0] = Syz - Szy;
+    N[0][2] = N[2][0] = Szx - Sxz;
+    N[0][3] = N[3][0] = Sxy - Syx;
+
+    N[1][1] = Sxx - Syy - Szz;
+    N[1][2] = N[2][1] = Sxy + Syx;
+    N[1][3] = N[3][1] = Szx + Sxz;
+
+    N[2][2] = -Sxx + Syy - Szz;
+    N[2][3] = N[3][2] = Syz + Szy;
+
+    N[3][3] = -Sxx - Syy + Szz;
+
+    //this construction prevents JavaScript from requiring preloading of Eigen
+    
+    float[] v = ((EigenInterface) Interface.getInterface("javajs.util.Eigen"))
+        .setM(N).getEigenvectorsFloatTransposed()[3];
+    q = Quat.newP4(P4.new4(v[1], v[2], v[3], v[0]));
+    retStddev[1] = getRmsd(centerAndPoints, q);
+    return q;
+  }
+
+  /**
+   * Fills a 4x4 matrix with rotation-translation of mapped points A to B.
+   * If centerA is null, this is a standard 4x4 rotation-translation matrix;
+   * otherwise, this 4x4 matrix is a rotation around a vector through the center of ptsA,
+   * and centerA is filled with that center; 
+   * Prior to Jmol 14.3.12_2014.02.14, when used from the JmolScript compare() function,
+   * this method returned the second of these options instead of the first.
+   * 
+   * @param ptsA
+   * @param ptsB
+   * @param m  4x4 matrix to be returned 
+   * @param centerA return center of rotation; if null, then standard 4x4 matrix is returned
+   * @return stdDev
+   */
+  public static float getTransformMatrix4(Lst<P3> ptsA, Lst<P3> ptsB, M4 m,
+                                          P3 centerA) {
+    P3[] cptsA = getCenterAndPoints(ptsA);
+    P3[] cptsB = getCenterAndPoints(ptsB);
+    float[] retStddev = new float[2];
+    Quat q = calculateQuaternionRotation(new P3[][] { cptsA, cptsB },
+        retStddev);
+    M3 r = q.getMatrix();
+    if (centerA == null)
+      r.rotate(cptsA[0]);
+    else
+      centerA.setT(cptsA[0]);
+    V3 t = V3.newVsub(cptsB[0], cptsA[0]);
+    m.setMV(r, t);
+    return retStddev[1];
+  }
+
+  /**
+   * from a list of points, create an array that includes the center
+   * point as the first point. This array is used as a starting point for
+   * a quaternion analysis of superposition.
+   * 
+   * @param vPts
+   * @return  array of points with first point center
+   */
+       public static P3[] getCenterAndPoints(Lst<P3> vPts) {
+         int n = vPts.size();
+         P3[] pts = new P3[n + 1];
+         pts[0] = new P3();
+         if (n > 0) {
+           for (int i = 0; i < n; i++) {
+             pts[0].add(pts[i + 1] = vPts.get(i));
+           }
+           pts[0].scale(1f / n);
+         }
+         return pts;
+       }
+
+  public static float getRmsd(P3[][] centerAndPoints, Quat q) {
+    double sum2 = 0;
+    P3[] ptsA = centerAndPoints[0];
+    P3[] ptsB = centerAndPoints[1];
+    P3 cA = ptsA[0];
+    P3 cB = ptsB[0];
+    int n = ptsA.length - 1;
+    P3 ptAnew = new P3();
+    
+    for (int i = n + 1; --i >= 1;) {
+      ptAnew.sub2(ptsA[i], cA);
+      q.transform2(ptAnew, ptAnew).add(cB);
+      sum2 += ptAnew.distanceSquared(ptsB[i]);
+    }
+    return (float) Math.sqrt(sum2 / n);
+  }
+
+}
diff --git a/src/javajs/util/OC.java b/src/javajs/util/OC.java
new file mode 100644 (file)
index 0000000..97f7ddb
--- /dev/null
@@ -0,0 +1,386 @@
+package javajs.util;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+
+
+
+import javajs.J2SIgnoreImport;
+import javajs.api.BytePoster;
+import javajs.api.JmolObjectInterface;
+
+/**
+ * 
+ * A generic output method. JmolOutputChannel can be used to:
+ * 
+ * add characters to a StringBuffer 
+ *   using fileName==null, append() and toString()
+ *   
+ * add bytes utilizing ByteArrayOutputStream 
+ *   using writeBytes(), writeByteAsInt(), append()*, and bytesAsArray()
+ *       *append() can be used as long as os==ByteArrayOutputStream
+ *        or it is not used before one of the writeByte methods. 
+ * 
+ * output characters to a FileOutputStream 
+ *  using os==FileOutputStream, asWriter==true, append(), and closeChannel()
+ *  
+ * output bytes to a FileOutputStream 
+ *  using os==FileOutputStream, writeBytes(), writeByteAsInt(), append(), and closeChannel()
+ * 
+ * post characters or bytes to a remote server
+ *  using fileName=="http://..." or "https://...",
+ *    writeBytes(), writeByteAsInt(), append(), and closeChannel()
+ *    
+ * send characters or bytes to a JavaScript function
+ *  when JavaScript and (typeof fileName == "function")
+ *  
+ * if fileName equals ";base64,", then the data are base64-encoded
+ * prior to writing, and closeChannel() returns the data.
+ * 
+ *  @author hansonr  Bob Hanson hansonr@stolaf.edu  9/2013
+ *  
+ *  
+ */
+
+@J2SIgnoreImport({ java.io.FileOutputStream.class })
+public class OC extends OutputStream {
+  private BytePoster bytePoster; // only necessary for writing to http:// or https://
+  private String fileName;
+  private BufferedWriter bw;
+  private boolean isLocalFile;
+  private int byteCount;
+  private boolean isCanceled;
+  private boolean closed;
+  private OutputStream os;
+  private SB sb;
+  private String type;
+       private boolean isBase64;
+       private OutputStream os0;
+       private byte[] bytes; // preset bytes; output only
+  
+  public OC setParams(BytePoster bytePoster, String fileName,
+                                     boolean asWriter, OutputStream os) {
+    this.bytePoster = bytePoster;
+    this.fileName = fileName;
+    isBase64 = ";base64,".equals(fileName);
+    if (isBase64) {
+       fileName = null;
+       os0 = os;
+       os = null;
+    }
+    this.os = os;
+    isLocalFile = (fileName != null && !isRemote(fileName));
+    if (asWriter && !isBase64 && os != null)
+      bw = new BufferedWriter(new OutputStreamWriter(os));
+    return this;
+  }
+
+  public OC setBytes(byte[] b) {
+       bytes = b;
+       return this;
+  }
+  
+  public String getFileName() {
+    return fileName;
+  }
+  
+  public String getName() {
+    return (fileName == null ? null : fileName.substring(fileName.lastIndexOf("/") + 1));
+  }
+
+  public int getByteCount() {
+    return byteCount;
+  }
+
+  /**
+   * 
+   * @param type  user-identified type (PNG, JPG, etc)
+   */
+  public void setType(String type) {
+    this.type = type;
+  }
+  
+  public String getType() {
+    return type;
+  }
+
+  /**
+   * will go to string buffer if bw == null and os == null
+   * 
+   * @param s
+   * @return this, for chaining like a standard StringBuffer
+   * 
+   */
+  public OC append(String s) {
+    try {
+      if (bw != null) {
+        bw.write(s);
+      } else if (os == null) {
+        if (sb == null)
+          sb = new SB();
+        sb.append(s);
+      } else {
+        byte[] b = s.getBytes();
+        os.write(b, 0, b.length);
+        byteCount += b.length;
+        return this;
+      }
+    } catch (IOException e) {
+      // ignore
+    }
+    byteCount += s.length(); // not necessarily exactly correct if unicode
+    return this;
+  }
+
+  public void reset() {
+    sb = null;
+    initOS();
+  }
+
+
+  private void initOS() {
+    if (sb != null) {
+      String s = sb.toString();
+      reset();
+      append(s);
+      return;
+    }
+    try {
+      /**
+       * @j2sNative
+       * 
+       *            this.os = null;
+       */
+      {
+        if (os instanceof FileOutputStream) {
+          os.close();
+          os = new FileOutputStream(fileName);
+        } else {
+          os = null;
+        }
+      }
+      if (os == null)
+        os = new ByteArrayOutputStream();
+      if (bw != null) {
+        bw.close();
+        bw = new BufferedWriter(new OutputStreamWriter(os));
+      }
+    } catch (Exception e) {
+      // not perfect here.
+      System.out.println(e.toString());
+    }
+    byteCount = 0;
+  }
+
+  /**
+   * @j2sOverride
+   */
+  @Override
+  public void write(byte[] buf, int i, int len) {
+    if (os == null)
+      initOS();
+    try {
+      os.write(buf, i, len);
+    } catch (IOException e) {
+    }
+    byteCount += len;
+  }
+  
+  /**
+   * @param b  
+   */
+  public void writeByteAsInt(int b) {
+    if (os == null)
+      initOS();
+    /**
+     * @j2sNative
+     * 
+     *  this.os.writeByteAsInt(b);
+     * 
+     */
+    {
+      try {
+        os.write(b);
+      } catch (IOException e) {
+      }
+    }
+    byteCount++;
+  }
+  
+  /**
+   * Will break JavaScript if used.
+   * 
+   * @j2sIgnore
+   * 
+   * @param b
+   */
+  @Override
+  @Deprecated
+  public void write(int b) {
+    // required by standard ZipOutputStream -- do not use, as it will break JavaScript methods
+    if (os == null)
+      initOS();
+    try {
+      os.write(b);
+    } catch (IOException e) {
+    }
+    byteCount++;
+  }
+
+//  /**
+//   * Will break if used; no equivalent in JavaScript.
+//   * 
+//   * @j2sIgnore
+//   * 
+//   * @param b
+//   */
+//  @Override
+//  @Deprecated
+//  public void write(byte[] b) {
+//    // not used in JavaScript due to overloading problem there
+//    write(b, 0, b.length);
+//  }
+
+  public void cancel() {
+    isCanceled = true;
+    closeChannel();
+  }
+
+  @SuppressWarnings({ "null", "unused" })
+  public String closeChannel() {
+    if (closed)
+      return null;
+    // can't cancel file writers
+    try {
+      if (bw != null) {
+        bw.flush();
+        bw.close();
+      } else if (os != null) {
+        os.flush();
+        os.close();
+      }
+      if (os0 != null && isCanceled) {
+        os0.flush();
+        os0.close();
+      }
+    } catch (Exception e) {
+      // ignore closing issues
+    }
+    if (isCanceled) {
+      closed = true;
+      return null;
+    }
+    if (fileName == null) {
+      if (isBase64) {
+        String s = getBase64();
+        if (os0 != null) {
+          os = os0;
+          append(s);
+        }
+        sb = new SB();
+        sb.append(s);
+        isBase64 = false;
+        return closeChannel();
+      }
+      return (sb == null ? null : sb.toString());
+    }
+    closed = true;
+    JmolObjectInterface jmol = null;
+    Object _function = null;
+    /**
+     * @j2sNative
+     * 
+     *            jmol = Jmol; _function = (typeof this.fileName == "function" ?
+     *            this.fileName : null);
+     * 
+     */
+    {
+      if (!isLocalFile) {
+        String ret = postByteArray(); // unsigned applet could do this
+        if (ret.startsWith("java.net"))
+          byteCount = -1;
+        return ret;
+      }
+    }
+    if (jmol != null) {
+      Object data = (sb == null ? toByteArray() : sb.toString());
+      if (_function == null)
+        jmol._doAjax(fileName, null, data);
+      else
+        jmol._apply(fileName, data);
+    }
+    return null;
+  }
+
+       public boolean isBase64() {
+               return isBase64;
+       }
+
+       public String getBase64() {
+    return Base64.getBase64(toByteArray()).toString();
+       }
+       
+  public byte[] toByteArray() {
+    return (bytes != null ? bytes : os instanceof ByteArrayOutputStream ? ((ByteArrayOutputStream)os).toByteArray() : null);
+  }
+
+  @Override
+  @Deprecated
+  public void close() {
+    closeChannel();
+  }
+
+  @Override
+  public String toString() {
+    if (bw != null)
+      try {
+        bw.flush();
+      } catch (IOException e) {
+        // TODO
+      }
+    if (sb != null)
+      return closeChannel();
+    return byteCount + " bytes";
+  }
+
+  private String postByteArray() {
+    byte[] bytes = (sb == null ? toByteArray() : sb.toString().getBytes());
+    return bytePoster.postByteArray(fileName, bytes);
+  }
+
+  public final static String[] urlPrefixes = { "http:", "https:", "sftp:", "ftp:",
+  "file:" };
+  // note that SFTP is not supported
+  public final static int URL_LOCAL = 4;
+
+  public static boolean isRemote(String fileName) {
+    if (fileName == null)
+      return false;
+    int itype = urlTypeIndex(fileName);
+    return (itype >= 0 && itype != URL_LOCAL);
+  }
+
+  public static boolean isLocal(String fileName) {
+    if (fileName == null)
+      return false;
+    int itype = urlTypeIndex(fileName);
+    return (itype < 0 || itype == URL_LOCAL);
+  }
+
+  public static int urlTypeIndex(String name) {
+    if (name == null)
+      return -2; // local unsigned applet
+    for (int i = 0; i < urlPrefixes.length; ++i) {
+      if (name.startsWith(urlPrefixes[i])) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+}
diff --git a/src/javajs/util/P3.java b/src/javajs/util/P3.java
new file mode 100644 (file)
index 0000000..3917159
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+
+
+/**
+ * A 3 element point that is represented by single precision floating point
+ * x,y,z coordinates.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.10 $, $Date:
+ *          2006/09/08 20:20:20 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ * 
+ */
+public class P3 extends T3 {
+
+  /**
+   * @j2sIgnore
+   */
+  public P3() {
+    // ignore T3
+  }
+  
+  public static P3 newP(T3 t) {
+    P3 p = new P3();
+    p.x = t.x;
+    p.y = t.y;
+    p.z = t.z;
+    return p;
+  }
+
+  private static P3 unlikely;
+  
+  public static P3 getUnlikely() {
+    return (unlikely == null ? unlikely = new3((float) Math.PI, (float) Math.E, (float) (Math.PI * Math.E)) : unlikely);
+  }
+  
+  public static P3 new3(float x, float y, float z) {
+    P3 p = new P3();
+    p.x = x;
+    p.y = y;
+    p.z = z;
+    return p;
+  }
+
+}
diff --git a/src/javajs/util/P3i.java b/src/javajs/util/P3i.java
new file mode 100644 (file)
index 0000000..8f39550
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+
+
+/**
+ * A 3 element point that is represented by signed integer x,y,z coordinates.
+ * 
+ * @since Java 3D 1.2
+ * @version specification 1.2, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:33 $
+ * @author Kenji hiranabe
+ * 
+ * 
+ *         additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique
+ *         constructor and method names for the optimization of compiled
+ *         JavaScript using Java2Script
+ */
+public class P3i extends T3i {
+
+  public static P3i new3(int x, int y, int z) {
+    P3i pt = new P3i();
+    pt.x = x;
+    pt.y = y;
+    pt.z = z;
+    return pt;
+  }
+}
diff --git a/src/javajs/util/P4.java b/src/javajs/util/P4.java
new file mode 100644 (file)
index 0000000..a434f53
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+
+
+/**
+ * A 4 element point that is represented by single precision floating point
+ * x,y,z,w coordinates.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public class P4 extends T4 {
+
+  /**
+   * 
+   * @j2sIgnore   * 
+   */
+  public P4() {
+    // skip T4() constructor
+  }
+  
+  public static P4 new4(float x, float y, float z, float w) {
+    P4 pt = new P4();
+    pt.set4(x, y, z, w);
+    return pt;
+  }
+
+  public static P4 newPt(P4 value) {
+    P4 pt = new P4();
+    pt.set4(value.x, value.y, value.z, value.w);    
+    return pt;
+  }
+
+  /**
+   * Returns the distance between this point and point p1.
+   * 
+   * @param p1
+   *        the other point
+   * @return the distance between these two points
+   */
+  public final float distance4(P4 p1) {
+    double dx = x - p1.x;
+    double dy = y - p1.y;
+    double dz = z - p1.z;
+    double dw = w - p1.w;
+    return (float) Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
+  }
+
+}
diff --git a/src/javajs/util/PT.java b/src/javajs/util/PT.java
new file mode 100644 (file)
index 0000000..e6a27b4
--- /dev/null
@@ -0,0 +1,1540 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-04-26 16:57:51 -0500 (Thu, 26 Apr 2007) $
+ * $Revision: 7502 $
+ *
+ * Copyright (C) 2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+package javajs.util;
+
+import java.lang.reflect.Array;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javajs.J2SIgnoreImport;
+import javajs.api.JSONEncodable;
+
+/**
+ * a combination of Parsing and Text-related utility classes
+ * 
+ * @author hansonr
+ * 
+ */
+
+@J2SIgnoreImport(value = { java.lang.reflect.Array.class })
+public class PT {
+
+  public static int parseInt(String str) {
+    return parseIntNext(str, new int[] {0});
+  }
+
+  public static int parseIntNext(String str, int[] next) {
+    int cch = str.length();
+    if (next[0] < 0 || next[0] >= cch)
+      return Integer.MIN_VALUE;
+    return parseIntChecked(str, cch, next);
+  }
+
+  public static int parseIntChecked(String str, int ichMax, int[] next) {
+    boolean digitSeen = false;
+    int value = 0;
+    int ich = next[0];
+    if (ich < 0)
+      return Integer.MIN_VALUE;
+    int ch;
+    while (ich < ichMax && isWhiteSpace(str, ich))
+      ++ich;
+    boolean negative = false;
+    if (ich < ichMax && str.charAt(ich) == 45) { //"-"
+      negative = true;
+      ++ich;
+    }
+    while (ich < ichMax && (ch = str.charAt(ich)) >= 48 && ch <= 57) {
+      value = value * 10 + (ch - 48);
+      digitSeen = true;
+      ++ich;
+    }
+    if (!digitSeen)// || !checkTrailingText(str, ich, ichMax))
+      value = Integer.MIN_VALUE;
+    else if (negative)
+      value = -value;
+    next[0] = ich;
+    return value;
+  }
+
+  public static boolean isWhiteSpace(String str, int ich) {
+    char ch;
+    return (ich >= 0 && ((ch = str.charAt(ich)) == ' ' || ch == '\t' || ch == '\n'));
+  }
+
+  /**
+   * A float parser that is 30% faster than Float.parseFloat(x) and also accepts
+   * x.yD+-n
+   * 
+   * @param str
+   * @param ichMax
+   * @param next
+   *        pointer; incremented
+   * @param isStrict
+   * @return value or Float.NaN
+   */
+  public static float parseFloatChecked(String str, int ichMax, int[] next,
+                                         boolean isStrict) {
+    boolean digitSeen = false;
+    int ich = next[0];
+    if (isStrict && str.indexOf('\n') != str.lastIndexOf('\n'))
+      return Float.NaN;
+    while (ich < ichMax && isWhiteSpace(str, ich))
+      ++ich;
+    boolean negative = false;
+    if (ich < ichMax && str.charAt(ich) == '-') {
+      ++ich;
+      negative = true;
+    }
+    // looks crazy, but if we don't do this, Google Closure Compiler will 
+    // write code that Safari will misinterpret in a VERY nasty way -- 
+    // getting totally confused as to long integers and double values
+    
+    // This is Safari figuring out the values of the numbers on the line (x, y, then z):
+  
+    //  ATOM 1241 CD1 LEU A 64 -2.206 36.532 31.576 1.00 60.60 C
+    //  e=1408749273
+    //  -e =-1408749273
+    //  ATOM 1241 CD1 LEU A 64 -2.206 36.532 31.576 1.00 60.60 C
+    //  e=-1821066134
+    //  e=36.532
+    //  ATOM 1241 CD1 LEU A 64 -2.206 36.532 31.576 1.00 60.60 C
+    //  e=-1133871366
+    //  e=31.576
+    //
+    //  "e" values are just before and after the "value = -value" statement.
+    
+    int ch = 0;
+    float ival = 0f;
+    float ival2 = 0f;
+    while (ich < ichMax && (ch = str.charAt(ich)) >= 48 && ch <= 57) {
+      ival = (ival * 10f) + (ch - 48)*1f;
+      ++ich;
+      digitSeen = true;
+    }
+    boolean isDecimal = false;
+    int iscale = 0;
+    int nzero = (ival == 0 ? -1 : 0);
+    if (ch == '.') {
+      isDecimal = true;
+      while (++ich < ichMax && (ch = str.charAt(ich)) >= 48 && ch <= 57) {
+        digitSeen = true;
+        if (nzero < 0) {
+          if (ch == 48) { 
+            nzero--;
+            continue;
+          }
+          nzero = -nzero;
+        } 
+        if (iscale  < decimalScale.length) {
+          ival2 = (ival2 * 10f) + (ch - 48)*1f;
+          iscale++;
+        }
+      }
+    }
+    float value;
+    
+    // Safari breaks here intermittently converting integers to floats 
+    
+    if (!digitSeen) {
+      value = Float.NaN;
+    } else if (ival2 > 0) {
+      value = ival2 * decimalScale[iscale - 1];
+      if (nzero > 1) {
+        if (nzero - 2 < decimalScale.length) {
+          value *= decimalScale[nzero - 2];
+        } else {
+          value *= Math.pow(10, 1 - nzero);
+        }
+      } else {
+        value += ival;
+      }
+    } else {
+      value = ival;
+    }
+    boolean isExponent = false;
+    if (ich < ichMax && (ch == 69 || ch == 101 || ch == 68)) { // E e D
+      isExponent = true;
+      if (++ich >= ichMax)
+        return Float.NaN;
+      ch = str.charAt(ich);
+      if ((ch == '+') && (++ich >= ichMax))
+        return Float.NaN;
+      next[0] = ich;
+      int exponent = parseIntChecked(str, ichMax, next);
+      if (exponent == Integer.MIN_VALUE)
+        return Float.NaN;
+      if (exponent > 0 && exponent <= tensScale.length)
+        value *= tensScale[exponent - 1];
+      else if (exponent < 0 && -exponent <= decimalScale.length)
+        value *= decimalScale[-exponent - 1];
+      else if (exponent != 0)
+        value *= Math.pow(10, exponent);
+    } else {
+      next[0] = ich; // the exponent code finds its own ichNextParse
+    }
+    // believe it or not, Safari reports the long-equivalent of the 
+    // float value here, then later the float value, after no operation!
+    if (negative)
+      value = -value;
+    if (value == Float.POSITIVE_INFINITY)
+      value = Float.MAX_VALUE;
+    return (!isStrict || (!isExponent || isDecimal)
+        && checkTrailingText(str, next[0], ichMax) ? value : Float.NaN);
+  }
+
+  public final static float[] tensScale = { 10f, 100f, 1000f, 10000f, 100000f, 1000000f };
+  public final static float[] decimalScale = { 
+  0.1f, 
+  0.01f, 
+  0.001f, 
+  0.0001f, 
+  0.00001f,
+  0.000001f, 
+  0.0000001f, 
+  0.00000001f, 
+  0.000000001f
+  };
+  public static boolean checkTrailingText(String str, int ich, int ichMax) {
+    //number must be pure -- no additional characters other than white space or ;
+    char ch;
+    while (ich < ichMax && (isWhitespace(ch = str.charAt(ich)) || ch == ';'))
+      ++ich;
+    return (ich == ichMax);
+  }
+
+  public static float[] parseFloatArray(String str) {
+    return parseFloatArrayNext(str, new int[1], null, null, null);
+  }
+
+  public static int parseFloatArrayInfested(String[] tokens, float[] data) {
+    int len = data.length;
+    int nTokens = tokens.length;
+    int n = 0;
+    int max = 0;
+    for (int i = 0; i >= 0 && i < len && n < nTokens; i++) {
+      float f;
+      while (Float.isNaN(f = parseFloat(tokens[n++])) 
+          && n < nTokens) {
+      }
+      if (!Float.isNaN(f))
+        data[(max = i)] = f;
+      if (n == nTokens)
+        break;
+    }
+    return max + 1;
+  }
+
+  /**
+   * @param str
+   * @param next
+   * @param f
+   * @param strStart or null
+   * @param strEnd   or null
+   * @return array of float values
+   * 
+   */
+  public static float[] parseFloatArrayNext(String str, int[] next, float[] f,
+                                            String strStart, String strEnd) {
+    int n = 0;
+    int pt = next[0];
+    if (pt >= 0) {
+      if (strStart != null) {
+        int p = str.indexOf(strStart, pt);
+        if (p >= 0)
+          next[0] = p + strStart.length();
+      }
+      str = str.substring(next[0]);
+      pt = (strEnd == null ? -1 : str.indexOf(strEnd));
+      if (pt < 0)
+        pt = str.length();
+      else
+        str = str.substring(0, pt);
+      next[0] += pt + 1;
+      String[] tokens = getTokens(str);
+      if (f == null)
+        f = new float[tokens.length];
+      n = parseFloatArrayInfested(tokens, f);
+    }
+    if (f == null)
+      return new float[0];
+    for (int i = n; i < f.length; i++)
+      f[i] = Float.NaN;
+    return f;
+  }
+
+  public static float parseFloatRange(String str, int ichMax, int[] next) {
+    int cch = str.length();
+    if (ichMax > cch)
+      ichMax = cch;
+    if (next[0] < 0 || next[0] >= ichMax)
+      return Float.NaN;
+    return parseFloatChecked(str, ichMax, next, false);
+  }
+
+  public static float parseFloatNext(String str, int[] next) {
+    int cch = (str == null ? -1 : str.length());
+    return (next[0] < 0 || next[0] >= cch ? Float.NaN : parseFloatChecked(str, cch, next, false));
+  }
+
+  public static float parseFloatStrict(String str) {
+    // checks trailing characters and does not allow "1E35" to be float
+    int cch = str.length();
+    if (cch == 0)
+      return Float.NaN;
+    return parseFloatChecked(str, cch, new int[] {0}, true);
+  }
+
+  public static float parseFloat(String str) {
+    return parseFloatNext(str, new int[] {0});
+  }
+
+  public static int parseIntRadix(String s, int i) throws NumberFormatException {
+    /**
+     * 
+     * JavaScript uses parseIntRadix
+     * 
+     * @j2sNative
+     * 
+     *    return Integer.parseIntRadix(s, i);
+     *    
+     */
+    {
+      return Integer.parseInt(s, i);
+    }
+  }
+
+  public static String[] getTokens(String line) {
+    return getTokensAt(line, 0);
+  }
+
+  public static String parseToken(String str) {
+    return parseTokenNext(str, new int[] {0});
+  }
+
+  public static String parseTrimmed(String str) {
+    return parseTrimmedRange(str, 0, str.length());
+  }
+
+  public static String parseTrimmedAt(String str, int ichStart) {
+    return parseTrimmedRange(str, ichStart, str.length());
+  }
+
+  public static String parseTrimmedRange(String str, int ichStart, int ichMax) {
+    int cch = str.length();
+    if (ichMax < cch)
+      cch = ichMax;
+    if (cch < ichStart)
+      return "";
+    return parseTrimmedChecked(str, ichStart, cch);
+  }
+
+  public static String[] getTokensAt(String line, int ich) {
+    if (line == null)
+      return null;
+    int cchLine = line.length();
+    if (ich < 0 || ich > cchLine)
+      return null;
+    int tokenCount = countTokens(line, ich);
+    String[] tokens = new String[tokenCount];
+    int[] next = new int[1];
+    next[0] = ich;
+    for (int i = 0; i < tokenCount; ++i)
+      tokens[i] = parseTokenChecked(line, cchLine, next);
+    return tokens;
+  }
+
+  public static int countChar(String line, char c) {
+    int tokenCount = 0;
+    int pt = -1;
+    while ((pt = line.indexOf(c, pt + 1)) >= 0)
+      tokenCount++;
+    return  tokenCount;
+  }
+  
+  public static int countTokens(String line, int ich) {
+    int tokenCount = 0;
+    if (line != null) {
+      int ichMax = line.length();
+      while (true) {
+        while (ich < ichMax && isWhiteSpace(line, ich))
+          ++ich;
+        if (ich == ichMax)
+          break;
+        ++tokenCount;
+        do {
+          ++ich;
+        } while (ich < ichMax && !isWhiteSpace(line, ich));
+      }
+    }
+    return tokenCount;
+  }
+
+  public static String parseTokenNext(String str, int[] next) {
+    int cch = str.length();
+    return (next[0] < 0 || next[0] >= cch ? null : parseTokenChecked(str, cch, next));
+  }
+
+  public static String parseTokenRange(String str, int ichMax, int[] next) {
+    int cch = str.length();
+    if (ichMax > cch)
+      ichMax = cch;
+    return (next[0] < 0 || next[0] >= ichMax ? null : parseTokenChecked(str, ichMax, next));
+  }
+
+  public static String parseTokenChecked(String str, int ichMax, int[] next) {
+    int ich = next[0];
+    while (ich < ichMax && isWhiteSpace(str, ich))
+      ++ich;
+    int ichNonWhite = ich;
+    while (ich < ichMax && !isWhiteSpace(str, ich))
+      ++ich;
+    next[0] = ich;
+    return (ichNonWhite == ich ? null : str.substring(ichNonWhite, ich));
+  }
+
+  public static String parseTrimmedChecked(String str, int ich, int ichMax) {
+    while (ich < ichMax && isWhiteSpace(str, ich))
+      ++ich;
+    int ichLast = ichMax - 1;
+    while (ichLast >= ich && isWhiteSpace(str, ichLast))
+      --ichLast;
+    return (ichLast < ich ? "" : str.substring(ich, ichLast + 1));
+  }
+
+  public static double dVal(String s) throws NumberFormatException {
+    /**
+     * @j2sNative
+     * 
+     * if(s==null)
+     *   throw new NumberFormatException("null");
+     * var d=parseFloat(s);
+     * if(isNaN(d))
+     *  throw new NumberFormatException("Not a Number : "+s);
+     * return d 
+     * 
+     */
+    {
+      return Double.valueOf(s).doubleValue();
+    }
+  }
+
+  public static float fVal(String s) throws NumberFormatException {
+    /**
+     * @j2sNative
+     * 
+     * return this.dVal(s);
+     */
+    {
+      return Float.parseFloat(s);
+    }
+  }
+
+  public static int parseIntRange(String str, int ichMax, int[] next) {
+    int cch = str.length();
+    if (ichMax > cch)
+      ichMax = cch;
+    return (next[0] < 0 || next[0] >= ichMax ? Integer.MIN_VALUE : parseIntChecked(str, ichMax, next));
+  }
+
+  /**
+   * parses a string array for floats. Returns NaN for nonfloats.
+   * 
+   *  @param tokens  the strings to parse
+   *  @param data    the array to fill
+   */
+  public static void parseFloatArrayData(String[] tokens, float[] data) {
+    parseFloatArrayDataN(tokens, data, data.length);
+  }
+
+  /**
+   * parses a string array for floats. Returns NaN for nonfloats or missing data.
+   * 
+   *  @param tokens  the strings to parse
+   *  @param data    the array to fill
+   *  @param nData   the number of elements
+   */
+  public static void parseFloatArrayDataN(String[] tokens, float[] data, int nData) {
+    for (int i = nData; --i >= 0;)
+      data[i] = (i >= tokens.length ? Float.NaN : parseFloat(tokens[i]));
+  }
+
+  /**
+   * 
+   *  proper splitting, even for Java 1.3 -- if the text ends in the run,
+   *  no new line is appended.
+   * 
+   * @param text
+   * @param run
+   * @return  String array
+   */
+  public static String[] split(String text, String run) {
+    if (text.length() == 0)
+      return new String[0];
+    int n = 1;
+    int i = text.indexOf(run);
+    String[] lines;
+    int runLen = run.length();
+    if (i < 0 || runLen == 0) {
+      lines = new String[1];
+      lines[0] = text;
+      return lines;
+    }
+    int len = text.length() - runLen;
+    for (; i >= 0 && i < len; n++)
+      i = text.indexOf(run, i + runLen);
+    lines = new String[n];
+    i = 0;
+    int ipt = 0;
+    int pt = 0;
+    for (; (ipt = text.indexOf(run, i)) >= 0 && pt + 1 < n;) {
+      lines[pt++] = text.substring(i, ipt);
+      i = ipt + runLen;
+    }
+    if (text.indexOf(run, len) != len)
+      len += runLen;
+    lines[pt] = text.substring(i, len);
+    return lines;
+  }
+
+  public final static float FLOAT_MIN_SAFE = 2E-45f; 
+  // Float.MIN_VALUE (1.45E-45) is not reliable with JavaScript because of the float/double difference there
+  
+  /// general static string-parsing class ///
+
+  // next[0] tracks the pointer within the string so these can all be static.
+  // but the methods parseFloat, parseInt, parseToken, parseTrimmed, and getTokens do not require this.
+
+//  public static String concatTokens(String[] tokens, int iFirst, int iEnd) {
+//    String str = "";
+//    String sep = "";
+//    for (int i = iFirst; i < iEnd; i++) {
+//      if (i < tokens.length) {
+//        str += sep + tokens[i];
+//        sep = " ";
+//      }
+//    }
+//    return str;
+//  }
+  
+  public static String getQuotedStringAt(String line, int ipt0) {
+    int[] next = new int[] { ipt0 };
+    return getQuotedStringNext(line, next);
+  }
+  
+  /**
+   * 
+   * @param line
+   * @param next passes [current pointer]
+   * @return quoted string -- does NOT unescape characters
+   */
+  public static String getQuotedStringNext(String line, int[] next) {
+    int i = next[0];
+    if (i < 0 || (i = line.indexOf("\"", i)) < 0)
+      return "";
+    int pt = i + 1;
+    int len = line.length();
+    while (++i < len && line.charAt(i) != '"')
+      if (line.charAt(i) == '\\')
+        i++;
+    next[0] = i + 1;
+    return line.substring(pt, i);
+  }
+  
+  /**
+   * CSV format -- escaped quote is "" WITHIN "..."
+   *
+   * 
+   * @param line
+   * @param next int[2] filled with [ptrQuote1, ptrAfterQuote2]
+   *            next[1] will be -1 if unmatched quotes are found (continuation on next line)
+   * @return unescaped string or null
+   */
+  public static String getCSVString(String line, int[] next) {
+    int i = next[1];
+    if (i < 0 || (i = line.indexOf("\"", i)) < 0)
+      return null;
+    int pt = next[0] = i;
+    int len = line.length();
+    boolean escaped = false;
+    boolean haveEscape = false;
+    while (++i < len 
+        && (line.charAt(i) != '"' || (escaped = (i + 1 < len && line.charAt(i + 1) == '"'))))
+      if (escaped) {
+        escaped = false;
+        haveEscape = true;
+        i++;
+      }
+    if (i >= len) {
+      next[1] = -1;
+      return null; // unmatched
+    }
+    next[1] = i + 1;
+    String s = line.substring(pt + 1, i);
+    return (haveEscape ? rep(rep(s, "\"\"", "\0"), "\0","\"") : s);
+  }
+  
+  public static boolean isOneOf(String key, String semiList) {
+    if (semiList.length() == 0)
+      return false;
+    if (semiList.charAt(0) != ';')
+      semiList = ";" + semiList + ";";
+    return key.indexOf(";") < 0  && semiList.indexOf(';' + key + ';') >= 0;
+  }
+
+  public static String getQuotedAttribute(String info, String name) {
+    int i = info.indexOf(name + "=");
+    return (i < 0 ? null : getQuotedStringAt(info, i));
+  }
+
+  public static float approx(float f, float n) {
+    return Math.round (f * n) / n;
+  }
+
+  /**
+   * Does a clean ITERATIVE replace of strFrom in str with strTo. 
+   * Thus, rep("Testttt", "tt","t") becomes "Test".
+   * 
+   * @param str
+   * @param strFrom
+   * @param strTo
+   * @return replaced string
+   */
+  public static String rep(String str, String strFrom, String strTo) {
+    if (str == null || strFrom.length() == 0 || str.indexOf(strFrom) < 0)
+      return str;
+    boolean isOnce = (strTo.indexOf(strFrom) >= 0);
+    do {
+      str = str.replace(strFrom, strTo);
+    } while (!isOnce && str.indexOf(strFrom) >= 0);
+    return str;
+  }
+
+  public static String formatF(float value, int width, int precision,
+                              boolean alignLeft, boolean zeroPad) {
+    return formatS(DF.formatDecimal(value, precision), width, 0, alignLeft, zeroPad);
+  }
+
+  /**
+   * 
+   * @param value
+   * @param width
+   * @param precision
+   * @param alignLeft
+   * @param zeroPad
+   * @param allowOverflow IGNORED
+   * @return formatted string
+   */
+  public static String formatD(double value, int width, int precision,
+                              boolean alignLeft, boolean zeroPad, boolean allowOverflow) {
+    return formatS(DF.formatDecimal((float)value, -1 - precision), width, 0, alignLeft, zeroPad);
+  }
+
+  /**
+   * 
+   * @param value       
+   * @param width       number of columns
+   * @param precision   precision > 0 ==> precision = number of characters max from left
+   *                    precision < 0 ==> -1 - precision = number of char. max from right
+   * @param alignLeft
+   * @param zeroPad     generally for numbers turned strings
+   * @return            formatted string
+   */
+  public static String formatS(String value, int width, int precision,
+                              boolean alignLeft, boolean zeroPad) {
+    if (value == null)
+      return "";
+    int len = value.length();
+    if (precision != Integer.MAX_VALUE && precision > 0
+        && precision < len)
+      value = value.substring(0, precision);
+    else if (precision < 0 && len + precision >= 0)
+      value = value.substring(len + precision + 1);
+  
+    int padLength = width - value.length();
+    if (padLength <= 0)
+      return value;
+    boolean isNeg = (zeroPad && !alignLeft && value.charAt(0) == '-');
+    char padChar = (zeroPad ? '0' : ' ');
+    char padChar0 = (isNeg ? '-' : padChar);
+  
+    SB sb = new SB();
+    if (alignLeft)
+      sb.append(value);
+    sb.appendC(padChar0);
+    for (int i = padLength; --i > 0;)
+      // this is correct, not >= 0
+      sb.appendC(padChar);
+    if (!alignLeft)
+      sb.append(isNeg ? padChar + value.substring(1) : value);
+    return sb.toString();
+  }
+
+  /**
+   * Does a clean replace of any of the characters in str with chrTo
+   * If strTo contains strFrom, then only a single pass is done.
+   * Otherwise, multiple passes are made until no more replacements can be made.
+   * 
+   * @param str
+   * @param strFrom
+   * @param chTo
+   * @return  replaced string
+   */
+  public static String replaceWithCharacter(String str, String strFrom,
+                                            char chTo) {
+    if (str == null)
+      return null;
+    for (int i = strFrom.length(); --i >= 0;)
+      str = str.replace(strFrom.charAt(i), chTo);
+    return str;
+  }
+
+  /**
+   * Does a clean replace of any of the characters in str with strTo
+   * If strTo contains strFrom, then only a single pass is done.
+   * Otherwise, multiple passes are made until no more replacements can be made.
+   * 
+   * @param str
+   * @param strFrom
+   * @param strTo
+   * @return  replaced string
+   */
+  public static String replaceAllCharacters(String str, String strFrom,
+                                            String strTo) {
+    for (int i = strFrom.length(); --i >= 0;) {
+      String chFrom = strFrom.substring(i, i + 1);
+      str = rep(str, chFrom, strTo);
+    }
+    return str;
+  }
+
+  public static String trim(String str, String chars) {
+    if (str == null || str.length() == 0)
+      return str;
+    if (chars.length() == 0)
+      return str.trim();
+    int len = str.length();
+    int k = 0;
+    while (k < len && chars.indexOf(str.charAt(k)) >= 0)
+      k++;
+    int m = str.length() - 1;
+    while (m > k && chars.indexOf(str.charAt(m)) >= 0)
+      m--;
+    return str.substring(k, m + 1);
+  }
+
+  public static String trimQuotes(String value) {
+    return (value != null && value.length() > 1 && value.startsWith("\"")
+        && value.endsWith("\"") ? value.substring(1, value.length() - 1)
+        : value);
+  }
+
+  public static boolean isNonStringPrimitive(Object info) {
+    // note that we don't use Double, Float, or Integer here
+    // because in JavaScript those would be false for unwrapped primitives
+    // coming from equivalent of Array.get()
+    // Strings will need their own escaped processing
+    
+    return info instanceof Number || info instanceof Boolean;
+  }
+
+  private static Object arrayGet(Object info, int i) {
+    /**
+     * 
+     * Note that info will be a primitive in JavaScript
+     * but a wrapped primitive in Java.
+     * 
+     * @j2sNative
+     * 
+     *            return info[i];
+     */
+    {
+      return Array.get(info, i);
+    }
+  }
+  
+  @SuppressWarnings("unchecked")
+  public static String toJSON(String infoType, Object info) {
+    if (info == null)
+      return packageJSON(infoType, null);
+    if (isNonStringPrimitive(info))
+      return packageJSON(infoType, info.toString());
+    String s = null;
+    SB sb = null;
+    while (true) {
+      if (info instanceof String) {
+        s = (String) info;
+        /**
+         * @j2sNative
+         * 
+         * if (typeof s == "undefined") s = "null"
+         * 
+         */
+        {}
+        if (s.indexOf("{\"") != 0) {
+          //don't doubly fix JSON strings when retrieving status
+          s = rep(s, "\"", "\\\"");
+          s = rep(s, "\n", "\\n");
+          s = "\"" + s + "\"";
+        }
+        break;
+      }
+      if (info instanceof JSONEncodable) {
+        // includes javajs.util.BS, org.jmol.script.SV
+        if ((s = ((JSONEncodable) info).toJSON()) == null)
+          s = "null"; // perhaps a list has a null value (group3List, for example)
+        break;
+      }
+      sb = new SB();
+      if (info instanceof Map) {
+        sb.append("{ ");
+        String sep = "";
+        for (String key : ((Map<String, ?>) info).keySet()) {
+          sb.append(sep).append(
+              packageJSON(key, toJSON(null, ((Map<?, ?>) info).get(key))));
+          sep = ",";
+        }
+        sb.append(" }");
+        break;
+      }
+      if (info instanceof Lst) {
+        sb.append("[ ");
+        int n = ((Lst<?>) info).size();
+        for (int i = 0; i < n; i++) {
+          if (i > 0)
+            sb.appendC(',');
+          sb.append(toJSON(null, ((Lst<?>) info).get(i)));
+        }
+        sb.append(" ]");
+        break;
+      }
+      if (info instanceof M34) {
+        // M4 extends M3
+        int len = (info instanceof M4 ? 4 : 3);
+        float[] x = new float[len];
+        M34 m = (M34) info;
+        sb.appendC('[');
+        for (int i = 0; i < len; i++) {
+          if (i > 0)
+            sb.appendC(',');
+          m.getRow(i, x);
+          sb.append(toJSON(null, x));
+        }
+        sb.appendC(']');
+        break;
+      }
+      s = nonArrayString(info);
+      if (s == null) {
+        sb.append("[");
+        int n = AU.getLength(info);
+        for (int i = 0; i < n; i++) {
+          if (i > 0)
+            sb.appendC(',');
+          sb.append(toJSON(null, arrayGet(info, i)));
+        }
+        sb.append("]");
+        break;
+      }
+      info = info.toString();
+    }
+    return packageJSON(infoType, (s == null ? sb.toString() : s));
+  }
+
+  /**
+   * Checks to see if an object is an array, and if it is, returns null;
+   * otherwise it returns the string equivalent of that object.
+   * 
+   * @param x
+   * @return String or null
+   */
+  public static String nonArrayString(Object x) {
+    /**
+     * @j2sNative
+     * 
+     *            var s = x.toString(); return (s.startsWith("[object") &&
+     *            s.endsWith("Array]") ? null : s);
+     * 
+     */
+    {
+      try {
+        Array.getLength(x);
+        return null;
+      } catch (Exception e) {
+        return x.toString();
+      }
+    }
+  }
+
+  public static String byteArrayToJSON(byte[] data) {
+    SB sb = new SB();
+    sb.append("[");
+    int n = data.length;
+    for (int i = 0; i < n; i++) {
+      if (i > 0)
+        sb.appendC(',');
+      sb.appendI(data[i] & 0xFF);
+    }
+    sb.append("]");
+    return sb.toString();
+  }
+  
+  public static String packageJSON(String infoType, String info) {
+    return (infoType == null ? info : "\"" + infoType + "\": " + info);
+  }
+
+  public static String escapeUrl(String url) {
+    url = rep(url, "\n", "");
+    url = rep(url, "%", "%25");
+    url = rep(url, "#", "%23");
+    url = rep(url, "[", "%5B");
+    url = rep(url, "]", "%5D");
+    url = rep(url, " ", "%20");
+    return url;
+  }
+
+  private final static String escapable = "\\\\\tt\rr\nn\"\""; 
+
+  public static String esc(String str) {
+    if (str == null || str.length() == 0)
+      return "\"\"";
+    boolean haveEscape = false;
+    int i = 0;
+    for (; i < escapable.length(); i += 2)
+      if (str.indexOf(escapable.charAt(i)) >= 0) {
+        haveEscape = true;
+        break;
+      }
+    if (haveEscape)
+      while (i < escapable.length()) {
+        int pt = -1;
+        char ch = escapable.charAt(i++);
+        char ch2 = escapable.charAt(i++);
+        SB sb = new SB();
+        int pt0 = 0;
+        while ((pt = str.indexOf(ch, pt + 1)) >= 0) {
+          sb.append(str.substring(pt0, pt)).appendC('\\').appendC(ch2);
+          pt0 = pt + 1;
+        }
+        sb.append(str.substring(pt0, str.length()));
+        str = sb.toString();
+      }    
+    return "\"" + escUnicode(str) + "\"";
+  }
+
+  public static String escUnicode(String str) {
+    for (int i = str.length(); --i >= 0;)
+      if (str.charAt(i) > 0x7F) {
+        String s = "0000" + Integer.toHexString(str.charAt(i));
+        str = str.substring(0, i) + "\\u" + s.substring(s.length() - 4)
+            + str.substring(i + 1);
+      }
+    return str;
+  }
+
+  /**
+   * ensures that a float turned to string has a decimal point
+   * 
+   * @param f
+   * @return string version of float
+   */
+  public static String escF(float f) {
+    String sf = "" + f;
+    /**
+     * @j2sNative
+     * 
+     * if (sf.indexOf(".") < 0 && sf.indexOf("e") < 0)
+     *   sf += ".0";
+     */
+    {
+    }
+    return sf;
+  }
+  public static String join(String[] s, char c, int i0) {
+    if (s.length < i0)
+      return null;
+    SB sb = new SB();
+    sb.append(s[i0++]);
+    for (int i = i0; i < s.length; i++)
+      sb.appendC(c).append(s[i]);
+    return sb.toString();
+  }
+
+  /**
+   * a LIKE "x"    a is a string and equals x
+   * 
+   * a LIKE "*x"   a is a string and ends with x
+   * 
+   * a LIKE "x*"   a is a string and starts with x
+   * 
+   * a LIKE "*x*"  a is a string and contains x
+   *  
+   * @param a
+   * @param b
+   * @return  a LIKE b
+   */
+  public static boolean isLike(String a, String b) {
+    boolean areEqual = a.equals(b);
+    if (areEqual)
+      return true;
+    boolean isStart = b.startsWith("*");
+    boolean isEnd = b.endsWith("*");
+    return (!isStart && !isEnd) ? areEqual
+        : isStart && isEnd ? b.length() == 1 || a.contains(b.substring(1, b.length() - 1))
+        : isStart ? a.endsWith(b.substring(1))
+        : a.startsWith(b.substring(0, b.length() - 1));
+  }
+
+  public static Object getMapValueNoCase(Map<String, ?> h, String key) {
+    if ("this".equals(key))
+      return h;
+    Object val = h.get(key);
+    if (val == null)
+      for (Entry<String, ?> e : h.entrySet())
+        if (e.getKey().equalsIgnoreCase(key))
+          return e.getValue();
+    return val;
+  }
+
+  public static String clean(String s) {
+    return rep(replaceAllCharacters(s, " \t\n\r", " "), "  ", " ").trim();
+  }
+
+  /**
+   * 
+   * fdup      duplicates p or q formats for formatCheck
+   *           and the format() function.
+   * 
+   * @param f
+   * @param pt
+   * @param n
+   * @return     %3.5q%3.5q%3.5q%3.5q or %3.5p%3.5p%3.5p
+   */
+  public static String fdup(String f, int pt, int n) {
+    char ch;
+    int count = 0;
+    for (int i = pt; --i >= 1; ) {
+      if (isDigit(ch = f.charAt(i)))
+        continue;
+      switch (ch) {
+      case '.':
+        if (count++ != 0)
+          return f;
+        continue;
+      case '-':
+        if (i != 1 && f.charAt(i - 1) != '.')
+          return f;
+        continue;
+      default:
+        return f;
+      }
+    }
+    String s = f.substring(0, pt + 1);
+    SB sb = new SB();
+    for (int i = 0; i < n; i++)
+      sb.append(s);
+    sb.append(f.substring(pt + 1));
+    return sb.toString();
+  }
+
+  /**
+   * generic string formatter  based on formatLabel in Atom
+   * 
+   * 
+   * @param strFormat   .... %width.precisionKEY....
+   * @param key      any string to match
+   * @param strT     replacement string or null
+   * @param floatT   replacement float or Float.NaN
+   * @param doubleT  replacement double or Double.NaN -- for exponential
+   * @param doOne    mimic sprintf    
+   * @return         formatted string
+   */
+  
+  public static String formatString(String strFormat, String key, String strT,
+                                    float floatT, double doubleT, boolean doOne) {
+    if (strFormat == null)
+      return null;
+    if ("".equals(strFormat))
+      return "";
+    int len = key.length();
+    if (strFormat.indexOf("%") < 0 || len == 0 || strFormat.indexOf(key) < 0)
+      return strFormat;
+  
+    String strLabel = "";
+    int ich, ichPercent, ichKey;
+    for (ich = 0; (ichPercent = strFormat.indexOf('%', ich)) >= 0
+        && (ichKey = strFormat.indexOf(key, ichPercent + 1)) >= 0;) {
+      if (ich != ichPercent)
+        strLabel += strFormat.substring(ich, ichPercent);
+      ich = ichPercent + 1;
+      if (ichKey > ichPercent + 6) {
+        strLabel += '%';
+        continue;//%12.10x
+      }
+      try {
+        boolean alignLeft = false;
+        if (strFormat.charAt(ich) == '-') {
+          alignLeft = true;
+          ++ich;
+        }
+        boolean zeroPad = false;
+        if (strFormat.charAt(ich) == '0') {
+          zeroPad = true;
+          ++ich;
+        }
+        char ch;
+        int width = 0;
+        while ((ch = strFormat.charAt(ich)) >= '0' && (ch <= '9')) {
+          width = (10 * width) + (ch - '0');
+          ++ich;
+        }
+        int precision = Integer.MAX_VALUE;
+        boolean isExponential = false;
+        if (strFormat.charAt(ich) == '.') {
+          ++ich;
+          if ((ch = strFormat.charAt(ich)) == '-') {
+            isExponential = true;
+            ++ich;
+          } 
+          if ((ch = strFormat.charAt(ich)) >= '0' && ch <= '9') {
+            precision = ch - '0';
+            ++ich;
+          }
+          if (isExponential)
+            precision = -precision - (strT == null ? 1 : 0);
+        }
+        String st = strFormat.substring(ich, ich + len);
+        if (!st.equals(key)) {
+          ich = ichPercent + 1;
+          strLabel += '%';
+          continue;
+        }
+        ich += len;
+        if (!Float.isNaN(floatT))
+          strLabel += formatF(floatT, width, precision, alignLeft,
+              zeroPad);
+        else if (strT != null)
+          strLabel += formatS(strT, width, precision, alignLeft,
+              zeroPad);
+        else if (!Double.isNaN(doubleT))
+          strLabel += formatD(doubleT, width, precision, alignLeft,
+              zeroPad, true);
+        if (doOne)
+          break;
+      } catch (IndexOutOfBoundsException ioobe) {
+        ich = ichPercent;
+        break;
+      }
+    }
+    strLabel += strFormat.substring(ich);
+    //if (strLabel.length() == 0)
+      //return null;
+    return strLabel;
+  }
+
+  public static String formatStringS(String strFormat, String key, String strT) {
+    return formatString(strFormat, key, strT, Float.NaN, Double.NaN, false);
+  }
+
+  public static String formatStringF(String strFormat, String key, float floatT) {
+    return formatString(strFormat, key, null, floatT, Double.NaN, false);
+  }
+
+  public static String formatStringI(String strFormat, String key, int intT) {
+    return formatString(strFormat, key, "" + intT, Float.NaN, Double.NaN, false);
+  }
+
+  /**
+   * sprintf emulation uses (almost) c++ standard string formats
+   * 
+   * 's' string 'i' or 'd' integer, 'e' double, 'f' float, 'p' point3f 'q'
+   * quaternion/plane/axisangle with added "i" (equal to the insipid "d" --
+   * digits?)
+   * 
+   * @param strFormat
+   * @param list
+   *        a listing of what sort of data will be found in Object[] values, in
+   *        order: s string, f float, i integer, d double, p point3f, q
+   *        quaternion/point4f, S String[], F float[], I int[], and D double[]
+   * @param values
+   *        Object[] containing above types
+   * @return formatted string
+   */
+  public static String sprintf(String strFormat, String list, Object[] values) {
+    if (values == null)
+      return strFormat;
+    int n = list.length();
+    if (n == values.length)
+      try {
+        for (int o = 0; o < n; o++) {
+          if (values[o] == null)
+            continue;
+          switch (list.charAt(o)) {
+          case 's':
+            strFormat = formatString(strFormat, "s", (String) values[o],
+                Float.NaN, Double.NaN, true);
+            break;
+          case 'f':
+            strFormat = formatString(strFormat, "f", null, ((Float) values[o])
+                .floatValue(), Double.NaN, true);
+            break;
+          case 'i':
+            strFormat = formatString(strFormat, "d", "" + values[o], Float.NaN,
+                Double.NaN, true);
+            strFormat = formatString(strFormat, "i", "" + values[o], Float.NaN,
+                Double.NaN, true);
+            break;
+          case 'd':
+            strFormat = formatString(strFormat, "e", null, Float.NaN,
+                ((Double) values[o]).doubleValue(), true);
+            break;
+          case 'p':
+            T3 pVal = (T3) values[o];
+            strFormat = formatString(strFormat, "p", null, pVal.x, Double.NaN,
+                true);
+            strFormat = formatString(strFormat, "p", null, pVal.y, Double.NaN,
+                true);
+            strFormat = formatString(strFormat, "p", null, pVal.z, Double.NaN,
+                true);
+            break;
+          case 'q':
+            T4 qVal = (T4) values[o];
+            strFormat = formatString(strFormat, "q", null, qVal.x, Double.NaN,
+                true);
+            strFormat = formatString(strFormat, "q", null, qVal.y, Double.NaN,
+                true);
+            strFormat = formatString(strFormat, "q", null, qVal.z, Double.NaN,
+                true);
+            strFormat = formatString(strFormat, "q", null, qVal.w, Double.NaN,
+                true);
+            break;
+          case 'S':
+            String[] sVal = (String[]) values[o];
+            for (int i = 0; i < sVal.length; i++)
+              strFormat = formatString(strFormat, "s", sVal[i], Float.NaN,
+                  Double.NaN, true);
+            break;
+          case 'F':
+            float[] fVal = (float[]) values[o];
+            for (int i = 0; i < fVal.length; i++)
+              strFormat = formatString(strFormat, "f", null, fVal[i],
+                  Double.NaN, true);
+            break;
+          case 'I':
+            int[] iVal = (int[]) values[o];
+            for (int i = 0; i < iVal.length; i++)
+              strFormat = formatString(strFormat, "d", "" + iVal[i], Float.NaN,
+                  Double.NaN, true);
+            for (int i = 0; i < iVal.length; i++)
+              strFormat = formatString(strFormat, "i", "" + iVal[i], Float.NaN,
+                  Double.NaN, true);
+            break;
+          case 'D':
+            double[] dVal = (double[]) values[o];
+            for (int i = 0; i < dVal.length; i++)
+              strFormat = formatString(strFormat, "e", null, Float.NaN,
+                  dVal[i], true);
+          }
+  
+        }
+        return rep(strFormat, "%%", "%");
+      } catch (Exception e) {
+        //
+      }
+    System.out.println("TextFormat.sprintf error " + list + " " + strFormat);
+    return rep(strFormat, "%", "?");
+  }
+
+  /**
+   * 
+   * formatCheck   checks p and q formats and duplicates if necessary
+   *               "%10.5p xxxx" ==> "%10.5p%10.5p%10.5p xxxx" 
+   * 
+   * @param strFormat
+   * @return    f or dupicated format
+   */
+  public static String formatCheck(String strFormat) {
+    if (strFormat == null || strFormat.indexOf('p') < 0 && strFormat.indexOf('q') < 0)
+      return strFormat;
+    strFormat = rep(strFormat, "%%", "\1");
+    strFormat = rep(strFormat, "%p", "%6.2p");
+    strFormat = rep(strFormat, "%q", "%6.2q");
+    String[] format = split(strFormat, "%");
+    SB sb = new SB();
+    sb.append(format[0]);
+    for (int i = 1; i < format.length; i++) {
+      String f = "%" + format[i];
+      int pt;
+      if (f.length() >= 3) {
+        if ((pt = f.indexOf('p')) >= 0)
+          f = fdup(f, pt, 3);
+        if ((pt = f.indexOf('q')) >= 0)
+          f = fdup(f, pt, 4);
+      }
+      sb.append(f);
+    }
+    return sb.toString().replace('\1', '%');
+  }
+
+  public static void leftJustify(SB s, String s1, String s2) {
+    s.append(s2);
+    int n = s1.length() - s2.length();
+    if (n > 0)
+      s.append(s1.substring(0, n));
+  }
+
+  public static void rightJustify(SB s, String s1, String s2) {
+    int n = s1.length() - s2.length();
+    if (n > 0)
+      s.append(s1.substring(0, n));
+    s.append(s2);
+  }
+
+  public static String safeTruncate(float f, int n) {
+    if (f > -0.001 && f < 0.001)
+      f = 0;
+    return (f + "         ").substring(0,n);
+  }
+
+  public static boolean isWild(String s) {
+    return s != null && (s.indexOf("*") >= 0 || s.indexOf("?") >= 0);
+  }
+
+  /**
+   * A general non-regex (for performance) text matcher that utilizes ? and *.
+   * 
+   * ??? means "at most three" characters if at beginning or end; 
+   *   "exactly three" otherwise
+   * \1 in search is a stand-in for actual ?
+   * 
+   * @param search
+   *        the string to search
+   * @param match
+   *        the match string
+   * @param checkStar
+   * @param allowInitialStar
+   * @return true if found
+   */
+  public static boolean isMatch(String search, String match, boolean checkStar,
+                                boolean allowInitialStar) {
+    // search == match --> true
+    if (search.equals(match))
+      return true;
+    int mLen = match.length();
+    // match == ""  --> false
+    if (mLen == 0)
+      return false;
+    boolean isStar0 = (checkStar && allowInitialStar ? match.charAt(0) == '*'
+        : false);
+    // match == "*" --> true
+    if (mLen == 1 && isStar0)
+      return true;
+    boolean isStar1 = (checkStar && match.endsWith("*"));
+    boolean haveQ = (match.indexOf('?') >= 0);
+    // match == "**" --> true
+    // match == "*xxx*" --> search contains "xxx"
+    // match == "*xxx" --> search ends with "xxx"
+    // match == "xxx*" --> search starts with "xxx"
+    if (!haveQ) {
+      if (isStar0)
+        return (isStar1 ? (mLen < 3 || search.indexOf(match.substring(1,
+            mLen - 1)) >= 0) : search.endsWith(match.substring(1)));
+      else if (isStar1)
+        return search.startsWith(match.substring(0, mLen - 1));
+    }
+    int sLen = search.length();
+    // pad match with "?" -- same as *
+    String qqqq = "????";
+    int nq = 4;
+    while (nq < sLen) {
+      qqqq += qqqq;
+      nq += 4;
+    }
+    if (checkStar) {
+      if (isStar0) {
+        match = qqqq + match.substring(1);
+        mLen += nq - 1;
+      }
+      if (isStar1) {
+        match = match.substring(0, mLen - 1) + qqqq;
+        mLen += nq - 1;
+      }
+    }
+    // length of match < length of search --> false 
+    if (mLen < sLen)
+      return false;
+  
+    // -- each ? matches ONE character if not at end
+    // -- extra ? at end ignored
+  
+    // (allowInitialStar == true)
+    // -- extra ? at beginning reduced to match length
+  
+    int ich = 0;
+    while (mLen > sLen) {
+      if (allowInitialStar && match.charAt(ich) == '?') {
+        ++ich;
+      } else if (match.charAt(ich + mLen - 1) != '?') {
+        return false;
+      }
+      --mLen;
+    }
+  
+    // both are effectively same length now.
+    // \1 is stand-in for "?"
+  
+    for (int i = sLen; --i >= 0;) {
+      char chm = match.charAt(ich + i);
+      if (chm == '?')
+        continue;
+      char chs = search.charAt(i);
+      if (chm != chs && (chm != '\1' || chs != '?'))
+        return false;
+    }
+    return true;
+  }
+
+  public static String replaceQuotedStrings(String s, Lst<String> list,
+                                            Lst<String> newList) {
+    int n = list.size();
+    for (int i = 0; i < n; i++) {
+      String name = list.get(i);
+      String newName = newList.get(i);
+      if (!newName.equals(name))
+        s = rep(s, "\"" + name + "\"", "\"" + newName
+            + "\"");
+    }
+    return s;
+  }
+
+  public static String replaceStrings(String s, Lst<String> list,
+                                      Lst<String> newList) {
+    int n = list.size();
+    for (int i = 0; i < n; i++) {
+      String name = list.get(i);
+      String newName = newList.get(i);
+      if (!newName.equals(name))
+        s = rep(s, name, newName);
+    }
+    return s;
+  }
+
+  public static boolean isDigit(char ch) {
+    // just way simpler code than  Character.isDigit(ch);
+    int c = ch;
+    return (48 <= c && c <= 57);
+  }
+
+  public static boolean isUpperCase(char ch) {
+    int c = ch;
+    return (65 <= c && c <= 90);
+  }
+
+  public static boolean isLowerCase(char ch) {
+    int c = ch;
+    return (97 <= c && c <= 122);
+  }
+
+  public static boolean isLetter(char ch) {
+    // just way simpler code than     Character.isLetter(ch);
+    int c = ch;
+    return (65 <= c && c <= 90 || 97 <= c && c <= 122);
+  }
+
+  public static boolean isLetterOrDigit(char ch) {
+    // just way simpler code than     Character.isLetterOrDigit(ch);
+    int c = ch;
+    return (65 <= c && c <= 90 || 97 <= c && c <= 122 || 48 <= c && c <= 57);
+  }
+
+  public static boolean isWhitespace(char ch) {
+    int c = ch;
+    return (c >= 0x1c && c <= 0x20 || c >= 0x9 && c <= 0xd);
+  }
+
+  public static final float FRACTIONAL_PRECISION = 100000f;
+  public static final float CARTESIAN_PRECISION =  10000f;
+
+  public static void fixPtFloats(T3 pt, float f) {
+    //this will equate float and double as long as -256 <= x <= 256
+    pt.x = Math.round(pt.x * f) / f;
+    pt.y = Math.round(pt.y * f) / f;
+    pt.z = Math.round(pt.z * f) / f;
+  }
+  
+  public static double fixDouble(double d, double f) {
+    return Math.round(d * f) / f;
+  }
+
+  /**
+   * parse a float or "float/float"
+   * @param s
+   * @return a/b
+   */
+  public static float parseFloatFraction(String s) {
+      int pt = s.indexOf("/");
+      return (pt < 0 ? parseFloat(s) : parseFloat(s.substring(0, pt))
+          / parseFloat(s.substring(pt + 1)));
+  }
+
+//static {
+//    
+//  double d = 790.8999998888;
+//  float x  = 790.8999998888f;
+//  for (int i = 0; i < 50; i++) {
+//  System.out.println(x + " " + d);
+//  System.out.println(Math.round(x * 100000) / 100000f);
+//  System.out.println(Math.round(d * 100000) / 100000.);
+//  System.out.println(Math.round(x * 10000) / 10000f);
+//  System.out.println(Math.round(d * 10000) / 10000.);
+//  x+=1; 
+//  d+=1;
+//  }
+//  System.out.println(100.123456789f);
+//}
+
+//  static {
+//    long t;
+//    char c = '0';
+//    t = System.currentTimeMillis();
+//    for (int i = 0; i < 10000000; i++) {
+//      boolean b = PT.isUpperCase(c);
+//    }
+//    System.out.println(System.currentTimeMillis() - t);
+//
+//    t = System.currentTimeMillis();
+//    for (int i = 0; i < 10000000; i++) {
+//      boolean b = Character.isUpperCase(c);
+//    }
+//    System.out.println(System.currentTimeMillis() - t);
+//    
+//    t = System.currentTimeMillis();
+//    for (int i = 0; i < 10000000; i++) {
+//      boolean b = PT.isUpperCase(c);
+//    }
+//    System.out.println(System.currentTimeMillis() - t);
+//
+//    System.out.println("PT test");
+//  }
+}
diff --git a/src/javajs/util/Quat.java b/src/javajs/util/Quat.java
new file mode 100644 (file)
index 0000000..6b93578
--- /dev/null
@@ -0,0 +1,815 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-04-05 09:07:28 -0500 (Thu, 05 Apr 2007) $
+ * $Revision: 7326 $
+ *
+ * Copyright (C) 2003-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+/*
+ * Standard UNIT quaternion math -- for rotation.
+ * 
+ * All rotations can be represented as two identical quaternions. 
+ * This is because any rotation can be considered from either end of the
+ * rotational axis -- either as a + rotation or a - rotation. This code
+ * is designed to always maintain the quaternion with a rotation in the
+ * [0, PI) range. 
+ * 
+ * This ensures that the reported theta is always positive, and the normal
+ * reported is always associated with a positive theta.  
+ * 
+ * @author Bob Hanson, hansonr@stolaf.edu 6/2008
+ * 
+ */
+
+public class Quat {
+  public float q0, q1, q2, q3;
+  private M3 mat;
+
+  private final static P4 qZero = new P4();
+  private static final double RAD_PER_DEG = Math.PI / 180;
+  
+  public Quat() {
+    q0 = 1;
+  }
+
+  public static Quat newQ(Quat q) {
+    Quat q1 = new Quat();
+    q1.set(q);
+    return q1;
+  }
+
+  public static Quat newVA(T3 v, float theta) {
+    Quat q = new Quat();
+    q.setTA(v, theta);
+    return q;
+  }
+
+  public static Quat newM(M3 mat) {
+    Quat q = new Quat();
+    q.setM(M3.newM3(mat));
+    return q;
+  }
+
+  public static Quat newAA(A4 a) {
+    Quat q = new Quat();
+    q.setAA(a);
+    return q;
+  }
+
+  public static Quat newP4(P4 pt) {
+    Quat q = new Quat();
+    q.setP4(pt);
+    return q;
+  }
+
+  /**
+   * Note that q0 is the last parameter here
+   * 
+   * @param q1
+   * @param q2
+   * @param q3
+   * @param q0
+   * @return {q1 q2 q3 q0}
+   */
+  public static Quat new4(float q1, float q2, float q3, float q0) {
+    Quat q = new Quat();
+    if (q0 < -1) {
+      q.q0 = -1;
+      return q;
+    }
+    if (q0 > 1) {
+      q.q0 = 1;
+      return q;
+    }
+    q.q0 = q0;
+    q.q1 = q1;
+    q.q2 = q2;
+    q.q3 = q3;
+    return q;
+  }
+
+  public void set(Quat q) {
+    q0 = q.q0;
+    q1 = q.q1;
+    q2 = q.q2;
+    q3 = q.q3;
+  }
+
+  /**
+   * {x y z w} --> {q1 q2 q3 q0} and factored
+   * 
+   * @param pt
+   */
+  private void setP4(P4 pt) {
+    float factor = (pt == null ? 0 : pt.distance4(qZero));
+    if (factor == 0) {
+      q0 = 1;
+      return;
+    }
+    q0 = pt.w / factor;
+    q1 = pt.x / factor;
+    q2 = pt.y / factor;
+    q3 = pt.z / factor;
+  }
+
+  /**
+   * q = (cos(theta/2), sin(theta/2) * n)
+   * 
+   * @param pt
+   * @param theta
+   */
+  public void setTA(T3 pt, float theta) {
+    if (pt.x == 0 && pt.y == 0 && pt.z == 0) {
+      q0 = 1;
+      return;
+    }
+    double fact = (Math.sin(theta / 2 * RAD_PER_DEG) / Math.sqrt(pt.x
+        * pt.x + pt.y * pt.y + pt.z * pt.z));
+    q0 = (float) (Math.cos(theta / 2 * RAD_PER_DEG));
+    q1 = (float) (pt.x * fact);
+    q2 = (float) (pt.y * fact);
+    q3 = (float) (pt.z * fact);
+  }
+
+  public void setAA(A4 a) {
+    A4 aa = A4.newAA(a);
+    if (aa.angle == 0)
+      aa.y = 1;
+    setM(new M3().setAA(aa));
+  }
+
+  private void setM(M3 mat) {
+
+    /*
+     * Changed 7/16/2008 to double precision for 11.5.48.
+     * 
+     * <quote>
+     *  
+     * RayTrace Software Package, release 3.0.  May 3, 2006.
+     *
+     * Mathematics Subpackage (VrMath)
+     *
+     * Author: Samuel R. Buss
+     *
+     * Software is "as-is" and carries no warranty.  It may be used without
+     *   restriction, but if you modify it, please change the filenames to
+     *   prevent confusion between different versions.  Please acknowledge
+     *   all use of the software in any publications or products based on it.
+     *
+     * Bug reports: Sam Buss, sbuss@ucsd.edu.
+     * Web page: http://math.ucsd.edu/~sbuss/MathCG
+     
+     // Use Shepperd's algorithm, which is stable, does not lose
+     //    significant precision and uses only one sqrt.
+     //   J. Guidance and Control, 1 (1978) 223-224.
+
+     * </quote>
+     * 
+     * Except, that code has errors.
+     * 
+     * CORRECTIONS (as noted below) of Quaternion.cpp. I have reported the bug.
+     *  
+     * -- Bob Hanson
+     * 
+     *  theory:    
+     *         cos(theta/2)^2 = (cos(theta) + 1)/2
+     *  and      
+     *         trace = (1-x^2)ct + (1-y^2)ct + (1-z^2)ct + 1 = 2cos(theta) + 1
+     *  or
+     *         cos(theta) = (trace - 1)/2 
+     *         
+     *  so in general,       
+     *       
+     *       w = cos(theta/2) 
+     *         = sqrt((cos(theta)+1)/2) 
+     *         = sqrt((trace-1)/4+1/2)
+     *         = sqrt((trace+1)/4)
+     *         = sqrt(trace+1)/2
+     *     
+     *  but there are precision issues, so we allow for other situations.
+     *  note -- trace >= 0.5 when cos(theta) >= -0.25 (-104.48 <= theta <= 104.48).
+     *  this code cleverly matches the precision in all four options.
+     *
+     */
+
+    this.mat = mat;
+    
+    double trace = mat.m00 + mat.m11 + mat.m22;
+    double temp;
+    double w, x, y, z;
+    if (trace >= 0.5) {
+      w = Math.sqrt(1.0 + trace);
+      x = (mat.m21 - mat.m12) / w;
+      y = (mat.m02 - mat.m20) / w;
+      z = (mat.m10 - mat.m01) / w;
+    } else if ((temp = mat.m00 + mat.m00 - trace) >= 0.5) {
+      x = Math.sqrt(1.0 + temp);
+      w = (mat.m21 - mat.m12) / x;
+      y = (mat.m10 + mat.m01) / x;
+      z = (mat.m20 + mat.m02) / x;
+    } else if ((temp = mat.m11 + mat.m11 - trace) >= 0.5 
+        || mat.m11 > mat.m22) {
+      y = Math.sqrt(1.0 + temp);
+      w = (mat.m02 - mat.m20) / y;
+      x = (mat.m10 + mat.m01) / y;
+      z = (mat.m21 + mat.m12) / y;
+    } else {
+      z = Math.sqrt(1.0 + mat.m22 + mat.m22 - trace);
+      w = (mat.m10 - mat.m01) / z;
+      x = (mat.m20 + mat.m02) / z; // was -
+      y = (mat.m21 + mat.m12) / z; // was -
+    }
+
+    q0 = (float) (w * 0.5);
+    q1 = (float) (x * 0.5);
+    q2 = (float) (y * 0.5);
+    q3 = (float) (z * 0.5);
+
+    /*
+     *  Originally from http://www.gamedev.net/community/forums/topic.asp?topic_id=448380
+     *  later algorithm was adapted from Visualizing Quaternions, by Andrew J. Hanson
+     *   (Morgan Kaufmann, 2006), page 446
+     *  
+     *  HOWEVER, checking with AxisAngle4f and Quat4f equivalents, it was found that
+     *  BOTH of these sources produce inverted quaternions. So here we do an inversion.
+     *  
+     *  This correction was made in 11.5.42  6/19/2008  -- Bob Hanson
+     *
+     *  former algorithm used:     
+     * /
+     
+     double tr = mat.m00 + mat.m11 + mat.m22; //Matrix trace 
+     double s;
+     double[] q = new double[4];
+     if (tr > 0) {
+     s = Math.sqrt(tr + 1);
+     q0 = (float) (0.5 * s);
+     s = 0.5 / s; // = 1/q0
+     q1 = (float) ((mat.m21 - mat.m12) * s);
+     q2 = (float) ((mat.m02 - mat.m20) * s);
+     q3 = (float) ((mat.m10 - mat.m01) * s);
+     } else {
+     float[][] m = new float[][] { new float[3], new float[3], new float[3] };
+     mat.getRow(0, m[0]);
+     mat.getRow(1, m[1]);
+     mat.getRow(2, m[2]);
+
+     //Find out the biggest element along the diagonal 
+     float max = Math.max(mat.m11, mat.m00);
+     int i = (mat.m22 > max ? 2 : max == mat.m11 ? 1 : 0);
+     int j = (i + 1) % 3;
+     int k = (j + 1) % 3;
+     s = -Math.sqrt(1 + m[i][i] - m[j][j] - m[k][k]);
+     // 0 = 1 + (1-x^2)ct + x^2 -(1-y^2)ct - y^2 - (1-z^2)ct - z^2
+     // 0 = 1 - ct + (x^2 - y^2 - z^2) - (x^2 - y^2 - z^2)ct
+     // 0 = 1 - ct + 2x^2 - 1 - (2x^2)ct + ct
+     // 0 = 2x^2(1 - ct)
+     // theta = 0 (but then trace = 1 + 1 + 1 = 3)
+     // or x = 0. 
+     q[i] = s * 0.5;
+     if (s != 0)
+     s = 0.5 / s; // = 1/q[i]
+     q[j] = (m[i][j] + m[j][i]) * s;
+     q[k] = (m[i][k] + m[k][i]) * s;
+     q0 = (float) ((m[k][j] - m[j][k]) * s);
+     q1 = (float) q[0]; // x
+     q2 = (float) q[1]; // y
+     q3 = (float) q[2]; // z 
+     }
+
+     */
+  }
+
+  /*
+   * if qref is null, "fix" this quaternion
+   * otherwise, return a quaternion that is CLOSEST to the given quaternion
+   * that is, one that gives a positive dot product
+   * 
+   */
+  public void setRef(Quat qref) {
+    if (qref == null) {
+      mul(getFixFactor());
+      return;
+    }
+    if (dot(qref) >= 0)
+      return;
+    q0 *= -1;
+    q1 *= -1;
+    q2 *= -1;
+    q3 *= -1;
+  }
+
+  /**
+   * returns a quaternion frame based on three points (center, x, and any point in xy plane)
+   * or two vectors (vA, vB).
+   * 
+   * @param center  (null for vA/vB option)
+   * @param x
+   * @param xy
+   * @return quaternion for frame
+   */
+  public static final Quat getQuaternionFrame(P3 center, T3 x,
+                                                    T3 xy) {
+    V3 vA = V3.newV(x);
+    V3 vB = V3.newV(xy);
+    if (center != null) {
+      vA.sub(center);
+      vB.sub(center);
+    }
+    return getQuaternionFrameV(vA, vB, null, false);
+  }
+
+  /**
+   * Create a quaternion based on a frame
+   * @param vA
+   * @param vB
+   * @param vC
+   * @param yBased
+   * @return quaternion
+   */
+  public static final Quat getQuaternionFrameV(V3 vA, V3 vB,
+                                                    V3 vC, boolean yBased) {
+    if (vC == null) {
+      vC = new V3();
+      vC.cross(vA, vB);
+      if (yBased)
+        vA.cross(vB, vC);
+    }
+    V3 vBprime = new V3();
+    vBprime.cross(vC, vA);
+    vA.normalize();
+    vBprime.normalize();
+    vC.normalize();
+    M3 mat = new M3();
+    mat.setColumnV(0, vA);
+    mat.setColumnV(1, vBprime);
+    mat.setColumnV(2, vC);
+
+    /*
+     * 
+     * Verification tests using Quat4f and AngleAxis4f:
+     * 
+     System.out.println("quaternion frame matrix: " + mat);
+     
+     Point3f pt2 = new Point3f();
+     mat.transform(Point3f.new3(1, 0, 0), pt2);
+     System.out.println("vA=" + vA + " M(100)=" + pt2);
+     mat.transform(Point3f.new3(0, 1, 0), pt2);
+     System.out.println("vB'=" + vBprime + " M(010)=" + pt2);
+     mat.transform(Point3f.new3(0, 0, 1), pt2);
+     System.out.println("vC=" + vC + " M(001)=" + pt2);
+     Quat4f q4 = new Quat4f();
+     q4.set(mat);
+     System.out.println("----");
+     System.out.println("Quat4f: {" + q4.w + " " + q4.x + " " + q4.y + " " + q4.z + "}");
+     System.out.println("Quat4f: 2xy + 2wz = m10: " + (2 * q4.x * q4.y + 2 * q4.w * q4.z) + " = " + mat.m10);   
+     
+     */
+
+    Quat q = newM(mat);
+
+     /*
+     System.out.println("Quaternion mat from q \n" + q.getMatrix());
+     System.out.println("Quaternion: " + q.getNormal() + " " + q.getTheta());
+     AxisAngle4f a = new AxisAngle4f();
+     a.set(mat);
+     Vector3f v = Vector3f.new3(a.x, a.y, a.z);
+     v.normalize();
+     System.out.println("angleAxis: " + v + " "+(a.angle/Math.PI * 180));
+     */
+     
+    return q;
+  }
+
+  public M3 getMatrix() {
+    if (mat == null)
+      setMatrix();
+    return mat;
+  }
+
+  private void setMatrix() {
+    mat = new M3();
+    // q0 = w, q1 = x, q2 = y, q3 = z
+    mat.m00 = q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3;
+    mat.m01 = 2 * q1 * q2 - 2 * q0 * q3;
+    mat.m02 = 2 * q1 * q3 + 2 * q0 * q2;
+    mat.m10 = 2 * q1 * q2 + 2 * q0 * q3;
+    mat.m11 = q0 * q0 - q1 * q1 + q2 * q2 - q3 * q3;
+    mat.m12 = 2 * q2 * q3 - 2 * q0 * q1;
+    mat.m20 = 2 * q1 * q3 - 2 * q0 * q2;
+    mat.m21 = 2 * q2 * q3 + 2 * q0 * q1;
+    mat.m22 = q0 * q0 - q1 * q1 - q2 * q2 + q3 * q3;
+  }
+
+  public Quat add(float x) {
+    // scalar theta addition (degrees) 
+   return newVA(getNormal(), getTheta() + x);
+  }
+
+  public Quat mul(float x) {
+    // scalar theta multiplication
+    return (x == 1 ? new4(q1, q2, q3, q0) : 
+      newVA(getNormal(), getTheta() * x));
+  }
+
+  public Quat mulQ(Quat p) {
+    return new4(
+        q0 * p.q1 + q1 * p.q0 + q2 * p.q3 - q3 * p.q2, 
+        q0 * p.q2 + q2 * p.q0 + q3 * p.q1 - q1 * p.q3, 
+        q0 * p.q3 + q3 * p.q0 + q1 * p.q2 - q2 * p.q1, 
+        q0 * p.q0 - q1 * p.q1 - q2 * p.q2 - q3 * p.q3);
+  }
+
+  public Quat div(Quat p) {
+    // unit quaternions assumed -- otherwise would scale by 1/p.dot(p)
+    return mulQ(p.inv());
+  }
+
+  public Quat divLeft(Quat p) {
+    // unit quaternions assumed -- otherwise would scale by 1/p.dot(p)
+    return this.inv().mulQ(p);
+  }
+
+  public float dot(Quat q) {
+    return this.q0 * q.q0 + this.q1 * q.q1 + this.q2 * q.q2 + this.q3 * q.q3;
+  }
+
+  public Quat inv() {
+    return new4(-q1, -q2, -q3, q0);
+  }
+
+  public Quat negate() {
+    return new4(-q1, -q2, -q3, -q0);
+  }
+
+  /**
+   * ensures 
+   * 
+   * 1) q0 > 0
+   * or
+   * 2) q0 = 0 and q1 > 0
+   * or
+   * 3) q0 = 0 and q1 = 0 and q2 > 0
+   * or
+   * 4) q0 = 0 and q1 = 0 and q2 = 0 and q3 > 0
+   * 
+   * @return 1 or -1  
+   * 
+   */
+
+  private float getFixFactor() {
+    return (q0 < 0 || 
+        q0 == 0 && (q1 < 0 || q1 == 0 && (q2 < 0 || q2 == 0 && q3 < 0)) ? -1 : 1);
+  }
+  
+  public V3 getVector(int i) {
+    return getVectorScaled(i, 1f);
+  }
+
+  public V3 getVectorScaled(int i, float scale) {
+    if (i == -1) {
+      scale *= getFixFactor();
+      return V3.new3(q1 * scale, q2 * scale, q3 * scale);
+    }
+    if (mat == null)
+      setMatrix();
+    V3 v = new V3();
+    mat.getColumnV(i, v);
+    if (scale != 1f)
+      v.scale(scale);
+    return v;
+  }
+
+  /**
+   * 
+   * @return  vector such that 0 <= angle <= 180
+   */
+  public V3 getNormal() {
+    V3 v = getRawNormal(this);
+    v.scale(getFixFactor());
+    return v;
+  }
+
+  private static V3 getRawNormal(Quat q) {
+    V3 v = V3.new3(q.q1, q.q2, q.q3);
+    if (v.length() == 0)
+      return V3.new3(0, 0, 1);
+    v.normalize();
+    return v;
+  }
+
+  /**
+   * 
+   * @return 0 <= angle <= 180 in degrees
+   */
+  public float getTheta() {
+    return (float) (Math.acos(Math.abs(q0)) * 2 * 180 / Math.PI);
+  }
+
+  public float getThetaRadians() {
+    return (float) (Math.acos(Math.abs(q0)) * 2);
+  }
+
+  /**
+   * 
+   * @param v0
+   * @return    vector option closest to v0
+   * 
+   */
+  public V3 getNormalDirected(V3 v0) {
+    V3 v = getNormal();
+    if (v.x * v0.x + v.y * v0.y + v.z * v0.z < 0) {
+      v.scale(-1);
+    }
+    return v;
+  }
+
+  public V3 get3dProjection(V3 v3d) {
+    v3d.set(q1, q2, q3);
+    return v3d;
+  }
+  
+  /**
+   * 
+   * @param axisAngle
+   * @return   fill in theta of axisAngle such that 
+   */
+  public P4 getThetaDirected(P4 axisAngle) {
+    //fills in .w;
+    float theta = getTheta();
+    V3 v = getNormal();
+    if (axisAngle.x * q1 + axisAngle.y * q2 + axisAngle.z * q3 < 0) {
+      v.scale(-1);
+      theta = -theta;
+    }
+    axisAngle.set4(v.x, v.y, v.z, theta);
+    return axisAngle;
+  }
+
+  /**
+   * 
+   * @param vector  a vector, same as for getNormalDirected
+   * @return   return theta 
+   */
+  public float getThetaDirectedV(V3 vector) {
+    //fills in .w;
+    float theta = getTheta();
+    V3 v = getNormal();
+    if (vector.x * q1 + vector.y * q2 + vector.z * q3 < 0) {
+      v.scale(-1);
+      theta = -theta;
+    }
+    return theta;
+  }
+
+  /**
+   *   Quaternions are saved as {q1, q2, q3, q0} 
+   * 
+   * While this may seem odd, it is so that for any point4 -- 
+   * planes, axisangles, and quaternions -- we can use the 
+   * first three coordinates to determine the relavent axis
+   * the fourth then gives us offset to {0,0,0} (plane), 
+   * rotation angle (axisangle), and cos(theta/2) (quaternion).
+   * @return {x y z w} (unnormalized)
+   */
+  public P4 toPoint4f() {
+    return P4.new4(q1, q2, q3, q0); // x,y,z,w
+  }
+
+  public A4 toAxisAngle4f() {
+    double theta = 2 * Math.acos(Math.abs(q0));
+    double sinTheta2 = Math.sin(theta/2);
+    V3 v = getNormal();
+    if (sinTheta2 < 0) {
+      v.scale(-1);
+      theta = Math.PI - theta;
+    }
+    return A4.newVA(v, (float) theta);
+  }
+
+  public T3 transform2(T3 pt, T3 ptNew) {
+    if (mat == null)
+      setMatrix();
+    mat.rotate2(pt, ptNew);
+    return ptNew;
+  }
+
+  public Quat leftDifference(Quat q2) {
+    //dq = q.leftDifference(qnext);//q.inv().mul(qnext);
+    Quat q2adjusted = (this.dot(q2) < 0 ? q2.negate() : q2);
+    return inv().mulQ(q2adjusted);
+  }
+
+  public Quat rightDifference(Quat q2) {
+    //dq = qnext.rightDifference(q);//qnext.mul(q.inv());
+    Quat q2adjusted = (this.dot(q2) < 0 ? q2.negate() : q2);
+    return mulQ(q2adjusted.inv());
+  }
+
+  /**
+   * 
+   *  Java axisAngle / plane / Point4f format
+   *  all have the format {x y z w}
+   *  so we go with that here as well
+   *   
+   * @return  "{q1 q2 q3 q0}"
+   */
+  @Override
+  public String toString() {
+    return "{" + q1 + " " + q2 + " " + q3 + " " + q0 + "}";
+  }
+
+  /**
+   * 
+   * @param data1
+   * @param data2
+   * @param nMax     > 0 --> limit to this number
+   * @param isRelative
+   * 
+   * @return       pairwise array of data1 / data2 or data1 \ data2
+   */
+  public static Quat[] div(Quat[] data1, Quat[] data2, int nMax, boolean isRelative) {
+    int n;
+    if (data1 == null || data2 == null || (n = Math.min(data1.length, data2.length)) == 0)
+      return null;
+    if (nMax > 0 && n > nMax)
+      n = nMax;
+    Quat[] dqs = new Quat[n];
+    for (int i = 0; i < n; i++) {
+      if (data1[i] == null || data2[i] == null)
+        return null;
+      dqs[i] = (isRelative ? data1[i].divLeft(data2[i]) : data1[i].div(data2[i]));
+    }
+    return dqs;
+  }
+  
+  public static Quat sphereMean(Quat[] data, float[] retStddev, float criterion) {
+    // Samuel R. Buss, Jay P. Fillmore: 
+    // Spherical averages and applications to spherical splines and interpolation. 
+    // ACM Trans. Graph. 20(2): 95-126 (2001)
+      if (data == null || data.length == 0)
+        return new Quat();
+      if (retStddev == null)
+        retStddev = new float[1];
+      if (data.length == 1) {
+        retStddev[0] = 0;
+        return newQ(data[0]);
+      }
+      float diff = Float.MAX_VALUE;
+      float lastStddev = Float.MAX_VALUE;
+      Quat qMean = simpleAverage(data);
+      int maxIter = 100; // typically goes about 5 iterations
+      int iter = 0;
+      while (diff > criterion && lastStddev != 0 && iter < maxIter) {
+        qMean = newMean(data, qMean);
+        retStddev[0] = stdDev(data, qMean);
+        diff = Math.abs(retStddev[0] - lastStddev);
+        lastStddev = retStddev[0];
+        //Logger.info(++iter + " sphereMean " + qMean + " stddev=" + lastStddev + " diff=" + diff);
+      }
+      return qMean;
+  }
+
+  /**
+   * Just a starting point.
+   * get average normal vector
+   * scale normal by average projection of vectors onto it
+   * create quaternion from this 3D projection
+   * 
+   * @param ndata
+   * @return approximate average
+   */
+  private static Quat simpleAverage(Quat[] ndata) {
+    V3 mean = V3.new3(0, 0, 1);
+    // using the directed normal ensures that the mean is 
+    // continually added to and never subtracted from 
+    V3 v = ndata[0].getNormal();
+    mean.add(v);
+    for (int i = ndata.length; --i >= 0;)
+      mean.add(ndata[i].getNormalDirected(mean));
+    mean.sub(v);
+    mean.normalize();
+    float f = 0;
+    // the 3D projection of the quaternion is [sin(theta/2)]*n
+    // so dotted with the normalized mean gets us an approximate average for sin(theta/2)
+    for (int i = ndata.length; --i >= 0;)
+      f += Math.abs(ndata[i].get3dProjection(v).dot(mean)); 
+    if (f != 0)
+      mean.scale(f / ndata.length);
+    // now convert f to the corresponding cosine instead of sine
+    f = (float) Math.sqrt(1 - mean.lengthSquared());
+    if (Float.isNaN(f))
+      f = 0;
+    return newP4(P4.new4(mean.x, mean.y, mean.z, f));
+  }
+
+  private static Quat newMean(Quat[] data, Quat mean) {
+    /* quaternion derivatives nicely take care of producing the necessary 
+     * metric. Since dq gives us the normal with the smallest POSITIVE angle, 
+     * we just scale by that -- using degrees.
+     * No special normalization is required.
+     * 
+     * The key is that the mean has been set up already, and dq.getTheta()
+     * will always return a value between 0 and 180. True, for groupings
+     * where dq swings wildly -- 178, 182, 178, for example -- there will
+     * be problems, but the presumption here is that there is a REASONABLE
+     * set of data. Clearly there are spherical data sets that simply cannot
+     * be assigned a mean. (For example, where the three projected points
+     * are equally distant on the sphere. We just can't worry about those
+     * cases here. Rather, if there is any significance to the data,
+     * there will be clusters of projected points, and the analysis will
+     * be meaningful.
+     * 
+     * Note that the hemisphere problem drops out because dq.getNormal() and
+     * dq.getTheta() will never return (n, 182 degrees) but will 
+     * instead return (-n, 2 degrees). That's just what we want in that case.
+     *
+     *  Note that the projection in this case is to 3D -- a set of vectors
+     *  in space with lengths proportional to theta (not the sin(theta/2) 
+     *  that is associated with a quaternion map).
+     *  
+     *  This is officially an "exponential" or "hyperbolic" projection.
+     *  
+     */
+    V3 sum = new V3();
+    V3 v;
+    Quat q, dq;
+    //System.out.println("newMean mean " + mean);
+    for (int i = data.length; --i >= 0;) {
+      q = data[i];
+      dq = q.div(mean);
+      v = dq.getNormal();
+      v.scale(dq.getTheta());
+      sum.add(v);
+    }
+    sum.scale(1f/data.length);
+    Quat dqMean = newVA(sum, sum.length());
+    //System.out.println("newMean dqMean " + dqMean + " " + dqMean.getNormal() + " " + dqMean.getTheta());
+    return dqMean.mulQ(mean);
+  }
+
+  /**
+   * @param data
+   * @param mean
+   * @return     standard deviation in units of degrees
+   */
+  private static float stdDev(Quat[] data, Quat mean) {
+    // the quaternion dot product gives q0 for dq (i.e. q / mean)
+    // that is, cos(theta/2) for theta between them
+    double sum2 = 0;
+    int n = data.length;
+    for (int i = n; --i >= 0;) {
+      float theta = data[i].div(mean).getTheta(); 
+      sum2 += theta * theta;
+    }
+    return (float) Math.sqrt(sum2 / n);
+  }
+
+  public float[] getEulerZYZ() {
+    // http://www.swarthmore.edu/NatSci/mzucker1/e27/diebel2006attitude.pdf
+    double rA, rB, rG;
+    if (q1 == 0 && q2 == 0) {
+      float theta = getTheta();
+      // pure Z rotation - ambiguous
+      return new float[] { q3 < 0 ? -theta : theta , 0, 0 };
+    }
+    rA = Math.atan2(2 * (q2 * q3 + q0 * q1), 2 * (-q1 * q3 + q0 * q2 ));
+    rB = Math.acos(q3 * q3 - q2 * q2 - q1 * q1 + q0 * q0);
+    rG = Math.atan2( 2 * (q2 * q3 - q0 * q1), 2 * (q0 * q2 + q1 * q3));
+    return new float[]  {(float) (rA / RAD_PER_DEG), (float) (rB / RAD_PER_DEG), (float) (rG / RAD_PER_DEG)};
+  } 
+
+  public float[] getEulerZXZ() {
+    // NOT http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles
+    // http://www.swarthmore.edu/NatSci/mzucker1/e27/diebel2006attitude.pdf
+    double rA, rB, rG;
+    if (q1 == 0 && q2 == 0) {
+      float theta = getTheta();
+      // pure Z rotation - ambiguous
+      return new float[] { q3 < 0 ? -theta : theta , 0, 0 };
+    }
+    rA = Math.atan2(2 * (q1 * q3 - q0 * q2), 2 * (q0 * q1 + q2 * q3 ));
+    rB = Math.acos(q3 * q3 - q2 * q2 - q1 * q1 + q0 * q0);
+    rG = Math.atan2( 2 * (q1 * q3 + q0 * q2), 2 * (-q2 * q3 + q0 * q1));
+    return new float[]  {(float) (rA / RAD_PER_DEG), (float) (rB / RAD_PER_DEG), (float) (rG / RAD_PER_DEG)};
+  }
+
+}
diff --git a/src/javajs/util/Rdr.java b/src/javajs/util/Rdr.java
new file mode 100644 (file)
index 0000000..5296964
--- /dev/null
@@ -0,0 +1,509 @@
+/* $RCSfile$
+ * $Author: hansonr $
+ * $Date: 2007-04-05 09:07:28 -0500 (Thu, 05 Apr 2007) $
+ * $Revision: 7326 $
+ *
+ * Copyright (C) 2003-2005  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+package javajs.util;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+
+import java.util.Map;
+
+
+import javajs.api.GenericCifDataParser;
+import javajs.api.GenericLineReader;
+import javajs.api.GenericZipTools;
+
+/**
+ * A general helper class for a variety of stream and reader functionality
+ * including:
+ * 
+ *  stream and byte magic-number decoding for PNG, PNGJ, ZIP, and GZIP streams
+ *  
+ *  various stream/reader methods, including UTF-encoded stream reading
+ *  
+ *  reflection-protected access to a CIF parser and ZIP tools
+ *  
+ *   
+ * 
+ * 
+ */
+public class Rdr implements GenericLineReader {
+
+  BufferedReader reader;
+
+  public Rdr(BufferedReader reader) {
+    this.reader = reader;
+  }
+  
+  @Override
+  public String readNextLine() throws Exception {
+    return reader.readLine();
+  }
+
+  public static Map<String, Object> readCifData(GenericCifDataParser parser, BufferedReader br) {
+    return parser.set(null, br).getAllCifData();
+  }
+  
+  
+  ///////////
+  
+  public static String fixUTF(byte[] bytes) {    
+    Encoding encoding = getUTFEncoding(bytes);
+    if (encoding != Encoding.NONE)
+    try {
+      String s = new String(bytes, encoding.name().replace('_', '-'));
+      switch (encoding) {
+      case UTF8:
+      case UTF_16BE:
+      case UTF_16LE:
+        // extra byte at beginning removed
+        s = s.substring(1);
+        break;
+      default:
+        break;        
+      }
+      return s;
+    } catch (UnsupportedEncodingException e) {
+      System.out.println(e);
+    }
+    return new String(bytes);
+  }
+
+  private static Encoding getUTFEncoding(byte[] bytes) {
+    if (bytes.length >= 3 && bytes[0] == (byte) 0xEF && bytes[1] == (byte) 0xBB && bytes[2] == (byte) 0xBF)
+      return Encoding.UTF8;
+    if (bytes.length >= 4 && bytes[0] == (byte) 0 && bytes[1] == (byte) 0 
+        && bytes[2] == (byte) 0xFE && bytes[3] == (byte) 0xFF)
+      return Encoding.UTF_32BE;
+    if (bytes.length >= 4 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE 
+        && bytes[2] == (byte) 0 && bytes[3] == (byte) 0)
+      return Encoding.UTF_32LE;
+    if (bytes.length >= 2 && bytes[0] == (byte) 0xFF && bytes[1] == (byte) 0xFE)
+      return Encoding.UTF_16LE;
+    if (bytes.length >= 2 && bytes[0] == (byte) 0xFE && bytes[1] == (byte) 0xFF)
+      return Encoding.UTF_16BE;
+    return Encoding.NONE;
+  
+  }
+  
+  ////////// stream type checking //////////
+  
+
+  private static Encoding getUTFEncodingForStream(BufferedInputStream is) throws IOException {
+    /**
+     * @j2sNative
+     * 
+     *  is.resetStream();
+     * 
+     */
+    {
+    }
+    byte[] abMagic = new byte[4];
+    abMagic[3] = 1;
+    try{
+    is.mark(5);
+    } catch (Exception e) {
+      return Encoding.NONE;
+    }
+    is.read(abMagic, 0, 4);
+    is.reset();
+    return getUTFEncoding(abMagic);
+  }
+
+  public static boolean isBase64(SB sb) {
+    return (sb.indexOf(";base64,") == 0);
+  }
+
+  public static boolean isCompoundDocumentS(InputStream is) {
+    return isCompoundDocumentB(getMagic(is, 8));
+  }
+
+  public static boolean isCompoundDocumentB(byte[] bytes) {
+    return (bytes.length >= 8 && bytes[0] == (byte) 0xD0
+        && bytes[1] == (byte) 0xCF && bytes[2] == (byte) 0x11
+        && bytes[3] == (byte) 0xE0 && bytes[4] == (byte) 0xA1
+        && bytes[5] == (byte) 0xB1 && bytes[6] == (byte) 0x1A 
+        && bytes[7] == (byte) 0xE1);
+  }
+
+  public static boolean isGzipS(InputStream is) {
+    return isGzipB(getMagic(is, 2));
+  }
+
+  public static boolean isGzipB(byte[] bytes) {    
+      return (bytes != null && bytes.length >= 2 
+          && bytes[0] == (byte) 0x1F && bytes[1] == (byte) 0x8B);
+  }
+
+  public static boolean isPickleS(InputStream is) {
+    return Rdr.isPickleB(getMagic(is, 2));
+  }
+
+  public static boolean isPickleB(byte[] bytes) {    
+      return (bytes != null && bytes.length >= 2 
+          && bytes[0] == (byte) 0x7D && bytes[1] == (byte) 0x71);
+  }
+
+  public static boolean isPngZipStream(InputStream is) {
+    return isPngZipB(getMagic(is, 55));
+  }
+
+  public static boolean isPngZipB(byte[] bytes) {
+    // \0PNGJ starting at byte 50
+    return (bytes[50] == 0 && bytes[51] == 0x50 && bytes[52] == 0x4E && bytes[53] == 0x47 && bytes[54] == 0x4A);
+  }
+
+  public static boolean isZipS(InputStream is) {
+    return isZipB(getMagic(is, 4));
+  }
+
+  public static boolean isZipB(byte[] bytes) {
+    return (bytes.length >= 4 
+        && bytes[0] == 0x50  //PK<03><04> 
+        && bytes[1] == 0x4B
+        && bytes[2] == 0x03 
+        && bytes[3] == 0x04);
+  }
+
+  private static byte[] getMagic(InputStream is, int n) {
+    byte[] abMagic = new byte[n];
+    /**
+     * @j2sNative
+     * 
+     * is.resetStream();
+     * 
+     */
+    {
+    }
+    try {
+      is.mark(n + 1);
+      is.read(abMagic, 0, n);
+    } catch (IOException e) {
+    }
+    try {
+      is.reset();
+    } catch (IOException e) {
+    }
+    return abMagic;
+  }
+
+  public static String guessMimeTypeForBytes(byte[] bytes) {
+     // only options here are JPEG, PNG, GIF, and BMP
+    switch (bytes.length < 2 ? -1 : bytes[1]) {
+    case 0:
+      return "image/jpg"; // 0xFF 0x00 ...
+    case 0x49:
+      return "image/gif"; // GIF89a...
+    case 0x4D:
+      return "image/BMP"; // BM...
+    case 0x50:
+      return "image/png";
+    default:
+      return  "image/unknown";
+    }
+  }
+
+
+  ////////// stream/byte methods ///////////
+  
+  public static BufferedInputStream getBIS(byte[] bytes) {
+    return new BufferedInputStream(new ByteArrayInputStream(bytes));
+  }
+
+  public static BufferedReader getBR(String string) {
+    return new BufferedReader(new StringReader(string));
+  }
+
+  /**
+   * Drill down into a GZIP stack until no more layers.
+   * @param jzt 
+   * 
+   * @param bis
+   * @return non-gzipped buffered input stream.
+   * 
+   * @throws IOException
+   */
+  public static BufferedInputStream getUnzippedInputStream(GenericZipTools jzt, BufferedInputStream bis) throws IOException {
+    while (isGzipS(bis))
+      bis = new BufferedInputStream(jzt.newGZIPInputStream(bis));
+    return bis;
+  }
+
+  /**
+   * Allow for base64-encoding check.
+   * 
+   * @param sb
+   * @return byte array
+   */
+  public static byte[] getBytesFromSB(SB sb) {
+    return (isBase64(sb) ? Base64.decodeBase64(sb.substring(8)) : sb.toBytes(0, -1));    
+  }
+
+ /**
+   * Read a an entire BufferedInputStream for its bytes, and 
+   * either return them or leave them in the designated output channel.
+   *  
+   * @param bis
+   * @param out a destination output channel, or null
+   * @return byte[] (if out is null) or a message indicating length (if not)
+   * 
+   * @throws IOException
+   */
+  public static Object getStreamAsBytes(BufferedInputStream bis,
+                                         OC out) throws IOException {
+    byte[] buf = new byte[1024];
+    byte[] bytes = (out == null ? new byte[4096] : null);
+    int len = 0;
+    int totalLen = 0;
+    while ((len = bis.read(buf, 0, 1024)) > 0) {
+      totalLen += len;
+      if (out == null) {
+        if (totalLen >= bytes.length)
+          bytes = AU.ensureLengthByte(bytes, totalLen * 2);
+        System.arraycopy(buf, 0, bytes, totalLen - len, len);
+      } else {
+        out.write(buf, 0, len);
+      }
+    }
+    bis.close();
+    if (out == null) {
+      return AU.arrayCopyByte(bytes, totalLen);
+    }
+    return totalLen + " bytes";
+  }
+
+  /**
+   * Read an input stream fully, saving a byte array, then
+   * return a buffered reader to those bytes converted to string form.
+   * 
+   * @param bis
+   * @param charSet
+   * @return Reader
+   * @throws IOException
+   */
+  public static BufferedReader getBufferedReader(BufferedInputStream bis, String charSet)
+      throws IOException {
+    // could also just make sure we have a buffered input stream here.
+    if (getUTFEncodingForStream(bis) == Encoding.NONE)
+      return new BufferedReader(new InputStreamReader(bis, (charSet == null ? "UTF-8" : charSet)));
+    byte[] bytes = getLimitedStreamBytes(bis, -1);
+    bis.close();
+    return getBR(charSet == null ? fixUTF(bytes) : new String(bytes, charSet));
+  }
+
+  /**
+   * Read a possibly limited number of bytes (when n > 0) from a stream, 
+   * leaving the stream open.
+   * 
+   * @param is an input stream, not necessarily buffered.
+   * @param n the maximum number of bytes to read, or -1 for all
+   * @return the bytes read
+   * 
+   * @throws IOException
+   */
+  public static byte[] getLimitedStreamBytes(InputStream is, long n)
+      throws IOException {
+
+    //Note: You cannot use InputStream.available() to reliably read
+    //      zip data from the web. 
+
+    int buflen = (n > 0 && n < 1024 ? (int) n : 1024);
+    byte[] buf = new byte[buflen];
+    byte[] bytes = new byte[n < 0 ? 4096 : (int) n];
+    int len = 0;
+    int totalLen = 0;
+    if (n < 0)
+      n = Integer.MAX_VALUE;
+    while (totalLen < n && (len = is.read(buf, 0, buflen)) > 0) {
+      totalLen += len;
+      if (totalLen > bytes.length)
+        bytes = AU.ensureLengthByte(bytes, totalLen * 2);
+      System.arraycopy(buf, 0, bytes, totalLen - len, len);
+      if (n != Integer.MAX_VALUE && totalLen + buflen > bytes.length)
+        buflen = bytes.length - totalLen;
+
+    }
+    if (totalLen == bytes.length)
+      return bytes;
+    buf = new byte[totalLen];
+    System.arraycopy(bytes, 0, buf, 0, totalLen);
+    return buf;
+  }
+
+  /**
+   * 
+   * Read a UTF-8 stream fully, converting it to a String.
+   * Called by Jmol's XMLReaders
+   * 
+   * @param bis
+   * @return a UTF-8 string
+   */
+  public static String StreamToUTF8String(BufferedInputStream bis) {
+    String[] data = new String[1];
+    try {
+      readAllAsString(getBufferedReader(bis, "UTF-8"), -1, true, data, 0);
+    } catch (IOException e) {
+    }
+    return data[0];
+  }
+
+  /**
+   * This method fills data[i] with string data from a file that may or may not
+   * be binary even though it is being read by a reader. It is meant to be used
+   * simple text-based files only.
+   *  
+   * @param br
+   * @param nBytesMax
+   * @param allowBinary
+   * @param data
+   * @param i
+   * @return true if data[i] holds the data; false if data[i] holds an error message. 
+   */
+  public static boolean readAllAsString(BufferedReader br, int nBytesMax, boolean allowBinary, String[] data, int i) {
+    try {
+      SB sb = SB.newN(8192);
+      String line;
+      if (nBytesMax < 0) {
+        line = br.readLine();
+        if (allowBinary || line != null && line.indexOf('\0') < 0
+            && (line.length() != 4 || line.charAt(0) != 65533
+            || line.indexOf("PNG") != 1)) {
+          sb.append(line).appendC('\n');
+          while ((line = br.readLine()) != null)
+            sb.append(line).appendC('\n');
+        }
+      } else {
+        int n = 0;
+        int len;
+        while (n < nBytesMax && (line = br.readLine()) != null) {
+          if (nBytesMax - n < (len = line.length()) + 1)
+            line = line.substring(0, nBytesMax - n - 1);
+          sb.append(line).appendC('\n');
+          n += len + 1;
+        }
+      }
+      br.close();
+      data[i] = sb.toString();
+      return true;
+    } catch (Exception ioe) {
+      data[i] = ioe.toString();
+      return false;
+    }
+  }
+
+  
+  /////////// PNGJ support /////////////
+  
+  
+  /**
+   * Look at byte 50 for "\0PNGJxxxxxxxxx+yyyyyyyyy" where xxxxxxxxx is a byte
+   * offset to the JMOL data and yyyyyyyyy is the length of the data.
+   * 
+   * @param bis
+   * @return same stream or byte stream
+   */
+
+  /**
+   * Retrieve the two numbers in a PNG iTXt tag indicating the 
+   * file pointer for the start of the ZIP data as well as its length.
+   * 
+   * @param bis
+   * @param pt_count
+   */
+  static void getPngZipPointAndCount(BufferedInputStream bis, int[] pt_count) {
+    bis.mark(75);
+    try {
+      byte[] data = getLimitedStreamBytes(bis, 74);
+      bis.reset();
+      int pt = 0;
+      for (int i = 64, f = 1; --i > 54; f *= 10)
+        pt += (data[i] - '0') * f;
+      int n = 0;
+      for (int i = 74, f = 1; --i > 64; f *= 10)
+        n += (data[i] - '0') * f;
+      pt_count[0] = pt;
+      pt_count[1] = n;
+    } catch (Throwable e) {
+      pt_count[1] = 0;
+    }
+  }
+
+  /**
+   * Either advance a PNGJ stream to its zip file data or pull out the ZIP data
+   * bytes and create a new stream for them from which a ZIP utility can start
+   * extracting files.
+   * 
+   * @param bis
+   * @param asNewStream  
+   * @return new buffered ByteArrayInputStream, possibly with no data if there is an error
+   */
+  public static BufferedInputStream getPngZipStream(BufferedInputStream bis, boolean asNewStream) {
+    if (!isPngZipStream(bis))
+      return bis;
+    byte[] data = new byte[0];
+    bis.mark(75);
+    try {
+      int pt_count[] = new int[2];
+      getPngZipPointAndCount(bis, pt_count);
+      if (pt_count[1] != 0) {
+        int pt = pt_count[0];
+        while (pt > 0)
+          pt -= bis.skip(pt);
+        if (!asNewStream)
+          return bis;
+        data = getLimitedStreamBytes(bis, pt_count[1]);
+      }
+    } catch (Throwable e) {
+    } finally {
+      try {
+        if (asNewStream)
+          bis.close();
+      } catch (Exception e) {
+        // ignore
+      }
+    }
+    return getBIS(data);
+  }
+
+  /** We define a request for zip file extraction by vertical bar:
+   *  zipName|interiorFileName. These may be nested if there is a
+   *  zip file contained in a zip file. 
+   *  
+   * @param fileName
+   * @return filename trimmed of interior fileName
+   * 
+   */
+  public static String getZipRoot(String fileName) {
+    int pt = fileName.indexOf("|");
+    return (pt < 0 ? fileName : fileName.substring(0, pt));
+  }
+
+  
+}
+
diff --git a/src/javajs/util/SB.java b/src/javajs/util/SB.java
new file mode 100644 (file)
index 0000000..2b9efa6
--- /dev/null
@@ -0,0 +1,342 @@
+
+package javajs.util;
+
+import javajs.J2SIgnoreImport;
+
+/**
+ * Interesting thing here is that JavaScript is 3x faster than Java in handling strings.
+ * 
+ * Java StringBuilder is final, unfortunately. I guess they weren't thinking about Java2Script!
+ * 
+ * The reason we have to do this that several overloaded append methods is WAY too expensive
+ * 
+ */
+
+@J2SIgnoreImport({java.lang.StringBuilder.class})
+public class SB {
+  
+  private java.lang.StringBuilder sb;
+  String s; // used by JavaScript only; no Java references
+  
+  //TODO: JS experiment with using array and .push() here
+
+  public SB() {
+    /**
+     * @j2sNative
+     * 
+     *            this.s = "";
+     * 
+     */
+    {
+      sb = new java.lang.StringBuilder();
+    }
+  }
+
+  public static SB newN(int n) {
+    /**
+     * @j2sNative
+     *            return new javajs.util.SB(); 
+     */
+    {
+      // not perfect, because it requires defining sb twice. 
+      // We can do better...
+      SB sb = new SB();
+      sb.sb = new java.lang.StringBuilder(n);
+      return sb;
+    }
+  }
+
+  public static SB newS(String s) {
+    /**
+     * @j2sNative 
+     * 
+     * var sb = new javajs.util.SB();
+     * sb.s = s;
+     * return sb; 
+     * 
+     */
+    {
+    SB sb = new SB();
+    sb.sb = new java.lang.StringBuilder(s);
+    return sb;
+    }
+  }
+
+  public SB append(String s) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s += s
+     * 
+     */
+    {
+      sb.append(s);
+    }
+    return this;
+  }
+  
+  public SB appendC(char c) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s += c;
+     */
+    {
+      sb.append(c);
+    }
+    return this;
+    
+  }
+
+  public SB appendI(int i) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s += i
+     * 
+     */
+    {
+      sb.append(i);
+    }
+    return this;
+  }
+
+  public SB appendB(boolean b) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s += b
+     * 
+     */
+    {
+      sb.append(b);
+    }
+    return this;
+  }
+
+  /**
+   * note that JavaScript could drop off the ".0" in "1.0"
+   * @param f
+   * @return this
+   */
+  public SB appendF(float f) {
+    /**
+     * @j2sNative
+     * 
+     * var sf = "" + f;
+     * if (sf.indexOf(".") < 0 && sf.indexOf("e") < 0)
+     *   sf += ".0" ;
+     *            this.s += sf;
+     * 
+     */
+    {
+      sb.append(f);
+    }
+    return this;
+  }
+
+  public SB appendD(double d) {
+    /**
+     * @j2sNative
+     * 
+     * var sf = "" + d;
+     * if (sf.indexOf(".") < 0 && sf.indexOf("e") < 0)
+     *   sf += ".0" ;
+     *            this.s += sf;
+     * 
+     */
+    {
+      sb.append(d);
+    }
+    return this;
+  }
+
+  public SB appendSB(SB buf) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s += buf.s;
+     * 
+     */
+    {
+      sb.append(buf.sb);
+    }
+    return this;
+  }
+
+  public SB appendO(Object data) {
+    if (data != null) {
+      /**
+       * @j2sNative
+       * 
+       *            this.s += data.toString();
+       * 
+       */
+      {
+        sb.append(data);
+      }
+    }
+    return this;
+  }
+
+  public void appendCB(char[] cb, int off, int len) {
+    /**
+     * @j2sNative
+     * 
+     * for (var i = len,j=off; --i >= 0;)
+     *            this.s += cb[j++];
+     * 
+     */
+    {
+       sb.append(cb, off, len);
+    }
+  }
+
+  @Override
+  public String toString() {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s;
+     * 
+     */
+    {
+      return sb.toString();
+    }
+  }
+
+  public int length() {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.length;
+     * 
+     */
+    {
+      return sb.length();
+    }
+  }
+
+  public int indexOf(String s) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.indexOf(s);
+     * 
+     */
+    {
+      return sb.indexOf(s);
+    }
+  }
+
+  public char charAt(int i) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.charAt(i);
+     * 
+     */
+    {
+      return sb.charAt(i);
+    }
+  }
+
+  public int charCodeAt(int i) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.charCodeAt(i);
+     * 
+     */
+    {
+      return sb.codePointAt(i);
+    }
+  }
+
+  public void setLength(int n) {
+    /**
+     * @j2sNative
+     * 
+     *            this.s = this.s.substring(0, n);
+     */
+    {
+      sb.setLength(n);
+    }
+  }
+
+  public int lastIndexOf(String s) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.lastIndexOf(s);
+     */
+    {
+      return sb.lastIndexOf(s);
+    }
+  }
+
+  public int indexOf2(String s, int i) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.indexOf(s, i);
+     */
+    {
+      return sb.indexOf(s, i);
+    }
+  }
+
+  public String substring(int i) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.substring(i);
+     */
+    {
+      return sb.substring(i);
+    }
+  }
+
+  public String substring2(int i, int j) {
+    /**
+     * @j2sNative
+     * 
+     *            return this.s.substring(i, j);
+     */
+    {
+      return sb.substring(i, j);
+    }
+  }
+
+  /**
+   * simple byte conversion not allowing for unicode.
+   * Used for base64 conversion and allows for offset
+   * @param off 
+   * @param len or -1 for full length (then off must = 0)
+   * @return byte[]
+   */
+  public byte[] toBytes(int off, int len) {
+    if (len < 0)
+      len = length() - off;
+    byte[] b = new byte[len];
+    for (int i = off + len, j = i - off; --i >= off;)
+      b[--j] = (byte) charAt(i);
+    return b;
+  }
+
+       public void replace(int start, int end, String str) {
+               /**
+                * @j2sNative
+                * 
+                * this.s = this.s.substring(0, start) + str + this.s.substring(end);
+                */
+               {
+                       sb.replace(start, end, str);
+               }
+       }
+
+       public void insert(int offset, String str) {
+               replace(offset, offset, str);
+       }
+
+}
diff --git a/src/javajs/util/StringDataReader.java b/src/javajs/util/StringDataReader.java
new file mode 100644 (file)
index 0000000..32e87e1
--- /dev/null
@@ -0,0 +1,48 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2011  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+import java.io.StringReader;
+
+
+
+
+
+public class StringDataReader extends DataReader {
+
+  public StringDataReader() {
+    super();
+  }
+  
+  public StringDataReader(String data) {
+    super(new StringReader(data));
+  }
+
+  @Override
+  public DataReader setData(Object data) {
+    return new StringDataReader((String) data);
+  }
+}
\ No newline at end of file
diff --git a/src/javajs/util/T3.java b/src/javajs/util/T3.java
new file mode 100644 (file)
index 0000000..4412565
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+import java.io.Serializable;
+
+import javajs.api.JSONEncodable;
+
+/**
+ * A generic 3 element tuple that is represented by single precision floating
+ * point x,y and z coordinates.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.10 $, $Date:
+ *          2006/09/08 20:20:20 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public abstract class T3 implements JSONEncodable, Serializable {
+
+  public float x, y, z;
+
+  /**
+   * @j2sIgnore
+   * 
+   */
+  public T3() {
+  }
+
+  /**
+   * Sets the value of this tuple to the specified xyz coordinates.
+   * 
+   * @param x
+   *        the x coordinate
+   * @param y
+   *        the y coordinate
+   * @param z
+   *        the z coordinate
+   */
+  public final void set(float x, float y, float z) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+  }
+
+  /**
+   * Sets the value of this tuple from the 3 values specified in the array.
+   * 
+   * @param t
+   *        the array of length 3 containing xyz in order
+   */
+  public final void setA(float t[]) {
+    // ArrayIndexOutOfBounds is thrown if t.length < 3
+    x = t[0];
+    y = t[1];
+    z = t[2];
+  }
+
+  /**
+   * Sets the value of this tuple to the value of the Tuple3f argument.
+   * 
+   * @param t1
+   *        the tuple to be copied
+   */
+  public final void setT(T3 t1) {
+    x = t1.x;
+    y = t1.y;
+    z = t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector sum of tuples t1 and t2.
+   * 
+   * @param t1
+   *        the first tuple
+   * @param t2
+   *        the second tuple
+   */
+  public final void add2(T3 t1, T3 t2) {
+    x = t1.x + t2.x;
+    y = t1.y + t2.y;
+    z = t1.z + t2.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector sum of itself and tuple t1.
+   * 
+   * @param t1
+   *        the other tuple
+   */
+  public final void add(T3 t1) {
+    x += t1.x;
+    y += t1.y;
+    z += t1.z;
+  }
+
+  /**
+   * Computes the square of the distance between this point and point p1.
+   * 
+   * @param p1
+   *        the other point
+   * @return the square of distance between these two points as a float
+   */
+  public final float distanceSquared(T3 p1) {
+    double dx = x - p1.x;
+    double dy = y - p1.y;
+    double dz = z - p1.z;
+    return (float) (dx * dx + dy * dy + dz * dz);
+  }
+
+  /**
+   * Returns the distance between this point and point p1.
+   * 
+   * @param p1
+   *        the other point
+   * @return the distance between these two points
+   */
+  public final float distance(T3 p1) {
+    return (float) Math.sqrt(distanceSquared(p1));
+  }
+
+  /**
+   * Sets the value of this tuple to the vector difference of tuple t1 and t2
+   * (this = t1 - t2).
+   * 
+   * @param t1
+   *        the first tuple
+   * @param t2
+   *        the second tuple
+   */
+  public final void sub2(T3 t1, T3 t2) {
+    x = t1.x - t2.x;
+    y = t1.y - t2.y;
+    z = t1.z - t2.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector difference of itself and tuple
+   * t1 (this = this - t1).
+   * 
+   * @param t1
+   *        the other tuple
+   */
+  public final void sub(T3 t1) {
+    x -= t1.x;
+    y -= t1.y;
+    z -= t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the scalar multiplication of itself.
+   * 
+   * @param s
+   *        the scalar value
+   */
+  public final void scale(float s) {
+    x *= s;
+    y *= s;
+    z *= s;
+  }
+
+  /**
+   * Add {a b c}
+   * 
+   * @param a
+   * @param b
+   * @param c
+   */
+  public final void add3(float a, float b, float c) {
+    x += a;
+    y += b;
+    z += c;
+  }
+
+  
+  /**
+   * {x*p.x, y*p.y, z*p.z)  used for three-way scaling
+   * 
+   * @param p
+   */
+  public final void scaleT(T3 p) {
+    x *= p.x;
+    y *= p.y;
+    z *= p.z;
+  }
+
+  
+  /**
+   * Sets the value of this tuple to the scalar multiplication of tuple t1 and
+   * then adds tuple t2 (this = s*t1 + t2).
+   * 
+   * @param s
+   *        the scalar value
+   * @param t1
+   *        the tuple to be multipled
+   * @param t2
+   *        the tuple to be added
+   */
+  public final void scaleAdd2(float s, T3 t1, T3 t2) {
+    x = s * t1.x + t2.x;
+    y = s * t1.y + t2.y;
+    z = s * t1.z + t2.z;
+  }
+
+  
+  /**
+   * average of two tuples
+   * 
+   * @param a
+   * @param b
+   */
+  public void ave(T3 a, T3 b) {
+    x = (a.x + b.x) / 2f;
+    y = (a.y + b.y) / 2f;
+    z = (a.z + b.z) / 2f; 
+  }
+
+  /**
+   * Vector dot product. Was in Vector3f; more useful here, though.
+   * 
+   * @param v
+   *        the other vector
+   * @return this.dot.v
+   */
+  public final float dot(T3 v) {
+    return x * v.x + y * v.y + z * v.z;
+  }
+
+  /**
+   * Returns the squared length of this vector.
+   * Was in Vector3f; more useful here, though.
+   * 
+   * @return the squared length of this vector
+   */
+  public final float lengthSquared() {
+    return x * x + y * y + z * z;
+  }
+
+  /**
+   * Returns the length of this vector.
+   * Was in Vector3f; more useful here, though.
+   * 
+   * @return the length of this vector
+   */
+  public final float length() {
+    return (float) Math.sqrt(lengthSquared());
+  }
+
+  /**
+   * Normalizes this vector in place.
+   * Was in Vector3f; more useful here, though.
+   */
+  public final void normalize() {
+    double d = length();
+
+    // zero-div may occur.
+    x /= d;
+    y /= d;
+    z /= d;
+  }
+
+  /**
+   * Sets this tuple to be the vector cross product of vectors v1 and v2.
+   * 
+   * @param v1
+   *        the first vector
+   * @param v2
+   *        the second vector
+   */
+  public final void cross(T3 v1, T3 v2) {
+    set(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y
+        - v1.y * v2.x);
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Tuple3f objects with identical data values (ie, returns true for
+   * equals(Tuple3f) ) will return the same hash number. Two vectors with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   */
+  @Override
+  public int hashCode() {
+    long bits = 1L;
+    bits = 31L * bits + floatToIntBits0(x);
+    bits = 31L * bits + floatToIntBits0(y);
+    bits = 31L * bits + floatToIntBits0(z);
+    return (int) (bits ^ (bits >> 32));
+  }
+
+  public static int floatToIntBits0(float f) {
+    return (f == 0 ? 0 : Float.floatToIntBits(f));
+  }
+
+  /**
+   * Returns true if all of the data members of Tuple3f t1 are equal to the
+   * corresponding data members in this
+   * 
+   * @param t1
+   *        the vector with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object t1) {
+    if (!(t1 instanceof T3))
+      return false;
+    T3 t2 = (T3) t1;
+    return (x == t2.x && y == t2.y && z == t2.z);
+  }
+
+  /**
+   * Returns a string that contains the values of this Tuple3f. The form is
+   * (x,y,z).
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "{" + x + ", " + y + ", " + z + "}";
+  }
+  
+  @Override
+  public String toJSON() {
+    return "[" + x + "," + y + "," + z + "]";
+  }
+}
diff --git a/src/javajs/util/T3d.java b/src/javajs/util/T3d.java
new file mode 100644 (file)
index 0000000..08d02d7
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+import java.io.Serializable;
+
+/**
+ * A generic 3 element tuple that is represented by double precision floating
+ * point x,y and z coordinates.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public abstract class T3d implements Serializable {
+  /**
+   * The x coordinate.
+   */
+  public double x;
+
+  /**
+   * The y coordinate.
+   */
+  public double y;
+
+  /**
+   * The z coordinate.
+   */
+  public double z;
+
+  /**
+   * Constructs and initializes a Tuple3d to (0,0,0).
+   */
+  public T3d() {
+  }
+
+  /**
+   * Sets the value of this tuple to the specified xyz coordinates.
+   * 
+   * @param x
+   *        the x coordinate
+   * @param y
+   *        the y coordinate
+   * @param z
+   *        the z coordinate
+   */
+  public final void set(double x, double y, double z) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+  }
+
+  /**
+   * Sets the value of this tuple from the 3 values specified in the array.
+   * 
+   * @param t
+   *        the array of length 3 containing xyz in order
+   */
+  public final void setA(double t[]) {
+    // ArrayIndexOutOfBounds is thrown if t.length < 3
+    x = t[0];
+    y = t[1];
+    z = t[2];
+  }
+
+  /**
+   * Sets the value of this tuple to the value of the Tuple3d argument.
+   * 
+   * @param t1
+   *        the tuple to be copied
+   */
+  public final void setT(T3d t1) {
+    x = t1.x;
+    y = t1.y;
+    z = t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector sum of tuples t1 and t2.
+   * 
+   * @param t1
+   *        the first tuple
+   * @param t2
+   *        the second tuple
+   */
+  public final void add2(T3d t1, T3d t2) {
+    x = t1.x + t2.x;
+    y = t1.y + t2.y;
+    z = t1.z + t2.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector sum of itself and tuple t1.
+   * 
+   * @param t1
+   *        the other tuple
+   */
+  public final void add(T3d t1) {
+    x += t1.x;
+    y += t1.y;
+    z += t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector difference of tuple t1 and t2
+   * (this = t1 - t2).
+   * 
+   * @param t1
+   *        the first tuple
+   * @param t2
+   *        the second tuple
+   */
+  public final void sub2(T3d t1, T3d t2) {
+    x = t1.x - t2.x;
+    y = t1.y - t2.y;
+    z = t1.z - t2.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the vector difference of itself and tuple
+   * t1 (this = this - t1).
+   * 
+   * @param t1
+   *        the other tuple
+   */
+  public final void sub(T3d t1) {
+    x -= t1.x;
+    y -= t1.y;
+    z -= t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the scalar multiplication of itself.
+   * 
+   * @param s
+   *        the scalar value
+   */
+  public final void scale(double s) {
+    x *= s;
+    y *= s;
+    z *= s;
+  }
+
+  /**
+   * Sets the value of this tuple to the scalar multiplication of tuple t1 and
+   * then adds tuple t2 (this = s*t1 + t2).
+   * 
+   * @param s
+   *        the scalar value
+   * @param t1
+   *        the tuple to be multipled
+   * @param t2
+   *        the tuple to be added
+   */
+  public final void scaleAdd(double s, T3d t1, T3d t2) {
+    x = s * t1.x + t2.x;
+    y = s * t1.y + t2.y;
+    z = s * t1.z + t2.z;
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Tuple3d objects with identical data values (ie, returns true for
+   * equals(Tuple3d) ) will return the same hash number. Two vectors with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   */
+  @Override
+  public int hashCode() {
+    long xbits = doubleToLongBits0(x);
+    long ybits = doubleToLongBits0(y);
+    long zbits = doubleToLongBits0(z);
+    return (int) (xbits ^ (xbits >> 32) ^ ybits ^ (ybits >> 32) ^ zbits ^ (zbits >> 32));
+  }
+
+  static long doubleToLongBits0(double d) {
+    // Check for +0 or -0
+    return (d == 0 ? 0 : Double.doubleToLongBits(d));
+  }
+
+  /**
+   * Returns true if all of the data members of Tuple3d t1 are equal to the
+   * corresponding data members in this
+   * 
+   * @param t1
+   *        the vector with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object t1) {
+    if (!(t1 instanceof T3d))
+      return false;
+    T3d t2 = (T3d) t1;
+    return (this.x == t2.x && this.y == t2.y && this.z == t2.z);
+  }
+
+  /**
+   * Returns a string that contains the values of this Tuple3d. The form is
+   * (x,y,z).
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "{" + x + ", " + y + ", " + z + "}";
+  }
+
+}
diff --git a/src/javajs/util/T3i.java b/src/javajs/util/T3i.java
new file mode 100644 (file)
index 0000000..7fbd3bb
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+import java.io.Serializable;
+
+/**
+ * A 3-element tuple represented by signed integer x,y,z coordinates.
+ * 
+ * @since Java 3D 1.2
+ * @version specification 1.2, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ *         additions by Bob Hanson hansonr@stolaf.edu 9/30/2012 for unique
+ *         constructor and method names for the optimization of compiled
+ *         JavaScript using Java2Script
+ */
+public abstract class T3i implements Serializable {
+
+  /**
+   * The x coordinate.
+   */
+  public int x;
+
+  /**
+   * The y coordinate.
+   */
+  public int y;
+
+  /**
+   * The z coordinate.
+   */
+  public int z;
+
+  /**
+   * Constructs and initializes a Tuple3i to (0,0,0).
+   */
+  public T3i() {
+  }
+
+  /**
+   * Sets the value of this tuple to to the specified x, y, and z coordinates.
+   * 
+   * @param x
+   *        the x coordinate.
+   * @param y
+   *        the y coordinate.
+   * @param z
+   *        the z coordinate.
+   */
+  public final void set(int x, int y, int z) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+  }
+
+  /**
+   * Sets the value of this tuple to the value of tuple t1.
+   * 
+   * @param t1
+   *        the tuple to be copied.
+   */
+  public final void setT(T3i t1) {
+    x = t1.x;
+    y = t1.y;
+    z = t1.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the sum of itself and t1.
+   * 
+   * @param t
+   *        is the other tuple
+   */
+  public final void add(T3i t) {
+    x += t.x;
+    y += t.y;
+    z += t.z;
+  }
+
+  /**
+   * Sets the value of this tuple to the scalar multiplication of tuple t1 plus
+   * tuple t2 (this = s*t1 + t2).
+   * 
+   * @param s
+   *        the scalar value
+   * @param t1
+   *        the tuple to be multipled
+   * @param t2
+   *        the tuple to be added
+   */
+  public final void scaleAdd(int s, T3i t1, T3i t2) {
+    x = s * t1.x + t2.x;
+    y = s * t1.y + t2.y;
+    z = s * t1.z + t2.z;
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Tuple3i objects with identical data values (ie, returns true for
+   * equals(Tuple3i) ) will return the same hash number. Two vectors with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   */
+  @Override
+  public int hashCode() {
+    return x ^ y ^ z;
+  }
+
+  /**
+   * Returns true if the Object o is of type Tuple3i and all of the data members
+   * of t are equal to the corresponding data members in this Tuple3i.
+   * 
+   * @param o
+   *        the object with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof T3i))
+      return false;
+    T3i t = (T3i) o;
+    return (this.x == t.x && this.y == t.y && this.z == t.z);
+  }
+
+  /**
+   * Returns a string that contains the values of this Tuple3i. The form is
+   * (x,y,z).
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "(" + x + ", " + y + ", " + z + ")";
+  }
+
+}
diff --git a/src/javajs/util/T4.java b/src/javajs/util/T4.java
new file mode 100644 (file)
index 0000000..1309fa3
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+/**
+ * A generic 4 element tuple that is represented by single precision floating
+ * point x,y,z and w coordinates.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public abstract class T4 extends T3 {
+
+  /**
+   * The w coordinate.
+   */
+  public float w;
+
+  /**
+   * Constructs and initializes a Tuple4f to (0,0,0,0).
+   * 
+   * @j2sIgnore   * 
+   */
+  public T4() {
+  }
+
+  /**
+   * Sets the value of this tuple to the specified xyzw coordinates.
+   * 
+   * @param x
+   *        the x coordinate
+   * @param y
+   *        the y coordinate
+   * @param z
+   *        the z coordinate
+   * @param w
+   *        the w coordinate
+   */
+  public final void set4(float x, float y, float z, float w) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+    this.w = w;
+  }
+
+  /**
+   * Sets the value of this tuple to the scalar multiplication of itself.
+   * 
+   * @param s
+   *        the scalar value
+   */
+  public final void scale4(float s) {
+    scale(s);
+    w *= s;
+  }
+
+  /**
+   * Returns a hash number based on the data values in this object. Two
+   * different Tuple4f objects with identical data values (ie, returns true for
+   * equals(Tuple4f) ) will return the same hash number. Two vectors with
+   * different data members may return the same hash value, although this is not
+   * likely.
+   */
+  @Override
+  public int hashCode() {
+    return floatToIntBits0(x) ^ floatToIntBits0(y)
+        ^ floatToIntBits0(z) ^ floatToIntBits0(w);
+  }
+
+  /**
+   * Returns true if all of the data members of Object are equal to the
+   * corresponding data members in this
+   * 
+   * @param o
+   *        the vector with which the comparison is made.
+   */
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof T4))
+      return false;
+    T4 t = (T4) o;
+    return (this.x == t.x && this.y == t.y && this.z == t.z && this.w == t.w);
+  }
+
+  /**
+   * Returns a string that contains the values of this Tuple4f. The form is
+   * (x,y,z,w).
+   * 
+   * @return the String representation
+   */
+  @Override
+  public String toString() {
+    return "(" + x + ", " + y + ", " + z + ", " + w + ")";
+  }
+
+  @Override
+  public String toJSON() {
+    return "[" + x + ", " + y + ", " + z + ", " + w + "]";
+  }
+
+}
diff --git a/src/javajs/util/V3.java b/src/javajs/util/V3.java
new file mode 100644 (file)
index 0000000..12c0ce8
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 1997,1998,1999
+ Kenji Hiranabe, Eiwa System Management, Inc.
+
+ This program is free software.
+ Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+ conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+ Permission to use, copy, modify, distribute and sell this software
+ and its documentation for any purpose is hereby granted without fee,
+ provided that the above copyright notice appear in all copies and
+ that both that copyright notice and this permission notice appear
+ in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+ makes no representations about the suitability of this software for any
+ purpose.  It is provided "AS IS" with NO WARRANTY.
+ */
+package javajs.util;
+
+
+/**
+ * A 3-element vector that is represented by single precision floating point
+ * x,y,z coordinates. If this value represents a normal, then it should be
+ * normalized.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.10 $, $Date:
+ *          2006/10/03 19:52:30 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public class V3 extends T3 {
+
+  /**
+   * @j2sIgnoreSuperConstructor
+   */
+  public V3() {
+    // ignore T3
+  }
+  public static V3 newV(T3 t) {
+    return V3.new3(t.x, t.y, t.z);
+  }
+
+  public static V3 newVsub(T3 t1, T3 t2) {
+    return V3.new3(t1.x - t2.x, t1.y - t2.y,t1.z - t2.z);
+  }
+
+  public static V3 new3(float x, float y, float z) {
+    V3 v = new V3();
+    v.x = x;
+    v.y = y;
+    v.z = z;
+    return v;
+  }
+
+  /**
+   * Returns the angle in radians between this vector and the vector parameter;
+   * the return value is constrained to the range [0,PI].
+   * 
+   * @param v1
+   *        the other vector
+   * @return the angle in radians in the range [0,PI]
+   */
+  public final float angle(V3 v1) {
+    // return (double)Math.acos(dot(v1)/v1.length()/v.length());
+    // Numerically, near 0 and PI are very bad condition for acos.
+    // In 3-space, |atan2(sin,cos)| is much stable.
+
+    double xx = y * v1.z - z * v1.y;
+    double yy = z * v1.x - x * v1.z;
+    double zz = x * v1.y - y * v1.x;
+    double cross = Math.sqrt(xx * xx + yy * yy + zz * zz);
+
+    return (float) Math.abs(Math.atan2(cross, dot(v1)));
+  }
+}
diff --git a/src/javajs/util/V3d.java b/src/javajs/util/V3d.java
new file mode 100644 (file)
index 0000000..9060575
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+   Copyright (C) 1997,1998,1999
+   Kenji Hiranabe, Eiwa System Management, Inc.
+
+   This program is free software.
+   Implemented by Kenji Hiranabe(hiranabe@esm.co.jp),
+   conforming to the Java(TM) 3D API specification by Sun Microsystems.
+
+   Permission to use, copy, modify, distribute and sell this software
+   and its documentation for any purpose is hereby granted without fee,
+   provided that the above copyright notice appear in all copies and
+   that both that copyright notice and this permission notice appear
+   in supporting documentation. Kenji Hiranabe and Eiwa System Management,Inc.
+   makes no representations about the suitability of this software for any
+   purpose.  It is provided "AS IS" with NO WARRANTY.
+*/
+package javajs.util;
+
+
+
+
+/**
+ * A 3 element vector that is represented by double precision floating point
+ * x,y,z coordinates. If this value represents a normal, then it should be
+ * normalized.
+ * 
+ * @version specification 1.1, implementation $Revision: 1.9 $, $Date:
+ *          2006/07/28 17:01:32 $
+ * @author Kenji hiranabe
+ * 
+ * additions by Bob Hanson hansonr@stolaf.edu 9/30/2012
+ * for unique constructor and method names
+ * for the optimization of compiled JavaScript using Java2Script
+ */
+public class V3d extends T3d {
+
+  /**
+   * Sets this vector to be the vector cross product of vectors v1 and v2.
+   * 
+   * @param v1
+   *        the first vector
+   * @param v2
+   *        the second vector
+   */
+  public final void cross(V3d v1, V3d v2) {
+    // store on stack once for aliasing-safty
+    // i.e. safe when a.cross(a, b)
+    set(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y
+        - v1.y * v2.x);
+  }
+
+  /**
+   * Normalizes this vector in place.
+   */
+  public final void normalize() {
+    double d = length();
+
+    // zero-div may occur.
+    x /= d;
+    y /= d;
+    z /= d;
+  }
+
+  /**
+   * Computes the dot product of the this vector and vector v.
+   * 
+   * @param v
+   *        the other vector
+   * @return this.dot.v
+   */
+  public final double dot(V3d v) {
+    return x * v.x + y * v.y + z * v.z;
+  }
+
+  /**
+   * Returns the squared length of this vector.
+   * 
+   * @return the squared length of this vector
+   */
+  public final double lengthSquared() {
+    return x * x + y * y + z * z;
+  }
+
+  /**
+   * Returns the length of this vector.
+   * 
+   * @return the length of this vector
+   */
+  public final double length() {
+    return Math.sqrt(lengthSquared());
+  }
+
+}
diff --git a/src/javajs/util/XmlUtil.java b/src/javajs/util/XmlUtil.java
new file mode 100644 (file)
index 0000000..d2194cd
--- /dev/null
@@ -0,0 +1,165 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2006  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+public class XmlUtil {
+
+  public XmlUtil() {
+    // Jmol's PropertyManager class uses reflection 
+  }
+  // / simple Xml parser/generator ///
+
+  public static void openDocument(SB data) {
+    data.append("<?xml version=\"1.0\"?>\n");
+  }
+
+  public static void openTag(SB sb, String name) {
+    sb.append("<").append(name).append(">\n");
+  }
+
+  public static void openTagAttr(SB sb, String name, Object[] attributes) {
+    appendTagAll(sb, name, attributes, null, false, false);
+    sb.append("\n");
+  }
+
+  public static void closeTag(SB sb, String name) {
+    sb.append("</").append(name).append(">\n");
+  }
+
+  public static void appendTagAll(SB sb, String name,
+                               Object[] attributes, Object data,
+                               boolean isCdata, boolean doClose) {
+    String closer = ">";
+    if (name.endsWith("/")){
+      name = name.substring(0, name.length() - 1);
+      if (data == null) {
+        closer = "/>\n";
+        doClose = false;
+      }
+    }
+    sb.append("<").append(name);
+    if (attributes != null)
+      for (int i = 0; i < attributes.length; i++) {
+        Object o = attributes[i];
+        if (o == null)
+          continue;
+        if (o instanceof Object[])
+          for (int j = 0; j < ((Object[]) o).length; j+= 2)
+          appendAttrib(sb, ((Object[]) o)[j], ((Object[]) o)[j + 1]);
+        else
+          appendAttrib(sb, o, attributes[++i]);
+      }
+    sb.append(closer);
+    if (data != null) {
+      if (isCdata)
+        data = wrapCdata(data);
+      sb.appendO(data);
+    }
+    if (doClose)
+      closeTag(sb, name);
+  }
+
+  /**
+   * wrap the string as character data, with replacements for [ noted 
+   * as a list starting with * after the CDATA termination
+   * 
+   * @param data
+   * @return      wrapped text
+   */
+  public static String wrapCdata(Object data) {
+    String s = "" + data;
+    return (s.indexOf("&") < 0 && s.indexOf("<") < 0 ? (s.startsWith("\n") ? "" : "\n") + s 
+        : "<![CDATA[" + PT.rep(s, "]]>", "]]]]><![CDATA[>") + "]]>");
+  }
+  
+  /**
+   * @param s
+   * @return   unwrapped text
+   */
+  public static String unwrapCdata(String s) {
+    return (s.startsWith("<![CDATA[") && s.endsWith("]]>") ?
+        PT.rep(s.substring(9, s.length()-3),"]]]]><![CDATA[>", "]]>") : s);
+  }
+  
+  /**
+   * standard <name attr="..." attr="...">data</name>"
+   * 
+   * @param sb
+   * @param name
+   * @param attributes
+   * @param data
+   */
+  public static void appendTagObj(SB sb, String name,
+                               Object[] attributes, Object data) {
+    appendTagAll(sb, name, attributes, data, false, true);
+  }
+
+  /**
+   * standard <name>data</name>"
+   * standard <name attr="..." attr="..."></name>"
+   * 
+   * @param sb
+   * @param name
+   * @param data
+   */
+  public static void appendTag(SB sb, String name, Object data) {
+    if (data instanceof Object[])
+      appendTagAll(sb, name, (Object[]) data, null, false, true);
+    else
+      appendTagAll(sb, name, null, data, false, true);
+  }
+
+  /**
+   * <name><![CDATA[data]]></name>"
+   * 
+   * will convert ]]> to ]] >
+   * 
+   * @param sb
+   * @param name
+   * @param attributes 
+   * @param data
+   */
+  public static void appendCdata(SB sb, String name, 
+                                 Object[] attributes, String data) {
+    appendTagAll(sb, name, attributes, data, true, true);
+  }
+
+  /**
+   * 
+   * @param sb
+   * @param name
+   * @param value
+   */
+  public static void appendAttrib(SB sb, Object name, Object value) {
+    if (value == null)
+      return;
+    
+    // note: <&" are disallowed but not checked for here
+    
+    sb.append(" ").appendO(name).append("=\"").appendO(value).append("\"");
+  }
+
+}
diff --git a/src/javajs/util/ZipData.java b/src/javajs/util/ZipData.java
new file mode 100644 (file)
index 0000000..f20715f
--- /dev/null
@@ -0,0 +1,76 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2006  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+import java.io.BufferedInputStream;
+
+import javajs.api.GenericZipTools;
+
+
+
+
+public class ZipData {
+  boolean isEnabled = true;
+  byte[] buf;
+  int pt;
+  int nBytes;
+  
+  public ZipData(int nBytes) {
+    this.nBytes = nBytes;
+  }
+  
+  public int addBytes(byte[] byteBuf, int nSectorBytes, int nBytesRemaining) {
+    if (pt == 0) {
+      if (!Rdr.isGzipB(byteBuf)) {
+        isEnabled = false;
+        return -1;
+      }
+      buf = new byte[nBytesRemaining];
+    }
+    int nToAdd = Math.min(nSectorBytes, nBytesRemaining);
+    System.arraycopy(byteBuf, 0, buf, pt, nToAdd);
+    pt += nToAdd;
+    return nBytesRemaining - nToAdd;
+  }    
+
+  public void addTo(GenericZipTools jzt, SB data) {
+    data.append(getGzippedBytesAsString(jzt, buf));
+  }
+
+  static String getGzippedBytesAsString(GenericZipTools jzt, byte[] bytes) {
+    try {
+      BufferedInputStream bis = jzt.getUnGzippedInputStream(bytes);
+      String s = ZipTools.getStreamAsString(bis);
+      bis.close();
+      return s;
+    } catch (Exception e) {
+      return "";
+    }
+  }
+
+}
+
diff --git a/src/javajs/util/ZipTools.java b/src/javajs/util/ZipTools.java
new file mode 100644 (file)
index 0000000..deed8c8
--- /dev/null
@@ -0,0 +1,432 @@
+/* $RCSfile$
+ * $Author$
+ * $Date$
+ * $Revision$
+ *
+ * Copyright (C) 2006  The Jmol Development Team
+ *
+ * Contact: jmol-developers@lists.sf.net
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library 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
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+package javajs.util;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javajs.J2SIgnoreImport;
+import javajs.api.GenericZipInputStream;
+import javajs.api.GenericZipTools;
+import javajs.api.ZInputStream;
+
+import java.util.Map;
+import java.util.zip.CRC32;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+
+/**
+ * Note the JSmol/HTML5 must use its own version of java.util.zip.ZipOutputStream.
+ * 
+ */
+@J2SIgnoreImport({ java.util.zip.ZipOutputStream.class })
+public class ZipTools implements GenericZipTools {
+
+  public ZipTools() {
+    // for reflection
+  }
+  
+  @Override
+  public ZInputStream newZipInputStream(InputStream is) {
+    return newZIS(is);
+  }
+
+  @SuppressWarnings("resource")
+  private static ZInputStream newZIS(InputStream is) {
+    return (is instanceof ZInputStream ? (ZInputStream) is
+        : is instanceof BufferedInputStream ? new GenericZipInputStream(is)
+            : new GenericZipInputStream(new BufferedInputStream(is)));
+  }
+
+  /**
+   * reads a ZIP file and saves all data in a Hashtable so that the files may be
+   * organized later in a different order. Also adds a #Directory_Listing entry.
+   * 
+   * Files are bracketed by BEGIN Directory Entry and END Directory Entry lines,
+   * similar to CompoundDocument.getAllData.
+   * 
+   * @param is
+   * @param subfileList
+   * @param name0
+   *        prefix for entry listing
+   * @param binaryFileList
+   *        |-separated list of files that should be saved as xx xx xx hex byte
+   *        strings. The directory listing is appended with ":asBinaryString"
+   * @param fileData
+   */
+  @Override
+  public void getAllZipData(InputStream is, String[] subfileList,
+                                          String name0, String binaryFileList,
+                                          Map<String, String> fileData) {
+    ZipInputStream zis = (ZipInputStream) newZIS(is);
+    ZipEntry ze;
+    SB listing = new SB();
+    binaryFileList = "|" + binaryFileList + "|";
+    String prefix = PT.join(subfileList, '/', 1);
+    String prefixd = null;
+    if (prefix != null) {
+      prefixd = prefix.substring(0, prefix.indexOf("/") + 1);
+      if (prefixd.length() == 0)
+        prefixd = null;
+    }
+    try {
+      while ((ze = zis.getNextEntry()) != null) {
+        String name = ze.getName();
+        if (prefix != null && prefixd != null
+            && !(name.equals(prefix) || name.startsWith(prefixd)))
+          continue;
+        //System.out.println("ziputil: " + name);
+        listing.append(name).appendC('\n');
+        String sname = "|" + name.substring(name.lastIndexOf("/") + 1) + "|";
+        boolean asBinaryString = (binaryFileList.indexOf(sname) >= 0);
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());
+        String str;
+        if (asBinaryString) {
+          str = getBinaryStringForBytes(bytes);
+          name += ":asBinaryString";
+        } else {
+          str = Rdr.fixUTF(bytes);
+        }
+        str = "BEGIN Directory Entry " + name + "\n" + str
+            + "\nEND Directory Entry " + name + "\n";
+        fileData.put(name0 + "|" + name, str);
+      }
+    } catch (Exception e) {
+    }
+    fileData.put("#Directory_Listing", listing.toString());
+  }
+
+  private String getBinaryStringForBytes(byte[] bytes) {
+    SB ret = new SB();
+    for (int i = 0; i < bytes.length; i++)
+      ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');
+    return ret.toString();
+  }
+
+  /**
+   * iteratively drills into zip files of zip files to extract file content or
+   * zip file directory. Also works with JAR files.
+   * 
+   * Does not return "__MACOS" paths
+   * 
+   * @param bis
+   * @param list
+   * @param listPtr
+   * @param asBufferedInputStream
+   *        for Pmesh
+   * @return directory listing or subfile contents
+   */
+  @Override
+  public Object getZipFileDirectory(BufferedInputStream bis, String[] list,
+                                    int listPtr, boolean asBufferedInputStream) {
+    SB ret;
+    if (list == null || listPtr >= list.length)
+      return getZipDirectoryAsStringAndClose(bis);
+    bis = Rdr.getPngZipStream(bis, true);
+    String fileName = list[listPtr];
+    ZipInputStream zis = new ZipInputStream(bis);
+    ZipEntry ze;
+    //System.out.println("fname=" + fileName);
+    try {
+      boolean isAll = (fileName.equals("."));
+      if (isAll || fileName.lastIndexOf("/") == fileName.length() - 1) {
+        ret = new SB();
+        while ((ze = zis.getNextEntry()) != null) {
+          String name = ze.getName();
+          if (isAll || name.startsWith(fileName))
+            ret.append(name).appendC('\n');
+        }
+        String str = ret.toString();
+        return (asBufferedInputStream ? Rdr.getBIS(str.getBytes()) : str);
+      }
+      int pt = fileName.indexOf(":asBinaryString");
+      boolean asBinaryString = (pt > 0);
+      if (asBinaryString)
+        fileName = fileName.substring(0, pt);
+      fileName = fileName.replace('\\', '/');
+      while ((ze = zis.getNextEntry()) != null
+          && !fileName.equals(ze.getName())) {
+      }
+      byte[] bytes = (ze == null ? null : Rdr.getLimitedStreamBytes(zis,
+          ze.getSize()));
+      ze = null;
+      zis.close();
+      if (bytes == null)
+        return "";
+      if (Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes))
+        return getZipFileDirectory(Rdr.getBIS(bytes), list, ++listPtr,
+            asBufferedInputStream);
+      if (asBufferedInputStream)
+        return Rdr.getBIS(bytes);
+      if (asBinaryString) {
+        ret = new SB();
+        for (int i = 0; i < bytes.length; i++)
+          ret.append(Integer.toHexString(bytes[i] & 0xFF)).appendC(' ');
+        return ret.toString();
+      }
+      if (Rdr.isGzipB(bytes))
+        bytes = Rdr.getLimitedStreamBytes(getUnGzippedInputStream(bytes), -1);
+      return Rdr.fixUTF(bytes);
+    } catch (Exception e) {
+      return "";
+    }
+  }
+
+  @Override
+  public byte[] getZipFileContentsAsBytes(BufferedInputStream bis,
+                                          String[] list, int listPtr) {
+    byte[] ret = new byte[0];
+    String fileName = list[listPtr];
+    if (fileName.lastIndexOf("/") == fileName.length() - 1)
+      return ret;
+    try {
+      bis = Rdr.getPngZipStream(bis, true);
+      ZipInputStream zis = new ZipInputStream(bis);
+      ZipEntry ze;
+      while ((ze = zis.getNextEntry()) != null) {
+        if (!fileName.equals(ze.getName()))
+          continue;
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, ze.getSize());
+        return ((Rdr.isZipB(bytes) || Rdr.isPngZipB(bytes)) && ++listPtr < list.length ? getZipFileContentsAsBytes(
+            Rdr.getBIS(bytes), list, listPtr) : bytes);
+      }
+    } catch (Exception e) {
+    }
+    return ret;
+  }
+  
+  @Override
+  public String getZipDirectoryAsStringAndClose(BufferedInputStream bis) {
+    SB sb = new SB();
+    String[] s = new String[0];
+    try {
+      s = getZipDirectoryOrErrorAndClose(bis, null);
+      bis.close();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+    for (int i = 0; i < s.length; i++)
+      sb.append(s[i]).appendC('\n');
+    return sb.toString();
+  }
+
+  @Override
+  public String[] getZipDirectoryAndClose(BufferedInputStream bis,
+                                                 String manifestID) {
+    String[] s = new String[0];
+    try {
+      s = getZipDirectoryOrErrorAndClose(bis, manifestID);
+      bis.close();
+    } catch (Exception e) {
+      System.out.println(e.toString());
+    }
+    return s;
+  }
+
+  private String[] getZipDirectoryOrErrorAndClose(BufferedInputStream bis,
+                                                  String manifestID)
+      throws IOException {
+    bis = Rdr.getPngZipStream(bis, true);
+    Lst<String> v = new Lst<String>();
+    ZipInputStream zis = new ZipInputStream(bis);
+    ZipEntry ze;
+    String manifest = null;
+    while ((ze = zis.getNextEntry()) != null) {
+      String fileName = ze.getName();
+      if (manifestID != null && fileName.startsWith(manifestID))
+        manifest = getStreamAsString(zis);
+      else if (!fileName.startsWith("__MACOS")) // resource fork not nec.
+        v.addLast(fileName);
+    }
+    zis.close();
+    if (manifestID != null)
+      v.add(0, manifest == null ? "" : manifest + "\n############\n");
+    return v.toArray(new String[v.size()]);
+  }
+
+  public static String getStreamAsString(InputStream is) throws IOException {
+    return Rdr.fixUTF(Rdr.getLimitedStreamBytes(is, -1));
+  }
+
+  @Override
+  public InputStream newGZIPInputStream(InputStream is) throws IOException {
+    return new BufferedInputStream(new GZIPInputStream(is, 512));
+  }
+
+  @Override
+  public BufferedInputStream getUnGzippedInputStream(byte[] bytes) {
+    try {
+      return Rdr.getUnzippedInputStream(this, Rdr.getBIS(bytes));
+    } catch (Exception e) {
+      return null;
+    }
+  }
+
+  @Override
+  public void addZipEntry(Object zos, String fileName) throws IOException {
+    ((ZipOutputStream) zos).putNextEntry(new ZipEntry(fileName));
+  }
+
+  @Override
+  public void closeZipEntry(Object zos) throws IOException {
+    ((ZipOutputStream) zos).closeEntry();
+  }
+
+  @Override
+  public Object getZipOutputStream(Object bos) {
+    /**
+     * @j2sNative
+     * 
+     *            return javajs.api.Interface.getInterface(
+     *            "java.util.zip.ZipOutputStream").setZOS(bos);
+     * 
+     */
+    {
+      return new ZipOutputStream((OutputStream) bos);
+    }
+  }
+
+  @Override
+  public int getCrcValue(byte[] bytes) {
+    CRC32 crc = new CRC32();
+    crc.update(bytes, 0, bytes.length);
+    return (int) crc.getValue();
+  }
+
+  @Override
+  public void readFileAsMap(BufferedInputStream bis, Map<String, Object> bdata, String name) {
+    int pt = (name == null ? -1 : name.indexOf("|"));
+    name = (pt >= 0 ? name.substring(pt + 1) : null);
+    try {
+      if (Rdr.isPngZipStream(bis)) {
+        boolean isImage = "_IMAGE_".equals(name);
+        if (name == null || isImage)
+          bdata.put((isImage ? "_DATA_" : "_IMAGE_"), new BArray(getPngImageBytes(bis)));
+        if (!isImage)
+          cacheZipContents(bis, name, bdata, true);
+      } else if (Rdr.isZipS(bis)) {
+        cacheZipContents(bis, name, bdata, true);
+      } else if (name == null){
+        bdata.put("_DATA_", new BArray(Rdr.getLimitedStreamBytes(bis, -1)));
+      } else {
+        throw new IOException("ZIP file " + name + " not found");
+      }
+      bdata.put("$_BINARY_$", Boolean.TRUE);
+    } catch (IOException e) {
+      bdata.clear();
+      bdata.put("_ERROR_", e.getMessage());
+    }
+  }
+
+  @Override
+  public String cacheZipContents(BufferedInputStream bis,
+                                        String fileName,
+                                        Map<String, Object> cache, 
+                                        boolean asByteArray) {
+    ZipInputStream zis = (ZipInputStream) newZIS(bis);
+    ZipEntry ze;
+    SB listing = new SB();
+    long n = 0;
+    boolean oneFile = (asByteArray && fileName != null);
+    int pt = (oneFile ? fileName.indexOf("|") : -1);
+    String file0 = (pt >= 0 ? fileName : null);
+    if (pt >= 0)
+      fileName = fileName.substring(0,  pt);
+    try {
+      while ((ze = zis.getNextEntry()) != null) {
+        String name = ze.getName();
+        if (fileName != null) {
+          if (oneFile) {
+            if (!name.equalsIgnoreCase(fileName))
+              continue;
+          } else {
+            listing.append(name).appendC('\n');
+          }
+        }
+        long nBytes = ze.getSize();
+        byte[] bytes = Rdr.getLimitedStreamBytes(zis, nBytes);
+        if (file0 != null) {
+          readFileAsMap(Rdr.getBIS(bytes), cache, file0);
+          return null;
+        }
+        n += bytes.length;
+        Object o = (asByteArray ? new BArray(bytes) : bytes);        
+        cache.put((oneFile ? "_DATA_" : (fileName == null ? "" : fileName + "|") + name), o);
+        if (oneFile)
+          break;
+      }
+      zis.close();
+    } catch (Exception e) {
+      try {
+        zis.close();
+      } catch (IOException e1) {
+      }
+      return null;
+    }
+    if (n == 0 || fileName == null)
+      return null;
+    System.out.println("ZipTools cached " + n + " bytes from " + fileName);
+    return listing.toString();
+  }
+
+  private static byte[] getPngImageBytes(BufferedInputStream bis) {
+    try {
+      if (Rdr.isPngZipStream(bis)) {
+        int pt_count[] = new int[2];
+        Rdr.getPngZipPointAndCount(bis, pt_count);
+        if (pt_count[1] != 0)
+          return deActivatePngZipB(Rdr.getLimitedStreamBytes(bis, pt_count[0]));
+      }
+      return Rdr.getLimitedStreamBytes(bis, -1);
+    } catch (IOException e) {
+      return null;
+    }
+  }
+
+  /**
+   * Once a PNGJ image has been extracted, we want to red-line its
+   * iTXt "Jmol Type PNGJ" tag, since it is no longer associated with
+   * ZIP data.
+   *  
+   * @param bytes
+   * @return disfigured bytes
+   * 
+   */
+  private static byte[] deActivatePngZipB(byte[] bytes) {
+    // \0PNGJ starting at byte 50 changed to \0 NGJ
+    if (Rdr.isPngZipB(bytes))
+      bytes[51] = 32;
+    return bytes;
+  }
+
+
+
+}
diff --git a/src/netscape/javascript/JSException.java b/src/netscape/javascript/JSException.java
new file mode 100644 (file)
index 0000000..165cbda
--- /dev/null
@@ -0,0 +1,5 @@
+package netscape.javascript;
+
+public class JSException extends Exception {
+
+}
diff --git a/src/netscape/javascript/JSObject.java b/src/netscape/javascript/JSObject.java
new file mode 100644 (file)
index 0000000..4e84f89
--- /dev/null
@@ -0,0 +1,41 @@
+package netscape.javascript;
+
+import jalview.bin.JalviewLite;
+
+public class JSObject {
+
+       public static JSObject getWindow(JalviewLite jvlite) {
+               /**
+                * @j2sNative
+                * 
+                * return window;
+                * 
+                */
+               {
+                       return null;
+               }
+       }
+
+       public void call(String _listener, Object[] objects) {
+               /**
+                * @j2sNative
+                * 
+                * alert("call " + _listener);
+                */
+               {}
+       }
+
+       public Object eval(String string) {
+               /**
+                * @j2sNative
+                * 
+                * alert("evval " + string);
+                */
+               {
+                       
+                       
+               }
+               return eval(string);
+       }
+
+}
diff --git a/src/org/exolab/castor/mapping/Mapping.java b/src/org/exolab/castor/mapping/Mapping.java
new file mode 100644 (file)
index 0000000..0bef0ce
--- /dev/null
@@ -0,0 +1,16 @@
+package org.exolab.castor.mapping;
+
+import java.net.URL;
+
+public class Mapping {
+
+       public Mapping(ClassLoader classLoader) {
+               // TODO Auto-generated constructor stub
+       }
+
+       public void loadMapping(URL url) {
+               // TODO Auto-generated method stub
+               
+       }
+
+}
diff --git a/src/org/exolab/castor/xml/Unmarshaller.java b/src/org/exolab/castor/xml/Unmarshaller.java
new file mode 100644 (file)
index 0000000..640328b
--- /dev/null
@@ -0,0 +1,44 @@
+package org.exolab.castor.xml;
+
+import java.io.PrintWriter;
+import java.io.Reader;
+
+import org.exolab.castor.mapping.Mapping;
+
+public class Unmarshaller {
+
+       public Unmarshaller(Object record) {
+               // TODO Auto-generated constructor stub
+       }
+
+       public void setIgnoreExtraElements(boolean b) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       public void setIgnoreExtraAttributes(boolean b) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       public void setMapping(Mapping map) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       public void setLogWriter(PrintWriter printWriter) {
+               // TODO Auto-generated method stub
+               
+       }
+
+       public Object unmarshal(Reader file) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       public void setDebug(boolean debugEnabled) {
+               // TODO Auto-generated method stub
+               
+       }
+
+}
diff --git a/src/org/jmol/viewer/Viewer.java b/src/org/jmol/viewer/Viewer.java
new file mode 100644 (file)
index 0000000..1f6c399
--- /dev/null
@@ -0,0 +1,5 @@
+package org.jmol.viewer;
+
+public class Viewer {
+
+}
diff --git a/src/swingjs/JSEvent.java b/src/swingjs/JSEvent.java
new file mode 100644 (file)
index 0000000..5b2a6e6
--- /dev/null
@@ -0,0 +1,22 @@
+package swingjs;
+
+import java.awt.event.InvocationEvent;
+
+/**
+ * a custom implementation of java.awt.event.InvocationEvent for JSThread
+ * 
+ * @author Bob Hanson
+ *
+ */
+public class JSEvent extends InvocationEvent {
+       
+       /**
+        * 
+        */
+       private static final long serialVersionUID = -8061376242084344200L;
+
+       JSEvent(JSThread t, Runnable r) {
+               super(t, r);
+       }
+
+}
diff --git a/src/swingjs/JSThread.java b/src/swingjs/JSThread.java
new file mode 100644 (file)
index 0000000..b7e7f10
--- /dev/null
@@ -0,0 +1,143 @@
+package swingjs;
+
+import java.awt.Toolkit;
+import java.awt.event.InvocationEvent;
+import swingjs.api.JSFunction;
+
+/**
+ * A class that takes care of simple threading. There are three states: INIT, LOOP, and DONE.
+ * These states are passed into run1
+ * 
+ * 
+ * @author Bob Hanson
+ * 
+ */
+public abstract class JSThread extends Thread implements JSFunction {
+
+       public static final int INIT = 0;
+       public static final int LOOP = 1;
+       public static final int DONE = 2;
+
+       protected boolean isJS;
+       protected boolean doDispatch = true;
+       protected int msDelay;
+
+       public JSThread(ThreadGroup group, String name) {
+               super(group, name);
+               /**
+                * @j2sNative
+                * 
+                * this.isJS = true;
+                */
+               {}
+       }
+
+       public void run() {
+               run1(INIT);
+       }
+
+       @Override
+       public synchronized void start() {
+
+               /**
+                * @j2sNative
+                * 
+                *            JSToolkit.setTimeout(this, 1, 0);
+                * 
+                */
+               {
+                       super.start();
+               }
+
+       }
+
+       /**
+        * set the delay time between run1 calls
+        * 
+        * @param ms
+        */
+       public void setDelayMillis(int ms) {
+               msDelay = ms;
+       }
+
+       /**
+        * a generic method that loops until done, or in JavaScript, will reenter and
+        * continue at the appropriate spot. Example given here
+        * 
+        * @param state
+        */
+       protected abstract void run1(int state);
+
+       
+       // protected void run1(int state) {
+       // try {
+       // while (true)
+       // switch (state) {
+       // case INIT:
+       // // once-through stuff here
+       // state = LOOP;
+       // break;
+       // case LOOP:
+       // if (!doDispatch || isInterrupted()) {
+       // state = DONE;
+       // } else {
+       // // put the loop code here
+       // };
+       // dispatchAndReturn(state);
+       // if (isJS)
+       // return;
+       // }
+       // break;
+       // // add more cases as needed
+       // case DONE:
+       // // finish up here
+       // if (isInterrupted())
+       // return;
+       // // or here
+       // break;
+       // }
+       // } finally {
+       // // stuff here to be executed after each loop in JS or at the end in Java
+       // }
+       // }
+
+       /**
+        * 
+        * @param r
+        * @param state
+        * @throws InterruptedException
+        */
+       protected void dispatchAndReturn(final int state)
+                       throws InterruptedException {
+               final int delay = msDelay;
+               if (isJS) {
+                       // in JavaScript, we need to do this through the system event queue,
+                       // which in JSToolkit takes care of all the "thread" handling.
+                       
+                       final JSThread me = this;
+                       Runnable r = new Runnable() {
+                               @Override
+                               public void run() {
+                                       me.run1(state);
+                               }
+                       };
+                       /**
+                        * @j2sNative
+                        * 
+                        *            setTimeout(function() {
+                        *            java.awt.Toolkit.getDefaultToolkit().getSystemEventQueue
+                        *            ().postEvent(new java.awt.event.InvocationEvent(me, r)),
+                        *            delay; }
+                        * 
+                        */
+                       {
+                               // for reference only
+                               Toolkit.getDefaultToolkit().getSystemEventQueue()
+                                               .postEvent(new InvocationEvent(me, r));
+                       }
+               } else {
+                       sleep(delay);                   
+               }
+       }
+
+}
diff --git a/src/swingjs/api/JSFunction.java b/src/swingjs/api/JSFunction.java
new file mode 100644 (file)
index 0000000..4dcc3ea
--- /dev/null
@@ -0,0 +1,5 @@
+package swingjs.api;
+
+public interface JSFunction {
+
+}