text:
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <mruby.h>
#include <mruby/proc.h>
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/compile.h>
#include <mruby/error.h>
#include <mruby/hash.h>
#include <mruby/opcode.h>
#include <mruby/string.h>
#include <mruby/throw.h>
#include <mruby/variable.h>
#include <mruby_input_stream.h>
#include "h2o.h"
#include "h2o/mruby_.h"
#include "mruby/embedded.c.h"

#define STATUS_FALLTHRU 399
#define FALLTHRU_SET_PREFIX "x-fallthru-set-"

#define FREEZE_STRING(v) MRB_SET_FROZEN_FLAG(mrb_obj_ptr(v))

void h2o_mruby__abort_exc(mrb_state *mrb, const char *mess, const char *file, int line)
{
    fprintf(stderr, "%s at file: \"%s\", line %d: %s\n", mess, file, line, RSTRING_PTR(mrb_inspect(mrb, mrb_obj_value(mrb->exc))));
    abort();
}

mrb_value h2o_mruby__new_str(mrb_state *mrb, const char *s, size_t len, int is_static, const char *file, int line)
{
    if (mrb->exc != NULL)
        h2o_mruby__abort_exc(mrb, "h2o_mruby_new_str:precondition failure", file, line);
    mrb_value ret = is_static ? mrb_str_new_static(mrb, s, len) : mrb_str_new(mrb, s, len);
    if (mrb->exc != NULL)
        h2o_mruby__abort_exc(mrb, "h2o_mruby_new_str:failed to create string", file, line);
    return ret;
}

static void on_gc_dispose_generator(mrb_state *mrb, void *_generator)
{
    h2o_mruby_generator_t *generator = _generator;
    if (generator == NULL)
        return;
    generator->refs.generator = mrb_nil_value();
}

static void on_gc_dispose_error_stream(mrb_state *mrb, void *_error_stream)
{
    h2o_mruby_error_stream_t *error_stream = _error_stream;
    if (error_stream == NULL)
        return;
    if (error_stream->generator != NULL) {
        error_stream->generator->error_stream = NULL;
        error_stream->generator->refs.error_stream = mrb_nil_value();
    }
    free(error_stream);
}

const static struct mrb_data_type generator_type = {"generator", on_gc_dispose_generator};
const static struct mrb_data_type error_stream_type = {"error_stream", on_gc_dispose_error_stream};

h2o_mruby_generator_t *h2o_mruby_get_generator(mrb_state *mrb, mrb_value obj)
{
    h2o_mruby_generator_t *generator = mrb_data_check_get_ptr(mrb, obj, &generator_type);
    return generator;
}

h2o_mruby_error_stream_t *h2o_mruby_get_error_stream(mrb_state *mrb, mrb_value obj)
{
    h2o_mruby_error_stream_t *error_stream = mrb_data_check_get_ptr(mrb, obj, &error_stream_type);
    return error_stream;
}

void h2o_mruby_setup_globals(mrb_state *mrb)
{
    const char *root = getenv("H2O_ROOT");
    if (root == NULL)
        root = H2O_TO_STR(H2O_ROOT);
    mrb_gv_set(mrb, mrb_intern_lit(mrb, "$H2O_ROOT"), h2o_mruby_new_str(mrb, root, strlen(root)));

    h2o_mruby_eval_expr(mrb, "$LOAD_PATH << \"#{$H2O_ROOT}/share/h2o/mruby\"");
    h2o_mruby_assert(mrb);

    /* require core modules and include built-in libraries */
    h2o_mruby_eval_expr(mrb, "require \"#{$H2O_ROOT}/share/h2o/mruby/preloads.rb\"");
    if (mrb->exc != NULL) {
        fprintf(stderr, "an error occurred while loading %s/%s: %s\n", root, "share/h2o/mruby/preloads.rb",
                RSTRING_PTR(mrb_inspect(mrb, mrb_obj_value(mrb->exc))));
        if (mrb_obj_is_instance_of(mrb, mrb_obj_value(mrb->exc), mrb_class_get(mrb, "LoadError"))) {
            fprintf(stderr, "Did you forget to run `make install`?\n");
        }
        abort();
    }
}

mrb_value h2o_mruby_to_str(mrb_state *mrb, mrb_value v)
{
    if (!mrb_string_p(v))
        H2O_MRUBY_EXEC_GUARD({ v = mrb_str_to_str(mrb, v); });
    return v;
}

mrb_value h2o_mruby_to_int(mrb_state *mrb, mrb_value v)
{
    H2O_MRUBY_EXEC_GUARD({ v = mrb_Integer(mrb, v); });
    return v;
}

mrb_value h2o_mruby_eval_expr(mrb_state *mrb, const char *expr)
{
    return mrb_funcall(mrb, mrb_top_self(mrb), "eval", 1, mrb_str_new_cstr(mrb, expr));
}

mrb_value h2o_mruby_eval_expr_location(mrb_state *mrb, const char *expr, const char *path, const int lineno)
{
    return mrb_funcall(mrb, mrb_top_self(mrb), "eval", 4, mrb_str_new_cstr(mrb, expr), mrb_nil_value(), mrb_str_new_cstr(mrb, path),
                       mrb_fixnum_value(lineno));
}

void h2o_mruby_define_callback(mrb_state *mrb, const char *name, h2o_mruby_callback_t callback)
{
    h2o_mruby_shared_context_t *shared_ctx = mrb->ud;
    h2o_vector_reserve(NULL, &shared_ctx->callbacks, shared_ctx->callbacks.size + 1);
    shared_ctx->callbacks.entries[shared_ctx->callbacks.size++] = callback;

    mrb_value args[2];
    args[0] = mrb_str_new_cstr(mrb, name);
    args[1] = mrb_fixnum_value(-(int)shared_ctx->callbacks.size);
    mrb_funcall_argv(mrb, mrb_top_self(mrb), mrb_intern_lit(mrb, "_h2o_define_callback"), 2, args);

    if (mrb->exc != NULL) {
        fprintf(stderr, "failed to define mruby function: %s\n", name);
        h2o_mruby_assert(mrb);
    }
}

mrb_value h2o_mruby_create_data_instance(mrb_state *mrb, mrb_value class_obj, void *ptr, const mrb_data_type *type)
{
    struct RClass *klass = mrb_class_ptr(class_obj);
    struct RData *data = mrb_data_object_alloc(mrb, klass, ptr, type);
    return mrb_obj_value(data);
}

struct RProc *h2o_mruby_compile_code(mrb_state *mrb, h2o_mruby_config_vars_t *config, char *errbuf)
{
    mrbc_context *cxt;
    struct mrb_parser_state *parser;
    struct RProc *proc = NULL;

    /* parse */
    if ((cxt = mrbc_context_new(mrb)) == NULL) {
        fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME);
        abort();
    }
    if (config->path != NULL)
        mrbc_filename(mrb, cxt, config->path);
    cxt->capture_errors = 1;
    cxt->lineno = config->lineno;
    if ((parser = mrb_parse_nstring(mrb, config->source.base, (int)config->source.len, cxt)) == NULL) {
        fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME);
        abort();
    }
    /* return erro if errbuf is supplied, or abort */
    if (parser->nerr != 0) {
        if (errbuf == NULL) {
            fprintf(stderr, "%s: internal error (unexpected state)\n", H2O_MRUBY_MODULE_NAME);
            abort();
        }
        snprintf(errbuf, 256, "line %d:%s", parser->error_buffer[0].lineno, parser->error_buffer[0].message);
        strcat(errbuf, "\n\n");
        if (h2o_str_at_position(errbuf + strlen(errbuf), config->source.base, config->source.len,
                                parser->error_buffer[0].lineno - config->lineno + 1, parser->error_buffer[0].column) != 0) {
            /* remove trailing "\n\n" in case we failed to append the source code at the error location */
            errbuf[strlen(errbuf) - 2] = '\0';
        }
        goto Exit;
    }
    /* generate code */
    if ((proc = mrb_generate_code(mrb, parser)) == NULL) {
        fprintf(stderr, "%s: internal error (mrb_generate_code failed)\n", H2O_MRUBY_MODULE_NAME);
        abort();
    }

Exit:
    mrb_parser_free(parser);
    mrbc_context_free(mrb, cxt);
    return proc;
}

static h2o_iovec_t convert_header_name_to_env(h2o_mem_pool_t *pool, const char *name, size_t len)
{
#define KEY_PREFIX "HTTP_"
#define KEY_PREFIX_LEN (sizeof(KEY_PREFIX) - 1)

    h2o_iovec_t ret;

    ret.len = len + KEY_PREFIX_LEN;
    ret.base = h2o_mem_alloc_pool(pool, char, ret.len);

    memcpy(ret.base, KEY_PREFIX, KEY_PREFIX_LEN);

    char *d = ret.base + KEY_PREFIX_LEN;
    for (; len != 0; ++name, --len)
        *d++ = *name == '-' ? '_' : h2o_toupper(*name);

    return ret;

#undef KEY_PREFIX
#undef KEY_PREFIX_LEN
}

static int handle_early_hints_header(h2o_mruby_shared_context_t *shared_ctx, h2o_iovec_t *name, h2o_iovec_t value, void *_req)
{
    h2o_req_t *req = _req;
    h2o_add_header_by_str(&req->pool, &req->res.headers, name->base, name->len, 1, NULL, value.base, value.len);
    return 0;
}

mrb_value send_early_hints_proc(mrb_state *mrb, mrb_value self)
{
    mrb_value headers;
    mrb_get_args(mrb, "H", &headers);

    h2o_mruby_generator_t *generator = h2o_mruby_get_generator(mrb, mrb_proc_cfunc_env_get(mrb, 0));
    if (generator == NULL)
        return mrb_nil_value();

    if (h2o_mruby_iterate_rack_headers(mrb->ud, headers, handle_early_hints_header, generator->req) == -1)
        mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
    generator->req->res.status = 103;
    h2o_send_informational(generator->req);

    return mrb_nil_value();
}

static mrb_value build_constants(mrb_state *mrb, const char *server_name, size_t server_name_len)
{
    mrb_value ary = mrb_ary_new_capa(mrb, H2O_MRUBY_NUM_CONSTANTS);
    mrb_int i;

    int gc_arena = mrb_gc_arena_save(mrb);

    {
        h2o_mem_pool_t pool;
        h2o_mem_init_pool(&pool);
        for (i = 0; i != H2O_MAX_TOKENS; ++i) {
            const h2o_token_t *token = h2o__tokens + i;
            if (token->buf.len == 0)
                continue;
            mrb_value lit = h2o_mruby_new_str(mrb, token->buf.base, token->buf.len);
            FREEZE_STRING(lit);
            mrb_ary_set(mrb, ary, i, lit);
        }
        for (; i != H2O_MAX_TOKENS * 2; ++i) {
            const h2o_token_t *token = h2o__tokens + i - H2O_MAX_TOKENS;
            mrb_value lit = mrb_nil_value();
            if (token == H2O_TOKEN_CONTENT_TYPE) {
                lit = mrb_str_new_lit(mrb, "CONTENT_TYPE");
            } else if (token->buf.len != 0) {
                h2o_iovec_t n = convert_header_name_to_env(&pool, token->buf.base, token->buf.len);
                lit = h2o_mruby_new_str(mrb, n.base, n.len);
            }
            if (mrb_string_p(lit)) {
                FREEZE_STRING(lit);
                mrb_ary_set(mrb, ary, i, lit);
            }
        }
        h2o_mem_clear_pool(&pool);
    }

#define SET_STRING(idx, value)                                                                                \
    do {                                                                                \
        mrb_value lit = (value);                                                                                \
        FREEZE_STRING(lit);                                                                                \
        mrb_ary_set(mrb, ary, idx, lit);                                                                                \
    } while (0)
#define SET_LITERAL(idx, str) SET_STRING(idx, mrb_str_new_lit(mrb, str))

    SET_LITERAL(H2O_MRUBY_LIT_REQUEST_METHOD, "REQUEST_METHOD");
    SET_LITERAL(H2O_MRUBY_LIT_SCRIPT_NAME, "SCRIPT_NAME");
    SET_LITERAL(H2O_MRUBY_LIT_PATH_INFO, "PATH_INFO");
    SET_LITERAL(H2O_MRUBY_LIT_QUERY_STRING, "QUERY_STRING");
    SET_LITERAL(H2O_MRUBY_LIT_SERVER_NAME, "SERVER_NAME");
    SET_LITERAL(H2O_MRUBY_LIT_SERVER_ADDR, "SERVER_ADDR");
    SET_LITERAL(H2O_MRUBY_LIT_SERVER_PORT, "SERVER_PORT");
    SET_LITERAL(H2O_MRUBY_LIT_SERVER_PROTOCOL, "SERVER_PROTOCOL");
    SET_LITERAL(H2O_MRUBY_LIT_CONTENT_LENGTH, "CONTENT_LENGTH");
    SET_LITERAL(H2O_MRUBY_LIT_REMOTE_ADDR, "REMOTE_ADDR");
    SET_LITERAL(H2O_MRUBY_LIT_REMOTE_PORT, "REMOTE_PORT");
    SET_LITERAL(H2O_MRUBY_LIT_REMOTE_USER, "REMOTE_USER");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_URL_SCHEME, "rack.url_scheme");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_MULTITHREAD, "rack.multithread");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_MULTIPROCESS, "rack.multiprocess");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_RUN_ONCE, "rack.run_once");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_HIJACK_, "rack.hijack?");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_INPUT, "rack.input");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_ERRORS, "rack.errors");
    SET_LITERAL(H2O_MRUBY_LIT_RACK_EARLY_HINTS, "rack.early_hints");
    SET_LITERAL(H2O_MRUBY_LIT_SERVER_SOFTWARE, "SERVER_SOFTWARE");
    SET_LITERAL(H2O_MRUBY_LIT_H2O_REMAINING_DELEGATIONS, "h2o.remaining_delegations");
    SET_LITERAL(H2O_MRUBY_LIT_H2O_REMAINING_REPROCESSES, "h2o.remaining_reprocesses");
    SET_STRING(H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE, h2o_mruby_new_str(mrb, server_name, server_name_len));

