public static String getFirstSubstring(final String inputString,
            final String startingWith, final String endingWith) {
        if (!inputString.contains(startingWith)
                || !inputString.contains(endingWith)) {
            return null;
        }
        final int startIndex = inputString.indexOf(startingWith);

        if (!((startIndex + 1) < inputString.length())) {
            return null;
        }

        final int endIndex = inputString.indexOf(endingWith, startIndex + 1)
                + 1;
        if (startIndex > endIndex || startIndex < 0 || endIndex < 0) {
            return null;
        }
        return inputString.substring(startIndex, endIndex);
    }

public static String getFirstSubstring ( final String inputString , final String startingWith , final String endingWith ) { if ( ! inputString . contains ( startingWith ) || ! inputString . contains ( endingWith ) ) { return null ; } final int startIndex = inputString . indexOf ( startingWith ) ; if ( ! ( ( startIndex + 1 ) < inputString . length ( ) ) ) { return null ; } final int endIndex = inputString . indexOf ( endingWith , startIndex + 1 ) + 1 ; if ( startIndex > endIndex || startIndex < 0 || endIndex < 0 ) { return null ; } return inputString . substring ( startIndex , endIndex ) ; }

gets the first substring which starts and ends with the given values.

@param inputString
the string from which the substring will be
extracted.
@param startingWith
to match the starting substring
@param endingWith
to match the ending substring
@return the substring which starts and ends with the given
{@code startingWith} and {@code endingWith} values. Or returns
null if it doesn't contain.
@author WFF
@since 1.0.0

gets the first substring which starts and ends with the given values .


public static String[] cloneArray(final String[] inputArray) {
        final String[] array = new String[inputArray.length];
        System.arraycopy(inputArray, 0, array, 0, inputArray.length);
        return array;
    }

public static String [ ] cloneArray ( final String [ ] inputArray ) { final String [ ] array = new String [ inputArray . length ] ; System . arraycopy ( inputArray , 0 , array , 0 , inputArray . length ) ; return array ; }

To make the clone copy of the given String array. This method is faster
than the clone method of String array.

@param inputArray
@return the cloned array of the given string array.
@author WFF
@since 1.0.0

To make the clone copy of the given String array . This method is faster than the clone method of String array .


public static boolean containsWhitespace(final String string) {

        for (int i = 0; i < string.length(); i++) {
            if (Character.isWhitespace(string.charAt(i))) {
                return true;
            }
        }

        return false;
    }

public static boolean containsWhitespace ( final String string ) { for ( int i = 0 ; i < string . length ( ) ; i ++ ) { if ( Character . isWhitespace ( string . charAt ( i ) ) ) { return true ; } } return false ; }

Checks if the given string contains whitespace.

@param string
@return true if the given string contains space char.
@since 3.0.1
@author WFF

Checks if the given string contains whitespace .


public static String strip(final String s) {

        int first;
        int last;

        for (first = 0; first < s.length(); first++) {
            if (!Character.isWhitespace(s.charAt(first))) {
                break;
            }
        }

        for (last = s.length(); last > first; last--) {
            if (!Character.isWhitespace(s.charAt(last - 1))) {
                break;
            }
        }

        return s.substring(first, last);
    }

public static String strip ( final String s ) { int first ; int last ; for ( first = 0 ; first < s . length ( ) ; first ++ ) { if ( ! Character . isWhitespace ( s . charAt ( first ) ) ) { break ; } } for ( last = s . length ( ) ; last > first ; last -- ) { if ( ! Character . isWhitespace ( s . charAt ( last - 1 ) ) ) { break ; } } return s . substring ( first , last ) ; }

Removes the trailing and leading whitespaces

@param s
@return the striped string
@since 3.0.1


public void removeAllChildren() {

        boolean listenerInvoked = false;
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();

        try {

            lock.lock();

            final AbstractHtml[] removedAbstractHtmls = children
                    .toArray(new AbstractHtml[children.size()]);
            children.clear();

            initNewSharedObjectInAllNestedTagsAndSetSuperParentNull(
                    removedAbstractHtmls);
            final ChildTagRemoveListener listener = sharedObject
                    .getChildTagRemoveListener(ACCESS_OBJECT);
            if (listener != null) {
                listener.allChildrenRemoved(new ChildTagRemoveListener.Event(
                        this, removedAbstractHtmls));
                listenerInvoked = true;
            }

        } finally {
            lock.unlock();
        }
        if (listenerInvoked) {
            final PushQueue pushQueue = sharedObject
                    .getPushQueue(ACCESS_OBJECT);
            if (pushQueue != null) {
                pushQueue.push();
            }
        }
    }

Removes all children from this tag.

@author WFF


protected void addInnerHtmls(final boolean updateClient,
            final AbstractHtml... innerHtmls) {

        boolean listenerInvoked = false;
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();

        try {
            lock.lock();

            final AbstractHtml[] removedAbstractHtmls = children
                    .toArray(new AbstractHtml[children.size()]);
            children.clear();

            initNewSharedObjectInAllNestedTagsAndSetSuperParentNull(
                    removedAbstractHtmls);

            final InnerHtmlAddListener listener = sharedObject
                    .getInnerHtmlAddListener(ACCESS_OBJECT);

            if (listener != null && updateClient) {

                final InnerHtmlAddListener.Event[] events = new InnerHtmlAddListener.Event[innerHtmls.length];

                int index = 0;

                for (final AbstractHtml innerHtml : innerHtmls) {

                    AbstractHtml previousParentTag = null;

                    if (innerHtml.parent != null
                            && innerHtml.parent.sharedObject == sharedObject) {
                        previousParentTag = innerHtml.parent;
                    }

                    addChild(innerHtml, false);

                    events[index] = new InnerHtmlAddListener.Event(this,
                            innerHtml, previousParentTag);
                    index++;

                }

                listener.innerHtmlsAdded(this, events);
                listenerInvoked = true;
            } else {
                for (final AbstractHtml innerHtml : innerHtmls) {
                    addChild(innerHtml, false);
                }
            }

        } finally {
            lock.unlock();
        }

        if (listenerInvoked) {
            final PushQueue pushQueue = sharedObject
                    .getPushQueue(ACCESS_OBJECT);
            if (pushQueue != null) {
                pushQueue.push();
            }
        }

    }

Removes all children and adds the given tags as children.

@param updateClient
true to update client browser page if it is
available. The default value is true but it will
be ignored if there is no client browser page.
@param innerHtmls
the inner html tags to add

@since 2.1.15
@author WFF

Removes all children and adds the given tags as children .


public boolean removeChildren(final Collection<AbstractHtml> children) {
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();
        boolean result = false;
        try {
            lock.lock();
            result = this.children.removeAll(children);
        } finally {
            lock.unlock();
        }
        final PushQueue pushQueue = sharedObject.getPushQueue(ACCESS_OBJECT);
        if (pushQueue != null) {
            pushQueue.push();
        }
        return result;
    }

public boolean removeChildren ( final Collection < AbstractHtml > children ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . writeLock ( ) ; boolean result = false ; try { lock . lock ( ) ; result = this . children . removeAll ( children ) ; } finally { lock . unlock ( ) ; } final PushQueue pushQueue = sharedObject . getPushQueue ( ACCESS_OBJECT ) ; if ( pushQueue != null ) { pushQueue . push ( ) ; } return result ; }

Removes the given tags from its children tags.

@param children
the tags to remove from its children.
@return true given given children tags have been removed.
@author WFF

Removes the given tags from its children tags .


public boolean removeChild(final AbstractHtml child) {

        boolean listenerInvoked = false;
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();
        boolean removed = false;
        try {
            lock.lock();

            removed = children.remove(child);

            if (removed) {

                // making child.parent = null inside the below method.
                initNewSharedObjectInAllNestedTagsAndSetSuperParentNull(child);

                final ChildTagRemoveListener listener = sharedObject
                        .getChildTagRemoveListener(ACCESS_OBJECT);

                if (listener != null) {
                    listener.childRemoved(
                            new ChildTagRemoveListener.Event(this, child));
                    listenerInvoked = true;
                }

            }

        } finally {
            lock.unlock();
        }
        if (listenerInvoked) {
            final PushQueue pushQueue = sharedObject
                    .getPushQueue(ACCESS_OBJECT);
            if (pushQueue != null) {
                pushQueue.push();
            }
        }
        return removed;
    }

Removes the given tag from its children only if the given tag is a child
of this tag.

@param child
the tag to remove from its children
@return true if removed
@author WFF

Removes the given tag from its children only if the given tag is a child of this tag .


public void appendChildren(final Collection<AbstractHtml> children) {

        boolean listenerInvoked = false;
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();
        try {
            lock.lock();

            final Collection<ChildMovedEvent> movedOrAppended = new ArrayDeque<>(
                    children.size());

            for (final AbstractHtml child : children) {
                final AbstractHtml previousParent = child.parent;

                addChild(child, false);

                final ChildMovedEvent event = new ChildMovedEvent(
                        previousParent, this, child);
                movedOrAppended.add(event);

            }

            final ChildTagAppendListener listener = sharedObject
                    .getChildTagAppendListener(ACCESS_OBJECT);
            if (listener != null) {
                listener.childrendAppendedOrMoved(movedOrAppended);
                listenerInvoked = true;
            }
        } finally {
            lock.unlock();
        }
        if (listenerInvoked) {
            final PushQueue pushQueue = sharedObject
                    .getPushQueue(ACCESS_OBJECT);
            if (pushQueue != null) {
                pushQueue.push();
            }
        }
    }

public void appendChildren ( final Collection < AbstractHtml > children ) { boolean listenerInvoked = false ; final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . writeLock ( ) ; try { lock . lock ( ) ; final Collection < ChildMovedEvent > movedOrAppended = new ArrayDeque <> ( children . size ( ) ) ; for ( final AbstractHtml child : children ) { final AbstractHtml previousParent = child . parent ; addChild ( child , false ) ; final ChildMovedEvent event = new ChildMovedEvent ( previousParent , this , child ) ; movedOrAppended . add ( event ) ; } final ChildTagAppendListener listener = sharedObject . getChildTagAppendListener ( ACCESS_OBJECT ) ; if ( listener != null ) { listener . childrendAppendedOrMoved ( movedOrAppended ) ; listenerInvoked = true ; } } finally { lock . unlock ( ) ; } if ( listenerInvoked ) { final PushQueue pushQueue = sharedObject . getPushQueue ( ACCESS_OBJECT ) ; if ( pushQueue != null ) { pushQueue . push ( ) ; } } }

adds the given children to the last position of the current children of
this object.

@param children
children to append in this object's existing
children.
@author WFF

adds the given children to the last position of the current children of this object .


private void initAttributes(final AbstractAttribute... attributes) {

        if (attributes == null || attributes.length == 0) {
            return;
        }

        // initial capacity must be greater than 1 instead of 1
        // because the load factor is 0.75f
        // possible initial attributes on a tag may be maximum 8
        // they may be id, name, class, value, style, onchange, placeholder
        attributesMap = new ConcurrentHashMap<>(8);

        for (final AbstractAttribute attribute : attributes) {
            attributesMap.put(attribute.getAttributeName(), attribute);
        }

        this.attributes = new AbstractAttribute[attributesMap.size()];
        attributesMap.values().toArray(this.attributes);
    }

initializes attributes in this.attributes and also in attributesMap. this
should be called only once per object.

@param attributes
@since 2.0.0
@author WFF

initializes attributes in this . attributes and also in attributesMap . this should be called only once per object .


public AbstractAttribute getAttributeByName(final String attributeName) {
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        AbstractAttribute result = null;
        try {
            lock.lock();

            if (attributesMap != null) {
                result = attributesMap.get(attributeName);
            }
        } finally {
            lock.unlock();
        }
        return result;
    }

public AbstractAttribute getAttributeByName ( final String attributeName ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . readLock ( ) ; AbstractAttribute result = null ; try { lock . lock ( ) ; if ( attributesMap != null ) { result = attributesMap . get ( attributeName ) ; } } finally { lock . unlock ( ) ; } return result ; }

