<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/filters/WriterFilter.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware.filters;

import io.vertx.core.buffer.Buffer;

/**
 * # WriterFilter
 */
public interface WriterFilter {
    /**
     * Returns the content encoding name for this filter.
     * @return encoder name gzip, deflate
     */
    String encoding();

    void write(Buffer buffer);

    void write(String chunk);

    void write(String chunk, String enc);

    Buffer end(Buffer buffer);

    Buffer end(String chunk);

    Buffer end(String chunk, String enc);

    boolean canFilter(String contentType);
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/core/YokeAsyncResult.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.core;

import org.jetbrains.annotations.NotNull;
import io.vertx.core.AsyncResult;

/**
 * # YokeAsyncResult
 *
 * Class to wrap a pair of Throwable + Result into a Vert.x AsyncResult Object.
 */
public class YokeAsyncResult<T> implements AsyncResult<T> {
    final Throwable throwable;
    final T result;

    /** Create a YokeAsyncResult given an error object and a result in the same style as CPS. This is useful for
     * scripting engines where data types do not have to match java types.
     *
     * @param error error object null for success
     * @param result operation result any
     */
    public YokeAsyncResult(Object error, T result) {
        if (error != null) {
            if (error instanceof Throwable) {
                this.throwable = (Throwable) error;
            } else if (error instanceof Number) {
                this.throwable = new YokeException((Number) error);
            } else {
                this.throwable = new YokeException(error.toString());
            }
        } else {
            this.throwable = null;
        }
        this.result = result;
    }

    /** Create a new YokeAsyncResult given a Throwable error. This is always a failure result.
     *
     * @param throwable the error that was thrown.
     */
    public YokeAsyncResult(@NotNull Throwable throwable) {
        this.throwable = throwable;
        this.result = null;
    }

    /** Create a new YokeAsyncResult given a T result. This is always a successful result.
     *
     * @param result the result from the operation.
     */
    public YokeAsyncResult(T result) {
        this.throwable = null;
        this.result = result;
    }

    @Override
    public T result() {
        return result;
    }

    @Override
    public Throwable cause() {
        return throwable;
    }

    @Override
    public boolean succeeded() {
        return throwable == null;
    }