#undef SET_LITERAL
#undef SET_STRING

    h2o_mruby_eval_expr_location(mrb, H2O_MRUBY_CODE_CORE, "(h2o)lib/handler/mruby/embedded/core.rb", 1);
    h2o_mruby_assert(mrb);

    mrb_ary_set(mrb, ary, H2O_MRUBY_PROC_EACH_TO_ARRAY,
                mrb_funcall(mrb, mrb_obj_value(mrb->kernel_module), "_h2o_proc_each_to_array", 0));
    h2o_mruby_assert(mrb);

    mrb_gc_arena_restore(mrb, gc_arena);
    return ary;
}

static void handle_exception(h2o_mruby_context_t *ctx, h2o_mruby_generator_t *generator)
{
    mrb_state *mrb = ctx->shared->mrb;
    assert(mrb->exc != NULL);

    if (generator == NULL || generator->req->_generator != NULL) {
        fprintf(stderr, "mruby raised: %s\n", RSTRING_PTR(mrb_inspect(mrb, mrb_obj_value(mrb->exc))));
    } else {
        h2o_req_log_error(generator->req, H2O_MRUBY_MODULE_NAME, "mruby raised: %s\n",
                          RSTRING_PTR(mrb_inspect(mrb, mrb_obj_value(mrb->exc))));
        h2o_send_error_500(generator->req, "Internal Server Error", "Internal Server Error", 0);
    }
    mrb->exc = NULL;
}

mrb_value send_error_callback(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args, int *run_again)
{
    mrb_state *mrb = ctx->shared->mrb;
    mrb->exc = mrb_obj_ptr(mrb_ary_entry(args, 0));
    h2o_mruby_generator_t *generator = h2o_mruby_get_generator(mrb, mrb_ary_entry(args, 1));
    handle_exception(ctx, generator);
    return mrb_nil_value();
}

mrb_value block_request_callback(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args, int *run_again)
{
    mrb_state *mrb = ctx->shared->mrb;
    mrb_value blocking_req = mrb_ary_new_capa(mrb, 2);
    mrb_ary_set(mrb, blocking_req, 0, ctx->proc);
    mrb_ary_set(mrb, blocking_req, 1, input);
    mrb_ary_push(mrb, ctx->blocking_reqs, blocking_req);
    return mrb_nil_value();
}

mrb_value run_blocking_requests_callback(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args,
                                         int *run_again)
{
    mrb_state *mrb = ctx->shared->mrb;

    mrb_value exc = mrb_ary_entry(args, 0);
    if (!mrb_nil_p(exc)) {
        mrb->exc = mrb_obj_ptr(exc);
        handle_exception(ctx, NULL);
    }

    mrb_int i;
    mrb_int len = RARRAY_LEN(ctx->blocking_reqs);
    for (i = 0; i != len; ++i) {
        mrb_value blocking_req = mrb_ary_entry(ctx->blocking_reqs, i);
        mrb_value blocking_req_resumer = mrb_ary_entry(blocking_req, 0);
        mrb_value blocking_req_input = mrb_ary_entry(blocking_req, 1);
        h2o_mruby_run_fiber(ctx, blocking_req_resumer, blocking_req_input, NULL);
    }
    mrb_ary_clear(mrb, ctx->blocking_reqs);

    return mrb_nil_value();
}

mrb_value run_child_fiber_callback(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args, int *run_again)
{
    mrb_state *mrb = ctx->shared->mrb;

    mrb_value resumer = mrb_ary_entry(args, 0);

    /*
     * swap receiver to run child fiber immediately, while storing main fiber resumer
     * which will be called after the child fiber is yielded
     */
    mrb_ary_push(mrb, ctx->resumers, *receiver);
    *receiver = resumer;
    *run_again = 1;

    return mrb_nil_value();
}

mrb_value finish_child_fiber_callback(h2o_mruby_context_t *ctx, mrb_value input, mrb_value *receiver, mrb_value args,
                                      int *run_again)
{
    /* do nothing */
    return mrb_nil_value();
}

static mrb_value error_stream_write(mrb_state *mrb, mrb_value self)
{
    h2o_mruby_error_stream_t *error_stream;
    if ((error_stream = h2o_mruby_get_error_stream(mrb, self)) == NULL) {
        mrb_raise(mrb, E_ARGUMENT_ERROR, "ErrorStream#write wrong self");
    }

    mrb_value msgstr;
    mrb_get_args(mrb, "o", &msgstr);
    msgstr = h2o_mruby_to_str(mrb, msgstr);

    h2o_iovec_t msg = h2o_iovec_init(RSTRING_PTR(msgstr), RSTRING_LEN(msgstr));

    if (error_stream->generator != NULL) {
        h2o_req_t *req = error_stream->generator->req;
        req->error_log_delegate.cb(req->error_log_delegate.data, h2o_iovec_init(NULL, 0), msg);
    } else if (error_stream->ctx->handler->pathconf->error_log.emit_request_errors) {
        h2o_write_error_log(h2o_iovec_init(NULL, 0), msg);
    }

    return mrb_fixnum_value(msg.len);
}

static h2o_mruby_shared_context_t *create_shared_context(h2o_context_t *ctx)
{
    /* init mruby in every thread */
    h2o_mruby_shared_context_t *shared_ctx = h2o_mem_alloc(sizeof(*shared_ctx));
    if ((shared_ctx->mrb = mrb_open()) == NULL) {
        fprintf(stderr, "%s: no memory\n", H2O_MRUBY_MODULE_NAME);
        abort();
    }
    shared_ctx->mrb->ud = shared_ctx;
    shared_ctx->ctx = ctx;
    shared_ctx->current_context = NULL;
    shared_ctx->callbacks = (h2o_mruby_callbacks_t){NULL};

    h2o_mruby_setup_globals(shared_ctx->mrb);
    shared_ctx->constants = build_constants(shared_ctx->mrb, ctx->globalconf->server_name.base, ctx->globalconf->server_name.len);

    shared_ctx->symbols.sym_call = mrb_intern_lit(shared_ctx->mrb, "call");
    shared_ctx->symbols.sym_close = mrb_intern_lit(shared_ctx->mrb, "close");
    shared_ctx->symbols.sym_method = mrb_intern_lit(shared_ctx->mrb, "method");
    shared_ctx->symbols.sym_headers = mrb_intern_lit(shared_ctx->mrb, "headers");
    shared_ctx->symbols.sym_body = mrb_intern_lit(shared_ctx->mrb, "body");
    shared_ctx->symbols.sym_async = mrb_intern_lit(shared_ctx->mrb, "async");

    h2o_mruby_define_callback(shared_ctx->mrb, "_h2o__send_error", send_error_callback);
    h2o_mruby_define_callback(shared_ctx->mrb, "_h2o__block_request", block_request_callback);
    h2o_mruby_define_callback(shared_ctx->mrb, "_h2o__run_blocking_requests", run_blocking_requests_callback);
    h2o_mruby_define_callback(shared_ctx->mrb, "_h2o__run_child_fiber", run_child_fiber_callback);
    h2o_mruby_define_callback(shared_ctx->mrb, "_h2o__finish_child_fiber", finish_child_fiber_callback);

    h2o_mruby_sender_init_context(shared_ctx);
    h2o_mruby_http_request_init_context(shared_ctx);
    h2o_mruby_redis_init_context(shared_ctx);
    h2o_mruby_sleep_init_context(shared_ctx);
    h2o_mruby_middleware_init_context(shared_ctx);
    h2o_mruby_channel_init_context(shared_ctx);

    struct RClass *module = mrb_define_module(shared_ctx->mrb, "H2O");
    mrb_ary_set(shared_ctx->mrb, shared_ctx->constants, H2O_MRUBY_H2O_MODULE, mrb_obj_value(module));
    struct RClass *generator_klass = mrb_define_class_under(shared_ctx->mrb, module, "Generator", shared_ctx->mrb->object_class);
    mrb_ary_set(shared_ctx->mrb, shared_ctx->constants, H2O_MRUBY_GENERATOR_CLASS, mrb_obj_value(generator_klass));

    struct RClass *error_stream_class = mrb_class_get_under(shared_ctx->mrb, module, "ErrorStream");
    mrb_ary_set(shared_ctx->mrb, shared_ctx->constants, H2O_MRUBY_ERROR_STREAM_CLASS, mrb_obj_value(error_stream_class));
    mrb_define_method(shared_ctx->mrb, error_stream_class, "write", error_stream_write, MRB_ARGS_REQ(1));

    return shared_ctx;
}

static void dispose_shared_context(void *data)
{
    if (data == NULL)
        return;
    h2o_mruby_shared_context_t *shared_ctx = (h2o_mruby_shared_context_t *)data;
    mrb_close(shared_ctx->mrb);
    free(shared_ctx);
}

static h2o_mruby_shared_context_t *get_shared_context(h2o_context_t *ctx)
{
    static size_t key = SIZE_MAX;
    void **data = h2o_context_get_storage(ctx, &key, dispose_shared_context);
    if (*data == NULL) {
        *data = create_shared_context(ctx);
    }
    return *data;
}

mrb_value prepare_fibers(h2o_mruby_context_t *ctx)
{
    mrb_state *mrb = ctx->shared->mrb;

    h2o_mruby_config_vars_t config = ctx->handler->config;
    mrb_value conf = mrb_hash_new_capa(mrb, 3);
    mrb_hash_set(mrb, conf, mrb_symbol_value(mrb_intern_lit(mrb, "code")),
                 h2o_mruby_new_str(mrb, config.source.base, config.source.len));
    mrb_hash_set(mrb, conf, mrb_symbol_value(mrb_intern_lit(mrb, "file")),
                 h2o_mruby_new_str(mrb, config.path, strlen(config.path)));
    mrb_hash_set(mrb, conf, mrb_symbol_value(mrb_intern_lit(mrb, "line")), mrb_fixnum_value(config.lineno));

    /* run code and generate handler */
    mrb_value result = mrb_funcall(mrb, mrb_obj_value(mrb->kernel_module), "_h2o_prepare_app", 1, conf);
    h2o_mruby_assert(mrb);
    assert(mrb_array_p(result));

    return result;
}