gets the attribute by attribute name

@return the attribute object for the given attribute name if exists
otherwise returns null.
@since 2.0.0
@author WFF


private void markOwnerTag(final AbstractAttribute[] attributes) {
        if (attributes == null) {
            return;
        }
        for (final AbstractAttribute abstractAttribute : attributes) {
            abstractAttribute.setOwnerTag(this);
        }
    }

private void markOwnerTag ( final AbstractAttribute [ ] attributes ) { if ( attributes == null ) { return ; } for ( final AbstractAttribute abstractAttribute : attributes ) { abstractAttribute . setOwnerTag ( this ) ; } }

marks the owner tag in the attributes

@param attributes
@since 1.0.0
@author WFF


private void initInConstructor() {
        htmlStartSB = new StringBuilder(tagName == null ? 0
                : tagName.length() + 2
                        + ((attributes == null ? 0 : attributes.length) * 16));

        htmlEndSB = new StringBuilder(
                tagName == null ? 16 : tagName.length() + 3);
    }

private void initInConstructor ( ) { htmlStartSB = new StringBuilder ( tagName == null ? 0 : tagName . length ( ) + 2 + ( ( attributes == null ? 0 : attributes . length ) * 16 ) ) ; htmlEndSB = new StringBuilder ( tagName == null ? 16 : tagName . length ( ) + 3 ) ; }

to initialize objects in the constructor

@since 1.0.0
@author WFF


public AbstractHtml[] getChildrenAsArray() {

        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        try {
            lock.lock();

            return children.toArray(new AbstractHtml[children.size()]);
        } finally {
            lock.unlock();
        }
    }

public AbstractHtml [ ] getChildrenAsArray ( ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . readLock ( ) ; try { lock . lock ( ) ; return children . toArray ( new AbstractHtml [ children . size ( ) ] ) ; } finally { lock . unlock ( ) ; } }

Gets the children of this tag as an array. An efficient way to get the
children as an array.

@return the array of children of this tag.
@since 3.0.1
@author WFF

Gets the children of this tag as an array . An efficient way to get the children as an array .


public AbstractHtml getFirstChild() {
        // this block must be synchronized otherwise may get null or
        // ConcurrentModificationException
        // the test cases are written to check its thread safety and can be
        // reproduce by uncommenting this synchronized block, checkout
        // AbstractHtmlTest class for it.
        // synchronized (children) {
        //
        // }
        // it's been replaced with locking

        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        try {
            lock.lock();

            // this must be most efficient because the javadoc of findFirst says
            // "This is a short-circuiting terminal operation."
            // return (T) children.stream().findFirst().orElse(null);

            // but as per CodePerformanceTest.testPerformanceOfFindFirst
            // the below is faster

            final Iterator<AbstractHtml> iterator = children.iterator();
            if (iterator.hasNext()) {
                return iterator.next();
            }
            return null;
        } finally {
            lock.unlock();
        }

    }

Gets the first child of this tag. The efficient way to get the first
child.

@return the first child of this tag or null if there is no child.

@since 3.0.1
@author WFF

Gets the first child of this tag . The efficient way to get the first child .


public int getChildrenSize() {
        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        try {
            lock.lock();

            return children.size();
        } finally {
            lock.unlock();
        }
    }

public int getChildrenSize ( ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . readLock ( ) ; try { lock . lock ( ) ; return children . size ( ) ; } finally { lock . unlock ( ) ; } }

Gets the number of children in this tag. An efficient way to find the
size of children.

@return the size of children.
@since 3.0.1
@author WFF

Gets the number of children in this tag . An efficient way to find the size of children .


public boolean containsChild(final AbstractHtml childTag) {

        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).readLock();
        try {
            lock.lock();

            return children.contains(childTag);
        } finally {
            lock.unlock();
        }
    }

public boolean containsChild ( final AbstractHtml childTag ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . readLock ( ) ; try { lock . lock ( ) ; return children . contains ( childTag ) ; } finally { lock . unlock ( ) ; } }

Checks whether a tag is contained in its direct children. An efficient
way to check if the given tag is a direct child of this tag.

@param childTag
@return true if the given tag is a child of this tags.
@since 3.0.1
@author WFF

Checks whether a tag is contained in its direct children . An efficient way to check if the given tag is a direct child of this tag .


public final String getOpeningTag() {
        if (isRebuild() || isModified()) {
            final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();
            try {
                lock.lock();

                buildOpeningTag(true);
            } finally {
                lock.unlock();
            }

        }
        return openingTag;
    }

public final String getOpeningTag ( ) { if ( isRebuild ( ) || isModified ( ) ) { final Lock lock = sharedObject . getLock ( ACCESS_OBJECT ) . writeLock ( ) ; try { lock . lock ( ) ; buildOpeningTag ( true ) ; } finally { lock . unlock ( ) ; } } return openingTag ; }

For internal purpose. Not recommended for external purpose.

@return the opening tag of this object
@author WFF

For internal purpose . Not recommended for external purpose .


public boolean insertBefore(final AbstractHtml... abstractHtmls) {

        if (parent == null) {
            throw new NoParentException("There must be a parent for this tag.");
        }

        final Lock lock = sharedObject.getLock(ACCESS_OBJECT).writeLock();
        boolean result = false;
        try {
            lock.lock();

            final AbstractHtml[] removedParentChildren = parent.children
                    .toArray(new AbstractHtml[parent.children.size()]);

            result = insertBefore(removedParentChildren, abstractHtmls);
        } finally {
            lock.unlock();
        }
        final PushQueue pushQueue = sharedObject.getPushQueue(ACCESS_OBJECT);
        if (pushQueue != null) {
            pushQueue.push();
        }
        return result;
    }

public
boolean
insertBefore
(
final
AbstractHtml
...
abstractHtmls
)
{
if
(
parent
==
)
{
throw
new
NoParentException
(
"There must be a parent for this tag."
)
;
}
final
Lock
lock
=
sharedObject
.
getLock
(
ACCESS_OBJECT
)
.
writeLock
(
)
;
boolean
result
=
false
;
try
{
lock
.
lock
(
)
;
final
AbstractHtml
[
]
removedParentChildren
=
parent
.
children
.
toArray
(
new
AbstractHtml
[
parent
.
children
.
size
(
)
]
)
;
result
=
insertBefore
(
removedParentChildren
,
abstractHtmls
)
;
}
finally
{
lock
.
unlock
(
)
;
}
final
PushQueue
pushQueue
=
sharedObject
.
getPushQueue
(
ACCESS_OBJECT
)
;
if
(
pushQueue
!=
)
{
pushQueue
.
push
(
)
;
}
return
result
;
}

Inserts the given tags before this tag. There must be a parent for this
method tag.

@param abstractHtmls
to insert before this tag
@return true if inserted otherwise false.
@since 2.1.1
@author WFF

Inserts the given tags before this tag . There must be a parent for this method tag .


@Override
    protected void setAttributeValue(final boolean updateClient,
            final String value) {
        if (value != null) {
            final Collection<String> allValues = extractValues(value);
            super.replaceAllInAttributeValueSet(updateClient, allValues);
        }
    }

@ Override protected void setAttributeValue ( final boolean updateClient , final String value ) { if ( value != null ) { final Collection < String > allValues = extractValues ( value ) ; super . replaceAllInAttributeValueSet ( updateClient , allValues ) ; } }

sets the value for this attribute

@param updateClient
true to update client browser page if it is
available. The default value is true but it will
be ignored if there is no client browser page.
@param value
the value for the attribute.
@since 2.1.15
@author WFF


protected void replaceAllInAttributeValueSet(final boolean updateClient,
            final String... attrValues) {
        if (attrValues != null) {

            final Collection<String> allValues = new ArrayDeque<>();
            for (final String attrValue : attrValues) {
                if (attrValue != null) {
                    allValues.addAll(extractValues(attrValue));
                }
            }

            super.replaceAllInAttributeValueSet(updateClient, allValues);
        }
    }

protected void replaceAllInAttributeValueSet ( final boolean updateClient , final String ... attrValues ) { if ( attrValues != null ) { final Collection < String > allValues = new ArrayDeque <> ( ) ; for ( final String attrValue : attrValues ) { if ( attrValue != null ) { allValues . addAll ( extractValues ( attrValue ) ) ; } } super . replaceAllInAttributeValueSet ( updateClient , allValues ) ; } }

Removes all values from the attributeValueSet and adds the given
attribute values.

@param updateClient
@param attrValues
@since 3.0.1

Removes all values from the attributeValueSet and adds the given attribute values .


public final void addWebSocketPushListener(final String sessionId,
            final WebSocketPushListener wsListener) {

        sessionIdWsListeners.put(sessionId, wsListener);
        wsListeners.push(wsListener);

        this.wsListener = wsListener;

        if (pushQueueOnNewWebSocketListener) {
            pushWffBMBytesQueue();
        }

    }

public final void addWebSocketPushListener ( final String sessionId , final WebSocketPushListener wsListener ) { sessionIdWsListeners . put ( sessionId , wsListener ) ; wsListeners . push ( wsListener ) ; this . wsListener = wsListener ; if ( pushQueueOnNewWebSocketListener ) { pushWffBMBytesQueue ( ) ; } }

adds the WebSocket listener for the given WebSocket session

@param sessionId
the unique id of WebSocket session
@param wsListener
@since 2.1.0
@author WFF


public final void removeWebSocketPushListener(final String sessionId) {

        final WebSocketPushListener removed = sessionIdWsListeners
                .remove(sessionId);
        wsListeners.remove(removed);
        wsListener = wsListeners.peek();
    }

public final void removeWebSocketPushListener ( final String sessionId ) { final WebSocketPushListener removed = sessionIdWsListeners . remove ( sessionId ) ; wsListeners . remove ( removed ) ; wsListener = wsListeners . peek ( ) ; }

removes the WebSocket listener added for this WebSocket session

@param sessionId
the unique id of WebSocket session
@since 2.1.0
@author WFF


public final void removeFromContext(final boolean enable, final On... ons) {
        for (final On on : ons) {
            if (On.TAB_CLOSE.equals(on)) {
                removeFromBrowserContextOnTabClose = enable;
            } else if (On.INIT_REMOVE_PREVIOUS.equals(on)) {
                removePrevFromBrowserContextOnTabInit = enable;
            }
        }
    }

public final void removeFromContext ( final boolean enable , final On ... ons ) { for ( final On on : ons ) { if ( On . TAB_CLOSE . equals ( on ) ) { removeFromBrowserContextOnTabClose = enable ; } else if ( On . INIT_REMOVE_PREVIOUS . equals ( on ) ) { removePrevFromBrowserContextOnTabInit = enable ; } } }

By default On.TAB_CLOSE and On.INIT_REMOVE_PREVIOUS are enabled.

@param enable
@param ons
the instance of On to represent on which browser event
the browser page needs to be removed.
@since 2.1.4
@author WFF

By default On . TAB_CLOSE and On . INIT_REMOVE_PREVIOUS are enabled .


public final TagRepository getTagRepository() {

        if (tagRepository == null && rootTag != null) {
            synchronized (this) {
                if (tagRepository == null) {
                    tagRepository = new TagRepository(ACCESS_OBJECT, this,
                            tagByWffId, rootTag);
                }
            }
        }

        return tagRepository;
    }

public final TagRepository getTagRepository ( ) { if ( tagRepository == null && rootTag != null ) { synchronized ( this ) { if ( tagRepository == null ) { tagRepository = new TagRepository ( ACCESS_OBJECT , this , tagByWffId , rootTag ) ; } } } return tagRepository ; }

Gets the TagRepository to do different tag operations. This tag
repository is specific to this BrowserPage instance.

@return the TagRepository object to do different tag operations. Or null
if any one of the BrowserPage#toString or
BrowserPage#toOutputStream methods is not called.
@since 2.1.8
@author WFF

Gets the TagRepository to do different tag operations . This tag repository is specific to this BrowserPage instance .


