cbowditch 2004/04/02 05:50:52 Modified: src/java/org/apache/fop/fo/flow Block.java Log: Applied Luca Furini's patch from bugzilla entry 28021. Corrections to behaviour of whitespace-treatment property Revision Changes Path 1.14 +404 -391 xml-fop/src/java/org/apache/fop/fo/flow/Block.java Index: Block.java =================================================================== RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/fo/flow/Block.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- Block.java 7 Mar 2004 17:52:43 -0000 1.13 +++ Block.java 2 Apr 2004 13:50:52 -0000 1.14 @@ -1,391 +1,404 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* $Id$ */ - -package org.apache.fop.fo.flow; - -// XML -import org.xml.sax.Attributes; - -// FOP -import org.apache.fop.apps.FOPException; -import org.apache.fop.datatypes.ColorType; -import org.apache.fop.fo.CharIterator; -import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; -import org.apache.fop.fo.FObjMixed; -import org.apache.fop.fo.RecursiveCharIterator; -import org.apache.fop.fo.FOTreeVisitor; -import org.apache.fop.fo.Constants; -import org.apache.fop.fo.properties.CommonAccessibility; -import org.apache.fop.fo.properties.CommonAural; -import org.apache.fop.fo.properties.CommonBackground; -import org.apache.fop.fo.properties.CommonBorderAndPadding; -import org.apache.fop.fo.properties.CommonHyphenation; -import org.apache.fop.fo.properties.CommonMarginBlock; -import org.apache.fop.fo.properties.CommonRelativePosition; -import org.apache.fop.util.CharUtilities; - -/* - Modified by Mark Lillywhite [EMAIL PROTECTED] The changes - here are based on memory profiling and do not change functionality. - Essentially, the Block object had a pointer to a BlockArea object - that it created. The BlockArea was not referenced after the Block - was finished except to determine the size of the BlockArea, however - a reference to the BlockArea was maintained and this caused a lot of - GC problems, and was a major reason for FOP memory leaks. So, - the reference to BlockArea was made local, the required information - is now stored (instead of a reference to the complex BlockArea object) - and it appears that there are a lot of changes in this file, in fact - there are only a few sematic changes; mostly I just got rid of - "this." from blockArea since BlockArea is now local. - */ - /** - * Class modelling the fo:block object. See Sec. 6.5.2 of the XSL-FO Standard. - */ -public class Block extends FObjMixed { - - private int align; - private int alignLast; - private int breakAfter; - private int lineHeight; - private int startIndent; - private int endIndent; - private int spaceBefore; - private int spaceAfter; - private int textIndent; - private int keepWithNext; - private ColorType backgroundColor; - private int blockWidows; - private int blockOrphans; - - private String id; - private int span; - private int wsTreatment; //ENUMERATION - private int lfTreatment; //ENUMERATION - private boolean bWScollapse; //true if white-space-collapse=true - - // this may be helpful on other FOs too - private boolean anythingLaidOut = false; - - /** - * Index of first inline-type FO seen in a sequence. - * Used during FO tree building to do white-space handling. - */ - private FONode firstInlineChild = null; - - /** - * @param parent FONode that is the parent of this object - */ - public Block(FONode parent) { - super(parent); - } - - /** - * @see org.apache.fop.fo.FObj#handleAttrs - */ - public void handleAttrs(Attributes attlist) throws FOPException { - super.handleAttrs(attlist); - this.span = this.propertyList.get(PR_SPAN).getEnum(); - this.wsTreatment = - this.propertyList.get(PR_WHITE_SPACE_TREATMENT).getEnum(); - this.bWScollapse = - (this.propertyList.get(PR_WHITE_SPACE_COLLAPSE).getEnum() - == Constants.TRUE); - this.lfTreatment = - this.propertyList.get(PR_LINEFEED_TREATMENT).getEnum(); - - setupID(); - - getFOTreeControl().getFOInputHandler().startBlock(this); - } - - private void setup() { - - // Common Accessibility Properties - CommonAccessibility mAccProps = propMgr.getAccessibilityProps(); - - // Common Aural Properties - CommonAural mAurProps = propMgr.getAuralProps(); - - // Common Border, Padding, and Background Properties - CommonBorderAndPadding bap = propMgr.getBorderAndPadding(); - CommonBackground bProps = propMgr.getBackgroundProps(); - - // Common Font Properties - //this.fontState = propMgr.getFontState(area.getFontInfo()); - - // Common Hyphenation Properties - CommonHyphenation mHyphProps = propMgr.getHyphenationProps(); - - // Common Margin Properties-Block - CommonMarginBlock mProps = propMgr.getMarginProps(); - - // Common Relative Position Properties - CommonRelativePosition mRelProps = - propMgr.getRelativePositionProps(); - - // this.propertyList.get("break-after"); - // this.propertyList.get("break-before"); - // this.propertyList.get("color"); - // this.propertyList.get("text-depth"); - // this.propertyList.get("text-altitude"); - // this.propertyList.get("hyphenation-keep"); - // this.propertyList.get("hyphenation-ladder-count"); - setupID(); - // this.propertyList.get("keep-together"); - // this.propertyList.get("keep-with-next"); - // this.propertyList.get("keep-with-previous"); - // this.propertyList.get("last-line-end-indent"); - // this.propertyList.get("linefeed-treatment"); - // this.propertyList.get("line-height"); - // this.propertyList.get("line-height-shift-adjustment"); - // this.propertyList.get("line-stacking-strategy"); - // this.propertyList.get("orphans"); - // this.propertyList.get("white-space-treatment"); - // this.propertyList.get("span"); - // this.propertyList.get("text-align"); - // this.propertyList.get("text-align-last"); - // this.propertyList.get("text-indent"); - // this.propertyList.get("visibility"); - // this.propertyList.get("white-space-collapse"); - // this.propertyList.get("widows"); - // this.propertyList.get("wrap-option"); - // this.propertyList.get("z-index"); - - this.align = this.propertyList.get(PR_TEXT_ALIGN).getEnum(); - this.alignLast = - this.propertyList.get(PR_TEXT_ALIGN_LAST).getEnum(); - this.breakAfter = this.propertyList.get(PR_BREAK_AFTER).getEnum(); - this.lineHeight = this.propertyList.get( - PR_LINE_HEIGHT).getLength().getValue(); - this.startIndent = this.propertyList.get( - PR_START_INDENT).getLength().getValue(); - this.endIndent = this.propertyList.get( - PR_END_INDENT).getLength().getValue(); - this.spaceBefore = this.propertyList.get( - PR_SPACE_BEFORE | CP_OPTIMUM).getLength().getValue(); - this.spaceAfter = this.propertyList.get( - PR_SPACE_AFTER | CP_OPTIMUM).getLength().getValue(); - this.textIndent = this.propertyList.get( - PR_TEXT_INDENT).getLength().getValue(); - this.keepWithNext = - this.propertyList.get(PR_KEEP_WITH_NEXT).getEnum(); - - this.blockWidows = - this.propertyList.get(PR_WIDOWS).getNumber().intValue(); - this.blockOrphans = - this.propertyList.get(PR_ORPHANS).getNumber().intValue(); - - } - - /** - * @return true (Block can contain Markers) - */ - protected boolean containsMarkers() { - return true; - } - - /** - * @return span for this Block, in millipoints (??) - */ - public int getSpan() { - return this.span; - } - - /** - * @return false (Block cannot generate inline areas) - */ - public boolean generatesInlineAreas() { - return false; - } - - /** - * @see org.apache.fop.fo.FObj#addChild - */ - public void addChild(FONode child) { - // Handle whitespace based on values of properties - // Handle a sequence of inline-producing children in - // one pass - if (child instanceof FObj && ((FObj) child).generatesInlineAreas()) { - if (firstInlineChild == null) { - firstInlineChild = child; - } - // lastInlineChild = children.size(); - } else { - // Handle whitespace in preceeding inline areas if any - handleWhiteSpace(); - } - super.addChild(child); - } - - /** - * @see org.apache.fop.fo.FONode#end - */ - public void end() { - handleWhiteSpace(); - getFOTreeControl().getFOInputHandler().endBlock(this); - } - - private void handleWhiteSpace() { - //getLogger().debug("fo:block: handleWhiteSpace"); - if (firstInlineChild != null) { - boolean bInWS = false; - boolean bPrevWasLF = false; - - /* bSeenNonWSYet is an indicator used for trimming all leading - whitespace for the first inline child of the block - */ - boolean bSeenNonWSYet = false; - RecursiveCharIterator charIter = - new RecursiveCharIterator(this, firstInlineChild); - LFchecker lfCheck = new LFchecker(charIter); - - while (charIter.hasNext()) { - switch (CharUtilities.classOf(charIter.nextChar())) { - case CharUtilities.XMLWHITESPACE: - /* Some kind of whitespace character, except linefeed. */ - boolean bIgnore = false; - - switch (wsTreatment) { - case Constants.IGNORE: - bIgnore = true; - break; - case Constants.IGNORE_IF_BEFORE_LINEFEED: - bIgnore = lfCheck.nextIsLF(); - break; - case Constants.IGNORE_IF_SURROUNDING_LINEFEED: - bIgnore = (bPrevWasLF - || lfCheck.nextIsLF()); - break; - case Constants.IGNORE_IF_AFTER_LINEFEED: - bIgnore = bPrevWasLF; - break; - } - // Handle ignore - if (bIgnore) { - charIter.remove(); - } else if (bWScollapse) { - if (bInWS || (lfTreatment == Constants.PRESERVE - && (bPrevWasLF || lfCheck.nextIsLF()))) { - charIter.remove(); - } else { - // this is to retain a single space between words - bInWS = true; - // remove the space if no word in block - // encountered yet - if (!bSeenNonWSYet) { - charIter.remove(); - } - } - } - break; - - case CharUtilities.LINEFEED: - /* A linefeed */ - lfCheck.reset(); - bPrevWasLF = true; // for following whitespace - - switch (lfTreatment) { - case Constants.IGNORE: - charIter.remove(); - break; - case Constants.TREAT_AS_SPACE: - if (bInWS) { - // only if bWScollapse=true - charIter.remove(); - } else { - if (bWScollapse) { - bInWS = true; - // remove the linefeed if no word in block - // encountered yet - if (!bSeenNonWSYet) { - charIter.remove(); - } - } - charIter.replaceChar('\u0020'); - } - break; - case Constants.TREAT_AS_ZERO_WIDTH_SPACE: - charIter.replaceChar('\u200b'); - // Fall through: this isn't XML whitespace - case Constants.PRESERVE: - bInWS = false; - break; - } - break; - - case CharUtilities.EOT: - // A "boundary" objects such as non-character inline - // or nested block object was encountered. - // If any whitespace run in progress, finish it. - // FALL THROUGH - - case CharUtilities.UCWHITESPACE: // Non XML-whitespace - case CharUtilities.NONWHITESPACE: - /* Any other character */ - bInWS = bPrevWasLF = false; - bSeenNonWSYet = true; - lfCheck.reset(); - break; - } - } - firstInlineChild = null; - } - } - - private static class LFchecker { - private boolean bNextIsLF = false; - private RecursiveCharIterator charIter; - - LFchecker(RecursiveCharIterator charIter) { - this.charIter = charIter; - } - - boolean nextIsLF() { - if (bNextIsLF == false) { - CharIterator lfIter = charIter.mark(); - while (lfIter.hasNext()) { - char c = lfIter.nextChar(); - if (c == '\n') { - bNextIsLF = true; - break; - } else if (CharUtilities.classOf(c) - != CharUtilities.XMLWHITESPACE) { - break; - } - } - } - return bNextIsLF; - } - - void reset() { - bNextIsLF = false; - } - } - - /** - * This is a hook for an FOTreeVisitor subclass to be able to access - * this object. - * @param fotv the FOTreeVisitor subclass that can access this object. - * @see org.apache.fop.fo.FOTreeVisitor - */ - public void acceptVisitor(FOTreeVisitor fotv) { - fotv.serveBlock(this); - } - -} +/*
+ * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.fo.flow; + +// XML +import org.xml.sax.Attributes; + +// FOP +import org.apache.fop.apps.FOPException; +import org.apache.fop.datatypes.ColorType; +import org.apache.fop.fo.CharIterator; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; +import org.apache.fop.fo.FObjMixed; +import org.apache.fop.fo.RecursiveCharIterator; +import org.apache.fop.fo.FOTreeVisitor; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.properties.CommonAccessibility; +import org.apache.fop.fo.properties.CommonAural; +import org.apache.fop.fo.properties.CommonBackground; +import org.apache.fop.fo.properties.CommonBorderAndPadding; +import org.apache.fop.fo.properties.CommonHyphenation; +import org.apache.fop.fo.properties.CommonMarginBlock; +import org.apache.fop.fo.properties.CommonRelativePosition; +import org.apache.fop.util.CharUtilities; + +/* + Modified by Mark Lillywhite [EMAIL PROTECTED] The changes + here are based on memory profiling and do not change functionality. + Essentially, the Block object had a pointer to a BlockArea object + that it created. The BlockArea was not referenced after the Block + was finished except to determine the size of the BlockArea, however + a reference to the BlockArea was maintained and this caused a lot of + GC problems, and was a major reason for FOP memory leaks. So, + the reference to BlockArea was made local, the required information + is now stored (instead of a reference to the complex BlockArea object) + and it appears that there are a lot of changes in this file, in fact + there are only a few sematic changes; mostly I just got rid of + "this." from blockArea since BlockArea is now local. + */ + /** + * Class modelling the fo:block object. See Sec. 6.5.2 of the XSL-FO Standard. + */ +public class Block extends FObjMixed { + + private int align; + private int alignLast; + private int breakAfter; + private int lineHeight; + private int startIndent; + private int endIndent; + private int spaceBefore; + private int spaceAfter; + private int textIndent; + private int keepWithNext; + private ColorType backgroundColor; + private int blockWidows; + private int blockOrphans; + + private String id; + private int span; + private int wsTreatment; //ENUMERATION + private int lfTreatment; //ENUMERATION + private boolean bWScollapse; //true if white-space-collapse=true + + // this may be helpful on other FOs too + private boolean anythingLaidOut = false; + + /** + * Index of first inline-type FO seen in a sequence. + * Used during FO tree building to do white-space handling. + */ + private FONode firstInlineChild = null; + + /** + * @param parent FONode that is the parent of this object + */ + public Block(FONode parent) { + super(parent); + } + + /** + * @see org.apache.fop.fo.FObj#handleAttrs + */ + public void handleAttrs(Attributes attlist) throws FOPException { + super.handleAttrs(attlist); + this.span = this.propertyList.get(PR_SPAN).getEnum(); + this.wsTreatment = + this.propertyList.get(PR_WHITE_SPACE_TREATMENT).getEnum(); + this.bWScollapse = + (this.propertyList.get(PR_WHITE_SPACE_COLLAPSE).getEnum() + == Constants.TRUE); + this.lfTreatment = + this.propertyList.get(PR_LINEFEED_TREATMENT).getEnum(); + + setupID(); + + getFOTreeControl().getFOInputHandler().startBlock(this); + } + + private void setup() { + + // Common Accessibility Properties + CommonAccessibility mAccProps = propMgr.getAccessibilityProps(); + + // Common Aural Properties + CommonAural mAurProps = propMgr.getAuralProps(); + + // Common Border, Padding, and Background Properties + CommonBorderAndPadding bap = propMgr.getBorderAndPadding(); + CommonBackground bProps = propMgr.getBackgroundProps(); + + // Common Font Properties + //this.fontState = propMgr.getFontState(area.getFontInfo()); + + // Common Hyphenation Properties + CommonHyphenation mHyphProps = propMgr.getHyphenationProps(); + + // Common Margin Properties-Block + CommonMarginBlock mProps = propMgr.getMarginProps(); + + // Common Relative Position Properties + CommonRelativePosition mRelProps = + propMgr.getRelativePositionProps(); + + // this.propertyList.get("break-after"); + // this.propertyList.get("break-before"); + // this.propertyList.get("color"); + // this.propertyList.get("text-depth"); + // this.propertyList.get("text-altitude"); + // this.propertyList.get("hyphenation-keep"); + // this.propertyList.get("hyphenation-ladder-count"); + setupID(); + // this.propertyList.get("keep-together"); + // this.propertyList.get("keep-with-next"); + // this.propertyList.get("keep-with-previous"); + // this.propertyList.get("last-line-end-indent"); + // this.propertyList.get("linefeed-treatment"); + // this.propertyList.get("line-height"); + // this.propertyList.get("line-height-shift-adjustment"); + // this.propertyList.get("line-stacking-strategy"); + // this.propertyList.get("orphans"); + // this.propertyList.get("white-space-treatment"); + // this.propertyList.get("span"); + // this.propertyList.get("text-align"); + // this.propertyList.get("text-align-last"); + // this.propertyList.get("text-indent"); + // this.propertyList.get("visibility"); + // this.propertyList.get("white-space-collapse"); + // this.propertyList.get("widows"); + // this.propertyList.get("wrap-option"); + // this.propertyList.get("z-index"); + + this.align = this.propertyList.get(PR_TEXT_ALIGN).getEnum(); + this.alignLast = + this.propertyList.get(PR_TEXT_ALIGN_LAST).getEnum(); + this.breakAfter = this.propertyList.get(PR_BREAK_AFTER).getEnum(); + this.lineHeight = this.propertyList.get( + PR_LINE_HEIGHT).getLength().getValue(); + this.startIndent = this.propertyList.get( + PR_START_INDENT).getLength().getValue(); + this.endIndent = this.propertyList.get( + PR_END_INDENT).getLength().getValue(); + this.spaceBefore = this.propertyList.get( + PR_SPACE_BEFORE | CP_OPTIMUM).getLength().getValue(); + this.spaceAfter = this.propertyList.get( + PR_SPACE_AFTER | CP_OPTIMUM).getLength().getValue(); + this.textIndent = this.propertyList.get( + PR_TEXT_INDENT).getLength().getValue(); + this.keepWithNext = + this.propertyList.get(PR_KEEP_WITH_NEXT).getEnum(); + + this.blockWidows = + this.propertyList.get(PR_WIDOWS).getNumber().intValue(); + this.blockOrphans = + this.propertyList.get(PR_ORPHANS).getNumber().intValue(); + + } + + /** + * @return true (Block can contain Markers) + */ + protected boolean containsMarkers() { + return true; + } + + /** + * @return span for this Block, in millipoints (??) + */ + public int getSpan() { + return this.span; + } + + /** + * @return false (Block cannot generate inline areas) + */ + public boolean generatesInlineAreas() { + return false; + } + + /** + * @see org.apache.fop.fo.FObj#addChild + */ + public void addChild(FONode child) { + // Handle whitespace based on values of properties + // Handle a sequence of inline-producing children in + // one pass + if (child instanceof FObj && ((FObj) child).generatesInlineAreas()) { + if (firstInlineChild == null) { + firstInlineChild = child; + } + // lastInlineChild = children.size(); + } else { + // Handle whitespace in preceeding inline areas if any + handleWhiteSpace(); + } + super.addChild(child); + } + + /** + * @see org.apache.fop.fo.FONode#end + */ + public void end() { + handleWhiteSpace(); + getFOTreeControl().getFOInputHandler().endBlock(this); + } + + private void handleWhiteSpace() { + //getLogger().debug("fo:block: handleWhiteSpace"); + if (firstInlineChild != null) { + boolean bInWS = false; + boolean bPrevWasLF = false; + + /* bSeenNonWSYet is an indicator used for trimming all leading + whitespace for the first inline child of the block + */ + boolean bSeenNonWSYet = false; + RecursiveCharIterator charIter = + new RecursiveCharIterator(this, firstInlineChild); + LFchecker lfCheck = new LFchecker(charIter); + + while (charIter.hasNext()) { + char currentChar = charIter.nextChar(); + switch (CharUtilities.classOf(currentChar)) { + case CharUtilities.XMLWHITESPACE: + /* Some kind of whitespace character, except linefeed. */ + boolean bIgnore = false; + + switch (wsTreatment) { + case Constants.IGNORE: + bIgnore = true; + break; + case Constants.IGNORE_IF_BEFORE_LINEFEED: + bIgnore = lfCheck.nextIsLF(); + break; + case Constants.IGNORE_IF_SURROUNDING_LINEFEED: + bIgnore = (bPrevWasLF + || lfCheck.nextIsLF()); + break; + case Constants.IGNORE_IF_AFTER_LINEFEED: + bIgnore = bPrevWasLF; + break; + case Constants.PRESERVE: + // nothing to do now, replacement takes place later + break; + } + // Handle ignore and replacement + if (bIgnore) { + charIter.remove(); + } else if (bWScollapse) { + if (bInWS || (lfTreatment == Constants.PRESERVE + && (bPrevWasLF || lfCheck.nextIsLF()))) { + charIter.remove(); + } else { + // this is to retain a single space between words + bInWS = true; + // remove the space if no word in block + // encountered yet + if (!bSeenNonWSYet) { + charIter.remove(); + } else { + if (currentChar != '\u0020') { + charIter.replaceChar('\u0020'); + } + } + } + } else { + // !bWScollapse + if (currentChar != '\u0020') { + charIter.replaceChar('\u0020'); + } + } + break; + + case CharUtilities.LINEFEED: + /* A linefeed */ + lfCheck.reset(); + bPrevWasLF = true; // for following whitespace + + switch (lfTreatment) { + case Constants.IGNORE: + charIter.remove(); + break; + case Constants.TREAT_AS_SPACE: + if (bInWS) { + // only if bWScollapse=true + charIter.remove(); + } else { + if (bWScollapse) { + bInWS = true; + // remove the linefeed if no word in block + // encountered yet + if (!bSeenNonWSYet) { + charIter.remove(); + } + } + charIter.replaceChar('\u0020'); + } + break; + case Constants.TREAT_AS_ZERO_WIDTH_SPACE: + charIter.replaceChar('\u200b'); + // Fall through: this isn't XML whitespace + case Constants.PRESERVE: + bInWS = false; + break; + } + break; + + case CharUtilities.EOT: + // A "boundary" objects such as non-character inline + // or nested block object was encountered. + // If any whitespace run in progress, finish it. + // FALL THROUGH + + case CharUtilities.UCWHITESPACE: // Non XML-whitespace + case CharUtilities.NONWHITESPACE: + /* Any other character */ + bInWS = bPrevWasLF = false; + bSeenNonWSYet = true; + lfCheck.reset(); + break; + } + } + firstInlineChild = null; + } + } + + private static class LFchecker { + private boolean bNextIsLF = false; + private RecursiveCharIterator charIter; + + LFchecker(RecursiveCharIterator charIter) { + this.charIter = charIter; + } + + boolean nextIsLF() { + if (bNextIsLF == false) { + CharIterator lfIter = charIter.mark(); + while (lfIter.hasNext()) { + char c = lfIter.nextChar(); + if (c == '\n') { + bNextIsLF = true; + break; + } else if (CharUtilities.classOf(c) + != CharUtilities.XMLWHITESPACE) { + break; + } + } + } + return bNextIsLF; + } + + void reset() { + bNextIsLF = false; + } + } + + /** + * This is a hook for an FOTreeVisitor subclass to be able to access + * this object. + * @param fotv the FOTreeVisitor subclass that can access this object. + * @see org.apache.fop.fo.FOTreeVisitor + */ + public void acceptVisitor(FOTreeVisitor fotv) { + fotv.serveBlock(this); + } + +} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]