static void on_context_init(h2o_handler_t *_handler, h2o_context_t *ctx)
{
    h2o_mruby_handler_t *handler = (void *)_handler;
    h2o_mruby_context_t *handler_ctx = h2o_mem_alloc(sizeof(*handler_ctx));

    handler_ctx->handler = handler;
    handler_ctx->shared = get_shared_context(ctx);

    mrb_state *mrb = handler_ctx->shared->mrb;

    handler_ctx->blocking_reqs = mrb_ary_new(mrb);
    handler_ctx->resumers = mrb_ary_new(mrb);

    /* compile code (must be done for each thread) */
    int arena = mrb_gc_arena_save(mrb);

    mrb_value fibers = prepare_fibers(handler_ctx);
    assert(mrb_array_p(fibers));

    handler_ctx->proc = mrb_ary_entry(fibers, 0);

    /* run configurator */
    mrb_value configurator = mrb_ary_entry(fibers, 1);
    h2o_mruby_run_fiber(handler_ctx, configurator, mrb_nil_value(), NULL);
    h2o_mruby_assert(handler_ctx->shared->mrb);

    mrb_gc_arena_restore(mrb, arena);
    mrb_gc_protect(mrb, handler_ctx->proc);
    mrb_gc_protect(mrb, configurator);

    h2o_context_set_handler_context(ctx, &handler->super, handler_ctx);
}

static void on_context_dispose(h2o_handler_t *_handler, h2o_context_t *ctx)
{
    h2o_mruby_handler_t *handler = (void *)_handler;
    h2o_mruby_context_t *handler_ctx = h2o_context_get_handler_context(ctx, &handler->super);

    if (handler_ctx == NULL)
        return;

    free(handler_ctx);
}

static void on_handler_dispose(h2o_handler_t *_handler)
{
    h2o_mruby_handler_t *handler = (void *)_handler;

    free(handler->config.source.base);
    free(handler->config.path);
    free(handler);
}

static void stringify_address(h2o_conn_t *conn, socklen_t (*cb)(h2o_conn_t *conn, struct sockaddr *), mrb_state *mrb,
                              mrb_value *host, mrb_value *port)
{
    struct sockaddr_storage ss;
    socklen_t sslen;
    char buf[NI_MAXHOST];

    *host = mrb_nil_value();
    *port = mrb_nil_value();

    if ((sslen = cb(conn, (void *)&ss)) == 0)
        return;
    size_t l = h2o_socket_getnumerichost((void *)&ss, sslen, buf);
    if (l != SIZE_MAX)
        *host = h2o_mruby_new_str(mrb, buf, l);
    int32_t p = h2o_socket_getport((void *)&ss);
    if (p != -1) {
        l = (int)sprintf(buf, "%" PRIu16, (uint16_t)p);
        *port = h2o_mruby_new_str(mrb, buf, l);
    }
}

static void on_rack_input_free(mrb_state *mrb, const char *base, mrb_int len, void *_input_stream)
{
    /* reset ref to input_stream */
    mrb_value *input_stream = _input_stream;
    *input_stream = mrb_nil_value();
}

static int build_env_sort_header_cb(const void *_x, const void *_y)
{
    const h2o_header_t *x = *(const h2o_header_t **)_x, *y = *(const h2o_header_t **)_y;
    if (x->name->len < y->name->len)
        return -1;
    if (x->name->len > y->name->len)
        return 1;
    if (x->name->base != y->name->base) {
        int r = memcmp(x->name->base, y->name->base, x->name->len);
        if (r != 0)
            return r;
    }
    assert(x != y);
    /* the order of the headers having the same name needs to be retained */
    return x < y ? -1 : 1;
}

static mrb_value build_path_info(mrb_state *mrb, h2o_req_t *req, size_t confpath_len_wo_slash)
{
    if (req->path_normalized.len == confpath_len_wo_slash)
        return mrb_str_new_lit(mrb, "");

    assert(req->path_normalized.len > confpath_len_wo_slash);

    size_t path_info_start, path_info_end = req->query_at != SIZE_MAX ? req->query_at : req->path.len;

    if (req->norm_indexes == NULL) {
        path_info_start = confpath_len_wo_slash;
    } else if (req->norm_indexes[0] == 0 && confpath_len_wo_slash == 0) {
        /* path without leading slash */
        path_info_start = 0;
    } else {
        path_info_start = req->norm_indexes[confpath_len_wo_slash] - 1;
    }

    return h2o_mruby_new_str(mrb, req->path.base + path_info_start, path_info_end - path_info_start);
}

int h2o_mruby_iterate_native_headers(h2o_mruby_shared_context_t *shared_ctx, h2o_mem_pool_t *pool, h2o_headers_t *headers,
                                     int (*cb)(h2o_mruby_shared_context_t *, h2o_mem_pool_t *, h2o_header_t *, void *),
                                     void *cb_data)
{
    h2o_header_t **sorted = alloca(sizeof(*sorted) * headers->size);
    size_t i, num_sorted = 0;
    for (i = 0; i != headers->size; ++i) {
        if (headers->entries[i].name == &H2O_TOKEN_TRANSFER_ENCODING->buf)
            continue;
        sorted[num_sorted++] = headers->entries + i;
    }
    qsort(sorted, num_sorted, sizeof(*sorted), build_env_sort_header_cb);
    h2o_iovec_t *values = alloca(sizeof(*values) * (num_sorted * 2 - 1));
    for (i = 0; i != num_sorted; ++i) {
        /* build flattened value of the header field values that have the same name as sorted[i] */
        size_t num_values = 0;
        values[num_values++] = sorted[i]->value;
        while (i < num_sorted - 1 && h2o_header_name_is_equal(sorted[i], sorted[i + 1])) {
            ++i;
            values[num_values++] = h2o_iovec_init(sorted[i]->name == &H2O_TOKEN_COOKIE->buf ? "; " : ", ", 2);
            values[num_values++] = sorted[i]->value;
        }
        h2o_header_t h = *sorted[i];
        h.value = num_values == 1 ? values[0] : h2o_concat_list(pool, values, num_values);
        if (cb(shared_ctx, pool, &h, cb_data) != 0) {
            assert(shared_ctx->mrb->exc != NULL);
            return -1;
        }
    }
    return 0;
}

static int iterate_headers_callback(h2o_mruby_shared_context_t *shared_ctx, h2o_mem_pool_t *pool, h2o_header_t *header,
                                    void *cb_data)
{
    mrb_value env = mrb_obj_value(cb_data);
    mrb_value n;
    if (h2o_iovec_is_token(header->name)) {
        const h2o_token_t *token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, header->name);
        n = h2o_mruby_token_env_key(shared_ctx, token);
    } else {
        h2o_iovec_t vec = convert_header_name_to_env(pool, header->name->base, header->name->len);
        n = h2o_mruby_new_str(shared_ctx->mrb, vec.base, vec.len);
    }
    mrb_value v = h2o_mruby_new_str(shared_ctx->mrb, header->value.base, header->value.len);
    mrb_hash_set(shared_ctx->mrb, env, n, v);
    return 0;
}

mrb_value h2o_mruby_token_string(h2o_mruby_shared_context_t *shared, const h2o_token_t *token)
{
    return mrb_ary_entry(shared->constants, token - h2o__tokens);
}

mrb_value h2o_mruby_token_env_key(h2o_mruby_shared_context_t *shared, const h2o_token_t *token)
{
    return mrb_ary_entry(shared->constants, token - h2o__tokens + H2O_MAX_TOKENS);
}

static mrb_value build_env(h2o_mruby_generator_t *generator)
{
    h2o_mruby_shared_context_t *shared = generator->ctx->shared;
    mrb_state *mrb = shared->mrb;
    mrb_value env = mrb_hash_new_capa(mrb, 16);
    char http_version[sizeof("HTTP/1.0")];
    size_t http_version_sz;

    /* environment */
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REQUEST_METHOD),
                 h2o_mruby_new_str(mrb, generator->req->method.base, generator->req->method.len));

    size_t confpath_len_wo_slash = generator->req->pathconf->path.len;
    if (generator->req->pathconf->path.base[generator->req->pathconf->path.len - 1] == '/')
        --confpath_len_wo_slash;
    assert(confpath_len_wo_slash <= generator->req->path_normalized.len);

    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SCRIPT_NAME),
                 h2o_mruby_new_str(mrb, generator->req->pathconf->path.base, confpath_len_wo_slash));
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_PATH_INFO),
                 build_path_info(mrb, generator->req, confpath_len_wo_slash));
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_QUERY_STRING),
                 generator->req->query_at != SIZE_MAX
                     ? h2o_mruby_new_str(mrb, generator->req->path.base + generator->req->query_at + 1,
                                         generator->req->path.len - (generator->req->query_at + 1))
                     : mrb_str_new_lit(mrb, ""));
    mrb_hash_set(
        mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_NAME),
        h2o_mruby_new_str(mrb, generator->req->hostconf->authority.host.base, generator->req->hostconf->authority.host.len));
    http_version_sz = h2o_stringify_protocol_version(http_version, generator->req->version);
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_PROTOCOL),
                 h2o_mruby_new_str(mrb, http_version, http_version_sz));
    {
        mrb_value h, p;
        stringify_address(generator->req->conn, generator->req->conn->callbacks->get_sockname, mrb, &h, &p);
        if (!mrb_nil_p(h))
            mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_ADDR), h);
        if (!mrb_nil_p(p))
            mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_PORT), p);
    }
    mrb_hash_set(mrb, env, h2o_mruby_token_env_key(shared, H2O_TOKEN_HOST),
                 h2o_mruby_new_str(mrb, generator->req->authority.base, generator->req->authority.len));
    if (generator->req->entity.base != NULL) {
        char buf[32];
        int l = sprintf(buf, "%zu", generator->req->entity.len);
        mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_CONTENT_LENGTH), h2o_mruby_new_str(mrb, buf, l));
        generator->rack_input = mrb_input_stream_value(mrb, NULL, 0);
        mrb_input_stream_set_data(mrb, generator->rack_input, generator->req->entity.base, (mrb_int)generator->req->entity.len, 0,
                                  on_rack_input_free, &generator->rack_input);
        mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_INPUT), generator->rack_input);
    }
    {
        mrb_value h, p;
        stringify_address(generator->req->conn, generator->req->conn->callbacks->get_peername, mrb, &h, &p);
        if (!mrb_nil_p(h))
            mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REMOTE_ADDR), h);
        if (!mrb_nil_p(p))
            mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_REMOTE_PORT), p);
    }
    {
        size_t i;
        for (i = 0; i != generator->req->env.size; i += 2) {
            h2o_iovec_t *name = generator->req->env.entries + i, *value = name + 1;
            mrb_hash_set(mrb, env, h2o_mruby_new_str(mrb, name->base, name->len), h2o_mruby_new_str(mrb, value->base, value->len));
        }
    }

    /* headers */
    h2o_mruby_iterate_native_headers(shared, &generator->req->pool, &generator->req->headers, iterate_headers_callback,
                                     mrb_obj_ptr(env));
    mrb_value early_data_key = h2o_mruby_token_env_key(shared, H2O_TOKEN_EARLY_DATA);
    int found_early_data = !mrb_nil_p(mrb_hash_fetch(mrb, env, early_data_key, mrb_nil_value()));
    if (!found_early_data && h2o_conn_is_early_data(generator->req->conn)) {
        mrb_hash_set(mrb, env, early_data_key, h2o_mruby_new_str(mrb, "1", 1));
        generator->req->reprocess_if_too_early = 1;
    }

    /* rack.* */
    /* TBD rack.version? */
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_URL_SCHEME),
                 h2o_mruby_new_str(mrb, generator->req->scheme->name.base, generator->req->scheme->name.len));
    /* we are using shared-none architecture, and therefore declare ourselves as multiprocess */
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_MULTITHREAD), mrb_false_value());
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_MULTIPROCESS), mrb_true_value());
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_RUN_ONCE), mrb_false_value());
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_HIJACK_), mrb_false_value());
    mrb_value error_stream = h2o_mruby_create_data_instance(
        shared->mrb, mrb_ary_entry(shared->constants, H2O_MRUBY_ERROR_STREAM_CLASS), generator->error_stream, &error_stream_type);
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_ERRORS), error_stream);
    generator->refs.error_stream = error_stream;
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_RACK_EARLY_HINTS),
                 mrb_obj_value(mrb_proc_new_cfunc_with_env(mrb, send_early_hints_proc, 1, &generator->refs.generator)));

    /* server name */
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_SOFTWARE),
                 mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_SERVER_SOFTWARE_VALUE));

    /* h2o specific */
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_H2O_REMAINING_DELEGATIONS),
                 mrb_fixnum_value(generator->req->remaining_delegations));
    mrb_hash_set(mrb, env, mrb_ary_entry(shared->constants, H2O_MRUBY_LIT_H2O_REMAINING_REPROCESSES),
                 mrb_fixnum_value(generator->req->remaining_reprocesses));

    return env;
}

