package org.thymeleaf.spring6.processor;

import org.springframework.util.StringUtils;
import org.thymeleaf.context.ITemplateContext;
import org.thymeleaf.engine.AttributeDefinition;
import org.thymeleaf.engine.AttributeDefinitions;
import org.thymeleaf.engine.AttributeName;
import org.thymeleaf.engine.IAttributeDefinitionsAware;
import org.thymeleaf.exceptions.TemplateProcessingException;
import org.thymeleaf.model.IProcessableElementTag;
import org.thymeleaf.processor.element.AbstractAttributeTagProcessor;
import org.thymeleaf.processor.element.IElementTagStructureHandler;
import org.thymeleaf.spring6.context.IThymeleafBindStatus;
import org.thymeleaf.spring6.naming.SpringContextVariableNames;
import org.thymeleaf.spring6.util.FieldUtils;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.util.Validate;

/**
 * Binds an input property with the value in the form's backing bean.
 * <p>
 * Values for {@code th:field} attributes must be selection expressions
 * {@code (*{...})}, as they will be evaluated on the form backing bean and not
 * on the context variables (model attributes in Spring MVC jargon).
 *
 * @author Daniel Fernández
 * @since 3.0.3
 */
public abstract class AbstractSpringFieldTagProcessor
        extends AbstractAttributeTagProcessor
        implements IAttributeDefinitionsAware {

    public static final int ATTR_PRECEDENCE = 1700;
    public static final String ATTR_NAME = "field";

    private static final TemplateMode TEMPLATE_MODE = TemplateMode.HTML;

    protected static final String INPUT_TAG_NAME = "input";
    protected static final String SELECT_TAG_NAME = "select";
    protected static final String OPTION_TAG_NAME = "option";
    protected static final String TEXTAREA_TAG_NAME = "textarea";

    protected static final String ID_ATTR_NAME = "id";
    protected static final String TYPE_ATTR_NAME = "type";
    protected static final String NAME_ATTR_NAME = "name";
    protected static final String VALUE_ATTR_NAME = "value";
    protected static final String CHECKED_ATTR_NAME = "checked";
    protected static final String SELECTED_ATTR_NAME = "selected";
    protected static final String DISABLED_ATTR_NAME = "disabled";
    protected static final String MULTIPLE_ATTR_NAME = "multiple";

    private AttributeDefinition discriminatorAttributeDefinition;
    protected AttributeDefinition idAttributeDefinition;
    protected AttributeDefinition typeAttributeDefinition;
    protected AttributeDefinition nameAttributeDefinition;
    protected AttributeDefinition valueAttributeDefinition;
    protected AttributeDefinition checkedAttributeDefinition;
    protected AttributeDefinition selectedAttributeDefinition;
    protected AttributeDefinition disabledAttributeDefinition;
    protected AttributeDefinition multipleAttributeDefinition;

    private final String discriminatorAttrName;
    private final String[] discriminatorAttrValues;
    private final boolean removeAttribute;

    public AbstractSpringFieldTagProcessor(
            final String dialectPrefix, final String elementName,
            final String discriminatorAttrName, final String[] discriminatorAttrValues,
            final boolean removeAttribute) {
        super(TEMPLATE_MODE, dialectPrefix, elementName, false, ATTR_NAME, true, ATTR_PRECEDENCE, false);
        this.discriminatorAttrName = discriminatorAttrName;
        this.discriminatorAttrValues = discriminatorAttrValues;
        this.removeAttribute = removeAttribute;
    }

    public void setAttributeDefinitions(final AttributeDefinitions attributeDefinitions) {
        Validate.notNull(attributeDefinitions, "Attribute Definitions cannot be null");
        // We precompute the AttributeDefinitions in order to being able to use much
        // faster methods for setting/replacing attributes on the ElementAttributes implementation
        this.discriminatorAttributeDefinition =
                (this.discriminatorAttrName != null? attributeDefinitions.forName(TEMPLATE_MODE, this.discriminatorAttrName) : null);
        this.idAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, ID_ATTR_NAME);
        this.typeAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, TYPE_ATTR_NAME);
        this.nameAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, NAME_ATTR_NAME);
        this.valueAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, VALUE_ATTR_NAME);
        this.checkedAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, CHECKED_ATTR_NAME);
        this.selectedAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, SELECTED_ATTR_NAME);
        this.disabledAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, DISABLED_ATTR_NAME);
        this.multipleAttributeDefinition = attributeDefinitions.forName(TEMPLATE_MODE, MULTIPLE_ATTR_NAME);
    }

    private boolean matchesDiscriminator(final IProcessableElementTag tag) {

        if (this.discriminatorAttrName == null) {
            return true;
        }
        final boolean hasDiscriminatorAttr = tag.hasAttribute(this.discriminatorAttributeDefinition.getAttributeName());
        if (this.discriminatorAttrValues == null || this.discriminatorAttrValues.length == 0) {
            return hasDiscriminatorAttr;
        }
        final String discriminatorTagValue =
                (hasDiscriminatorAttr? tag.getAttributeValue(this.discriminatorAttributeDefinition.getAttributeName()) : null);
        for (int i = 0; i < this.discriminatorAttrValues.length; i++) {
            final String discriminatorAttrValue = this.discriminatorAttrValues[i];
            if (discriminatorAttrValue == null) {
                if (!hasDiscriminatorAttr || discriminatorTagValue == null) {
                    return true;
                }
            } else if (discriminatorAttrValue.equals(discriminatorTagValue)) {
                return true;
            }
        }
        return false;

    }

    @Override
    protected void doProcess(
            final ITemplateContext context,
            final IProcessableElementTag tag,
            final AttributeName attributeName, final String attributeValue,
            final IElementTagStructureHandler structureHandler) {

        /*
         * First thing to check is whether this processor really matches, because so far we have asked the engine only
         * to match per attribute (th:field) and host tag (input, select, option...) but we still don't know if the
         * match is complete because we might still need to assess for example that the 'type' attribute has the
         * correct value. For example, the same processor will not be executing on <input type="text" th:field="*{a}"/>
         * and on <input type="checkbox" th:field="*{a}"/>
         */
        if (!matchesDiscriminator(tag)) {
            // Note in this case we do not have to remove the th:field attribute because the correct processor is still
            // to be executed!
            return;
        }

        if (this.removeAttribute) {
            structureHandler.removeAttribute(attributeName);
        }

        final IThymeleafBindStatus bindStatus = FieldUtils.getBindStatus(context, attributeValue);

        if (bindStatus == null) {
            throw new TemplateProcessingException(
                    "Cannot process attribute '" + attributeName + "': no associated BindStatus could be found for " +
                    "the intended form binding operations. This can be due to the lack of a proper management of the " +
                    "Spring RequestContext, which is usually done through the ThymeleafView or ThymeleafReactiveView");
        }

        // We set the BindStatus into a local variable just in case we have more BindStatus-related processors to
        // be applied for the same tag, like for example a th:errorclass
        structureHandler.setLocalVariable(SpringContextVariableNames.THYMELEAF_FIELD_BIND_STATUS, bindStatus);

        doProcess(context, tag, attributeName, attributeValue, bindStatus, structureHandler);

    }

    protected abstract void doProcess(
            final ITemplateContext context,
            final IProcessableElementTag tag,
            final AttributeName attributeName,
            final String attributeValue,
            final IThymeleafBindStatus bindStatus,
            final IElementTagStructureHandler structureHandler);

    // This method is designed to be called from the diverse subclasses
    protected final String computeId(
            final ITemplateContext context,
            final IProcessableElementTag tag,
            final String name, final boolean sequence) {

        String id = tag.getAttributeValue(this.idAttributeDefinition.getAttributeName());
        if (!org.thymeleaf.util.StringUtils.isEmptyOrWhitespace(id)) {
            return (StringUtils.hasText(id) ? id : null);
        }

        id = FieldUtils.idFromName(name);
        if (sequence) {
            final Integer count = context.getIdentifierSequences().getAndIncrementIDSeq(id);
            return id + count.toString();
        }
        return id;

    }

}


package org.apache.zookeeper.server;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.CancelledKeyException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.security.cert.Certificate;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.jute.BinaryInputArchive;
import org.apache.jute.BinaryOutputArchive;
import org.apache.jute.Record;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.data.Id;
import org.apache.zookeeper.proto.ReplyHeader;
import org.apache.zookeeper.proto.RequestHeader;
import org.apache.zookeeper.proto.WatcherEvent;
import org.apache.zookeeper.server.NIOServerCnxnFactory.SelectorThread;
import org.apache.zookeeper.server.command.CommandExecutor;
import org.apache.zookeeper.server.command.FourLetterCommands;
import org.apache.zookeeper.server.command.SetTraceMaskCommand;
import org.apache.zookeeper.server.command.NopCommand;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This class handles communication with clients using NIO. There is one per
 * client, but only one thread doing the communication.
 */
public class NIOServerCnxn extends ServerCnxn {
    private static final Logger LOG = LoggerFactory.getLogger(NIOServerCnxn.class);

    private final NIOServerCnxnFactory factory;

    private final SocketChannel sock;

    private final SelectorThread selectorThread;

    private final SelectionKey sk;

    private boolean initialized;

    private final ByteBuffer lenBuffer = ByteBuffer.allocate(4);

    private ByteBuffer incomingBuffer = lenBuffer;

    private final Queue<ByteBuffer> outgoingBuffers =
        new LinkedBlockingQueue<ByteBuffer>();

    private int sessionTimeout;

    private final ZooKeeperServer zkServer;

    /**
     * The number of requests that have been submitted but not yet responded to.
     */
    private final AtomicInteger outstandingRequests = new AtomicInteger(0);