    @Override
    public boolean failed() {
        return throwable != null;
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/Logger.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.core.impl.ThreadLocalUTCDateFormat;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.core.net.SocketAddress;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpVersion;

import java.util.Date;

/** # Logger
 *
 * Logger for request. There are 3 formats included:
 * 1. DEFAULT
 * 2. SHORT
 * 3. TINY
 *
 * Default tries to log in a format similar to Apache log format, while the other 2 are more suited to development mode.
 * The logging depends on Vert.x logger settings and the severity of the error, so for errors with status greater or
 * equal to 500 the fatal severity is used, for status greater or equal to 400 the error severity is used, for status
 * greater or equal to 300 warn is used and for status above 100 info is used.
 */
public class Logger extends Middleware {

    private final io.vertx.core.logging.Logger logger = LoggerFactory.getLogger(this.getClass());

    /** The Date formatter (UTC JS compatible format)
     */
    private final ThreadLocalUTCDateFormat ISODATE;

    /**
     * The possible out of the box formats.
     */
    public enum Format {
        DEFAULT,
        SHORT,
        TINY
    }

    /** log before request or after
     */
    private final boolean immediate;

    /** the current choosen format
     */
    private final Format format;

    public Logger(final boolean immediate, @NotNull Format format) {
        this.immediate = immediate;
        this.format = format;

        ISODATE = new ThreadLocalUTCDateFormat();
    }

    public Logger(@NotNull Format format) {
        this(false, format);
    }

    public Logger() {
        this(false, Format.DEFAULT);
    }

    private String getVersionString(HttpVersion version) {
        switch (version) {
            case HTTP_1_1:
                return "HTTP/1.1";
            case HTTP_1_0:
                return "HTTP/1.0";
        }
        return null;
    }

    private String getClientAddress(SocketAddress inetSocketAddress) {
        if (inetSocketAddress == null) {
            return null;
        }

        return inetSocketAddress.host();
    }

    private void log(YokeRequest request, long timestamp, final String remoteClient, final String version, final String method, final String uri) {
        long contentLength = 0;
        if (immediate) {
            Object obj = request.getHeader("content-length");
            if (obj != null) {
                contentLength = Long.parseLong(obj.toString());
            }
        } else {
            Object obj = request.response().getHeader("content-length");
            if (obj != null) {
                contentLength = Long.parseLong(obj.toString());
            }
        }

        int status = request.response().getStatusCode();
        String message = null;

        switch (format) {
            case DEFAULT:
                Object referrer = request.getHeader("referrer", "");
                Object userAgent = request.getHeader("user-agent", "");

                message = String.format("%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\"",
                        remoteClient,
                        ISODATE.format(new Date(timestamp)),
                        method,
                        uri,
                        version,
                        status,
                        contentLength,
                        referrer,
                        userAgent);
                break;
            case SHORT:
                message = String.format("%s - %s %s %s %d %d - %d ms",
                        remoteClient,
                        method,
                        uri,
                        version,
                        status,
                        contentLength,
                        (System.currentTimeMillis() - timestamp));
                break;
            case TINY:
                message = String.format("%s %s %d %d - %d ms",
                        method,
                        uri,
                        status,
                        contentLength,
                        (System.currentTimeMillis() - timestamp));
                break;
        }

        logMessage(status, message);
    }

    protected void logMessage(int status, String message)
    {
        if (status >= 500) {
            logger.fatal(message);
        } else if (status >= 400) {
            logger.error(message);
        } else if (status >= 300) {
            logger.warn(message);
        } else {
            logger.info(message);
        }
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {

        // common logging data
        final long timestamp = System.currentTimeMillis();
        final String remoteClient = getClientAddress(request.remoteAddress());
        final HttpMethod method = request.method();
        final String uri = request.uri();
        final String version = getVersionString(request.version());

        if (immediate) {
            log(request, timestamp, remoteClient, version, method.name(), uri);
        } else {
            request.response().endHandler(new Handler<Void>() {
                @Override
                public void handle(Void event) {
                    log(request, timestamp, remoteClient, version, method.name(), uri);
                }
            });
        }

        next.handle(null);
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/core/RequestWrapper.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.core;

import com.jetdrone.vertx.yoke.Engine;
import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import com.jetdrone.vertx.yoke.store.SessionStore;
import io.vertx.core.http.HttpServerRequest;

import java.util.Map;

/**
 * # RequestWrapper
 *
 * Interface to wrap request objects to language specific implementations. This is an internal interface and should
 * not be used on a normal Yoke application.
 */
public interface RequestWrapper {

    /**
     * For other language bindings this method can be override.
     *
     * @param request The Vertx HttpServerRequest
     * @param context The request context a map where data can be temporarily stored during the lifespan of the request
     * @param engines the current list of render engines (this is an unmodifiable map)
     * @param store the current Session Store implementation
     * @return an Implementation of YokeRequest
     */
    YokeRequest wrap(HttpServerRequest request, Context context, Map<String, Engine> engines, SessionStore store);
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/json/ArrayValidator.java<|end_filename|>
package com.jetdrone.vertx.yoke.json;

import io.vertx.core.json.JsonArray;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public final class ArrayValidator {

    public static boolean isValid(Object instance, JsonSchemaResolver.Schema schema) {
        if (!isArray(instance)) {
            return false;
        }

        // apply default value
        if (instance == null) {
            instance = schema.get("default");
        }

        // from now on work with lists
        if (instance instanceof JsonArray) {
            instance = ((JsonArray) instance).getList();
        }

        final List array = (List) instance;

        if (array != null) {
            // validate additionalItems
            Boolean additionalItems = schema.get("additionalItems");

            if (additionalItems != null && !additionalItems) {
                List<Object> items = schema.get("items");
                if (array.size() > items.size()) {
                    return false;
                }
            }

            // validate maxItems
            Integer maxItems = schema.get("maxItems");

            if (maxItems != null) {
                if (array.size() > maxItems) {
                    return false;
                }
            }

            // validate minItems
            Integer minItems = schema.get("minItems");

            if (minItems != null) {
                if (array.size() < minItems) {
                    return false;
                }
            }

            // validate uniqueItems
            Boolean uniqueItems = schema.get("uniqueItems");

            if (uniqueItems != null && uniqueItems) {
                Set<Object> set = new HashSet<>();

                for (Object o : array) {
                    if (!set.add(o)) {
                        return false;
                    }
                }

                set.clear();
            }

            Object items = schema.get("items");
            JsonSchemaResolver.Schema itemsSchema = null;

            if (items instanceof JsonSchemaResolver.Schema) {
                itemsSchema = (JsonSchemaResolver.Schema) items;
            } else {
                if (items instanceof Map) {
                    // convert to schema
                    itemsSchema = JsonSchemaResolver.resolveSchema((Map<String, Object>) items, schema.getParent());
                    schema.put("items", itemsSchema);
                }
            }

//            setParentIfNotNull(itemsSchema, schema);

            for (Object item : array) {
                if (!JsonSchema.conformsSchema(item, itemsSchema)) {
                    return false;
                }
            }
        }

        return true;
    }

    private static boolean isArray(Object value) {
        return value == null || value instanceof List || value instanceof JsonArray;
    }

    private static void setParentIfNotNull(JsonSchemaResolver.Schema schema, JsonSchemaResolver.Schema parent) {
        if (schema != null) {
            schema.setParent(parent);
        }
    }
}


<|start_filename|>examples/swagger-petstore/src/main/resources/swagger-ui-2.0.12/lib/jquery.slideto.min.js<|end_filename|>
(function (b) {
  b.fn.slideto = function (a) {
    a = b.extend({slide_duration: "slow", highlight_duration: 3E3, highlight: true, highlight_color: "#FFFF99"}, a);
    return this.each(function () {
      obj = b(this);
      b("body").animate({scrollTop: obj.offset().top}, a.slide_duration, function () {
        a.highlight && b.ui.version && obj.effect("highlight", {color: a.highlight_color}, a.highlight_duration)
      })
    })
  }
})(jQuery);


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/engine/AbstractEngineSync.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.engine;

import com.jetdrone.vertx.yoke.Engine;
import com.jetdrone.vertx.yoke.core.impl.LRUCache;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.file.FileProps;
import io.vertx.core.file.FileSystem;

import java.util.Date;

/**
 * # AbstractEngineSync
 *
 * Engine represents a Template Engine that can be registered with Yoke. Any template engine just needs to
 * extend this abstract class. The class provides access to the Vertx object so the engine might do I/O
 * operations in the context of the module.
 */
public abstract class AbstractEngineSync<T> implements Engine {

    protected Vertx vertx;

    private final LRUCache<String, T> cache = new LRUCache<>(1024);

    @Override
    public void setVertx(Vertx vertx) {
        this.vertx = vertx;
    }

    @Override
    public String contentType() {
        return "text/html";
    }

    @Override
    public String contentEncoding() {
        return "UTF-8";
    }

    /**
     * Verifies if a file in the filesystem is still fresh against the cache. Errors are treated as not fresh.
     *
     * @param filename File to look for
     */
    public boolean isFresh(final String filename) {
        final FileSystem fileSystem = vertx.fileSystem();

        try {
            FileProps fileProps = fileSystem.propsBlocking(filename);
            LRUCache.CacheEntry<String, T> cacheEntry = cache.get(filename);
            final long lastModified = fileProps.lastModifiedTime();

            if (cacheEntry == null) {
                return false;
            }
            if (cacheEntry.isFresh(lastModified)) {
                return true;
            }
            // not fresh anymore, purge it
            cache.remove(filename);
            return false;
        } catch (RuntimeException e) {
            return false;
        }
    }

    /**
     * Returns the last modified time for the cache entry
     *
     * @param filename File to look for
     */
    public long lastModified(final String filename) {
        LRUCache.CacheEntry<String, T> cacheEntry = cache.get(filename);
        if (cacheEntry == null) {
            return -1;
        }
        return cacheEntry.lastModified;
    }

    private void loadToCache(final String filename) {
        final FileSystem fileSystem = vertx.fileSystem();

        if (fileSystem.existsBlocking(filename)) {
            FileProps fileProps = fileSystem.propsBlocking(filename);
            final long lastModified = fileProps.lastModifiedTime();
            // load from the file system
            Buffer content = fileSystem.readFileBlocking(filename);
            // cache the result
            cache.put(filename, new LRUCache.CacheEntry<String, T>(lastModified, content.toString(contentEncoding())));
        }
    }

    /**
     * Loads a resource from the filesystem into a string.
     *
     * Verifies if the file last modified date is newer than on the cache
     * if it is loads into a string
     * returns the string or the cached value
     */
    public String read(final String filename) {
        if (isFresh(filename)) {
            String cachedValue = getFileFromCache(filename);
            if (cachedValue != null) {
                return cachedValue;
            }
        }
        // either fresh is false or cachedValue is null
        loadToCache(filename);
        return getFileFromCache(filename);
    }

    /**
     * Gets the content of the file from cache this is a synchronous operation since there is no blocking or I/O
     */
    private String getFileFromCache(String filename) {
        LRUCache.CacheEntry<String, T> cachedTemplate = cache.get(filename);

        if (cachedTemplate == null) {
            return null;
        }

        return cache.get(filename).raw;
    }

    /**
     * Gets the compiled value from cache this is a synchronous operation since there is no blocking or I/O
     */
    public T getTemplateFromCache(String filename) {

        LRUCache.CacheEntry<String, T> cachedTemplate = cache.get(filename);

        // this is to avoid null pointer exception in case of the layout composite template
        if (cachedTemplate == null) {
            return null;
        }

        return cachedTemplate.compiled;
    }

    /**
     * Gets the compiled value from cache this is a synchronous operation since there is no blocking or I/O
     */
    public void putTemplateToCache(String filename, T template) {
        cache.putCompiled(filename, template);
    }

    /**
     * Removes an entry from cache
     */
    public void removeFromCache(String filename) {
        cache.remove(filename);
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/ErrorHandler.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.util.Utils;
import com.jetdrone.vertx.yoke.core.YokeException;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * # ErrorHandler
 *
 * Creates pretty print error pages in *html*, *text* or *json* depending on the *accept* header from the client.
 */
public class ErrorHandler extends Middleware {

    /**
     * Flag to enable/disable printing the full stack trace of exceptions.
     */
    private final boolean fullStack;

    /**
     * Cached template for rendering the html errors
     */
    private final String errorTemplate;

    /**
     * Create a new ErrorHandler allowing to print or not the stack trace. Include stack trace `true` might be useful in
     * development mode but probably you don't want it in production.
     *
     * <pre>
     * Yoke yoke = new Yoke(...);
     * yoke.use(new ErrorHandler(true);
     * </pre>
     *
     * @param fullStack include full stack trace in error report.
     */
    public ErrorHandler(boolean fullStack) {
        this.fullStack = fullStack;
        errorTemplate = Utils.readResourceToBuffer(getClass(), "error.html").toString();
    }

    /**
     * Override the Middleware isErrorHandler getter.
     *
     * @return always true
     */
    @Override
    public boolean isErrorHandler() {
        return true;
    }

    /**
     * Extracts a single message from a error Object. This will handle Throwables, Strings and Numbers. In case of
     * numbers these are handled as Http error codes.
     *
     * @param error Error object
     * @return String representation of the error object.
     */
    private String getMessage(Object error) {
        if (error instanceof Throwable) {
            String message = ((Throwable) error).getMessage();

            if (message == null) {
                if (fullStack) {
                    message = error.getClass().getName();
                }
            }

            return message;
        } else if (error instanceof String) {
            return (String) error;
        } else if (error instanceof Integer) {
            return HttpResponseStatus.valueOf((Integer) error).reasonPhrase();
        } else if (error instanceof JsonObject) {
            return ((JsonObject) error).getString("message");
        } else if (error instanceof Map) {
            return (String) ((Map) error).get("message");
        } else {
            return error.toString();
        }
    }

    /**
     * Extracts a single error code from a error Object. This will handle Throwables, Strings and Numbers.
     *
     * @param error Error object
     * @return HTTP status code for the error object
     */
    private int getErrorCode(Object error) {
        if (error instanceof Number) {
            return ((Number) error).intValue();
        } else if (error instanceof YokeException) {
            return ((YokeException) error).getErrorCode().intValue();
        } else if (error instanceof JsonObject) {
            return ((JsonObject) error).getInteger("errorCode", 500);
        } else if (error instanceof Map) {
            Integer tmp = (Integer) ((Map) error).get("errorCode");
            return tmp != null ? tmp : 500;
        } else {
            return 500;
        }
    }

    /**
     * Convert the stack trace to a List in order to be rendered in the error template.
     *
     * @param error error object
     * @return List containing the stack trace for the object
     */
    private List<String> getStackTrace(Object error) {
        if (fullStack && error instanceof Throwable) {
            List<String> stackTrace = new ArrayList<>();
            for (StackTraceElement t : ((Throwable) error).getStackTrace()) {
                stackTrace.add(t.toString());
            }
            return stackTrace;
        } else {
            return Collections.emptyList();
        }
    }

    private boolean sendError(YokeRequest request, String mime, int errorCode, String errorMessage, List<String> stackTrace) {

        YokeResponse response = request.response();

        if (mime.startsWith("text/html")) {
            StringBuilder stack = new StringBuilder();
            for (String s : stackTrace) {
                stack.append("<li>");
                stack.append(s);
                stack.append("</li>");
            }

            response.setContentType("text/html");
            response.end(
                    errorTemplate.replace("{title}", request.get("title"))
                            .replace("{errorCode}", Integer.toString(errorCode))
                            .replace("{errorMessage}", errorMessage == null ? "" : errorMessage)
                            .replace("{stackTrace}", stack.toString())
            );
            return true;
        }

        if (mime.startsWith("application/json")) {
            JsonObject jsonError = new JsonObject();
            JsonObject jsonErrorMessage = new JsonObject().put("code", errorCode);

            jsonError.put("error", jsonErrorMessage);

            if (errorMessage != null) {
                jsonError.put("message", errorMessage);
            }

            if (!stackTrace.isEmpty()) {
                JsonArray stack = new JsonArray();
                for (String t : stackTrace) {
                    stack.add(t);
                }
                jsonError.put("stack", stack);
            }
            response.setContentType("application/json", "UTF-8");
            response.end(jsonError.encode());
            return true;
        }

        if (mime.startsWith("text/plain")) {
            response.setContentType("text/plain");

            StringBuilder sb = new StringBuilder();
            sb.append("Error ");
            sb.append(errorCode);

            if (errorMessage != null) {
                sb.append(": ");
                sb.append(errorMessage);
            }

            for (String t : stackTrace) {
                sb.append("\tat ");
                sb.append(t);
                sb.append("\n");
            }

            response.end(sb.toString());
            return true;
        }

        return false;
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {

        YokeResponse response = request.response();

        if (response.getStatusCode() < 400) {
            response.setStatusCode(getErrorCode(request.get("error")));
        }

        if (request.get("error") == null) {
            request.put("error", response.getStatusCode());
        }
        String errorMessage = getMessage(request.get("error"));
        int errorCode = response.getStatusCode();

        // set the status message also to the right error code
        response.setStatusMessage(HttpResponseStatus.valueOf(errorCode).reasonPhrase());

        List<String> stackTrace = getStackTrace(request.get("error"));

        // does the response already set the mime type?
        String mime = response.getHeader("content-type");

        if (mime != null) {
            if (sendError(request, mime, errorCode, errorMessage, stackTrace)) {
                return;
            }
        }

        // respect the client accept order
        List<String> acceptedMimes = request.sortedHeader("accept");

        for (String accept : acceptedMimes) {
            if (sendError(request, accept, errorCode, errorMessage, stackTrace)) {
                return;
            }
        }

        // fall back plain/text
        sendError(request, "text/plain", errorCode, errorMessage, stackTrace);
    }
}


<|start_filename|>middleware/helmet/src/main/java/com/jetdrone/vertx/yoke/middleware/XFrame.java<|end_filename|>
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

public final class XFrame extends Middleware {

    public static enum Action {
        DENY("DENY"),
        ALLOWFROM("ALLOW-FROM"),
        SAMEORIGIN("SAMEORIGIN");

        private final String action;

        Action(String action) {
            this.action = action;
        }

        @Override
        public String toString() {
            return action;
        }
    }

    private final String header;

    public XFrame() {
        this(Action.DENY);
    }

    public XFrame(Action action) {
        this(action, null);
    }

    public XFrame(Action action, String option) {
        if (action == Action.ALLOWFROM && option == null) {
            throw new RuntimeException("ALLOW-FROM requires a second argument");
        }

        if (action == Action.ALLOWFROM) {
            header = Action.ALLOWFROM.toString() + " " + option;
        } else {
            header = action.toString();
        }
    }

    @Override
    public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
        request.response().putHeader("X-FRAME-OPTIONS", header);
        next.handle(null);
    }
}


<|start_filename|>engine/mvel/src/main/java/com/jetdrone/vertx/yoke/engine/MVELEngine.java<|end_filename|>
/*
 * Copyright 2011-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetdrone.vertx.yoke.engine;

import com.jetdrone.vertx.yoke.core.YokeAsyncResult;
import org.mvel2.templates.CompiledTemplate;
import org.mvel2.templates.TemplateCompiler;
import org.mvel2.templates.TemplateRuntime;
import io.vertx.core.AsyncResult;
import io.vertx.core.AsyncResultHandler;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;

import java.io.IOException;
import java.util.Map;

public class MVELEngine extends AbstractEngine<CompiledTemplate> {

    private final String extension;
    private final String prefix;

    public MVELEngine(final String views) {
        this(views, ".mvel");
    }

    public MVELEngine(final String views, final String extension) {
        this.extension = extension;

        if ("".equals(views)) {
            prefix = views;
        } else {
            prefix = views.endsWith("/") ? views : views + "/";
        }
    }

    @Override
    public String extension() {
        return extension;
    }

    @Override
    public void render(final String filename, final Map<String, Object> context, final Handler<AsyncResult<Buffer>> next) {
        read(prefix + filename, new AsyncResultHandler<String>() {
            @Override
            public void handle(AsyncResult<String> asyncResult) {
                if (asyncResult.failed()) {
                    next.handle(new YokeAsyncResult<Buffer>(asyncResult.cause()));
                } else {
                    try {
                        CompiledTemplate template = compile(prefix + filename, asyncResult.result());
                        next.handle(new YokeAsyncResult<>(Buffer.buffer((String) TemplateRuntime.execute(template, context))));
                    } catch (IOException ex) {
                        next.handle(new YokeAsyncResult<Buffer>(ex));
                    }
                }
            }
        });
    }

    private CompiledTemplate compile(String filename, String templateText) throws IOException {

        CompiledTemplate template = getTemplateFromCache(filename);

        if (template == null) {
            // real compile
            template = TemplateCompiler.compileTemplate(templateText);
            putTemplateToCache(filename, template);
        }

        return template;
    }
}


<|start_filename|>examples/swagger-petstore/src/main/resources/swagger-ui-2.0.12/lib/jquery.wiggle.min.js<|end_filename|>
/*
 jQuery Wiggle
 Author: WonderGroup, <NAME>
 URL: http://labs.wondergroup.com/demos/mini-ui/index.html
 License: MIT (http://en.wikipedia.org/wiki/MIT_License)
 */
jQuery.fn.wiggle = function (o) {
  var d = {speed: 50, wiggles: 3, travel: 5, callback: null};
  var o = jQuery.extend(d, o);
  return this.each(function () {
    var cache = this;
    var wrap = jQuery(this).wrap('<div class="wiggle-wrap"></div>').css("position", "relative");
    var calls = 0;
    for (i = 1; i <= o.wiggles; i++) {
      jQuery(this).animate({left: "-=" + o.travel}, o.speed).animate({left: "+=" + o.travel * 2}, o.speed * 2).animate({left: "-=" + o.travel}, o.speed, function () {
        calls++;
        if (jQuery(cache).parent().hasClass('wiggle-wrap')) {
          jQuery(cache).parent().replaceWith(cache);
        }
        if (calls == o.wiggles && jQuery.isFunction(o.callback)) {
          o.callback();
        }
      });
    }
  });
};

<|start_filename|>middleware/helmet/src/main/java/com/jetdrone/vertx/yoke/middleware/IEXSS.java<|end_filename|>
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.middleware.impl.WebClient;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

public final class IEXSS extends Middleware {

    private final boolean setOnOldIE;

    public IEXSS() {
        this(false);
    }

    public IEXSS(boolean setOnOldIE) {
        this.setOnOldIE = setOnOldIE;
    }

    @Override
    public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
        final WebClient webClient = WebClient.detect(request.getHeader("user-agent"));

        boolean isIE = webClient.getUserAgent() == WebClient.UserAgent.IE;
        int majorVersion = webClient.getMajorVersion();

        String value;

        if ((!isIE) || (majorVersion >= 9) || (setOnOldIE)) {
            value = "1; mode=block";
        } else {
            value = "0";
        }

        request.response().putHeader("X-XSS-Protection", value);
        next.handle(null);
    }
}


<|start_filename|>middleware/reststore/src/main/java/com/jetdrone/vertx/yoke/middleware/rest/ValidatingStore.java<|end_filename|>
/*
 * Copyright 2011-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetdrone.vertx.yoke.middleware.rest;

import com.jetdrone.vertx.yoke.core.YokeAsyncResult;
import io.vertx.core.AsyncResultHandler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

public class ValidatingStore extends AbstractValidatingStore {

    public ValidatingStore(Store store) {
        super(store);
    }

    private static final YokeAsyncResult<String> OK_STRING = new YokeAsyncResult<>(null, null);
    private static final YokeAsyncResult<JsonObject> OK_JSONOBJECT = new YokeAsyncResult<>(null, null);
    private static final YokeAsyncResult<JsonArray> OK_JSONARRAY = new YokeAsyncResult<>(null, null);
    private static final YokeAsyncResult<Number> OK_NUMBER = new YokeAsyncResult<>(null, null);

    public void beforeCreate(String entity, JsonObject object, AsyncResultHandler<String> response) {
        response.handle(OK_STRING);
    }

    public void afterCreate(String entity, JsonObject object, AsyncResultHandler<String> response) {
        response.handle(OK_STRING);
    }

    public void beforeRead(String entity, String id, AsyncResultHandler<JsonObject> response) {
        response.handle(OK_JSONOBJECT);
    }

    public void afterRead(String entity, String id, AsyncResultHandler<JsonObject> response) {
        response.handle(OK_JSONOBJECT);
    }

    public void beforeUpdate(String entity, String id, JsonObject object, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }

    public void afterUpdate(String entity, String id, JsonObject object, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }

    public void beforeDelete(String entity, String id, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }

    public void afterDelete(String entity, String id, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }

    public void beforeQuery(String entity, JsonObject query, Number start, Number end, JsonObject sort, AsyncResultHandler<JsonArray> response) {
        response.handle(OK_JSONARRAY);
    }

    public void afterQuery(String entity, JsonObject query, Number start, Number end, JsonObject sort, AsyncResultHandler<JsonArray> response) {
        response.handle(OK_JSONARRAY);
    }

    public void beforeCount(String entity, JsonObject query, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }

    public void afterCount(String entity, JsonObject query, AsyncResultHandler<Number> response) {
        response.handle(OK_NUMBER);
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/Csrf.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import io.vertx.core.http.HttpMethod;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

import java.util.UUID;

/**
 * # Csrf
 *
 * This middleware adds a CSRF token to requests which mutate state. You should put the result within a hidden form
 * field, query-string etc. This token should be validated against the visitor's session.
 * The default value handler checks request body generated by the BodyParser middleware, request query generated and
 * the "X-CSRF-Token" header field.
 *
 * This middleware requires session support, thus should be added somewhere below Session.
 */
public class Csrf extends Middleware {

    /**
     * Handler that validates the CRSF token
     */
    private final ValueHandler valueHandler;

    /**
     * Name of the property where the token is found/stored in the request context
     */
    private final String key;

    /**
     * Instantiate a new Csrf with a user defined key
     *
     * <pre>
     * new Csrf("_crsf")
     * </pre>
     *
     * @param key name of the context variable to store the token.
     */
    public Csrf(@NotNull final String key) {
        this.key = key;
        valueHandler = new ValueHandler() {
            @Override
            public String handle(YokeRequest request) {
                String token = request.formAttributes().get(key);
                if (token == null) {
                    token = request.params().get(key);
                    if (token == null) {
                        token = request.headers().get("x-csrf-token");
                    }
                }

                return token;
            }
        };
    }

    /**
     * Instantiate a new Csrf with the default key "_crsf"
     *
     * <pre>
     * new Csrf()
     * </pre>
     */
    public Csrf() {
        this("_csrf");
    }

    /**
     * Instantiate a new Csrf with custom Handler and key
     *
     * <pre>
     * new Csrf("_crsf", new ValueHandler() {...})
     * </pre>
     *
     * @param key          name of the context variable to store the token.
     * @param valueHandler the handler for the token validation.
     */
    public Csrf(@NotNull String key, @NotNull ValueHandler valueHandler) {
        this.key = key;
        this.valueHandler = valueHandler;
    }

    /**
     * Instantiate a new Csrf with custom Handler
     *
     * <pre>
     * new Csrf(new ValueHandler() {...})
     * </pre>
     *
     * @param valueHandler the handler for the token validation.
     */
    public Csrf(@NotNull final ValueHandler valueHandler) {
        this("_csrf", valueHandler);
    }

    public interface ValueHandler {
        String handle(YokeRequest request);
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {

        String token = request.get(key);
        // generate CSRF token
        if (token == null) {
            token = UUID.randomUUID().toString();
            request.put(key, token);
        }

        // ignore these methods
        if (HttpMethod.GET.equals(request.method()) || HttpMethod.HEAD.equals(request.method()) || HttpMethod.OPTIONS.equals(request.method())) {
            next.handle(null);
            return;
        }

        // expect multipart
        request.setExpectMultipart(true);

        // determine value
        String val = valueHandler.handle(request);

        // check
        if (!token.equals(val)) {
            next.handle(403);
            return;
        }

        // OK
        next.handle(null);
    }

}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/ResponseHeaders.java<|end_filename|>

package com.jetdrone.vertx.yoke.middleware;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

import com.jetdrone.vertx.yoke.Middleware;

/**
 * <p>
 * A simple {@link Middleware} that allows adding custom response headers to all
 * {@link YokeResponse}.
 * </p>
 * <p>
 * Example:
 * </p>
 *
 * <pre>
 * {@code
 * yoke.use(new ResponseHeaders()
 *          .with("X-Build-Meta", "1.0-SNAPSHOT")
 *          .with("X-Server-Id", "server-123"));
 * }
 * </pre>
 */
public class ResponseHeaders extends Middleware
{
    private final Map<CharSequence, CharSequence[]> headers;

    public ResponseHeaders()
    {
        headers = new HashMap<>();
    }

    public ResponseHeaders with(final CharSequence name, final CharSequence... values)
    {
        headers.put(name, values);
        return this;
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next)
    {
        for (final Entry<CharSequence, CharSequence[]> header : headers.entrySet())
        {
            request.response().headers().add(header.getKey(), Arrays.asList(header.getValue()));
        }

        next.handle(null);
    }
}


<|start_filename|>examples/cluster-benchmark/src/main/java/com/jetdrone/vertx/bench/YokeBench.java<|end_filename|>
package com.jetdrone.vertx.bench;

import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.middleware.Router;
import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;

public class YokeBench extends AbstractVerticle {

  @Override
  public void start() {

    new Yoke(this)
        .use(new Router()
            .get("/", new Handler<YokeRequest>() {
              @Override
              public void handle(YokeRequest request) {
                request.response().end("Hello World\n");
              }
            })
        ).listen(8080);
  }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/Yoke.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke;

import com.jetdrone.vertx.yoke.core.Context;
import com.jetdrone.vertx.yoke.core.MountedMiddleware;
import com.jetdrone.vertx.yoke.core.RequestWrapper;
import com.jetdrone.vertx.yoke.core.impl.DefaultRequestWrapper;
import com.jetdrone.vertx.yoke.jmx.ContextMBean;
import com.jetdrone.vertx.yoke.jmx.MiddlewareMBean;
import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import com.jetdrone.vertx.yoke.security.KeyStoreSecurity;
import com.jetdrone.vertx.yoke.security.SecretSecurity;
import com.jetdrone.vertx.yoke.store.SessionStore;
import com.jetdrone.vertx.yoke.store.SharedDataSessionStore;
import com.jetdrone.vertx.yoke.core.YokeException;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.vertx.core.*;
import io.vertx.core.http.HttpServer;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.impl.VertxInternal;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import org.jetbrains.annotations.*;

import javax.management.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.management.ManagementFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.*;

/**
 * # Yoke
 *
 * Yoke is a chain executor of middleware for Vert.x 2.x. The goal of this library is not to provide a web application
 * framework but the backbone that helps the creation of web applications.
 *
 * Yoke works in a similar way to Connect middleware. Users start by declaring which middleware components want to use
 * and then start an http server either managed by Yoke or provided by the user (say when you need https).
 *
 * Yoke has no extra dependencies than Vert.x itself so it is self contained.
 */
public class Yoke {

    //Get the MBean server
    private final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();

    /**
     * Vert.x instance
     */
    private final Vertx vertx;

    /**
     * request wrapper in use
     */
    private final RequestWrapper requestWrapper;

    /**
     * default context used by all requests
     *
     * <pre>
     * {
     *   title: "Yoke",
     *   x-powered-by: true,
     *   trust-proxy: true
     * }
     * </pre>
     */
    protected final Map<String, Object> defaultContext = new HashMap<>();

    /**
     * The internal registry of [render engines](Engine.html)
     */
    private final Map<String, Engine> engineMap = new HashMap<>();

    /**
     * Creates a Yoke instance.
     *
     * This constructor should be called from a verticle and pass a valid Vertx instance. This instance will be shared
     * with all registered middleware. The reason behind this is to allow middleware to use Vertx features such as file
     * system and timers.
     *
     * <pre>
     * public class MyVerticle extends AbstractVerticle {
     *   public void start() {
     *     final Yoke yoke = new Yoke(this);
     *     ...
     *   }
     * }
     * </pre>
     *
     * @param verticle the main verticle
     */
    public Yoke(@NotNull Verticle verticle) {
        this(verticle.getVertx());
    }

    /**
     * Creates a Yoke instance.
     *
     * This constructor should be called from a verticle and pass a valid Vertx instance and a Logger. This instance
     * will be shared with all registered middleware. The reason behind this is to allow middleware to use Vertx
     * features such as file system and timers.
     *
     * <pre>
     * public class MyVerticle extends AbstractVerticle {
     *   public void start() {
     *     final Yoke yoke = new Yoke(getVertx());
     *     ...
     *   }
     * }
     * </pre>
     *
     * @param vertx
     */
    public Yoke(@NotNull Vertx vertx) {
        this(vertx, new DefaultRequestWrapper());
    }

    /**
     * Creates a Yoke instance.
     *
     * This constructor should be called internally or from other language bindings.
     *
     * <pre>
     * public class MyVerticle extends AbstractVerticle {
     *   public void start() {
     *     final Yoke yoke = new Yoke(getVertx(),
     *         new RequestWrapper() {...});
     *     ...
     *   }
     * }
     * </pre>
     *
     * @param vertx
     * @param requestWrapper
     */
    public Yoke(@NotNull Vertx vertx, @NotNull RequestWrapper requestWrapper) {
        this.vertx = vertx;
        this.requestWrapper = requestWrapper;
        defaultContext.put("title", "Yoke");
        defaultContext.put("x-powered-by", true);
        defaultContext.put("trust-proxy", true);
        store = new SharedDataSessionStore(vertx, "yoke.sessiondata");

        // register on JMX
        try {
            mbs.registerMBean(new ContextMBean(defaultContext), new ObjectName("com.jetdrone.yoke:instance=@" + hashCode() + ",type=DefaultContext@" + defaultContext.hashCode()));
        } catch (InstanceAlreadyExistsException e) {
            // ignore
        } catch (MalformedObjectNameException | MBeanRegistrationException | NotCompliantMBeanException e) {
            throw new RuntimeException(e);
        }
    }

    public Vertx vertx() {
        return vertx;
    }

    /**
     * Ordered list of mounted middleware in the chain
     */
    private final List<MountedMiddleware> middlewareList = new ArrayList<>();

    /**
     * Special middleware used for error handling
     */
    private IMiddleware errorHandler;

    /**
     * Adds a IMiddleware to the chain. If the middleware is an Error Handler IMiddleware then it is
     * treated differently and only the last error handler is kept.
     *
     * You might want to add a middleware that is only supposed to run on a specific route (path prefix).
     * In this case if the request path does not match the prefix the middleware is skipped automatically.
     *
     * <pre>
     * yoke.use("/login", new CustomLoginMiddleware());
     * </pre>
     *
     * @param route      The route prefix for the middleware
     * @param middleware The middleware add to the chain
     */
    public Yoke use(@NotNull String route, @NotNull IMiddleware... middleware) {
        for (IMiddleware m : middleware) {
            if (m instanceof Middleware) {
                // when the type of middleware is error handler then the route is ignored and
                // the middleware is extracted from the execution chain into a special placeholder
                // for error handling
                if (((Middleware) m).isErrorHandler()) {
                    errorHandler = m;
                } else {
                    MountedMiddleware mm = new MountedMiddleware(route, m);
                    middlewareList.add(mm);

                    // register on JMX
                    try {
                        mbs.registerMBean(new MiddlewareMBean(mm), new ObjectName("com.jetdrone.yoke:type=Middleware@" + hashCode() + ",route=" + ObjectName.quote(route) + ",name=" + m.getClass().getSimpleName() + "@" + m.hashCode()));
                    } catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
                        throw new RuntimeException(e);
                    }
                }

                // initialize the middleware with the current Vert.x and Logger
                ((Middleware) m).init(this, route);
            } else {
                MountedMiddleware mm = new MountedMiddleware(route, m);
                middlewareList.add(mm);

                // register on JMX
                try {
                    mbs.registerMBean(new MiddlewareMBean(mm), new ObjectName("com.jetdrone.yoke:type=Middleware@" + hashCode() + ",route=" + ObjectName.quote(route) + ",name=" + m.getClass().getSimpleName() + "@" + m.hashCode()));
                } catch (MalformedObjectNameException | InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return this;
    }

    /**
     * Adds a middleware to the chain with the prefix "/".
     *
     * @param middleware The middleware add to the chain
     */
    public Yoke use(@NotNull IMiddleware... middleware) {
        return use("/", middleware);
    }

    /**
     * Adds a Handler to a route. The behaviour is similar to the middleware, however this
     * will be a terminal point in the execution chain. In this case any middleware added
     * after will not be executed. However you should care about the route which may lead
     * to skip this middleware.
     *
     * The idea to user a Handler is to keep the API familiar with the rest of the Vert.x
     * API.
     *
     * <pre>
     * yoke.use("/login", new Handler&lt;YokeRequest&gt;() {
     *   public void handle(YokeRequest request) {
     *     request.response.end("Hello");
     *   }
     * });
     * </pre>
     *
     * @param route   The route prefix for the middleware
     * @param handler The Handler to add
     */
    public Yoke use(@NotNull String route, final @NotNull Handler<YokeRequest> handler) {
        middlewareList.add(new MountedMiddleware(route, new IMiddleware() {
            @Override
            public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
                handler.handle(request);
            }
        }));
        return this;
    }

    /**
     * Adds a Handler to a route.
     *
     * <pre>
     * yoke.use("/login", new Handler&lt;YokeRequest&gt;() {
     *   public void handle(YokeRequest request) {
     *     request.response.end("Hello");
     *   }
     * });
     * </pre>
     * @param handler The Handler to add
     */
    public Yoke use(@NotNull Handler<YokeRequest> handler) {
        return use("/", handler);
    }

    /**
     * Adds a Render Engine to the library. Render Engines are Template engines you
     * might want to use to speed the development of your application. Once they are
     * registered you can use the method render in the YokeResponse to
     * render a template.
     *
     * @param engine    The implementation of the engine
     */
    public Yoke engine(@NotNull Engine engine) {
        engine.setVertx(vertx);
        engineMap.put(engine.extension(), engine);
        return this;
    }

    /**
     * Special store engine used for accessing session data
     */
    protected SessionStore store;

    public Yoke store(@NotNull SessionStore store) {
        this.store = store;
        return this;
    }

    protected YokeSecurity security;

    public Yoke keyStoreSecurity(@NotNull final String fileName, @NotNull final String keyStorePassword, @NotNull final JsonObject keyPasswords) {
        String storeType;
        int idx = fileName.lastIndexOf('.');

        if (idx == -1) {
            storeType = KeyStore.getDefaultType();
        } else {
            storeType = fileName.substring(idx + 1);
        }

        try {
            KeyStore ks = KeyStore.getInstance(storeType);

            try (InputStream in = new FileInputStream(((VertxInternal) vertx).resolveFile(fileName))) {
                ks.load(in, keyStorePassword.toCharArray());
            }

            this.security = new KeyStoreSecurity(ks, keyPasswords.getMap());

        } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        return this;
    }

    public Yoke keyStoreSecurity(@NotNull final String fileName, @NotNull final String keyStorePassword) {
        String storeType;
        int idx = fileName.lastIndexOf('.');

        if (idx == -1) {
            storeType = KeyStore.getDefaultType();
        } else {
            storeType = fileName.substring(idx + 1);
        }

        try {
            KeyStore ks = KeyStore.getInstance(storeType);

            try (InputStream in = new FileInputStream(((VertxInternal) vertx).resolveFile(fileName))) {
                ks.load(in, keyStorePassword.toCharArray());
            }

            this.security = new KeyStoreSecurity(ks, keyStorePassword);

        } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        return this;
    }

    public Yoke secretSecurity(@NotNull final String secret) {
        this.security = new SecretSecurity(secret);
        return this;
    }

    public Yoke secretSecurity(@NotNull final byte[] secret) {
        this.security = new SecretSecurity(secret);
        return this;
    }

    public YokeSecurity security() {
        if (security == null) {
            throw new RuntimeException("No YokeSecurity implementation is enabled!");
        }

        return security;
    }

    /**
     * When you need to share global properties with your requests you can add them
     * to Yoke and on every request they will be available as request.get(String)
     *
     * @param key   unique identifier
     * @param value Any non null value, nulls are not saved
     */
    public Yoke set(@NotNull String key, Object value) {
        if (value == null) {
            defaultContext.remove(key);
        } else {
            defaultContext.put(key, value);
        }

        return this;
    }

    /**
     * Starts the server listening at a given port bind to all available interfaces.
     *
     * @param port the server TCP port
     * @return {Yoke}
     */
    public Yoke listen(int port) {
        return listen(port, "0.0.0.0", null);
    }

    /**
     * Starts the server listening at a given port bind to all available interfaces.
     *
     * @param port    the server TCP port
     * @param handler for asynchronous result of the listen operation
     * @return {Yoke}
     */
    public Yoke listen(int port, @NotNull Handler<Boolean> handler) {
        return listen(port, "0.0.0.0", handler);
    }

    /**
     * Starts the server listening at a given port and given address.
     *
     * @param port the server TCP port
     * @return {Yoke}
     */
    public Yoke listen(int port, @NotNull String address) {
        return listen(port, address, null);
    }

    /**
     * Starts the server listening at a given port and given address.
     *
     * @param port    the server TCP port
     * @param handler for asynchronous result of the listen operation
     * @return {Yoke}
     */
    public Yoke listen(int port, @NotNull String address, final Handler<Boolean> handler) {
        HttpServer server = vertx.createHttpServer();

        listen(server);

        if (handler != null) {
            server.listen(port, address, new Handler<AsyncResult<HttpServer>>() {
                @Override
                public void handle(AsyncResult<HttpServer> listen) {
                    handler.handle(listen.succeeded());
                }
            });
        } else {
            server.listen(port, address);
        }
        return this;
    }

    /**
     * Starts listening at a already created server.
     *
     * @param server
     * @return {Yoke}
     */
    public Yoke listen(final @NotNull HttpServer server) {
        server.requestHandler(new Handler<HttpServerRequest>() {
            @Override
            public void handle(HttpServerRequest req) {
                // the context map is shared with all middlewares
                final YokeRequest request = requestWrapper.wrap(req, new Context(defaultContext), engineMap, store);

                // add x-powered-by header is enabled
                Boolean poweredBy = request.get("x-powered-by");
                if (poweredBy != null && poweredBy) {
                    request.response().putHeader("x-powered-by", "yoke");
                }

                new Handler<Object>() {
                    int currentMiddleware = -1;

                    @Override
                    public void handle(Object error) {
                        if (error == null) {
                            currentMiddleware++;
                            if (currentMiddleware < middlewareList.size()) {
                                final MountedMiddleware mountedMiddleware = middlewareList.get(currentMiddleware);

                                if (!mountedMiddleware.enabled) {
                                    // the middleware is disabled
                                    handle(null);
                                } else {
                                    if (request.path().startsWith(mountedMiddleware.mount)) {
                                        mountedMiddleware.middleware.handle(request, this);
                                    } else {
                                        // the middleware was not mounted on this uri, skip to the next entry
                                        handle(null);
                                    }
                                }
                            } else {
                                HttpServerResponse response = request.response();
                                // reached the end and no handler was able to answer the request
                                response.setStatusCode(404);
                                response.setStatusMessage(HttpResponseStatus.valueOf(404).reasonPhrase());
                                if (errorHandler != null) {
                                    errorHandler.handle(request, null);
                                } else {
                                    response.end(HttpResponseStatus.valueOf(404).reasonPhrase());
                                }
                            }
                        } else {
                            request.put("error", error);
                            if (errorHandler != null) {
                                errorHandler.handle(request, null);
                            } else {
                                HttpServerResponse response = request.response();

                                int errorCode;
                                // if the error was set on the response use it
                                if (response.getStatusCode() >= 400) {
                                    errorCode = response.getStatusCode();
                                } else {
                                    // if it was set as the error object use it
                                    if (error instanceof Number) {
                                        errorCode = ((Number) error).intValue();
                                    } else if (error instanceof YokeException) {
                                        errorCode = ((YokeException) error).getErrorCode().intValue();
                                    } else if (error instanceof JsonObject) {
                                        errorCode = ((JsonObject) error).getInteger("errorCode", 500);
                                    } else if (error instanceof Map) {
                                        Integer tmp = (Integer) ((Map) error).get("errorCode");
                                        errorCode = tmp != null ? tmp : 500;
                                    } else {
                                        // default error code
                                        errorCode = 500;
                                    }
                                }

                                response.setStatusCode(errorCode);
                                response.setStatusMessage(HttpResponseStatus.valueOf(errorCode).reasonPhrase());
                                response.end(HttpResponseStatus.valueOf(errorCode).reasonPhrase());
                            }
                        }
                    }
                }.handle(null);
            }
        });
        return this;
    }

    /**
     * Deploys required middleware from a config json element.
     *
     * The current format for the config is either a single item or an array:
     * <pre>
     * [{
     *   module: String, // the name of the module
     *   verticle: String, // the name of the verticle (either verticle or module must be present)
     *   instances: Number, // how many instances, default 1
     *   worker: Boolean, // is it a worker verticle? default false
     *   multiThreaded: Boolean, // is it a multiThreaded verticle? default false
     *   config: JsonObject // any config you need to pass to the module/verticle
     * }]
     * </pre>
     *
     * @param config a json array.
     */
    public Yoke deploy(@NotNull JsonArray config) {
        return deploy(config, null);
    }

    /**
     * Deploys required middleware from a config json element. The handler is only called once all middleware is
     * deployed or in error. The order of deployment is not guaranteed since all deploy functions are called
     * concurrently and do not wait for the previous result before deploying the next item.
     *
     * The current format for the config is either a single item or an array:
     * <pre>
     * {
     *   module: String, // the name of the module
     *   verticle: String, // the name of the verticle (either verticle or module must be present)
     *   instances: Number, // how many instances, default 1
     *   worker: Boolean, // is it a worker verticle? default false
     *   multiThreaded: Boolean, // is it a multiThreaded verticle? default false
     *   config: JsonObject // any config you need to pass to the module/verticle
     * }
     * </pre>
     *
     * @param config either a json object or a json array.
     * @param handler A handler that is called once all middleware is deployed or on error.
     */
    public Yoke deploy(final @NotNull JsonArray config, final Handler<Object> handler) {

        if (config.size() == 0) {
            if (handler == null) {
                return this;
            } else {
                handler.handle(null);
                return this;
            }
        }

        // wait for all deployments before calling the real handler
        Handler<AsyncResult<String>> waitFor = new Handler<AsyncResult<String>>() {

            private int latch = config.size();
            private boolean handled = false;

            @Override
            public void handle(AsyncResult<String> event) {
                latch--;
                if (handler != null) {
                    if (!handled && (event.failed() || latch == 0)) {
                        handled = true;
                        handler.handle(event.failed() ? event.cause() : null);
                    }
                }
            }
        };

        for (Object o : config) {
            JsonObject json = (JsonObject) o;
            vertx.deployVerticle(json.getString("verticle"), new DeploymentOptions(json), waitFor);
        }

        return this;
    }
}


<|start_filename|>middleware/reststore/src/main/java/com/jetdrone/vertx/yoke/middleware/rest/AbstractValidatingStore.java<|end_filename|>
/*
 * Copyright 2011-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jetdrone.vertx.yoke.middleware.rest;

import io.vertx.core.AsyncResult;
import io.vertx.core.AsyncResultHandler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

public abstract class AbstractValidatingStore implements Store {

    private final Store baseStore;

    public AbstractValidatingStore(Store store) {
        this.baseStore = store;
    }

    public abstract void beforeCreate(String entity, JsonObject object, AsyncResultHandler<String> response);

    public abstract void afterCreate(String entity, JsonObject object, AsyncResultHandler<String> response);

    @Override
    public final void create(final String entity, final JsonObject object, final AsyncResultHandler<String> response) {
        beforeCreate(entity, object, new AsyncResultHandler<String>() {
            @Override
            public void handle(AsyncResult<String> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.create(entity, object, new AsyncResultHandler<String>() {
                    @Override
                    public void handle(AsyncResult<String> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterCreate(entity, object, new AsyncResultHandler<String>() {
                            @Override
                            public void handle(AsyncResult<String> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }

    public abstract void beforeRead(String entity, String id, AsyncResultHandler<JsonObject> response);

    public abstract void afterRead(String entity, String id, AsyncResultHandler<JsonObject> response);

    @Override
    public final void read(final String entity, final String id, final AsyncResultHandler<JsonObject> response) {
        beforeRead(entity, id, new AsyncResultHandler<JsonObject>() {
            @Override
            public void handle(AsyncResult<JsonObject> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.read(entity, id, new AsyncResultHandler<JsonObject>() {
                    @Override
                    public void handle(AsyncResult<JsonObject> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterRead(entity, id, new AsyncResultHandler<JsonObject>() {
                            @Override
                            public void handle(AsyncResult<JsonObject> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }

    public abstract void beforeUpdate(String entity, String id, JsonObject object, AsyncResultHandler<Number> response);

    public abstract void afterUpdate(String entity, String id, JsonObject object, AsyncResultHandler<Number> response);

    @Override
    public final void update(final String entity, final String id, final JsonObject object, final AsyncResultHandler<Number> response) {
        beforeUpdate(entity, id, object, new AsyncResultHandler<Number>() {
            @Override
            public void handle(AsyncResult<Number> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.update(entity, id, object, new AsyncResultHandler<Number>() {
                    @Override
                    public void handle(AsyncResult<Number> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterUpdate(entity, id, object, new AsyncResultHandler<Number>() {
                            @Override
                            public void handle(AsyncResult<Number> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }

    public abstract void beforeDelete(String entity, String id, AsyncResultHandler<Number> response);

    public abstract void afterDelete(String entity, String id, AsyncResultHandler<Number> response);

    @Override
    public final void delete(final String entity, final String id, final AsyncResultHandler<Number> response) {
        beforeDelete(entity, id, new AsyncResultHandler<Number>() {
            @Override
            public void handle(AsyncResult<Number> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.delete(entity, id, new AsyncResultHandler<Number>() {
                    @Override
                    public void handle(AsyncResult<Number> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterDelete(entity, id, new AsyncResultHandler<Number>() {
                            @Override
                            public void handle(AsyncResult<Number> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }

    public abstract void beforeQuery(String entity, JsonObject query, Number start, Number end, JsonObject sort, AsyncResultHandler<JsonArray> response);

    public abstract void afterQuery(String entity, JsonObject query, Number start, Number end, JsonObject sort, AsyncResultHandler<JsonArray> response);

    @Override
    public final void query(final String entity, final JsonObject query, final Number start, final Number end, final JsonObject sort, final AsyncResultHandler<JsonArray> response) {
        beforeQuery(entity, query, start, end, sort, new AsyncResultHandler<JsonArray>() {
            @Override
            public void handle(AsyncResult<JsonArray> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.query(entity, query, start, end, sort, new AsyncResultHandler<JsonArray>() {
                    @Override
                    public void handle(AsyncResult<JsonArray> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterQuery(entity, query, start, end, sort, new AsyncResultHandler<JsonArray>() {
                            @Override
                            public void handle(AsyncResult<JsonArray> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }

    public abstract void beforeCount(String entity, JsonObject query, AsyncResultHandler<Number> response);

    public abstract void afterCount(String entity, JsonObject query, AsyncResultHandler<Number> response);

    @Override
    public final void count(final String entity, final JsonObject query, final AsyncResultHandler<Number> response) {
        beforeCount(entity, query, new AsyncResultHandler<Number>() {
            @Override
            public void handle(AsyncResult<Number> event) {
                if (event.failed()) {
                    response.handle(event);
                    return;
                }

                baseStore.count(entity, query, new AsyncResultHandler<Number>() {
                    @Override
                    public void handle(AsyncResult<Number> event) {
                        if (event.failed()) {
                            response.handle(event);
                            return;
                        }

                        afterCount(entity, query, new AsyncResultHandler<Number>() {
                            @Override
                            public void handle(AsyncResult<Number> event) {
                                if (event.failed()) {
                                    response.handle(event);
                                    return;
                                }

                                response.handle(event);
                            }
                        });
                    }
                });
            }
        });
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/security/JWT.java<|end_filename|>
package com.jetdrone.vertx.yoke.security;

import com.jetdrone.vertx.yoke.YokeSecurity;
import io.vertx.core.json.JsonObject;

import javax.crypto.Mac;
import java.security.Signature;
import java.security.SignatureException;
import java.util.*;

public final class JWT {

    private interface Crypto {
        byte[] sign(byte[] payload);
        boolean verify(byte[] signature, byte[] payload);
    }

    private static final class CryptoMac implements Crypto {
        private final Mac mac;

        private CryptoMac(final Mac mac) {
            this.mac = mac;
        }

        @Override
        public byte[] sign(byte[] payload) {
            synchronized (mac) {
                return mac.doFinal(payload);
            }
        }

        @Override
        public boolean verify(byte[] signature, byte[] payload) {
            synchronized (mac) {
                return Arrays.equals(signature, mac.doFinal(payload));
            }
        }
    }

    private static final class CryptoSignature implements Crypto {
        private final Signature sig;

        private CryptoSignature(final Signature signature) {
            this.sig = signature;
        }

        @Override
        public byte[] sign(byte[] payload) {
            try {
                synchronized (sig) {
                    sig.update(payload);
                    return sig.sign();
                }
            } catch (SignatureException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public boolean verify(byte[] signature, byte[] payload) {
            try {
                synchronized (sig) {
                    sig.update(payload);
                    return Arrays.equals(signature, sig.sign());
                }
            } catch (SignatureException e) {
                throw new RuntimeException(e);
            }
        }
    }

    private final Map<String, Crypto> CRYPTO_MAP;

    public JWT(final YokeSecurity security) {

        Map<String, Crypto> tmp = new HashMap<>();
        try {
            tmp.put("HS256", new CryptoMac(security.getMac("HS256")));
        } catch (RuntimeException e) {
            // Algorithm not supported
        }
        try {
            tmp.put("HS384", new CryptoMac(security.getMac("HS384")));
        } catch (RuntimeException e) {
            // Algorithm not supported
        }
        try {
            tmp.put("HS512", new CryptoMac(security.getMac("HS512")));
        } catch (RuntimeException e) {
            // Algorithm not supported
        }
        try {
            tmp.put("RS256", new CryptoSignature(security.getSignature("RS256")));
        } catch (RuntimeException e) {
            // Algorithm not supported
        }

        CRYPTO_MAP = Collections.unmodifiableMap(tmp);
    }

    public JsonObject decode(final String token) {
        return decode(token, false);
    }

    public JsonObject decode(final String token, boolean noVerify) {
        String[] segments = token.split("\\.");
        if (segments.length != 3) {
            throw new RuntimeException("Not enough or too many segments");
        }

        // All segment should be base64
        String headerSeg = segments[0];
        String payloadSeg = segments[1];
        String signatureSeg = segments[2];

        // base64 decode and parse JSON
        JsonObject header = new JsonObject(new String(Base64.getUrlDecoder().decode(headerSeg)));
        JsonObject payload = new JsonObject(new String(Base64.getUrlDecoder().decode(payloadSeg)));

        if (!noVerify) {
            Crypto crypto = CRYPTO_MAP.get(header.getString("alg"));

            if (crypto == null) {
                throw new RuntimeException("Algorithm not supported");
            }

            // verify signature. `sign` will return base64 string.
            String signingInput = headerSeg + "." + payloadSeg;

            if (!crypto.verify(Base64.getUrlDecoder().decode(signatureSeg), signingInput.getBytes())) {
                throw new RuntimeException("Signature verification failed");
            }
        }

        return payload;
    }

    public String encode(JsonObject payload) {
        return encode(payload, "HS256");
    }

    public String encode(JsonObject payload, String algorithm) {
        Crypto crypto = CRYPTO_MAP.get(algorithm);

        if (crypto == null) {
            throw new RuntimeException("Algorithm not supported");
        }

        // header, typ is fixed value.
        JsonObject header = new JsonObject()
                .put("typ", "JWT")
                .put("alg", algorithm);


        // create segments, all segment should be base64 string
        String headerSegment = Base64.getUrlEncoder().encodeToString(header.encode().getBytes());
        String payloadSegment = Base64.getUrlEncoder().encodeToString(payload.encode().getBytes());
        String signingInput = headerSegment + "." + payloadSegment;
        String signSegment = Base64.getUrlEncoder().encodeToString(crypto.sign(signingInput.getBytes()));

        return headerSegment + "." + payloadSegment + "." + signSegment;
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/annotations/processors/ContentNegotiationProcessorHandler.java<|end_filename|>
package com.jetdrone.vertx.yoke.annotations.processors;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.annotations.*;
import com.jetdrone.vertx.yoke.middleware.Router;
import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ContentNegotiationProcessorHandler extends AbstractAnnotationHandler<Router> {

    public ContentNegotiationProcessorHandler() {
        super(Router.class);
    }

    @Override
    public void process(final Router router, final Object instance, final Class<?> clazz, final Method method) {

        Produces clazzProducesAnn = Processor.getAnnotation(clazz, Produces.class);
        Consumes clazzConsumesAnn = Processor.getAnnotation(clazz, Consumes.class);

        String[] clazzProduces = clazzProducesAnn != null ? clazzProducesAnn.value() : null;
        String[] clazzConsumes = clazzConsumesAnn != null ? clazzConsumesAnn.value() : null;

        Produces producesAnn = Processor.getAnnotation(method, Produces.class);
        Consumes consumesAnn = Processor.getAnnotation(method, Consumes.class);

        String[] produces = producesAnn != null ? producesAnn.value() : null;
        String[] consumes = consumesAnn != null ? consumesAnn.value() : null;

        if (produces == null) {
            produces = clazzProduces;
        }
        if (consumes == null) {
            consumes = clazzConsumes;
        }

        if (produces == null && consumes == null) {
            return;
        }

        // process the methods that have both YokeRequest and Handler

        if (Processor.isCompatible(method, ALL.class, YokeRequest.class, Handler.class)) {
            router.all(Processor.getAnnotation(method, ALL.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, CONNECT.class, YokeRequest.class, Handler.class)) {
            router.connect(Processor.getAnnotation(method, CONNECT.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, OPTIONS.class, YokeRequest.class, Handler.class)) {
            router.options(Processor.getAnnotation(method, OPTIONS.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, HEAD.class, YokeRequest.class, Handler.class)) {
            router.head(Processor.getAnnotation(method, HEAD.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, GET.class, YokeRequest.class, Handler.class)) {
            router.get(Processor.getAnnotation(method, GET.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, POST.class, YokeRequest.class, Handler.class)) {
            router.post(Processor.getAnnotation(method, POST.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, PUT.class, YokeRequest.class, Handler.class)) {
            router.put(Processor.getAnnotation(method, PUT.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, PATCH.class, YokeRequest.class, Handler.class)) {
            router.patch(Processor.getAnnotation(method, PATCH.class).value(), wrap(consumes, produces));
        }
        if (Processor.isCompatible(method, DELETE.class, YokeRequest.class, Handler.class)) {
            router.delete(Processor.getAnnotation(method, DELETE.class).value(), wrap(consumes, produces));
        }
    }

    @Override
    public void process(Router router, Object instance, Class<?> clazz, Field field) {
        // NOOP
    }

    private static Middleware wrap(final String[] consumes, final String[] produces) {
        return new Middleware() {
            @Override
            public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
                // we only know how to process certain media types
                if (consumes != null) {
                    boolean canConsume = false;
                    for (String c : consumes) {
                        if (request.is(c)) {
                            canConsume = true;
                            break;
                        }
                    }

                    if (!canConsume) {
                        // 415 Unsupported Media Type (we don't know how to handle this media)
                        next.handle(415);
                        return;
                    }
                }

                // the object was marked with a specific content type
                if (produces != null) {
                    String bestContentType = request.accepts(produces);

                    // the client does not know how to handle our content type, return 406
                    if (bestContentType == null) {
                        next.handle(406);
                        return;
                    }

                    // mark the response with the correct content type (which allows middleware to know it later on)
                    request.response().setContentType(bestContentType);
                }

                // the request can be handled, it does respect the content negotiation
                next.handle(null);
            }
        };
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/Timeout.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

/** # Timeout
 *
 * Times out the request in ```ms```, defaulting to ```5000```.
 *
 * The timeout error is passed to ```next.handle(408)``` so that you may customize the response behaviour.
 */
public class Timeout extends Middleware {

    private final long timeout;

    public Timeout(final long timeout) {
        this.timeout = timeout;
    }

    public Timeout() {
        this(5000);
    }
    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
        final YokeResponse response = request.response();

        final long timerId = vertx().setTimer(timeout, new Handler<Long>() {
            @Override
            public void handle(Long event) {
                next.handle(408);
            }
        });

        response.endHandler(new Handler<Void>() {
            @Override
            public void handle(Void event) {
                vertx().cancelTimer(timerId);
            }
        });

        next.handle(null);
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/RequestProxy.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import io.vertx.core.http.HttpClientOptions;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpClient;
import io.vertx.core.VoidHandler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpClientRequest;
import io.vertx.core.http.HttpClientResponse;

/** # RequestProxy
 *
 * RequestProxy provides web client a simple way to interact with other REST service
 * providers via Yoke, meanwhile Yoke could pre-handle authentication, logging and etc.
 *
 * In order to handler the proxy request properly, Bodyparser should be disabled for the
 * path matched by RequestProxy.
 */
public class RequestProxy extends Middleware {

    private final String prefix;
    private final String host;
    private final int port;
    private final boolean secure;

    public RequestProxy(@NotNull final String prefix, @NotNull final String host, final int port, final boolean secure) {
        this.prefix = prefix;
        this.host = host;
        this.port = port;
        this.secure = secure;
    }

    public RequestProxy(@NotNull final String prefix, final int port, final boolean secure) {
        this(prefix, "localhost", port, secure);
    }

    @Override
    public void handle(@NotNull final YokeRequest req, @NotNull final Handler<Object> next) {
        if (!req.uri().startsWith(prefix)) {
          next.handle(null);
          return;
        }
        final String newUri = req.uri().replaceFirst(prefix, "");
        final HttpClient client = vertx().createHttpClient(new HttpClientOptions().setDefaultHost(host).setDefaultPort(port).setSsl(secure));

        final HttpClientRequest cReq = client.request(req.method(), newUri, new Handler<HttpClientResponse>() {
          public void handle(HttpClientResponse cRes) {
            req.response().setStatusCode(cRes.statusCode());
            req.response().headers().setAll(cRes.headers());
            req.response().setChunked(true);
            cRes.handler(new Handler<Buffer>() {
              public void handle(Buffer data) {
                req.response().write(data);
              }
            });
            cRes.endHandler(new VoidHandler() {
              public void handle() {
                req.response().end();
              }
            });
            cRes.exceptionHandler(new Handler<Throwable>() {
              public void handle(Throwable t) {
                next.handle(t);
              }
            });
          }
        });
        cReq.headers().setAll(req.headers());
        cReq.setChunked(true);
        req.handler(new Handler<Buffer>() {
          public void handle(Buffer data) {
            cReq.write(data);
          }
        });
        req.endHandler(new VoidHandler() {
          public void handle() {
            cReq.end();
          }
        });
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/annotations/processors/JsonSchemaProcessorHandler.java<|end_filename|>
package com.jetdrone.vertx.yoke.annotations.processors;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.annotations.*;
import com.jetdrone.vertx.yoke.annotations.JsonSchema;
import com.jetdrone.vertx.yoke.core.YokeException;
import com.jetdrone.vertx.yoke.json.*;
import com.jetdrone.vertx.yoke.middleware.Router;
import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class JsonSchemaProcessorHandler extends AbstractAnnotationHandler<Router> {

    public JsonSchemaProcessorHandler() {
        super(Router.class);
    }

    @Override
    public void process(Router router, Object instance, Class<?> clazz, Method method) {
        JsonSchema jsonSchema = Processor.getAnnotation(method, JsonSchema.class);

        if (jsonSchema == null) {
            return;
        }

        if (Processor.isCompatible(method, POST.class, YokeRequest.class, Handler.class)) {
            router.post(Processor.getAnnotation(method, POST.class).value(), wrap(JsonSchemaResolver.resolveSchema(jsonSchema.value())));
        }
        if (Processor.isCompatible(method, PUT.class, YokeRequest.class, Handler.class)) {
            router.put(Processor.getAnnotation(method, PUT.class).value(), wrap(JsonSchemaResolver.resolveSchema(jsonSchema.value())));
        }
        if (Processor.isCompatible(method, PATCH.class, YokeRequest.class, Handler.class)) {
            router.patch(Processor.getAnnotation(method, PATCH.class).value(), wrap(JsonSchemaResolver.resolveSchema(jsonSchema.value())));
        }
    }

    private static Middleware wrap(final JsonSchemaResolver.Schema schema) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (!com.jetdrone.vertx.yoke.json.JsonSchema.conformsSchema(request.body(), schema)) {
                    next.handle(new YokeException(400, "'" + request.body() + "' does not conforms to schema"));
                    return;
                }

                // the request can be handled, it does respect the content negotiation
                next.handle(null);
            }
        };
    }

    @Override
    public void process(Router router, Object instance, Class<?> clazz, Field field) {
        // NO-OP
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/core/YokeFileUpload.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.core;

import org.jetbrains.annotations.NotNull;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.file.FileSystem;
import io.vertx.core.http.HttpServerFileUpload;

import java.io.File;
import java.util.UUID;

/**
 * # YokeFileUpload
 */
public class YokeFileUpload {

    final FileSystem fileSystem;

    private final String filename;
    private final String name;
    private final String contentType;
    private final String contentTransferEncoding;
    private final String charset;
    private final long size;
    private final String path;

    private boolean isTransient = true;

    public YokeFileUpload(@NotNull final Vertx vertx, @NotNull final HttpServerFileUpload fileUpload, @NotNull String uploadDir) {
        this.fileSystem = vertx.fileSystem();

        this.filename = fileUpload.filename();
        this.name = fileUpload.name();
        this.contentType = fileUpload.contentType();
        this.contentTransferEncoding = fileUpload.contentTransferEncoding();
        this.charset = fileUpload.charset();
        this.size = fileUpload.size();

        if (!uploadDir.endsWith(File.separator)) {
            uploadDir += File.separator;
        }

        this.path = uploadDir + UUID.randomUUID().toString();
    }

    public YokeFileUpload(@NotNull final FileSystem fileSystem, @NotNull final String filename, @NotNull final String name, @NotNull final String contentType, @NotNull final String contentTransferEncoding, @NotNull final String charset, final long size, @NotNull final String path) {
        this.fileSystem = fileSystem;
        this.filename = filename;
        this.name = name;
        this.contentType = contentType;
        this.contentTransferEncoding = contentTransferEncoding;
        this.charset = charset;
        this.size = size;
        this.path = path;
    }

    public boolean isTransient() {
        return isTransient;
    }

    public void setTransient(boolean isTransient) {
        this.isTransient = isTransient;
    }

    /**
     * Returns the filename which was used when upload the file.
     */
    public String filename() {
        return filename;
    }

    /**
     * Returns the name of the attribute
     */
    public String name() {
        return name;
    }

    /**
     * Returns the contentType for the upload
     */
    public String contentType() {
        return contentType;
    }

    /**
     * Returns the contentTransferEncoding for the upload
     */
    public String contentTransferEncoding() {
        return contentTransferEncoding;
    }

    /**
     * Returns the charset for the upload
     */
    public String charset() {
        return charset;
    }

    /**
     * Returns the size of the upload (in bytes)
     */
    public long size() {
        return size;
    }

    /**
     * Returns filesystem path location
     */
    public String path() {
        return path;
    }

    public void delete(@NotNull final Handler<Throwable> handler) {
        fileSystem.delete(path, new Handler<AsyncResult<Void>>() {
            @Override
            public void handle(AsyncResult<Void> result) {
                if (result.failed()) {
                    handler.handle(result.cause());
                } else {
                    handler.handle(null);
                }
            }
        });
    }

    public void delete() {
        this.delete(new Handler<Throwable>() {
            @Override
            public void handle(Throwable result) {
            }
        });
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/Engine.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke;

import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;

import java.util.Map;

/**
 * # Engine
 *
 * Engine represents a Template Engine that can be registered with Yoke. Any template engine just needs to implement
 * this template. The class provides access to the Vertx object so the engine might do I/O operations in the context of
 * the module.
 */
public interface Engine {

    /**
     * Called on register to allow using vertx in the engine.
     *
     * @param vertx Vertx instance
     */
    void setVertx(Vertx vertx);

    /**
     * Returns the default content type for this template, e.g.: `text/html`.
     *
     * @return the content type
     */
    String contentType();

    /**
     * Returns the default content encoding for this template, e.g.: `UTF-8`.
     *
     * @return content encoding
     */
    String contentEncoding();

    /**
     * Return the file extension for this template, e.g.: jsp
     *
     * @return file extension
     */
    String extension();

    /**
     * The implementation of the render engine. The implementation should render the given file with the context in an
     * asynchronous way.
     *
     * @param filename String representing the file path to the template
     * @param context  Map with key values that might get substituted in the template
     * @param handler  The future result handler with a Buffer in case of success
     */
    void render(final String filename, final Map<String, Object> context, final Handler<AsyncResult<Buffer>> handler);
}


<|start_filename|>middleware/reststore/src/main/java/com/jetdrone/vertx/yoke/middleware/JsonStore.java<|end_filename|>
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.IMiddleware;
import com.jetdrone.vertx.yoke.Middleware;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JsonStore extends Router {

    private static final Pattern RANGE = Pattern.compile("items=(\\d+)-(\\d+)");
    private static final Pattern SORT = Pattern.compile("sort\\((.+)\\)");

    private final String prefix;
    private final String sortParam;

    public JsonStore() {
        this("/api");
    }

    public JsonStore(String prefix) {
        this(prefix, null);
    }

    public JsonStore(String prefix, String sortParam) {
        this.prefix = prefix.endsWith("/") ? prefix.substring(0, prefix.length() - 1) : prefix;
        this.sortParam = sortParam;
    }

    protected CRUD createCrud() {
        return new CRUD();
    }

    public CRUD collection(String name) {
        return collection(name, "id");
    }

    public CRUD collection(String name, @Nullable final IMiddleware validator) {
        return collection(name, "id", validator);
    }

    public CRUD collection(String name, String key) {
        return collection(name, key, null);
    }

    public CRUD collection(@NotNull final String name, @NotNull final String key, @Nullable final IMiddleware validator) {
        final CRUD crud = createCrud();
        collection(name, key, crud, validator);
        return crud;
    }

    public void collection(@NotNull final String name, @NotNull final String key, @NotNull final CRUD crud, @Nullable final IMiddleware validator) {

        if (validator != null) {
            // CREATE
            post(prefix + "/" + name, validator, create(name, key, crud));
            // READ ALL
            get(prefix + "/" + name, validator, query(name, key, crud));
            // READ ONE
            get(prefix + "/" + name + "/:" + key, validator, read(name, key, crud));
            // UPDATE
            put(prefix + "/" + name + "/:" + key, validator, update(name, key, crud));
            // DELETE
            delete(prefix + "/" + name + "/:" + key, validator, delete(name, key, crud));

            // shortcut for patch (as by Dojo Toolkit)
            post(prefix + "/" + name + "/:" + key, validator, append(name, key, crud));
            patch(prefix + "/" + name + "/:" + key, validator, append(name, key, crud));
        } else {
            // CREATE
            post(prefix + "/" + name, create(name, key, crud));
            // READ ALL
            get(prefix + "/" + name, query(name, key, crud));
            // READ ONE
            get(prefix + "/" + name + "/:" + key, read(name, key, crud));
            // UPDATE
            put(prefix + "/" + name + "/:" + key, update(name, key, crud));
            // DELETE
            delete(prefix + "/" + name + "/:" + key, delete(name, key, crud));

            // shortcut for patch (as by Dojo Toolkit)
            post(prefix + "/" + name + "/:" + key, append(name, key, crud));
            patch(prefix + "/" + name + "/:" + key, append(name, key, crud));
        }
    }

    private Middleware delete(final String collection, final String key, @NotNull final CRUD crud) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.deleteHandler == null) {
                    next.handle(405);
                    return;
                }

                // get the real id from the params multimap
                final String id = request.params().get(key);

                final JsonObject filter = new JsonObject()
                        .put("query", new JsonObject().put(key, id));

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.deleteHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final Integer result = reply.getInteger("value");
                        if (result == null || result == 0) {
                            next.handle(404);
                        } else {
                            request.response().setStatusCode(204);
                            request.response().end();
                        }
                    }
                });
            }
        };
    }

    private Middleware create(@NotNull final String collection, final String key, @NotNull final CRUD crud) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.createHandler == null) {
                    next.handle(405);
                    return;
                }

                final JsonObject item = request.body();

                if (item == null) {
                    next.handle("Body must be JSON");
                    return;
                }

                final JsonObject filter = new JsonObject()
                        .put("value", item);

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.createHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final JsonObject result = reply.getJsonObject("value");

                        request.response().putHeader("location", request.normalizedPath() + "/" + result.getValue(key));
                        request.response().setStatusCode(201);
                        request.response().end(result);
                    }
                });
            }
        };
    }