int h2o_mruby_set_response_header(h2o_mruby_shared_context_t *shared_ctx, h2o_iovec_t *name, h2o_iovec_t value, void *_req)
{
    h2o_req_t *req = _req;
    const h2o_token_t *token;
    static const h2o_iovec_t fallthru_set_prefix = {H2O_STRLIT(FALLTHRU_SET_PREFIX)};
    h2o_iovec_t lc_name;

    if (h2o_iovec_is_token(name)) {
        token = H2O_STRUCT_FROM_MEMBER(h2o_token_t, buf, name);
    } else {
        /* convert name to lowercase */
        lc_name = h2o_strdup(&req->pool, name->base, name->len);
        h2o_strtolower(lc_name.base, lc_name.len);
        token = h2o_lookup_token(lc_name.base, lc_name.len);
    }

    if (token != NULL) {
        if (token->flags.proxy_should_drop_for_res) {
            /* skip */
        } else if (token == H2O_TOKEN_CONTENT_LENGTH) {
            req->res.content_length = h2o_strtosize(value.base, value.len);
        } else {
            value = h2o_strdup(&req->pool, value.base, value.len);
            if (token == H2O_TOKEN_LINK) {
                h2o_iovec_t new_value = h2o_push_path_in_link_header(req, value.base, value.len);
                if (new_value.len)
                    h2o_add_header(&req->pool, &req->res.headers, token, NULL, new_value.base, new_value.len);
            } else {
                h2o_add_header(&req->pool, &req->res.headers, token, NULL, value.base, value.len);
            }
        }
    } else if (lc_name.len > fallthru_set_prefix.len &&
               h2o_memis(lc_name.base, fallthru_set_prefix.len, fallthru_set_prefix.base, fallthru_set_prefix.len)) {
        /* register environment variables (with the name converted to uppercase, and using `_`) */
        size_t i;
        lc_name.base += fallthru_set_prefix.len;
        lc_name.len -= fallthru_set_prefix.len;
        for (i = 0; i != lc_name.len; ++i)
            lc_name.base[i] = lc_name.base[i] == '-' ? '_' : h2o_toupper(lc_name.base[i]);
        h2o_iovec_t *slot = h2o_req_getenv(req, lc_name.base, lc_name.len, 1);
        *slot = h2o_strdup(&req->pool, value.base, value.len);
    } else {
        value = h2o_strdup(&req->pool, value.base, value.len);
        h2o_add_header_by_str(&req->pool, &req->res.headers, lc_name.base, lc_name.len, 0, NULL, value.base, value.len);
    }

    return 0;
}

static void clear_rack_input(h2o_mruby_generator_t *generator)
{
    if (!mrb_nil_p(generator->rack_input))
        mrb_input_stream_set_data(generator->ctx->shared->mrb, generator->rack_input, NULL, -1, 0, NULL, NULL);
}

static void on_generator_dispose(void *_generator)
{
    h2o_mruby_generator_t *generator = _generator;

    clear_rack_input(generator);
    generator->req = NULL;

    if (!mrb_nil_p(generator->refs.generator))
        DATA_PTR(generator->refs.generator) = NULL;

    if (generator->error_stream != NULL)
        generator->error_stream->generator = NULL;

    if (generator->sender != NULL)
        generator->sender->dispose(generator);
}

static int on_req(h2o_handler_t *_handler, h2o_req_t *req)
{
    h2o_mruby_handler_t *handler = (void *)_handler;
    h2o_mruby_shared_context_t *shared = get_shared_context(req->conn->ctx);
    int gc_arena = mrb_gc_arena_save(shared->mrb);

    h2o_mruby_context_t *ctx = h2o_context_get_handler_context(req->conn->ctx, &handler->super);

    h2o_mruby_generator_t *generator = h2o_mem_alloc_shared(&req->pool, sizeof(*generator), on_generator_dispose);
    generator->super.proceed = NULL;
    generator->super.stop = NULL;
    generator->req = req;
    generator->ctx = ctx;
    generator->rack_input = mrb_nil_value();
    generator->sender = NULL;

    generator->error_stream = h2o_mem_alloc(sizeof(*generator->error_stream));
    generator->error_stream->ctx = ctx;
    generator->error_stream->generator = generator;

    mrb_value gen = h2o_mruby_create_data_instance(shared->mrb, mrb_ary_entry(shared->constants, H2O_MRUBY_GENERATOR_CLASS),
                                                   generator, &generator_type);
    generator->refs.generator = gen;

    mrb_value env = build_env(generator);

    mrb_value args = mrb_ary_new(shared->mrb);
    mrb_ary_set(shared->mrb, args, 0, env);
    mrb_ary_set(shared->mrb, args, 1, gen);

    int is_delegate = 0;
    h2o_mruby_run_fiber(ctx, ctx->proc, args, &is_delegate);

    mrb_gc_arena_restore(shared->mrb, gc_arena);
    if (is_delegate)
        return -1;
    return 0;
}

static int send_response(h2o_mruby_generator_t *generator, mrb_int status, mrb_value resp, int *is_delegate)
{
    mrb_state *mrb = generator->ctx->shared->mrb;
    mrb_value body;
    h2o_iovec_t content = {NULL};

    /* set status */
    generator->req->res.status = (int)status;

    /* set headers */
    if (h2o_mruby_iterate_rack_headers(generator->ctx->shared, mrb_ary_entry(resp, 1), h2o_mruby_set_response_header,
                                       generator->req) != 0) {
        return -1;
    }

    /* return without processing body, if status is fallthru */
    if (generator->req->res.status == STATUS_FALLTHRU) {
        if (is_delegate != NULL) {
            *is_delegate = 1;
        } else {
            assert(generator->req->handler == &generator->ctx->handler->super);
            h2o_delegate_request_deferred(generator->req);
        }
        return 0;
    }

    /* add date: if it's missing from the response */
    if (h2o_find_header(&generator->req->res.headers, H2O_TOKEN_DATE, SIZE_MAX) == -1)
        h2o_resp_add_date_header(generator->req);

    /* obtain body */
    body = mrb_ary_entry(resp, 2);

    /* flatten body if possible */
    if (mrb_array_p(body)) {
        mrb_int i, len = RARRAY_LEN(body);
        /* calculate the length of the output, while at the same time converting the elements of the output array to string */
        content.len = 0;
        for (i = 0; i != len; ++i) {
            mrb_value e = mrb_ary_entry(body, i);
            if (!mrb_string_p(e)) {
                e = h2o_mruby_to_str(mrb, e);
                if (mrb->exc != NULL)
                    return -1;
                mrb_ary_set(mrb, body, i, e);
            }
            content.len += RSTRING_LEN(e);
        }
        /* allocate memory, and copy the response */
        char *dst = content.base = h2o_mem_alloc_pool(&generator->req->pool, char, content.len);
        for (i = 0; i != len; ++i) {
            mrb_value e = mrb_ary_entry(body, i);
            assert(mrb_string_p(e));
            memcpy(dst, RSTRING_PTR(e), RSTRING_LEN(e));
            dst += RSTRING_LEN(e);
        }
        /* reset body to nil, now that we have read all data */
        body = mrb_nil_value();
    }

    /* use fiber in case we need to call #each */
    if (!mrb_nil_p(body)) {
        if (h2o_mruby_init_sender(generator, body) != 0)
            return -1;
        h2o_start_response(generator->req, &generator->super);
        generator->sender->start(generator);
        return 0;
    }

    /* send the entire response immediately */
    if (status == 101 || status == 204 || status == 304 ||
        h2o_memis(generator->req->input.method.base, generator->req->input.method.len, H2O_STRLIT("HEAD"))) {
        h2o_start_response(generator->req, &generator->super);
        h2o_send(generator->req, NULL, 0, H2O_SEND_STATE_FINAL);
    } else {
        if (content.len < generator->req->res.content_length) {
            generator->req->res.content_length = content.len;
        } else {
            content.len = generator->req->res.content_length;
        }
        h2o_start_response(generator->req, &generator->super);
        h2o_send(generator->req, &content, 1, H2O_SEND_STATE_FINAL);
    }

    return 0;
}

void h2o_mruby_run_fiber(h2o_mruby_context_t *ctx, mrb_value receiver, mrb_value input, int *is_delegate)
{
    h2o_mruby_context_t *old_ctx = ctx->shared->current_context;
    ctx->shared->current_context = ctx;

    mrb_state *mrb = ctx->shared->mrb;
    mrb_value output, resp;
    mrb_int status = 0;
    h2o_mruby_generator_t *generator = NULL;
    h2o_mruby_send_response_callback_t send_response_callback = NULL;

    while (1) {
        /* send input to fiber */
        output = mrb_funcall_argv(mrb, receiver, ctx->shared->symbols.sym_call, 1, &input);
        if (mrb->exc != NULL)
            goto GotException;

        if (!mrb_array_p(output)) {
            mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "Fiber.yield must return an array"));
            goto GotException;
        }

        resp = mrb_ary_entry(output, 0);
        if (!mrb_array_p(resp)) {
            if ((send_response_callback = h2o_mruby_middleware_get_send_response_callback(ctx, resp)) != NULL) {
                break;
            } else {
                mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "rack app did not return an array"));
                goto GotException;
            }
        }

        /* fetch status */
        H2O_MRUBY_EXEC_GUARD({ status = mrb_int(mrb, mrb_ary_entry(resp, 0)); });
        if (mrb->exc != NULL)
            goto GotException;
        if (status >= 0) {
            if (!(100 <= status && status <= 999)) {
                mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "status returned from rack app is out of range"));
                goto GotException;
            }
            break;
        }

        receiver = mrb_ary_entry(resp, 1);
        mrb_value args = mrb_ary_entry(resp, 2);
        int run_again = 0;

        size_t callback_index = -status - 1;
        if (callback_index >= ctx->shared->callbacks.size) {
            input = mrb_exc_new_str_lit(mrb, E_RUNTIME_ERROR, "unexpected callback id sent from rack app");
            run_again = 1;
        } else {
            h2o_mruby_callback_t callback = ctx->shared->callbacks.entries[callback_index];
            input = callback(ctx, input, &receiver, args, &run_again);
        }
        if (mrb->exc != NULL)
            goto GotException;
        if (run_again == 0) {
            if (RARRAY_LEN(ctx->resumers) == 0)
                goto Exit;
            receiver = mrb_ary_pop(mrb, ctx->resumers);
        }

        mrb_gc_protect(mrb, receiver);
        mrb_gc_protect(mrb, input);
    }

    /* retrieve and validate generator */
    generator = h2o_mruby_get_generator(mrb, mrb_ary_entry(output, 1));
    if (generator == NULL)
        goto Exit; /* do nothing if req is already closed */

    if (send_response_callback == NULL)
        send_response_callback = send_response;
    if (send_response_callback(generator, status, resp, is_delegate) != 0)
        goto GotException;

    goto Exit;

GotException:
    if (generator == NULL && mrb_array_p(output))
        generator = h2o_mruby_get_generator(mrb, mrb_ary_entry(output, 1));
    handle_exception(ctx, generator);

Exit:
    ctx->shared->current_context = old_ctx;
}