    /**
     * This is the id that uniquely identifies the session of a client. Once
     * this session is no longer active, the ephemeral nodes will go away.
     */
    private long sessionId;

    private final int outstandingLimit;

    public NIOServerCnxn(ZooKeeperServer zk, SocketChannel sock,
                         SelectionKey sk, NIOServerCnxnFactory factory,
                         SelectorThread selectorThread) throws IOException {
        this.zkServer = zk;
        this.sock = sock;
        this.sk = sk;
        this.factory = factory;
        this.selectorThread = selectorThread;
        if (this.factory.login != null) {
            this.zooKeeperSaslServer = new ZooKeeperSaslServer(factory.login);
        }
        if (zk != null) {
            outstandingLimit = zk.getGlobalOutstandingLimit();
        } else {
            outstandingLimit = 1;
        }
        sock.socket().setTcpNoDelay(true);
        /* set socket linger to false, so that socket close does not block */
        sock.socket().setSoLinger(false, -1);
        InetAddress addr = ((InetSocketAddress) sock.socket()
                .getRemoteSocketAddress()).getAddress();
        addAuthInfo(new Id("ip", addr.getHostAddress()));
        this.sessionTimeout = factory.sessionlessCnxnTimeout;
    }

    /* Send close connection packet to the client, doIO will eventually
     * close the underlying machinery (like socket, selectorkey, etc...)
     */
    public void sendCloseSession() {
        sendBuffer(ServerCnxnFactory.closeConn);
    }

    /**
     * send buffer without using the asynchronous
     * calls to selector and then close the socket
     * @param bb
     */
    void sendBufferSync(ByteBuffer bb) {
       try {
           /* configure socket to be blocking
            * so that we dont have to do write in
            * a tight while loop
            */
           if (bb != ServerCnxnFactory.closeConn) {
               if (sock.isOpen()) {
                   sock.configureBlocking(true);
                   sock.write(bb);
               }
               packetSent();
           }
       } catch (IOException ie) {
           LOG.error("Error sending data synchronously ", ie);
       }
    }

    /**
     * sendBuffer pushes a byte buffer onto the outgoing buffer queue for
     * asynchronous writes.
     */
    public void sendBuffer(ByteBuffer bb) {
        if (LOG.isTraceEnabled()) {
            LOG.trace("Add a buffer to outgoingBuffers, sk " + sk
                      + " is valid: " + sk.isValid());
        }
        outgoingBuffers.add(bb);
        requestInterestOpsUpdate();
    }

    /** Read the request payload (everything following the length prefix) */
    private void readPayload() throws IOException, InterruptedException {
        if (incomingBuffer.remaining() != 0) { // have we read length bytes?
            int rc = sock.read(incomingBuffer); // sock is non-blocking, so ok
            if (rc < 0) {
                throw new EndOfStreamException(
                        "Unable to read additional data from client sessionid 0x"
                        + Long.toHexString(sessionId)
                        + ", likely client has closed socket");
            }
        }

        if (incomingBuffer.remaining() == 0) { // have we read length bytes?
            packetReceived();
            incomingBuffer.flip();
            if (!initialized) {
                readConnectRequest();
            } else {
                readRequest();
            }
            lenBuffer.clear();
            incomingBuffer = lenBuffer;
        }
    }

    /**
     * This boolean tracks whether the connection is ready for selection or
     * not. A connection is marked as not ready for selection while it is
     * processing an IO request. The flag is used to gatekeep pushing interest
     * op updates onto the selector.
     */
    private final AtomicBoolean selectable = new AtomicBoolean(true);

    public boolean isSelectable() {
        return sk.isValid() && selectable.get();
    }

    public void disableSelectable() {
        selectable.set(false);
    }

    public void enableSelectable() {
        selectable.set(true);
    }

    private void requestInterestOpsUpdate() {
        if (isSelectable()) {
            selectorThread.addInterestOpsUpdateRequest(sk);
        }
    }

    void handleWrite(SelectionKey k) throws IOException, CloseRequestException {
        if (outgoingBuffers.isEmpty()) {
            return;
        }

        /*
         * This is going to reset the buffer position to 0 and the
         * limit to the size of the buffer, so that we can fill it
         * with data from the non-direct buffers that we need to
         * send.
         */
        ByteBuffer directBuffer = NIOServerCnxnFactory.getDirectBuffer();
        if (directBuffer == null) {
            ByteBuffer[] bufferList = new ByteBuffer[outgoingBuffers.size()];
            // Use gathered write call. This updates the positions of the
            // byte buffers to reflect the bytes that were written out.
            sock.write(outgoingBuffers.toArray(bufferList));

            // Remove the buffers that we have sent
            ByteBuffer bb;
            while ((bb = outgoingBuffers.peek()) != null) {
                if (bb == ServerCnxnFactory.closeConn) {
                    throw new CloseRequestException("close requested");
                }
                if (bb.remaining() > 0) {
                    break;
                }
                packetSent();
                outgoingBuffers.remove();
            }
         } else {
            directBuffer.clear();

            for (ByteBuffer b : outgoingBuffers) {
                if (directBuffer.remaining() < b.remaining()) {
                    /*
                     * When we call put later, if the directBuffer is to
                     * small to hold everything, nothing will be copied,
                     * so we've got to slice the buffer if it's too big.
                     */
                    b = (ByteBuffer) b.slice().limit(
                            directBuffer.remaining());
                }
                /*
                 * put() is going to modify the positions of both
                 * buffers, put we don't want to change the position of
                 * the source buffers (we'll do that after the send, if
                 * needed), so we save and reset the position after the
                 * copy
                 */
                int p = b.position();
                directBuffer.put(b);
                b.position(p);
                if (directBuffer.remaining() == 0) {
                    break;
                }
            }
            /*
             * Do the flip: limit becomes position, position gets set to
             * 0. This sets us up for the write.
             */
            directBuffer.flip();

            int sent = sock.write(directBuffer);

            ByteBuffer bb;

            // Remove the buffers that we have sent
            while ((bb = outgoingBuffers.peek()) != null) {
                if (bb == ServerCnxnFactory.closeConn) {
                    throw new CloseRequestException("close requested");
                }
                if (sent < bb.remaining()) {
                    /*
                     * We only partially sent this buffer, so we update
                     * the position and exit the loop.
                     */
                    bb.position(bb.position() + sent);
                    break;
                }
                packetSent();
                /* We've sent the whole buffer, so drop the buffer */
                sent -= bb.remaining();
                outgoingBuffers.remove();
            }
        }
    }

    /**
     * Only used in order to allow testing
     */
    protected boolean isSocketOpen() {
        return sock.isOpen();
    }

    /**
     * Handles read/write IO on connection.
     */
    void doIO(SelectionKey k) throws InterruptedException {
        try {
            if (isSocketOpen() == false) {
                LOG.warn("trying to do i/o on a null socket for session:0x"
                         + Long.toHexString(sessionId));

                return;
            }
            if (k.isReadable()) {
                int rc = sock.read(incomingBuffer);
                if (rc < 0) {
                    throw new EndOfStreamException(
                            "Unable to read additional data from client sessionid 0x"
                            + Long.toHexString(sessionId)
                            + ", likely client has closed socket");
                }
                if (incomingBuffer.remaining() == 0) {
                    boolean isPayload;
                    if (incomingBuffer == lenBuffer) { // start of next request
                        incomingBuffer.flip();
                        isPayload = readLength(k);
                        incomingBuffer.clear();
                    } else {
                        // continuation
                        isPayload = true;
                    }
                    if (isPayload) { // not the case for 4letterword
                        readPayload();
                    }
                    else {
                        // four letter words take care
                        // need not do anything else
                        return;
                    }
                }
            }
            if (k.isWritable()) {
                handleWrite(k);

                if (!initialized && !getReadInterest() && !getWriteInterest()) {
                    throw new CloseRequestException("responded to info probe");
                }
            }
        } catch (CancelledKeyException e) {
            LOG.warn("CancelledKeyException causing close of session 0x"
                     + Long.toHexString(sessionId));
            if (LOG.isDebugEnabled()) {
                LOG.debug("CancelledKeyException stack trace", e);
            }
            close();
        } catch (CloseRequestException e) {
            // expecting close to log session closure
            close();
        } catch (EndOfStreamException e) {
            LOG.warn(e.getMessage());
            // expecting close to log session closure
            close();
        } catch (IOException e) {
            LOG.warn("Exception causing close of session 0x"
                     + Long.toHexString(sessionId) + ": " + e.getMessage());
            if (LOG.isDebugEnabled()) {
                LOG.debug("IOException stack trace", e);
            }
            close();
        }
    }

    private void readRequest() throws IOException {
        zkServer.processPacket(this, incomingBuffer);
    }

