import java.util.Vector;
import java.util.stream.Collectors;
-import org.jcolorbrewer.ColorBrewer;
-
-import jalview.api.AlignCalcWorkerI;
import jalview.bin.Console;
import jalview.commands.RemoveGapColCommand;
import jalview.datamodel.AlignedCodon;
import jalview.datamodel.IncompleteCodonException;
import jalview.datamodel.Mapping;
import jalview.datamodel.PDBEntry;
-import jalview.datamodel.SeqCigar;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
import jalview.datamodel.features.SequenceFeatures;
-import jalview.gui.AlignmentPanel;
import jalview.io.gff.SequenceOntologyI;
import jalview.schemes.ResidueProperties;
+import jalview.util.ColorUtils;
import jalview.util.Comparison;
import jalview.util.Constants;
import jalview.util.DBRefUtils;
import jalview.util.IntRangeComparator;
import jalview.util.MapList;
import jalview.util.MappingUtils;
-import jalview.util.MessageManager;
-import jalview.workers.SecondaryStructureConsensusThread;
/**
* grab bag of useful alignment manipulation operations Expect these to be
// TODO use Character.toLowerCase to avoid creating String objects?
char[] upstream = new String(ds
.getSequence(s.getStart() - 1 - ustream_ds, s.getStart() - 1))
- .toLowerCase(Locale.ROOT).toCharArray();
+ .toLowerCase(Locale.ROOT).toCharArray();
char[] downstream = new String(
ds.getSequence(s_end - 1, s_end + dstream_ds))
- .toLowerCase(Locale.ROOT).toCharArray();
+ .toLowerCase(Locale.ROOT).toCharArray();
char[] coreseq = s.getSequence();
char[] nseq = new char[offset + upstream.length + downstream.length
+ coreseq.length];
}
return false;
}
-
+
// Method to get the key for a given provider value
- public static String getSecondaryStructureProviderKey(String providerValue) {
- for (Map.Entry<String, String> entry : Constants.STRUCTURE_PROVIDERS.entrySet()) {
- if (entry.getValue().equals(providerValue)) {
- return entry.getKey(); // Return the key (abbreviation) for the matching provider value
- }
+ public static String getSecondaryStructureProviderKey(
+ String providerValue)
+ {
+ for (Map.Entry<String, String> entry : Constants.STRUCTURE_PROVIDERS
+ .entrySet())
+ {
+ if (entry.getValue().equals(providerValue))
+ {
+ return entry.getKey(); // Return the key (abbreviation) for the matching
+ // provider value
}
- return null; // Return null if no match is found
+ }
+ return null; // Return null if no match is found
}
-
- public static String reduceLabelLength(String label) {
+
+ public static String reduceLabelLength(String label)
+ {
// Split the input by " | "
String[] parts = label.split(" \\| ");
-
+
// Map the full names to their abbreviations
String reducedLabel = Arrays.stream(parts)
- .map(fullName -> Constants.STRUCTURE_PROVIDERS.entrySet().stream()
+ .map(fullName -> Constants.STRUCTURE_PROVIDERS.entrySet()
+ .stream()
.filter(entry -> entry.getValue().equals(fullName))
- .map(Map.Entry::getKey)
- .findFirst()
- .orElse(fullName)) // Use fullName if no abbreviation is found
+ .map(Map.Entry::getKey).findFirst().orElse(fullName)) // Use
+ // fullName
+ // if
+ // no
+ // abbreviation
+ // is
+ // found
.collect(Collectors.joining(" | "));
-
- return reducedLabel; // Return the reduced label if abbreviations were applied
+
+ return reducedLabel; // Return the reduced label if abbreviations were
+ // applied
}
-
- public static Color getSecondaryStructureProviderColor(String label) {
- //return Constants.STRUCTURE_PROVIDERS_COLOR.getOrDefault(label, Color.BLACK);
- Color c = Constants.STRUCTURE_PROVIDERS_COLOR.get(label.trim());
- if(c==null)
+ public static Color getSecondaryStructureProviderColor(String label)
+ {
+
+ // return Constants.STRUCTURE_PROVIDERS_COLOR.getOrDefault(label,
+ // Color.BLACK);
+ Color c = Constants.STRUCTURE_PROVIDERS_COLOR.get(label.trim());
+ if (c == null)
c = Color.BLACK;
return c;
}
-
-
- public static void assignSecondaryStructureProviderColor(Map<String, Color> secondaryStructureProviderColorMap,
- List<String> labels) {
-
+
+ public static void assignSecondaryStructureProviderColor(
+ Map<String, Color> secondaryStructureProviderColorMap,
+ List<String> labels)
+ {
+ /*
// Use a Set to track unique labels
Set<String> uniqueLabels = new HashSet<>(labels);
- Color[] palette = ColorBrewer.Paired.getColorPalette(uniqueLabels.size());
+ Color[] palette = ColorBrewer.Paired
+ .getColorPalette(uniqueLabels.size());
-
List<Color> colorList = new ArrayList<>();
Collections.addAll(colorList, palette);
Collections.shuffle(colorList);
- int i = 0;
-
+ int i = 0;
+ */
// Loop through each unique label and add it to the map with a color.
- for (String label : uniqueLabels) {
- // Generate or retrieve a color for the label.
- secondaryStructureProviderColorMap.put(label.toUpperCase().trim(), colorList.get(i));
- i++;
+ // for (String label : uniqueLabels)
+ for (String label : labels)
+ {
+ // Generate or retrieve a color for the label.
+ String name = label.toUpperCase(Locale.ROOT).trim();
+ secondaryStructureProviderColorMap.put(name,
+ // ColorUtils.getDefaultColourFromName(name));
+ ColorUtils.getColourFromNameAndScheme(name, "DESATURATED"));
+ // secondaryStructureProviderColorMap.put(label.toUpperCase().trim(),
+ // colorList.get(i));
+ // i++;
}
}
}
\ No newline at end of file
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
-import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.print.PrinterJob;
import java.util.ArrayList;
import java.util.BitSet;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Vector;
-import org.jcolorbrewer.ColorBrewer;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
{
/** DOCUMENT ME!! */
public static final String PLACEHOLDER = " * ";
-
+
private static final int DASHED_LINE_Y_OFFSET = 6;
TreeModel tree;
int offy;
private float threshold;
-
+
int labelLengthThreshold = 4;
String longestName;
BinaryNode highlightNode;
boolean applyToAllViews = false;
-
- //Map to store label positions (BinaryNode -> List of bounding rectangles for the label)
+
+ // Map to store label positions (BinaryNode -> List of bounding rectangles for
+ // the label)
private Map<BinaryNode, List<Rectangle>> labelBoundsMap = new HashMap<>();
/**
*/
public void drawNode(Graphics g, BinaryNode node, double chunk,
double wscale, int width, int offx, int offy)
- {
+ {
if (node == null)
{
return;
else
{
originalColor = av.getSequenceColour(seq);
- translucentColor = new Color(originalColor.getRed(), originalColor.getGreen(), originalColor.getBlue(), 128); // 128 for 50% transparency
+ translucentColor = new Color(originalColor.getRed(),
+ originalColor.getGreen(), originalColor.getBlue(), 128); // 128
+ // for
+ // 50%
+ // transparency
g.setColor(Color.black);
}
}
nodeLabel = nodeLabel + String.valueOf(node.bootstrap);
}
- if(node.hasLabel() && showStructureProviderColouredLines) {
-
- drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart, xend, ypos, nodeLabel);
-
- Rectangle labelBounds = new Rectangle(xstart, ypos, xend, ypos + DASHED_LINE_Y_OFFSET);
-
- // Add the bounding box to the map for this node
- labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds);
-
+ if (node.hasLabel() && showStructureProviderColouredLines)
+ {
+
+ drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart,
+ xend, ypos, nodeLabel);
+
+ Rectangle labelBounds = new Rectangle(xstart, ypos, xend,
+ ypos + DASHED_LINE_Y_OFFSET);
+
+ // Add the bounding box to the map for this node
+ labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>())
+ .add(labelBounds);
+
}
else if (!nodeLabel.equals(""))
{
charWidth, charHeight);
nameHash.put(node, rect);
-
+
g.setColor(translucentColor);
- g.fillRect(xend + 10, ypos - charHeight / 2, charWidth, charHeight);
- //g.fillRect(xstart - 2, ypos - 10, (xend + 20 + charWidth) - xstart, 20);
-
+ g.fillRect(xend + 10, ypos - charHeight / 2, charWidth, charHeight);
+ // g.fillRect(xstart - 2, ypos - 10, (xend + 20 + charWidth) - xstart,
+ // 20);
+
g.setColor(Color.black);
-
+
// Colour selected leaves differently
boolean isSelected = false;
if (tp.isColumnWise())
int xend = (int) (height * wscale) + offx;
int ypos = (int) (node.ycount * chunk) + offy;
- //g.setColor(node.color.darker());
-
+ // g.setColor(node.color.darker());
g.setColor(Color.black);
-
+
// Draw horizontal line
g.drawLine(xstart, ypos, xend, ypos);
if (node == highlightNode)
nodeLabel = nodeLabel + String.valueOf(node.bootstrap);
}
-
- //Display secondary structure providers only if:
+ // Display secondary structure providers only if:
// ~ node has Label assigned (Secondary structure providers)
// ~ either label or coloured lines option is selected by the user
- boolean labelHandled = false;
- if(node.hasLabel()) {
-
+ boolean labelHandled = false;
+ if (node.hasLabel())
+ {
+
if (showStructureProviderColouredLines)
{
- drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart, xend, ypos, nodeLabel);
-
- Rectangle labelBounds = new Rectangle(xstart, ypos, xend, ypos + DASHED_LINE_Y_OFFSET);
-
- // Add the bounding box to the map for this node (list allows multiple bounding boxes)
- labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds);
+ drawLinesAndLabelsForSecondaryStructureProvider(g, node, xstart,
+ xend, ypos, nodeLabel);
+
+ Rectangle labelBounds = new Rectangle(xstart, ypos, xend,
+ ypos + DASHED_LINE_Y_OFFSET);
+
+ // Add the bounding box to the map for this node (list allows multiple
+ // bounding boxes)
+ labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>())
+ .add(labelBounds);
labelHandled = true;
-
+
}
-
- if (showStructureProviderLabels && node.count > 3)
+
+ if (showStructureProviderLabels && node.count > 3)
{
-
+
String label = node.getLabel();
-
- if(label.length() > labelLengthThreshold) {
-
- //label = AlignmentUtils.reduceLabelLength(label);
+
+ if (label.length() > labelLengthThreshold)
+ {
+
+ // label = AlignmentUtils.reduceLabelLength(label);
}
-
+
nodeLabel = label + " | " + nodeLabel;
-
+
// Split the nodeLabel by "|"
String[] lines = nodeLabel.split("\\|");
-
+
// Draw each string separately
String longestLabelString = "";
int i = 0;
- for (i = 0; i < lines.length; i++) {
- g.drawString(lines[i].trim(), xstart + 2, ypos - 2 - (i * fm.getHeight()));
- if(longestLabelString.length() < lines[i].trim().length()) {
- longestLabelString = lines[i].trim();
- }
+ for (i = 0; i < lines.length; i++)
+ {
+ g.drawString(lines[i].trim(), xstart + 2,
+ ypos - 2 - (i * fm.getHeight()));
+ if (longestLabelString.length() < lines[i].trim().length())
+ {
+ longestLabelString = lines[i].trim();
+ }
}
-
+
int labelWidth = fm.stringWidth(longestLabelString);
- int labelHeight = fm.getHeight() * (i-1);
-
+ int labelHeight = fm.getHeight() * (i - 1);
+
// Bounding box of the string
int xLabelPos = xstart + 2;
int yLabelPos = ypos - 2;
- Rectangle labelBounds = new Rectangle(xLabelPos, yLabelPos - labelHeight, labelWidth, labelHeight);
-
- // Add the bounding box to the map for the node
- labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>()).add(labelBounds);
-
+ Rectangle labelBounds = new Rectangle(xLabelPos,
+ yLabelPos - labelHeight, labelWidth, labelHeight);
+
+ // Add the bounding box to the map for the node
+ labelBoundsMap.computeIfAbsent(node, k -> new ArrayList<>())
+ .add(labelBounds);
+
labelHandled = true;
}
}
-
+
if (!nodeLabel.equals("") && !labelHandled)
{
g.drawString(nodeLabel, xstart + 2, ypos - 2);
}
}
}
-
-
- private void drawLinesAndLabelsForSecondaryStructureProvider(Graphics g, BinaryNode node,
- int xstart, int xend, int ypos, String nodeLabel) {
-
+
+ private void drawLinesAndLabelsForSecondaryStructureProvider(Graphics g,
+ BinaryNode node, int xstart, int xend, int ypos, String nodeLabel)
+ {
+
Graphics2D g2d = (Graphics2D) g.create();
// Set dash pattern
-// float[] dashPattern = {2, 2};
-// g2d.setStroke(new BasicStroke(
-// 2.5f,
-// BasicStroke.CAP_BUTT,
-// BasicStroke.JOIN_ROUND,
-// 0.0f,
-// dashPattern,
-// 0.0f));
-
- g2d.setStroke(new BasicStroke(
- 4.0f,
- BasicStroke.CAP_BUTT,
- BasicStroke.JOIN_ROUND
- ));
+ // float[] dashPattern = {2, 2};
+ // g2d.setStroke(new BasicStroke(
+ // 2.5f,
+ // BasicStroke.CAP_BUTT,
+ // BasicStroke.JOIN_ROUND,
+ // 0.0f,
+ // dashPattern,
+ // 0.0f));
+
+ g2d.setStroke(new BasicStroke(4.0f, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND));
String label = node.getLabel();
String[] lines = label.split("\\|");
-
+
int mid = lines.length / 2;
-
+
// Draw lines for the first half
int firstHalfLinesCount = mid;
- drawSecondaryStructureProviderLinesSection(g2d,
- lines, 0, mid, xstart, xend,
- ypos - DASHED_LINE_Y_OFFSET,
- true);
- drawVerticalLineAndLabel(g, xstart, ypos, firstHalfLinesCount, true, nodeLabel);
+ drawSecondaryStructureProviderLinesSection(g2d, lines, 0, mid, xstart,
+ xend, ypos - DASHED_LINE_Y_OFFSET, true);
+ drawVerticalLineAndLabel(g, xstart, ypos, firstHalfLinesCount, true,
+ nodeLabel);
// Draw lines for the second half
int secondHalfLinesCount = lines.length - mid;
- drawSecondaryStructureProviderLinesSection(g2d,
- lines, mid, lines.length, xstart, xend,
- ypos,
- false);
- drawVerticalLineAndLabel(g, xstart, ypos, secondHalfLinesCount, false, nodeLabel);
+ drawSecondaryStructureProviderLinesSection(g2d, lines, mid,
+ lines.length, xstart, xend, ypos, false);
+ drawVerticalLineAndLabel(g, xstart, ypos, secondHalfLinesCount, false,
+ nodeLabel);
- g2d.dispose();
-}
+ g2d.dispose();
+ }
- private void drawSecondaryStructureProviderLinesSection(Graphics2D g2d, String[] lines, int start, int end, int xstart, int xend, int baseY, boolean above) {
-
- for (int i = start, j=0; i < end; i++, j++) {
- int adjustedY = above
- ? baseY - ((i - start) * DASHED_LINE_Y_OFFSET)
- : baseY +((i - start) * DASHED_LINE_Y_OFFSET);
- //Color providerColor = AlignmentUtils.getSecondaryStructureProviderColor(lines[i]);
-
- Map<String, Color> secondaryStructureProviderColorMap = tp.getSecondaryStructureProviderColorMap();
- Color providerColor = secondaryStructureProviderColorMap.getOrDefault(lines[i].toUpperCase().trim(), Color.BLACK);
- g2d.setColor(providerColor);
- if(i==start && !above) {
- g2d.drawLine(xstart, adjustedY, xend-3, adjustedY);
- }
- else
- {
- g2d.drawLine(xstart, adjustedY, xend, adjustedY);
- }
+ private void drawSecondaryStructureProviderLinesSection(Graphics2D g2d,
+ String[] lines, int start, int end, int xstart, int xend,
+ int baseY, boolean above)
+ {
+
+ for (int i = start, j = 0; i < end; i++, j++)
+ {
+ int adjustedY = above ? baseY - ((i - start) * DASHED_LINE_Y_OFFSET)
+ : baseY + ((i - start) * DASHED_LINE_Y_OFFSET);
+ // Color providerColor =
+ // AlignmentUtils.getSecondaryStructureProviderColor(lines[i]);
+
+ Map<String, Color> secondaryStructureProviderColorMap = tp
+ .getSecondaryStructureProviderColorMap();
+ Color providerColor = secondaryStructureProviderColorMap
+ .getOrDefault(lines[i].toUpperCase().trim(), Color.BLACK);
+ g2d.setColor(providerColor);
+ if (i == start && !above)
+ {
+ g2d.drawLine(xstart, adjustedY, xend - 3, adjustedY);
+ }
+ else
+ {
+ g2d.drawLine(xstart, adjustedY, xend, adjustedY);
}
+ }
}
-
- private void drawVerticalLineAndLabel(Graphics g, int xstart, int ypos,
- int linesCount, boolean above, String nodeLabel) {
-
- int adjustment = (linesCount * DASHED_LINE_Y_OFFSET) + (DASHED_LINE_Y_OFFSET / 3);
- int adjustedY = ypos + (above ? -adjustment : adjustment - DASHED_LINE_Y_OFFSET);
+
+ private void drawVerticalLineAndLabel(Graphics g, int xstart, int ypos,
+ int linesCount, boolean above, String nodeLabel)
+ {
+
+ int adjustment = (linesCount * DASHED_LINE_Y_OFFSET)
+ + (DASHED_LINE_Y_OFFSET / 3);
+ int adjustedY = ypos
+ + (above ? -adjustment : adjustment - DASHED_LINE_Y_OFFSET);
// draw vertical line
g.drawLine(xstart, ypos, xstart, adjustedY);
// draw label
- if(above && !nodeLabel.equals(""))
+ if (above && !nodeLabel.equals(""))
g.drawString(nodeLabel, xstart + 2, adjustedY - 2);
-}
-
+ }
/**
* DOCUMENT ME!
av.setCurrentTree(tree);
Object ob = findElement(evt.getX(), evt.getY());
-
+
// Get mouse coordinates
int mouseX = evt.getX();
int mouseY = evt.getY();
}
else
- {
-
+ {
+
if (highlightNode != null)
{
highlightNode = null;
setToolTipText(null);
repaint();
}
-
+
// Iterate through the map of label bounding boxes
- for (Map.Entry<BinaryNode, List<Rectangle>> entry : labelBoundsMap.entrySet()) {
- BinaryNode node = entry.getKey();
- List<Rectangle> boundsList = entry.getValue();
-
- // Check each bounding box for this node
- for (Rectangle labelBounds : boundsList) {
- if (labelBounds.contains(mouseX, mouseY)) {
- // Show tooltip for this node's label
- String nodeLabel = node.getDisplayName();
- this.setToolTipText(nodeLabel);
- repaint();
- return; // Exit once we find a matching label
- }
+ for (Map.Entry<BinaryNode, List<Rectangle>> entry : labelBoundsMap
+ .entrySet())
+ {
+ BinaryNode node = entry.getKey();
+ List<Rectangle> boundsList = entry.getValue();
+
+ // Check each bounding box for this node
+ for (Rectangle labelBounds : boundsList)
+ {
+ if (labelBounds.contains(mouseX, mouseY))
+ {
+ // Show tooltip for this node's label
+ String nodeLabel = node.getDisplayName();
+ this.setToolTipText(nodeLabel);
+ repaint();
+ return; // Exit once we find a matching label
}
+ }
}
// Clear tooltip if no label is hovered
setToolTipText(null);
Map<BitSet, Color> colors = new HashMap();
for (int i = 0; i < groups.size(); i++)
{
- String colId = groups.get(i).getNodeName();
+ String colId = groups.get(i).getBranchIdentifier();
Color col = ColorUtils.getDefaultColourFromName(colId);
setColor(groups.get(i), col.brighter());
Vector<BinaryNode> l = tree.findLeaves(groups.get(i));
- //gatherLabelsTo(groups.get(i), l);
+ // gatherLabelsTo(groups.get(i), l);
if (!tp.isColumnWise())
{
createSeqGroupFor(aps, l, col, groups.get(i).getLabel());
sb.append(" | ");
}
first = false;
-// if(labelsForNode.size()>1) {
-// String providerAbbreviation = AlignmentUtils.getProviderKey(label);
-// sb.append(providerAbbreviation);
-// }
+ // if(labelsForNode.size()>1) {
+ // String providerAbbreviation = AlignmentUtils.getProviderKey(label);
+ // sb.append(providerAbbreviation);
+ // }
sb.append(label);
-
+
}
binaryNode.setLabel(sb.toString());
}
ColourSchemeI cs = null;
SequenceGroup _sg = new SequenceGroup(sequences, null, cs, true, true,
false, 0, av.getAlignment().getWidth() - 1);
-
+
// Check if the label is not null and not empty
- if(label != null && !label.isEmpty()) {
+ if (label != null && !label.isEmpty())
+ {
// Retrieve the existing groups from the alignment
List<SequenceGroup> existingGroups = av.getAlignment().getGroups();
-
+
// Reduce the label length
label = AlignmentUtils.reduceLabelLength(label);
-
+
// Create group name based on the label
String newGroupName = "JTreeGroup:" + label;
-
+
// Counter for groups with the same name
int noOfGroupsWithSameName = 0;
-
+
// Iterate through the existing groups to check for naming conflicts
- for (SequenceGroup sg : existingGroups) {
- if (sg.getName().equals(newGroupName) || sg.getName().matches(newGroupName + " \\d+")) {
+ for (SequenceGroup sg : existingGroups)
+ {
+ if (sg.getName().equals(newGroupName)
+ || sg.getName().matches(newGroupName + " \\d+"))
+ {
noOfGroupsWithSameName++;
-
- // If a group name matches exactly, update the group's name by appending the count
- if(sg.getName().equals(newGroupName) ) {
- String updatedGroupName = sg.getName() + " " + noOfGroupsWithSameName;
+
+ // If a group name matches exactly, update the group's name by
+ // appending the count
+ if (sg.getName().equals(newGroupName))
+ {
+ String updatedGroupName = sg.getName() + " "
+ + noOfGroupsWithSameName;
sg.setName(updatedGroupName);
}
}
}
-
+
// If count > 0, increment the count and append it to the new group name
- if(noOfGroupsWithSameName>0) {
+ if (noOfGroupsWithSameName > 0)
+ {
noOfGroupsWithSameName++;
newGroupName = newGroupName + " " + noOfGroupsWithSameName;
}
-
+
_sg.setName(newGroupName);
}
- else {
+ else
+ {
_sg.setName("JTreeGroup:" + _sg.hashCode());
}
_sg.setIdColour(col);
this.showDistances = state;
repaint();
}
-
+
public void hideStructureProviders(boolean state)
{
- if(state) {
+ if (state)
+ {
this.showStructureProviderColouredLines = false;
this.showStructureProviderLabels = false;
repaint();
}
}
-
+
public void setShowStructureProviderColouredLines(boolean state)
{
this.showStructureProviderColouredLines = state;
- if(state) {
+ if (state)
+ {
this.showStructureProviderLabels = false;
}
repaint();
}
-
+
public void setShowStructureProviderLabels(boolean state)
{
this.showStructureProviderLabels = state;
- if(state) {
+ if (state)
+ {
this.showStructureProviderColouredLines = false;
}
repaint();
}
-
/**
* DOCUMENT ME!