h2o_mruby_handler_t *h2o_mruby_register(h2o_pathconf_t *pathconf, h2o_mruby_config_vars_t *vars)
{
    h2o_mruby_handler_t *handler = (void *)h2o_create_handler(pathconf, sizeof(*handler));

    handler->super.on_context_init = on_context_init;
    handler->super.on_context_dispose = on_context_dispose;
    handler->super.dispose = on_handler_dispose;
    handler->super.on_req = on_req;
    handler->config.source = h2o_strdup(NULL, vars->source.base, vars->source.len);
    if (vars->path != NULL)
        handler->config.path = h2o_strdup(NULL, vars->path, SIZE_MAX).base;
    handler->config.lineno = vars->lineno;
    handler->pathconf = pathconf;

    return handler;
}

mrb_value h2o_mruby_each_to_array(h2o_mruby_shared_context_t *shared_ctx, mrb_value src)
{
    return mrb_funcall_argv(shared_ctx->mrb, mrb_ary_entry(shared_ctx->constants, H2O_MRUBY_PROC_EACH_TO_ARRAY),
                            shared_ctx->symbols.sym_call, 1, &src);
}

int h2o_mruby_iterate_header_values(h2o_mruby_shared_context_t *shared_ctx, mrb_value name, mrb_value value,
                                    int (*cb)(h2o_mruby_shared_context_t *, h2o_iovec_t *, h2o_iovec_t, void *), void *cb_data)
{
    mrb_state *mrb = shared_ctx->mrb;
    h2o_iovec_t namevec;

    /* convert name and value to string */
    name = h2o_mruby_to_str(mrb, name);
    if (mrb->exc != NULL)
        return -1;
    namevec = (h2o_iovec_init(RSTRING_PTR(name), RSTRING_LEN(name)));
    value = h2o_mruby_to_str(mrb, value);
    if (mrb->exc != NULL)
        return -1;

    /* call the callback, splitting the values with '\n' */
    const char *vstart = RSTRING_PTR(value), *vend = vstart + RSTRING_LEN(value), *eol;
    while (1) {
        for (eol = vstart; eol != vend; ++eol)
            if (*eol == '\n')
                break;
        if (cb(shared_ctx, &namevec, h2o_iovec_init(vstart, eol - vstart), cb_data) != 0)
            return -1;
        if (eol == vend)
            break;
        vstart = eol + 1;
    }

    return 0;
}

int h2o_mruby_iterate_rack_headers(h2o_mruby_shared_context_t *shared_ctx, mrb_value headers,
                                   int (*cb)(h2o_mruby_shared_context_t *, h2o_iovec_t *, h2o_iovec_t, void *), void *cb_data)
{
    mrb_state *mrb = shared_ctx->mrb;

    if (!(mrb_hash_p(headers) || mrb_array_p(headers))) {
        headers = h2o_mruby_each_to_array(shared_ctx, headers);
        if (mrb->exc != NULL)
            return -1;
        assert(mrb_array_p(headers));
    }

    if (mrb_hash_p(headers)) {
        mrb_value keys = mrb_hash_keys(mrb, headers);
        mrb_int i, len = RARRAY_LEN(keys);
        for (i = 0; i != len; ++i) {
            mrb_value k = mrb_ary_entry(keys, i);
            mrb_value v = mrb_hash_get(mrb, headers, k);
            if (h2o_mruby_iterate_header_values(shared_ctx, k, v, cb, cb_data) != 0)
                return -1;
        }
    } else {
        assert(mrb_array_p(headers));
        mrb_int i, len = RARRAY_LEN(headers);
        for (i = 0; i != len; ++i) {
            mrb_value pair = mrb_ary_entry(headers, i);
            if (!mrb_array_p(pair)) {
                mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_ARGUMENT_ERROR, "array element of headers MUST by an array"));
                return -1;
            }
            if (h2o_mruby_iterate_header_values(shared_ctx, mrb_ary_entry(pair, 0), mrb_ary_entry(pair, 1), cb, cb_data) != 0)
                return -1;
        }
    }

    return 0;
}


text:
#include BOSS_CURL_U_curl_setup_h //original-code:"curl_setup.h"

#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
    defined(NTLM_WB_ENABLED)

/*
 * NTLM details:
 *
 * http://davenport.sourceforge.net/ntlm.html
 * https://www.innovation.ch/java/ntlm.html
 */

#define DEBUG_ME 0

#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_SIGNAL_H
#include <signal.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif

#include BOSS_CURL_U_urldata_h //original-code:"urldata.h"
#include BOSS_CURL_U_sendf_h //original-code:"sendf.h"
#include BOSS_CURL_U_select_h //original-code:"select.h"
#include BOSS_CURL_U_vauth__ntlm_h //original-code:"vauth/ntlm.h"
#include BOSS_CURL_U_curl_ntlm_wb_h //original-code:"curl_ntlm_wb.h"
#include BOSS_CURL_U_url_h //original-code:"url.h"
#include BOSS_CURL_U_strerror_h //original-code:"strerror.h"
/* The last 3 #include files should be in this order */
#include BOSS_CURL_U_curl_printf_h //original-code:"curl_printf.h"
#include BOSS_CURL_U_curl_memory_h //original-code:"curl_memory.h"
#include BOSS_CURL_U_memdebug_h //original-code:"memdebug.h"

#if DEBUG_ME
# define DEBUG_OUT(x) x
#else
# define DEBUG_OUT(x) Curl_nop_stmt
#endif

/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
   to avoid fooling the socket leak detector */
#if defined(HAVE_CLOSESOCKET)
#  define sclose_nolog(x)  closesocket((x))
#elif defined(HAVE_CLOSESOCKET_CAMEL)
#  define sclose_nolog(x)  CloseSocket((x))
#else
#  define sclose_nolog(x)  close((x))
#endif

void Curl_ntlm_wb_cleanup(struct connectdata *conn)
{
  if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
    sclose(conn->ntlm_auth_hlpr_socket);
    conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
  }

  if(conn->ntlm_auth_hlpr_pid) {
    int i;
    for(i = 0; i < 4; i++) {
      pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
      if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
        break;
      switch(i) {
      case 0:
        kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
        break;
      case 1:
        /* Give the process another moment to shut down cleanly before
           bringing down the axe */
        Curl_wait_ms(1);
        break;
      case 2:
        kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
        break;
      case 3:
        break;
      }
    }
    conn->ntlm_auth_hlpr_pid = 0;
  }

  free(conn->challenge_header);
  conn->challenge_header = NULL;
  free(conn->response_header);
  conn->response_header = NULL;
}

static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
{
  curl_socket_t sockfds[2];
  pid_t child_pid;
  const char *username;
  char *slash, *domain = NULL;
  const char *ntlm_auth = NULL;
  char *ntlm_auth_alloc = NULL;
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
  struct passwd pw, *pw_res;
  char pwbuf[1024];
#endif
  int error;

  /* Return if communication with ntlm_auth already set up */
  if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
     conn->ntlm_auth_hlpr_pid)
    return CURLE_OK;

  username = userp;
  /* The real ntlm_auth really doesn't like being invoked with an
     empty username. It won't make inferences for itself, and expects
     the client to do so (mostly because it's really designed for
     servers like squid to use for auth, and client support is an
     afterthought for it). So try hard to provide a suitable username
     if we don't already have one. But if we can't, provide the
     empty one anyway. Perhaps they have an implementation of the
     ntlm_auth helper which *doesn't* need it so we might as well try */
  if(!username || !username[0]) {
    username = getenv("NTLMUSER");
    if(!username || !username[0])
      username = getenv("LOGNAME");
    if(!username || !username[0])
      username = getenv("USER");
#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
    if((!username || !username[0]) &&
       !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
       pw_res) {
      username = pw.pw_name;
    }
#endif
    if(!username || !username[0])
      username = userp;
  }
  slash = strpbrk(username, "\\/");
  if(slash) {
    if((domain = strdup(username)) == NULL)
      return CURLE_OUT_OF_MEMORY;
    slash = domain + (slash - username);
    *slash = '\0';
    username = username + (slash - domain) + 1;
  }

  /* For testing purposes, when DEBUGBUILD is defined and environment
     variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
     NTLM challenge/response which only accepts commands and output
     strings pre-written in test case definitions */
#ifdef DEBUGBUILD
  ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
  if(ntlm_auth_alloc)
    ntlm_auth = ntlm_auth_alloc;
  else
#endif
    ntlm_auth = NTLM_WB_FILE;

  if(access(ntlm_auth, X_OK) != 0) {
    error = ERRNO;
    failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
          ntlm_auth, error, Curl_strerror(conn, error));
    goto done;
  }

  if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
    error = ERRNO;
    failf(conn->data, "Could not open socket pair. errno %d: %s",
          error, Curl_strerror(conn, error));
    goto done;
  }

  child_pid = fork();
  if(child_pid == -1) {
    error = ERRNO;
    sclose(sockfds[0]);
    sclose(sockfds[1]);
    failf(conn->data, "Could not fork. errno %d: %s",
          error, Curl_strerror(conn, error));
    goto done;
  }
  else if(!child_pid) {
    /*
     * child process
     */

    /* Don't use sclose in the child since it fools the socket leak detector */
    sclose_nolog(sockfds[0]);
    if(dup2(sockfds[1], STDIN_FILENO) == -1) {
      error = ERRNO;
      failf(conn->data, "Could not redirect child stdin. errno %d: %s",
            error, Curl_strerror(conn, error));
      exit(1);
    }

    if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
      error = ERRNO;
      failf(conn->data, "Could not redirect child stdout. errno %d: %s",
            error, Curl_strerror(conn, error));
      exit(1);
    }

    if(domain)
      execl(ntlm_auth, ntlm_auth,
            "--helper-protocol", "ntlmssp-client-1",
            "--use-cached-creds",
            "--username", username,
            "--domain", domain,
            NULL);
    else
      execl(ntlm_auth, ntlm_auth,
            "--helper-protocol", "ntlmssp-client-1",
            "--use-cached-creds",
            "--username", username,
            NULL);

    error = ERRNO;
    sclose_nolog(sockfds[1]);
    failf(conn->data, "Could not execl(). errno %d: %s",
          error, Curl_strerror(conn, error));
    exit(1);
  }

  sclose(sockfds[1]);
  conn->ntlm_auth_hlpr_socket = sockfds[0];
  conn->ntlm_auth_hlpr_pid = child_pid;
  free(domain);
  free(ntlm_auth_alloc);
  return CURLE_OK;

done:
  free(domain);
  free(ntlm_auth_alloc);
  return CURLE_REMOTE_ACCESS_DENIED;
}