    // Only called as callback from zkServer.processPacket()
    protected void incrOutstandingRequests(RequestHeader h) {
        if (h.getXid() >= 0) {
            outstandingRequests.incrementAndGet();
            // check throttling
            int inProcess = zkServer.getInProcess();
            if (inProcess > outstandingLimit) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Throttling recv " + inProcess);
                }
                disableRecv();
            }
        }
    }

    // returns whether we are interested in writing, which is determined
    // by whether we have any pending buffers on the output queue or not
    private boolean getWriteInterest() {
        return !outgoingBuffers.isEmpty();
    }

    // returns whether we are interested in taking new requests, which is
    // determined by whether we are currently throttled or not
    private boolean getReadInterest() {
        return !throttled.get();
    }

    private final AtomicBoolean throttled = new AtomicBoolean(false);

    // Throttle acceptance of new requests. If this entailed a state change,
    // register an interest op update request with the selector.
    public void disableRecv() {
        if (throttled.compareAndSet(false, true)) {
            requestInterestOpsUpdate();
        }
    }

    // Disable throttling and resume acceptance of new requests. If this
    // entailed a state change, register an interest op update request with
    // the selector.
    public void enableRecv() {
        if (throttled.compareAndSet(true, false)) {
            requestInterestOpsUpdate();
        }
    }

    private void readConnectRequest() throws IOException, InterruptedException {
        if (!isZKServerRunning()) {
            throw new IOException("ZooKeeperServer not running");
        }
        zkServer.processConnectRequest(this, incomingBuffer);
        initialized = true;
    }

    /**
     * This class wraps the sendBuffer method of NIOServerCnxn. It is
     * responsible for chunking up the response to a client. Rather
     * than cons'ing up a response fully in memory, which may be large
     * for some commands, this class chunks up the result.
     */
    private class SendBufferWriter extends Writer {
        private StringBuffer sb = new StringBuffer();

        /**
         * Check if we are ready to send another chunk.
         * @param force force sending, even if not a full chunk
         */
        private void checkFlush(boolean force) {
            if ((force && sb.length() > 0) || sb.length() > 2048) {
                sendBufferSync(ByteBuffer.wrap(sb.toString().getBytes()));
                // clear our internal buffer
                sb.setLength(0);
            }
        }

        @Override
        public void close() throws IOException {
            if (sb == null) return;
            checkFlush(true);
            sb = null; // clear out the ref to ensure no reuse
        }

        @Override
        public void flush() throws IOException {
            checkFlush(true);
        }

        @Override
        public void write(char[] cbuf, int off, int len) throws IOException {
            sb.append(cbuf, off, len);
            checkFlush(false);
        }
    }
    /** Return if four letter word found and responded to, otw false **/
    private boolean checkFourLetterWord(final SelectionKey k, final int len)
    throws IOException
    {
        // We take advantage of the limited size of the length to look
        // for cmds. They are all 4-bytes which fits inside of an int
        if (!FourLetterCommands.isKnown(len)) {
            return false;
        }

        String cmd = FourLetterCommands.getCommandString(len);
        packetReceived();

        /** cancel the selection key to remove the socket handling
         * from selector. This is to prevent netcat problem wherein
         * netcat immediately closes the sending side after sending the
         * commands and still keeps the receiving channel open.
         * The idea is to remove the selectionkey from the selector
         * so that the selector does not notice the closed read on the
         * socket channel and keep the socket alive to write the data to
         * and makes sure to close the socket after its done writing the data
         */
        if (k != null) {
            try {
                k.cancel();
            } catch(Exception e) {
                LOG.error("Error cancelling command selection key ", e);
            }
        }

        final PrintWriter pwriter = new PrintWriter(
                new BufferedWriter(new SendBufferWriter()));

        // ZOOKEEPER-2693: don't execute 4lw if it's not enabled.
        if (!FourLetterCommands.isEnabled(cmd)) {
            LOG.debug("Command {} is not executed because it is not in the whitelist.", cmd);
            NopCommand nopCmd = new NopCommand(pwriter, this, cmd +
                    " is not executed because it is not in the whitelist.");
            nopCmd.start();
            return true;
        }

        LOG.info("Processing " + cmd + " command from "
                + sock.socket().getRemoteSocketAddress());

        if (len == FourLetterCommands.setTraceMaskCmd) {
            incomingBuffer = ByteBuffer.allocate(8);
            int rc = sock.read(incomingBuffer);
            if (rc < 0) {
                throw new IOException("Read error");
            }
            incomingBuffer.flip();
            long traceMask = incomingBuffer.getLong();
            ZooTrace.setTextTraceLevel(traceMask);
            SetTraceMaskCommand setMask = new SetTraceMaskCommand(pwriter, this, traceMask);
            setMask.start();
            return true;
        } else {
            CommandExecutor commandExecutor = new CommandExecutor();
            return commandExecutor.execute(this, pwriter, len, zkServer, factory);
        }
    }

    /** Reads the first 4 bytes of lenBuffer, which could be true length or
     *  four letter word.
     *
     * @param k selection key
     * @return true if length read, otw false (wasn't really the length)
     * @throws IOException if buffer size exceeds maxBuffer size
     */
    private boolean readLength(SelectionKey k) throws IOException {
        // Read the length, now get the buffer
        int len = lenBuffer.getInt();
        if (!initialized && checkFourLetterWord(sk, len)) {
            return false;
        }
        if (len < 0 || len > BinaryInputArchive.maxBuffer) {
            throw new IOException("Len error " + len);
        }
        if (!isZKServerRunning()) {
            throw new IOException("ZooKeeperServer not running");
        }
        incomingBuffer = ByteBuffer.allocate(len);
        return true;
    }

    /**
     * @return true if the server is running, false otherwise.
     */
    boolean isZKServerRunning() {
        return zkServer != null && zkServer.isRunning();
    }

    public long getOutstandingRequests() {
        return outstandingRequests.get();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.zookeeper.server.ServerCnxnIface#getSessionTimeout()
     */
    public int getSessionTimeout() {
        return sessionTimeout;
    }

    /**
     * Used by "dump" 4-letter command to list all connection in
     * cnxnExpiryMap
     */
    @Override
    public String toString() {
        return "ip: " + sock.socket().getRemoteSocketAddress() +
               " sessionId: 0x" + Long.toHexString(sessionId);
    }

    /**
     * Close the cnxn and remove it from the factory cnxns list.
     */
    @Override
    public void close() {
        if (!factory.removeCnxn(this)) {
            return;
        }

        if (zkServer != null) {
            zkServer.removeCnxn(this);
        }

        if (sk != null) {
            try {
                // need to cancel this selection key from the selector
                sk.cancel();
            } catch (Exception e) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("ignoring exception during selectionkey cancel", e);
                }
            }
        }

        closeSock();
    }

    /**
     * Close resources associated with the sock of this cnxn.
     */
    private void closeSock() {
        if (sock.isOpen() == false) {
            return;
        }

        LOG.info("Closed socket connection for client "
                + sock.socket().getRemoteSocketAddress()
                + (sessionId != 0 ?
                        " which had sessionid 0x" + Long.toHexString(sessionId) :
                        " (no session established for client)"));
        closeSock(sock);
    }

    /**
     * Close resources associated with a sock.
     */
    public static void closeSock(SocketChannel sock) {
        if (sock.isOpen() == false) {
            return;
        }

        try {
            /*
             * The following sequence of code is stupid! You would think that
             * only sock.close() is needed, but alas, it doesn't work that way.
             * If you just do sock.close() there are cases where the socket
             * doesn't actually close...
             */
            sock.socket().shutdownOutput();
        } catch (IOException e) {
            // This is a relatively common exception that we can't avoid
            if (LOG.isDebugEnabled()) {
                LOG.debug("ignoring exception during output shutdown", e);
            }
        }
        try {
            sock.socket().shutdownInput();
        } catch (IOException e) {
            // This is a relatively common exception that we can't avoid
            if (LOG.isDebugEnabled()) {
                LOG.debug("ignoring exception during input shutdown", e);
            }
        }
        try {
            sock.socket().close();
        } catch (IOException e) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("ignoring exception during socket close", e);
            }
        }
        try {
            sock.close();
        } catch (IOException e) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("ignoring exception during socketchannel close", e);
            }
        }
    }

    private final static byte fourBytes[] = new byte[4];

    /*
     * (non-Javadoc)
     *
     * @see org.apache.zookeeper.server.ServerCnxnIface#sendResponse(org.apache.zookeeper.proto.ReplyHeader,
     *      org.apache.jute.Record, java.lang.String)
     */
    @Override
    public void sendResponse(ReplyHeader h, Record r, String tag) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // Make space for length
            BinaryOutputArchive bos = BinaryOutputArchive.getArchive(baos);
            try {
                baos.write(fourBytes);
                bos.writeRecord(h, "header");
                if (r != null) {
                    bos.writeRecord(r, tag);
                }
                baos.close();
            } catch (IOException e) {
                LOG.error("Error serializing response");
            }
            byte b[] = baos.toByteArray();
            ByteBuffer bb = ByteBuffer.wrap(b);
            bb.putInt(b.length - 4).rewind();
            sendBuffer(bb);
            if (h.getXid() > 0) {
                // check throttling
                if (outstandingRequests.decrementAndGet() < 1 ||
                    zkServer.getInProcess() < outstandingLimit) {
                    enableRecv();
                }
            }
         } catch(Exception e) {
            LOG.warn("Unexpected exception. Destruction averted.", e);
         }
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.zookeeper.server.ServerCnxnIface#process(org.apache.zookeeper.proto.WatcherEvent)
     */
    @Override
    public void process(WatchedEvent event) {
        ReplyHeader h = new ReplyHeader(-1, -1L, 0);
        if (LOG.isTraceEnabled()) {
            ZooTrace.logTraceMessage(LOG, ZooTrace.EVENT_DELIVERY_TRACE_MASK,
                                     "Deliver event " + event + " to 0x"
                                     + Long.toHexString(this.sessionId)
                                     + " through " + this);
        }

        // Convert WatchedEvent to a type that can be sent over the wire
        WatcherEvent e = event.getWrapper();

        sendResponse(h, e, "notification");
    }

    /*
     * (non-Javadoc)
     *
     * @see org.apache.zookeeper.server.ServerCnxnIface#getSessionId()
     */
    @Override
    public long getSessionId() {
        return sessionId;
    }

    @Override
    public void setSessionId(long sessionId) {
        this.sessionId = sessionId;
        factory.addSession(sessionId, this);
    }

    @Override
    public void setSessionTimeout(int sessionTimeout) {
        this.sessionTimeout = sessionTimeout;
        factory.touchCnxn(this);
    }

    @Override
    public int getInterestOps() {
        if (!isSelectable()) {
            return 0;
        }
        int interestOps = 0;
        if (getReadInterest()) {
            interestOps |= SelectionKey.OP_READ;
        }
        if (getWriteInterest()) {
            interestOps |= SelectionKey.OP_WRITE;
        }
        return interestOps;
    }

    @Override
    public InetSocketAddress getRemoteSocketAddress() {
        if (sock.isOpen() == false) {
            return null;
        }
        return (InetSocketAddress) sock.socket().getRemoteSocketAddress();
    }

    public InetAddress getSocketAddress() {
        if (sock.isOpen() == false) {
            return null;
        }
        return sock.socket().getInetAddress();
    }

    @Override
    protected ServerStats serverStats() {
        if (zkServer == null) {
            return null;
        }
        return zkServer.serverStats();
    }

    @Override
    public boolean isSecure() {
        return false;
    }

    @Override
    public Certificate[] getClientCertificateChain() {
        throw new UnsupportedOperationException(
                "SSL is unsupported in NIOServerCnxn");
    }

    @Override
    public void setClientCertificateChain(Certificate[] chain) {
        throw new UnsupportedOperationException(
                "SSL is unsupported in NIOServerCnxn");
    }

}