protected final void setNonceForWffScript(final String value) {

        if (autoremoveWffScript) {
            throw new InvalidUsageException(
                    "Cannot remove while autoremoveWffScript is set as true. Please do setAutoremoveWffScript(false)");
        }

        if (value != null) {
            if (nonceForWffScriptTag == null) {
                nonceForWffScriptTag = new Nonce(value);
                if (wffScriptTagId != null) {
                    final AbstractHtml[] ownerTags = wffScriptTagId
                            .getOwnerTags();
                    if (ownerTags.length > 0) {
                        final AbstractHtml wffScript = ownerTags[0];
                        wffScript.addAttributes(nonceForWffScriptTag);
                    }
                }
            } else {
                nonceForWffScriptTag.setValue(value);
            }
        } else {
            if (wffScriptTagId != null && nonceForWffScriptTag != null) {
                final AbstractHtml[] ownerTags = wffScriptTagId.getOwnerTags();
                if (ownerTags.length > 0) {
                    final AbstractHtml wffScript = ownerTags[0];
                    wffScript.removeAttributes(nonceForWffScriptTag);
                }
            }
            nonceForWffScriptTag = null;
        }

    }

Sets nonce attribute value for wff script.

@param value
pass value to set nonce value or pass null to remove
nonce attribute
@since 3.0.1

Sets nonce attribute value for wff script .


public Border setBorderStyle(final BorderStyle borderStyle) {

        if (borderStyle == BorderStyle.INITIAL
                || borderStyle == BorderStyle.INHERIT) {
            throw new InvalidValueException("the given borderStyle cannot be "
                    + borderStyle.getCssValue());
        }

        final StringBuilder cssValueBuilder = new StringBuilder();

        if (borderWidthValue != null) {
            cssValueBuilder.append(borderWidthValue).append(' ');
        }

        if (borderStyle != null) {
            cssValueBuilder.append(borderStyle.getCssValue()).append(' ');
        }

        if (borderColorCssValues != null) {
            cssValueBuilder.append(borderColorCssValues.getValue()).append(' ');
        }

        final String trimmedCssValue = StringBuilderUtil
                .getTrimmedString(cssValueBuilder).toString();
        cssValue = trimmedCssValue.isEmpty() ? INHERIT : trimmedCssValue;

        this.borderStyle = borderStyle;

        if (getStateChangeInformer() != null) {
            getStateChangeInformer().stateChanged(this);
        }
        return this;
    }

public
Border
setBorderStyle
(
final
BorderStyle
borderStyle
)
{
if
(
borderStyle
==
BorderStyle
.
INITIAL
||
borderStyle
==
BorderStyle
.
INHERIT
)
{
throw
new
InvalidValueException
(
"the given borderStyle cannot be "
+
borderStyle
.
getCssValue
(
)
)
;
}
final
StringBuilder
cssValueBuilder
=
new
StringBuilder
(
)
;
if
(
borderWidthValue
!=
)
{
cssValueBuilder
.
append
(
borderWidthValue
)
.
append
(
'
'
)
;
}
if
(
borderStyle
!=
)
{
cssValueBuilder
.
append
(
borderStyle
.
getCssValue
(
)
)
.
append
(
'
'
)
;
}
if
(
borderColorCssValues
!=
)
{
cssValueBuilder
.
append
(
borderColorCssValues
.
getValue
(
)
)
.
append
(
'
'
)
;
}
final
String
trimmedCssValue
=
StringBuilderUtil
.
getTrimmedString
(
cssValueBuilder
)
.
toString
(
)
;
cssValue
=
trimmedCssValue
.
isEmpty
(
)
INHERIT
:
trimmedCssValue
;
this
.
borderStyle
=
borderStyle
;
if
(
getStateChangeInformer
(
)
!=
)
{
getStateChangeInformer
(
)
.
stateChanged
(
this
)
;
}
return
this
;
}

to set the border style.

@param borderStyle
@return the current object.
@author WFF
@since 1.0.0


public void setValue(final UUID uuid) {
        if (uuid != null) {
            super.setAttributeValue(uuid.toString());
            this.uuid = uuid;
        }
    }

public void setValue ( final UUID uuid ) { if ( uuid != null ) { super . setAttributeValue ( uuid . toString ( ) ) ; this . uuid = uuid ; } }

value for the id attribute.

@param uuid
@since 1.0.0
@author WFF


public static ByteBuffer merge(final ByteBuffer... dataArray) {
        int totalCapacity = 0;
        for (final ByteBuffer data : dataArray) {
            totalCapacity += data.capacity();
        }
        final ByteBuffer wholeData = ByteBuffer.allocate(totalCapacity);
        for (final ByteBuffer data : dataArray) {
            wholeData.put(data);
        }
        wholeData.flip();

        return wholeData;
    }

public static ByteBuffer merge ( final ByteBuffer ... dataArray ) { int totalCapacity = 0 ; for ( final ByteBuffer data : dataArray ) { totalCapacity += data . capacity ( ) ; } final ByteBuffer wholeData = ByteBuffer . allocate ( totalCapacity ) ; for ( final ByteBuffer data : dataArray ) { wholeData . put ( data ) ; } wholeData . flip ( ) ; return wholeData ; }

Merges and returns ByteBuffer from the given dataArray. The ByteBuffer
will be returned after flip.

@param dataArray
the ByteByffers to merge
@return a single ByteBuffer after flip merged from all ByteBuffer objects
from dataArray.

@since 3.0.2

Merges and returns ByteBuffer from the given dataArray . The ByteBuffer will be returned after flip .


public void removeAllCssProperties() {
        final long stamp = lock.writeLock();
        try {
            cssProperties.clear();
            abstractCssPropertyClassObjects.clear();
            super.removeAllFromAttributeValueMap();
        } finally {
            lock.unlockWrite(stamp);
        }

    }

public void removeAllCssProperties ( ) { final long stamp = lock . writeLock ( ) ; try { cssProperties . clear ( ) ; abstractCssPropertyClassObjects . clear ( ) ; super . removeAllFromAttributeValueMap ( ) ; } finally { lock . unlockWrite ( stamp ) ; } }

Removes all css properties

@since 3.0.1


public boolean contains(final CssProperty cssProperty) {
        final long stamp = lock.readLock();
        try {
            return cssProperties.contains(cssProperty);
        } finally {
            lock.unlockRead(stamp);
        }
    }

public boolean contains ( final CssProperty cssProperty ) { final long stamp = lock . readLock ( ) ; try { return cssProperties . contains ( cssProperty ) ; } finally { lock . unlockRead ( stamp ) ; } }

Checks if the given cssProperty object exists in this style object.

@return

@since 3.0.1

Checks if the given cssProperty object exists in this style object .


Map<String, CssProperty> getCssPropertiesAsMap(final boolean rebuild) {
        if (rebuild || !loadedOnce) {
            synchronized (cssProperties) {
                if (rebuild || !loadedOnce) {
                    cssProperties.clear();
                    load(cssProperties);
                    loadedOnce = true;
                    setModified(true);
                }
            }
        }
        return cssPropertiesAsMap;
    }

Map < String , CssProperty > getCssPropertiesAsMap ( final boolean rebuild ) { if ( rebuild || ! loadedOnce ) { synchronized ( cssProperties ) { if ( rebuild || ! loadedOnce ) { cssProperties . clear ( ) ; load ( cssProperties ) ; loadedOnce = true ; setModified ( true ) ; } } } return cssPropertiesAsMap ; }

rebuild true to rebuild, the load method will be invoked again.

@return the cssProperties as map with key as the cssName and value as
{@code CssProperty}.
@since 1.0.0
@author WFF

rebuild true to rebuild the load method will be invoked again .


public Collection<AbstractHtml> findTagsByAttribute(
            final AbstractAttribute attribute) throws NullValueException {

        if (attribute == null) {
            throw new NullValueException("attribute cannot be null");
        }

        final Collection<AbstractHtml> tags = new HashSet<>();

        for (final AbstractHtml ownerTag : attribute.getOwnerTags()) {
            if (browserPage.contains(ownerTag)) {
                tags.add(ownerTag);
            }
        }

        return tags;
    }

public
Collection
<
AbstractHtml
>
findTagsByAttribute
(
final
AbstractAttribute
attribute
)
throws
NullValueException
{
if
(
attribute
==
)
{
throw
new
NullValueException
(
"attribute cannot be null"
)
;
}
final
Collection
<
AbstractHtml
>
tags
=
new
HashSet
<>
(
)
;
for
(
final
AbstractHtml
ownerTag
:
attribute
.
getOwnerTags
(
)
)
{
if
(
browserPage
.
contains
(
ownerTag
)
)
{
tags
.
add
(
ownerTag
)
;
}
}
return
tags
;
}

Finds tags by attribute instance.

@param attribute
@return all tags which are consuming the given attribute instance. It
returns the only tags consuming the given attribute object which
are available in browserPage.
@throws NullValueException
if the {@code attribute} is null
@since 2.1.8
@author WFF


public AbstractHtml findOneTagByAttribute(
            final AbstractAttribute attribute) {

        if (attribute == null) {
            throw new NullValueException("attribute cannot be null");
        }

        for (final AbstractHtml ownerTag : attribute.getOwnerTags()) {
            if (browserPage.contains(ownerTag)) {
                return ownerTag;
            }
        }

        return null;
    }

public
AbstractHtml
findOneTagByAttribute
(
final
AbstractAttribute
attribute
)
{
if
(
attribute
==
)
{
throw
new
NullValueException
(
"attribute cannot be null"
)
;
}
for
(
final
AbstractHtml
ownerTag
:
attribute
.
getOwnerTags
(
)
)
{
if
(
browserPage
.
contains
(
ownerTag
)
)
{
return
ownerTag
;
}
}
return
;
}

Finds one tag by attribute instance.

@param attribute
@return the first matching tag consuming the given attribute instance.
There must be a consuming tag which is available in the
browserPage instance otherwise returns null.
@throws NullValueException
if the {@code attribute } is null
@since 2.1.8
@author WFF


public Collection<AbstractAttribute> findAllAttributes(
            final boolean parallel) {
        final Collection<Lock> locks = getReadLocks(rootTags);
        for (final Lock lock : locks) {
            lock.lock();
        }
        try {
            return buildAllAttributesStream(parallel)
                    .collect(Collectors.toSet());
        } finally {
            for (final Lock lock : locks) {
                lock.unlock();
            }
        }
    }

public Collection < AbstractAttribute > findAllAttributes ( final boolean parallel ) { final Collection < Lock > locks = getReadLocks ( rootTags ) ; for ( final Lock lock : locks ) { lock . lock ( ) ; } try { return buildAllAttributesStream ( parallel ) . collect ( Collectors . toSet ( ) ) ; } finally { for ( final Lock lock : locks ) { lock . unlock ( ) ; } } }

Finds all attributes from all tags.

@param parallel
true to internally use parallel stream. If true it
will split the finding task to different batches and
will execute the batches in different threads in
parallel consuming all CPUs. It will perform faster
in finding from extremely large number of tags but at
the same time it will less efficient in finding from
small number of tags.
@return the collection of all attributes
@since 3.0.0
@author WFF


public Stream<AbstractAttribute> buildAllAttributesStream(
            final boolean parallel) {
        final Stream<AbstractAttribute> attributesStream = buildAllTagsStream(
                parallel).filter(tag -> tag.getAttributes() != null)
                        .map(tag -> {
                            return tag.getAttributes();
                        }).flatMap(attributes -> attributes.stream());
        return attributesStream;
    }

public Stream < AbstractAttribute > buildAllAttributesStream ( final boolean parallel ) { final Stream < AbstractAttribute > attributesStream = buildAllTagsStream ( parallel ) . filter ( tag -> tag . getAttributes ( ) != null ) . map ( tag -> { return tag . getAttributes ( ) ; } ) . flatMap ( attributes -> attributes . stream ( ) ) ; return attributesStream ; }

Finds all attributes as stream from all tags.

@param parallel
true to internally use parallel stream. If true it
will split the finding task to different batches and
will execute the batches in different threads in
parallel consuming all CPUs. It will perform faster
in finding from extremely large number of tags but at
the same time it will less efficient in finding from
small number of tags.
@return the stream of all attributes
@since 3.0.0
@author WFF