static CURLcode ntlm_wb_response(struct connectdata *conn,
                                 const char *input, curlntlm state)
{
  char *buf = malloc(NTLM_BUFSIZE);
  size_t len_in = strlen(input), len_out = 0;

  if(!buf)
    return CURLE_OUT_OF_MEMORY;

  while(len_in > 0) {
    ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in);
    if(written == -1) {
      /* Interrupted by a signal, retry it */
      if(errno == EINTR)
        continue;
      /* write failed if other errors happen */
      goto done;
    }
    input += written;
    len_in -= written;
  }
  /* Read one line */
  while(1) {
    ssize_t size;
    char *newbuf;

    size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
    if(size == -1) {
      if(errno == EINTR)
        continue;
      goto done;
    }
    else if(size == 0)
      goto done;

    len_out += size;
    if(buf[len_out - 1] == '\n') {
      buf[len_out - 1] = '\0';
      break;
    }
    newbuf = realloc(buf, len_out + NTLM_BUFSIZE);
    if(!newbuf) {
      free(buf);
      return CURLE_OUT_OF_MEMORY;
    }
    buf = newbuf;
  }

  /* Samba/winbind installed but not configured */
  if(state == NTLMSTATE_TYPE1 &&
     len_out == 3 &&
     buf[0] == 'P' && buf[1] == 'W')
    goto done;
  /* invalid response */
  if(len_out < 4)
    goto done;
  if(state == NTLMSTATE_TYPE1 &&
     (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' '))
    goto done;
  if(state == NTLMSTATE_TYPE2 &&
     (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') &&
     (buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
    goto done;

  conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
  free(buf);
  return CURLE_OK;
done:
  free(buf);
  return CURLE_REMOTE_ACCESS_DENIED;
}

/*
 * This is for creating ntlm header output by delegating challenge/response
 * to Samba's winbind daemon helper ntlm_auth.
 */
CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
                              bool proxy)
{
  /* point to the address of the pointer that holds the string to send to the
     server, which is for a plain host or for a HTTP proxy */
  char **allocuserpwd;
  /* point to the name and password for this */
  const char *userp;
  /* point to the correct struct with this */
  struct ntlmdata *ntlm;
  struct auth *authp;

  CURLcode res = CURLE_OK;
  char *input;

  DEBUGASSERT(conn);
  DEBUGASSERT(conn->data);

  if(proxy) {
    allocuserpwd = &conn->allocptr.proxyuserpwd;
    userp = conn->proxyuser;
    ntlm = &conn->proxyntlm;
    authp = &conn->data->state.authproxy;
  }
  else {
    allocuserpwd = &conn->allocptr.userpwd;
    userp = conn->user;
    ntlm = &conn->ntlm;
    authp = &conn->data->state.authhost;
  }
  authp->done = FALSE;

  /* not set means empty */
  if(!userp)
    userp="";

  switch(ntlm->state) {
  case NTLMSTATE_TYPE1:
  default:
    /* Use Samba's 'winbind' daemon to support NTLM authentication,
     * by delegating the NTLM challenge/response protocal to a helper
     * in ntlm_auth.
     * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
     * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
     * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
     * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
     * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
     * filename of ntlm_auth helper.
     * If NTLM authentication using winbind fails, go back to original
     * request handling process.
     */
    /* Create communication with ntlm_auth */
    res = ntlm_wb_init(conn, userp);
    if(res)
      return res;
    res = ntlm_wb_response(conn, "YR\n", ntlm->state);
    if(res)
      return res;

    free(*allocuserpwd);
    *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
                            proxy ? "Proxy-" : "",
                            conn->response_header);
    DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
    free(conn->response_header);
    conn->response_header = NULL;
    break;
  case NTLMSTATE_TYPE2:
    input = aprintf("TT %s\n", conn->challenge_header);
    if(!input)
      return CURLE_OUT_OF_MEMORY;
    res = ntlm_wb_response(conn, input, ntlm->state);
    free(input);
    input = NULL;
    if(res)
      return res;

    free(*allocuserpwd);
    *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
                            proxy ? "Proxy-" : "",
                            conn->response_header);
    DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
    ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
    authp->done = TRUE;
    Curl_ntlm_wb_cleanup(conn);
    break;
  case NTLMSTATE_TYPE3:
    /* connection is already authenticated,
     * don't send a header in future requests */
    free(*allocuserpwd);
    *allocuserpwd=NULL;
    authp->done = TRUE;
    break;
  }

  return CURLE_OK;
}

#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */

redpajama_set_name: RedPajamaGithub


text:
require 'spec_helper'

describe "errs/show.html.haml" do
  before do
    err = Fabricate(:err)
    problem = err.problem
    comment = Fabricate(:comment)
    assign :problem, problem
    assign :comment, comment
    assign :app, problem.app
    assign :notices, err.notices.page(1).per(1)
    assign :notice, err.notices.first
    controller.stub(:current_user) { Fabricate(:user) }
  end

  def with_issue_tracker(tracker, problem)
    problem.app.issue_tracker = tracker.new :api_token => "token token token", :project_id => "1234"
    assign :problem, problem
    assign :app, problem.app
  end

  describe "content_for :action_bar" do
    def action_bar
      view.content_for(:action_bar)
    end

    it "should confirm the 'resolve' link by default" do
      render

      action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
    end

    it "should confirm the 'resolve' link if configuration is unset" do
      Errbit::Config.stub(:confirm_resolve_err).and_return(nil)
      render

      action_bar.should have_selector('a.resolve[data-confirm="Seriously?"]')
    end

    it "should not confirm the 'resolve' link if configured not to" do
      Errbit::Config.stub(:confirm_resolve_err).and_return(false)
      render

      action_bar.should have_selector('a.resolve[data-confirm="null"]')
    end

    it "should link 'up' to HTTP_REFERER if is set" do
      url = 'http://localhost:3000/errs'
      controller.request.env['HTTP_REFERER'] = url
      render

      action_bar.should have_selector("span a.up[href='#{url}']", :text => 'up')
    end

    it "should link 'up' to app_errs_path if HTTP_REFERER isn't set'" do
      controller.request.env['HTTP_REFERER'] = nil
      problem = Fabricate(:problem_with_comments)
      assign :problem, problem
      assign :app, problem.app
      render

      action_bar.should have_selector("span a.up[href='#{app_errs_path(problem.app)}']", :text => 'up')
    end

    context 'create issue links' do
      it 'should allow creating issue for github if current user has linked their github account' do
        user = Fabricate(:user, :github_login => 'test_user', :github_oauth_token => 'abcdef')
        controller.stub(:current_user) { user }

        problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
        assign :problem, problem
        assign :app, problem.app
        render

        action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
      end

      it 'should allow creating issue for github if application has a github tracker' do
        problem = Fabricate(:problem_with_comments, :app => Fabricate(:app, :github_repo => "test_user/test_repo"))
        with_issue_tracker(GithubIssuesTracker, problem)
        assign :problem, problem
        assign :app, problem.app
        render

        action_bar.should have_selector("span a.github_create.create-issue", :text => 'create issue')
      end
    end
  end

  describe "content_for :comments with comments disabled for configured issue tracker" do
    before do
      Errbit::Config.stub(:allow_comments_with_issue_tracker).and_return(false)
    end

    it 'should display comments and new comment form when no issue tracker' do
      problem = Fabricate(:problem_with_comments)
      assign :problem, problem
      assign :app, problem.app
      render

      view.content_for(:comments).should include('Test comment')
      view.content_for(:comments).should include('Add a comment')
    end

    context "with issue tracker" do
      it 'should not display the comments section' do
        problem = Fabricate(:problem)
        with_issue_tracker(PivotalLabsTracker, problem)
        render
        view.view_flow.get(:comments).should be_blank
      end

      it 'should display existing comments' do
        problem = Fabricate(:problem_with_comments)
        problem.reload
        with_issue_tracker(PivotalLabsTracker, problem)
        render

        view.content_for(:comments).should include('Test comment')
        view.content_for(:comments).should_not include('Add a comment')
      end
    end
  end
end


text:
layout: page
title: Website
description: Personal Website Files
img: assets/img/jekyll.jpg
importance: 1
category: Software
redirect: https://github.com/tsnowak/tsnowak.github.io
---


text:
package org.apache.olingo.ext.proxy.api;

public interface StructuredComposableInvoker<T extends StructuredType<?>, O extends Operations>
        extends StructuredInvoker<T>, ComposableInvoker<T, O> {
//No additional methods needed for now.
}


text:
title: 'Properties in C++/CLI….The C# look alike !!!'
author: vivekragunathan
layout: post
date: 2006-04-11T03:56:00+00:00
url: /2006/04/11/properties-in-ccli-the-c-look-alike/
categories:
  - Uncategorized

---

Inherently after writing some code in C#, I wanted everything to be as easy to do like in C#. And could not resist myself writing property like syntax in C++ [ofcourse C++/CLI, threw away the ugly Managed C++ before it was too late for my code to grow into a tree]. Then I learnt that properties are supported in C++.NET too but as always in the ugly way. But in C++/CLI, I was happy enough that the syntax is more elegantly redefined. For instance, there was this boolean member `logToStdError` in my class, and in my legacy code, the property definition for `logToStdError` looked like:-

```cpp
__property bool get_LogToStdError()
{
  return logToStdError;
}

__property void set_LogToStdError(bool value)
{
 logToStdError = value;
}
```

Doesn't that seem like the cat scorching its skin wanting to look like a tiger ? But we need to understand that the Managed C++ is just an extension provided by Microsoft for C++, and is not standard unlike C++/CLI. And then in C++/CLI, the syntax for property was reformed with the property keyword:-

```cpp
property bool LogToStdError
{
  bool get() { return logToStdError; }
  void set(bool value) { logToStdError = value; }
}
```

This makes life bit luxurious, and the compiler takes care of still generating the `get_LogToStdError` and `set_LogToStdError` versions of the methods. Try defining a method with that name and see what happens.

The purpose of this post is not just put another note on C++/CLI Property instead there are 2 cute features that I liked:-

1. If the property that we define is a very simple one, just getting and setting the value of the related member variable, then we can simply declare a statement like this in our class [for the LogToStdError], and the compiler takes care of the under-the-cover activities.

```cpp
property bool logToStdError;
```

2. This one I love very much because I wanted this behaviour in a lot of places in my code, and before. It is possible to specify different accessibility levels for the get and the set property accessors. For example ...

  ```cpp
  property bool LogToStdError
  {
    public: bool get() { return logToStdError; }
    protected internal: void set(bool value) { logToStdError = value; }
  }
  ```

  The get accessor can be accessed anywhere outside the class in the assembly, but the set accessor can be accessed only inside the current assembly or within the types derived from the type in which LogToStdError is declared. I guess that this facility is not available in C#.


text:
layout: default
---

        	{{ content }}

{{ page.button_text }} »

      {% include home-widgets.html %}
      {% include footer.html %}


text:
# Base Syntax

## Package and class name

It's unnecessary to declare package name and class name in the code.Kalang use the directory name as package name and use the file name as class name.For example,the file `/src/foo/bar/Helloworld.kl` means that the package name is `foo.bar` , the main class name is `Helloworld` and the full class name is `foo.bar.Helloworld`,if the source root is `/src`.

## Keywords

`abstract` `as` `assert` `boolean` `break` `byte` `case` `catch`

`char` `class` `const` `constructor` `continue` `default` `do`

`double` `else` `enum` `extends` `final` `finally` `float` `for`

`foreach` `goto` `if` `implements` `import` `in` `instanceof`

`int` `interface` `long` `mixin` `native` `new` `null` `override`

`package` `private` `protected` `public` `return` `short` `static`

`strictfp` `super` `switch` `synchronized` `this` `throw` `throws`

`transient` `try` `val` `var` `void` `volatile` `while` `with`

## Identifiers

### Normal identifiers

Identifiers must start with a letter or an underscore.

For example:

```
var name = "kalang";
var _length = 4;
```

### Quoted identifiers

Quoted identifiers could be use as field name or method name.

For example:

```
System."in".read();
System.out."println"("hello");
```

## Strings

Double-quoted string

```
val str = "hello,kalang\n";
```

Triple-single-quoted string(support multiline)

```
val text = '''Hello
Kalang
''';
```

Interpolation

```
var name = "kalang";
println( "hello,${name}!" );//output:hello,kalang!
```

## Numbers

```
byte a = 1;
char b = 2;
short c = 3;
int d = 4;
long e = 5;
```

## Booleans

```
var t = true;
var f = false;
```

## Arrays

```
var intArray = [1,2,3];                    //int[]
var integerArray= <Integer>[1,2,3];        //Integer[]
var stringArray = ["hello","world"];       //String[]
```

```
int[] arr = new int[10];             //length is 10
int[] arr2 = new int[]{1,2,3};       //arr2 is initialized and it's length is 3
```

## Maps

```
var objectMap = ["name":"kalang","year":2016];          //Map<String,Object>
var stringMap = ["name":"kalang","type":"language"];    //Map<String,String>
var ov = objectMap.get("name");                         //ov is Object type
var sv = stringMap.get("name");                         //sv is String type
```

## Import classes

Import single class:

```
import foo.bar.Helloworld;
```

Import using alias:

```
import foo.bar.HelloKalang as KL;
```

Import all classes in package:

```
import foo.bar.*;
```

## Declare class

Define a normal class:

```
//define a class,default modifier is public
class{
    //declare fields and methods
}
```

Define a generic class:

```
class<T>{
    //...
}
```

Extend and implement:

```
class extends Object implements List<String>{
    //...
}
```