<?php

require_once 'PHPUnit/Util/Filter.php';

PHPUnit_Util_Filter::addFileToFilter(__FILE__);

require_once 'PHPUnit/Extensions/OutputTestCase.php';

/**
 *
 *
 * @category   Testing
 * @package    PHPUnit
 * @author     Sebastian Bergmann <sb@sebastian-bergmann.de>
 * @copyright  2002-2008 Sebastian Bergmann <sb@sebastian-bergmann.de>
 * @license    http://www.opensource.org/licenses/bsd-license.php  BSD License
 * @version    Release: 3.2.9
 * @link       http://www.phpunit.de/
 * @since      Class available since Release 2.0.0
 */
class OutputTestCase extends PHPUnit_Extensions_OutputTestCase
{
    public function testExpectOutputStringFooActualFoo()
    {
        $this->expectOutputString('foo');
        print 'foo';
    }

    public function testExpectOutputStringFooActualBar()
    {
        $this->expectOutputString('foo');
        print 'bar';
    }

    public function testExpectOutputRegexFooActualFoo()
    {
        $this->expectOutputRegex('/foo/');
        print 'foo';
    }

    public function testExpectOutputRegexFooActualBar()
    {
        $this->expectOutputRegex('/foo/');
        print 'bar';
    }
}
?>


""" Models for display visual shapes whose attributes can be associated
with data columns from data sources.

"""
from __future__ import absolute_import

from ..plot_object import PlotObject
from ..mixins import FillProps, LineProps, TextProps
from ..enums import Direction, Anchor
from ..properties import AngleSpec, Bool, DistanceSpec, Enum, Float, Include, Instance, NumberSpec, StringSpec

from .mappers import LinearColorMapper

class Glyph(PlotObject):
    """ Base class for all glyphs/marks/geoms/whatever-you-call-'em in Bokeh.

    """

    visible = Bool(help="""
    Whether the glyph should render or not.
    """)

class AnnularWedge(Glyph):
    """ Render annular wedges.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/AnnularWedge.py
        :source-position: none

    *source:* `tests/glyphs/AnnularWedge.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/AnnularWedge.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the center of the annular wedges.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the center of the annular wedges.
    """)

    inner_radius = DistanceSpec("inner_radius", help="""
    The inner radii of the annular wedges.
    """)

    outer_radius = DistanceSpec("outer_radius", help="""
    The outer radii of the annular wedges.
    """)

    start_angle = AngleSpec("start_angle", help="""
    The angles to start the annular wedges, in radians, as measured from
    the horizontal.
    """)

    end_angle = AngleSpec("end_angle", help="""
    The angles to end the annular wedges, in radians, as measured from
    the horizontal.
    """)

    direction = Enum(Direction, help="""
    Which direction to stroke between the start and end angles.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the annular wedges.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the annular wedges.
    """)

class Annulus(Glyph):
    """ Render annuli.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Annulus.py
        :source-position: none

    *source:* `tests/glyphs/Annulus.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Annulus.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the center of the annuli.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the center of the annuli.
    """)

    inner_radius = DistanceSpec("inner_radius", help="""
    The inner radii of the annuli.
    """)

    outer_radius = DistanceSpec("outer_radius", help="""
    The outer radii of the annuli.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the annuli.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the annuli.
    """)