    private Middleware update(@NotNull final String collection, final String key, @NotNull final CRUD crud) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.updateHandler == null) {
                    next.handle(405);
                    return;
                }

                final JsonObject item = request.body();

                if (item == null) {
                    next.handle("Body must be JSON");
                    return;
                }

                // get the real id from the params multimap
                String id = request.params().get(key);

                final JsonObject filter = new JsonObject()
                        .put("value", item)
                        .put("query", new JsonObject().put(key, id));

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.updateHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final Integer result = reply.getInteger("value");
                        if (result == null || result == 0) {
                            next.handle(404);
                        } else {
                            request.response().setStatusCode(204);
                            request.response().end();
                        }
                    }
                });
            }
        };
    }

    private Middleware read(@NotNull final String collection, final String key, @NotNull final CRUD crud) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.readHandler == null) {
                    next.handle(405);
                    return;
                }

                // content negotiation
                if (request.accepts("application/json") == null) {
                    // Not Acceptable (we only talk json)
                    next.handle(406);
                    return;
                }

                // get the real id from the params multimap
                final String id = request.params().get(key);

                final JsonObject filter = new JsonObject()
                        .put("query", new JsonObject().put(key, id));

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.readHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final JsonArray result = reply.getJsonArray("value");
                        if (result == null || result.size() == 0) {
                            next.handle(404);
                            return;
                        }

                        final JsonObject item = result.getJsonObject(0);
                        if (item == null) {
                            next.handle(404);
                        } else {
                            request.response().end(item);
                        }

                    }
                });
            }
        };
    }

    private Middleware append(@NotNull final String collection, final String key, @NotNull final CRUD crud) {
        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.readHandler == null || crud.updateHandler == null) {
                    next.handle(405);
                    return;
                }

                // get the real id from the params multimap
                final String id = request.params().get(key);

                final JsonObject filter = new JsonObject()
                        .put("query", new JsonObject().put(key, id));

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.readHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final String ifMatch = request.getHeader("If-Match");
                        final String ifNoneMatch = request.getHeader("If-None-Match");

                        // merge existing json with incoming one
                        final boolean overwrite =
                                // pure PUT, must exist and will be updated
                                (ifMatch == null && ifNoneMatch == null) ||
                                        // must exist and will be updated
                                        ("*".equals(ifMatch));

                        final JsonObject result = reply.getJsonObject("value");

                        if (result == null) {
                            // does not exist but was marked as overwrite
                            if (overwrite) {
                                // does not exist, returns 412
                                next.handle(412);
                            } else {
                                // does not exist, returns 404
                                next.handle(404);
                            }
                        } else {
                            // does exist but was marked as not overwrite
                            if (!overwrite) {
                                // does exist, returns 412
                                next.handle(412);
                            } else {
                                result.mergeIn((JsonObject) request.body());

                                final JsonObject filter = new JsonObject()
                                        .put("value", result)
                                        .put("query", new JsonObject().put(key, id));

                                final JsonObject userFilter = request.get("filter");

                                if (userFilter != null) {
                                    filter.mergeIn(userFilter);
                                }

                                // update back to the db
                                crud.updateHandler.handle(request, filter, new Handler<JsonObject>() {
                                    @Override
                                    public void handle(JsonObject reply) {
                                        if ("error".equals(reply.getString("status"))) {
                                            String message = reply.getString("message");
                                            if (message != null) {
                                                next.handle(message);
                                            } else {
                                                next.handle(500);
                                            }
                                            return;
                                        }

                                        final Integer result = reply.getInteger("value");
                                        if (result == null || result == 0) {
                                            next.handle(404);
                                        } else {
                                            request.response().setStatusCode(204);
                                            request.response().end();
                                        }
                                    }
                                });
                            }
                        }
                    }
                });
            }
        };
    }

    private static Integer parseInt(String value) {
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException nfe) {
            return null;
        }
    }

    private Middleware query(@NotNull final String collection, final String key, @NotNull final CRUD crud) {

        return new Middleware() {
            @Override
            public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
                if (crud.readHandler == null) {
                    next.handle(405);
                    return;
                }

                // content negotiation
                if (request.accepts("application/json") == null) {
                    // Not Acceptable (we only talk json)
                    next.handle(406);
                    return;
                }

                // parse ranges
                final String range = request.getHeader("range");
                final Integer start, end;
                if (range != null) {
                    Matcher m = RANGE.matcher(range);
                    if (m.matches()) {
                        start = parseInt(m.group(1));
                        end = parseInt(m.group(2));
                    } else {
                        start = null;
                        end = null;
                    }
                } else {
                    start = null;
                    end = null;
                }

                // parse query
                final JsonObject dbquery = new JsonObject();
                final JsonObject dbsort = new JsonObject();
                for (Map.Entry<String, String> entry : request.params()) {
                    String[] sortArgs;
                    // parse sort
                    if (sortParam == null) {
                        Matcher sort = SORT.matcher(entry.getKey());

                        if (sort.matches()) {
                            sortArgs = sort.group(1).split(",");
                            for (String arg : sortArgs) {
                                if (arg.charAt(0) == '+' || arg.charAt(0) == ' ') {
                                    dbsort.put(arg.substring(1), 1);
                                } else if (arg.charAt(0) == '-') {
                                    dbsort.put(arg.substring(1), -1);
                                }
                            }
                            continue;
                        }
                    } else {
                        if (sortParam.equals(entry.getKey())) {
                            sortArgs = entry.getValue().split(",");
                            for (String arg : sortArgs) {
                                if (arg.charAt(0) == '+' || arg.charAt(0) == ' ') {
                                    dbsort.put(arg.substring(1), 1);
                                } else if (arg.charAt(0) == '-') {
                                    dbsort.put(arg.substring(1), -1);
                                }
                            }
                            continue;
                        }
                    }
                    dbquery.put(entry.getKey(), entry.getValue());
                }

                final JsonObject filter = new JsonObject()
                        .put("query", dbquery)
                        .put("sort", dbsort)
                        .put("start", start)
                        .put("end", end);

                final JsonObject userFilter = request.get("filter");

                if (userFilter != null) {
                    filter.mergeIn(userFilter);
                }

                crud.readHandler.handle(request, filter, new Handler<JsonObject>() {
                    @Override
                    public void handle(JsonObject reply) {
                        if ("error".equals(reply.getString("status"))) {
                            String message = reply.getString("message");
                            if (message != null) {
                                next.handle(message);
                            } else {
                                next.handle(500);
                            }
                            return;
                        }

                        final JsonArray result = reply.getJsonArray("value");

                        if (result == null) {
                            next.handle(404);
                        } else {
                            if (range != null) {
                                // need to send the content-range with totals
                                Long count = reply.getLong("count");

                                if (count != null) {
                                    Integer realEnd = end;

                                    if (start != null && end != null) {
                                        realEnd = start + result.size();
                                    }

                                    request.response().putHeader("content-range", "items " + start + "-" + realEnd + "/" + count);

                                }
                            }

                            request.response().end(result);
                        }
                    }
                });
            }
        };
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/JWT.java<|end_filename|>
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.core.YokeException;
import io.vertx.core.http.HttpMethod;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;