Finds all attributes as stream from all tags .


public static Collection<AbstractAttribute> findAllAttributes(
            final boolean parallel, final AbstractHtml... fromTags)
            throws NullValueException {

        if (fromTags == null) {
            throw new NullValueException("fromTags cannot be null");
        }

        final Collection<Lock> locks = getReadLocks(fromTags);
        for (final Lock lock : locks) {
            lock.lock();
        }
        try {
            return getAllNestedChildrenIncludingParent(parallel, fromTags)
                    .filter(tag -> tag.getAttributes() != null).map(tag -> {
                        return tag.getAttributes();
                    }).flatMap(attributes -> attributes.stream())
                    .collect(Collectors.toSet());
        } finally {
            for (final Lock lock : locks) {
                lock.unlock();
            }
        }
    }

public
static
Collection
<
AbstractAttribute
>
findAllAttributes
(
final
boolean
parallel
,
final
AbstractHtml
...
fromTags
)
throws
NullValueException
{
if
(
fromTags
==
)
{
throw
new
NullValueException
(
"fromTags cannot be null"
)
;
}
final
Collection
<
Lock
>
locks
=
getReadLocks
(
fromTags
)
;
for
(
final
Lock
lock
:
locks
)
{
lock
.
lock
(
)
;
}
try
{
return
getAllNestedChildrenIncludingParent
(
parallel
,
fromTags
)
.
filter
(
tag
->
tag
.
getAttributes
(
)
!=
)
.
map
(
tag
->
{
return
tag
.
getAttributes
(
)
;
}
)
.
flatMap
(
attributes
->
attributes
.
stream
(
)
)
.
collect
(
Collectors
.
toSet
(
)
)
;
}
finally
{
for
(
final
Lock
lock
:
locks
)
{
lock
.
unlock
(
)
;
}
}
}

Finds all attributes from the given tags

@param parallel
true to internally use parallel stream. If true it
will split the finding task to different batches and
will execute the batches in different threads in
parallel consuming all CPUs. It will perform faster
in finding from extremely large number of tags but at
the same time it will less efficient in finding from
small number of tags.
@param fromTags
the tags to find the attributes from.
@return the all attributes from the given tags including the nested tags.
@throws NullValueException
if {@code fromTags} is null
@since 3.0.0
@author WFF


public boolean exists(final AbstractHtml tag)
            throws NullValueException, InvalidTagException {
        if (tag == null) {
            throw new NullValueException("tag cannot be null");
        }
        if (NoTag.class.isAssignableFrom(tag.getClass())) {
            throw new InvalidTagException(
                    "classes like NoTag.class cannot be used to find tags as it's not a logical tag in behaviour.");
        }
        return browserPage.contains(tag);
    }

Checks the existence of a tag instance.

@param tag
@return true if the given tag instance exists anywhere in the browser
page.
@throws NullValueException
if the tag is null
@throws InvalidTagException
if the given tag is {@code NoTag}.
@since 2.1.8
@author WFF

Checks the existence of a tag instance .


public boolean exists(final AbstractAttribute attribute)
            throws NullValueException {

        if (attribute == null) {
            throw new NullValueException("attribute cannot be null");
        }

        for (final AbstractHtml ownerTag : attribute.getOwnerTags()) {
            if (browserPage.contains(ownerTag)) {
                return true;
            }
        }

        return false;
    }

public
boolean
exists
(
final
AbstractAttribute
attribute
)
throws
NullValueException
{
if
(
attribute
==
)
{
throw
new
NullValueException
(
"attribute cannot be null"
)
;
}
for
(
final
AbstractHtml
ownerTag
:
attribute
.
getOwnerTags
(
)
)
{
if
(
browserPage
.
contains
(
ownerTag
)
)
{
return
true
;
}
}
return
false
;
}

Checks the existence of an attribute instance.

@param attribute
@return true if the given attribute instance exists anywhere in the
browser page.
@throws NullValueException
if the {@code attribute} is null
@since 2.1.8
@author WFF

Checks the existence of an attribute instance .


public static Stream<AbstractAttribute> buildAllAttributesStream(
            final boolean parallel, final AbstractHtml... fromTags) {
        final Stream<AbstractAttribute> attributesStream = getAllNestedChildrenIncludingParent(
                parallel, fromTags).filter(tag -> tag.getAttributes() != null)
                        .map(tag -> {
                            return tag.getAttributes();
                        }).flatMap(attributes -> attributes.stream());
        return attributesStream;
    }

public static Stream < AbstractAttribute > buildAllAttributesStream ( final boolean parallel , final AbstractHtml ... fromTags ) { final Stream < AbstractAttribute > attributesStream = getAllNestedChildrenIncludingParent ( parallel , fromTags ) . filter ( tag -> tag . getAttributes ( ) != null ) . map ( tag -> { return tag . getAttributes ( ) ; } ) . flatMap ( attributes -> attributes . stream ( ) ) ; return attributesStream ; }

Builds all attributes stream from the given tags.

@param parallel
true to internally use parallel stream. If true it
will split the finding task to different batches and
will execute the batches in different threads in
parallel consuming all CPUs. It will perform faster
in finding from extremely large number of tags but at
the same time it will less efficient in finding from
small number of tags.
@param fromTags
the tags to build stream of nested children's
attributes from.
@return {@code Stream<AbstractAttribute>}
@since 3.0.0
@author WFF

Builds all attributes stream from the given tags .


public String getChildText() {
        final List<AbstractHtml> children = getChildren();
        if (children.size() > 0) {
            final StringBuilder builder = new StringBuilder();
            for (final AbstractHtml child : children) {
                builder.append(child.toHtmlString());
            }
            return builder.toString();
        }
        return "";
    }

public String getChildText ( ) { final List < AbstractHtml > children = getChildren ( ) ; if ( children . size ( ) > 0 ) { final StringBuilder builder = new StringBuilder ( ) ; for ( final AbstractHtml child : children ) { builder . append ( child . toHtmlString ( ) ) ; } return builder . toString ( ) ; } return "" ; }

gets the child text set for this tag.

@return the child text set for this tag in string format. If there is no
children/child text then will return empty string.
@since 2.1.4


private void writeByChunk(final byte[] bytes) throws IOException {

        final int chunkSize = this.chunkSize;

        if (bytes.length == 0) {
            return;
        }

        if (chunkSize < bytes.length && chunkSize > 0) {

            int remaining = bytes.length;

            int offset = 0;

            while (remaining > 0) {
                if (chunkSize < remaining) {
                    os.write(bytes, offset, chunkSize);
                    remaining -= chunkSize;
                    offset += chunkSize;
                } else {
                    os.write(bytes, offset, remaining);
                    remaining = 0;
                }
            }

        } else {
            os.write(bytes);
        }
    }

private void writeByChunk ( final byte [ ] bytes ) throws IOException { final int chunkSize = this . chunkSize ; if ( bytes . length == 0 ) { return ; } if ( chunkSize < bytes . length && chunkSize > 0 ) { int remaining = bytes . length ; int offset = 0 ; while ( remaining > 0 ) { if ( chunkSize < remaining ) { os . write ( bytes , offset , chunkSize ) ; remaining -= chunkSize ; offset += chunkSize ; } else { os . write ( bytes , offset , remaining ) ; remaining = 0 ; } } } else { os . write ( bytes ) ; } }

writes maximum bytes at chuckSize

@param bytes
@throws IOException
@since 1.1.2
@author WFF


public EmbeddedTomcat setContextPath(String contextPath) {

		if (contextPath == null
				|| !contextPath.equals("") && !contextPath.startsWith("/")) {
			throw new IllegalArgumentException(
					"contextPath must be the empty string \"\" or a path starting with /");
		}

		this.contextPath = contextPath;
		return this;
	}

Sets the contextPath for the webapplication

@param contextPath The new contextPath. Has to start with / or is the empty ""
string
@return The embedded Tomcat


public EmbeddedTomcat setContextFile(String contextFile) {
		try {
			this.contextFileURL = new File(contextFile).toURI().toURL();
		}
		catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
		return this;
	}

public EmbeddedTomcat setContextFile ( String contextFile ) { try { this . contextFileURL = new File ( contextFile ) . toURI ( ) . toURL ( ) ; } catch ( MalformedURLException e ) { throw new RuntimeException ( e ) ; } return this ; }

Sets the location of the context file that configures this web application

@param contextFile Location of the context file
@return The embedded Tomcat instance


@Deprecated
	public EmbeddedTomcat addContextEnvironmentAndResourceFromFile(String contextFile) {
		try {
			setContextFile(new File(contextFile).toURI().toURL());
		}
		catch (MalformedURLException e) {
			throw new RuntimeException(e);
		}
		return this;
	}

Read ContextEnvironment and ContextResource definition from a text file.