Write as a script:

```
println("Hello,world");
```

## Declare method

```
int sum(int a,int b){
    return a+b;
}
```

## Declare variable

Declare a int variable

```
var a = 1;
```

Declare a string variable

```
var b = String.format("%d",2);
```

Declare a immutable int variable

```
val ia = 3;
```

Declare a variable with specified type and initial value

```
var obj as Object = "hello";
```

Destructuring variables declaration

```
//same as: val length = "ABCD".length(); val bytes = "ABCD".bytes();
val {length,bytes} = "ABCD";

//same as: val firstVar = 1; val secondVar = 2;
val [firstVar, secondVar] = [1,2];
```

## Loop

For loop:

```
for(var i=0;i<9;i++){
    println(i);
}
```

Foreach loop

```
for (v in [1,2,3]){
    println("value:${v}");
}
for (v,i in [1,2,3]){
    println("index:${i},value:${v}");
}
```

Loop invoke

```
var arr = ["a","ab","abc"];
var lens = arr*.length();//lens will be [1,2,3]
```

While loop:

```
while(expression){
    //do some thing
}
```

Do loop:

```
do{
//do some thing
}while(expression);
```

## Try statement

```
try {
    // do some thing
} catch (Exception ex) {
    println(ex);
} finally {

}
```

```
try (val os = new ByteArrayOutputStream()) {
    // do some thing
}
```

## Comments

```
//line comment

/*
multi-line comment
*/

```

## Null safe

```
void hello(String? name){
    name.length();           //compile error:name may be null
    if(name!=null){
        name.length();       //compile passed:name is null checked
    }
}
```

## Default for nullable expression

```
val s as String? = null;
println(s ?? "test");     //output: test
```

## Cast type automatically

```
Object s = "hello";
if(s instanceof String){
    s.chars();//the type of s is changed from Object to String automatically
}
```

## Closures

Closures supports up to 8 parameters.

```
void sayHello(String name,&Void(String) callback) {
    callback("Hello,${name}");
}

sayHello("kalang" , result => println(result));

val sayHi as &Void(String) = (name) => {
    println("Hi,${name}");
};
sayHi("kalang");

```

## Mixin method

A mixin method is a static method which could be use like a non-static method.

For example:

```
val array = <Integer>[1,2,3];

// change an Integer array to an Integer list.
// same as: val list = CollectionMixin.asList(array);
val list = array..asList();

// sum an Integer list.
// same as: val sum = CollectionMixin.sumInt(list);
val sum = list..sumInt();

// read text from a file.
// same as: val text = IOMixin.readToString(new File("hello.txt"), "utf8");
val text = new File("hello.txt")..readToString("utf8");
```

All built-in mixin methods could be found in [kalang.mixin](https://github.com/kasonyang/kalang/tree/master/kalang-runtime/src/main/java/kalang/mixin) package.


text:
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// 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.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Components;
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels;
using System.Collections;
using System.Management.Automation;

namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Implementation
{
    /// <summary>
    /// Updates an existing resource group.
    /// </summary>
    [Cmdlet(VerbsCommon.Set, "AzureRmResourceGroup", DefaultParameterSetName = ResourceGroupNameParameterSet), OutputType(typeof(PSResourceGroup))]
    public class SetAzureResourceGroupCmdlet : ResourceManagerCmdletBase
    {
        /// <summary>
        /// List resources group by name parameter set.
        /// </summary>
        internal const string ResourceGroupNameParameterSet = "Lists the resource group based in the name.";

        /// <summary>
        /// List resources group by Id parameter set.
        /// </summary>
        internal const string ResourceGroupIdParameterSet = "Lists the resource group based in the Id.";

        [Alias("ResourceGroupName")]
        [Parameter(Mandatory = true, ParameterSetName = ResourceGroupNameParameterSet, ValueFromPipelineByPropertyName = true, HelpMessage = "The resource group name.")]
        [ValidateNotNullOrEmpty]
        public string Name { get; set; }

        [Alias("Tags")]
        [Parameter(Mandatory = true, Position = 1, ValueFromPipelineByPropertyName = true, HelpMessage = "A hashtable which represents resource tags.")]
        public Hashtable Tag { get; set; }

        [Alias("ResourceGroupId", "ResourceId")]
        [Parameter(Mandatory = true, ParameterSetName = ResourceGroupIdParameterSet, ValueFromPipelineByPropertyName = false, HelpMessage = "The resource group Id.")]
        [ValidateNotNullOrEmpty]
        public string Id { get; set; }

        public override void ExecuteCmdlet()
        {
            PSUpdateResourceGroupParameters parameters = new PSUpdateResourceGroupParameters
            {
                ResourceGroupName = Name ?? ResourceIdentifier.FromResourceGroupIdentifier(this.Id).ResourceGroupName,
                Tag = Tag,
            };

            var resourceGroup = ResourceManagerSdkClient.UpdatePSResourceGroup(parameters);
            if (resourceGroup != null)
            {
                WriteObject(resourceGroup);
            }
        }
    }
}


text:
module header
  implicit none
  ! variable declarations and assignments
contains
  ! function and subroutine definitions
end module header


text:
require File.dirname(__FILE__) + '/../../../spec_helper'
require File.dirname(__FILE__) + '/shared/constants'

describe "Digest::SHA512#digest_length" do

  it 'returns the length of computed digests' do
    cur_digest = Digest::SHA512.new
    cur_digest.digest_length.should == SHA512Constants::DigestLength
  end

end


text:
@interface MRAdView ()

- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL;

@end

@implementation FakeMRAdView

- (void)rotateToOrientation:(UIInterfaceOrientation)newOrientation
{
    self.currentInterfaceOrientation = newOrientation;

    [super rotateToOrientation:newOrientation];
}

- (void)loadHTMLString:(NSString *)string baseURL:(NSURL *)baseURL
{
    self.loadedHTMLString = string;

    [super loadHTMLString:string baseURL:baseURL];
}

@end


text:
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Subtext.Framework.Components;
using Subtext.Framework.Configuration;
using Subtext.Framework.Services;
using Subtext.Framework.Text;
using Subtext.Web.Controls;

namespace Subtext.Web.UI.Controls
{
    /// <summary>
    /// Displays the most recent comments on the skin.
    /// </summary>
    [PartialCaching(120, null, null, "Blogger", true)]
    public class RecentComments : BaseControl
    {
        private const int DefaultRecentPostCount = 5;
        protected Repeater feedList;

        /// <summary>
        /// Initializes a new instance of the <see cref="RecentComments"/> class.
        /// </summary>
        public RecentComments()
        {
            int commentCount = Config.CurrentBlog.NumberOfRecentComments > 0
                                   ? Config.CurrentBlog.NumberOfRecentComments
                                   : DefaultRecentPostCount;
            ICollection<FeedbackItem> comments = FeedbackItem.GetRecentComments(commentCount);
            Comments = (from c in comments where c.EntryId > 0 select c).ToList();
            Gravatar = new GravatarService(ConfigurationManager.AppSettings);
        }

        protected GravatarService Gravatar { get; private set; }

        protected IEnumerable<FeedbackItem> Comments { get; private set; }

        protected FeedbackItem Comment { get; set; }

        protected string SafeCommentBody
        {
            get
            {
                if(Comment != null)
                {
                    string commentBody = HttpUtility.HtmlEncode(HtmlHelper.RemoveHtml(Comment.Body));
                    if(Blog.RecentCommentsLength > 0)
                    {
                        if(commentBody.Length > Blog.RecentCommentsLength)
                        {
                            commentBody = commentBody.Substring(0, Blog.RecentCommentsLength) + "...";
                        }
                    }
                    return commentBody;
                }
                return string.Empty;
            }
        }

        protected string AlternatingCssClass { get; set; }

        /// <summary>
        /// Binds the comments <see cref="List{T}"/> to the comment list repeater.
        /// Raises the <see cref="E:System.Web.UI.Control.Load"/>
        /// event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs"/> object that contains the event data.</param>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if(Comments != null && feedList != null)
            {
                feedList.DataSource = Comments;
                feedList.DataBind();
            }
            else
            {
                Controls.Clear();
                Visible = false;
            }
        }

        public string EditUrl(FeedbackItem feedback)
        {
            string url = AdminUrl.FeedbackEdit(feedback.Id);

            return VirtualPathUtility.ToAbsolute(StringHelper.LeftBefore(url, "?")) + "?" +
                   url.RightAfter("?");
        }

        protected void EntryCreated(object sender, RepeaterItemEventArgs e)
        {
            if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
            {
                Comment = (FeedbackItem)e.Item.DataItem;

                var title = (HyperLink)e.Item.FindControl("Link");
                if(title != null)
                {
                    title.Text = SafeCommentBody;
                    title.NavigateUrl = Url.FeedbackUrl(Comment);
                    ControlHelper.SetTitleIfNone(title, "Reader Comment.");
                }
                var author = (Literal)e.Item.FindControl("Author");
                if(author != null)
                {
                    author.Text = HttpUtility.HtmlEncode(Comment.Author);
                }
            }
        }

        protected void OnItemBound(object sender, RepeaterItemEventArgs e)
        {
            AlternatingCssClass = e.Item.ItemType != ListItemType.Item ? " alt" : string.Empty;
        }
    }
}


text:
<!DOCTYPE html>
<meta charset=utf-8>
<title>invalid src: port-leading-colon</title>
<audio src="http://2001::1"></audio>


text:
module CSVImporter
  class UserGroups < CSVImporter::Base
    #125.01763010025 seconds!
    #135 with district constrained delete
    #
    #
    FIELD_DESCRIPTIONS = {
    :district_user_id => 'Key for user',
    :district_group_id => "Key for group (the one you created for the SIMS group.)",
    :principal => "true if the user is the principal for that group, blank otherwise.
The most common case this would be used would be for assistant principals assigned to teams or neighborhoods.
Schoolwide (or asst principals by grade) would be covered by all_students_in_school.csv  (Y/N also works)"
}
    class << self
      def description
        "Assigns users to groups."
      end

      def csv_headers
        [:district_user_id, :district_group_id, :principal]
      end
      def overwritten
      end

      def load_order
      end

      def removed
      end

#      def related
#      end

      def how_often
        "Once per semester (or quarter), or as often as the \"students\" file is uploaded"
      end

#      def alternate
#      end

      def upload_responses
        super
      end

      def how_many_rows
        "One row per user per group.   A group might have one or multiple users, and a user could be assigned to multiple groups."
      end

    end

  private

    def load_data_infile
      headers=csv_headers
      headers[-1]="@principal"
      <<-EOF
          LOAD DATA LOCAL INFILE "#{@clean_file}"
            INTO TABLE #{temporary_table_name}
            FIELDS TERMINATED BY ','
            OPTIONALLY ENCLOSED BY '"'
            (#{headers.join(", ")})
        set    principal= case trim(lower(@principal))
        when 't' then true
        when 'y' then true
        when 'yes' then true
        when 'true' then true
        when '-1' then true
        when '1' then true
        else false
        end ;
        EOF
    end

    def index_options
      [[:district_user_id, :district_group_id]]
    end

    def migration t
      t.string :district_user_id, :limit => User.columns_hash["district_user_id"].limit, :null => User.columns_hash["district_user_id"].null
      t.string :district_group_id, :limit => Group.columns_hash["district_group_id"].limit, :null => Group.columns_hash["district_group_id"].null
      t.boolean :principal
    end

    def delete
      query = "delete from uga using user_group_assignments uga
      inner join users on uga.user_id = users.id
      inner join groups on uga.group_id = groups.id
      inner join schools on groups.school_id = schools.id
      where schools.district_id = #{@district.id} and users.district_id = #{@district.id} and schools.district_school_id is not null and groups.district_group_id !='' and users.district_user_id !=''
      "

extra ="      where not exists (
        select 1 from #{temporary_table_name} tug
        where tug.district_user_id = users.district_user_id and tug.district_group_id = groups.district_group_id)
      )"
      UserGroupAssignment.connection.update query
    end

    def insert
      query=("insert into user_group_assignments
      (user_id,group_id, is_principal, created_at, updated_at)
      select u.id , g.id, principal, CURDATE(), CURDATE() from #{temporary_table_name} tug inner join
      users u on u.district_user_id = tug.district_user_id
      inner join groups g
      on tug.district_group_id = g.district_group_id
      and u.district_id = #{@district.id}
      group by u.id,g.id,principal
      "
      )
      Group.connection.update query
    end
  end