class Arc(Glyph):
    """ Render arcs.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Arc.py
        :source-position: none

    *source:* `tests/glyphs/Arc.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Arc.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the center of the arcs.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the center of the arcs.
    """)

    radius = DistanceSpec("radius", help="""
    Radius of the arc.
    """)

    start_angle = AngleSpec("start_angle", help="""
    The angles to start the arcs, in radians, as measured from the horizontal.
    """)

    end_angle = AngleSpec("end_angle", help="""
    The angles to end the arcs, in radians, as measured from the horizontal.
    """)

    direction = Enum(Direction, help="""
    Which direction to stroke between the start and end angles.
    """)
    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the arcs.
    """)

class Bezier(Glyph):
    u""" Render Bézier curves.

    For more information consult the `Wikipedia article for Bézier curve`_.

    .. _Wikipedia article for Bézier curve: http://en.wikipedia.org/wiki/Bézier_curve

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Bezier.py
        :source-position: none

    *source:* `tests/glyphs/Bezier.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Bezier.py>`_

    """

    x0 = NumberSpec("x0", help="""
    The x-coordinates of the starting points.
    """)

    y0 = NumberSpec("y0", help="""
    The y-coordinates of the starting points.
    """)

    x1 = NumberSpec("x1", help="""
    The x-coordinates of the ending points.
    """)

    y1 = NumberSpec("y1", help="""
    The y-coordinates of the ending points.
    """)

    cx0 = NumberSpec("cx0", help="""
    The x-coordinates of first control points.
    """)

    cy0 = NumberSpec("cy0", help="""
    The y-coordinates of first control points.
    """)

    cx1 = NumberSpec("cx1", help="""
    The x-coordinates of second control points.
    """)

    cy1 = NumberSpec("cy1", help="""
    The y-coordinates of second control points.
    """)

    line_props = Include(LineProps, use_prefix=False, help=u"""
    The %s values for the Bézier curves.
    """)

class Gear(Glyph):
    """ Render gears.

    The details and nomenclature concerning gear construction can
    be quite involved. For more information, consult the `Wikipedia
    article for Gear`_.

    .. _Wikipedia article for Gear: http://en.wikipedia.org/wiki/Gear

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Gear.py
        :source-position: none

    *source:* `tests/glyphs/Gear.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Gear.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the center of the gears.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the center of the gears.
    """)

    angle = AngleSpec(default=0, help="""
    The angle the gears are rotated from horizontal. [rad]
    """)

    module = NumberSpec("module", help="""
    A scaling factor, given by::

        m = p / pi

    where *p* is the circular pitch, defined as the distance from one
    face of a tooth to the corresponding face of an adjacent tooth on
    the same gear, measured along the pitch circle. [float]
    """)

    teeth = NumberSpec("teeth", help="""
    How many teeth the gears have. [int]
    """)

    pressure_angle = NumberSpec(default=20, help= """
    The complement of the angle between the direction that the teeth
    exert force on each other, and the line joining the centers of the
    two gears. [deg]
    """)

    # TODO: (bev) evidently missing a test for default value
    shaft_size = NumberSpec(default=0.3, help="""
    The central gear shaft size as a percentage of the overall gear
    size. [float]
    """)

    # TODO: (bev) evidently missing a test for default value
    internal = NumberSpec(default=False, help="""
    Whether the gear teeth are internal. [bool]
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the gears.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the gears.
    """)

class Image(Glyph):
    """ Render images given as scalar data together with a color
    mapper.

    """

    def __init__(self, **kwargs):
        if 'palette' in kwargs and 'color_mapper' in kwargs:
            raise ValueError("only one of 'palette' and 'color_mapper' may be specified")
        elif 'color_mapper' not in kwargs:
            # Use a palette (given or default)
            palette = kwargs.pop('palette', 'Greys9')
            mapper = LinearColorMapper(palette)

            reserve_val = kwargs.pop('reserve_val', None)
            if reserve_val is not None:
                mapper.reserve_val = reserve_val

            reserve_color = kwargs.pop('reserve_color', None)
            if reserve_color is not None:
                mapper.reserve_color = reserve_color

            kwargs['color_mapper'] = mapper

        super(Image, self).__init__(**kwargs)

    image = NumberSpec("image", help="""
    The arrays of scalar data for the images to be colormapped.
    """)

    x = NumberSpec("x", help="""
    The x-coordinates to locate the image anchors.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates to locate the image anchors.
    """)

    dw = DistanceSpec("dw", help="""
    The widths of the plot regions that the images will occupy.

    .. note::
        This is not the number of pixels that an image is wide.
        That number is fixed by the image itself.

    """)

    dh = DistanceSpec("dh", help="""
    The height of the plot region that the image will occupy.

    .. note::
        This is not the number of pixels that an image is tall.
        That number is fixed by the image itself.

    """)

    dilate = Bool(False, help="""
    Whether to always round fractional pixel locations in such a way
    as to make the images bigger.

    This setting may be useful if pixel rounding errors are causing
    images to have a gap between them, when they should appear flush.

    """)

    color_mapper = Instance(LinearColorMapper, help="""
    A ``ColorMapper`` to use to map the scalar data from ``image``
    into RGBA values for display.

    .. note::
        The color mapping step happens on the client.

    """)

    # TODO: (bev) support anchor property for Image
    # ref: https://github.com/bokeh/bokeh/issues/1763

class ImageRGBA(Glyph):
    """ Render images given as RGBA data.

    """

    image = NumberSpec("image", help="""
    The arrays of RGBA data for the images.
    """)

    x = NumberSpec("x", help="""
    The x-coordinates to locate the image anchors.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates to locate the image anchors.
    """)

    rows = NumberSpec("rows", help="""
    The numbers of rows in the images
    """)

    cols = NumberSpec("cols", help="""
    The numbers of columns in the images
    """)

    dw = DistanceSpec("dw", help="""
    The widths of the plot regions that the images will occupy.

    .. note::
        This is not the number of pixels that an image is wide.
        That number is fixed by the image itself.

    """)

    dh = DistanceSpec("dh", help="""
    The height of the plot region that the image will occupy.

    .. note::
        This is not the number of pixels that an image is tall.
        That number is fixed by the image itself.

    """)

    dilate = Bool(False, help="""
    Whether to always round fractional pixel locations in such a way
    as to make the images bigger.

    This setting may be useful if pixel rounding errors are causing
    images to have a gap between them, when they should appear flush.
    """)

    # TODO: (bev) support anchor property for ImageRGBA
    # ref: https://github.com/bokeh/bokeh/issues/1763

class ImageURL(Glyph):
    """ Render images loaded from given URLs.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/ImageURL.py
        :source-position: none

    *source:* `tests/glyphs/ImageURL.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/ImageURL.py>`_

    """

    url = NumberSpec("url", help="""
    The URLs to retrieve images from.

    .. note::
        The actual retrieving and loading of the images happens on
        the client.

    """)

    x = NumberSpec("x", help="""
    The x-coordinates to locate the image anchors.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates to locate the image anchors.
    """)

    # TODO: (bev) rename to "dw" for consistency
    w = DistanceSpec("w", help="""
    The widths of the plot regions that the images will occupy.

    .. note::
        This is not the number of pixels that an image is wide.
        That number is fixed by the image itself.

    .. note::
        This may be renamed to "dw" in the future.

    """)

    # TODO: (bev) rename to "dh" for consistency
    h = DistanceSpec("h", help="""
    The height of the plot region that the image will occupy.

    .. note::
        This is not the number of pixels that an image is tall.
        That number is fixed by the image itself.

    .. note::
        This may be renamed to "dh" in the future.

    """)

    angle = AngleSpec(default=0, help="""
    The angles to rotate the images, in radians as measured from the
    horizontal.
    """)

    global_alpha = Float(1.0, help="""
    The opacity that each image is rendered with.
    """)

    dilate = Bool(False, help="""
    Whether to always round fractional pixel locations in such a way
    as to make the images bigger.

    This setting may be useful if pixel rounding errors are causing
    images to have a gap between them, when they should appear flush.
    """)

    anchor = Enum(Anchor, help="""
    What position of the image should be anchored at the `x`, `y`
    coordinates.
    """)

class Line(Glyph):
    """ Render a single line.

    .. note::
        The ``Line`` glyph is different from most other glyphs in that
        the vector of values only produces one glyph on the Plot.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Line.py
        :source-position: none

    *source:* `tests/glyphs/Line.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Line.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates for the points of the line.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates for the points of the line.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the line.
    """)

class MultiLine(Glyph):
    """ Render several lines.

    .. note::
        The data for the ``MultiLine`` glyph is different in that the
        vector of values is not a vector of scalars. Rather, it is a
        "list of lists".

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/MultiLine.py
        :source-position: none

    *source:* `tests/glyphs/MultiLine.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/MultiLine.py>`_

    """
    xs = NumberSpec("xs", help="""
    The x-coordinates for all the lines, given as a "list of lists".
    """)

    ys = NumberSpec("ys", help="""
    The x-coordinates for all the lines, given as a "list of lists".
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the lines.
    """)

class Oval(Glyph):
    u""" Render ovals.

    .. note::
        This glyph renders ovals using Bézier curves, which are similar,
        but not identical to ellipses.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Oval.py
        :source-position: none

    *source:* `tests/glyphs/Oval.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Oval.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the centers of the ovals.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the centers of the ovals.
    """)

    width = DistanceSpec("width", help="""
    The overall widths of each oval.
    """)

    height = DistanceSpec("height", help="""
    The overall height of each oval.
    """)

    angle = AngleSpec("angle", help="""
    The angle the ovals are rotated from horizontal. [rad]
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the ovals.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the ovals.
    """)

class Patch(Glyph):
    """ Render a single patch.

    .. note::
        The ``Patch`` glyph is different from most other glyphs in that
        the vector of values only produces one glyph on the Plot.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Patch.py
        :source-position: none

    *source:* `tests/glyphs/Patch.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Patch.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates for the points of the patch.

    .. note::
        A patch may comprise multiple polygons. In this case the
        x-coordinates for each polygon should be separated by NaN
        values in the sequence.

    """)

    y = NumberSpec("y", help="""
    The y-coordinates for the points of the patch.

    .. note::
        A patch may comprise multiple polygons. In this case the
        y-coordinates for each polygon should be separated by NaN
        values in the sequence.

    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the patch.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the patch.
    """)

class Patches(Glyph):
    """ Render several patches.

    .. note::
        The data for the ``Patches`` glyph is different in that the
        vector of values is not a vector of scalars. Rather, it is a
        "list of lists".

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Patches.py
        :source-position: none

    *source:* `tests/glyphs/Patches.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Patches.py>`_

    """

    xs = NumberSpec("xs", help="""
    The x-coordinates for all the patches, given as a "list of lists".

    .. note::
        Individual patches may comprise multiple polygons. In this case
        the x-coordinates for each polygon should be separated by NaN
        values in the sublists.

    """)

    ys = NumberSpec("ys", help="""
    The y-coordinates for all the patches, given as a "list of lists".

    .. note::
        Individual patches may comprise multiple polygons. In this case
        the y-coordinates for each polygon should be separated by NaN
        values in the sublists.

    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the patches.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the patches.
    """)

class Quad(Glyph):
    """ Render axis-aligned quads.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Quad.py
        :source-position: none

    *source:* `tests/glyphs/Quad.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Quad.py>`_

    """

    left = NumberSpec("left", help="""
    The x-coordinates of the left edges.
    """)

    right = NumberSpec("right", help="""
    The x-coordinates of the right edges.
    """)

    bottom = NumberSpec("bottom", help="""
    The y-coordinates of the bottom edges.
    """)

    top = NumberSpec("top", help="""
    The y-coordinates of the top edges.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the quads.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the quads.
    """)

class Quadratic(Glyph):
    """ Render parabolas.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Quadratic.py
        :source-position: none

    *source:* `tests/glyphs/Quadratic.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Quadratic.py>`_

    """

    x0 = NumberSpec("x0", help="""
    The x-coordinates of the starting points.
    """)

    y0 = NumberSpec("y0", help="""
    The y-coordinates of the starting points.
    """)

    x1 = NumberSpec("x1", help="""
    The x-coordinates of the ending points.
    """)

    y1 = NumberSpec("y1", help="""
    The y-coordinates of the ending points.
    """)

    cx = NumberSpec("cx", help="""
    The x-coordinates of the control points.
    """)

    cy = NumberSpec("cy", help="""
    The y-coordinates of the control points.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the parabolas.
    """)

class Ray(Glyph):
    """ Render rays.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Ray.py
        :source-position: none

    *source:* `tests/glyphs/Ray.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Ray.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates to start the rays.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates to start the rays.
    """)

    angle = AngleSpec("angle", help="""
    The angles in radians to extend the rays, as measured from the
    horizontal.
    """)

    length = DistanceSpec("length", help="""
    The length to extend the ray. Note that this ``length`` defaults
    to screen units.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the rays.
    """)

class Rect(Glyph):
    """ Render rectangles.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Rect.py
        :source-position: none

    *source:* `tests/glyphs/Rect.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Rect.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the centers of the rectangles.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the centers of the rectangles.
    """)

    width = DistanceSpec("width", help="""
    The overall widths of the rectangles.
    """)

    height = DistanceSpec("height", help="""
    The overall heights of the rectangles.
    """)

    angle = AngleSpec("angle", help="""
    The angles to rotate the rectangles, in radians, as measured from
    the horizontal.
    """)

    dilate = Bool(False, help="""
    Whether to always round fractional pixel locations in such a way
    as to make the rectangles bigger.

    This setting may be useful if pixel rounding errors are causing
    rectangles to have a gap between them, when they should appear
    flush.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the rectangles.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the rectangles.
    """)

class Segment(Glyph):
    """ Render segments.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Segment.py
        :source-position: none

    *source:* `tests/glyphs/Segment.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Segment.py>`_

    """

    x0 = NumberSpec("x0", help="""
    The x-coordinates of the starting points.
    """)

    y0 = NumberSpec("y0", help="""
    The y-coordinates of the starting points.
    """)

    x1 = NumberSpec("x1", help="""
    The x-coordinates of the ending points.
    """)

    y1 = NumberSpec("y1", help="""
    The y-coordinates of the ending points.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the segments.
    """)

class Text(Glyph):
    """ Render text.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Text.py
        :source-position: none

    *source:* `tests/glyphs/Text.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Text.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates to locate the text anchors.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates to locate the text anchors.
    """)

    text = StringSpec("text", help="""
    The text values to render.
    """)

    angle = AngleSpec(default=0, help="""
    The angles to rotate the text, in radians,, as measured from the horizontal.
    """)

    x_offset = NumberSpec(default=0, help="""
    Offset values to apply to the x-coordinates.

    This is useful, for instance, if it is desired to "float" text a fixed
    distance in screen units from a given data position.
    """)

    y_offset = NumberSpec(default=0, help="""
    Offset values to apply to the y-coordinates.

    This is useful, for instance, if it is desired to "float" text a fixed
    distance in screen units from a given data position.
    """)

    text_props = Include(TextProps, use_prefix=False, help="""
    The %s values for the text.
    """)

class Wedge(Glyph):
    """ Render wedges.

    Example
    -------

    .. bokeh-plot:: ../tests/glyphs/Wedge.py
        :source-position: none

    *source:* `tests/glyphs/Wedge.py <https://github.com/bokeh/bokeh/tree/master/tests/glyphs/Wedge.py>`_

    """

    x = NumberSpec("x", help="""
    The x-coordinates of the points of the wedges.
    """)

    y = NumberSpec("y", help="""
    The y-coordinates of the points of the wedges.
    """)

    radius = DistanceSpec("radius", help="""
    Radii of the wedges.
    """)

    start_angle = AngleSpec("start_angle", help="""
    The angles to start the wedges, in radians, as measured from the horizontal.
    """)

    end_angle = AngleSpec("end_angle", help="""
    The angles to end the wedges, in radians as measured from the horizontal.
    """)

    direction = Enum(Direction, help="""
    Which direction to stroke between the start and end angles.
    """)

    line_props = Include(LineProps, use_prefix=False, help="""
    The %s values for the wedges.
    """)

    fill_props = Include(FillProps, use_prefix=False, help="""
    The %s values for the wedges.
    """)

# XXX: allow `from bokeh.models.glyphs import *`
from .markers import (Marker, Asterisk, Circle, CircleCross, CircleX, Cross,
                      Diamond, DiamondCross, InvertedTriangle, Square,
                      SquareCross, SquareX, Triangle, X)

# Fool pyflakes
(Marker, Asterisk, Circle, CircleCross, CircleX, Cross, Diamond, DiamondCross,
InvertedTriangle, Square, SquareCross, SquareX, Triangle, X)


stage: Verify
group: Testing
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
type: reference, howto
---

# Load Performance Testing **(PREMIUM)**

> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/10683) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.2.

With Load Performance Testing, you can test the impact of any pending code changes
to your application's backend in [GitLab CI/CD](../../../ci/README.md).

GitLab uses [k6](https://k6.io/), a free and open source
tool, for measuring the system performance of applications under
load.

Unlike [Browser Performance Testing](browser_performance_testing.md), which is
used to measure how web sites perform in client browsers, Load Performance Testing
can be used to perform various types of [load tests](https://k6.io/docs/#use-cases)
against application endpoints such as APIs, Web Controllers, and so on.
This can be used to test how the backend or the server performs at scale.

For example, you can use Load Performance Testing to perform many concurrent
GET calls to a popular API endpoint in your application to see how it performs.

## How Load Performance Testing works

First, define a job in your `.gitlab-ci.yml` file that generates the
[Load Performance report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsload_performance-premium).
GitLab checks this report, compares key load performance metrics
between the source and target branches, and then shows the information in a merge request widget:

![Load Performance Widget](img/load_performance_testing.png)

Next, you need to configure the test environment and write the k6 test.

The key performance metrics that the merge request widget shows after the test completes are:

- Checks: The percentage pass rate of the [checks](https://k6.io/docs/using-k6/checks) configured in the k6 test.
- TTFB P90: The 90th percentile of how long it took to start receiving responses, aka the [Time to First Byte](https://en.wikipedia.org/wiki/Time_to_first_byte) (TTFB).
- TTFB P95: The 95th percentile for TTFB.
- RPS: The average requests per second (RPS) rate the test was able to achieve.

NOTE: **Note:**
If the Load Performance report has no data to compare, such as when you add the
Load Performance job in your `.gitlab-ci.yml` for the very first time,
the Load Performance report widget won't show. It must have run at least
once on the target branch (`master`, for example), before it will display in a
merge request targeting that branch.

## Configure the Load Performance Testing job

Configuring your Load Performance Testing job can be broken down into several distinct parts:

- Determine the test parameters such as throughput, and so on.
- Set up the target test environment for load performance testing.
- Design and write the k6 test.

### Determine the test parameters

The first thing you need to do is determine the [type of load test](https://k6.io/docs/test-types/introduction)
you want to run, and how it will run (for example, the number of users, throughput, and so on).

Refer to the [k6 docs](https://k6.io/docs/), especially the [k6 testing guides](https://k6.io/docs/testing-guides),
for guidance on the above and more.

### Test Environment setup

A large part of the effort around load performance testing is to prepare the target test environment
for high loads. You should ensure it's able to handle the
[throughput](https://k6.io/blog/monthly-visits-concurrent-users) it will be tested with.

It's also typically required to have representative test data in the target environment
for the load performance test to use.

We strongly recommend [not running these tests against a production environment](https://k6.io/our-beliefs#load-test-in-a-pre-production-environment).

### Write the load performance test

After the environment is prepared, you can write the k6 test itself. k6 is a flexible
tool and can be used to run [many kinds of performance tests](https://k6.io/docs/test-types/introduction).
Refer to the [k6 documentation](https://k6.io/docs/) for detailed information on how to write tests.

### Configure the test in GitLab CI/CD

When your k6 test is ready, the next step is to configure the load performance
testing job in GitLab CI/CD. The easiest way to do this is to use the
[`Verify/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Verify/Load-Performance-Testing.gitlab-ci.yml)
template that is included with GitLab.

NOTE: **Note:**
For large scale k6 tests you need to ensure the GitLab Runner instance performing the actual
test is able to handle running the test. Refer to [k6's guidance](https://k6.io/docs/testing-guides/running-large-tests#hardware-considerations)
for spec details. The [default shared GitLab.com runners](../../gitlab_com/#linux-shared-runners)
likely have insufficient specs to handle most large k6 tests.

This template runs the
[k6 Docker container](https://hub.docker.com/r/loadimpact/k6/) in the job and provides several ways to customize the
job.

An example configuration workflow:

1. Set up a GitLab Runner that can run Docker containers, such as a Runner using the
   [Docker-in-Docker workflow](../../../ci/docker/using_docker_build.md#use-docker-in-docker-workflow-with-docker-executor).
1. Configure the default Load Performance Testing CI job in your `.gitlab-ci.yml` file.
   You need to include the template and configure it with variables:

   ```yaml
   include:
     template: Verify/Load-Performance-Testing.gitlab-ci.yml

   load_performance:
     variables:
       K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT>
   ```

The above example creates a `load_performance` job in your CI/CD pipeline that runs
the k6 test.

NOTE: **Note:**
For Kubernetes setups a different template should be used: [`Jobs/Load-Performance-Testing.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Load-Performance-Testing.gitlab-ci.yml).

k6 has [various options](https://k6.io/docs/using-k6/options) to configure how it will run tests, such as what throughput (RPS) to run with,
how long the test should run, and so on. Almost all options can be configured in the test itself, but as
you can also pass command line options via the `K6_OPTIONS` variable.

For example, you can override the duration of the test with a CLI option:

```yaml
  include:
    template: Verify/Load-Performance-Testing.gitlab-ci.yml

  load_performance:
    variables:
      K6_TEST_FILE: <PATH TO K6 TEST FILE IN PROJECT>
      K6_OPTIONS: '--duration 30s'
```

GitLab only displays the key performance metrics in the MR widget if k6's results are saved
via [summary export](https://k6.io/docs/results-visualization/json#summary-export)
as a [Load Performance report artifact](../../../ci/pipelines/job_artifacts.md#artifactsreportsload_performance-premium).
The latest Load Performance artifact available is always used, using the
summary values from the test.

If [GitLab Pages](../pages/index.md) is enabled, you can view the report directly in your browser.

### Load Performance testing in Review Apps

The CI/CD YAML configuration example above works for testing against static environments,
but it can be extended to work with [review apps](../../../ci/review_apps) or
[dynamic environments](../../../ci/environments) with a few extra steps.

The best approach is to capture the dynamic URL into a custom environment variable that
is then [inherited](../../../ci/variables/README.md#inherit-environment-variables)
by the `load_performance` job. The k6 test script to be run should then be configured to
use that environment URL, such as: ``http.get(`${__ENV.ENVIRONMENT_URL`})``.

For example:

1. In the `review` job:
    1. Capture the dynamic URL and save it into a `.env` file, e.g. `echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env`.
    1. Set the `.env` file to be an [`artifacts:reports:dotenv` report](../../../ci/variables/README.md#inherit-environment-variables).
1. Set the `load_performance` job to depend on the review job, so it inherits the environment variable.
1. Configure the k6 test script to use the environment variable in it's steps.

Your `.gitlab-ci.yml` file might be similar to:

```yaml
stages:
  - deploy
  - performance

include:
  template: Verify/Load-Performance-Testing.gitlab-ci.yml

review:
  stage: deploy
  environment:
    name: review/$CI_COMMIT_REF_NAME
    url: http://$CI_ENVIRONMENT_SLUG.example.com
  script:
    - run_deploy_script
    - echo "ENVIRONMENT_URL=$CI_ENVIRONMENT_URL" >> review.env
  artifacts:
    reports:
      dotenv:
        review.env
  rules:
    - if: '$CI_COMMIT_BRANCH'  # Modify to match your pipeline rules, or use `only/except` if needed.

load_performance:
  dependencies:
    - review
  rules:
    - if: '$CI_COMMIT_BRANCH'  # Modify to match your pipeline rules, or use `only/except` if needed.
```


import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import {DashboardComponent} from './dashboard.component';

const routes: Routes = [
  {
    path: '',
    component: DashboardComponent
  }
];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class DashboardRoutingModule { }


var soundMap = [{
    name: 'river water',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/Water_Lap_River_Edge_Gentle.L.wav",
    audioOptions: {
        position: {
            x: 580,
            y: 493,
            z: 528
        },
        volume: 0.4,
        loop: true
    }
}, {
    name: 'windmill',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/WINDMILL_Mono.wav",
    audioOptions: {
        position: {
            x: 530,
            y: 516,
            z: 518
        },
        volume: 0.08,
        loop: true
    }
}, {
    name: 'insects',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/insects3.wav",
    audioOptions: {
        position: {
            x: 560,
            y: 495,
            z: 474
        },
        volume: 0.25,
        loop: true
    }
}, {
    name: 'fireplace',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/0619_Fireplace__Tree_B.L.wav",
    audioOptions: {
        position: {
            x: 551.61,
            y: 494.88,
            z: 502.00
        },
        volume: 0.25,
        loop: true
    }
}, {
    name: 'cat purring',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/Cat_Purring_Deep_Low_Snor.wav",
    audioOptions: {
        position: {
            x: 551.48,
            y: 495.60,
            z: 502.08
        },
        volume: 0.03,
        loop: true
    }
}, {
    name: 'dogs barking',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/dogs_barking_1.L.wav",
    audioOptions: {
        position: {
            x: 523,
            y: 494.88,
            z: 469
        },
        volume: 0.05,
        loop: false
    },
    playAtInterval: 60 * 1000
}, {
    name: 'arcade game',
    url: "http://hifi-production.s3.amazonaws.com/DomainContent/Toybox/sounds/ARCADE_GAMES_VID.L.L.wav",
    audioOptions: {
        position: {
            x: 543.77,
            y: 495.07,
            z: 502.25
        },
        volume: 0.01,
        loop: false,
    },
    playAtInterval: 90 * 1000
}];

function loadSounds() {
    soundMap.forEach(function(soundData) {
        soundData.sound = SoundCache.getSound(soundData.url);
    });
}

function playSound(soundData) {
    if (soundData.injector) {
        // try/catch in case the injector QObject has been deleted already
        try {
            soundData.injector.stop();
        } catch (e) {}
    }
    soundData.injector = Audio.playSound(soundData.sound, soundData.audioOptions);
}

function checkDownloaded(soundData) {
    if (soundData.sound.downloaded) {

        Script.clearInterval(soundData.downloadTimer);

        if (soundData.hasOwnProperty('playAtInterval')) {
            soundData.playingInterval = Script.setInterval(function() {
                playSound(soundData)
            }, soundData.playAtInterval);
        } else {
            playSound(soundData);
        }

    }
}

function startCheckDownloadedTimers() {
    soundMap.forEach(function(soundData) {
        soundData.downloadTimer = Script.setInterval(function() {
            checkDownloaded(soundData);
        }, 1000);
    });
}

Script.scriptEnding.connect(function() {
    soundMap.forEach(function(soundData) {

        if (soundData.hasOwnProperty("injector")) {
            soundData.injector.stop();
        }

        if (soundData.hasOwnProperty("downloadTimer")) {
            Script.clearInterval(soundData.downloadTimer);
        }

        if (soundData.hasOwnProperty("playingInterval")) {
            Script.clearInterval(soundData.playingInterval);
        }

    });

});

loadSounds();
startCheckDownloadedTimers();


#include "types.h"
#include "qpid/Msg.h"
#include "qpid/broker/Message.h"
#include "qpid/broker/Queue.h"
#include "qpid/Exception.h"
#include <algorithm>
#include <iostream>
#include <iterator>
#include <assert.h>

namespace qpid {
namespace ha {

using namespace std;

const string QPID_REPLICATE("qpid.replicate");
const string QPID_HA_UUID("qpid.ha-uuid");

const char* QPID_HA_PREFIX = "qpid.ha-";
const char* QUEUE_REPLICATOR_PREFIX = "qpid.ha-q:";

bool startsWith(const string& name, const string& prefix) {
    return name.compare(0, prefix.size(), prefix) == 0;
}

string EnumBase::str() const {
    assert(value < count);
    return names[value];
}

void EnumBase::parse(const string& s) {
    if (!parseNoThrow(s))
        throw Exception(QPID_MSG("Invalid " << name << " value: " << s));
}

bool EnumBase::parseNoThrow(const string& s) {
    const char** i = find(names, names+count, s);
    value = i - names;
    return value < count;
}

template <> const char* Enum<ReplicateLevel>::NAME = "replication";
template <> const char* Enum<ReplicateLevel>::NAMES[] = { "none", "configuration", "all" };
template <> const size_t Enum<ReplicateLevel>::N = 3;

template <> const char* Enum<BrokerStatus>::NAME = "HA broker status";

// NOTE: Changing status names will  have an impact on qpid-ha and
// the qpidd-primary init script.
// Don't change them unless you are going to  update all dependent code.
//
template <> const char* Enum<BrokerStatus>::NAMES[] = {
    "joining", "catchup", "ready", "recovering", "active", "standalone"
};
template <> const size_t Enum<BrokerStatus>::N = 6;

ostream& operator<<(ostream& o, EnumBase e) {
    return o << e.str();
}

istream& operator>>(istream& i, EnumBase& e) {
    string s;
    i >> s;
    e.parse(s);
    return i;
}

ostream& operator<<(ostream& o, const UuidSet& ids) {
    ostream_iterator<qpid::types::Uuid> out(o, " ");
    o << "{ ";
    for (UuidSet::const_iterator i = ids.begin(); i != ids.end(); ++i)
        o << shortStr(*i) << " ";
    o << "}";
    return o;
}

std::string logMessageId(const std::string& q, QueuePosition pos, ReplicationId id) {
    return Msg() << q << "[" << pos << "]" << "=" << id;
}
std::string logMessageId(const std::string& q, ReplicationId id) {
    return Msg() << q << "[]" << "=" << id;
}
std::string logMessageId(const std::string& q, const broker::Message& m)  {
    return logMessageId(q, m.getSequence(), m.getReplicationId());
}
std::string logMessageId(const broker::Queue& q, QueuePosition pos, ReplicationId id) {
    return logMessageId(q.getName(), pos, id);
}
std::string logMessageId(const broker::Queue& q, ReplicationId id) {
    return logMessageId(q.getName(), id);
}
std::string logMessageId(const broker::Queue& q, const broker::Message& m) {
    return logMessageId(q.getName(), m);
}

void UuidSet::encode(framing::Buffer& b) const {
    b.putLong(size());
    for (const_iterator i = begin(); i != end(); ++i)
        b.putRawData(i->data(), i->size());
}

void UuidSet::decode(framing::Buffer& b) {
    size_t n = b.getLong();
    for ( ; n > 0; --n) {
        types::Uuid id;
        b.getRawData(const_cast<unsigned char*>(id.data()), id.size());
        insert(id);
    }
}

size_t UuidSet::encodedSize() const {
    return sizeof(uint32_t) + size()*16;
}

}} // namespace qpid::ha


package com.amazonaws.services.lambda.model;

import java.io.Serializable;

import com.amazonaws.AmazonWebServiceRequest;

/**
 * Container for the parameters to the {@link com.amazonaws.services.lambda.AWSLambda#listEventSourceMappings(ListEventSourceMappingsRequest) ListEventSourceMappings operation}.
 *

 * Returns a list of event source mappings you created using the
 * CreateEventSourceMapping (see CreateEventSourceMapping),
 * where you identify a stream as an event source. This list does not
 * include Amazon S3 event sources.
 *

 *

 * For each mapping, the API returns configuration information. You can
 * optionally specify filters to retrieve specific event source mappings.
 *

 *

 * This operation requires permission for the
 * lambda:ListEventSourceMappings action.
 *

 *
 * @see com.amazonaws.services.lambda.AWSLambda#listEventSourceMappings(ListEventSourceMappingsRequest)
 */
public class ListEventSourceMappingsRequest extends AmazonWebServiceRequest implements Serializable, Cloneable {

    /**
     * The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     *

     * Constraints:

     * Pattern: arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)

     */
    private String eventSourceArn;

    /**
     * The name of the Lambda function.
 You can specify an unqualified
     * function name (for example, "Thumbnail") or you can specify Amazon
     * Resource Name (ARN) of the function (for example,
     * "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     * also allows you to specify only the account ID qualifier (for example,
     * "account-id:Thumbnail"). Note that the length constraint applies only
     * to the ARN. If you specify only the function name, it is limited to 64
     * character in length.
     *

     * Constraints:

     * Length: 1 - 140

     * Pattern: (arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?

     */
    private String functionName;

    /**
     * Optional string. An opaque pagination token returned from a previous
     * ListEventSourceMappings operation. If present, specifies
     * to continue the list from where the returning call left off.
     */
    private String marker;

    /**
     * Optional integer. Specifies the maximum number of event sources to
     * return in response. This value must be greater than 0.
     *

     * Constraints:

     * Range: 1 - 10000

     */
    private Integer maxItems;

    /**
     * The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     *

     * Constraints:

     * Pattern: arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)

     *
     * @return The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     */
    public String getEventSourceArn() {
        return eventSourceArn;
    }

    /**
     * The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     *

     * Constraints:

     * Pattern: arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)

     *
     * @param eventSourceArn The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     */
    public void setEventSourceArn(String eventSourceArn) {
        this.eventSourceArn = eventSourceArn;
    }

    /**
     * The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     *

     * Returns a reference to this object so that method calls can be chained together.
     *

     * Constraints:

     * Pattern: arn:aws:([a-zA-Z0-9\-])+:([a-z]{2}-[a-z]+-\d{1})?:(\d{12})?:(.*)

     *
     * @param eventSourceArn The Amazon Resource Name (ARN) of the Amazon Kinesis stream.
     *
     * @return A reference to this updated object so that method calls can be chained
     *         together.
     */
    public ListEventSourceMappingsRequest withEventSourceArn(String eventSourceArn) {
        this.eventSourceArn = eventSourceArn;
        return this;
    }

    /**
     * The name of the Lambda function.
 You can specify an unqualified
     * function name (for example, "Thumbnail") or you can specify Amazon
     * Resource Name (ARN) of the function (for example,
     * "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     * also allows you to specify only the account ID qualifier (for example,
     * "account-id:Thumbnail"). Note that the length constraint applies only
     * to the ARN. If you specify only the function name, it is limited to 64
     * character in length.
     *

     * Constraints:

     * Length: 1 - 140

     * Pattern: (arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?

     *
     * @return The name of the Lambda function.
 You can specify an unqualified
     *         function name (for example, "Thumbnail") or you can specify Amazon
     *         Resource Name (ARN) of the function (for example,
     *         "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     *         also allows you to specify only the account ID qualifier (for example,
     *         "account-id:Thumbnail"). Note that the length constraint applies only
     *         to the ARN. If you specify only the function name, it is limited to 64
     *         character in length.
     */
    public String getFunctionName() {
        return functionName;
    }

    /**
     * The name of the Lambda function.
 You can specify an unqualified
     * function name (for example, "Thumbnail") or you can specify Amazon
     * Resource Name (ARN) of the function (for example,
     * "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     * also allows you to specify only the account ID qualifier (for example,
     * "account-id:Thumbnail"). Note that the length constraint applies only
     * to the ARN. If you specify only the function name, it is limited to 64
     * character in length.
     *

     * Constraints:

     * Length: 1 - 140

     * Pattern: (arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?

     *
     * @param functionName The name of the Lambda function.
 You can specify an unqualified
     *         function name (for example, "Thumbnail") or you can specify Amazon
     *         Resource Name (ARN) of the function (for example,
     *         "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     *         also allows you to specify only the account ID qualifier (for example,
     *         "account-id:Thumbnail"). Note that the length constraint applies only
     *         to the ARN. If you specify only the function name, it is limited to 64
     *         character in length.
     */
    public void setFunctionName(String functionName) {
        this.functionName = functionName;
    }

    /**
     * The name of the Lambda function.
 You can specify an unqualified
     * function name (for example, "Thumbnail") or you can specify Amazon
     * Resource Name (ARN) of the function (for example,
     * "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     * also allows you to specify only the account ID qualifier (for example,
     * "account-id:Thumbnail"). Note that the length constraint applies only
     * to the ARN. If you specify only the function name, it is limited to 64
     * character in length.
     *

     * Returns a reference to this object so that method calls can be chained together.
     *

     * Constraints:

     * Length: 1 - 140

     * Pattern: (arn:aws:lambda:)?([a-z]{2}-[a-z]+-\d{1}:)?(\d{12}:)?(function:)?([a-zA-Z0-9-_]+)(:(\$LATEST|[a-zA-Z0-9-_]+))?

     *
     * @param functionName The name of the Lambda function.
 You can specify an unqualified
     *         function name (for example, "Thumbnail") or you can specify Amazon
     *         Resource Name (ARN) of the function (for example,
     *         "arn:aws:lambda:us-west-2:account-id:function:ThumbNail"). AWS Lambda
     *         also allows you to specify only the account ID qualifier (for example,
     *         "account-id:Thumbnail"). Note that the length constraint applies only
     *         to the ARN. If you specify only the function name, it is limited to 64
     *         character in length.
     *
     * @return A reference to this updated object so that method calls can be chained
     *         together.
     */
    public ListEventSourceMappingsRequest withFunctionName(String functionName) {
        this.functionName = functionName;
        return this;
    }

    /**
     * Optional string. An opaque pagination token returned from a previous
     * ListEventSourceMappings operation. If present, specifies
     * to continue the list from where the returning call left off.
     *
     * @return Optional string. An opaque pagination token returned from a previous
     *         ListEventSourceMappings operation. If present, specifies
     *         to continue the list from where the returning call left off.
     */
    public String getMarker() {
        return marker;
    }

    /**
     * Optional string. An opaque pagination token returned from a previous
     * ListEventSourceMappings operation. If present, specifies
     * to continue the list from where the returning call left off.
     *
     * @param marker Optional string. An opaque pagination token returned from a previous
     *         ListEventSourceMappings operation. If present, specifies
     *         to continue the list from where the returning call left off.
     */
    public void setMarker(String marker) {
        this.marker = marker;
    }

    /**
     * Optional string. An opaque pagination token returned from a previous
     * ListEventSourceMappings operation. If present, specifies
     * to continue the list from where the returning call left off.
     *

     * Returns a reference to this object so that method calls can be chained together.
     *
     * @param marker Optional string. An opaque pagination token returned from a previous
     *         ListEventSourceMappings operation. If present, specifies
     *         to continue the list from where the returning call left off.
     *
     * @return A reference to this updated object so that method calls can be chained
     *         together.
     */
    public ListEventSourceMappingsRequest withMarker(String marker) {
        this.marker = marker;
        return this;
    }

    /**
     * Optional integer. Specifies the maximum number of event sources to
     * return in response. This value must be greater than 0.
     *

     * Constraints:

     * Range: 1 - 10000

     *
     * @return Optional integer. Specifies the maximum number of event sources to
     *         return in response. This value must be greater than 0.
     */
    public Integer getMaxItems() {
        return maxItems;
    }

    /**
     * Optional integer. Specifies the maximum number of event sources to
     * return in response. This value must be greater than 0.
     *

     * Constraints:

     * Range: 1 - 10000

     *
     * @param maxItems Optional integer. Specifies the maximum number of event sources to
     *         return in response. This value must be greater than 0.
     */
    public void setMaxItems(Integer maxItems) {
        this.maxItems = maxItems;
    }

    /**
     * Optional integer. Specifies the maximum number of event sources to
     * return in response. This value must be greater than 0.
     *

     * Returns a reference to this object so that method calls can be chained together.
     *

     * Constraints:

     * Range: 1 - 10000

     *
     * @param maxItems Optional integer. Specifies the maximum number of event sources to
     *         return in response. This value must be greater than 0.
     *
     * @return A reference to this updated object so that method calls can be chained
     *         together.
     */
    public ListEventSourceMappingsRequest withMaxItems(Integer maxItems) {
        this.maxItems = maxItems;
        return this;
    }

    /**
     * Returns a string representation of this object; useful for testing and
     * debugging.
     *
     * @return A string representation of this object.
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("{");
        if (getEventSourceArn() != null) sb.append("EventSourceArn: " + getEventSourceArn() + ",");
        if (getFunctionName() != null) sb.append("FunctionName: " + getFunctionName() + ",");
        if (getMarker() != null) sb.append("Marker: " + getMarker() + ",");
        if (getMaxItems() != null) sb.append("MaxItems: " + getMaxItems() );
        sb.append("}");
        return sb.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int hashCode = 1;

        hashCode = prime * hashCode + ((getEventSourceArn() == null) ? 0 : getEventSourceArn().hashCode());
        hashCode = prime * hashCode + ((getFunctionName() == null) ? 0 : getFunctionName().hashCode());
        hashCode = prime * hashCode + ((getMarker() == null) ? 0 : getMarker().hashCode());
        hashCode = prime * hashCode + ((getMaxItems() == null) ? 0 : getMaxItems().hashCode());
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null) return false;

        if (obj instanceof ListEventSourceMappingsRequest == false) return false;
        ListEventSourceMappingsRequest other = (ListEventSourceMappingsRequest)obj;

        if (other.getEventSourceArn() == null ^ this.getEventSourceArn() == null) return false;
        if (other.getEventSourceArn() != null && other.getEventSourceArn().equals(this.getEventSourceArn()) == false) return false;
        if (other.getFunctionName() == null ^ this.getFunctionName() == null) return false;
        if (other.getFunctionName() != null && other.getFunctionName().equals(this.getFunctionName()) == false) return false;
        if (other.getMarker() == null ^ this.getMarker() == null) return false;
        if (other.getMarker() != null && other.getMarker().equals(this.getMarker()) == false) return false;
        if (other.getMaxItems() == null ^ this.getMaxItems() == null) return false;
        if (other.getMaxItems() != null && other.getMaxItems().equals(this.getMaxItems()) == false) return false;
        return true;
    }

    @Override
    public ListEventSourceMappingsRequest clone() {

            return (ListEventSourceMappingsRequest) super.clone();
    }

}


/* */
var MapCache = require('./_MapCache');
var FUNC_ERROR_TEXT = 'Expected a function';
function memoize(func, resolver) {
  if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
    throw new TypeError(FUNC_ERROR_TEXT);
  }
  var memoized = function() {
    var args = arguments,
        key = resolver ? resolver.apply(this, args) : args[0],
        cache = memoized.cache;
    if (cache.has(key)) {
      return cache.get(key);
    }
    var result = func.apply(this, args);
    memoized.cache = cache.set(key, result) || cache;
    return result;
  };
  memoized.cache = new (memoize.Cache || MapCache);
  return memoized;
}
memoize.Cache = MapCache;
module.exports = memoize;