@param contextFile Location to a context file
@return The embedded Tomcat
@deprecated use {@link #setContextFile(String)}

Read ContextEnvironment and ContextResource definition from a text file .


public static <T> Filter<T> filter(final Path.Filter filter, final Content.Type<T> contentType) {
		return new Filter<T>() {
			@Override
			public boolean matches(Path.ID id, Content.Type<T> ct) {
				return ct == contentType && filter.matches(id);
			}
			@Override
			public boolean matchesSubpath(Path.ID id) {
				return filter.matchesSubpath(id);
			}
			@Override
			public String toString() {
				return filter.toString();
			}
		};
	}

public static < T > Filter < T > filter ( final Path . Filter filter , final Content . Type < T > contentType ) { return new Filter < T > ( ) { @ Override public boolean matches ( Path . ID id , Content . Type < T > ct ) { return ct == contentType && filter . matches ( id ) ; } @ Override public boolean matchesSubpath ( Path . ID id ) { return filter . matchesSubpath ( id ) ; } @ Override public String toString ( ) { return filter . toString ( ) ; } } ; }

Construct a content filter from a path filter and a content type.

@param filter --- path filter
@param contentType
@return

Construct a content filter from a path filter and a content type .


public static <T> Filter<T> or(final Filter<T> f1, final Filter<T> f2) {
		return new Filter<T>() {
			@Override
			public boolean matches(Path.ID id, Content.Type<T> ct) {
				return f1.matches(id, ct) || f2.matches(id, ct);
			}
			@Override
			public boolean matchesSubpath(Path.ID id) {
				return f1.matchesSubpath(id) || f2.matchesSubpath(id);
			}
			@Override
			public String toString() {
				return f1.toString() + "|" + f2.toString();
			}
		};
	}

public static < T > Filter < T > or ( final Filter < T > f1 , final Filter < T > f2 ) { return new Filter < T > ( ) { @ Override public boolean matches ( Path . ID id , Content . Type < T > ct ) { return f1 . matches ( id , ct ) || f2 . matches ( id , ct ) ; } @ Override public boolean matchesSubpath ( Path . ID id ) { return f1 . matchesSubpath ( id ) || f2 . matchesSubpath ( id ) ; } @ Override public String toString ( ) { return f1 . toString ( ) + "|" + f2 . toString ( ) ; } } ; }

Combine two filters together produce one filter whose items must be
matched by at least one of the original filters.

@param f1
@param f2
@return

Combine two filters together produce one filter whose items must be matched by at least one of the original filters .


private void checkNotEof() {
		skipWhiteSpace();
		if (index >= tokens.size()) {
			if (index > 0) {
				syntaxError("unexpected end-of-file", tokens.get(index - 1));
			} else {
				// I believe this is actually dead-code, since checkNotEof()
				// won't be called before at least one token is matched.
				throw new SyntacticException("unexpected end-of-file", file.getEntry(), null);
			}
		}
	}

Check that the End-Of-File has not been reached. This method should be
called from contexts where we are expecting something to follow.

Check that the End - Of - File has not been reached . This method should be called from contexts where we are expecting something to follow .


private boolean isLineSpace(Token token) {
		return token.kind == Token.Kind.Indent || token.kind == Token.Kind.LineComment;
	}

private boolean isLineSpace ( Token token ) { return token . kind == Token . Kind . Indent || token . kind == Token . Kind . LineComment ; }

Define what is considered to be linespace.

@param token
@return

Define what is considered to be linespace .


protected String parseString(String v) {
		/*
		 * Parsing a string requires several steps to be taken. First, we need
		 * to strip quotes from the ends of the string.
		 */
		v = v.substring(1, v.length() - 1);

		StringBuffer result = new StringBuffer();
		// Second, step through the string and replace escaped characters
		for (int i = 0; i < v.length(); i++) {
			if (v.charAt(i) == '\\') {
				if (v.length() <= i + 1) {
					throw new RuntimeException("unexpected end-of-string");
				} else {
					char replace = 0;
					int len = 2;
					switch (v.charAt(i + 1)) {
					case 'b':
						replace = '\b';
						break;
					case 't':
						replace = '\t';
						break;
					case 'n':
						replace = '\n';
						break;
					case 'f':
						replace = '\f';
						break;
					case 'r':
						replace = '\r';
						break;
					case '"':
						replace = '\"';
						break;
					case '\'':
						replace = '\'';
						break;
					case '\\':
						replace = '\\';
						break;
					case 'u':
						len = 6; // unicode escapes are six digits long,
						// including "slash u"
						String unicode = v.substring(i + 2, i + 6);
						replace = (char) Integer.parseInt(unicode, 16); // unicode
						i = i + 5;
						break;
					default:
						throw new RuntimeException("unknown escape character");
					}
					result = result.append(replace);
					i = i + 1;
				}
			} else {
				result = result.append(v.charAt(i));
			}
		}
		return result.toString();
	}

Parse a string constant whilst interpreting all escape characters.

@param v
@return

Parse a string constant whilst interpreting all escape characters .


public List<Token> scan() throws Error {
		ArrayList<Token> tokens = new ArrayList<>();
		int pos = 0;
		while (pos < input.length()) {
			int start = pos;
			for (int i = 0; i != rules.length; ++i) {
				Rule rule = rules[i];
				int left = input.length() - pos;
				if (left >= rule.lookahead()) {
					Token t = rule.match(input, pos);
					if (t != null) {
						tokens.add(t);
						pos = pos + t.text.length();
						break; // restart rule application loop
					}
				}
			}
			if(pos == start) {
				throw new Error("unrecognised token encountered (" + input.charAt(pos) + ")",pos);
			}
		}
		return tokens;
	}

public
List
<
Token
>
scan
(
)
throws
Error
{
ArrayList
<
Token
>
tokens
=
new
ArrayList
<>
(
)
;
int
pos
=
0
;
while
(
pos
<
input
.
length
(
)
)
{
int
start
=
pos
;
for
(
int
i
=
0
;
i
!=
rules
.
length
;
++
i
)
{
Rule
rule
=
rules
[
i
]
;
int
left
=
input
.
length
(
)
pos
;
if
(
left
>=
rule
.
lookahead
(
)
)
{
Token
t
=
rule
.
match
(
input
,
pos
)
;
if
(
t
!=
)
{
tokens
.
add
(
t
)
;
pos
=
pos
+
t
.
text
.
length
(
)
;
break
;
// restart rule application loop
}
}
}
if
(
pos
==
start
)
{
throw
new
Error
(
"unrecognised token encountered ("
+
input
.
charAt
(
pos
)
+
")"
,
pos
)
;
}
}
return
tokens
;
}

Scan the given input stream and produce a list of tokens, or an error.

@return

Scan the given input stream and produce a list of tokens or an error .


protected Command.Template parse(Command.Descriptor root, String[] args, int index) {
		ArrayList<Command.Option> options = new ArrayList<>();
		ArrayList<String> arguments = new ArrayList<>();
		//
		Command.Template sub = null;
		while (index < args.length) {
			String arg = args[index];
			if (isLongOption(arg)) {
				options.add(parseLongOption(root, args[index]));
			} else if (isCommand(arg, root.getCommands())) {
				Command.Descriptor cmd = getCommandDescriptor(arg, root.getCommands());
				sub = parse(cmd, args, index + 1);
				break;
			} else {
				arguments.add(arg);
			}
			index = index + 1;
		}
		//

		Command.Options optionMap = new OptionsMap(options, root.getOptionDescriptors());
		//
		return new ConcreteTemplate(root, optionMap, arguments, sub);
	}

protected Command . Template parse ( Command . Descriptor root , String [ ] args , int index ) { ArrayList < Command . Option > options = new ArrayList <> ( ) ; ArrayList < String > arguments = new ArrayList <> ( ) ; // Command . Template sub = null ; while ( index < args . length ) { String arg = args [ index ] ; if ( isLongOption ( arg ) ) { options . add ( parseLongOption ( root , args [ index ] ) ) ; } else if ( isCommand ( arg , root . getCommands ( ) ) ) { Command . Descriptor cmd = getCommandDescriptor ( arg , root . getCommands ( ) ) ; sub = parse ( cmd , args , index + 1 ) ; break ; } else { arguments . add ( arg ) ; } index = index + 1 ; } // Command . Options optionMap = new OptionsMap ( options , root . getOptionDescriptors ( ) ) ; // return new ConcreteTemplate ( root , optionMap , arguments , sub ) ; }

Parse a given set of command-line arguments starting from a given index
position to produce an appropriate command template.

@param args
@param index

Parse a given set of command - line arguments starting from a given index position to produce an appropriate command template .


private static Object parseData(String str) {
		if (str.equals("true")) {
			return true;
		} else if (str.equals("false")) {
			return false;
		} else if (Character.isDigit(str.charAt(0))) {
			// number
			return Integer.parseInt(str);
		} else {
			return str;
		}
	}

private
static
Object
parseData
(
String
str
)
{
if
(
str
.
equals
(
"true"
)
)
{
return
true
;
}
else
if
(
str
.
equals
(
"false"
)
)
{
return
false
;
}
else
if
(
Character
.
isDigit
(
str
.
charAt
(
0
)
)
)
{
// number
return
Integer
.
parseInt
(
str
)
;
}
else
{
return
str
;
}
}

Parse a given string representing a data value into an instance of Data.

@param str
The string to be parsed.
@return

Parse a given string representing a data value into an instance of Data .


protected void printUsage() {
		List<Command.Descriptor> descriptors = project.getParent().getCommandDescriptors();
		//
		out.println("usage: wy [--verbose] command [<options>] [<args>]");
		out.println();
		int maxWidth = determineCommandNameWidth(descriptors);
		out.println("Commands:");
		for (Command.Descriptor d : descriptors) {
			out.print("  ");
			out.print(rightPad(d.getName(), maxWidth));
			out.println("   " + d.getDescription());
		}
		out.println();
		out.println("Run `wy help COMMAND` for more information on a command");
	}

Print usage information to the console .


private static int determineCommandNameWidth(List<Command.Descriptor> descriptors) {
		int max = 0;
		for (Command.Descriptor d : descriptors) {
			max = Math.max(max, d.getName().length());
		}
		return max;
	}

private static int determineCommandNameWidth ( List < Command . Descriptor > descriptors ) { int max = 0 ; for ( Command . Descriptor d : descriptors ) { max = Math . max ( max , d . getName ( ) . length ( ) ) ; } return max ; }

Determine the maximum width of any configured command name

@param descriptors
@return


private ZipFile createZipFile(List<Path.Entry<?>> files) throws IOException {
		// The set of known paths
		HashSet<Path.ID> paths = new HashSet<>();
		// The zip file we're creating
		ZipFile zf = new ZipFile();
		// Add each file to zip file
		for (int i = 0; i != files.size(); ++i) {
			Path.Entry<?> file = files.get(i);
			// Extract path
			addPaths(file.id().parent(),paths,zf);
			// Construct filename for given entry
			String filename = file.id().toString() + "." + file.contentType().getSuffix();
			// Extract bytes representing entry
			byte[] contents = readFileContents(file);
			zf.add(new ZipEntry(filename), contents);
		}
		//
		return zf;
	}

private
ZipFile
createZipFile
(
List
<
Path
.
Entry
<
>
>
files
)
throws
IOException
{
// The set of known paths
HashSet
<
Path
.
ID
>
paths
=
new
HashSet
<>
(
)
;
// The zip file we're creating
ZipFile
zf
=
new
ZipFile
(
)
;
// Add each file to zip file
for
(
int
i
=
0
;
i
!=
files
.
size
(
)
;
++
i
)
{
Path
.
Entry
<
>
file
=
files
.
get
(
i
)
;
// Extract path
addPaths
(
file
.
id
(
)
.
parent
(
)
,
paths
,
zf
)
;
// Construct filename for given entry
String
filename
=
file
.
id
(
)
.
toString
(
)
+
"."
+
file
.
contentType
(
)
.
getSuffix
(
)
;
// Extract bytes representing entry
byte
[
]
contents
=
readFileContents
(
file
)
;
zf
.
add
(
new
ZipEntry
(
filename
)
,
contents
)
;
}
//
return
zf
;
}

Given a list of files construct a corresponding ZipFile containing them.

@param files
@return
@throws IOException

Given a list of files construct a corresponding ZipFile containing them .


private byte[] readFileContents(Path.Entry<?> file) throws IOException {
		InputStream in = file.inputStream();
		ByteArrayOutputStream buffer = new ByteArrayOutputStream();
		int nRead;
		// Read bytes in max 1024 chunks
		byte[] data = new byte[1024];
		// Read all bytes from the input stream
		while ((nRead = in.read(data, 0, data.length)) != -1) {
			buffer.write(data, 0, nRead);
		}
		// Done
		buffer.flush();
		return buffer.toByteArray();
	}

private
byte
[
]
readFileContents
(
Path
.
Entry
<
>
file
)
throws
IOException
{
InputStream
in
=
file
.
inputStream
(
)
;
ByteArrayOutputStream
buffer
=
new
ByteArrayOutputStream
(
)
;
int
nRead
;
// Read bytes in max 1024 chunks
byte
[
]
data
=
new
byte
[
1024
]
;
// Read all bytes from the input stream
while
(
(
nRead
=
in
.
read
(
data
,
0
,
data
.
length
)
)
!=
1
)
{
buffer
.
write
(
data
,
0
,
nRead
)
;
}
// Done
buffer
.
flush
(
)
;
return
buffer
.
toByteArray
(
)
;
}

Read the contents of a given file into a byte array.

@param file
@return
@throws IOException

Read the contents of a given file into a byte array .


private Content.Filter createFilter(String filter) {
		String[] split = filter.split("\\.");
		//
		Content.Type contentType = getContentType(split[1]);
		//
		return Content.filter(split[0], contentType);
	}

private Content . Filter createFilter ( String filter ) { String [ ] split = filter . split ( "\\." ) ; // Content . Type contentType = getContentType ( split [ 1 ] ) ; // return Content . filter ( split [ 0 ] , contentType ) ; }

Create a content filter from the string representation.

@param filter
@return

Create a content filter from the string representation .


@Override
	public void write(int i) throws IOException {
		if(count == 0) {
			output.write(i & 0xFF);
		} else {
			write_un(i & 0xFF,8);
		}
	}

@ Override public void write ( int i ) throws IOException { if ( count == 0 ) { output . write ( i & 0xFF ) ; } else { write_un ( i & 0xFF , 8 ) ; } }

Write an unsigned integer value using 8bits using a big-endian encoding.

@param w
@throws IOException

Write an unsigned integer value using 8bits using a big - endian encoding .


public void write_u32(int w) throws IOException {
		write_u8((w >> 24) & 0xFF);
		write_u8((w >> 16) & 0xFF);
		write_u8((w >> 8) & 0xFF);
		write_u8(w & 0xFF);
	}

public void write_u32 ( int w ) throws IOException { write_u8 ( ( w >> 24 ) & 0xFF ) ; write_u8 ( ( w >> 16 ) & 0xFF ) ; write_u8 ( ( w >> 8 ) & 0xFF ) ; write_u8 ( w & 0xFF ) ; }

Write an unsigned integer value using 32bits using a big-endian encoding.

@param w
@throws IOException

Write an unsigned integer value using 32bits using a big - endian encoding .


public void write_un(int bits, int n) throws IOException {
		int mask = 1;
		for(int i=0;i<n;++i) {
			boolean bit = (bits & mask) != 0;
			write_bit(bit);
			mask = mask << 1;
		}
	}

public void write_un ( int bits , int n ) throws IOException { int mask = 1 ; for ( int i = 0 ; i < n ; ++ i ) { boolean bit = ( bits & mask ) != 0 ; write_bit ( bit ) ; mask = mask << 1 ; } }

Write an unsigned integer value using n bits using a big-endian encoding.

@param w
@throws IOException

Write an unsigned integer value using n bits using a big - endian encoding .


public static void printSyntacticMarkers(PrintStream output, Collection<Path.Entry<?>> sources, Path.Entry<?> target) throws IOException {
		// Extract all syntactic markers from entries in the build graph
		List<SyntacticItem.Marker> items = extractSyntacticMarkers(target);
		// For each marker, print out error messages appropriately
		for (int i = 0; i != items.size(); ++i) {
			// Log the error message
			printSyntacticMarkers(output, sources, items.get(i));
		}
	}

Print out syntactic markers for all entries in the build graph. This requires
going through all entries, extracting the markers and then printing them.

@param executor
@throws IOException

Print out syntactic markers for all entries in the build graph . This requires going through all entries extracting the markers and then printing them .


private static void printSyntacticMarkers(PrintStream output, Collection<Path.Entry<?>> sources, SyntacticItem.Marker marker) {
		//
		Path.Entry<?> source = getSourceEntry(sources,marker.getSource());
		//
		Span span = marker.getTarget().getAncestor(AbstractCompilationUnit.Attribute.Span.class);
		// Read the enclosing line so we can print it
		EnclosingLine line = readEnclosingLine(source, span);
		// Sanity check we found it
		if(line != null) {
			// print the error message
			output.println(source.location() + ":" + line.lineNumber + ": " + marker.getMessage());
			// Finally print the line highlight
			printLineHighlight(output, line);
		} else {
			output.println(source.location() + ":?: " + marker.getMessage());
		}
	}

Print out an individual syntactic markers.

@param marker

Print out an individual syntactic markers .


private static List<SyntacticItem.Marker> extractSyntacticMarkers(Path.Entry<?>... binaries) throws IOException {
		List<SyntacticItem.Marker> annotated = new ArrayList<>();
		//
		for (Path.Entry<?> binary : binaries) {
			Object o = binary.read();
			// If the object in question can be decoded as a syntactic heap then we can look
			// for syntactic messages.
			if (o instanceof SyntacticHeap) {
				SyntacticHeap h = (SyntacticHeap) o;
				extractSyntacticMarkers(h.getRootItem(), annotated, new BitSet());
			}
		}
		//
		return annotated;
	}

Traverse the various binaries which have been generated looking for error
messages.

@param binaries
@return
@throws IOException

Traverse the various binaries which have been generated looking for error messages .


@Override
	public <T extends SyntacticItem> T getParent(Class<T> kind) {
		return parent.getParent(this, kind);
	}

@ Override public < T extends SyntacticItem > T getParent ( Class < T > kind ) { return parent . getParent ( this , kind ) ; }

Get the first syntactic item of a given kind which refers to this item.

@param kind
@return

Get the first syntactic item of a given kind which refers to this item .


@Override
	public <T extends SyntacticItem> List<T> getParents(Class<T> kind) {
		return parent.getParents(this, kind);
	}

@ Override public < T extends SyntacticItem > List < T > getParents ( Class < T > kind ) { return parent . getParents ( this , kind ) ; }

Get all syntactic items of a given kind which refer to this item.

@param kind
@return

Get all syntactic items of a given kind which refer to this item .


@Override
	public <T extends SyntacticItem> T getAncestor(Class<T> kind) {
		return parent.getAncestor(this, kind);
	}

@ Override public < T extends SyntacticItem > T getAncestor ( Class < T > kind ) { return parent . getAncestor ( this , kind ) ; }

Get the first syntactic item of a given kind which refers to this item either
indirectly or directly.

@param kind
@return

Get the first syntactic item of a given kind which refers to this item either indirectly or directly .


public static int[] append(int lhs, int[] rhs) {
		int[] rs = new int[rhs.length+1];
		rs[0] = lhs;
		System.arraycopy(rhs, 0, rs, 1, rhs.length);
		return rs;
	}

public static int [ ] append ( int lhs , int [ ] rhs ) { int [ ] rs = new int [ rhs . length + 1 ] ; rs [ 0 ] = lhs ; System . arraycopy ( rhs , 0 , rs , 1 , rhs . length ) ; return rs ; }

Append an integer item to the front of an array of integer type together,
producing a fresh array whose length equals that the second plus one.

@param lhs
The left-hand side. Elements of this array will be copied
first into the resulting array.
@param rhs
The right-hand side. Elements of this array will be copied
last into the resulting array.
@return

Append an integer item to the front of an array of integer type together producing a fresh array whose length equals that the second plus one .


public static int[] append(int first, int second, int[] rhs) {
		int[] rs = new int[rhs.length+2];
		rs[0] = first;
		rs[1] = second;
		System.arraycopy(rhs, 0, rs, 2, rhs.length);
		return rs;
	}

public static int [ ] append ( int first , int second , int [ ] rhs ) { int [ ] rs = new int [ rhs . length + 2 ] ; rs [ 0 ] = first ; rs [ 1 ] = second ; System . arraycopy ( rhs , 0 , rs , 2 , rhs . length ) ; return rs ; }

Append two integer items to the front of an array of integer type
together, producing a fresh array whose length equals that of the third
plus two.

@param lhs
The left-hand side. Elements of this array will be copied
first into the resulting array.
@param rhs
The right-hand side. Elements of this array will be copied
last into the resulting array.
@return

Append two integer items to the front of an array of integer type together producing a fresh array whose length equals that of the third plus two .


public static int[] append(int[] lhs, int[] rhs) {
		int[] rs = java.util.Arrays.copyOf(lhs, lhs.length + rhs.length);
		System.arraycopy(rhs, 0, rs, lhs.length, rhs.length);
		return rs;
	}

public static int [ ] append ( int [ ] lhs , int [ ] rhs ) { int [ ] rs = java . util . Arrays . copyOf ( lhs , lhs . length + rhs . length ) ; System . arraycopy ( rhs , 0 , rs , lhs . length , rhs . length ) ; return rs ; }

Append two arrays of integer type together, producing a fresh array whose
length equals that of the first and second added together.

@param lhs
The left-hand side. Elements of this array will be copied
first into the resulting array.
@param rhs
The right-hand side. Elements of this array will be copied
last into the resulting array.
@return

Append two arrays of integer type together producing a fresh array whose length equals that of the first and second added together .


public static <T> T[] append(Class<T> type, T lhs, T... rhs) {
		T[] rs = (T[]) Array.newInstance(type, rhs.length+1);
		System.arraycopy(rhs, 0, rs, 1, rhs.length);
		rs[0] = lhs;
		return rs;
	}

public static < T > T [ ] append ( Class < T > type , T lhs , T ... rhs ) { T [ ] rs = ( T [ ] ) Array . newInstance ( type , rhs . length + 1 ) ; System . arraycopy ( rhs , 0 , rs , 1 , rhs . length ) ; rs [ 0 ] = lhs ; return rs ; }

Append an element onto an array of unknown type together, producing a
fresh array whose length equals that of the second plus one.

@param lhs
The left-hand side. This element will be copied
first into the resulting array.
@param rhs
The right-hand side. Elements of this array will be copied
last into the resulting array.
@return

Append an element onto an array of unknown type together producing a fresh array whose length equals that of the second plus one .


public static <T> void addAll(T[] lhs, Collection<T> rhs) {
		for(int i=0;i!=lhs.length;++i) {
			rhs.add(lhs[i]);
		}
	}

public static < T > void addAll ( T [ ] lhs , Collection < T > rhs ) { for ( int i = 0 ; i != lhs . length ; ++ i ) { rhs . add ( lhs [ i ] ) ; } }

Add all elements from an array into a given collection of the same type.

@param lhs
The left-hand side. Elements of this array will be added to
the collection.
@param rhs
The right-hand side. Elements from the left-hand side will be
added to this collection.

Add all elements from an array into a given collection of the same type .


public static String[] toStringArray(Collection<String> items) {
		String[] result = new String[items.size()];
		int i = 0;
		for(String s : items) {
			result[i++] = s;
		}
		return result;
	}

public static String [ ] toStringArray ( Collection < String > items ) { String [ ] result = new String [ items . size ( ) ] ; int i = 0 ; for ( String s : items ) { result [ i ++ ] = s ; } return result ; }

Convert a collection of strings into a string array.

@param items
@return

Convert a collection of strings into a string array .


public static int[] toIntArray(Collection<Integer> items) {
		int[] result = new int[items.size()];
		int i = 0;
		for (Integer v : items) {
			result[i++] = v;
		}
		return result;
	}

public static int [ ] toIntArray ( Collection < Integer > items ) { int [ ] result = new int [ items . size ( ) ] ; int i = 0 ; for ( Integer v : items ) { result [ i ++ ] = v ; } return result ; }

Convert a collection of Integers into an int array.

@param items
@return

Convert a collection of Integers into an int array .


public static <T extends S, S extends Comparable<S>> T[] sortAndRemoveDuplicates(T[] children) {
		int r = isSortedAndUnique(children);
		switch (r) {
		case 0:
			// In this case, the array is already sorted and no duplicates were
			// found.
			return children;
		case 1:
			// In this case, the array is already sorted, but duplicates were
			// found
			return ArrayUtils.sortedRemoveDuplicates(children);
		default:
			// In this case, the array is not sorted and may or may not
			// contain duplicates.
			children = Arrays.copyOf(children, children.length);
			Arrays.sort(children);
			return ArrayUtils.sortedRemoveDuplicates(children);
		}
	}

Sort and remove duplicate items from a given array.

@param children
@return

Sort and remove duplicate items from a given array .


public static <T extends Comparable<T>> int isSortedAndUnique(T[] children) {
		int r = 0;
		for (int i = 1; i < children.length; ++i) {
			int c = children[i - 1].compareTo(children[i]);
			if (c == 0) {
				// Duplicate found, though still could be in sorted order.
				r = 1;
			} else if (c > 0) {
				// NOT in sorted order
				return -1;
			}
		}
		// All good
		return r;
	}

Check whether or not the children of this array are sorted according to
their underlying order. And, if so, whether or not there are any
duplicate elements encountered.

@param children
@return

Check whether or not the children of this array are sorted according to their underlying order . And if so whether or not there are any duplicate elements encountered .


public static <S,T extends Comparable<S>> int compareTo(T[] lhs, T[] rhs) {
		if(lhs.length != rhs.length) {
			return lhs.length - rhs.length;
		} else {
			for(int i=0;i!=lhs.length;++i) {
				int r = lhs[i].compareTo((S) rhs[i]);
				if(r != 0) {
					return r;
				}
			}
			return 0;
		}
	}

public static < S , T extends Comparable < S > > int compareTo ( T [ ] lhs , T [ ] rhs ) { if ( lhs . length != rhs . length ) { return lhs . length - rhs . length ; } else { for ( int i = 0 ; i != lhs . length ; ++ i ) { int r = lhs [ i ] . compareTo ( ( S ) rhs [ i ] ) ; if ( r != 0 ) { return r ; } } return 0 ; } }

A default operator for comparing arrays

@param lhs
@param rhs
@return


public Configuration.Schema getBuildSchema() {
		Configuration.Schema[] schemas = new Configuration.Schema[buildPlatforms.size() + 1];
		schemas[0] = LOCAL_CONFIG_SCHEMA;
		for (int i = 0; i != buildPlatforms.size(); ++i) {
			wybs.lang.Build.Platform platform = buildPlatforms.get(i);
			schemas[i + 1] = platform.getConfigurationSchema();
		}
		return Configuration.toCombinedSchema(schemas);
	}

public Configuration . Schema getBuildSchema ( ) { Configuration . Schema [ ] schemas = new Configuration . Schema [ buildPlatforms . size ( ) + 1 ] ; schemas [ 0 ] = LOCAL_CONFIG_SCHEMA ; for ( int i = 0 ; i != buildPlatforms . size ( ) ; ++ i ) { wybs . lang . Build . Platform platform = buildPlatforms . get ( i ) ; schemas [ i + 1 ] = platform . getConfigurationSchema ( ) ; } return Configuration . toCombinedSchema ( schemas ) ; }

Get the appropriate configuration schema for a project. This defines what
keys are permitted.

@return

Get the appropriate configuration schema for a project . This defines what keys are permitted .


private void createTemplateExtensionPoint() {
		context.create(Command.Descriptor.class, new Module.ExtensionPoint<Command.Descriptor>() {
			@Override
			public void register(Command.Descriptor command) {
				commandDescriptors.add(command);
			}
		});
	}

private void createTemplateExtensionPoint ( ) { context . create ( Command . Descriptor . class , new Module . ExtensionPoint < Command . Descriptor > ( ) { @ Override public void register ( Command . Descriptor command ) { commandDescriptors . add ( command ) ; } } ) ; }

Create the Build.Template extension point. This is where plugins register
their primary functionality for constructing a specific build project.

@param context
@param templates

Create the Build . Template extension point . This is where plugins register their primary functionality for constructing a specific build project .


private void activateDefaultPlugins(Configuration global) {
		// Determine the set of install plugins
		List<Path.ID> plugins = global.matchAll(Trie.fromString("plugins/*"));
		// start modules
		for (Path.ID id : plugins) {
			UTF8 activator = global.get(UTF8.class, id);
			try {
				Class<?> c = Class.forName(activator.toString());
				Module.Activator instance = (Module.Activator) c.newInstance();
				instance.start(context);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

private
void
activateDefaultPlugins
(
Configuration
global
)
{
// Determine the set of install plugins
List
<
Path
.
ID
>
plugins
=
global
.
matchAll
(
Trie
.
fromString
(
"plugins/*"
)
)
;
// start modules
for
(
Path
.
ID
id
:
plugins
)
{
UTF8
activator
=
global
.
get
(
UTF8
.
class
,
id
)
;
try
{
Class
<
>
c
=
Class
.
forName
(
activator
.
toString
(
)
)
;
Module
.
Activator
instance
=
(
Module
.
Activator
)
c
.
newInstance
(
)
;
instance
.
start
(
context
)
;
}
catch
(
ClassNotFoundException
e
)
{
e
.
printStackTrace
(
)
;
}
catch
(
InstantiationException
e
)
{
e
.
printStackTrace
(
)
;
}
catch
(
IllegalAccessException
e
)
{
e
.
printStackTrace
(
)
;
}
}
}

Activate the default set of plugins which the tool uses. Currently this list
is statically determined, but eventually it will be possible to dynamically
add plugins to the system.

@param verbose
@param locations
@return

Activate the default set of plugins which the tool uses . Currently this list is statically determined but eventually it will be possible to dynamically add plugins to the system .


private static String determineSystemRoot() throws IOException {
		String whileyhome = System.getenv("WHILEYHOME");
		if (whileyhome == null) {
			System.err.println("error: WHILEYHOME environment variable not set");
			System.exit(-1);
		}
		return whileyhome;
	}

Determine the system root. That is, the installation directory for the
compiler itself.

@param tool
@return
@throws IOException

Determine the system root . That is the installation directory for the compiler itself .


private static String determineLocalRoot() throws IOException {
		// Determine current working directory
		File dir = new File(".");
		// Traverse up the directory hierarchy
		while (dir != null && dir.exists() && dir.isDirectory()) {
			File wyf = new File(dir + File.separator + "wy.toml");
			if (wyf.exists()) {
				return dir.getPath();
			}
			// Traverse back up the directory hierarchy looking for a suitable directory.
			dir = dir.getParentFile();
		}
		// If we get here then it means we didn't find a root, therefore just use
		// current directory.
		return ".";
	}

Determine where the root of this project is. This is the nearest enclosing
directory containing a "wy.toml" file. The point is that we may be operating
in some subdirectory of the project and want the tool to automatically search
out the real root for us.

@return
@throws IOException

Determine where the root of this project is . This is the nearest enclosing directory containing a wy . toml file . The point is that we may be operating in some subdirectory of the project and want the tool to automatically search out the real root for us .


private static Configuration readConfigFile(String name, String dir, Configuration.Schema... schemas) throws IOException {
		DirectoryRoot root = new DirectoryRoot(dir, BOOT_REGISTRY);
		Path.Entry<ConfigFile> config = root.get(Trie.fromString(name), ConfigFile.ContentType);
		if (config == null) {
			return Configuration.EMPTY;
		}
		try {
			// Read the configuration file
			ConfigFile cf = config.read();
			// Construct configuration according to given schema
			return cf.toConfiguration(Configuration.toCombinedSchema(schemas));
		} catch (SyntacticException e) {
			e.outputSourceError(System.out, false);
			System.exit(-1);
			return null;
		}
	}

Attempt to read a configuration file from a given root.

@param name
@param root
@return
@throws IOException

Attempt to read a configuration file from a given root .


public <T extends Module> T getInstance(Class<T> module) {
		return (T) instances.get(module);
	}

public < T extends Module > T getInstance ( Class < T > module ) { return ( T ) instances . get ( module ) ; }

Get instance of given module within this context, or null if no
instance available.

@param module
@return

Get instance of given module within this context or null if no instance available .


public void start() {

		// Construct the URLClassLoader which will be used to load
		// classes within the modules.
		URL[] urls = new URL[modules.size()];
		for(int i=0;i!=modules.size();++i) {
			urls[i] = modules.get(i).getLocation();
		}
		URLClassLoader loader = new URLClassLoader(urls);

		// Third, active the modules. This will give them the opportunity to
		// register whatever extensions they like.
		activateModules(loader);
	}

Scan and activate all modules on the search path. As part of this, all
module dependencies will be checked.

Scan and activate all modules on the search path . As part of this all module dependencies will be checked .


private void activateModules(URLClassLoader loader) {
		for (int i = 0; i != modules.size(); ++i) {
			Descriptor module = modules.get(i);
			try {
				Class c = loader.loadClass(module.getActivator());
				Module.Activator self = (Module.Activator) c.newInstance();
				Module instance = self.start(context);
				instances.put(c, instance);
				logger.logTimedMessage("Activated module " + module.getId() + " (v" + module.getVersion() + ")", 0, 0);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

private
void
activateModules
(
URLClassLoader
loader
)
{
for
(
int
i
=
0
;
i
!=
modules
.
size
(
)
;
++
i
)
{
Descriptor
module
=
modules
.
get
(
i
)
;
try
{
Class
c
=
loader
.
loadClass
(
module
.
getActivator
(
)
)
;
Module
.
Activator
self
=
(
Module
.
Activator
)
c
.
newInstance
(
)
;
Module
instance
=
self
.
start
(
context
)
;
instances
.
put
(
c
,
instance
)
;
logger
.
logTimedMessage
(
"Activated module "
+
module
.
getId
(
)
+
" (v"
+
module
.
getVersion
(
)
+
")"
,
0
,
0
)
;
}
catch
(
Exception
e
)
{
e
.
printStackTrace
(
)
;
}
}
}

Activate all modules in the order of occurrence in the given list. It is
assumed that all dependencies are already resolved prior to this and all
modules are topologically sorted.

Activate all modules in the order of occurrence in the given list . It is assumed that all dependencies are already resolved prior to this and all modules are topologically sorted .


public void outputSourceError(PrintStream output, boolean brief) {
		Attribute.Span span;
		if (entry == null || element == null) {
			output.println("syntax error: " + getMessage());
			return;
		} else if(element instanceof Attribute.Span) {
			span = (Attribute.Span) element;
		} else  {
			SyntacticHeap parent = element.getHeap();
			span = parent.getParent(element,Attribute.Span.class);
		}
		//
		EnclosingLine enclosing = (span == null) ? null : readEnclosingLine(entry, span);
		if(enclosing == null) {
			output.println("syntax error: " + getMessage());
		} else if(brief) {
			printBriefError(output,entry,enclosing,getMessage());
		} else {
			printFullError(output,entry,enclosing,getMessage());
		}
	}

public
void
outputSourceError
(
PrintStream
output
,
boolean
brief
)
{
Attribute
.
Span
span
;
if
(
entry
==
||
element
==
)
{
output
.
println
(
"syntax error: "
+
getMessage
(
)
)
;
return
;
}
else
if
(
element
instanceof
Attribute
.
Span
)
{
span
=
(
Attribute
.
Span
)
element
;
}
else
{
SyntacticHeap
parent
=
element
.
getHeap
(
)
;
span
=
parent
.
getParent
(
element
,
Attribute
.
Span
.
class
)
;
}
//
EnclosingLine
enclosing
=
(
span
==
)
:
readEnclosingLine
(
entry
,
span
)
;
if
(
enclosing
==
)
{
output
.
println
(
"syntax error: "
+
getMessage
(
)
)
;
}
else
if
(
brief
)
{
printBriefError
(
output
,
entry
,
enclosing
,
getMessage
(
)
)
;
}
else
{
printFullError
(
output
,
entry
,
enclosing
,
getMessage
(
)
)
;
}
}

Output the syntax error to a given output stream in either full or brief
form. Brief form is intended to be used by 3rd party tools and is easier
to parse. In full form, contextual information from the originating
source file is included.

Output the syntax error to a given output stream in either full or brief form . Brief form is intended to be used by 3rd party tools and is easier to parse . In full form contextual information from the originating source file is included .


private boolean ready(Build.Task task) {
		// FIXME: this is not a great solution in the long run for several reasons.
		// Firstly, its possible that a given source will be rebuilt in the near future
		// as a result of some other task and we should be waiting for that.
		Path.Entry<?> target = task.getTarget();
		for(Path.Entry<?> s : task.getSources()) {
			if(s.lastModified() > target.lastModified()) {
				return true;
			}
		}
		return false;
	}

Check whether a given task is ready to be built. This is currently determined
by having at least one source whose timestamp is in front of the target.

@param task
@return

Check whether a given task is ready to be built . This is currently determined by having at least one source whose timestamp is in front of the target .


public static Map<String,Object> parseOptions(List<String> args, OptArg... options) {
		HashMap<String,Object> result = new HashMap<>();
		HashMap<String,OptArg> optmap = new HashMap<>();

		for(OptArg opt : options) {
			if(opt.defaultValue != null) {
				result.put(opt.option, opt.defaultValue);
			}
			optmap.put(opt.option, opt);
			optmap.put(opt.shortForm, opt);
		}

		Iterator<String> iter = args.iterator();
		while(iter.hasNext()) {
			String arg = iter.next();
			if (arg.startsWith("-")) {
				arg = arg.substring(1,arg.length());
				OptArg opt = optmap.get(arg);
				if(opt != null) {
					// matched
					iter.remove(); // remove option from args list
					Kind k = opt.argument;
					if(k != null) {
						String param = iter.next();
						iter.remove();
						k.process(opt.option,param,result);
					} else {
						result.put(opt.option,null);
					}
				} else {
					throw new RuntimeException("unknown command-line option: -" + arg);
				}
			}
		}

		return result;
	}

public
static
Map
<
String
,
Object
>
parseOptions
(
List
<
String
>
args
,
OptArg
...
options
)
{
HashMap
<
String
,
Object
>
result
=
new
HashMap
<>
(
)
;
HashMap
<
String
,
OptArg
>
optmap
=
new
HashMap
<>
(
)
;
for
(
OptArg
opt
:
options
)
{
if
(
opt
.
defaultValue
!=
)
{
result
.
put
(
opt
.
option
,
opt
.
defaultValue
)
;
}
optmap
.
put
(
opt
.
option
,
opt
)
;
optmap
.
put
(
opt
.
shortForm
,
opt
)
;
}
Iterator
<
String
>
iter
=
args
.
iterator
(
)
;
while
(
iter
.
hasNext
(
)
)
{
String
arg
=
iter
.
next
(
)
;
if
(
arg
.
startsWith
(
"-"
)
)
{
arg
=
arg
.
substring
(
1
,
arg
.
length
(
)
)
;
OptArg
opt
=
optmap
.
get
(
arg
)
;
if
(
opt
!=
)
{
// matched
iter
.
remove
(
)
;
// remove option from args list
Kind
k
=
opt
.
argument
;
if
(
k
!=
)
{
String
param
=
iter
.
next
(
)
;
iter
.
remove
(
)
;
k
.
process
(
opt
.
option
,
param
,
result
)
;
}
else
{
result
.
put
(
opt
.
option
,
)
;
}
}
else
{
throw
new
RuntimeException
(
"unknown command-line option: -"
+
arg
)
;
}
}
}
return
result
;
}

Parse options from the list of arguments, removing those which are
recognised. Anything which is not recognised is left as is.

@param args
--- the list of argument strings. This is modified by removing
those which are processed.
@param options
--- the list of OptArg defining which options should be
processed
@throws --- a RuntimeException if an unrecognised option is
encountered (that is, a token starting with '-')..

Parse options from the list of arguments removing those which are recognised . Anything which is not recognised is left as is .


private static Map<String, Object> splitConfig(String str) {
		HashMap<String, Object> options = new HashMap<>();
		String[] splits = str.split(",");
		for (String s : splits) {
			String[] p = s.split("=");
			options.put(p[0], parseValue(p[1]));
		}
		return options;
	}

private static Map < String , Object > splitConfig ( String str ) { HashMap < String , Object > options = new HashMap <> ( ) ; String [ ] splits = str . split ( "," ) ; for ( String s : splits ) { String [ ] p = s . split ( "=" ) ; options . put ( p [ 0 ] , parseValue ( p [ 1 ] ) ) ; } return options ; }

This splits strings of the form "x=y,v=w" into distinct components and
puts them into a map. In the case of a string like "x,y=z" then x is
loaded with the empty string.

@param str
@return

This splits strings of the form x = y v = w into distinct components and puts them into a map . In the case of a string like x y = z then x is loaded with the empty string .


@Override
	public <T extends SyntacticItem> T getParent(SyntacticItem child, Class<T> kind) {
		// FIXME: this could be optimised a *lot*
		for (int i = 0; i != syntacticItems.size(); ++i) {
			SyntacticItem parent = syntacticItems.get(i);
			if(kind.isInstance(parent)) {
				for(int j=0;j!=parent.size();++j) {
					if(parent.get(j) == child) {
						return (T) parent;
					}
				}
			}
		}
		// no match
		return null;
	}

Get first parent of a syntactic item matching the given kind. If no item
was found, then null is returned.

@param child
@param kind
@return

Get first parent of a syntactic item matching the given kind . If no item was found then null is returned .


@Override
	public <T extends SyntacticItem> T getAncestor(SyntacticItem child, Class<T> kind) {
		// FIXME: this could be optimised a *lot*
		if (kind.isInstance(child)) {
			return (T) child;
		} else {
			for (int i = 0; i != syntacticItems.size(); ++i) {
				SyntacticItem parent = syntacticItems.get(i);
				for (int j = 0; j != parent.size(); ++j) {
					// Don't follow cross-references
					if (parent.get(j) == child && !(parent instanceof AbstractCompilationUnit.Ref)) {
						// FIXME: this is not specifically efficient. It would
						// be helpful if SyntacticItems actually contained
						// references to their parent items.
						T tmp = getAncestor(parent, kind);
						if (tmp != null) {
							return tmp;
						}
					}
				}
			}
			// no match
			return null;
		}
	}

Get first ancestor of a syntactic item matching the given kind. If no item
was found, then null is returned.

@param child
@param kind
@return

Get first ancestor of a syntactic item matching the given kind . If no item was found then null is returned .


private static SyntacticItem substitute(SyntacticItem item, SyntacticItem from, SyntacticItem to,
			Map<SyntacticItem, SyntacticItem> mapping) {
		SyntacticItem sItem = mapping.get(item);
		if (sItem != null) {
			// We've previously substituted this item already to produce a
			// potentially updated item. Therefore, simply return that item to
			// ensure the original aliasing structure of the ancestor(s) is
			// properly preserved.
			return sItem;
		} else if (item == from) {
			// We've matched the item being replaced, therefore return the item
			// to which it is being replaced.
			return to;
		} else {
			SyntacticItem nItem = item;
			// We need to recursively descend into children of this item looking
			// for the item to replace. The challenge here is that we need to
			// ensure the original item is preserved as is if there is no
			// change.
			SyntacticItem[] children = item.getAll();
			// Initially, this will alias children. In the event of a child
			// which is actually updated, then this will refer to a new array.
			// That will be the signal that we need to create a new item to
			// return.
			SyntacticItem[] nChildren = children;
			if (children != null) {
				for (int i = 0; i != children.length; ++i) {
					SyntacticItem child = children[i];
					// Check for null, since we don't want to try and substitute
					// into null.
					if (child != null) {
						// Perform the substitution in the given child
						SyntacticItem nChild = substitute(child, from, to, mapping);
						// Check whether anything was actually changed by the
						// substitution.
						if (nChild != child && children == nChildren) {
							// Yes, the child changed and we haven't already
							// cloned the children array. Hence, we'd better
							// clone it now to make sure that the original item
							// is preserved.
							nChildren = Arrays.copyOf(children, children.length);
						}
						nChildren[i] = nChild;
					}
				}
				// Now, clone the original item if necessary. This is only
				// necessary if the children array as been updated in some way.
				if (children != nChildren) {
					// Create the new item which, at this point, will be
					// detached.
					nItem = item.clone(nChildren);
				}
			}
			mapping.put(item, nItem);
			return nItem;
		}
	}

Helper method for above.

@param mapping
A mapping from the original syntactic items to the cloned
syntactic items. This is necessary to preserve the aliasing
structure in the resulting cloned item.


private Content.Type<?> getContentType(String file) {
		List<Content.Type<?>> cts = project.getParent().getContentTypes();
		for (int i = 0; i != cts.size(); ++i) {
			Content.Type<?> ct = cts.get(i);
			String suffix = "." + ct.getSuffix();
			if (file.endsWith(suffix)) {
				return ct;
			}
		}
		// Default is just a binary file
		return Content.BinaryFile;
	}

private
Content
.
Type
<
>
getContentType
(
String
file
)
{
List
<
Content
.
Type
<
>
>
cts
=
project
.
getParent
(
)
.
getContentTypes
(
)
;
for
(
int
i
=
0
;
i
!=
cts
.
size
(
)
;
++
i
)
{
Content
.
Type
<
>
ct
=
cts
.
get
(
i
)
;
String
suffix
=
"."
+
ct
.
getSuffix
(
)
;
if
(
file
.
endsWith
(
suffix
)
)
{
return
ct
;
}
}
// Default is just a binary file
return
Content
.
BinaryFile
;
}

Determine the content type for this file.

@param file
@return

Determine the content type for this file .


public Path.Entry<?> getEntry(String file, Content.Type<?> ct) throws IOException {
		// Strip suffix
		file = file.replace("." + ct.getSuffix(), "");
		// Determine path id
		Path.ID id = Trie.fromString(file);
		// Get the file from the repository root
		return project.getParent().getLocalRoot().get(id, ct);
	}

Get the entry associated with this file.

@param file
@param ct
@return
@throws IOException

Get the entry associated with this file .


private void inspect(Path.Entry<?> entry, Content.Type<?> ct, boolean garbage) throws IOException {
		Object o = entry.read();
		if (o instanceof SyntacticHeap) {
			new SyntacticHeapPrinter(new PrintWriter(out), garbage).print((SyntacticHeap) o);
		} else {
			inspectBinaryFile(readAllBytes(entry.inputStream()));
		}
	}

private void inspect ( Path . Entry < ? > entry , Content . Type < ? > ct , boolean garbage ) throws IOException { Object o = entry . read ( ) ; if ( o instanceof SyntacticHeap ) { new SyntacticHeapPrinter ( new PrintWriter ( out ) , garbage ) . print ( ( SyntacticHeap ) o ) ; } else { inspectBinaryFile ( readAllBytes ( entry . inputStream ( ) ) ) ; } }

Inspect a given path entry.

@param entry
@param ct
@throws IOException


private void inspectBinaryFile(byte[] bytes) {
		for (int i = 0; i < bytes.length; i += width) {
			out.print(String.format("0x%04X ", i));
			// Print out databytes
			for (int j = 0; j < width; ++j) {
				if(j+i < bytes.length) {
					out.print(String.format("%02X ", bytes[i+j]));
				} else {
					out.print("   ");
				}
			}
			//
			for (int j = 0; j < width; ++j) {
				if(j+i < bytes.length) {
					char c = (char) bytes[i+j];
					if(c >= 32 && c < 128) {
						out.print(c);
					} else {
						out.print(".");
					}
				}
			}
			//
			out.println();
		}
	}

private
void
inspectBinaryFile
(
byte
[
]
bytes
)
{
for
(
int
i
=
0
;
i
<
bytes
.
length
;
i
+=
width
)
{
out
.
print
(
String
.
format
(
"0x%04X "
,
i
)
)
;
// Print out databytes
for
(
int
j
=
0
;
j
<
width
;
++
j
)
{
if
(
j
+
i
<
bytes
.
length
)
{
out
.
print
(
String
.
format
(
"%02X "
,
bytes
[
i
+
j
]
)
)
;
}
else
{
out
.
print
(
"   "
)
;
}
}
//
for
(
int
j
=
0
;
j
<
width
;
++
j
)
{
if
(
j
+
i
<
bytes
.
length
)
{
char
c
=
(
char
)
bytes
[
i
+
j
]
;
if
(
c
>=
32
&&
c
<
128
)
{
out
.
print
(
c
)
;
}
else
{
out
.
print
(
"."
)
;
}
}
}
//
out
.
println
(
)
;
}
}

Inspect a given binary file. That is a file for which we don't have a better
inspector.

@param bytes

Inspect a given binary file . That is a file for which we don t have a better inspector .


protected Pair<Integer, SyntacticItem[]> readItems() throws IOException {
		// first, write magic number
		checkHeader();
		// second, determine number of items
		int size = in.read_uv();
		// third, determine the root item
		int root = in.read_uv();
		//
		Bytecode[] items = new Bytecode[size];
		// third, read abstract syntactic items
		for (int i = 0; i != items.length; ++i) {
			items[i] = readItem();
		}
		//
		return new Pair<>(root, constructItems(items));
	}

protected
Pair
<
Integer
,
SyntacticItem
[
]
>
readItems
(
)
throws
IOException
{
// first, write magic number
checkHeader
(
)
;
// second, determine number of items
int
size
=
in
.
read_uv
(
)
;
// third, determine the root item
int
root
=
in
.
read_uv
(
)
;
//
Bytecode
[
]
items
=
new
Bytecode
[
size
]
;
// third, read abstract syntactic items
for
(
int
i
=
0
;
i
!=
items
.
length
;
++
i
)
{
items
[
i
]
=
readItem
(
)
;
}
//
return
new
Pair
<>
(
root
,
constructItems
(
items
)
)
;
}

Read all the items in this heap, returning the identified root item and an
array of all items contained therein.

@return
@throws IOException

Read all the items in this heap returning the identified root item and an array of all items contained therein .


public static Trie fromString(Path.ID id) {
		if(id instanceof Trie) {
			return ((Trie)id);
		}
		Trie r = ROOT;
		for(int i=0;i!=id.size();++i) {
			r = r.append(id.get(i));
		}
		return r;
	}

public static Trie fromString ( Path . ID id ) { if ( id instanceof Trie ) { return ( ( Trie ) id ) ; } Trie r = ROOT ; for ( int i = 0 ; i != id . size ( ) ; ++ i ) { r = r . append ( id . get ( i ) ) ; } return r ; }

Construct a Trie from a Path ID.

@param str
@return