import java.util.regex.Pattern;

public class JWT extends Middleware {

    private static final Pattern BEARER = Pattern.compile("^Bearer$", Pattern.CASE_INSENSITIVE);

    public interface JWTHandler {
        public void handle(JsonObject token, Handler<Object> result);
    }

    private final String skip;

    private com.jetdrone.vertx.yoke.security.JWT jwt;

    private final JWTHandler handler;

    public JWT() {
        this.skip = null;
        this.handler = null;
    }

    public JWT(final @NotNull String skip) {
        this.skip = skip;
        this.handler = null;
    }

    public JWT(final @NotNull String skip, final @NotNull JWTHandler handler) {
        this.skip = skip;
        this.handler = handler;
    }

    public JWT(final @NotNull JWTHandler handler) {
        this.skip = null;
        this.handler = handler;
    }

    @Override
    public Middleware init(@NotNull final Yoke yoke, @NotNull final String mount) {
        super.init(yoke, mount);

        jwt = new com.jetdrone.vertx.yoke.security.JWT(yoke.security());
        return this;
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
        String token = null;

        if (HttpMethod.OPTIONS.equals(request.method()) && request.getHeader("access-control-request-headers") != null) {
            for (String ctrlReq : request.getHeader("access-control-request-headers").split(",")) {
                if (ctrlReq.contains("authorization")) {
                    next.handle(null);
                    return;
                }
            }
        }

        if (skip != null && skip.contains(request.normalizedPath())) {
            next.handle(null);
            return;
        }

        final String authorization = request.getHeader("authorization");

        if (authorization != null) {
            String[] parts = authorization.split(" ");
            if (parts.length == 2) {
                final String scheme = parts[0],
                             credentials = parts[1];

                if (BEARER.matcher(scheme).matches()) {
                    token = credentials;
                }
            } else {
                next.handle(new YokeException(401, "Format is Authorization: Bearer [token]"));
                return;
            }
        } else {
            next.handle(new YokeException(401, "No Authorization header was found"));
            return;
        }

        try {
            final JsonObject jwtToken = jwt.decode(token);

            // All dates in JWT are of type NumericDate
            // a NumericDate is: numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until
            // the specified UTC date/time, ignoring leap seconds
            final long now = System.currentTimeMillis() / 1000;

            if (jwtToken.containsKey("iat")) {
                Long iat = jwtToken.getLong("iat");
                // issue at must be in the past
                if (iat > now) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }

            if (jwtToken.containsKey("nbf")) {
                Long nbf = jwtToken.getLong("nbf");
                // not before must be after now
                if (nbf > now) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }

            if (jwtToken.containsKey("exp")) {
                Long exp = jwtToken.getLong("exp");
                // expires must be after now
                if (now > exp) {
                    next.handle(new YokeException(401, "Invalid Token!"));
                    return;
                }
            }
            request.put("jwt", jwtToken);

            if (handler == null) {
                next.handle(null);
                return;
            }

            handler.handle(jwtToken, next);
        } catch (RuntimeException e) {
            next.handle(new YokeException(401, e));
        }
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/sockjs/BridgeEventType.java<|end_filename|>
/*
 * Copyright 2014 Red Hat, Inc.
 *
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  and Apache License v2.0 which accompanies this distribution.
 *
 *  The Eclipse Public License is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  The Apache License v2.0 is available at
 *  http://www.opensource.org/licenses/apache2.0.php
 *
 *  You may elect to redistribute this code under either of these licenses.
 */
package com.jetdrone.vertx.yoke.sockjs;

/**
 * Bridge Event Types.
 *
 * @author <a href="http://tfox.org"><NAME></a>
 */
public enum BridgeEventType {

  /**
   * This event will occur when a new SockJS socket is created.
   */
  SOCKET_CREATED,

  /**
   * This event will occur when a SockJS socket is closed.
   */
  SOCKET_CLOSED,

  /**
   * This event will occur when a message is attempted to be sent from the client to the server.
   */
  SEND,

  /**
   * This event will occur when a message is attempted to be published from the client to the server.
   */
  PUBLISH,

  /**
   * This event will occur when a message is attempted to be delivered from the server to the client.
   */
  RECEIVE,

  /**
   * This event will occur when a client attempts to register a handler.
   */
  REGISTER,

  /**
   * This event will occur when a client attempts to unregister a handler.
   */
  UNREGISTER
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/YokeResponse.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Engine;
import com.jetdrone.vertx.yoke.MimeType;
import com.jetdrone.vertx.yoke.core.Context;
import com.jetdrone.vertx.yoke.middleware.filters.WriterFilter;
import com.jetdrone.vertx.yoke.core.YokeException;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
import io.vertx.core.*;
import io.vertx.core.http.HttpMethod;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.*;

/** # YokeResponse */
public class YokeResponse implements HttpServerResponse {
    // the original request
    private final HttpServerResponse response;
    // the context
    private final Context context;
    // engine map
    private final Map<String, Engine> engines;
    // response cookies
    private Set<Cookie> cookies;
    // link to request method
    private HttpMethod method;

    // extra handlers
    private List<Handler<Void>> headersHandler;
    private boolean headersHandlerTriggered;
    private List<Handler<Void>> endHandler;

    // writer filter
    private WriterFilter filter;
    private boolean hasBody;

    public YokeResponse(HttpServerResponse response, Context context, Map<String, Engine> engines) {
        this.response = response;
        this.context = context;
        this.engines = engines;
    }

    // protected extension

    void setMethod(HttpMethod method) {
        this.method = method;
    }

    void setFilter(WriterFilter filter) {
        this.filter = filter;
    }

    // extension to default interface

    public YokeResponse setContentType(String contentType) {
        setContentType(contentType, MimeType.getCharset(contentType));
        return this;
    }

    public YokeResponse setContentType(String contentType, String contentEncoding) {
        if (contentEncoding == null) {
            putHeader("content-type", contentType);
        } else {
            putHeader("content-type", contentType + ";charset=" + contentEncoding);
        }
        return this;
    }

    public void render(final String template, final Handler<Object> next) {
        int sep = template.lastIndexOf('.');
        if (sep != -1) {
            String extension = template.substring(sep);

            final Engine renderEngine = engines.get(extension);

            if (renderEngine == null) {
                next.handle("No engine registered for extension: " + extension);
            } else {
                renderEngine.render(template, context, new AsyncResultHandler<Buffer>() {
                    @Override
                    public void handle(AsyncResult<Buffer> asyncResult) {
                        if (asyncResult.failed()) {
                            next.handle(asyncResult.cause());
                        } else {
                            setContentType(renderEngine.contentType(), renderEngine.contentEncoding());
                            end(asyncResult.result());
                        }
                    }
                });
            }
        } else {
            next.handle("Cannot determine the extension of the template");
        }
    }

    public void render(final String template) {
        render(template, new Handler<Object>() {
            @Override
            public void handle(Object error) {
                if (error != null) {
                    int errorCode;
                    // if the error was set on the response use it
                    if (getStatusCode() >= 400) {
                        errorCode = getStatusCode();
                    } else {
                        // if it was set as the error object use it
                        if (error instanceof Number) {
                            errorCode = ((Number) error).intValue();
                        } else if (error instanceof YokeException) {
                            errorCode = ((YokeException) error).getErrorCode().intValue();
                        } else {
                            // default error code
                            errorCode = 500;
                        }
                    }

                    setStatusCode(errorCode);
                    setStatusMessage(HttpResponseStatus.valueOf(errorCode).reasonPhrase());
                    end(HttpResponseStatus.valueOf(errorCode).reasonPhrase());
                }
            }
        });
    }

    /**
     * Allow getting headers in a generified way.
     *
     * @param name The key to get
     * @param <R> The type of the return
     * @return The found object
     */
    @SuppressWarnings("unchecked")
    public <R> R getHeader(String name) {
        return (R) headers().get(name);
    }

    /**
     * Allow getting headers in a generified way and return defaultValue if the key does not exist.
     *
     * @param name The key to get
     * @param defaultValue value returned when the key does not exist
     * @param <R> The type of the return
     * @return The found object
     */
    public <R> R getHeader(String name, R defaultValue) {
        if (headers().contains(name)) {
            return getHeader(name);
        } else {
            return defaultValue;
        }
    }

    public void redirect(String url) {
        redirect(302, url);
    }

    public void redirect(int status, String url) {
        setStatusCode(status);
        setStatusMessage(HttpResponseStatus.valueOf(status).reasonPhrase());
        putHeader("location", url);
        end();
    }

    public void end(JsonArray jsonArray) {
        setContentType("application/json", "UTF-8");
        end(jsonArray.encode());
    }

    public void end(JsonObject jsonObject) {
        setContentType("application/json", "UTF-8");
        end(jsonObject.encode());
    }

    public void jsonp(JsonArray json) {
        jsonp("callback", json);
    }

    public void jsonp(JsonObject json) {
        jsonp("callback", json);
    }

    public void jsonp(String callback, JsonArray json) {

        if (callback == null) {
            // treat as normal json response
            end(json);
            return;
        }

        String body = null;

        if (json != null) {
            body = json.encode();
        }

        jsonp(callback, body);
    }

    public void jsonp(String callback, JsonObject json) {

        if (callback == null) {
            // treat as normal json response
            end(json);
            return;
        }

        String body = null;

        if (json != null) {
            body = json.encode();
        }

        jsonp(callback, body);
    }

    public void jsonp(String body) {
        jsonp("callback", body);
    }

    public void jsonp(String callback, String body) {

        if (callback == null) {
            // treat as normal json response
            setContentType("application/json", "UTF-8");
            end(body);
            return;
        }

        if (body == null) {
            body = "null";
        }

        // replace special chars
        body = body.replaceAll("\\u2028", "\\\\u2028").replaceAll("\\u2029", "\\\\u2029");

        // content-type
        setContentType("text/javascript", "UTF-8");
        String cb = callback.replaceAll("[^\\[\\]\\w$.]", "");
        end(cb + " && " + cb + "(" + body + ");");
    }

    public YokeResponse addCookie(Cookie cookie) {
        if (cookies == null) {
            cookies = new TreeSet<>();
        }
        cookies.add(cookie);
        return this;
    }

    public void headersHandler(Handler<Void> handler) {
        if (!headersHandlerTriggered) {
            if (headersHandler == null) {
                headersHandler = new ArrayList<>();
            }
            headersHandler.add(handler);
        }
    }

    public void endHandler(Handler<Void> handler) {
        if (endHandler == null) {
            endHandler = new ArrayList<>();
        }
        endHandler.add(handler);
    }

    private void triggerHeadersHandlers() {
        if (!headersHandlerTriggered) {
            headersHandlerTriggered = true;
            // if there are handlers call them
            if (headersHandler != null) {
                for (Handler<Void> handler : headersHandler) {
                    handler.handle(null);
                }
            }
            // convert the cookies set to the right header
            if (cookies != null) {
                response.putHeader("set-cookie", ServerCookieEncoder.STRICT.encode(cookies));
            }

            // if there is a filter then set the right header
            if (filter != null) {
                // verify if the filter can filter this content
                String contentType = response.headers().get("content-type");
                if (contentType != null && filter.canFilter(contentType)) {
                    response.putHeader("content-encoding", filter.encoding());
                } else {
                    // disable the filter
                    filter = null;
                }
            }
            // if there is no content and method is not HEAD delete content-type, content-encoding
            if (!hasBody && !"HEAD".equals(method)) {
                response.headers().remove("content-encoding");
                response.headers().remove("content-type");
            }
        }
    }

    private void triggerEndHandlers() {
        if (endHandler != null) {
            for (Handler<Void> handler : endHandler) {
                handler.handle(null);
            }
        }
    }

    // interface implementation

    @Override
    public int getStatusCode() {
        return response.getStatusCode();
    }

    @Override
    public YokeResponse setStatusCode(int statusCode) {
        response.setStatusCode(statusCode);
        return this;
    }

    @Override
    public String getStatusMessage() {
        return response.getStatusMessage();
    }

    @Override
    public YokeResponse setStatusMessage(String statusMessage) {
        response.setStatusMessage(statusMessage);
        return this;
    }

    @Override
    public YokeResponse setChunked(boolean chunked) {
        response.setChunked(chunked);
        return this;
    }

    @Override
    public boolean isChunked() {
        return response.isChunked();
    }

    @Override
    public MultiMap headers() {
        return response.headers();
    }

    @Override
    public YokeResponse putHeader(String name, String value) {
        response.putHeader(name, value);
        return this;
    }

    @Override
    public YokeResponse putHeader(CharSequence name, CharSequence value) {
        response.putHeader(name, value);
        return this;
    }

    @Override
    public YokeResponse putHeader(String name, Iterable<String> values) {
        response.putHeader(name, values);
        return this;
    }

    @Override
    public YokeResponse putHeader(CharSequence name, Iterable<CharSequence> values) {
        response.putHeader(name, values);
        return this;
    }

    @Override
    public MultiMap trailers() {
        return response.trailers();
    }

    @Override
    public YokeResponse putTrailer(String name, String value) {
        response.putTrailer(name, value);
        return this;
    }

    @Override
    public YokeResponse putTrailer(CharSequence name, CharSequence value) {
        response.putTrailer(name, value);
        return this;
    }

    @Override
    public YokeResponse putTrailer(String name, Iterable<String> values) {
        response.putTrailer(name, values);
        return this;
    }

    @Override
    public YokeResponse putTrailer(CharSequence name, Iterable<CharSequence> value) {
        response.putTrailer(name, value);
        return this;
    }

    @Override
    public YokeResponse closeHandler(Handler<Void> handler) {
        response.closeHandler(handler);
        return this;
    }

    @Override
    public YokeResponse write(Buffer chunk) {
        hasBody = true;
        triggerHeadersHandlers();
        if (filter == null) {
            response.write(chunk);
        } else {
            filter.write(chunk);
        }
        return this;
    }

    @Override
    public YokeResponse setWriteQueueMaxSize(int maxSize) {
        response.setWriteQueueMaxSize(maxSize);
        return this;
    }

    @Override
    public boolean writeQueueFull() {
        return response.writeQueueFull();
    }

    @Override
    public YokeResponse drainHandler(Handler<Void> handler) {
        response.drainHandler(handler);
        return this;
    }

    @Override
    public YokeResponse write(@NotNull String chunk, @NotNull String enc) {
        hasBody = true;
        triggerHeadersHandlers();
        if (filter == null) {
            response.write(chunk, enc);
        } else {
            filter.write(chunk, enc);
        }
        return this;
    }

    @Override
    public YokeResponse write(@NotNull String chunk) {
        hasBody = true;
        triggerHeadersHandlers();
        if (filter == null) {
            response.write(chunk);
        } else {
            filter.write(chunk);
        }
        return this;
    }

    @Override
    public HttpServerResponse writeContinue() {
        return response.writeContinue();
    }

    @Override
    public void end(@NotNull String chunk) {
        hasBody = true;
        triggerHeadersHandlers();
        if (filter == null) {
            response.end(chunk);
        } else {
            response.end(filter.end(chunk));
        }
        triggerEndHandlers();
    }

    @Override
    public void end(@NotNull String chunk, @NotNull String enc) {
        hasBody = true;
        triggerHeadersHandlers();
        if (filter == null) {
            response.end(chunk, enc);
        } else {
            response.end(filter.end(chunk, enc));
        }
        triggerEndHandlers();
    }

    @Override
    public void end(@NotNull Buffer chunk) {
        hasBody = true;
        triggerHeadersHandlers();
        response.end(filter == null ? chunk : filter.end(chunk));
        triggerEndHandlers();
    }

    @Override
    public void end() {
        triggerHeadersHandlers();
        response.end();
        triggerEndHandlers();
    }

    @Override
    public YokeResponse sendFile(String filename) {
        // TODO: filter file?
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(filename);
        triggerEndHandlers();
        return this;
    }

    @Override
    public HttpServerResponse sendFile(String filename, long offset) {
        // TODO: filter file?
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(filename, offset);
        triggerEndHandlers();
        return this;
    }

    @Override
    public HttpServerResponse sendFile(String s, long l, long l1) {
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(s, l, l1);
        triggerEndHandlers();
        return this;
    }

    @Override
    public YokeResponse sendFile(String filename, Handler<AsyncResult<Void>> resultHandler) {
        // TODO: filter file?
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(filename, resultHandler);
        triggerEndHandlers();
        return this;
    }

    @Override
    public HttpServerResponse sendFile(String filename, long offset, Handler<AsyncResult<Void>> resultHandler) {
        // TODO: filter file?
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(filename, offset, resultHandler);
        triggerEndHandlers();
        return this;
    }

    @Override
    public HttpServerResponse sendFile(String s, long l, long l1, Handler<AsyncResult<Void>> handler) {
        hasBody = true;
        filter = null;
        triggerHeadersHandlers();
        response.sendFile(s, l, l1, handler);
        triggerEndHandlers();
        return this;
    }

    @Override
    public void close() {
        response.close();
        triggerEndHandlers();
    }

    @Override
    public boolean ended() {
        return response.ended();
    }

    @Override
    public boolean closed() {
        return response.closed();
    }

    @Override
    public boolean headWritten() {
        return response.headWritten();
    }

    @Override
    public HttpServerResponse headersEndHandler(Handler<Void> handler) {
        return response.headersEndHandler(handler);
    }

    @Override
    public HttpServerResponse bodyEndHandler(Handler<Void> handler) {
        return response.bodyEndHandler(handler);
    }

    @Override
    public long bytesWritten() {
        return response.bytesWritten();
    }

    @Override
    public YokeResponse exceptionHandler(Handler<Throwable> handler) {
        response.exceptionHandler(handler);
        return this;
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/engine/StringPlaceholderEngine.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.engine;

import com.jetdrone.vertx.yoke.core.YokeAsyncResult;
import io.vertx.core.AsyncResult;
import io.vertx.core.AsyncResultHandler;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * # StringPlaceholderEngine
 */
public class StringPlaceholderEngine extends AbstractEngine<String> {

    private static final String placeholderPrefix = "${";
    private static final String placeholderSuffix = "}";
    private static final boolean ignoreUnresolvablePlaceholders = true;

    private static final String funcName = "([a-zA-Z0-9]+)";
    private static final String arguments = "\\((.*)\\)";
    private static final Pattern FUNCTION = Pattern.compile(funcName + "\\s*" + arguments);

    private static final String argument = "(.*?)";
    private static final String quote = "\'";
    private static final String sep = "(,\\s*)?";
    private static final Pattern ARG = Pattern.compile(quote + argument + quote + sep);

    private final String extension;
    private final String prefix;

    public StringPlaceholderEngine(final String views) {
        this(views, ".shtml");
    }

    public StringPlaceholderEngine(final String views, final String extension) {
        this.extension = extension;

        if ("".equals(views)) {
            prefix = views;
        } else {
            prefix = views.endsWith("/") ? views : views + "/";
        }
    }

    @Override
    public String extension() {
        return extension;
    }

    /**
     * An interpreter for strings with named placeholders.
     *
     * For example given the string "hello ${myName}" and the map <code>
     *      Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();
     *      map.put("myName", "world");
     * </code>
     *
     * the call returns "hello world"
     *
     * It replaces every occurrence of a named placeholder with its given value
     * in the map. If there is a named place holder which is not found in the
     * map then the string will retain that placeholder. Likewise, if there is
     * an entry in the map that does not have its respective placeholder, it is
     * ignored.
     */
    @Override
    public void render(final String file, final Map<String, Object> context, final Handler<AsyncResult<Buffer>> handler) {
        // verify if the file is still fresh in the cache
        read(prefix + file, new AsyncResultHandler<String>() {
            @Override
            public void handle(AsyncResult<String> asyncResult) {
                if (asyncResult.failed()) {
                    handler.handle(new YokeAsyncResult<Buffer>(asyncResult.cause()));
                } else {
                    try {
                        handler.handle(new YokeAsyncResult<>(parseStringValue(asyncResult.result(), context, new HashSet<String>())));
                    } catch (IllegalArgumentException iae) {
                        handler.handle(new YokeAsyncResult<Buffer>(iae));
                    }
                }
            }
        });
    }
    
    private Buffer parseStringValue(String template, Map<String, Object> context, Set<String> visitedPlaceholders) {
        StringBuilder buf = new StringBuilder(template);

        int startIndex = template.indexOf(placeholderPrefix);
        while (startIndex != -1) {
            int endIndex = findPlaceholderEndIndex(buf, startIndex);
            if (endIndex != -1) {
                String placeholder = buf.substring(startIndex + placeholderPrefix.length(), endIndex);
                if (!visitedPlaceholders.add(placeholder)) {
                    throw new IllegalArgumentException(
                            "Circular placeholder reference '" + placeholder + "' in property definitions");
                }
                // Recursive invocation, parsing placeholders contained in the placeholder key.
                placeholder = parseStringValue(placeholder, context, visitedPlaceholders).toString(contentEncoding());

                // Now obtain the value for the fully resolved key...
                Object propVal;
                boolean isFn = false;

                Matcher fn = FUNCTION.matcher(placeholder);
                if (fn.find()) {
                    // function syntax used, get the object from context with the proper name
                    propVal = context.get(fn.group(1));
                    isFn = true;
                } else {
                    propVal = context.get(placeholder);
                }

                if (propVal != null) {
                    // Recursive invocation, parsing placeholders contained in the
                    // previously resolved placeholder value.
                    String propValStr;
                    if (isFn && propVal instanceof Function) {
                        Matcher arg = ARG.matcher(fn.group(2));
                        List<Object> args = null;

                        while (arg.find()) {
                            if (args == null) {
                                args = new ArrayList<>();
                            }
                            args.add(arg.group(1));
                        }
                        if (args == null) {
                            propValStr = ((Function) propVal).exec(context);
                        } else {
                            propValStr = ((Function) propVal).exec(context, args.toArray());
                        }
                    } else {
                        propValStr = propVal.toString();
                    }
                    propValStr = parseStringValue(propValStr, context, visitedPlaceholders).toString(contentEncoding());
                    buf.replace(startIndex, endIndex + placeholderSuffix.length(), propValStr);

                    startIndex = buf.indexOf(placeholderPrefix, startIndex + propValStr.length());
                }
                else if (ignoreUnresolvablePlaceholders) {
                    // Proceed with unprocessed value.
                    startIndex = buf.indexOf(placeholderPrefix, endIndex + placeholderSuffix.length());
                }
                else {
                    throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'");
                }

                visitedPlaceholders.remove(placeholder);
            }
            else {
                startIndex = -1;
            }
        }

        return Buffer.buffer(buf.toString());
    }

    private static int findPlaceholderEndIndex(CharSequence buf, int startIndex) {
        int index = startIndex + placeholderPrefix.length();
        int withinNestedPlaceholder = 0;
        while (index < buf.length()) {
            if (substringMatch(buf, index, placeholderSuffix)) {
                if (withinNestedPlaceholder > 0) {
                    withinNestedPlaceholder--;
                    index = index + placeholderPrefix.length() - 1;
                }
                else {
                    return index;
                }
            }
            else if (substringMatch(buf, index, placeholderPrefix)) {
                withinNestedPlaceholder++;
                index = index + placeholderPrefix.length();
            }
            else {
                index++;
            }
        }
        return -1;
    }

    private static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
        for (int j = 0; j < substring.length(); j++) {
            int i = index + j;
            if (i >= str.length() || str.charAt(i) != substring.charAt(j)) {
                return false;
            }
        }
        return true;
    }
}


<|start_filename|>examples/sockjs/src/main/java/com/jetdrone/vertx/extras/SockJSExample.java<|end_filename|>
package com.jetdrone.vertx.extras;

import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.middleware.BodyParser;
import com.jetdrone.vertx.yoke.middleware.ErrorHandler;
import com.jetdrone.vertx.yoke.middleware.Static;
import com.jetdrone.vertx.yoke.sockjs.*;
import io.vertx.core.AbstractVerticle;

/*
 * @author <a href="http://tfox.org"><NAME></a>
 */
public class SockJSExample extends AbstractVerticle {

  @Override
  public void start() throws Exception {

    final Yoke yoke = new Yoke(this);

    // Allow outbound traffic to the news-feed address

    BridgeOptions options = new BridgeOptions().addOutboundPermitted(new PermittedOptions().setAddress("news-feed"));

    // TODO: This MUST be /eventbus since the regex's at the yoke side are hardcoded
    yoke.use("/eventbus", new SockJS(vertx, new SockJSHandlerOptions()).bridge(options, event -> {

      // You can also optionally provide a handler like this which will be passed any events that occur on the bridge
      // You can use this for monitoring or logging, or to change the raw messages in-flight.
      // It can also be used for fine grained access control.

      if (event.type() == BridgeEventType.SOCKET_CREATED) {
        System.out.println("A socket was created");
      }

      // This signals that it's ok to process the event
      event.complete(true);

    }));

    yoke.use(new BodyParser());
    yoke.use(new ErrorHandler(true));
    yoke.use(new Static("static"));

    yoke.listen(8080);

    System.out.println("Yoke server listening on port 8080");

    // Publish a message to the address "news-feed" every second
    vertx.setPeriodic(1000, t -> vertx.eventBus().publish("news-feed", "news from the server!"));
  }
}


<|start_filename|>examples/dojo-reststore/src/main/java/com/jetdrone/vertx/extras/JsonRestExample.java<|end_filename|>
package com.jetdrone.vertx.extras;

import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.middleware.*;
import com.jetdrone.vertx.yoke.middleware.BodyParser;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;

public class JsonRestExample extends AbstractVerticle {

  @Override
  public void start() {
    final Yoke yoke = new Yoke(this);

    yoke.use(new BodyParser());
    yoke.use(new ErrorHandler(true));

    // db access
    final InMemoryStore db = new InMemoryStore();

    // preload states from config
    db.bulkLoad("states", "id", config().getJsonArray("states"));

    yoke.use(new JsonRestRouter(db)
        .rest("/states", "states")
    );

    yoke.use(new Static("static"));

    yoke.use(new Handler<YokeRequest>() {
      @Override
      public void handle(YokeRequest request) {
        request.response().redirect("/index.html");
      }
    });

    yoke.listen(8080);

    System.out.println("Yoke server listening on port 8080");
  }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/core/YokeCookie.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.core;

import com.jetdrone.vertx.yoke.YokeSecurity;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import org.jetbrains.annotations.NotNull;

import javax.crypto.Mac;

/**
 * # YokeCookie
 */
public class YokeCookie implements Cookie {

    private final Cookie nettyCookie;
    private final Mac mac;
    private String value;
    private boolean signed;

    public YokeCookie(@NotNull final Cookie nettyCookie, final Mac mac) {
        this.nettyCookie = nettyCookie;
        this.mac = mac;

        // get the original value
        value = nettyCookie.value();
        // if the prefix is there then it is signed
        if (value.startsWith("s:")) {
            signed = true;
            // if it is signed get the unsigned value
            if (mac == null) {
                // this is an error
                value = null;
            } else {
                value = YokeSecurity.unsign(value.substring(2), mac);
            }
        }
    }

    public YokeCookie(@NotNull final String name, final Mac mac) {
        this(new DefaultCookie(name, ""), mac);
    }

    public YokeCookie(@NotNull final String name, @NotNull final String value) {
        this(new DefaultCookie(name, value), null);
    }

    // extensions
    public boolean isSigned() {
        return signed;
    }

    public void sign() {
        if (mac != null) {
            nettyCookie.setValue("s:" + YokeSecurity.sign(value, mac));
            signed = true;
        } else {
            signed = false;
        }
    }

    public String getUnsignedValue() {
        return value;
    }

    @Override
    public String value() {
        return nettyCookie.value();
    }

    @Override
    public void setValue(final String value) {
        this.value = value;
        this.signed = false;
        nettyCookie.setValue(value);
    }

    @Override
    public boolean wrap() {
        return nettyCookie.wrap();
    }

    @Override
    public void setWrap(boolean wrap) {
        nettyCookie.setWrap(wrap);
    }

    @Override
    public String name() {
        return nettyCookie.name();
    }

    @Override
    public String domain() {
        return nettyCookie.domain();
    }

    @Override
    public void setDomain(final String domain) {
        nettyCookie.setDomain(domain);
    }

    @Override
    public String path() {
        return nettyCookie.path();
    }

    @Override
    public void setPath(final String path) {
        nettyCookie.setPath(path);
    }

    @Override
    public long maxAge() {
        return nettyCookie.maxAge();
    }

    @Override
    public void setMaxAge(final long maxAge) {
        nettyCookie.setMaxAge(maxAge);
    }

    @Override
    public boolean isSecure() {
        return nettyCookie.isSecure();
    }

    @Override
    public void setSecure(final boolean secure) {
        nettyCookie.setSecure(secure);
    }

    @Override
    public boolean isHttpOnly() {
        return nettyCookie.isHttpOnly();
    }

    @Override
    public void setHttpOnly(final boolean httpOnly) {
        nettyCookie.setHttpOnly(httpOnly);
    }

    @Override
    public int compareTo(@NotNull final Cookie o) {
        return nettyCookie.compareTo(o);
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/Middleware.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke;

import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.file.FileSystem;

/**
 * # Middleware
 *
 * Abstract class that needs to be implemented when creating a new middleware piece.
 * The class provides access to the Vertx object and by default is not marked as a error handler middleware.
 *
 * If there is a need to create a new error handler middleware the isErrorHandler method should be overridden to
 * return true.
 *
 * The current list of Middleware is:
 * * [BasicAuth](middleware/BasicAuth.html),
 * * [BodyParser](middleware/BodyParser.html),
 * * [BridgeSecureHandler](middleware/BridgeSecureHandler.html),
 * * [Compress](middleware/Compress.html),
 * * [CookieParser](middleware/CookieParser.html),
 * * [Csrf](middleware/Csrf.html),
 * * [ErrorHandler](middleware/ErrorHandler.html),
 * * [Favicon](middleware/Favicon.html),
 * * [Limit](middleware/Limit.html),
 * * [Logger](middleware/Logger.html),
 * * [MethodOverride](middleware/MethodOverride.html),
 * * [RequestProxy](middleware/RequestProxy.html),
 * * [ResponseTime](middleware/ResponseTime.html),
 * * [Router](middleware/Router.html),
 * * [Session](middleware/Session.html),
 * * [Static](middleware/Static.html),
 * * [Timeout](middleware/Timeout.html),
 * * [Vhost](middleware/Vhost.html).
 *
 * Using the extras project you get the following extra Middleware:
 * * [JsonRestRouter].
 */
public abstract class Middleware implements IMiddleware {

    /**
     * Local Yoke instance for usage within the middleware. This is useful to use all asynchronous features of it.
     */
    protected Yoke yoke;

    /**
     * The configured mount point for this middleware.
     */
    protected String mount;

    /**
     * Internal flag to ensure that middleware is initialized only once
     */
    private boolean initialized = false;

    /**
     * Initializes the middleware. This methos is called from Yoke once a middleware is added to the chain.
     *
     * @param yoke the local Yoke instance.
     * @param mount the configured mount path.
     * @return self
     */
    public Middleware init(@NotNull final Yoke yoke, @NotNull final String mount) {

        if (initialized) {
            throw new RuntimeException("Already Initialized!");
        }

        this.yoke = yoke;
        this.mount = mount;
        this.initialized = true;

        return this;
    }

    /**
     * Read only check if this middleware instance has been initialized.
     * @return true if the init method has been called
     */
    public boolean isInitialized() {
        return initialized;
    }

    /**
     * Get access to the event bus
     * @return eventBus
     */
    public EventBus eventBus() {
        return vertx().eventBus();
    }

    /**
     * Get access to the FileSystem object from Vert.x
     * @return fileSystem
     */
    public FileSystem fileSystem() {
        return vertx().fileSystem();
    }

    /**
     * Get access to the security object from Yoke
     * @return security
     */
    public YokeSecurity security() {
        return yoke.security();
    }

    /**
     * Get access to Vert.x object
     * @return vertx
     */
    public Vertx vertx() {
        return yoke.vertx();
    }

    /**
     * When there is a need to identify a middleware to handle errors (error handler) this method should return true.
     *
     * @return true is this middleware will handle errors.
     */
    public boolean isErrorHandler() {
        return false;
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/Cors.java<|end_filename|>

package com.jetdrone.vertx.yoke.middleware;

import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_CREDENTIALS;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_HEADERS;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_METHODS;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_EXPOSE_HEADERS;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_REQUEST_HEADERS;
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_REQUEST_METHOD;
import static io.netty.handler.codec.http.HttpHeaders.Names.ORIGIN;
import static io.netty.handler.codec.http.HttpMethod.OPTIONS;

import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;

import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.http.HttpServerResponse;

import com.jetdrone.vertx.yoke.Middleware;

/**
 * Basic CORS support.
 */
public class Cors extends Middleware
{
    private final Pattern allowedOriginPattern;
    private final Set<String> allowedMethods;
    private final Set<String> allowedHeaders;
    private final Set<String> exposedHeaders;
    private final boolean allowCredentials;

    /**
     * @param allowedOriginPattern if null, '*' will be used.
     */
    public Cors(final Pattern allowedOriginPattern,
                final Set<String> allowedMethods,
                final Set<String> allowedHeaders,
                final Set<String> exposedHeaders,
                final boolean allowCredentials)
    {
        if (allowCredentials && allowedOriginPattern == null)
        {
            throw new IllegalArgumentException("Resource that supports credentials can't accept all origins.");
        }

        this.allowedOriginPattern = allowedOriginPattern;
        this.allowedMethods = allowedMethods;
        this.allowedHeaders = allowedHeaders;
        this.exposedHeaders = exposedHeaders;
        this.allowCredentials = allowCredentials;
    }

    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next)
    {
        if (isPreflightRequest(request))
        {
            handlePreflightRequest(request);
        }
        else
        {
            addCorsResponseHeaders(request, request.response());
            next.handle(null);
        }
    }

    private boolean isPreflightRequest(final YokeRequest request)
    {
        return OPTIONS.name().equals(request.method())
               && (request.getHeader(ACCESS_CONTROL_REQUEST_HEADERS) != null || request.getHeader(ACCESS_CONTROL_REQUEST_METHOD) != null);
    }

    private void handlePreflightRequest(final YokeRequest request)
    {
        if (isValidOrigin(request.getHeader(ORIGIN)))
        {
            addCorsResponseHeaders(request.getHeader(ORIGIN),
                request.response().setStatusCode(204).setStatusMessage("No Content")).end();
        }
        else
        {
            request.response().setStatusCode(403).setStatusMessage("CORS Rejected").end();
        }
    }

    private HttpServerResponse addCorsResponseHeaders(final YokeRequest request, final YokeResponse response)
    {
        final String origin = request.getHeader(ORIGIN);
        return addCorsResponseHeaders(origin, response);
    }

    private HttpServerResponse addCorsResponseHeaders(final String origin, final YokeResponse response)
    {
        if (isValidOrigin(origin))
        {
            response.putHeader(ACCESS_CONTROL_ALLOW_ORIGIN, getAllowedOrigin(origin));

            if (!isEmpty(allowedMethods))
            {
                response.putHeader(ACCESS_CONTROL_ALLOW_METHODS, join(allowedMethods, ","));
            }

            if (!isEmpty(allowedHeaders))
            {
                response.putHeader(ACCESS_CONTROL_ALLOW_HEADERS, join(allowedHeaders, ","));
            }

            if (!isEmpty(exposedHeaders))
            {
                response.putHeader(ACCESS_CONTROL_EXPOSE_HEADERS, join(exposedHeaders, ","));
            }

            if (allowCredentials)
            {
                response.putHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            }
        }

        return response;
    }

    private boolean isValidOrigin(final String origin)
    {
        return allowedOriginPattern == null
               || (isNotBlank(origin) && allowedOriginPattern.matcher(origin).matches());
    }

    private String getAllowedOrigin(final String origin)
    {
        return allowedOriginPattern == null ? "*" : origin;
    }

    private static boolean isEmpty(final Collection<?> c)
    {
        return c == null || c.isEmpty();
    }

    private static boolean isNotBlank(final String s)
    {
        return s != null && !s.trim().isEmpty();
    }

    private static String join(final Collection<String> ss, final String j)
    {
        if (ss == null || ss.isEmpty())
        {
            return "";
        }

        final StringBuilder sb = new StringBuilder();
        boolean first = true;
        for (final String s : ss)
        {
            if (!first)
            {
                sb.append(j);
            }
            sb.append(s);
            first = false;
        }
        return sb.toString();
    }
}


<|start_filename|>examples/form-auth/src/main/java/com/jetdrone/vertx/FormAuthExample.java<|end_filename|>
package com.jetdrone.vertx;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.middleware.AuthHandler;
import com.jetdrone.vertx.yoke.middleware.FormAuth;
import com.jetdrone.vertx.yoke.middleware.*;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonObject;

import javax.crypto.Mac;

public class FormAuthExample extends AbstractVerticle {

  @Override
  public void start() {

    final Yoke app = new Yoke(this);
    app.secretSecurity("keyboard cat");

    final Mac hmac = app.security().getMac("HmacSHA256");

    app.use(new BodyParser());
    app.use(new CookieParser(hmac));
    app.use(new Session(hmac));

    final FormAuth formAuth = new FormAuth(new AuthHandler() {
      @Override
      public void handle(String username, String password, Handler<JsonObject> result) {
        if ("foo".equals(username) && "bar".equals(password)) {
          result.handle(new JsonObject().put("username", "foo"));
        } else {
          result.handle(null);
        }
      }
    });

    app.use(formAuth);

    app.use(new Router() {{
      get("/", new Handler<YokeRequest>() {
        @Override
        public void handle(YokeRequest request) {
          JsonObject session = request.get("session");

          if (session != null && session.getString("user") != null) {
            request.response().setContentType("text/html");
            request.response().end("Welcome " + session.getString("user") + "<br>" + "<a href='/logout'>logout</a>");
          } else {
            request.response().end("<a href='/login'> Login</a>");
          }
        }
      });

      get("/profile", formAuth.RequiredAuth, new Middleware() {
        @Override
        public void handle(YokeRequest request, Handler<Object> next) {
          JsonObject session = request.get("session");
          request.response().setContentType("text/html");
          request.response().end("Profile page of " + session.getString("user") + "<br>" + " click to <a href='/logout'>logout</a>");
        }
      });
    }});

    app.listen(8000);
  }
}

<|start_filename|>examples/swagger-petstore/src/main/resources/swagger-ui-2.0.12/swagger-ui.min.js<|end_filename|>
$(function () {
  $.fn.vAlign = function () {
    return this.each(function (c) {
      var a = $(this).height();
      var d = $(this).parent().height();
      var b = (d - a) / 2;
      $(this).css("margin-top", b)
    })
  };
  $.fn.stretchFormtasticInputWidthToParent = function () {
    return this.each(function (b) {
      var d = $(this).closest("form").innerWidth();
      var c = parseInt($(this).closest("form").css("padding-left"), 10) + parseInt($(this).closest("form").css("padding-right"), 10);
      var a = parseInt($(this).css("padding-left"), 10) + parseInt($(this).css("padding-right"), 10);
      $(this).css("width", d - c - a)
    })
  };
  $("form.formtastic li.string input, form.formtastic textarea").stretchFormtasticInputWidthToParent();
  $("ul.downplayed li div.content p").vAlign();
  $("form.sandbox").submit(function () {
    var a = true;
    $(this).find("input.required").each(function () {
      $(this).removeClass("error");
      if ($(this).val() == "") {
        $(this).addClass("error");
        $(this).wiggle();
        a = false
      }
    });
    return a
  })
});
function clippyCopiedCallback(b) {
  $("#api_key_copied").fadeIn().delay(1000).fadeOut()
}
function log() {
  if (window.console) {
    console.log.apply(console, arguments)
  }
}
if (Function.prototype.bind && console && typeof console.log == "object") {
  ["log", "info", "warn", "error", "assert", "dir", "clear", "profile", "profileEnd"].forEach(function (a) {
    console[a] = this.bind(console[a], console)
  }, Function.prototype.call)
}
var Docs = {
  shebang: function () {
    var b = $.param.fragment().split("/");
    b.shift();
    switch (b.length) {
      case 1:
        var d = "resource_" + b[0];
        Docs.expandEndpointListForResource(b[0]);
        $("#" + d).slideto({highlight: false});
        break;
      case 2:
        Docs.expandEndpointListForResource(b[0]);
        $("#" + d).slideto({highlight: false});
        var c = b.join("_");
        var a = c + "_content";
        Docs.expandOperation($("#" + a));
        $("#" + c).slideto({highlight: false});
        break
    }
  }, toggleEndpointListForResource: function (b) {
    var a = $("li#resource_" + Docs.escapeResourceName(b) + " ul.endpoints");
    if (a.is(":visible")) {
      Docs.collapseEndpointListForResource(b)
    } else {
      Docs.expandEndpointListForResource(b)
    }
  }, expandEndpointListForResource: function (b) {
    var b = Docs.escapeResourceName(b);
    if (b == "") {
      $(".resource ul.endpoints").slideDown();
      return
    }
    $("li#resource_" + b).addClass("active");
    var a = $("li#resource_" + b + " ul.endpoints");
    a.slideDown()
  }, collapseEndpointListForResource: function (b) {
    var b = Docs.escapeResourceName(b);
    $("li#resource_" + b).removeClass("active");
    var a = $("li#resource_" + b + " ul.endpoints");
    a.slideUp()
  }, expandOperationsForResource: function (a) {
    Docs.expandEndpointListForResource(a);
    if (a == "") {
      $(".resource ul.endpoints li.operation div.content").slideDown();
      return
    }
    $("li#resource_" + Docs.escapeResourceName(a) + " li.operation div.content").each(function () {
      Docs.expandOperation($(this))
    })
  }, collapseOperationsForResource: function (a) {
    Docs.expandEndpointListForResource(a);
    $("li#resource_" + Docs.escapeResourceName(a) + " li.operation div.content").each(function () {
      Docs.collapseOperation($(this))
    })
  }, escapeResourceName: function (a) {
    return a.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g, "\\$&")
  }, expandOperation: function (a) {
    a.slideDown()
  }, collapseOperation: function (a) {
    a.slideUp()
  }
};
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.content_type = b(function (g, l, f, k, j) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    j = j || {};
    var i = "", c, h = "function", m = this;

    function e(r, q) {
      var o = "", p;
      o += "\n  ";
      p = f.each.call(r, r.produces, {hash: {}, inverse: m.noop, fn: m.program(2, d, q), data: q});
      if (p || p === 0) {
        o += p
      }
      o += "\n";
      return o
    }

    function d(r, q) {
      var o = "", p;
      o += '\n	<option value="';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += '">';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += "</option>\n	";
      return o
    }

    function n(p, o) {
      return '\n  <option value="application/json">application/json</option>\n'
    }

    i += '<label for="contentType"></label>\n<select name="contentType">\n';
    c = f["if"].call(l, l.produces, {hash: {}, inverse: m.program(4, n, j), fn: m.program(1, e, j), data: j});
    if (c || c === 0) {
      i += c
    }
    i += "\n</select>\n";
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.main = b(function (g, m, f, l, k) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    k = k || {};
    var i = "", c, h = "function", j = this.escapeExpression, p = this;

    function e(v, u) {
      var r = "", t, s;
      r += '\n    <div class="info_title">' + j(((t = ((t = v.info), t == null || t === false ? t : t.title)), typeof t === h ? t.apply(v) : t)) + '</div>\n    <div class="info_description">';
      s = ((t = ((t = v.info), t == null || t === false ? t : t.description)), typeof t === h ? t.apply(v) : t);
      if (s || s === 0) {
        r += s
      }
      r += "</div>\n    ";
      s = f["if"].call(v, ((t = v.info), t == null || t === false ? t : t.termsOfServiceUrl), {
        hash: {},
        inverse: p.noop,
        fn: p.program(2, d, u),
        data: u
      });
      if (s || s === 0) {
        r += s
      }
      r += "\n    ";
      s = f["if"].call(v, ((t = v.info), t == null || t === false ? t : t.contact), {
        hash: {},
        inverse: p.noop,
        fn: p.program(4, q, u),
        data: u
      });
      if (s || s === 0) {
        r += s
      }
      r += "\n    ";
      s = f["if"].call(v, ((t = v.info), t == null || t === false ? t : t.license), {
        hash: {},
        inverse: p.noop,
        fn: p.program(6, o, u),
        data: u
      });
      if (s || s === 0) {
        r += s
      }
      r += "\n  ";
      return r
    }

    function d(u, t) {
      var r = "", s;
      r += '<div class="info_tos"><a href="' + j(((s = ((s = u.info), s == null || s === false ? s : s.termsOfServiceUrl)), typeof s === h ? s.apply(u) : s)) + '">Terms of service</a></div>';
      return r
    }

    function q(u, t) {
      var r = "", s;
      r += "<div class='info_contact'><a href=\"mailto:" + j(((s = ((s = u.info), s == null || s === false ? s : s.contact)), typeof s === h ? s.apply(u) : s)) + '">Contact the developer</a></div>';
      return r
    }

    function o(u, t) {
      var r = "", s;
      r += "<div class='info_license'><a href='" + j(((s = ((s = u.info), s == null || s === false ? s : s.licenseUrl)), typeof s === h ? s.apply(u) : s)) + "'>" + j(((s = ((s = u.info), s == null || s === false ? s : s.license)), typeof s === h ? s.apply(u) : s)) + "</a></div>";
      return r
    }

    function n(u, t) {
      var r = "", s;
      r += '\n        , <span style="font-variant: small-caps">api version</span>: ';
      if (s = f.apiVersion) {
        s = s.call(u, {hash: {}, data: t})
      } else {
        s = u.apiVersion;
        s = typeof s === h ? s.apply(u) : s
      }
      r += j(s) + "\n        ";
      return r
    }

    i += "<div class='info' id='api_info'>\n  ";
    c = f["if"].call(m, m.info, {hash: {}, inverse: p.noop, fn: p.program(1, e, k), data: k});
    if (c || c === 0) {
      i += c
    }
    i += "\n</div>\n<div class='container' id='resources_container'>\n    <ul id='resources'>\n    </ul>\n\n    <div class=\"footer\">\n        <br>\n        <br>\n        <h4 style=\"color: #999\">[ <span style=\"font-variant: small-caps\">base url</span>: ";
    if (c = f.basePath) {
      c = c.call(m, {hash: {}, data: k})
    } else {
      c = m.basePath;
      c = typeof c === h ? c.apply(m) : c
    }
    i += j(c) + "\n        ";
    c = f["if"].call(m, m.apiVersion, {hash: {}, inverse: p.noop, fn: p.program(8, n, k), data: k});
    if (c || c === 0) {
      i += c
    }
    i += "]</h4>\n    </div>\n</div>\n";
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.operation = b(function (h, n, g, m, l) {
    this.compilerInfo = [4, ">= 1.0.0"];
    g = this.merge(g, h.helpers);
    l = l || {};
    var j = "", d, i = "function", k = this.escapeExpression, r = this;

    function f(v, u) {
      var s = "", t;
      s += "\n        <h4>Implementation Notes</h4>\n        <p>";
      if (t = g.notes) {
        t = t.call(v, {hash: {}, data: u})
      } else {
        t = v.notes;
        t = typeof t === i ? t.apply(v) : t
      }
      if (t || t === 0) {
        s += t
      }
      s += "</p>\n        ";
      return s
    }

    function c(t, s) {
      return '\n          <h4>Response Class</h4>\n          <p><span class="model-signature" /></p>\n          <br/>\n          <div class="response-content-type" />\n        '
    }

    function q(t, s) {
      return '\n          <h4>Parameters</h4>\n          <table class=\'fullwidth\'>\n          <thead>\n            <tr>\n            <th style="width: 100px; max-width: 100px">Parameter</th>\n            <th style="width: 310px; max-width: 310px">Value</th>\n            <th style="width: 200px; max-width: 200px">Description</th>\n            <th style="width: 100px; max-width: 100px">Parameter Type</th>\n            <th style="width: 220px; max-width: 230px">Data Type</th>\n            </tr>\n          </thead>\n          <tbody class="operation-params">\n\n          </tbody>\n          </table>\n          '
    }

    function p(t, s) {
      return "\n          <div style='margin:0;padding:0;display:inline'></div>\n          <h4>Error Status Codes</h4>\n          <table class='fullwidth'>\n            <thead>\n            <tr>\n              <th>HTTP Status Code</th>\n              <th>Reason</th>\n            </tr>\n            </thead>\n            <tbody class=\"operation-status\">\n            \n            </tbody>\n          </table>\n          "
    }

    function o(t, s) {
      return "\n          "
    }

    function e(t, s) {
      return "\n          <div class='sandbox_header'>\n            <input class='submit' name='commit' type='button' value='Try it out!' />\n            <a href='#' class='response_hider' style='display:none'>Hide Response</a>\n            <img alt='Throbber' class='response_throbber' src='images/throbber.gif' style='display:none' />\n          </div>\n          "
    }

    j += "\n  <ul class='operations' >\n    <li class='";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + " operation' id='";
    if (d = g.resourceName) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.resourceName;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.nickname) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.nickname;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.number) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.number;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "'>\n      <div class='heading'>\n        <h3>\n          <span class='http_method'>\n          <a href='#!/";
    if (d = g.resourceName) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.resourceName;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "/";
    if (d = g.nickname) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.nickname;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.number) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.number;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + '\' class="toggleOperation">';
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "</a>\n          </span>\n          <span class='path'>\n          <a href='#!/";
    if (d = g.resourceName) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.resourceName;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "/";
    if (d = g.nickname) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.nickname;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.number) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.number;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + '\' class="toggleOperation">';
    if (d = g.path) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.path;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "</a>\n          </span>\n        </h3>\n        <ul class='options'>\n          <li>\n          <a href='#!/";
    if (d = g.resourceName) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.resourceName;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "/";
    if (d = g.nickname) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.nickname;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.number) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.number;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + '\' class="toggleOperation">';
    if (d = g.summary) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.summary;
      d = typeof d === i ? d.apply(n) : d
    }
    if (d || d === 0) {
      j += d
    }
    j += "</a>\n          </li>\n        </ul>\n      </div>\n      <div class='content' id='";
    if (d = g.resourceName) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.resourceName;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.nickname) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.nickname;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.method) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.method;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_";
    if (d = g.number) {
      d = d.call(n, {hash: {}, data: l})
    } else {
      d = n.number;
      d = typeof d === i ? d.apply(n) : d
    }
    j += k(d) + "_content' style='display:none'>\n        ";
    d = g["if"].call(n, n.notes, {hash: {}, inverse: r.noop, fn: r.program(1, f, l), data: l});
    if (d || d === 0) {
      j += d
    }
    j += "\n        ";
    d = g["if"].call(n, n.type, {hash: {}, inverse: r.noop, fn: r.program(3, c, l), data: l});
    if (d || d === 0) {
      j += d
    }
    j += "\n        <form accept-charset='UTF-8' class='sandbox'>\n          <div style='margin:0;padding:0;display:inline'></div>\n          ";
    d = g["if"].call(n, n.parameters, {hash: {}, inverse: r.noop, fn: r.program(5, q, l), data: l});
    if (d || d === 0) {
      j += d
    }
    j += "\n          ";
    d = g["if"].call(n, n.responseMessages, {hash: {}, inverse: r.noop, fn: r.program(7, p, l), data: l});
    if (d || d === 0) {
      j += d
    }
    j += "\n          ";
    d = g["if"].call(n, n.isReadOnly, {hash: {}, inverse: r.program(11, e, l), fn: r.program(9, o, l), data: l});
    if (d || d === 0) {
      j += d
    }
    j += "\n        </form>\n        <div class='response' style='display:none'>\n          <h4>Request URL</h4>\n          <div class='block request_url'></div>\n          <h4>Response Body</h4>\n          <div class='block response_body'></div>\n          <h4>Response Code</h4>\n          <div class='block response_code'></div>\n          <h4>Response Headers</h4>\n          <div class='block response_headers'></div>\n        </div>\n      </div>\n    </li>\n  </ul>\n";
    return j
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.param = b(function (f, q, o, j, s) {
    this.compilerInfo = [4, ">= 1.0.0"];
    o = this.merge(o, f.helpers);
    s = s || {};
    var p = "", g, d = "function", c = this.escapeExpression, n = this;

    function m(x, w) {
      var u = "", v;
      u += "\n		";
      v = o["if"].call(x, x.isFile, {hash: {}, inverse: n.program(4, k, w), fn: n.program(2, l, w), data: w});
      if (v || v === 0) {
        u += v
      }
      u += "\n	";
      return u
    }

    function l(x, w) {
      var u = "", v;
      u += '\n			<input type="file" name=\'';
      if (v = o.name) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.name;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + '\'/>\n			<div class="parameter-content-type" />\n		';
      return u
    }

    function k(x, w) {
      var u = "", v;
      u += "\n			";
      v = o["if"].call(x, x.defaultValue, {hash: {}, inverse: n.program(7, h, w), fn: n.program(5, i, w), data: w});
      if (v || v === 0) {
        u += v
      }
      u += "\n		";
      return u
    }

    function i(x, w) {
      var u = "", v;
      u += "\n				<textarea class='body-textarea' name='";
      if (v = o.name) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.name;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + "'>";
      if (v = o.defaultValue) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.defaultValue;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + "</textarea>\n			";
      return u
    }

    function h(x, w) {
      var u = "", v;
      u += "\n				<textarea class='body-textarea' name='";
      if (v = o.name) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.name;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + '\'></textarea>\n				<br />\n				<div class="parameter-content-type" />\n			';
      return u
    }

    function e(x, w) {
      var u = "", v;
      u += "\n		";
      v = o["if"].call(x, x.defaultValue, {hash: {}, inverse: n.program(12, r, w), fn: n.program(10, t, w), data: w});
      if (v || v === 0) {
        u += v
      }
      u += "\n	";
      return u
    }

    function t(x, w) {
      var u = "", v;
      u += "\n			<input class='parameter' minlength='0' name='";
      if (v = o.name) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.name;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + "' placeholder='' type='text' value='";
      if (v = o.defaultValue) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.defaultValue;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + "'/>\n		";
      return u
    }

    function r(x, w) {
      var u = "", v;
      u += "\n			<input class='parameter' minlength='0' name='";
      if (v = o.name) {
        v = v.call(x, {hash: {}, data: w})
      } else {
        v = x.name;
        v = typeof v === d ? v.apply(x) : v
      }
      u += c(v) + "' placeholder='' type='text' value=''/>\n		";
      return u
    }

    p += "<td class='code'>";
    if (g = o.name) {
      g = g.call(q, {hash: {}, data: s})
    } else {
      g = q.name;
      g = typeof g === d ? g.apply(q) : g
    }
    p += c(g) + "</td>\n<td>\n\n	";
    g = o["if"].call(q, q.isBody, {hash: {}, inverse: n.program(9, e, s), fn: n.program(1, m, s), data: s});
    if (g || g === 0) {
      p += g
    }
    p += "\n\n</td>\n<td>";
    if (g = o.description) {
      g = g.call(q, {hash: {}, data: s})
    } else {
      g = q.description;
      g = typeof g === d ? g.apply(q) : g
    }
    if (g || g === 0) {
      p += g
    }
    p += "</td>\n<td>";
    if (g = o.paramType) {
      g = g.call(q, {hash: {}, data: s})
    } else {
      g = q.paramType;
      g = typeof g === d ? g.apply(q) : g
    }
    if (g || g === 0) {
      p += g
    }
    p += '</td>\n<td>\n	<span class="model-signature"></span>\n</td>\n';
    return p
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.param_list = b(function (g, r, p, l, w) {
    this.compilerInfo = [4, ">= 1.0.0"];
    p = this.merge(p, g.helpers);
    w = w || {};
    var q = "", i, e, o = this, d = "function", c = this.escapeExpression;

    function n(y, x) {
      return " multiple='multiple'"
    }

    function m(y, x) {
      return "\n    "
    }

    function k(A, z) {
      var x = "", y;
      x += "\n      ";
      y = p["if"].call(A, A.defaultValue, {hash: {}, inverse: o.program(8, h, z), fn: o.program(6, j, z), data: z});
      if (y || y === 0) {
        x += y
      }
      x += "\n    ";
      return x
    }

    function j(y, x) {
      return "\n      "
    }

    function h(A, z) {
      var x = "", y;
      x += "\n        ";
      y = p["if"].call(A, A.allowMultiple, {hash: {}, inverse: o.program(11, v, z), fn: o.program(9, f, z), data: z});
      if (y || y === 0) {
        x += y
      }
      x += "\n      ";
      return x
    }

    function f(y, x) {
      return "\n         "
    }

    function v(y, x) {
      return "\n          <option selected=\"\" value=''></option>\n         "
    }

    function u(A, z) {
      var x = "", y;
      x += "\n      ";
      y = p["if"].call(A, A.isDefault, {hash: {}, inverse: o.program(16, s, z), fn: o.program(14, t, z), data: z});
      if (y || y === 0) {
        x += y
      }
      x += "\n    ";
      return x
    }

    function t(A, z) {
      var x = "", y;
      x += '\n        <option selected="" value=\'';
      if (y = p.value) {
        y = y.call(A, {hash: {}, data: z})
      } else {
        y = A.value;
        y = typeof y === d ? y.apply(A) : y
      }
      x += c(y) + "'>";
      if (y = p.value) {
        y = y.call(A, {hash: {}, data: z})
      } else {
        y = A.value;
        y = typeof y === d ? y.apply(A) : y
      }
      x += c(y) + " (default)</option>\n      ";
      return x
    }

    function s(A, z) {
      var x = "", y;
      x += "\n        <option value='";
      if (y = p.value) {
        y = y.call(A, {hash: {}, data: z})
      } else {
        y = A.value;
        y = typeof y === d ? y.apply(A) : y
      }
      x += c(y) + "'>";
      if (y = p.value) {
        y = y.call(A, {hash: {}, data: z})
      } else {
        y = A.value;
        y = typeof y === d ? y.apply(A) : y
      }
      x += c(y) + "</option>\n      ";
      return x
    }

    q += "<td class='code'>";
    if (i = p.name) {
      i = i.call(r, {hash: {}, data: w})
    } else {
      i = r.name;
      i = typeof i === d ? i.apply(r) : i
    }
    q += c(i) + "</td>\n<td>\n  <select ";
    i = p["if"].call(r, r.allowMultiple, {hash: {}, inverse: o.noop, fn: o.program(1, n, w), data: w});
    if (i || i === 0) {
      q += i
    }
    q += " class='parameter' name='";
    if (i = p.name) {
      i = i.call(r, {hash: {}, data: w})
    } else {
      i = r.name;
      i = typeof i === d ? i.apply(r) : i
    }
    q += c(i) + "'>\n    ";
    i = p["if"].call(r, r.required, {hash: {}, inverse: o.program(5, k, w), fn: o.program(3, m, w), data: w});
    if (i || i === 0) {
      q += i
    }
    q += "\n    ";
    e = p.each.call(r, ((i = r.allowableValues), i == null || i === false ? i : i.descriptiveValues), {
      hash: {},
      inverse: o.noop,
      fn: o.program(13, u, w),
      data: w
    });
    if (e || e === 0) {
      q += e
    }
    q += "\n  </select>\n</td>\n<td>";
    if (e = p.description) {
      e = e.call(r, {hash: {}, data: w})
    } else {
      e = r.description;
      e = typeof e === d ? e.apply(r) : e
    }
    if (e || e === 0) {
      q += e
    }
    q += "</td>\n<td>";
    if (e = p.paramType) {
      e = e.call(r, {hash: {}, data: w})
    } else {
      e = r.paramType;
      e = typeof e === d ? e.apply(r) : e
    }
    if (e || e === 0) {
      q += e
    }
    q += '</td>\n<td><span class="model-signature"></span></td>';
    return q
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.param_readonly = b(function (g, m, f, l, k) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    k = k || {};
    var i = "", d, h = "function", j = this.escapeExpression, o = this;

    function e(t, s) {
      var q = "", r;
      q += "\n        <textarea class='body-textarea' readonly='readonly' name='";
      if (r = f.name) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.name;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "'>";
      if (r = f.defaultValue) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.defaultValue;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "</textarea>\n    ";
      return q
    }

    function c(t, s) {
      var q = "", r;
      q += "\n        ";
      r = f["if"].call(t, t.defaultValue, {hash: {}, inverse: o.program(6, n, s), fn: o.program(4, p, s), data: s});
      if (r || r === 0) {
        q += r
      }
      q += "\n    ";
      return q
    }

    function p(t, s) {
      var q = "", r;
      q += "\n            ";
      if (r = f.defaultValue) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.defaultValue;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "\n        ";
      return q
    }

    function n(r, q) {
      return "\n            (empty)\n        "
    }

    i += "<td class='code'>";
    if (d = f.name) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.name;
      d = typeof d === h ? d.apply(m) : d
    }
    i += j(d) + "</td>\n<td>\n    ";
    d = f["if"].call(m, m.isBody, {hash: {}, inverse: o.program(3, c, k), fn: o.program(1, e, k), data: k});
    if (d || d === 0) {
      i += d
    }
    i += "\n</td>\n<td>";
    if (d = f.description) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.description;
      d = typeof d === h ? d.apply(m) : d
    }
    if (d || d === 0) {
      i += d
    }
    i += "</td>\n<td>";
    if (d = f.paramType) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.paramType;
      d = typeof d === h ? d.apply(m) : d
    }
    if (d || d === 0) {
      i += d
    }
    i += '</td>\n<td><span class="model-signature"></span></td>\n';
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.param_readonly_required = b(function (g, m, f, l, k) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    k = k || {};
    var i = "", d, h = "function", j = this.escapeExpression, o = this;

    function e(t, s) {
      var q = "", r;
      q += "\n        <textarea class='body-textarea'  readonly='readonly' placeholder='(required)' name='";
      if (r = f.name) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.name;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "'>";
      if (r = f.defaultValue) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.defaultValue;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "</textarea>\n    ";
      return q
    }

    function c(t, s) {
      var q = "", r;
      q += "\n        ";
      r = f["if"].call(t, t.defaultValue, {hash: {}, inverse: o.program(6, n, s), fn: o.program(4, p, s), data: s});
      if (r || r === 0) {
        q += r
      }
      q += "\n    ";
      return q
    }

    function p(t, s) {
      var q = "", r;
      q += "\n            ";
      if (r = f.defaultValue) {
        r = r.call(t, {hash: {}, data: s})
      } else {
        r = t.defaultValue;
        r = typeof r === h ? r.apply(t) : r
      }
      q += j(r) + "\n        ";
      return q
    }

    function n(r, q) {
      return "\n            (empty)\n        "
    }

    i += "<td class='code required'>";
    if (d = f.name) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.name;
      d = typeof d === h ? d.apply(m) : d
    }
    i += j(d) + "</td>\n<td>\n    ";
    d = f["if"].call(m, m.isBody, {hash: {}, inverse: o.program(3, c, k), fn: o.program(1, e, k), data: k});
    if (d || d === 0) {
      i += d
    }
    i += "\n</td>\n<td>";
    if (d = f.description) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.description;
      d = typeof d === h ? d.apply(m) : d
    }
    if (d || d === 0) {
      i += d
    }
    i += "</td>\n<td>";
    if (d = f.paramType) {
      d = d.call(m, {hash: {}, data: k})
    } else {
      d = m.paramType;
      d = typeof d === h ? d.apply(m) : d
    }
    if (d || d === 0) {
      i += d
    }
    i += '</td>\n<td><span class="model-signature"></span></td>\n';
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.param_required = b(function (f, q, o, j, u) {
    this.compilerInfo = [4, ">= 1.0.0"];
    o = this.merge(o, f.helpers);
    u = u || {};
    var p = "", g, d = "function", c = this.escapeExpression, n = this;

    function m(z, y) {
      var w = "", x;
      w += "\n		";
      x = o["if"].call(z, z.isFile, {hash: {}, inverse: n.program(4, k, y), fn: n.program(2, l, y), data: y});
      if (x || x === 0) {
        w += x
      }
      w += "\n	";
      return w
    }

    function l(z, y) {
      var w = "", x;
      w += '\n			<input type="file" name=\'';
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "'/>\n		";
      return w
    }

    function k(z, y) {
      var w = "", x;
      w += "\n			";
      x = o["if"].call(z, z.defaultValue, {hash: {}, inverse: n.program(7, h, y), fn: n.program(5, i, y), data: y});
      if (x || x === 0) {
        w += x
      }
      w += "\n		";
      return w
    }

    function i(z, y) {
      var w = "", x;
      w += "\n				<textarea class='body-textarea' placeholder='(required)' name='";
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "'>";
      if (x = o.defaultValue) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.defaultValue;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "</textarea>\n			";
      return w
    }

    function h(z, y) {
      var w = "", x;
      w += "\n				<textarea class='body-textarea' placeholder='(required)' name='";
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + '\'></textarea>\n				<br />\n				<div class="parameter-content-type" />\n			';
      return w
    }

    function e(z, y) {
      var w = "", x;
      w += "\n		";
      x = o["if"].call(z, z.isFile, {hash: {}, inverse: n.program(12, t, y), fn: n.program(10, v, y), data: y});
      if (x || x === 0) {
        w += x
      }
      w += "\n	";
      return w
    }

    function v(z, y) {
      var w = "", x;
      w += "\n			<input class='parameter' class='required' type='file' name='";
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "'/>\n		";
      return w
    }

    function t(z, y) {
      var w = "", x;
      w += "\n			";
      x = o["if"].call(z, z.defaultValue, {hash: {}, inverse: n.program(15, r, y), fn: n.program(13, s, y), data: y});
      if (x || x === 0) {
        w += x
      }
      w += "\n		";
      return w
    }

    function s(z, y) {
      var w = "", x;
      w += "\n				<input class='parameter required' minlength='1' name='";
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "' placeholder='(required)' type='text' value='";
      if (x = o.defaultValue) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.defaultValue;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "'/>\n			";
      return w
    }

    function r(z, y) {
      var w = "", x;
      w += "\n				<input class='parameter required' minlength='1' name='";
      if (x = o.name) {
        x = x.call(z, {hash: {}, data: y})
      } else {
        x = z.name;
        x = typeof x === d ? x.apply(z) : x
      }
      w += c(x) + "' placeholder='(required)' type='text' value=''/>\n			";
      return w
    }

    p += "<td class='code required'>";
    if (g = o.name) {
      g = g.call(q, {hash: {}, data: u})
    } else {
      g = q.name;
      g = typeof g === d ? g.apply(q) : g
    }
    p += c(g) + "</td>\n<td>\n	";
    g = o["if"].call(q, q.isBody, {hash: {}, inverse: n.program(9, e, u), fn: n.program(1, m, u), data: u});
    if (g || g === 0) {
      p += g
    }
    p += "\n</td>\n<td>\n	<strong>";
    if (g = o.description) {
      g = g.call(q, {hash: {}, data: u})
    } else {
      g = q.description;
      g = typeof g === d ? g.apply(q) : g
    }
    if (g || g === 0) {
      p += g
    }
    p += "</strong>\n</td>\n<td>";
    if (g = o.paramType) {
      g = g.call(q, {hash: {}, data: u})
    } else {
      g = q.paramType;
      g = typeof g === d ? g.apply(q) : g
    }
    if (g || g === 0) {
      p += g
    }
    p += '</td>\n<td><span class="model-signature"></span></td>\n';
    return p
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.parameter_content_type = b(function (g, l, f, k, j) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    j = j || {};
    var i = "", c, h = "function", m = this;

    function e(r, q) {
      var o = "", p;
      o += "\n  ";
      p = f.each.call(r, r.consumes, {hash: {}, inverse: m.noop, fn: m.program(2, d, q), data: q});
      if (p || p === 0) {
        o += p
      }
      o += "\n";
      return o
    }

    function d(r, q) {
      var o = "", p;
      o += '\n  <option value="';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += '">';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += "</option>\n  ";
      return o
    }

    function n(p, o) {
      return '\n  <option value="application/json">application/json</option>\n'
    }

    i += '<label for="parameterContentType"></label>\n<select name="parameterContentType">\n';
    c = f["if"].call(l, l.consumes, {hash: {}, inverse: m.program(4, n, j), fn: m.program(1, e, j), data: j});
    if (c || c === 0) {
      i += c
    }
    i += "\n</select>\n";
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.resource = b(function (f, l, e, k, j) {
    this.compilerInfo = [4, ">= 1.0.0"];
    e = this.merge(e, f.helpers);
    j = j || {};
    var h = "", c, o, g = "function", i = this.escapeExpression, n = this, m = e.blockHelperMissing;

    function d(q, p) {
      return " : "
    }

    h += "<div class='heading'>\n  <h2>\n    <a href='#!/";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "' onclick=\"Docs.toggleEndpointListForResource('";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "');\">";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "</a> ";
    o = {hash: {}, inverse: n.noop, fn: n.program(1, d, j), data: j};
    if (c = e.description) {
      c = c.call(l, o)
    } else {
      c = l.description;
      c = typeof c === g ? c.apply(l) : c
    }
    if (!e.description) {
      c = m.call(l, c, o)
    }
    if (c || c === 0) {
      h += c
    }
    if (c = e.description) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.description;
      c = typeof c === g ? c.apply(l) : c
    }
    if (c || c === 0) {
      h += c
    }
    h += "\n  </h2>\n  <ul class='options'>\n    <li>\n      <a href='#!/";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "' id='endpointListTogger_";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "'\n         onclick=\"Docs.toggleEndpointListForResource('";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "');\">Show/Hide</a>\n    </li>\n    <li>\n      <a href='#' onclick=\"Docs.collapseOperationsForResource('";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "'); return false;\">\n        List Operations\n      </a>\n    </li>\n    <li>\n      <a href='#' onclick=\"Docs.expandOperationsForResource('";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "'); return false;\">\n        Expand Operations\n      </a>\n    </li>\n    <li>\n      <a href='";
    if (c = e.url) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.url;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "'>Raw</a>\n    </li>\n  </ul>\n</div>\n<ul class='endpoints' id='";
    if (c = e.name) {
      c = c.call(l, {hash: {}, data: j})
    } else {
      c = l.name;
      c = typeof c === g ? c.apply(l) : c
    }
    h += i(c) + "_endpoint_list' style='display:none'>\n\n</ul>\n";
    return h
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.response_content_type = b(function (g, l, f, k, j) {
    this.compilerInfo = [4, ">= 1.0.0"];
    f = this.merge(f, g.helpers);
    j = j || {};
    var i = "", c, h = "function", m = this;

    function e(r, q) {
      var o = "", p;
      o += "\n  ";
      p = f.each.call(r, r.produces, {hash: {}, inverse: m.noop, fn: m.program(2, d, q), data: q});
      if (p || p === 0) {
        o += p
      }
      o += "\n";
      return o
    }

    function d(r, q) {
      var o = "", p;
      o += '\n  <option value="';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += '">';
      p = (typeof r === h ? r.apply(r) : r);
      if (p || p === 0) {
        o += p
      }
      o += "</option>\n  ";
      return o
    }

    function n(p, o) {
      return '\n  <option value="application/json">application/json</option>\n'
    }

    i += '<label for="responseContentType"></label>\n<select name="responseContentType">\n';
    c = f["if"].call(l, l.produces, {hash: {}, inverse: m.program(4, n, j), fn: m.program(1, e, j), data: j});
    if (c || c === 0) {
      i += c
    }
    i += "\n</select>\n";
    return i
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.signature = b(function (e, k, d, j, i) {
    this.compilerInfo = [4, ">= 1.0.0"];
    d = this.merge(d, e.helpers);
    i = i || {};
    var g = "", c, f = "function", h = this.escapeExpression;
    g += '<div>\n<ul class="signature-nav">\n    <li><a class="description-link" href="#">Model</a></li>\n    <li><a class="snippet-link" href="#">Model Schema</a></li>\n</ul>\n<div>\n\n<div class="signature-container">\n    <div class="description">\n        ';
    if (c = d.signature) {
      c = c.call(k, {hash: {}, data: i})
    } else {
      c = k.signature;
      c = typeof c === f ? c.apply(k) : c
    }
    if (c || c === 0) {
      g += c
    }
    g += '\n    </div>\n\n    <div class="snippet">\n        <pre><code>';
    if (c = d.sampleJSON) {
      c = c.call(k, {hash: {}, data: i})
    } else {
      c = k.sampleJSON;
      c = typeof c === f ? c.apply(k) : c
    }
    g += h(c) + '</code></pre>\n        <small class="notice"></small>\n    </div>\n</div>\n\n';
    return g
  })
})();
(function () {
  var b = Handlebars.template, a = Handlebars.templates = Handlebars.templates || {};
  a.status_code = b(function (e, k, d, j, i) {
    this.compilerInfo = [4, ">= 1.0.0"];
    d = this.merge(d, e.helpers);
    i = i || {};
    var g = "", c, f = "function", h = this.escapeExpression;
    g += "<td width='15%' class='code'>";
    if (c = d.code) {
      c = c.call(k, {hash: {}, data: i})
    } else {
      c = k.code;
      c = typeof c === f ? c.apply(k) : c
    }
    g += h(c) + "</td>\n<td>";
    if (c = d.message) {
      c = c.call(k, {hash: {}, data: i})
    } else {
      c = k.message;
      c = typeof c === f ? c.apply(k) : c
    }
    if (c || c === 0) {
      g += c
    }
    g += "</td>\n";
    return g
  })
})();
(function () {
  var j, r, u, o, l, k, n, m, i, p, s, q, h, c, g, f, e, d, b, a, x, w, t = {}.hasOwnProperty, v = function (B, z) {
    for (var y in z) {
      if (t.call(z, y)) {
        B[y] = z[y]
      }
    }
    function A() {
      this.constructor = B
    }

    A.prototype = z.prototype;
    B.prototype = new A();
    B.__super__ = z.prototype;
    return B
  };
  s = (function (z) {
    v(y, z);
    function y() {
      q = y.__super__.constructor.apply(this, arguments);
      return q
    }

    y.prototype.dom_id = "swagger_ui";
    y.prototype.options = null;
    y.prototype.api = null;
    y.prototype.headerView = null;
    y.prototype.mainView = null;
    y.prototype.initialize = function (A) {
      var B = this;
      if (A == null) {
        A = {}
      }
      if (A.dom_id != null) {
        this.dom_id = A.dom_id;
        delete A.dom_id
      }
      if ($("#" + this.dom_id) == null) {
        $("body").append('<div id="' + this.dom_id + '"></div>')
      }
      this.options = A;
      this.options.success = function () {
        return B.render()
      };
      this.options.progress = function (C) {
        return B.showMessage(C)
      };
      this.options.failure = function (C) {
        return B.onLoadFailure(C)
      };
      this.headerView = new r({el: $("#header")});
      return this.headerView.on("update-swagger-ui", function (C) {
        return B.updateSwaggerUi(C)
      })
    };
    y.prototype.updateSwaggerUi = function (A) {
      this.options.url = A.url;
      return this.load()
    };
    y.prototype.load = function () {
      var B, A;
      if ((A = this.mainView) != null) {
        A.clear()
      }
      B = this.options.url;
      if (B.indexOf("http") !== 0) {
        B = this.buildUrl(window.location.href.toString(), B)
      }
      this.options.url = B;
      this.headerView.update(B);
      this.api = new SwaggerApi(this.options);
      this.api.build();
      return this.api
    };
    y.prototype.render = function () {
      var A = this;
      this.showMessage("Finished Loading Resource Information. Rendering Swagger UI...");
      this.mainView = new u({model: this.api, el: $("#" + this.dom_id)}).render();
      this.showMessage();
      switch (this.options.docExpansion) {
        case"full":
          Docs.expandOperationsForResource("");
          break;
        case"list":
          Docs.collapseOperationsForResource("")
      }
      if (this.options.onComplete) {
        this.options.onComplete(this.api, this)
      }
      return setTimeout(function () {
        return Docs.shebang()
      }, 400)
    };
    y.prototype.buildUrl = function (C, A) {
      var B, D;
      log("base is " + C);
      if (A.indexOf("/") === 0) {
        D = C.split("/");
        C = D[0] + "//" + D[2];
        return C + A
      } else {
        B = C.length;
        if (C.indexOf("?") > -1) {
          B = Math.min(B, C.indexOf("?"))
        }
        if (C.indexOf("#") > -1) {
          B = Math.min(B, C.indexOf("#"))
        }
        C = C.substring(0, B);
        if (C.indexOf("/", C.length - 1) !== -1) {
          return C + A
        }
        return C + "/" + A
      }
    };
    y.prototype.showMessage = function (A) {
      if (A == null) {
        A = ""
      }
      $("#message-bar").removeClass("message-fail");
      $("#message-bar").addClass("message-success");
      return $("#message-bar").html(A)
    };
    y.prototype.onLoadFailure = function (A) {
      var B;
      if (A == null) {
        A = ""
      }
      $("#message-bar").removeClass("message-success");
      $("#message-bar").addClass("message-fail");
      B = $("#message-bar").html(A);
      if (this.options.onFailure != null) {
        this.options.onFailure(A)
      }
      return B
    };
    return y
  })(Backbone.Router);
  window.SwaggerUi = s;
  r = (function (z) {
    v(y, z);
    function y() {
      h = y.__super__.constructor.apply(this, arguments);
      return h
    }

    y.prototype.events = {
      "click #show-pet-store-icon": "showPetStore",
      "click #show-wordnik-dev-icon": "showWordnikDev",
      "click #explore": "showCustom",
      "keyup #input_baseUrl": "showCustomOnKeyup",
      "keyup #input_apiKey": "showCustomOnKeyup"
    };
    y.prototype.initialize = function () {
    };
    y.prototype.showPetStore = function (A) {
      return this.trigger("update-swagger-ui", {url: "http://petstore.swagger.wordnik.com/api/api-docs"})
    };
    y.prototype.showWordnikDev = function (A) {
      return this.trigger("update-swagger-ui", {url: "http://api.wordnik.com/v4/resources.json"})
    };
    y.prototype.showCustomOnKeyup = function (A) {
      if (A.keyCode === 13) {
        return this.showCustom()
      }
    };
    y.prototype.showCustom = function (A) {
      if (A != null) {
        A.preventDefault()
      }
      return this.trigger("update-swagger-ui", {url: $("#input_baseUrl").val(), apiKey: $("#input_apiKey").val()})
    };
    y.prototype.update = function (B, C, A) {
      if (A == null) {
        A = false
      }
      $("#input_baseUrl").val(B);
      if (A) {
        return this.trigger("update-swagger-ui", {url: B})
      }
    };
    return y
  })(Backbone.View);
  u = (function (y) {
    v(z, y);
    function z() {
      g = z.__super__.constructor.apply(this, arguments);
      return g
    }

    z.prototype.initialize = function () {
    };
    z.prototype.render = function () {
      var C, B, A, D;
      $(this.el).html(Handlebars.templates.main(this.model));
      D = this.model.apisArray;
      for (B = 0, A = D.length; B < A; B++) {
        C = D[B];
        this.addResource(C)
      }
      return this
    };
    z.prototype.addResource = function (B) {
      var A;
      A = new n({model: B, tagName: "li", id: "resource_" + B.name, className: "resource"});
      return $("#resources").append(A.render().el)
    };
    z.prototype.clear = function () {
      return $(this.el).html("")
    };
    return z
  })(Backbone.View);
  n = (function (z) {
    v(y, z);
    function y() {
      f = y.__super__.constructor.apply(this, arguments);
      return f
    }

    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var B, C, A, D;
      $(this.el).html(Handlebars.templates.resource(this.model));
      this.number = 0;
      D = this.model.operationsArray;
      for (C = 0, A = D.length; C < A; C++) {
        B = D[C];
        this.addOperation(B)
      }
      return this
    };
    y.prototype.addOperation = function (A) {
      var B;
      A.number = this.number;
      B = new o({model: A, tagName: "li", className: "endpoint"});
      $(".endpoints", $(this.el)).append(B.render().el);
      return this.number++
    };
    return y
  })(Backbone.View);
  o = (function (z) {
    v(y, z);
    function y() {
      e = y.__super__.constructor.apply(this, arguments);
      return e
    }

    y.prototype.invocationUrl = null;
    y.prototype.events = {
      "submit .sandbox": "submitOperation",
      "click .submit": "submitOperation",
      "click .response_hider": "hideResponse",
      "click .toggleOperation": "toggleOperationContent"
    };
    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var A, P, G, M, K, Q, L, N, J, I, H, O, E, C, F, D, B;
      P = true;
      if (!P) {
        this.model.isReadOnly = true
      }
      $(this.el).html(Handlebars.templates.operation(this.model));
      if (this.model.responseClassSignature && this.model.responseClassSignature !== "string") {
        Q = {sampleJSON: this.model.responseSampleJSON, isParam: false, signature: this.model.responseClassSignature};
        K = new i({model: Q, tagName: "div"});
        $(".model-signature", $(this.el)).append(K.render().el)
      } else {
        $(".model-signature", $(this.el)).html(this.model.type)
      }
      A = {isParam: false};
      A.consumes = this.model.consumes;
      A.produces = this.model.produces;
      F = this.model.parameters;
      for (J = 0, O = F.length; J < O; J++) {
        G = F[J];
        N = G.type || G.dataType;
        if (N.toLowerCase() === "file") {
          if (!A.consumes) {
            log("set content type ");
            A.consumes = "multipart/form-data"
          }
        }
      }
      M = new m({model: A});
      $(".response-content-type", $(this.el)).append(M.render().el);
      D = this.model.parameters;
      for (I = 0, E = D.length; I < E; I++) {
        G = D[I];
        this.addParameter(G, A.consumes)
      }
      B = this.model.responseMessages;
      for (H = 0, C = B.length; H < C; H++) {
        L = B[H];
        this.addStatusCode(L)
      }
      return this
    };
    y.prototype.addParameter = function (C, A) {
      var B;
      C.consumes = A;
      B = new k({model: C, tagName: "tr", readOnly: this.model.isReadOnly});
      return $(".operation-params", $(this.el)).append(B.render().el)
    };
    y.prototype.addStatusCode = function (B) {
      var A;
      A = new p({model: B, tagName: "tr"});
      return $(".operation-status", $(this.el)).append(A.render().el)
    };
    y.prototype.submitOperation = function (O) {
      var Q, G, N, D, I, A, J, M, L, K, P, F, C, H, E, B;
      if (O != null) {
        O.preventDefault()
      }
      G = $(".sandbox", $(this.el));
      Q = true;
      G.find("input.required").each(function () {
        var R = this;
        $(this).removeClass("error");
        if (jQuery.trim($(this).val()) === "") {
          $(this).addClass("error");
          $(this).wiggle({
            callback: function () {
              return $(R).focus()
            }
          });
          return Q = false
        }
      });
      if (Q) {
        D = {};
        A = {parent: this};
        N = false;
        H = G.find("input");
        for (M = 0, P = H.length; M < P; M++) {
          I = H[M];
          if ((I.value != null) && jQuery.trim(I.value).length > 0) {
            D[I.name] = I.value
          }
          if (I.type === "file") {
            N = true
          }
        }
        E = G.find("textarea");
        for (L = 0, F = E.length; L < F; L++) {
          I = E[L];
          if ((I.value != null) && jQuery.trim(I.value).length > 0) {
            D.body = I.value
          }
        }
        B = G.find("select");
        for (K = 0, C = B.length; K < C; K++) {
          I = B[K];
          J = this.getSelectedValue(I);
          if ((J != null) && jQuery.trim(J).length > 0) {
            D[I.name] = J
          }
        }
        A.responseContentType = $("div select[name=responseContentType]", $(this.el)).val();
        A.requestContentType = $("div select[name=parameterContentType]", $(this.el)).val();
        $(".response_throbber", $(this.el)).show();
        if (N) {
          return this.handleFileUpload(D, G)
        } else {
          return this.model["do"](D, A, this.showCompleteStatus, this.showErrorStatus, this)
        }
      }
    };
    y.prototype.success = function (A, B) {
      return B.showCompleteStatus(A)
    };
    y.prototype.handleFileUpload = function (Q, I) {
      var M, H, C, N, L, K, J, G, E, D, P, T, S, R, F, B, A, U, O = this;
      log("it's a file upload");
      F = I.serializeArray();
      for (J = 0, P = F.length; J < P; J++) {
        N = F[J];
        if ((N.value != null) && jQuery.trim(N.value).length > 0) {
          Q[N.name] = N.value
        }
      }
      M = new FormData();
      B = this.model.parameters;
      for (G = 0, T = B.length; G < T; G++) {
        K = B[G];
        if (K.paramType === "form") {
          M.append(K.name, Q[K.name])
        }
      }
      C = {};
      A = this.model.parameters;
      for (E = 0, S = A.length; E < S; E++) {
        K = A[E];
        if (K.paramType === "header") {
          C[K.name] = Q[K.name]
        }
      }
      log(C);
      U = I.find('input[type~="file"]');
      for (D = 0, R = U.length; D < R; D++) {
        H = U[D];
        M.append($(H).attr("name"), H.files[0])
      }
      log(M);
      this.invocationUrl = this.model.supportHeaderParams() ? (C = this.model.getHeaderParams(Q), this.model.urlify(Q, false)) : this.model.urlify(Q, true);
      $(".request_url", $(this.el)).html("<pre>" + this.invocationUrl + "</pre>");
      L = {
        type: this.model.method,
        url: this.invocationUrl,
        headers: C,
        data: M,
        dataType: "json",
        contentType: false,
        processData: false,
        error: function (W, X, V) {
          return O.showErrorStatus(O.wrap(W), O)
        },
        success: function (V) {
          return O.showResponse(V, O)
        },
        complete: function (V) {
          return O.showCompleteStatus(O.wrap(V), O)
        }
      };
      if (window.authorizations) {
        window.authorizations.apply(L)
      }
      jQuery.ajax(L);
      return false
    };
    y.prototype.wrap = function (E) {
      var F, H, A, G, D, C, B;
      H = {};
      F = E.getAllResponseHeaders().split(":");
      for (A = D = 0, C = F.length / 2, B = 2; B > 0 ? D <= C : D >= C; A = D += B) {
        H[F[A]] = F[A + 1]
      }
      G = {};
      G.content = {};
      G.content.data = E.responseText;
      G.headers = H;
      G.request = {};
      G.request.url = this.invocationUrl;
      G.status = E.status;
      return G
    };
    y.prototype.getSelectedValue = function (A) {
      var D, C, F, B, E;
      if (!A.multiple) {
        return A.value
      } else {
        C = [];
        E = A.options;
        for (F = 0, B = E.length; F < B; F++) {
          D = E[F];
          if (D.selected) {
            C.push(D.value)
          }
        }
        if (C.length > 0) {
          return C.join(",")
        } else {
          return null
        }
      }
    };
    y.prototype.hideResponse = function (A) {
      if (A != null) {
        A.preventDefault()
      }
      $(".response", $(this.el)).slideUp();
      return $(".response_hider", $(this.el)).fadeOut()
    };
    y.prototype.showResponse = function (A) {
      var B;
      B = JSON.stringify(A, null, "\t").replace(/\n/g, "<br>");
      return $(".response_body", $(this.el)).html(escape(B))
    };
    y.prototype.showErrorStatus = function (B, A) {
      return A.showStatus(B)
    };
    y.prototype.showCompleteStatus = function (B, A) {
      return A.showStatus(B)
    };
    y.prototype.formatXml = function (H) {
      var D, G, B, I, N, J, C, A, L, M, F, E, K;
      A = /(>)(<)(\/*)/g;
      M = /[ ]*(.*)[ ]+\n/g;
      D = /(<.+>)(.+\n)/g;
      H = H.replace(A, "$1\n$2$3").replace(M, "$1\n").replace(D, "$1\n$2");
      C = 0;
      G = "";
      N = H.split("\n");
      B = 0;
      I = "other";
      L = {
        "single->single": 0,
        "single->closing": -1,
        "single->opening": 0,
        "single->other": 0,
        "closing->single": 0,
        "closing->closing": -1,
        "closing->opening": 0,
        "closing->other": 0,
        "opening->single": 1,
        "opening->closing": 0,
        "opening->opening": 1,
        "opening->other": 1,
        "other->single": 0,
        "other->closing": -1,
        "other->opening": 0,
        "other->other": 0
      };
      F = function (T) {
        var P, O, R, V, S, Q, U;
        Q = {
          single: Boolean(T.match(/<.+\/>/)),
          closing: Boolean(T.match(/<\/.+>/)),
          opening: Boolean(T.match(/<[^!?].*>/))
        };
        S = ((function () {
          var W;
          W = [];
          for (R in Q) {
            U = Q[R];
            if (U) {
              W.push(R)
            }
          }
          return W
        })())[0];
        S = S === void 0 ? "other" : S;
        P = I + "->" + S;
        I = S;
        V = "";
        B += L[P];
        V = ((function () {
          var X, Y, W;
          W = [];
          for (O = X = 0, Y = B; 0 <= Y ? X < Y : X > Y; O = 0 <= Y ? ++X : --X) {
            W.push("  ")
          }
          return W
        })()).join("");
        if (P === "opening->closing") {
          return G = G.substr(0, G.length - 1) + T + "\n"
        } else {
          return G += V + T + "\n"
        }
      };
      for (E = 0, K = N.length; E < K; E++) {
        J = N[E];
        F(J)
      }
      return G
    };
    y.prototype.showStatus = function (A) {
      var D, C, G, F, E, B;
      C = A.data;
      F = A.headers;
      G = F && F["Content-Type"] ? F["Content-Type"].split(";")[0].trim() : null;
      if (!C) {
        D = $("<code />").text("no content");
        E = $('<pre class="json" />').append(D)
      } else {
        if (G === "application/json" || /\+json$/.test(G)) {
          D = $("<code />").text(JSON.stringify(JSON.parse(C), null, "  "));
          E = $('<pre class="json" />').append(D)
        } else {
          if (G === "application/xml" || /\+xml$/.test(G)) {
            D = $("<code />").text(this.formatXml(C));
            E = $('<pre class="xml" />').append(D)
          } else {
            if (G === "text/html") {
              D = $("<code />").html(C);
              E = $('<pre class="xml" />').append(D)
            } else {
              if (/^image\//.test(G)) {
                E = $("<img>").attr("src", A.url)
              } else {
                D = $("<code />").text(C);
                E = $('<pre class="json" />').append(D)
              }
            }
          }
        }
      }
      B = E;
      $(".request_url", $(this.el)).html("<pre>" + A.url + "</pre>");
      $(".response_code", $(this.el)).html("<pre>" + A.status + "</pre>");
      $(".response_body", $(this.el)).html(B);
      $(".response_headers", $(this.el)).html("<pre>" + JSON.stringify(A.headers, null, "  ").replace(/\n/g, "<br>") + "</pre>");
      $(".response", $(this.el)).slideDown();
      $(".response_hider", $(this.el)).show();
      $(".response_throbber", $(this.el)).hide();
      return hljs.highlightBlock($(".response_body", $(this.el))[0])
    };
    y.prototype.toggleOperationContent = function () {
      var A;
      A = $("#" + Docs.escapeResourceName(this.model.resourceName) + "_" + this.model.nickname + "_" + this.model.method + "_" + this.model.number + "_content");
      if (A.is(":visible")) {
        return Docs.collapseOperation(A)
      } else {
        return Docs.expandOperation(A)
      }
    };
    return y
  })(Backbone.View);
  p = (function (z) {
    v(y, z);
    function y() {
      d = y.__super__.constructor.apply(this, arguments);
      return d
    }

    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var A;
      A = this.template();
      $(this.el).html(A(this.model));
      return this
    };
    y.prototype.template = function () {
      return Handlebars.templates.status_code
    };
    return y
  })(Backbone.View);
  k = (function (z) {
    v(y, z);
    function y() {
      b = y.__super__.constructor.apply(this, arguments);
      return b
    }

    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var G, A, C, F, B, H, E, D;
      D = this.model.type || this.model.dataType;
      if (this.model.paramType === "body") {
        this.model.isBody = true
      }
      if (D.toLowerCase() === "file") {
        this.model.isFile = true
      }
      E = this.template();
      $(this.el).html(E(this.model));
      B = {sampleJSON: this.model.sampleJSON, isParam: true, signature: this.model.signature};
      if (this.model.sampleJSON) {
        H = new i({model: B, tagName: "div"});
        $(".model-signature", $(this.el)).append(H.render().el)
      } else {
        $(".model-signature", $(this.el)).html(this.model.signature)
      }
      A = false;
      if (this.model.isBody) {
        A = true
      }
      G = {isParam: A};
      G.consumes = this.model.consumes;
      if (A) {
        C = new l({model: G});
        $(".parameter-content-type", $(this.el)).append(C.render().el)
      } else {
        F = new m({model: G});
        $(".response-content-type", $(this.el)).append(F.render().el)
      }
      return this
    };
    y.prototype.template = function () {
      if (this.model.isList) {
        return Handlebars.templates.param_list
      } else {
        if (this.options.readOnly) {
          if (this.model.required) {
            return Handlebars.templates.param_readonly_required
          } else {
            return Handlebars.templates.param_readonly
          }
        } else {
          if (this.model.required) {
            return Handlebars.templates.param_required
          } else {
            return Handlebars.templates.param
          }
        }
      }
    };
    return y
  })(Backbone.View);
  i = (function (z) {
    v(y, z);
    function y() {
      a = y.__super__.constructor.apply(this, arguments);
      return a
    }

    y.prototype.events = {
      "click a.description-link": "switchToDescription",
      "click a.snippet-link": "switchToSnippet",
      "mousedown .snippet": "snippetToTextArea"
    };
    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var A;
      A = this.template();
      $(this.el).html(A(this.model));
      this.switchToDescription();
      this.isParam = this.model.isParam;
      if (this.isParam) {
        $(".notice", $(this.el)).text("Click to set as parameter value")
      }
      return this
    };
    y.prototype.template = function () {
      return Handlebars.templates.signature
    };
    y.prototype.switchToDescription = function (A) {
      if (A != null) {
        A.preventDefault()
      }
      $(".snippet", $(this.el)).hide();
      $(".description", $(this.el)).show();
      $(".description-link", $(this.el)).addClass("selected");
      return $(".snippet-link", $(this.el)).removeClass("selected")
    };
    y.prototype.switchToSnippet = function (A) {
      if (A != null) {
        A.preventDefault()
      }
      $(".description", $(this.el)).hide();
      $(".snippet", $(this.el)).show();
      $(".snippet-link", $(this.el)).addClass("selected");
      return $(".description-link", $(this.el)).removeClass("selected")
    };
    y.prototype.snippetToTextArea = function (A) {
      var B;
      if (this.isParam) {
        if (A != null) {
          A.preventDefault()
        }
        B = $("textarea", $(this.el.parentNode.parentNode.parentNode));
        if ($.trim(B.val()) === "") {
          return B.val(this.model.sampleJSON)
        }
      }
    };
    return y
  })(Backbone.View);
  j = (function (y) {
    v(z, y);
    function z() {
      x = z.__super__.constructor.apply(this, arguments);
      return x
    }

    z.prototype.initialize = function () {
    };
    z.prototype.render = function () {
      var A;
      A = this.template();
      $(this.el).html(A(this.model));
      $("label[for=contentType]", $(this.el)).text("Response Content Type");
      return this
    };
    z.prototype.template = function () {
      return Handlebars.templates.content_type
    };
    return z
  })(Backbone.View);
  m = (function (y) {
    v(z, y);
    function z() {
      w = z.__super__.constructor.apply(this, arguments);
      return w
    }

    z.prototype.initialize = function () {
    };
    z.prototype.render = function () {
      var A;
      A = this.template();
      $(this.el).html(A(this.model));
      $("label[for=responseContentType]", $(this.el)).text("Response Content Type");
      return this
    };
    z.prototype.template = function () {
      return Handlebars.templates.response_content_type
    };
    return z
  })(Backbone.View);
  l = (function (z) {
    v(y, z);
    function y() {
      c = y.__super__.constructor.apply(this, arguments);
      return c
    }

    y.prototype.initialize = function () {
    };
    y.prototype.render = function () {
      var A;
      A = this.template();
      $(this.el).html(A(this.model));
      $("label[for=parameterContentType]", $(this.el)).text("Parameter content type:");
      return this
    };
    y.prototype.template = function () {
      return Handlebars.templates.parameter_content_type
    };
    return y
  })(Backbone.View)
}).call(this);

<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/YokeRequest.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.cert.X509Certificate;

import com.jetdrone.vertx.yoke.util.Utils;
import io.vertx.core.http.*;
import io.vertx.core.net.SocketAddress;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.MultiMap;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.NetSocket;

import com.jetdrone.vertx.yoke.core.Context;
import com.jetdrone.vertx.yoke.core.YokeCookie;
import com.jetdrone.vertx.yoke.core.YokeFileUpload;
import com.jetdrone.vertx.yoke.store.SessionStore;

/** YokeRequest is an extension to Vert.x *HttpServerRequest* with some helper methods to make it easier to perform common
 * tasks related to web application development.
 */
public class YokeRequest implements HttpServerRequest {

    private static final Comparator<String> ACCEPT_X_COMPARATOR = new Comparator<String>() {
        float getQuality(String s) {
            if (s == null) {
                return 0;
            }

            String[] params = s.split(" *; *");
            for (int i = 1; i < params.length; i++) {
                String[] q = params[1].split(" *= *");
                if ("q".equals(q[0])) {
                    return Float.parseFloat(q[1]);
                }
            }
            return 1;
        }
        @Override
        public int compare(String o1, String o2) {
            float f1 = getQuality(o1);
            float f2 = getQuality(o2);
            if (f1 < f2) {
                return 1;
            }
            if (f1 > f2) {
                return -1;
            }
            return 0;
        }
    };

    // the original request (if extensions need to access it, use the accessor)
    final private HttpServerRequest request;
    // the wrapped response (if extensions need to access it, use the accessor)
    final private YokeResponse response;
    // the request context
    final protected Context context;
    // session data store
    final protected SessionStore store;

    // we can overrride the setMethod
    private HttpMethod method;
    private long bodyLengthLimit = -1;
    // the body is protected so extensions can access the raw object instead of casted versions.
    protected Object body;
    private Map<String, YokeFileUpload> files;
    private Set<YokeCookie> cookies;
    // control flags
    private boolean expectMultiPartCalled = false;

    public YokeRequest(@NotNull final HttpServerRequest request, @NotNull final YokeResponse response, @NotNull final Context context, @NotNull final SessionStore store) {
        this.context = context;
        this.request = request;
        this.method = request.method();
        response.setMethod(this.method);
        this.response = response;
        this.store = store;
    }

    /** Allow getting properties in a generified way.
     *
     * @param name The key to get
     * @return {R} The found object
     */
    @SuppressWarnings("unchecked")
    public <R> R get(@NotNull final String name) {
        // do some conversions for JsonObject/JsonArray
        Object o = context.get(name);

        if (o instanceof Map) {
            return (R) new JsonObject((Map) o);
        }
        if (o instanceof List) {
            return (R) new JsonArray((List) o);
        }
        return (R) o;
    }

    /** Allow getting properties in a generified way and return defaultValue if the key does not exist.
     *
     * @param name The key to get
     * @param defaultValue value returned when the key does not exist
     * @return {R} The found object
     */
    public <R> R get(@NotNull final String name, R defaultValue) {
        if (context.containsKey(name)) {
            return get(name);
        } else {
            return defaultValue;
        }
    }

    /** Allows putting a value into the context
     *
     * @param name the key to store
     * @param value the value to store
     * @return {R} the previous value or null
     */
    @SuppressWarnings("unchecked")
    public <R> R put(@NotNull final String name, R value) {
        if (value == null) {
            return (R) context.remove(name);
        }
        return (R) context.put(name, value);
    }

    /** Allow getting headers in a generified way.
     *
     * @param name The key to get
     * @return The found object
     */
    @Override
    public String getHeader(@NotNull final String name) {
        return headers().get(name);
    }

    @Override
    public String getHeader(CharSequence charSequence) {
        return headers().get(charSequence);
    }

    /** Allow getting headers in a generified way.
     *
     * @param name The key to get
     * @return {List} The list of all found objects
     */
    public List<String> getAllHeaders(@NotNull final String name) {
        return headers().getAll(name);
    }

    /** Allow getting headers in a generified way and return defaultValue if the key does not exist.
     *
     * @param name The key to get
     * @param defaultValue value returned when the key does not exist
     * @return {String} The found object
     */
    public String getHeader(@NotNull final String name, String defaultValue) {
        if (headers().contains(name)) {
            return getHeader(name);
        } else {
            return defaultValue;
        }
    }

    /**
     * Access all request cookies
     * @return Set of cookies
     */
    public Set<YokeCookie> cookies() {
        return cookies;
    }

    /** Allow getting Cookie by name.
     *
     * @param name The key to get
     * @return The found object
     */
    public YokeCookie getCookie(@NotNull final String name) {
        if (cookies != null) {
            for (YokeCookie c : cookies) {
                if (name.equals(c.name())) {
                    return c;
                }
            }
        }
        return null;
    }

    /** Allow getting all Cookie by name.
     *
     * @param name The key to get
     * @return The found objects
     */
    public List<YokeCookie> getAllCookies(@NotNull final String name) {
        List<YokeCookie> foundCookies = new ArrayList<>();
        if (cookies != null) {
            for (YokeCookie c : cookies) {
                if (name.equals(c.name())) {
                    foundCookies.add(c);
                }
            }
        }
        return foundCookies;
    }

    // The original HTTP setMethod for the request. One of GET, PUT, POST, DELETE, TRACE, CONNECT, OPTIONS or HEAD
    public String originalMethod() {
        return request.method().name();
    }

    /** Package level mutator for the overrided setMethod
     * @param newMethod new setMethod GET, PUT, POST, DELETE, TRACE, CONNECT, OPTIONS or HEAD
     */
    void setMethod(@NotNull final HttpMethod newMethod) {
        this.method = newMethod;
        response.setMethod(this.method);
    }

    // Package level mutator for the bodyLength
    void setBodyLengthLimit(long limit) {
        bodyLengthLimit = limit;
    }

    // Holds the maximum allowed length for the setBody data. -1 for unlimited
    public long bodyLengthLimit() {
        return bodyLengthLimit;
    }

    /** Returns true if this request has setBody
     *
     * @return {Boolean} true if content-length or transfer-encoding is present
     */
    public boolean hasBody() {
        MultiMap headers = headers();
        return headers.contains("transfer-encoding") || headers.contains("content-length");
    }

    /** Returns the content length of this request setBody or -1 if header is not present.
     */
    public long contentLength() {
        String contentLengthHeader = headers().get("content-length");
        if (contentLengthHeader != null) {
            return Long.parseLong(contentLengthHeader);
        } else {
            return -1;
        }
    }

    /** The request body and eventually a parsed version of it in json or map */
    @SuppressWarnings("unchecked")
    public <V> V body() {
        if (body != null) {
            if (body instanceof Map) {
                return (V) new JsonObject((Map) body);
            }
            if (body instanceof List) {
                return (V) new JsonArray((List) body);
            }
        }

        return (V) body;
    }

    /** Mutator for the request setBody
     * The request setBody and eventually a parsed version of it in json or map*/
    void setBody(Object body) {
        this.body = body;
    }

    /** The uploaded setFiles */
    public Map<String, YokeFileUpload> files() {
        return files;
    }

    /** Get an uploaded file */
    public YokeFileUpload getFile(@NotNull final String name) {
        if (files == null) {
            return null;
        }

        return files.get(name);
    }

    /** The uploaded setFiles */
    void setFiles(Map<String, YokeFileUpload> files) {
        this.files = files;
    }

    /** Cookies */
    void setCookies(Set<YokeCookie> cookies) {
        this.cookies = cookies;
    }

    // Session management

    /** Destroys a session from the request context and also from the storage engine.
     */
    public void destroySession() {
    	JsonObject session = get("session");
        if (session == null) {
            return;
        }

        String sessionId = session.getString("id");
        // remove from the context
        put("session", null);

        if (sessionId == null) {
            return;
        }

        store.destroy(sessionId, new Handler<Object>() {
            @Override
            public void handle(Object error) {
                if (error != null) {
                    // TODO: better handling of errors
                    System.err.println(error);
                }
            }
        });
    }

    /** Loads a session given its session id and sets the "session" property in the request context.
     * @param sessionId the id to load
     * @param handler the success/complete handler
     */
    public void loadSession(final String sessionId, final Handler<Object> handler) {
        if (sessionId == null) {
            handler.handle(null);
            return;
        }

        store.get(sessionId, new Handler<JsonObject>() {
            @Override
            public void handle(JsonObject session) {
                if (session != null) {
                    put("session", session);
                }

                response().headersHandler(new Handler<Void>() {
                    @Override
                    public void handle(Void event) {
                        int responseStatus = response().getStatusCode();
                        // Only save on success and redirect status codes
                        if (responseStatus >= 200 && responseStatus < 400) {
                        	JsonObject session = get("session");
                            if (session != null) {
                                store.set(sessionId, session, new Handler<Object>() {
                                    @Override
                                    public void handle(Object error) {
                                        if (error != null) {
                                            // TODO: better handling of errors
                                            System.err.println(error);
                                        }
                                    }
                                });
                            }
                        }
                    }
                });

                handler.handle(null);
            }
        });
    }

    /** Create a new Session and store it with the underlying storage.
     * Internally create a entry in the request context under the name "session" and add a end handler to save that
     * object once the execution is terminated.
     *
     * @return {JsonObject} session
     */
    public JsonObject createSession() {
        final String sessionId = UUID.randomUUID().toString();
        return createSession(sessionId);
    }


    /** Create a new Session with custom Id and store it with the underlying storage.
     * Internally create a entry in the request context under the name "session" and add a end handler to save that
     * object once the execution is terminated. Custom session id could be used with external auth provider like mod-auth-mgr.
     *
     * @param sessionId custom session id
     * @return {JsonObject} session
     */
    public JsonObject createSession(@NotNull final String sessionId) {
        final JsonObject session = new JsonObject().put("id", sessionId);

        put("session", session);

        response().headersHandler(new Handler<Void>() {
            @Override
            public void handle(Void event) {
                int responseStatus = response().getStatusCode();
                // Only save on success and redirect status codes
                if (responseStatus >= 200 && responseStatus < 400) {
                	JsonObject session = get("session");
                    if (session != null) {
                        store.set(sessionId, session, new Handler<Object>() {
                            @Override
                            public void handle(Object error) {
                                if (error != null) {
                                    // TODO: better handling of errors
                                    System.err.println(error);
                                }
                            }
                        });
                    }
                }
            }
        });

        return session;
    }

    private static String[] splitMime(@NotNull String mime) {
        // find any ; e.g.: "application/json;q=0.8"
        int space = mime.indexOf(';');

        if (space != -1) {
            mime = mime.substring(0, space);
        }

        String[] parts = mime.split("/");

        if (parts.length < 2) {
            return new String[] {
                    parts[0],
                    "*"
            };
        }

        return parts;
    }

    /** Check if the given type(s) is acceptable, returning the best match when true, otherwise null, in which
     * case you should respond with 406 "Not Acceptable".
     *
     * The type value must be a single mime type string such as "application/json" and is validated by checking
     * if the request string starts with it.
     */
    public String accepts(@NotNull final String... types) {
        String accept = getHeader("Accept");
        // accept anything when accept is not present
        if (accept == null) {
            return types[0];
        }

        // parse
        String[] acceptTypes = accept.split(" *, *");
        // sort on quality
        Arrays.sort(acceptTypes, ACCEPT_X_COMPARATOR);

        for (String senderAccept : acceptTypes) {
            String[] sAccept = splitMime(senderAccept);

            for (String appAccept : types) {
                String[] aAccept = splitMime(appAccept);

                if (
                        (sAccept[0].equals(aAccept[0]) || "*".equals(sAccept[0]) || "*".equals(aAccept[0])) &&
                        (sAccept[1].equals(aAccept[1]) || "*".equals(sAccept[1]) || "*".equals(aAccept[1]))) {
                    return senderAccept;
                }
            }
        }

        return null;
    }

    /** Returns the array of accept-? ordered by quality.
     */
    public List<String> sortedHeader(@NotNull final String header) {
        String accept = getHeader(header);
        // accept anything when accept is not present
        if (accept == null) {
            return Collections.emptyList();
        }

        // parse
        String[] items = accept.split(" *, *");
        // sort on quality
        Arrays.sort(items, ACCEPT_X_COMPARATOR);

        List<String> list = new ArrayList<>(items.length);

        for (String item : items) {
            // find any ; e.g.: "application/json;q=0.8"
            int space = item.indexOf(';');

            if (space != -1) {
                list.add(item.substring(0, space));
            } else {
                list.add(item);
            }
        }

        return list;
    }

    /** Check if the incoming request contains the "Content-Type"
     * header field, and it contains the give mime `type`.
     *
     * Examples:
     *
     * // With Content-Type: text/html; charset=utf-8
     * req.is('html');
     * req.is('text/html');
     * req.is('text/*');
     * // returns true
     *
     * // When Content-Type is application/json
     * req.is('json');
     * req.is('application/json');
     * req.is('application/*');
     * // returns true
     *
     * req.is('html');
     * // returns false
     *
     * @param type content type
     * @return true if content type is of type
     */
    public boolean is(@NotNull String type) {
        String ct = getHeader("Content-Type");
        if (ct == null) {
            return false;
        }
        // get the content type only (exclude charset)
        ct = ct.split(";")[0];

        // if we received an incomplete CT
        if (type.indexOf('/') == -1) {
            // when the content is incomplete we assume */type, e.g.:
            // json -> */json
            type = "*/" + type;
        }

        // process wildcards
        if (type.contains("*")) {
            String[] parts = type.split("/");
            String[] ctParts = ct.split("/");
            return "*".equals(parts[0]) && parts[1].equals(ctParts[1]) || "*".equals(parts[1]) && parts[0].equals(ctParts[0]);

        }

        return ct.contains(type);
    }

    /** Returns the ip address of the client, when trust-proxy is true (default) then first look into X-Forward-For
     * Header */
    public String ip() {
        Boolean trustProxy = (Boolean) context.get("trust-proxy");
        if (trustProxy != null && trustProxy) {
            String xForwardFor = getHeader("x-forward-for");
            if (xForwardFor != null) {
                String[] ips = xForwardFor.split(" *, *");
                if (ips.length > 0) {
                    return ips[0];
                }
            }
        }

        return request.remoteAddress().host();
    }

    /** Allow getting parameters in a generified way.
     *
     * @param name The key to get
     * @return {String} The found object
     */
    @Override
    public String getParam(@NotNull final String name) {
        return request.getParam(name);
    }

    /** Allow getting parameters in a generified way and return defaultValue if the key does not exist.
     *
     * @param name The key to get
     * @param defaultValue value returned when the key does not exist
     * @return {String} The found object
     */
    public String getParam(@NotNull final String name, String defaultValue) {
        String value = getParam(name);

        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /** Allow getting parameters in a generified way.
     *
     * @param name The key to get
     * @return {List} The found object
     */
    public List<String> getParameterList(@NotNull final String name) {
        return params().getAll(name);
    }

    /** Allow getting form parameters in a generified way.
     *
     * @param name The key to get
     * @return {String} The found object
     */
    @Override
    public String getFormAttribute(@NotNull final String name) {
        return request.getFormAttribute(name);
    }

    @Override
    public ServerWebSocket upgrade() {
        return request.upgrade();
    }

    @Override
    public boolean isEnded() {
        return request.isEnded();
    }

    /** Allow getting form parameters in a generified way and return defaultValue if the key does not exist.
     *
     * @param name The key to get
     * @param defaultValue value returned when the key does not exist
     * @return {String} The found object
     */
    public String getFormAttribute(@NotNull final String name, String defaultValue) {
        String value = request.formAttributes().get(name);

        if (value == null) {
            return defaultValue;
        }

        return value;
    }

    /** Allow getting form parameters in a generified way.
     *
     * @param name The key to get
     * @return {List} The found object
     */
    public List<String> getFormParameterList(@NotNull final String name) {
        return request.formAttributes().getAll(name);
    }

    /** Return the real request */
    public HttpServerRequest vertxHttpServerRequest() {
        return request;
    }

    /** Read the default locale for this request
     *
     * @return Locale (best match if more than one)
     */
    public Locale locale() {
        String languages = getHeader("Accept-Language");
        if (languages != null) {
            // parse
            String[] acceptLanguages = languages.split(" *, *");
            // sort on quality
            Arrays.sort(acceptLanguages, ACCEPT_X_COMPARATOR);

            String bestLanguage = acceptLanguages[0];

            int idx = bestLanguage.indexOf(';');

            if (idx != -1) {
                bestLanguage = bestLanguage.substring(0, idx).trim();
            }

            String[] parts = bestLanguage.split("_|-");
            switch (parts.length) {
                case 3: return new Locale(parts[0], parts[1], parts[2]);
                case 2: return new Locale(parts[0], parts[1]);
                case 1: return new Locale(parts[0]);
            }
        }

        return Locale.getDefault();
    }

    @Override
    public HttpVersion version() {
        return request.version();
    }

    @Override
    public HttpMethod method() {
        if (method != null) {
            return method;
        }
        return request.method();
    }

    @Override
    public boolean isSSL() {
        return request.isSSL();
    }

    @Override
    public String uri() {
        return request.uri();
    }

    @Override
    public String path() {
        return request.path();
    }

    private String cachedNormalizedPath = null;

    public String normalizedPath() {
        if (cachedNormalizedPath != null) {
            return cachedNormalizedPath;
        }

        String path = Utils.decodeURIComponent(request.path());

        // path should start with / so we should ignore it
        if (path.charAt(0) == '/') {
            path = path.substring(1);
        } else {
            return null;
        }

        String[] parts = path.split("/");
        Deque<String> resolved = new LinkedList<>();

        for (String p : parts) {
            if ("".equals(p)) {
                continue;
            }

            if (".".equals(p)) {
                continue;
            }

            if ("..".equals(p)) {
                // if there is no entry the path is trying to jump outside the root
                if (resolved.pollLast() == null) {
                    return null;
                }
                continue;
            }

            resolved.offerLast(p);
        }

        if (resolved.size() == 0) {
            cachedNormalizedPath = "/";
            return cachedNormalizedPath;
        }

        // re assemble the path
        StringBuilder sb = new StringBuilder();

        for (String s : resolved) {
            sb.append("/");
            sb.append(s);
        }

        cachedNormalizedPath = sb.toString();
        return cachedNormalizedPath;
    }

    @Override
    public String query() {
        return request.query();
    }

    @Override
    public YokeResponse response() {
        return response;
    }

    @Override
    public MultiMap headers() {
        return request.headers();
    }

    @Override
    public MultiMap params() {
        return request.params();
    }

    @Override
    public SocketAddress remoteAddress() {
        return request.remoteAddress();
    }

    @Override
    public X509Certificate[] peerCertificateChain() throws SSLPeerUnverifiedException {
        return request.peerCertificateChain();
    }

    @Override
    public String absoluteURI() {
        return request.absoluteURI();
    }

    @Override
    public YokeRequest bodyHandler(Handler<Buffer> bodyHandler) {
        request.bodyHandler(bodyHandler);
        return this;
    }

    @Override
    public NetSocket netSocket() {
        return request.netSocket();
    }

    @Override
    public YokeRequest setExpectMultipart(final boolean expect) {
        // if we expect
        if (expect) {
            // then only call it once
            if (!expectMultiPartCalled) {
                expectMultiPartCalled = true;
                request.setExpectMultipart(true);
            }
        } else {
            // if we don't expect reset even if we were called before
            expectMultiPartCalled = false;
            request.setExpectMultipart(false);
        }
        return this;
    }

    @Override
    public boolean isExpectMultipart() {
        return request.isExpectMultipart();
    }

    @Override
    public YokeRequest uploadHandler(Handler<HttpServerFileUpload> uploadHandler) {
        request.uploadHandler(uploadHandler);
        return this;
    }

    @Override
    public MultiMap formAttributes() {
        return request.formAttributes();
    }

    @Override
    public YokeRequest handler(Handler<Buffer> handler) {
        request.handler(handler);
        return this;
    }

    @Override
    public HttpServerRequest pause() {
        request.pause();
        return this;
    }

    @Override
    public YokeRequest resume() {
        request.resume();
        return this;
    }

    @Override
    public YokeRequest endHandler(Handler<Void> endHandler) {
        request.endHandler(endHandler);
        return this;
    }

    @Override
    public YokeRequest exceptionHandler(Handler<Throwable> handler) {
        request.exceptionHandler(handler);
        return this;
    }

    @Override
    public SocketAddress localAddress() {
        return request.localAddress();
    }
}

<|start_filename|>middleware/swagger/src/main/java/com/jetdrone/vertx/yoke/middleware/Swagger.java<|end_filename|>
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.annotations.Processor;
import com.jetdrone.vertx.yoke.annotations.processors.SwaggerProcessor;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

// TODO: add api_key validator
public class Swagger {

    static {
        Processor.registerProcessor(SwaggerProcessor.class);
    }

    public static class Resource {

        final String path;
        final String description;

        JsonArray produces;
        JsonArray consumes;

        JsonObject models = new JsonObject();
        JsonObject apis = new JsonObject();

        Resource(String path, String description) {
            this.path = path;
            this.description = description;
        }

        private JsonObject getApi(String path) {
            JsonObject api = apis.getJsonObject(path);
            if (api == null) {
                api = new JsonObject()
                        .put("path", path)
                        .put("operations", new JsonArray());

                apis.put(path, api);
            }
            return api;
        }

        public Resource produces(String... mimes) {
            produces = new JsonArray();
            for (String mime : mimes) {
                if (!produces.contains(mime)) {
                    produces.add(mime);
                }
            }

            return this;
        }

        public Resource consumes(String... mimes) {
            consumes = new JsonArray();
            for (String mime : mimes) {
                if (!consumes.contains(mime)) {
                    consumes.add(mime);
                }
            }

            return this;
        }

        public Resource all(String path, JsonObject operation) {
            all(path, "", operation);
            return this;
        }
        public Resource all(String path, String summary, JsonObject operation) {
            addOperation("GET", path, summary, operation);
            addOperation("PUT", path, summary, operation);
            addOperation("POST", path, summary, operation);
            addOperation("DELETE", path, summary, operation);
            addOperation("OPTIONS", path, summary, operation);
            addOperation("HEAD", path, summary, operation);
            addOperation("TRACE", path, summary, operation);
            addOperation("CONNECT", path, summary, operation);
            addOperation("PATCH", path, summary, operation);
            return this;
        }
        public Resource get(String path, JsonObject operation) {
            get(path, "", operation);
            return this;
        }
        public Resource get(String path, String summary, JsonObject operation) {
            addOperation("GET", path, summary, operation);
            return this;
        }
        public Resource post(String path, JsonObject operation) {
            post(path, "", operation);
            return this;
        }
        public Resource post(String path, String summary, JsonObject operation) {
            addOperation("POST", path, summary, operation);
            return this;
        }
        public Resource put(String path, JsonObject operation) {
            put(path, "", operation);
            return this;
        }
        public Resource put(String path, String summary, JsonObject operation) {
            addOperation("PUT", path, summary, operation);
            return this;
        }
        public Resource delete(String path, JsonObject operation) {
            delete(path, "", operation);
            return this;
        }
        public Resource delete(String path, String summary, JsonObject operation) {
            addOperation("DELETE", path, summary, operation);
            return this;
        }
        public Resource options(String path, JsonObject operation) {
            options(path, "", operation);
            return this;
        }
        public Resource options(String path, String summary, JsonObject operation) {
            addOperation("OPTIONS", path, summary, operation);
            return this;
        }
        public Resource head(String path, JsonObject operation) {
            head(path, "", operation);
            return this;
        }
        public Resource head(String path, String summary, JsonObject operation) {
            addOperation("HEAD", path, summary, operation);
            return this;
        }
        public Resource trace(String path, JsonObject operation) {
            trace(path, "", operation);
            return this;
        }
        public Resource trace(String path, String summary, JsonObject operation) {
            addOperation("TRACE", path, summary, operation);
            return this;
        }
        public Resource connect(String path, JsonObject operation) {
            connect(path, "", operation);
            return this;
        }
        public Resource connect(String path, String summary, JsonObject operation) {
            addOperation("CONNECT", path, summary, operation);
            return this;
        }
        public Resource patch(String path, JsonObject operation) {
            patch(path, "", operation);
            return this;
        }
        public Resource patch(String path, String summary, JsonObject operation) {
            addOperation("PATCH", path, summary, operation);
            return this;
        }

        public Resource addModel(String id, JsonObject model) {
            model.put("id", id);
            models.put(id, model);
            return this;
        }

        protected void addOperation(String verb, String path, String summary, JsonObject operation) {
            // translate from yoke format to swagger format
            Matcher m =  Pattern.compile(":([A-Za-z][A-Za-z0-9_]*)").matcher(path);
            StringBuffer sb = new StringBuffer();
            while (m.find()) {
                m.appendReplacement(sb, "\\{$1\\}");
            }
            m.appendTail(sb);

            JsonObject op = new JsonObject()
                    .put("method", verb)
                    .put("summary", summary);

            op.mergeIn(operation);

            JsonObject api = getApi(sb.toString());
            api.getJsonArray("operations").add(op);
        }
    }

    private final List<Resource> resources = new ArrayList<>();

    private final Router router;
    private final String prefix;
    private final String apiVersion;

    private JsonObject info;
    private JsonObject authorizations;

    public Swagger(final Router router, final String apiVersion) {
        this(router, "/", apiVersion);
    }

    public Swagger(final Router router, final String prefix, final String apiVersion) {
        this.router = router;
        this.apiVersion = apiVersion;

        if (prefix.endsWith("/")) {
            this.prefix = prefix + "api-docs";
        } else {
            this.prefix = prefix + "/api-docs";
        }

        this.router.get(this.prefix, new Middleware() {
            @Override
            public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
                JsonObject result = new JsonObject()
                        .put("apiVersion", apiVersion)
                        .put("swaggerVersion", "1.2");

                JsonArray apis = new JsonArray();
                result.put("apis", apis);

                for (Resource r : resources) {
                    apis.add(new JsonObject()
                            .put("path", r.path)
                            .put("description", r.description));
                }

                if (authorizations != null) {
                    result.put("authorizations", authorizations);
                }

                result.put("info", info);

                request.response().end(result);
            }
        });
    }

    public Swagger setInfo(JsonObject info) {
        this.info = info;
        return this;
    }

    public Swagger setAuthorizations(JsonObject authorizations) {
        this.authorizations = authorizations;
        return this;
    }

    protected Resource createSwaggerResource(final String path, final String description) {
        // verify if already present
        for (Resource res : resources) {
            if (res.path.equals(path)) {
                return res;
            }
        }

        final Resource resource = new Resource(path, description);
        resources.add(resource);

        router.get(prefix + path, new Middleware() {
            @Override
            public void handle(@NotNull YokeRequest request, @NotNull Handler<Object> next) {
                JsonObject result = new JsonObject()
                        .put("apiVersion", apiVersion)
                        .put("swaggerVersion", "1.2")
                        .put("basePath", "/")
                        .put("resourcePath", path);

                if (resource.produces != null) {
                    result.put("produces", resource.produces);
                }

                if (resource.consumes != null) {
                    result.put("consumes", resource.consumes);
                }

                JsonArray apis = new JsonArray();
                result.put("apis", apis);

                for (String key : resource.apis.fieldNames()) {
                    apis.add(resource.apis.getValue(key));
                }
                result.put("models", resource.models);
                request.response().end(result);
            }
        });

        return resource;
    }

    public Resource createResource(final String path) {
        return createResource(path, "");
    }

    public Resource createResource(final String path, final String description) {

        final String normalizedPath;

        if (path.charAt(0) != '/') {
            normalizedPath = "/" + path;
        } else {
            normalizedPath = path;
        }

        return createSwaggerResource(normalizedPath, description);
    }

    public static Swagger from(final Router router, final String version, final Object... objs) {
        final Swagger swagger = new Swagger(router, version);
        from(swagger, objs);

        return swagger;
    }

    /**
     * Builds a Swagger from an annotated Java Object
     */
    public static Swagger from(final Swagger router, final Object... objs) {
        for (Object o : objs) {
            Processor.process(router, o);
        }

        return router;
    }
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/IMiddleware.java<|end_filename|>
package com.jetdrone.vertx.yoke;

import com.jetdrone.vertx.yoke.middleware.YokeRequest;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

public interface IMiddleware {

    /**
     * Handles a request that is inside the chain.
     *
     * Example that always returns Hello:
     * <pre>
     * class HelloMiddleware extends Middleware {
     *   public void handle(YokeRequest request, Handler&lt;Object&gt; next) {
     *     request.response.end("Hello");
     *   }
     * }
     * </pre>
     *
     * Example that always raises an internal server error:
     * <pre>
     * class HelloMiddleware extends Middleware {
     *   public void handle(YokeRequest request, Handler&lt;Object&gt; next) {
     *     next.handle("Something went wrong!");
     *   }
     * }
     * </pre>
     *
     * Example that passes the control to the next middleware:
     * <pre>
     * class HelloMiddleware extends Middleware {
     *   public void handle(YokeRequest request, Handler&lt;Object&gt; next) {
     *     // when the error is null, then the chain will execute
     *     // the next Middleware until the chain is complete,
     *     // when that happens a 404 error is returned since no
     *     // middleware was found that could handle the request.
     *     next.handle(null);
     *   }
     * }
     * </pre>
     *
     * @param request A YokeRequest which in practice is a extended HttpServerRequest
     * @param next    The callback to inform that the next middleware in the chain should be used. A value different from
     *                null represents an error and in that case the error handler middleware will be executed.
     */
    void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next);
}


<|start_filename|>framework/src/main/java/com/jetdrone/vertx/yoke/middleware/ResponseTime.java<|end_filename|>
/**
 * Copyright 2011-2014 the original author or authors.
 */
package com.jetdrone.vertx.yoke.middleware;

import com.jetdrone.vertx.yoke.Middleware;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;

/** # ResponseTime
 *
 * Adds the ```x-response-time``` header displaying the response duration in milliseconds.
 */
public class ResponseTime extends Middleware {
    @Override
    public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {

        final long start = System.currentTimeMillis();
        final YokeResponse response = request.response();

        response.headersHandler(new Handler<Void>() {
            @Override
            public void handle(Void event) {
                long duration = System.currentTimeMillis() - start;
                response.putHeader("x-response-time", duration + "ms");
            }
        });

        next.handle(null);
    }
}