end


text:
'use strict';

var fs = require('fs');
var GrammarRegistry = require('first-mate').GrammarRegistry;
var Table           = require('cli-table');

var registry = new GrammarRegistry();
var grammar  = registry.loadGrammarSync(
  './node_modules/language-babel/grammars/Babel Language.json');

var code   = fs.readFileSync('./app/samples/SmallComp.js', 'utf8');
var tls     = grammar.tokenizeLines(code);

function printTokenizedLine(tl) {
  var table  = new Table({head:['value', 'scopes'], colWidths:[12, 50]});

  table.push.apply(table,
    tl.map(function(t) {
      return [t.value, t.scopes.join('\n')];
    }));

  console.log(table.toString());
}

tls.forEach(printTokenizedLine);


text:
import { Component, Input } from '@angular/core';

@Component({
  selector: 'prx-episode-card',
  styleUrls: ['./episode-card.component.scss'],
  template: `

{{date | date: dateFormat}}

        {{title || seasonEpisode || (date | date:"MMM d, y")}}
        <ng-template #nolink>{{title || seasonEpisode || (date | date:"MMM d, y")}}</ng-template>

        {{seasonEpisodeNumbers}} |
        {{teaser}}

    <ng-content></ng-content>
  `
})
export class EpisodeCardComponent {
  @Input() date: Date;
  @Input() dateFormat = 'M/d';
  @Input() editLink: string | any[];
  @Input() title: string;
  @Input() seasonNumber: number;
  @Input() episodeNumber: number;
  @Input() teaser: string;
  @Input() status: 'draft' | 'scheduled' | 'published';

  get seasonEpisode(): string {
    if (!isNaN(this.seasonNumber) && !isNaN(this.episodeNumber)) {
      return `S${this.seasonNumber} E${this.episodeNumber}`;
    }
  }
}


text:
//Copyright © 2014 Sony Computer Entertainment America LLC. See License.txt.
using System;
using System.Collections.Generic;

using Sce.Atf;
using Sce.Atf.Dom;
using Sce.Atf.Applications;
using Sce.Atf.Adaptation;

namespace TextureEditor
{
    ///
    /// Context for manipulating resource metadata. Don't want undo/redo so custom implementation instead of inheriting from EditingContext
	//public class ResourceMetadataEditingContext : EditingContext, IObservableContext
	public class ResourceMetadataEditingContext : DomNodeAdapter, IObservableContext, ISelectionContext
	{
        ///
        /// Performs initialization when the adapter's node is set.
        /// Subscribes to events for DomNode tree changes and raises Reloaded event.
        protected override void OnNodeSet()
        {
            DomNode.AttributeChanged += (sender, e) => ItemChanged.Raise(this, new ItemChangedEventArgs<object>(e.DomNode));
            DomNode.ChildInserted += (sender, e) => ItemInserted.Raise(this, new ItemInsertedEventArgs<object>(e.Index, e.Child, e.Parent));
            DomNode.ChildRemoved += (sender,e)=> ItemRemoved.Raise(this, new ItemRemovedEventArgs<object>(e.Index, e.Child, e.Parent));

			m_selection.Changing += TheSelectionChanging;
			m_selection.Changed += TheSelectionChanged;

            Reloaded.Raise(this, EventArgs.Empty);
            base.OnNodeSet();
        }

        #region IObservableContext Members
        ///
        /// Event handler for node inserted in DomNode tree.
        public event EventHandler<ItemInsertedEventArgs<object>> ItemInserted;
        ///
        /// Event handler for node removed from DomNode tree.
        public event EventHandler<ItemRemovedEventArgs<object>> ItemRemoved;
        ///
        /// Event handler for node changed in DomNode tree.
        public event EventHandler<ItemChangedEventArgs<object>> ItemChanged;
        ///
        /// Event that is raised when the DomNode tree has been reloaded.
        public event EventHandler Reloaded;
        #endregion

		#region ISelectionContext Members

		///
		/// Gets or sets the selected items
		public IEnumerable<object> Selection
		{
			get { return m_selection; }
			set { m_selection.SetRange(value); }
		}

		///
		/// Gets all selected items of the given type
		/// <typeparam name="T">Desired item type</typeparam>
		/// <returns>All selected items of the given type</returns>
		public IEnumerable<T> GetSelection<T>() where T : class
		{
			return m_selection.AsIEnumerable<T>();
		}

		///
		/// Gets the last selected item as object
		public object LastSelected
		{
			get { return m_selection.LastSelected; }
		}

		///
		/// Gets the last selected item of the given type, which may not be the same
		/// as the LastSelected item
		/// <typeparam name="T">Desired item type</typeparam>
		/// <returns>Last selected item of the given type</returns>
		public T GetLastSelected<T>() where T : class
		{
			return m_selection.GetLastSelected<T>();
		}

		///
		/// Returns whether the selection contains the given item
		/// <param name="item">Item</param>
		/// <returns>True iff the selection contains the given item</returns>
		public bool SelectionContains(object item)
		{
			return m_selection.Contains(item);
		}

		///
		/// Gets the number of items in the current selection
		public int SelectionCount
		{
			get { return m_selection.Count; }
		}

		///
		/// Event that is raised before the selection changes
		public event EventHandler SelectionChanging;

		///
		/// Event that is raised after the selection changes
		public event EventHandler SelectionChanged;

		#endregion

		private void TheSelectionChanging(object sender, EventArgs e)
		{
			SelectionChanging.Raise(this, EventArgs.Empty);
		}

		private void TheSelectionChanged(object sender, EventArgs e)
		{
			SelectionChanged.Raise(this, EventArgs.Empty);
		}

		private readonly AdaptableSelection<object> m_selection = new AdaptableSelection<object>();
    }
}


text:
import { Server, CustomTransportStrategy } from '@nestjs/microservices'
import { serverBuilder } from 'rxjs-grpc'
import { Observable, Observer } from 'rxjs/'

import rpc from './rpc-decorator'
import { unknownRpcFunction } from './warnings'
import isServerBuilder from './is-server-builder'
import { makeGRPCError } from './helpers'

export interface CreateServerOptions extends GRPCServerConfig {
  /** Absolute path to the your .proto file. */
  protoPath: string
  /** The package specifier used in your .proto file. */
  packageName: string
}

export interface GRPCServerConfig {
  host: string
  port: number
  /**
   * The name of your RPC system defined in your .proto file.
   */
  serviceName: string
}

/**
 * A GRPC server compatible with the NestJS framework.
 *
 * Example:
 * ```typescript
 * import { GRPCServer } from '@fresh8/nestjs-grpc-transport'
 * import { ServerBuilder } from 'rxjs-grpc'
 * import { nsp } from './grpc-namespaces'
 *
 * NestFactory.createMicroservice(appModule, {
 *  strategy: new GRPCServer(
 *    new ServerBuilder('path/to/myproto.proto', 'nsp'),
 *    { host: 'localhost', port: 50051, serviceName: 'MyService' }
 *  )
 * })
 */
export class GRPCServer extends Server implements CustomTransportStrategy {
  private readonly server: any
  private readonly host: string
  private readonly port: number
  private readonly serviceName: string

  constructor(server: any, { host, port, serviceName }: GRPCServerConfig) {
    super()
    this.server = server
    this.host = host
    this.port = port
    this.serviceName = serviceName
  }

  /**
   * Start the GRPC server
   */
  listen(callback?: () => void) {
    this.init()
    this.server.start(`${this.host}:${this.port}`)
    callback && callback()
  }

  /**
   * Terminate the GRPC server.
   */
  close() {
    this.server && this.server.forceShutdown()
  }

  /**
   * Register RPC handlers
   */
  private init(): void {
    const delegates: any = this.getGRPCDelegates()
      .map(d => {
        return {
          ...d,
          rpc: this.wrapRpc(d.rpc)
        }
      })
      .reduce((acc: { [index: string]: Function }, val: any) => {
        acc[val.name] = val.rpc
        return acc
      }, {})

    this.server[`add${this.serviceName}`](delegates)
  }

  /**
   * Makes the output of some async method observable. This
   * is required by rxjs-grpc.
   * @param delegate the rpc handler to handle a request.
   */
  private wrapRpc(delegate: (...args: Array<any>) => Promise<any>) {
    return (...args: Array<any>) => {
      const response$ = this.transformToObservable(
        delegate(...args)
      ) as Observable<any>

      //TODO this whole block is to work around https://github.com/nestjs/nest/issues/290. Although error transforming will likely need to stay
      const workedAround = Observable.create((observer: Observer<any>) => {
        response$.subscribe({
          next(value: any) {
            if (value && value.error && value instanceof Observable) {
              return observer.error(makeGRPCError((value as any).error))
            }
            observer.next(value)
          },
          error(error) {
            observer.error(makeGRPCError(error))
          },
          complete: observer.complete.bind(observer)
        })
      })
      return workedAround

      //TODO `return response$` once https://github.com/nestjs/nest/issues/290 is resolved
    }
  }

  /**
   * Returns any methods decorated with @MessagePattern({ rpc: 'rpcMethod' })
   * or @rpc.
   */
  private getGRPCDelegates() {
    const handles = this.getHandlers()
    const ret: Array<{ rpc: any; name: string }> = []

    Object.keys(handles).forEach(serializedPattern => {
      if (serializedPattern !== 'undefined') {
        let pattern: { rpc?: string }

        try {
          pattern = JSON.parse(serializedPattern)
        } catch (error) {
          return
        }

        if (pattern.rpc) {
          ret.push({ rpc: handles[serializedPattern], name: pattern.rpc })
        }
      }
    })

    return ret
  }
}

/**
 * creates a GRPC server.
 */
function createGRPCServer(config: CreateServerOptions): GRPCServer
/**
 * creates a GRPC server.
 */
function createGRPCServer(
  server: any,
  { host, port, serviceName }: GRPCServerConfig
): GRPCServer
function createGRPCServer(serverOrConfig: any, startConfig?: any): GRPCServer {
  if (isServerBuilder(serverOrConfig)) {
    return new GRPCServer(serverOrConfig, startConfig)
  }

  return new GRPCServer(
    serverBuilder(serverOrConfig.protoPath, serverOrConfig.packageName),
    serverOrConfig
  )
}

export default createGRPCServer


text:
'use strict';

const nodeFetch = require('node-fetch'),
  jsonHeaders = {'Content-type':'application/json', Authorization: `Token ${process.env.CLAY_ACCESS_KEY}` };

function getObject(url, options) {
  return exports.fetch(url, options).then(function (response) {
    return response.json();
  });
}

function putObject(url, data) {
  return exports.fetch(url, {method: 'PUT', body: JSON.stringify(data), headers: jsonHeaders});
}

module.exports.fetch = nodeFetch;
module.exports.getObject = getObject;
module.exports.putObject = putObject;


text:
@class TwitterStatusViewController;
@class TwitterStatusViewMessageField;

// this class is used for receiving mouseDown event
@interface TwitterStatusViewMessageTextView : NSTextView {
    TwitterStatusViewMessageField *_parent;
}
- (void) setParentView:(TwitterStatusViewMessageField*)parent;
@end

@interface TwitterStatusViewMessageField :  NSScrollView {
    IBOutlet TwitterStatusViewMessageTextView *textView;

    float _defaultHeight;
    float _defaultY;
    BOOL _highlighted;

    TwitterStatusViewController *_controller;
}

- (void) highlight;
- (void) unhighlight;
- (BOOL) highlighted;
- (void) setMessage:(NSString*)message;
- (float) expandIfNeeded;
- (void) setViewController:(TwitterStatusViewController*)controller;
- (TwitterStatusViewController*)controller;

@end


text:
<title>Not created</title>

Your account could not be created.

	<? AuthUI.mainPageLink ?>