text:
#include "cv_obj.h"
#include "dlist.h"
#include "fion_poll.h"
#include "form_perf.h"
#include "logger.h"
#include "mode_perf.h"
#include "mutex_obj.h"
#include "output_if_std.h"
#include "sock_mod.h"
#include "thread_obj.h"
#include "thread_pool.h"
#include "token_bucket.h"
#include "util_cpu.h"
#include "util_date.h"
#include "util_debug.h"
#include "util_mem.h"
#include "util_string.h"

#include <string.h>
#include <unistd.h>
#include <pthread.h>

struct modeobj_priv
{
    uint16_t           parts;
    struct args_obj    args;
    struct threadpool  threadpool;
    struct mutexobj   *mtxarr;
    struct cvobj      *cvarr;
    struct dlist      *sockq;
    uint32_t          *activesocks;
    uint32_t          *closedsocks;
    uint32_t          *configsocks;
    struct sockobj    *workerstats;
    struct formobj    *workerforms;
};

/**
 * @brief Destroy a fully or partially constructed mode object.
 *
 * @param[in,out] mode A pointer to a mode object.
 *
 * @return Void.
 */
static void modeperf_destroyparts(struct modeobj * const mode)
{
    uint32_t i;

    switch (mode->priv->parts)
    {
        case 12:
            memset(&mode->ops, 0, sizeof(mode->ops));
            for (i = 0; i < mode->priv->args.threads; i++)
            {
                cvobj_destroy(&mode->priv->cvarr[i]);
                mutexobj_destroy(&mode->priv->mtxarr[i]);
            }
        case 11:
            threadpool_destroy(&mode->priv->threadpool);
        case 10:
            UTILMEM_FREE(mode->priv->workerforms);
        case 9:
            UTILMEM_FREE(mode->priv->workerstats);
        case 8:
            UTILMEM_FREE(mode->priv->configsocks);
        case 7:
            UTILMEM_FREE(mode->priv->closedsocks);
        case 6:
            UTILMEM_FREE(mode->priv->activesocks);
        case 5:
            UTILMEM_FREE(mode->priv->cvarr);
        case 4:
            UTILMEM_FREE(mode->priv->mtxarr);
        case 3:
            UTILMEM_FREE(mode->priv->sockq);
        case 2:
            memset(&mode->priv->args, 0, sizeof(mode->priv->args));
        case 1:
            UTILMEM_FREE(mode->priv);
            mode->priv = NULL;
        case 0:
            break;
        default:
            logger_printf(LOGGER_LEVEL_ERROR,
                          "%s: invalid mode object part (%u)\n",
                          __FUNCTION__,
                          mode->priv->parts);
            break;
    }
}

bool modeperf_create(struct modeobj * const mode,
                     const struct args_obj * const args)
{
    bool ret = false;
    uint32_t i;

    if (UTILDEBUG_VERIFY((mode != NULL) &&
                         (mode->priv == NULL) &&
                         (args != NULL)))
    {
        if ((mode->priv = UTILMEM_CALLOC(struct modeobj_priv,
                                         sizeof(struct modeobj_priv),
                                         1)) == NULL)
        {
            // Do nothing
        }
        else if (memcpy(&mode->priv->args,
                        args,
                        sizeof(mode->priv->args)) == NULL)
        {
            mode->priv->parts = 1;
        }
        else if ((mode->priv->sockq = UTILMEM_CALLOC(struct dlist,
                                                     sizeof(struct dlist),
                                                     args->threads)) == NULL)
        {
            mode->priv->parts = 2;
        }
        else if ((mode->priv->mtxarr = UTILMEM_CALLOC(struct mutexobj,
                                                     sizeof(struct mutexobj),
                                                     args->threads)) == NULL)
        {
            mode->priv->parts = 3;
        }
        else if ((mode->priv->cvarr = UTILMEM_CALLOC(struct cvobj,
                                                     sizeof(struct cvobj),
                                                     args->threads)) == NULL)
        {
            mode->priv->parts = 4;
        }
        else if ((mode->priv->activesocks = UTILMEM_CALLOC(uint32_t,
                                                           sizeof(uint32_t),
                                                           args->threads)) == NULL)
        {
            mode->priv->parts = 5;
        }
        else if ((mode->priv->closedsocks = UTILMEM_CALLOC(uint32_t,
                                                           sizeof(uint32_t),
                                                           args->threads)) == NULL)
        {
            mode->priv->parts = 6;
        }
        else if ((mode->priv->configsocks = UTILMEM_CALLOC(uint32_t,
                                                           sizeof(uint32_t),
                                                           args->threads)) == NULL)
        {
            mode->priv->parts = 7;
        }
        else if ((mode->priv->workerstats = UTILMEM_CALLOC(struct sockobj,
                                                           sizeof(struct sockobj),
                                                           args->threads)) == NULL)
        {
            mode->priv->parts = 8;
        }
        else if ((mode->priv->workerforms = UTILMEM_CALLOC(struct formobj,
                                                           sizeof(struct formobj),
                                                           args->threads)) == NULL)
        {
            mode->priv->parts = 9;
        }
        else if (!threadpool_create(&mode->priv->threadpool, args->threads + 2))
        {
            mode->priv->parts = 10;
        }
        else
        {
            mode->priv->parts = 11;

            for (i = 0; i < args->threads; i++)
            {
                mutexobj_create(&mode->priv->mtxarr[i]);
                cvobj_create(&mode->priv->cvarr[i]);
            }

            mode->ops.mode_create  = modeperf_create;
            mode->ops.mode_destroy = modeperf_destroy;
            mode->ops.mode_start   = modeperf_start;
            mode->ops.mode_stop    = modeperf_stop;
            mode->ops.mode_cancel  = modeperf_cancel;
            mode->priv->parts      = 12;

            ret = true;
        }

        if (!ret)
        {
            logger_printf(LOGGER_LEVEL_ERROR,
                          "%s: failed to create mode object part %d\n",
                          __FUNCTION__,
                          mode->priv == NULL ? 1 : mode->priv->parts);

            if (mode->priv != NULL)
            {
                modeperf_destroyparts(mode);
            }
        }
    }

    return ret;
}

bool modeperf_destroy(struct modeobj * const mode)
{
    bool ret = false;

    if (UTILDEBUG_VERIFY((mode != NULL) && (mode->priv != NULL)))
    {
        mode->ops.mode_stop(mode);
        modeperf_destroyparts(mode);
        ret = true;
    }

    return ret;
}

/**
 * @brief Copy a mode object configuration to a socket object configuration.
 *
 * @param[in,out] sock      A pointer to a socket object.
 * @param[in]     mode      A pointer to a mode object.
 * @param[in]     timeoutms Socket timeout in milliseconds.
 *
 * @return Void.
 */
static void modeperf_copy(struct modeobj_priv * const mode,
                          struct sockobj * const sock,
                          const int32_t timeoutms)
{
    memcpy(sock->conf.ipaddr, mode->args.ipaddr, sizeof(sock->conf.ipaddr));
    sock->conf.ipport        = mode->args.ipport;
    sock->conf.backlog       = mode->args.backlog;
    sock->conf.timeoutms     = timeoutms;
    sock->conf.datalimitbyte = mode->args.datalimitbyte;
    sock->conf.ratelimitbps  = mode->args.ratelimitbps;
    sock->conf.timelimitusec = mode->args.timelimitusec;
    sock->conf.family        = mode->args.family;
    sock->conf.type          = mode->args.type;
    sock->conf.model         = mode->args.arch;
}

/**
 * @brief Call a mode socket's receive or send function.
 *
 * @param[in,out] mode   A pointer to a mode object.
 * @param[in]     call   A pointer to a socket object's receive or send
 *                       function.
 * @param[in,out] stats  Function-specific socket statistics.
 * @param[in,out] obj    A pointer to a socket object.
 * @param[in]     buf    A pointer to a buffer.
 * @param[in]     buflen The maximum size of a buffer in bytes.
 * @param[in]     tsus   The current Unix time in microseconds.
 *
 * @return The number of bytes returned by a socket's receive or send function.
 */
static int32_t modeperf_call(struct modeobj_priv * const mode,
                             int32_t (*call)(struct sockobj * const obj,
                                             void * const buf,
                                             const uint32_t len),
                             struct sockobj_flowstats *stats,
                             struct sockobj * const sock,
                             void * const buf,
                             const uint32_t buflen,
                             const uint64_t tsus)
{
    int32_t ret = 0;
    uint64_t len = 0;

    if (mode->args.datalimitbyte > 0)
    {
        if ((uint64_t)stats->buflen.sum < mode->args.datalimitbyte)
        {
            len = mode->args.datalimitbyte - stats->buflen.sum;

            if (len > buflen)
            {
                len = buflen;
            }

            len = tokenbucket_remove(&sock->tb, len * 8) / 8;
        }
    }
    else
    {
        len = tokenbucket_remove(&sock->tb, buflen * 8) / 8;
    }

    if (len > 0)
    {
        ret = call(sock, buf, len);
    }
    else
    {
        if ((!sock->event.ops.fion_poll(&sock->event)) ||
            (sock->event.ops.fion_getevents(&sock->event, 0) & FIONOBJ_REVENT_ERROR))
        {
            sock->ops.sock_close(sock);
            sock->ops.sock_destroy(sock);
        }
    }

    if (ret < 0)
    {
        sock->ops.sock_close(sock);
        sock->ops.sock_destroy(sock);
    }
    else if ((mode->args.timelimitusec > 0) &&
             ((tsus - sock->info.startusec) >= mode->args.timelimitusec))
    {
        sock->ops.sock_close(sock);
        sock->ops.sock_destroy(sock);
    }
    else if ((mode->args.datalimitbyte > 0) &&
             ((uint64_t)stats->buflen.sum >= mode->args.datalimitbyte))
    {
        sock->ops.sock_close(sock);
        sock->ops.sock_destroy(sock);
    }

    tokenbucket_return(&sock->tb, ret < 0 ? 0 : len - (uint32_t)ret);

    return ret;
}

/**
 * @brief Get a new socket from a socket queue.
 *
 * @param[in,out] mode  A pointer to a mode object.
 * @param[in] qid       A socket queue id.
 * @param[in] timeoutms The maximum amount of time in milliseconds to wait for a
 *                      new socket.
 *
 * @return A pointer to a new socket on success. Otherwise, a null pointer is
 *         returned.
 */
static struct sockobj *modeperf_getsock(struct modeobj_priv * const mode,
                                        const uint32_t qid,
                                        const uint32_t timeoutms,
                                        bool * const shutdown)
{
    struct sockobj *ret = NULL;

    if (UTILDEBUG_VERIFY((mode != NULL) &&
                         (qid < mode->args.threads) &&
                         (shutdown != NULL)))
    {
        *shutdown = false;

        mutexobj_lock(&mode->mtxarr[qid]);

        if ((mode->sockq[qid].tail == NULL) && (timeoutms > 0))
        {
            cvobj_timedwait(&mode->cvarr[qid],
                            &mode->mtxarr[qid],
                            timeoutms * 1000);
        }

        if ((mode->sockq[qid].tail != NULL) &&
            ((ret = mode->sockq[qid].tail->val) != NULL))
        {
            dlist_removetail(&mode->sockq[qid]);
            mode->activesocks[qid]++;
        }

        if ((mode->args.arch == SOCKOBJ_MODEL_CLIENT) &&
            (mode->activesocks[qid] == 0) &&
            (mode->closedsocks[qid] == mode->configsocks[qid]))
        {
            *shutdown = true;
        }

        mutexobj_unlock(&mode->mtxarr[qid]);
    }

    return ret;
}

static bool modeperf_retsock(struct modeobj_priv * const mode,
                             struct sockobj * const sock,
                             uint32_t qid)
{
    bool ret = false;

    if (UTILDEBUG_VERIFY((mode != NULL) &&
                         (sock != NULL) &&
                         (qid < mode->args.threads)))
    {
        UTILMEM_FREE(sock);

        mutexobj_lock(&mode->mtxarr[qid]);
        mode->activesocks[qid]--;
        mode->closedsocks[qid]++;
        mutexobj_unlock(&mode->mtxarr[qid]);

        ret = true;
    }

    return ret;
}

/**
 * @brief A scheduler that accepts new sockets and inserts them into queue(s)
 *        based on a round-robin algorithm.
 *
 * @param[in,out] arg A pointer to a mode object.
 *
 * @return NULL.
 */
static void *modeperf_acceptorthread(void *arg)
{
    struct modeobj_priv *mode = (struct modeobj_priv*)arg;
    struct threadobj *thread = threadpool_getthread(&mode->threadpool);
    struct sockobj server, *sock = NULL;
    bool exit = true;
    uint32_t acceptsocks = 0, activesocks = 0, i = 0, qid = 0, tid = 0;

    memset(&server, 0, sizeof(server));

    modeperf_copy(mode, &server, 50);
    exit = !sockmod_init(&server);

    if (exit)
    {
        // @todo Call modeperf_call() instead.
        threadpool_wake(&mode->threadpool);
    }
    else
    {
        tid = threadpool_getid(&mode->threadpool);
        logger_printf(LOGGER_LEVEL_INFO,
                      "Accepting sockets on thread id %u\n",
                      tid);
    }

    while ((!exit) && (threadobj_isrunning(thread)))
    {
        if (sock == NULL)
        {
            sock = UTILMEM_CALLOC(struct sockobj,
                                  sizeof(struct sockobj),
                                  1);
        }

        if (sock == NULL)
        {
            logger_printf(LOGGER_LEVEL_ERROR,
                          "%s: failed to allocate memory\n",
                          __FUNCTION__);
        }
        else if (server.ops.sock_accept(&server, sock))
        {
            if (sock != NULL)
            {
                if ((mode->args.maxcon > 0) &&
                    (acceptsocks == mode->args.maxcon))
                {
                    logger_printf(LOGGER_LEVEL_INFO,
                                  "%s: rejected socket on queue %u\n",
                                  __FUNCTION__,
                                  qid);
                    sock->ops.sock_close(sock);
                    sock->ops.sock_destroy(sock);
                    continue;
                }
                else
                {
                    logger_printf(LOGGER_LEVEL_INFO,
                                  "%s: accepted socket on queue %u\n",
                                  __FUNCTION__,
                                  qid);
                }

                mutexobj_lock(&mode->mtxarr[qid]);

                if (dlist_inserttail(&mode->sockq[qid], sock))
                {
                    sock = NULL;
                }
                else
                {
                    sock->ops.sock_close(sock);
                    sock->ops.sock_destroy(sock);
                }

                mutexobj_unlock(&mode->mtxarr[qid]);
                // @todo Use semaphore instead since thread being signaled
                //       may not be blocking waiting for a signal.
                cvobj_signalone(&mode->cvarr[qid]);

                if (sock == NULL)
                {
                    acceptsocks++;
                    qid = acceptsocks % mode->args.threads;
                }
            }
        }
        else if (server.event.revents & FIONOBJ_REVENT_ERROR)
        {
            server.ops.sock_close(&server);
            server.ops.sock_destroy(&server);
            exit = true;
        }
        else
        {
            activesocks = 0;

            for (i = 0; i < mode->args.threads; i++)
            {
                mutexobj_lock(&mode->mtxarr[i]);
                activesocks += mode->activesocks[i];
                mutexobj_unlock(&mode->mtxarr[i]);
            }

            if (activesocks == 0)
            {
                acceptsocks = 0;
            }
        }
    }

    if (sock != NULL)
    {
        UTILMEM_FREE(sock);
        sock = NULL;
    }

    logger_printf(LOGGER_LEVEL_INFO,
                  "Finished accepting sockets on thread id %u\n",
                  tid);

    return NULL;
}

/**
 * @brief A scheduler that connects new sockets and inserts them into queue(s)
 *        based on a round-robin algorithm.
 *
 * @param[in,out] arg A pointer to a mode object.
 *
 * @return NULL.
 */
static void *modeperf_connectorthread(void *arg)
{
    struct modeobj_priv *mode = (struct modeobj_priv*)arg;
    struct threadobj *thread = threadpool_getthread(&mode->threadpool);
    struct sockobj *sock = NULL;
    uint32_t connectsocks = 0, i = 0, qid = 0, tid = 0;

    tid = threadpool_getid(&mode->threadpool);
    logger_printf(LOGGER_LEVEL_INFO,
                  "Connecting sockets on thread id %u\n",
                  tid);

    for (i = 0;
         (threadobj_isrunning(thread)) &&
         (i < mode->args.maxcon);
         i++)
    {
        if (sock == NULL)
        {
            sock = UTILMEM_CALLOC(struct sockobj,
                                  sizeof(struct sockobj),
                                  1);
        }

        if (sock == NULL)
        {
            logger_printf(LOGGER_LEVEL_ERROR,
                          "%s: failed to allocate memory\n",
                          __FUNCTION__);
        }
        else
        {
            modeperf_copy(mode, sock, 0);

            if (!sockmod_init(sock))
            {
                break; // @todo Only for multiple connections?
            }
            else
            {
                sock->ops.sock_connect(sock);
                logger_printf(LOGGER_LEVEL_INFO,
                              "%s: connected socket on queue %u\n",
                              __FUNCTION__,
                              qid);

                mutexobj_lock(&mode->mtxarr[qid]);

                if (!dlist_inserttail(&mode->sockq[qid], sock))
                {
                    logger_printf(LOGGER_LEVEL_ERROR,
                                  "%s: failed to store allocated memory\n",
                                  __FUNCTION__);

                    sock->ops.sock_close(sock);
                    sock->ops.sock_destroy(sock);
                }
                else
                {
                    if (connectsocks < mode->args.threads)
                    {
                        mode->configsocks[qid] = 1;
                    }
                    else
                    {
                        mode->configsocks[qid]++;
                    }

                    utilstring_concat(mode->workerstats[qid].addrself.sockaddrstr,
                                      sizeof(mode->workerstats[qid].addrself.sockaddrstr),
                                      "%s:*",
                                      sock->conf.ipaddr);
                    utilstring_concat(mode->workerstats[qid].addrpeer.sockaddrstr,
                                      sizeof(mode->workerstats[qid].addrpeer.sockaddrstr),
                                      "%s:%u",
                                      sock->conf.ipaddr, sock->conf.ipport);

                    sock = NULL;
                }

                mutexobj_unlock(&mode->mtxarr[qid]);
                // @todo Use semaphore instead since thread being signaled
                //       may not be blocking waiting for a signal.
                cvobj_signalone(&mode->cvarr[qid]);

                if (sock == NULL)
                {
                    connectsocks++;
                    qid = connectsocks % mode->args.threads;
                }
            }
        }
    }

    if (sock != NULL)
    {
        UTILMEM_FREE(sock);
        sock = NULL;
    }

    for (i = 0; i < mode->args.threads; i++)
    {
        if (mode->configsocks[i] == 0xFFFFFFFF)
        {
            mode->configsocks[i] = 0;
        }
    }

    logger_printf(LOGGER_LEVEL_INFO,
                  "Finished connecting sockets on thread id %u\n",
                  tid);

    return NULL;
}

/**
 * @brief A socket statistics reporter.
 *
 * @param[in,out] arg A pointer to a mode object.
 *
 * @return NULL.
 */
static void *modeperf_reporterthread(void *arg)
{
    struct modeobj_priv *mode = (struct modeobj_priv*)arg;
    struct threadobj *thread = threadpool_getthread(&mode->threadpool);
    struct sockobj stats;
    struct formobj form;
    bool exit = false, active = false;
    uint32_t activesocks, configsocks, closedsocks, i;
    int32_t formbytes;
    uint64_t tvus;
    // @todo Use a tree that contains total socket stats that can be broken down
    //       by thread and by individual port numbers.
    logger_printf(LOGGER_LEVEL_INFO,
                  "Started reporting sockets on thread id %u\n",
                  threadpool_getid(&mode->threadpool));

    memset(&stats, 0, sizeof(stats));
    memset(&form, 0, sizeof(form));
    modeperf_copy(mode, &stats, 0);
    formperf_create(&form, 4096);

    stats.tid = mode->args.threads;

    for (i = 0; i < mode->args.threads; i++)
    {
        formperf_create(&mode->workerforms[i], 4096);
        modeperf_copy(mode, &mode->workerstats[i], 0);
        mode->workerforms[i].sock = &mode->workerstats[i];
        mode->workerforms[i].intervalusec = mode->args.intervalusec;
        mode->workerstats[i].tid = i;
    }

    while (!exit && threadobj_isrunning(thread))
    {
        activesocks = 0;
        closedsocks = 0;
        configsocks = 0;
        stats.cpu.usage = 0;

        for (i = 0; i < mode->args.threads; i++)
        {
            mutexobj_lock(&mode->mtxarr[i]);
            activesocks += mode->activesocks[i];
            closedsocks += mode->closedsocks[i];
            configsocks += mode->configsocks[i];
            stats.conf.datalimitbyte = mode->args.datalimitbyte * configsocks;
            stats.cpu.usage += mode->workerstats[i].cpu.usage;
            mutexobj_unlock(&mode->mtxarr[i]);
        }

        logger_printf(LOGGER_LEVEL_INFO,
                      "%s: socket counts: active %u closed %u config %u\n",
                      __FUNCTION__,
                      activesocks,
                      closedsocks,
                      configsocks);

        stats.sid = activesocks;

        if ((!active) && (activesocks > 0))
        {
            mutexobj_lock(&mode->mtxarr[0]);
            if (mode->activesocks[i])
            {
                formbytes = mode->workerforms[0].ops.form_head(&mode->workerforms[0]);
                output_if_std_send(mode->workerforms[0].dstbuf, formbytes);
            }
            mutexobj_unlock(&mode->mtxarr[0]);
        }
        else if ((active) && (activesocks == 0))
        {
            tvus = utildate_gettstime(DATE_CLOCK_MONOTONIC, UNIT_TIME_USEC);
            stats.info.recv.buflen.sum = 0;
            stats.info.send.buflen.sum = 0;
            for (i = 0; i < mode->args.threads; i++)
            {
                mutexobj_lock(&mode->mtxarr[i]);
                if (mode->workerstats[i].info.startusec > 0)
                {
                    if ((stats.info.startusec == 0) ||
                        (stats.info.startusec > mode->workerstats[i].info.startusec))
                    {
                        if (mode->workerstats[i].info.startusec > 0)
                        {
                            stats.info.startusec = mode->workerstats[i].info.startusec;
                        }
                    }
                    if (stats.info.stopusec < mode->workerstats[i].info.stopusec)
                    {
                        stats.info.stopusec = mode->workerstats[i].info.stopusec;
                    }
                    stats.info.recv.buflen.sum += mode->workerstats[i].info.recv.buflen.sum;
                    stats.info.send.buflen.sum += mode->workerstats[i].info.send.buflen.sum;

                    formbytes = mode->workerforms[i].ops.form_foot(&mode->workerforms[i]);
                    output_if_std_send(mode->workerforms[i].dstbuf, formbytes);
                    memset(&mode->workerstats[i].info, 0, sizeof(mode->workerstats[i].info));
                }
                mutexobj_unlock(&mode->mtxarr[i]);
            }

            if (stats.info.startusec > 0)
            {
                form.sock = &stats;
                form.tsus = tvus;
                form.intervalusec = mode->args.intervalusec;
                formbytes = form.ops.form_foot(&form);
                output_if_std_send(form.dstbuf, formbytes);
                memset(&stats.info, 0, sizeof(stats.info));
            }
        }

        active = (activesocks > 0);

        if (active)
        {
            tvus = utildate_gettstime(DATE_CLOCK_MONOTONIC, UNIT_TIME_USEC);
            stats.info.recv.buflen.sum = 0;
            stats.info.send.buflen.sum = 0;
            for (i = 0; i < mode->args.threads; i++)
            {
                mutexobj_lock(&mode->mtxarr[i]);
                if (mode->activesocks[i] > 0)
                {
                    mode->workerforms[i].tsus = tvus;
                    formbytes = mode->workerforms[i].ops.form_body(&mode->workerforms[i]);
                    output_if_std_send(mode->workerforms[i].dstbuf, formbytes);
                    if ((stats.info.startusec == 0) ||
                        (stats.info.startusec > mode->workerstats[i].info.startusec))
                    {
                        if (mode->workerstats[i].info.startusec > 0)
                        {
                            stats.info.startusec = mode->workerstats[i].info.startusec;
                        }
                    }
                    stats.info.recv.buflen.sum += mode->workerstats[i].info.recv.buflen.sum;
                    stats.info.send.buflen.sum += mode->workerstats[i].info.send.buflen.sum;
                }
                mutexobj_unlock(&mode->mtxarr[i]);
            }

            if (stats.info.startusec > 0)
            {
                form.sock = &stats;
                form.tsus = tvus;
                form.intervalusec = mode->args.intervalusec;
                formbytes = form.ops.form_body(&form);
                if ((formbytes > 0) && (formbytes < form.dstlen))
                {
                    *(char*)(form.dstbuf + formbytes)     = '\n';
                    *(char*)(form.dstbuf + formbytes + 1) = '\0';
                    formbytes++;
                }
                output_if_std_send(form.dstbuf, formbytes);
            }
        }
        else
        {
            switch (mode->args.arch)
            {
                case SOCKOBJ_MODEL_CLIENT:
                    if ((activesocks == 0) && (closedsocks == configsocks))
                    {
                        exit = true;
                    }
                    break;
                case SOCKOBJ_MODEL_SERVER:
                    mutexobj_lock(&mode->mtxarr[0]);
                    formbytes = formobj_idle(&mode->workerforms[0]);
                    output_if_std_send(mode->workerforms[0].dstbuf, formbytes);
                    formbytes = utilstring_concat(mode->workerforms[0].dstbuf,
                                                  mode->workerforms[0].dstlen,
                                                  "%c",
                                                  '\r');
                    output_if_std_send(mode->workerforms[0].dstbuf, formbytes);
                    mutexobj_unlock(&mode->mtxarr[0]);
                    break;
                default:
                    exit = true;
                    break;
            }
        }

        threadobj_sleepusec(1000000);
    }

    for (i = 0; i < mode->args.threads; i++)
    {
        mode->workerforms[i].ops.form_destroy(&mode->workerforms[i]);
    }

    logger_printf(LOGGER_LEVEL_INFO,
                  "Finished reporting sockets on thread id %u\n",
                  threadpool_getid(&mode->threadpool));

    return NULL;
}

/**
 * @brief Perform a performance mode task.
 *
 * @param[in,out] arg A pointer to a mode object.
 *
 * @return NULL.
 */
static void *modeperf_workerthread(void *arg)
{
    struct modeobj_priv *mode = (struct modeobj_priv*)arg;
    struct threadobj *thread = threadpool_getthread(&mode->threadpool);
    bool exit = true;
    struct fionobj fion;
    struct dlist list;
    struct sockobj *sock = NULL;
    uint8_t *recvbuf = NULL, *sendbuf = NULL;
    int32_t recvbytes = 0, sendbytes = 0;
    uint32_t count = 0, tid = 0;

    struct dlist_node *next = NULL, *node = NULL;
    struct sockobj_flowstats *stats = NULL;
    struct utilcpu_info info;
    uint64_t delayus = 0, mindelayus = 0;
    uint64_t tsus = 0;
    uint32_t burstlimit = mode->args.backlog <= 0 ? SOMAXCONN : mode->args.backlog;
    uint32_t burst = 0;
    memset(&fion, 0, sizeof(fion));

    tid = threadpool_getid(&mode->threadpool);
    logger_printf(LOGGER_LEVEL_INFO,
                  "Working sockets on thread id %u\n",
                  tid);

    if (!fionpoll_create(&fion))
    {
        // Do nothing.
    }
    else if ((recvbuf = UTILMEM_CALLOC(uint8_t,
                                       sizeof(uint8_t),
                                       mode->args.buflen)) == NULL)
    {
        logger_printf(LOGGER_LEVEL_ERROR,
                      "%s: receive buffer allocation failed\n",
                      __FUNCTION__);
    }
    else if ((sendbuf = UTILMEM_CALLOC(uint8_t,
                                       sizeof(uint8_t),
                                       mode->args.buflen)) == NULL)
    {
        logger_printf(LOGGER_LEVEL_ERROR,
                      "%s: send buffer allocation failed\n",
                      __FUNCTION__);

        UTILMEM_FREE(recvbuf);
        recvbuf = NULL;
    }
    else
    {
        exit = false;
        fion.timeoutms = 0;
        fion.pevents = FIONOBJ_PEVENT_IN;
        memset(&list, 0, sizeof(list));

        while ((!exit) && (threadobj_isrunning(thread)))
        {
            burst = count;

            while ((!exit) && ((count - burst) < burstlimit))
            {
                if ((sock = modeperf_getsock(mode,
                                             tid,
                                             list.size > 0 ? 0 : 500,
                                             &exit)) != NULL)
                {
                    dlist_inserttail(&list, sock);
                    if ((mode->args.maxcon == 0) ||
                        (list.size <= mode->args.maxcon))
                    {
                        fion.ops.fion_insertfd(&fion, sock->fd);
                        mutexobj_lock(&mode->mtxarr[tid]);
                        mode->workerstats[tid].sid = ++count;
                        mutexobj_unlock(&mode->mtxarr[tid]);
                        //??sock->sid = ++count;
                        sock->tid = tid;
                        sock->event.timeoutms = 0;

                        if (list.size == 1)
                        {
                            mutexobj_lock(&mode->mtxarr[tid]);
                            mode->workerstats[tid].info.startusec = sock->info.startusec;
                            mutexobj_unlock(&mode->mtxarr[tid]);
                        }
                    }
                    else
                    {
                        // Refuse connection.
                        sock->ops.sock_close(sock);
                        sock->ops.sock_destroy(sock);
                        modeperf_retsock(mode, list.tail->val, tid);
                        dlist_removetail(&list);
                        sock = NULL;
                    }
                }
                else
                {
                    break;
                }
            }

            node = list.head;

            while (node != NULL)
            {
                sock = node->val;

                // @todo Perform once per iteration?
                tsus = utildate_gettstime(DATE_CLOCK_MONOTONIC, UNIT_TIME_USEC);

                if (mode->args.arch == SOCKOBJ_MODEL_CLIENT)
                {
                    stats = &sock->info.send;

                    if ((sock->state & SOCKOBJ_STATE_CONNECT) == 0)
                    {
                        sock->ops.sock_connect(sock);
                        sendbytes = 0;
                    }
                    else
                    {
                        sendbytes = modeperf_call(mode,
                                                  sock->ops.sock_send,
                                                  &sock->info.send,
                                                  sock,
                                                  sendbuf,
                                                  mindelayus > 0 ? 0 : mode->args.buflen,
                                                  tsus);
                    }

                    if (sendbytes > 0)
                    {
                        mutexobj_lock(&mode->mtxarr[tid]);
                        mode->workerstats[tid].info.send.buflen.sum += sendbytes;
                        mutexobj_unlock(&mode->mtxarr[tid]);
                    }

                    if ((sock->state & SOCKOBJ_STATE_CLOSE) == 0)
                    {
                        // Prevent thread spin when no bytes are available.
                        if (sendbytes == 0)
                        {
                            if (sock->tb.rate > 0)
                            {
                                delayus = tokenbucket_delay(&sock->tb,
                                                            mode->args.buflen * 8);

                                if ((delayus < mindelayus) || (mindelayus == 0))
                                {
                                    mindelayus = delayus;
                                }
                            }
                            else
                            {
                                fion.timeoutms++;
                                fion.pevents = FIONOBJ_PEVENT_OUT;
                            }
                        }
                        else
                        {
                            fion.timeoutms = 0;
                            fion.pevents = FIONOBJ_PEVENT_IN;
                        }
                    }
                }
                else
                {
                    stats = &sock->info.recv;

                    recvbytes = modeperf_call(mode,
                                              sock->ops.sock_recv,
                                              &sock->info.recv,
                                              sock,
                                              recvbuf,
                                              mindelayus > 0 ? 0 : mode->args.buflen,
                                              tsus);

                    if (recvbytes > 0)
                    {
                        mutexobj_lock(&mode->mtxarr[tid]);
                        mode->workerstats[tid].info.recv.buflen.sum += recvbytes;
                        mutexobj_unlock(&mode->mtxarr[tid]);
                    }

                    if ((sock->state & SOCKOBJ_STATE_CLOSE) == 0)
                    {
                        // Prevent thread spin when no bytes are available.
                        if (recvbytes == 0)
                        {
                            if (sock->tb.rate > 0)
                            {
                                delayus = tokenbucket_delay(&sock->tb,
                                                            mode->args.buflen * 8);

                                if ((delayus < mindelayus) || (mindelayus == 0))
                                {
                                    mindelayus = delayus;
                                }
                            }
                            else
                            {
                                fion.timeoutms++;
                            }
                        }
                        else
                        {
                            fion.timeoutms = 0;
                        }
                    }
                }

                if (sock->state & SOCKOBJ_STATE_CLOSE)
                {
                    if (list.size == 1)
                    {
                        mutexobj_lock(&mode->mtxarr[tid]);
                        mode->workerstats[tid].info.stopusec = sock->info.stopusec;
                        mutexobj_unlock(&mode->mtxarr[tid]);
                    }

                    utilcpu_getinfo(&info);
                    logger_printf(LOGGER_LEVEL_DEBUG,
                                  "%s: tid: %u cpu load: %d usr/sys time sec: %u.%06u / %u.%06u\n",
                                  __FUNCTION__,
                                  tid,
                                  info.usage,
                                  info.usrtime.tv_sec,
                                  info.usrtime.tv_usec,
                                  info.systime.tv_sec,
                                  info.systime.tv_usec);
                    logger_printf(LOGGER_LEVEL_INFO,
                                  "%s: buflen avg/min/max: %" PRIi64
                                  " / %" PRIi64
                                  " / %" PRIi64 "\n",
                                  __FUNCTION__,
                                  stats->buflen.avg,
                                  stats->buflen.min,
                                  stats->buflen.max);

                    next = node->next;
                    modeperf_retsock(mode, node->val, tid);
                    dlist_remove(&list, node);
                    node = next;
                    fion.ops.fion_deletefd(&fion, sock->fd);

                    if (list.size == 0)
                    {
                        count = 0;

                        if (mode->args.arch == SOCKOBJ_MODEL_CLIENT)
                        {
                            exit = true;
                        }
                    }
                }
                else
                {
                    node = node->next;
                }
            }

            if (mindelayus > 0)
            {
                // @todo Replace with semaphore.
                if (mindelayus > 100000)
                {
                    //usleep(100000);
                    mindelayus -= 100000;
                }
                else
                {
                    usleep((uint32_t)mindelayus);
                    mindelayus = 0;
                }
            }
            else if ((list.size > 0) && ((uint32_t)fion.timeoutms == list.size))
            {
                fion.timeoutms = 1;
                fion.ops.fion_setflags(&fion);
                fion.ops.fion_poll(&fion);
                fion.timeoutms = 0;
            }

            mutexobj_lock(&mode->mtxarr[tid]);
            mode->workerstats[tid].cpu.startusec = mode->workerstats[tid].info.startusec;
            utilcpu_getinfo(&mode->workerstats[tid].cpu);
            mutexobj_unlock(&mode->mtxarr[tid]);
        }

        UTILMEM_FREE(recvbuf);
        UTILMEM_FREE(sendbuf);
        fionpoll_destroy(&fion);
    }

    logger_printf(LOGGER_LEVEL_INFO,
                  "Finished working sockets on thread id %u\n",
                  tid);

    return NULL;
}

bool modeperf_start(struct modeobj * const mode)
{
    bool ret = false;
    uint32_t i;

    if (UTILDEBUG_VERIFY((mode != NULL) && (mode->priv != NULL)))
    {
        threadpool_stop(&mode->priv->threadpool);
        ret = threadpool_start(&mode->priv->threadpool);

        for (i = 0; i < mode->priv->args.threads; i++)
        {
            mode->priv->configsocks[i] = 0xFFFFFFFF;
            ret &= threadpool_execute(&mode->priv->threadpool,
                                      modeperf_workerthread,
                                      mode->priv,
                                      i);
        }

        ret &= threadpool_execute(&mode->priv->threadpool,
                                  modeperf_reporterthread,
                                  mode->priv,
                                  mode->priv->args.threads);

        switch (mode->priv->args.arch)
        {
            case SOCKOBJ_MODEL_CLIENT:
                ret &= threadpool_execute(&mode->priv->threadpool,
                                          modeperf_connectorthread,
                                          mode->priv,
                                          mode->priv->args.threads + 1);
                break;
            case SOCKOBJ_MODEL_SERVER:
                ret &= threadpool_execute(&mode->priv->threadpool,
                                          modeperf_acceptorthread,
                                          mode->priv,
                                          mode->priv->args.threads + 1);
                break;
            default:
                break;
        }

        threadpool_wait(&mode->priv->threadpool, mode->priv->args.threads + 2);
    }

    return ret;
}

bool modeperf_stop(struct modeobj * const mode)
{
    bool ret = false;
    uint32_t i;

    if (UTILDEBUG_VERIFY((mode != NULL) && (mode->priv != NULL)))
    {
        ret  = mode->ops.mode_cancel(mode);
        ret &= threadpool_stop(&mode->priv->threadpool);

        for (i = 0; i < mode->priv->args.threads; i++)
        {
            while (mode->priv->sockq[i].size > 0)
            {
                dlist_removehead(&mode->priv->sockq[i]);
            }
        }
    }

    return ret;
}

bool modeperf_cancel(struct modeobj * const mode)
{
    bool ret = false;

    if (UTILDEBUG_VERIFY((mode != NULL) && (mode->priv != NULL)))
    {
        ret = threadpool_wake(&mode->priv->threadpool);
    }

    return ret;
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<title>com.pcloud.networking.serialization.adapters</title>
    <meta name="date" content="2020-07-29">
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">

com.pcloud.networking.serialization.adapters

Classes

TimestampDateTypeAdapter

TimestampDateTypeAdapterFactory

redpajama_set_name: RedPajamaGithub


text:
#ifndef VKERNEL_KERNEL_SIGNAL
#define VKERNEL_KERNEL_SIGNAL

enum signal_mask {
	// Error Signal. Will eventually raise a panic.
	SIGFATAL = 0xFFFFFFFF,

	// Interrupt Delivered Signals
	SIGIRQ = 1 << 1,
	SIGTICK = 1 << 2,
	SIGKEY = 1 << 3,
	SIGFDC = 1 << 4,
};

struct signal {
	enum signal_mask mask;
	void *info;
};

typedef void(*signal_callback_t)(struct signal *recv);

void signal_add_listener(const char *name,
						 enum signal_mask mask,
						 signal_callback_t fn);

void signal(struct signal *s);
void raise(enum signal_mask sig, void *info);

#endif


text:
const concurrently = require('concurrently');
const { readdirSync } = require('fs');

const { argv } = process;
// eslint-disable-next-line no-unused-vars
const [node, path, ...packages] = argv;
const isDebug = process.env.NODE_ENV !== 'production';
const cmd = isDebug ? 'build:dev' : 'build';
const allPackages = readdirSync('./packages');
const firstToGo = ['core'];
const lastToGo = ['toolkit', 'keeper'];

const execute = ((packages && packages.length) ? packages.filter((p) => (allPackages.indexOf(p) >= 0)) : allPackages).sort((a, b) => {
  if (firstToGo.indexOf(a) >= 0 || lastToGo.indexOf(b) >= 0) {
    return -1;
  }
  if (lastToGo.indexOf(a) >= 0 || firstToGo.indexOf(b) >= 0) {
    return 1;
  }
  return a.localeCompare(b);
});

// eslint-disable-next-line no-console
console.log(`\x1b[30m\x1b[47m Watching libs in following order \x1b[31m`, execute.join('->'), '\x1b[0m');

if (execute && execute.length) {
  const commands = execute.map(module=>({command: `npx lerna run watch --scope=@spiral-toolkit/${module} --stream`, name: module}));
  concurrently(commands, {prefix: '{name}:{time}'});
} else {
  // eslint-disable-next-line no-console
  console.log('No package names specified or specified only invalid names');
}


text:
<?php

namespace SilverStripe\Comments\Forms;

use SilverStripe\Comments\Controllers\CommentingController;
use SilverStripe\Comments\Model\Comment;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\EmailField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\Forms\TextareaField;
use SilverStripe\Forms\TextField;
use SilverStripe\Security\Security;

class CommentForm extends Form
{
    /**
     * @param string $name
     * @param CommentingController $controller
     */
    public function __construct($name, CommentingController $controller)
    {
        $usePreview = $controller->getOption('use_preview');
        $nameRequired = _t('CommentInterface.YOURNAME_MESSAGE_REQUIRED', 'Please enter your name');
        $emailRequired = _t('CommentInterface.EMAILADDRESS_MESSAGE_REQUIRED', 'Please enter your email address');
        $emailInvalid = _t('CommentInterface.EMAILADDRESS_MESSAGE_EMAIL', 'Please enter a valid email address');
        $urlInvalid = _t('CommentInterface.COMMENT_MESSAGE_URL', 'Please enter a valid URL');
        $commentRequired = _t('CommentInterface.COMMENT_MESSAGE_REQUIRED', 'Please enter your comment');

        $fields = FieldList::create(
            $dataFields = CompositeField::create(
                // Name
                $a = TextField::create('Name', _t('CommentInterface.YOURNAME', 'Your name'))
                    ->setCustomValidationMessage($nameRequired)
                    ->setAttribute('data-msg-required', $nameRequired),
                // Email
                EmailField::create(
                    'Email',
                    _t(
                        'SilverStripe\\Comments\\Controllers\\CommentingController.EMAILADDRESS',
                        'Your email address (will not be published)'
                    )
                )
                    ->setCustomValidationMessage($emailRequired)
                    ->setAttribute('data-msg-required', $emailRequired)
                    ->setAttribute('data-msg-email', $emailInvalid)
                    ->setAttribute('data-rule-email', true),
                // Url
                TextField::create('URL', _t(
                    'SilverStripe\\Comments\\Controllers\\CommentingController.WEBSITEURL',
                    'Your website URL'
                ))
                    ->setAttribute('data-msg-url', $urlInvalid)
                    ->setAttribute('data-rule-url', true),
                // Comment
                TextareaField::create('Comment', _t(
                    'SilverStripe\\Comments\\Controllers\\CommentingController.COMMENTS',
                    'Comments'
                ))
                    ->setCustomValidationMessage($commentRequired)
                    ->setAttribute('data-msg-required', $commentRequired)
            ),
            HiddenField::create('ParentID'),
            HiddenField::create('ParentClassName'),
            HiddenField::create('ReturnURL'),
            HiddenField::create('ParentCommentID')
        );

        // Preview formatted comment. Makes most sense when shortcodes or
        // limited HTML is allowed. Populated by JS/Ajax.
        if ($usePreview) {
            $fields->insertAfter(
                ReadonlyField::create('PreviewComment', _t('CommentInterface.PREVIEWLABEL', 'Preview'))
                    ->setAttribute('style', 'display: none'), // enable through JS
                'Comment'
            );
        }

        $dataFields->addExtraClass('data-fields');

        // save actions
        $actions = FieldList::create(
            $postAction = new FormAction('doPostComment', _t('CommentInterface.POST', 'Post'))
        );

        if ($usePreview) {
            $actions->push(
                FormAction::create('doPreviewComment', _t('CommentInterface.PREVIEW', 'Preview'))
                    ->addExtraClass('action-minor')
                    ->setAttribute('style', 'display: none') // enable through JS
            );
        }

        $required = RequiredFields::create(
            $controller->config()->required_fields
        );

        parent::__construct($controller, $name, $fields, $actions, $required);

        // if the record exists load the extra required data
        if ($record = $controller->getOwnerRecord()) {
            // Load member data
            $member = Security::getCurrentUser();
            if (($record->CommentsRequireLogin || $record->PostingRequiredPermission) && $member) {
                $fields = $this->Fields();

                $fields->removeByName('Name');
                $fields->removeByName('Email');
                $fields->insertBefore(
                    ReadonlyField::create(
                        'NameView',
                        _t('CommentInterface.YOURNAME', 'Your name'),
                        $member->getName()
                    ),
                    'URL'
                );
                $fields->push(HiddenField::create('Name', '', $member->getName()));
                $fields->push(HiddenField::create('Email', '', $member->Email));
            }

            // we do not want to read a new URL when the form has already been submitted
            // which in here, it hasn't been.
            $this->loadDataFrom([
                'ParentID'        => $record->ID,
                'ReturnURL'       => $controller->getRequest()->getURL(),
                'ParentClassName' => $controller->getParentClass()
            ]);
        }

        // Set it so the user gets redirected back down to the form upon form fail
        $this->setRedirectToFormOnValidationError(true);

        // load any data from the session
        $data = $this->getSessionData();
        if (!is_array($data)) {
            return;
        }

        // load user data from previous form request back into form.
        if (array_key_exists('UserData', $data ?? [])) {
            $formData = json_decode($data['UserData'] ?? '', true);

            $this->loadDataFrom([
                'Name' => isset($formData['Name']) ? $formData['Name'] : '',
                'URL' => isset($formData['URL']) ? $formData['URL'] : '',
                'Email' => isset($formData['Email']) ? $formData['Email'] : ''
            ]);
        }

        // allow previous value to fill if comment
        if (array_key_exists('Comment', $data ?? [])) {
            $prevComment = $data['Comment'];

            if ($prevComment && $prevComment != '') {
                $this->loadDataFrom(['Comment' => $prevComment]);
            }
        }
    }

    /**
     * @param  array $data
     * @param  Form $form
     * @return HTTPResponse
     */
    public function doPreviewComment($data, $form)
    {
        $data['IsPreview'] = 1;

        return $this->doPostComment($data, $form);
    }

    /**
     * Process which creates a {@link Comment} once a user submits a comment from this form.
     *
     * @param  array $data
     * @param  Form $form
     * @return HTTPResponse
     */
    public function doPostComment($data, $form)
    {
        // Load class and parent from data
        if (isset($data['ParentClassName'])) {
            $this->controller->setParentClass($data['ParentClassName']);
        }
        if (isset($data['ParentID']) && ($class = $this->controller->getParentClass())) {
            $this->controller->setOwnerRecord($class::get()->byID($data['ParentID']));
        }
        if (!$this->controller->getOwnerRecord()) {
            return $this->getRequestHandler()->httpError(404);
        }

        // cache users data
        $form->setSessionData([
            'UserData' => json_encode($data),
            'Comment' =>  $data['Comment']
        ]);

        // extend hook to allow extensions. Also see onAfterPostComment
        $this->controller->extend('onBeforePostComment', $form);

        // If commenting can only be done by logged in users, make sure the user is logged in
        if (!$this->controller->getOwnerRecord()->canPostComment()) {
            return Security::permissionFailure(
                $this->controller,
                _t(
                    'SilverStripe\\Comments\\Controllers\\CommentingController.PERMISSIONFAILURE',
                    "You're not able to post comments to this page. Please ensure you are logged in and have an "
                    . 'appropriate permission level.'
                )
            );
        }

        if ($member = Security::getCurrentUser()) {
            $form->Fields()->push(HiddenField::create('AuthorID', 'Author ID', $member->ID));
        }

        // What kind of moderation is required?
        switch ($this->controller->getOwnerRecord()->ModerationRequired) {
            case 'Required':
                $requireModeration = true;
                break;
            case 'NonMembersOnly':
                $requireModeration = empty($member);
                break;
            case 'None':
            default:
                $requireModeration = false;
                break;
        }

        $comment = Comment::create();
        $form->saveInto($comment);

        $comment->ParentID = $data['ParentID'];
        $comment->ParentClass = $data['ParentClassName'];

        $comment->AllowHtml = $this->controller->getOption('html_allowed');
        $comment->Moderated = !$requireModeration;

        // Save into DB, or call pre-save hooks to give accurate preview
        $usePreview = $this->controller->getOption('use_preview');
        $isPreview = $usePreview && !empty($data['IsPreview']);
        if ($isPreview) {
            $comment->extend('onBeforeWrite');
        } else {
            $comment->write();

            // extend hook to allow extensions. Also see onBeforePostComment
            $this->controller->extend('onAfterPostComment', $comment);
        }

        // we want to show a notification if comments are moderated
        if ($requireModeration && !$comment->IsSpam) {
            $this->getRequest()->getSession()->set('CommentsModerated', 1);
        }

        // clear the users comment since the comment was successful.
        if ($comment->exists()) {
            // Remove the comment data as it's been saved already.
            unset($data['Comment']);
        }

        // cache users data (name, email, etc to prepopulate on other forms).
        $form->setSessionData([
            'UserData' => json_encode($data),
        ]);

        // Find parent link
        if (!empty($data['ReturnURL'])) {
            $url = $data['ReturnURL'];
        } elseif ($parent = $comment->Parent()) {
            $url = $parent->Link();
        } else {
            return $this->controller->redirectBack();
        }

        // Given a redirect page exists, attempt to link to the correct anchor
        if ($comment->IsSpam) {
            // Link to the form with the error message contained
            $hash = $form->FormName();
        } elseif (!$comment->Moderated) {
            // Display the "awaiting moderation" text
            $hash = 'moderated';
        } else {
            // Link to the moderated, non-spam comment
            $hash = $comment->Permalink();
        }

        return $this->controller->redirect(Controller::join_links($url, "#{$hash}"));
    }
}


text:
define('dustRender', ['jquery', 'utils', 'adminLTE'], function($, utils){
    /* get parameters from query string */
    var params = utils.urlparams(window.location.href);
    var tl_paths = params['tl'].split(':');
    var data_path = params['data'];
    if (!tl_paths || !data_path) {
        console.log('no template or data to render found, will not render anything.');
        return;
    }

    /* ajax get and compile templates in order, get data to render, render the template. */
    var data_data = null, compiled = false;
    var render_tl = function(tl_path, data) {
        dust.render(tl_path, data, function(err, out) {
            if (err) {
                console.log('render template failed. err=' + err + ', template=' + tl_path);
                throw err;
            }
            $('body').html(out);
            console.log('render complete!');
            $(document).trigger('bicycle.ready');
        });
        console.log('rendering...');
    }
    var compile_tlpath = function(tl_path, next) {
        $.get(tl_path, function(data) {
            var tl_compiled = dust.compile(data, tl_path);
            console.log('compile template: ' + tl_path);
            dust.loadSource(tl_compiled);
            next();
        });
    };
    var compile_in_order = function(index) {
        compile_tlpath(tl_paths[index], function(err) {
            if(err) throw err;
            if(index < tl_paths.length - 1){
                /* call compile_in_order recursively. */
                compile_in_order(index + 1);
            } else {
                compiled = true;
                if(data_data) {
                  render_tl(tl_paths[tl_paths.length-1], data_data);
                }
            }
        });
    };
    compile_in_order(0);
    $.get(data_path, function(data) {
        if(compiled) {
            render_tl(tl_paths[tl_paths.length-1], data);
        }
        data_data = data;
    });
});

requirejs.config({
    //By default load any module IDs from js/lib
    baseUrl: window.bicycle.relativeTo + '../js',
    //except, if the module ID starts with "app",
    //load it from the js/app directory. paths
    //config is relative to the baseUrl, and
    //never includes a ".js" extension since
    //the paths config could be for a directory.
    paths: {
        //app: '../app'
        jquery: '../bower_components/jquery/jquery',
        bootstrap: '../bower_components/bootstrap/dist/js/bootstrap',
        adminLTE: 'AdminLTE/app',
        k: "../vendor/kendo-ui/src/js",
    },
    shim: {
        jquery: {
            exports: '$',
        },
        bootstrap: {
            deps: ['jquery'],
            exports: "$.fn.popover",
        }
    },
});

requirejs(['dustRender'],
function () {
    console.log('app started!');
});


text:
angular.module("commons.models").service("LoginBean", function (UserRest, Security) {

    function LoginBean() {
        this.entName = undefined;
        this.account = $.cookie("ua");
        this.password = undefined;   //加密的密码,接口中使用
        this.agent = webhelper.getAgent();
        this.clientId = webhelper.guid();
        this.domainUser = false;
        this.mode = "Quick";
    }

    LoginBean.prototype = {
        signin: function () {
            return seajs.isPrivate ? this.prilogin() : this.publogin();
        },

        prilogin: function () {
            var param = Security.getNonceDTO(this.account, this.password);
            angular.extend(param, {
                agent: this.agent,
                entName: this.entName,
                userName: this.account,
                clientId: this.clientId,
                mode: "Account"
            });

            if (this.account === 'admin' || !this.domainUser) {
                return UserRest.user.logon(param);
            } else {
                param.realPwd = this.password;
                param.mode = 'Ldap';
                return UserRest.user.logon(param);
            }
        },

        publogin: function () {
            var param = Security.getNonceDTO(this.account, this.password);
            angular.extend(param, {
                agent: this.agent,
                entName: this.entName,
                userName: this.account,
                clientId: this.clientId,
                mode: this.entName ? "Account" : "Quick"
            });

            return UserRest.user.logon(param);
        }
    };

    return LoginBean;
});


text:
namespace Durwella.UrlShortening
{
    public static class Default
    {
        public static IHashScheme HashScheme() {  return new Sha1Base64Scheme(); }
    }
}


text:
using Microsoft.Research.MultiWorldTesting.ExploreLibrary;
using Microsoft.Research.MultiWorldTesting.ExploreLibrary.SingleAction;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TestCommon
{
    public interface IVariableActionContext
    {
        int GetNumberOfActions();
    }

    public class VariableActionProvider<TContext> : INumberOfActionsProvider<TContext>
    {
        public int GetNumberOfActions(TContext context)
        {
            return ((IVariableActionContext)context).GetNumberOfActions();
        }
    }

    public class TestPolicy<TContext> : IPolicy<TContext>
    {
        public TestPolicy() : this(-1) { }

        public TestPolicy(int index)
        {
            this.index = index;
            this.ActionToChoose = uint.MaxValue;
        }

        public PolicyDecision<int> MapContext(TContext context)
        {
            return (this.ActionToChoose != uint.MaxValue) ? (int)this.ActionToChoose : 5;
        }

        public uint ActionToChoose { get; set; }
        private int index;
    }

    public class TestSimplePolicy : IPolicy<SimpleContext>
    {
        public PolicyDecision<int> MapContext(SimpleContext context)
        {
            return 1;
        }
    }

    public class StringPolicy : IPolicy<SimpleContext>
    {
        public PolicyDecision<int> MapContext(SimpleContext context)
        {
            return 1;
        }
    }

    public class TestScorer<Ctx> : IScorer<Ctx>
    {
        public TestScorer(int param, int numActions, bool uniform = true)
        {
            this.param = param;
            this.uniform = uniform;
            this.numActions = numActions;
        }

        public PolicyDecision<float[]> MapContext(Ctx context)
        {
            if (uniform)
            {
                return Enumerable.Repeat<float>(param, numActions).ToArray();
            }
            else
            {
                return Array.ConvertAll<int, float>(Enumerable.Range(param, numActions).ToArray(), Convert.ToSingle).ToArray();
            }
        }

        private int param;
        private int numActions;
        private bool uniform;
    }

    public class RegularTestContext
    {
        private int id;

        public int Id
        {
            get { return id; }
            set { id = value; }
        }

        public override string ToString()
        {
            return id.ToString();
        }
    }

    public class VariableActionTestContext : RegularTestContext, IVariableActionContext
    {
        public VariableActionTestContext(int numberOfActions)
        {
            NumberOfActions = numberOfActions;
        }

        public int GetNumberOfActions()
        {
            return NumberOfActions;
        }

        public int NumberOfActions { get; set; }
    }
}


text:
from __future__ import unicode_literals
import os

__all__ = [
    'autodiscover',
    'apps',
    'urls'
]

apps = []
urls = []

def autodiscover(import_path, app_config='Extension'):
    # Relative path to the extension's package in
    # dot notation such as 'my_app.extensions'

    global apps, urls

    extensions_dir = os.path.join(os.getcwd(), *import_path.split('.'))
    apps_ = []
    urls_ = []

    for app in os.listdir(extensions_dir):
        app_import_path = '.'.join((import_path, app))

        if not os.path.isfile(os.path.join(extensions_dir, app, 'apps.py')):
            continue

        apps_.append(
            '.'.join((app_import_path, 'apps', app_config))
        )

        if not os.path.isfile(os.path.join(extensions_dir, app, 'urls.py')):
            continue

        urls_.append(
            '.'.join((app_import_path, 'urls'))
        )

    apps = apps_
    urls = urls_


text:
using Graphic2D.Kernel.Common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace Graphic2D.Kernel.Visuals
{
    public class VisualUnion : PropertyChangeNotify, IVisualInfo
    {

        #region Internal fields

        private VisualInfo _info;
        private ReadOnlyCollection<GraphicVisual> _visualCollection;

        #endregion

        #region Properties

        public ReadOnlyCollection<GraphicVisual> VisualCollection
        {
            get { return _visualCollection; }
            set
            {
                _visualCollection = value;
                NotifyPropertyChanged(nameof(VisualCollection));
            }
        }

        // IVisualInfo interfec members

        public double Angle
        {
            get { return _info.Angle; }
            set
            {
                SetAngle(value);
                NotifyPropertyChanged(nameof(Angle));
            }
        }

        public Point Origin
        {
            get { return _info.Origin; }
            set
            {
                SetOrigin(value);
                NotifyPropertyChanged(nameof(Origin));
            }

        }

        Brush IVisualInfo.Fill => _info.Fill;

        Pen IVisualInfo.Stroke => _info.Stroke;

        Point IVisualInfo.Center => _info.Center;

        #endregion

        #region Constructors

        public VisualUnion(IList<GraphicVisual> visuals)
        {
            SetVisualCollection(visuals);
        }

        #endregion

        #region Internal methods

        internal void SetVisualCollection(IList<GraphicVisual> visuals)
        {
            if (visuals == null)
                throw new ArgumentNullException();

            _visualCollection = new ReadOnlyCollection<GraphicVisual>(visuals);
            _info = new VisualInfo() { Fill = null, Stroke = null };
            if(_visualCollection.Count == 1)
            {

            }

            switch (_visualCollection.Count)
            {
                case 0:
                    _info.Angle = 0;
                    _info.Origin = new Point(0, 0);
                    break;
                case 1:
                    _info.Angle = _visualCollection[1].Angle;
                    _info.Origin = _visualCollection[1].Origin;
                    break;
                default:

            }

        }

        internal void SetOrigin(Point origin)
        {

        }

        internal void SetAngle(double angle)
        {

        }
        #endregion

    }
}


text:
using System.Xml.XPath;

using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Installer.Packages;

#endregion

namespace DotNetNuke.Services.Installer.Dependencies
{
    using System;

    /// -----------------------------------------------------------------------------
    /// <summary>
    /// The PackageDependency determines whether the dependent package is installed
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// -----------------------------------------------------------------------------
    public class PackageDependency : DependencyBase
    {
        private string PackageName;

        public override string ErrorMessage
        {
            get
            {
                return Util.INSTALL_Package + " - " + PackageName;
            }
        }

        public override bool IsValid
        {
            get
            {
                bool _IsValid = true;

                //Get Package from DataStore
                PackageInfo package = PackageController.Instance.GetExtensionPackage(Null.NullInteger, (p) => p.Name.Equals(PackageName, StringComparison.OrdinalIgnoreCase));
                if (package == null)
                {
                    _IsValid = false;
                }
                return _IsValid;
            }
        }

        public override void ReadManifest(XPathNavigator dependencyNav)
        {
            PackageName = dependencyNav.Value;
        }
    }
}


text:
<?php

namespace UWDOEM\Person;

/**
 * Container class for person and student-specific information received from Person Web
 * Service and Student Web Service
 *
 * @method static null|Student fromUWNetID() fromUWNetID(string $uwnetid)
 *                             Queries PWS/SWS to generate a Student, given a UWNetID.
 * @method static null|Student fromUWRegID() fromUWRegID(string $uwregid)
 *                             Queries PWS/SWS to generate a Student, given a UWRegID.
 *
 * @package UWDOEM\Person
 */
class Student extends Person
{

    /** @var string */
    protected static $AFFILIATION_TYPE = "student";

    /**
     * Perform a registration search on SWS, per
     *     https://wiki.cac.washington.edu/display/SWS/Registration+Search+Resource+v5
     *
     * @param integer  $year             Numeric year between 1950 and 2100 inclusive.
     * @param string   $quarter          One of ["autumn", "winter", "spring", "summer"].
     * @param string[] $extraSearchTerms Associative array of search terms ex: ["course_number" => "100"].
     * @return mixed Associative array object of registration search results
     * @throws \Exception If provided with invalid year, invalid quarter, or invalid search terms.
     */
    public function registrationSearch($year, $quarter, array $extraSearchTerms = [])
    {

        if (is_numeric($year) === false || $year < 1950 || $year > 2100) {
            throw new \Exception("Please provide a numeric year between 1950 and 2100");
        }

        $validQuarters = ["autumn", "winter", "spring", "summer"];
        if (in_array("$quarter", $validQuarters) === false) {
            throw new \Exception("Quarter must be one of [" . implode(", ", $validQuarters) . "], case sensitive.");
        }

        $validSearchKeys = [
            "curriculum_abbreviation", "course_number", "section_id", "instructor_reg_id",
            "is_active", "verbose", "changed_since_date", "transcriptable_course", "grading_system"
        ];
        $invalidSearchKeys = array_diff(array_keys($extraSearchTerms), $validSearchKeys);
        if ($invalidSearchKeys !== []) {
            throw new \Exception("Invalid search keys [" . implode(", ", $invalidSearchKeys) . "]" .
                "provided as extra search terms. Only [" . implode(", ", $validSearchKeys) . "] allowed");
        }

        $defaultSearchTerms = [
            "curriculum_abbreviation"=> "",
            "course_number" => "",
            "section_id" => "",
        ];

        $searchTerms = array_merge($defaultSearchTerms, $extraSearchTerms);
        $searchTerms["reg_id"] = $this->getAttr("UWRegID");
        $searchTerms["year"] = $year;
        $searchTerms["quarter"] = $quarter;

        $resp = static::getStudentConnection()->execGET(
            "registration.json?" . http_build_query($searchTerms)
        );

        return static::parse($resp->getData())["Registrations"];
    }

    /**
     * @param string $identifierKey
     * @param string $identifierValue
     * @return null|Student
     * @throws \Exception If $identifierKey is not one of ["uwregid", "uwnetid", "employee_id",
     *                                                     "student_number", "student_system_key"].
     */
    public static function fromIdentifier($identifierKey, $identifierValue)
    {
        /** @var null|Person $student */
        $student = parent::fromIdentifier($identifierKey, $identifierValue);

        /** @var string[] $personKeyToStudentKey */
        $personKeyToStudentKey = [
            "uwregid" => "reg_id",
            "uwnetid" => "net_id",
            "student_number" => "student_number",
            "employee_id" => "employee_id",
            "student_system_key" => "student_system_key",
        ];

        /** @var string[] $validIdentifierKeys */
        $validIdentifierKeys = array_keys($personKeyToStudentKey);

        /** @var boolean $identifierKeyIsValid */
        $identifierKeyIsValid = in_array($identifierKey, $validIdentifierKeys);

        if ($identifierKeyIsValid === false) {
            throw new \Exception(
                "Identifier key '$identifierKey' must be one of [" . implode(", ", $validIdentifierKeys) . "]."
            );
        }

        $identifierKey = $personKeyToStudentKey[$identifierKey];

        $resp = static::getStudentConnection()->execGET(
            "person.json?$identifierKey=$identifierValue"
        );
        $resp = static::parse($resp->getData());

        if (array_key_exists("Persons", $resp) === true && sizeof($resp["Persons"]) > 0) {
            if ($student === null) {
                $student = new Student();
            }
            $student->attrs = array_merge($student->attrs, $resp["Persons"][0]);
        }

        return $student;
    }

    /**
     * @param Person $person
     * @param array  $attrs
     * @return Student
     */
    protected static function fill(Person $person, array $attrs)
    {
        if (array_key_exists('StudentPersonAffiliation', $attrs["PersonAffiliations"]) === true) {
            $attrs = array_merge(
                $attrs,
                $attrs["PersonAffiliations"]["StudentPersonAffiliation"],
                $attrs["PersonAffiliations"]["StudentPersonAffiliation"]["StudentWhitePages"]
            );
        }

        $student = parent::fill($person, $attrs);

        return $student;
    }

    /**
     * @param string $studentNumber
     * @return null|Student
     */
    public static function fromStudentNumber($studentNumber)
    {
        return static::fromIdentifier("student_number", $studentNumber);
    }
}


text:
package com.opengamma.analytics.financial.montecarlo;

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

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.interestrate.InstrumentDerivative;
import com.opengamma.analytics.financial.interestrate.InterestRateCurveSensitivity;
import com.opengamma.analytics.financial.interestrate.YieldCurveBundle;
import com.opengamma.analytics.financial.model.interestrate.HullWhiteOneFactorPiecewiseConstantInterestRateModel;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.definition.HullWhiteOneFactorPiecewiseConstantDataBundle;
import com.opengamma.analytics.math.linearalgebra.CholeskyDecompositionCommons;
import com.opengamma.analytics.math.linearalgebra.CholeskyDecompositionResult;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.analytics.math.random.RandomNumberGenerator;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;

/**
 * Monte Carlo pricing method in the hull-White one factor model.
 * The Monte Carlo is on the solution of the discount factor (not on the equation of the short rate).
 */
public class HullWhiteMonteCarloMethod extends MonteCarloMethod {

  /**
   * The decision schedule calculator (calculate the exercise dates, the cash flow dates and the reference amounts).
   */
  private static final DecisionScheduleCalculator DC = DecisionScheduleCalculator.getInstance();
  /**
   * The decision schedule derivative calculator (calculate the exercise dates, the cash flow dates, the reference amounts and the sensitivity of the reference amount to the curves).
   */
  private static final DecisionScheduleDerivativeCalculator DDC = DecisionScheduleDerivativeCalculator.getInstance();
  /**
   * The calculator from discount factors (calculate the price from simulated discount factors and the reference amounts).
   */
  private static final MonteCarloDiscountFactorCalculator MCC = MonteCarloDiscountFactorCalculator.getInstance();
  /**
   * The calculator of price and derivatives from discount factors and reference amounts.
   */
  private static final MonteCarloDiscountFactorDerivativeCalculator MCDC = MonteCarloDiscountFactorDerivativeCalculator.getInstance();
  /**
   * The Hull-White one factor model.
   */
  private static final HullWhiteOneFactorPiecewiseConstantInterestRateModel MODEL = new HullWhiteOneFactorPiecewiseConstantInterestRateModel();
  /**
   * The number of paths in one block.
   */
  private static final int BLOCK_SIZE = 1000;

  /**
   * @param numberGenerator The random number generator.
   * @param nbPath The number of paths.
   */
  public HullWhiteMonteCarloMethod(RandomNumberGenerator numberGenerator, int nbPath) {
    super(numberGenerator, nbPath);
  }

  /**
   * Computes the present value in the Hull-White one factor model by Monte-Carlo.
   * Implementation note: The total number of paths is divided in blocks of maximum size BLOCK_SIZE=1000. The Monte Carlo is run on each block and the average of each
   * block price is the total price.
   * @param instrument The swaption.
   * @param ccy The currency
   * @param dscName The discounting curve name.
   * @param hwData The Hull-White data (curves and Hull-White parameters).
   * @return The present value.
   */
  public CurrencyAmount presentValue(final InstrumentDerivative instrument, Currency ccy, final String dscName, final HullWhiteOneFactorPiecewiseConstantDataBundle hwData) {
    // TODO: remove currency and dsc curve name (should be available from the instrument)
    YieldAndDiscountCurve dsc = hwData.getCurve(dscName);
    DecisionSchedule decision = DC.visit(instrument, hwData);
    double[] decisionTime = decision.getDecisionTime();
    double[][] impactTime = decision.getImpactTime();
    int nbJump = decisionTime.length;
    double numeraireTime = decisionTime[nbJump - 1];
    double pDN = dsc.getDiscountFactor(numeraireTime);
    // Discount factor to numeraire date for rebasing.
    double[][] pDI = new double[nbJump][];
    // Initial discount factors to each impact date.
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      pDI[loopjump] = new double[impactTime[loopjump].length];
      for (int i = 0; i < impactTime[loopjump].length; i++) {
        pDI[loopjump][i] = dsc.getDiscountFactor(impactTime[loopjump][i]) / pDN;
      }
    }
    double[] gamma = new double[nbJump];
    double[][] cov = new double[nbJump][nbJump];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      gamma[loopjump] = MODEL.beta(hwData.getHullWhiteParameter(), 0.0, decisionTime[loopjump]);
      gamma[loopjump] = gamma[loopjump] * gamma[loopjump];
      cov[loopjump][loopjump] = gamma[loopjump];
      for (int j = loopjump + 1; j < nbJump; j++) {
        cov[j][loopjump] = gamma[loopjump];
        cov[loopjump][j] = gamma[loopjump];
      }
    }
    double[][] h = MODEL.volatilityMaturityPart(hwData.getHullWhiteParameter(), numeraireTime, impactTime); // jump/cf
    double[][] h2 = new double[nbJump][];
    for (int i = 0; i < nbJump; i++) {
      h2[i] = new double[h[i].length];
      for (int j = 0; j < h[i].length; j++) {
        h2[i][j] = h[i][j] * h[i][j] / 2;
      }
    }
    // To remove the 0 (fixed coupons)
    int nbZero = 0;
    while (cov[nbZero][nbZero] < 1.0E-12) {
      nbZero++;
    }
    double[][] cov2 = new double[nbJump - nbZero][nbJump - nbZero];
    for (int loopjump = 0; loopjump < nbJump - nbZero; loopjump++) {
      for (int loopjump2 = 0; loopjump2 < nbJump - nbZero; loopjump2++) {
        cov2[loopjump][loopjump2] = cov[loopjump + nbZero][loopjump2 + nbZero];
      }
    }
    CholeskyDecompositionCommons cd = new CholeskyDecompositionCommons();
    CholeskyDecompositionResult cdr2 = cd.evaluate(new DoubleMatrix2D(cov2));
    double[][] covCD2 = cdr2.getL().toArray();
    double[][] covCD = new double[nbJump][nbJump];
    for (int loopjump = 0; loopjump < nbJump - nbZero; loopjump++) {
      for (int loopjump2 = 0; loopjump2 < nbJump - nbZero; loopjump2++) {
        covCD[loopjump + nbZero][loopjump2 + nbZero] = covCD2[loopjump][loopjump2];
      }
    }
    int nbBlock = (int) Math.round(Math.ceil(getNbPath() / ((double) BLOCK_SIZE)));
    int[] nbPath2 = new int[nbBlock];
    for (int i = 0; i < nbBlock - 1; i++) {
      nbPath2[i] = BLOCK_SIZE;
    }
    nbPath2[nbBlock - 1] = getNbPath() - (nbBlock - 1) * BLOCK_SIZE;
    double[][] impactAmount = decision.getImpactAmount();
    double pv = 0;
    for (int loopblock = 0; loopblock < nbBlock; loopblock++) {
      double[][] x = getNormalArray(nbJump, nbPath2[loopblock]);
      double[][] y = new double[nbJump][nbPath2[loopblock]]; // jump/path
      for (int looppath = 0; looppath < nbPath2[loopblock]; looppath++) {
        for (int i = 0; i < nbJump; i++) {
          for (int j = 0; j < nbJump; j++) {
            y[i][looppath] += x[j][looppath] * covCD[i][j];
          }
        }
      }
      Double[][][] pD = pathGeneratorDiscount(pDI, y, h, h2, gamma);
      pv += MCC.visit(instrument, new MonteCarloDiscountFactorDataBundle(pD, impactAmount)) * nbPath2[loopblock];
    }
    pv *= pDN / getNbPath(); // Multiply by the numeraire.
    return CurrencyAmount.of(ccy, pv);
  }

  /**
   * Computes the present value curve sensitivity in the Hull-White one factor model by Monte-Carlo. The sensitivity is computed by Adjoint Algorithmic Differentiation.
   * Implementation note: The total number of paths is divided in blocks of maximum size BLOCK_SIZE=1000. The Monte Carlo is run on each block and the average of each
   * block price is the total price.
   * @param instrument The swaption.
   * @param dscName The discounting curve name.
   * @param hwData The Hull-White data (curves and Hull-White parameters).
   * @return The curve sensitivity.
   */
  public InterestRateCurveSensitivity presentValueCurveSensitivity(final InstrumentDerivative instrument, final String dscName, final HullWhiteOneFactorPiecewiseConstantDataBundle hwData) {
    YieldAndDiscountCurve dsc = hwData.getCurve(dscName);
    // TODO: remove dsc curve name
    // Forward sweep
    DecisionScheduleDerivative decision = DDC.visit(instrument, hwData);
    double[] decisionTime = decision.getDecisionTime();
    double[][] impactTime = decision.getImpactTime();
    int nbJump = decisionTime.length;
    double numeraireTime = decisionTime[nbJump - 1];
    double pDN = dsc.getDiscountFactor(numeraireTime);
    // Discount factor to numeraire date for rebasing.
    double[][] pDI = new double[nbJump][];
    // Initial discount factors to each impact date.
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      pDI[loopjump] = new double[impactTime[loopjump].length];
      for (int i = 0; i < impactTime[loopjump].length; i++) {
        pDI[loopjump][i] = dsc.getDiscountFactor(impactTime[loopjump][i]) / pDN;
      }
    }
    double[] gamma = new double[nbJump];
    double[][] cov = new double[nbJump][nbJump];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      gamma[loopjump] = MODEL.beta(hwData.getHullWhiteParameter(), 0.0, decisionTime[loopjump]);
      gamma[loopjump] = gamma[loopjump] * gamma[loopjump];
      cov[loopjump][loopjump] = gamma[loopjump];
      for (int j = loopjump + 1; j < nbJump; j++) {
        cov[j][loopjump] = gamma[loopjump];
        cov[loopjump][j] = gamma[loopjump];
      }
    }
    double[][] h = MODEL.volatilityMaturityPart(hwData.getHullWhiteParameter(), numeraireTime, impactTime); // jump/cf
    double[][] h2 = new double[nbJump][];
    for (int i = 0; i < nbJump; i++) {
      h2[i] = new double[h[i].length];
      for (int j = 0; j < h[i].length; j++) {
        h2[i][j] = h[i][j] * h[i][j] / 2;
      }
    }
    // To remove the 0 (fixed coupons)
    int nbZero = 0;
    while (cov[nbZero][nbZero] < 1.0E-12) {
      nbZero++;
    }
    double[][] cov2 = new double[nbJump - nbZero][nbJump - nbZero];
    for (int loopjump = 0; loopjump < nbJump - nbZero; loopjump++) {
      for (int loopjump2 = 0; loopjump2 < nbJump - nbZero; loopjump2++) {
        cov2[loopjump][loopjump2] = cov[loopjump + nbZero][loopjump2 + nbZero];
      }
    }
    CholeskyDecompositionCommons cd = new CholeskyDecompositionCommons();
    CholeskyDecompositionResult cdr2 = cd.evaluate(new DoubleMatrix2D(cov2));
    double[][] covCD2 = cdr2.getL().toArray();
    double[][] covCD = new double[nbJump][nbJump];
    for (int loopjump = 0; loopjump < nbJump - nbZero; loopjump++) {
      for (int loopjump2 = 0; loopjump2 < nbJump - nbZero; loopjump2++) {
        covCD[loopjump + nbZero][loopjump2 + nbZero] = covCD2[loopjump][loopjump2];
      }
    }
    int nbBlock = (int) Math.round(Math.ceil(getNbPath() / ((double) BLOCK_SIZE)));
    int[] nbPath2 = new int[nbBlock];
    for (int i = 0; i < nbBlock - 1; i++) {
      nbPath2[i] = BLOCK_SIZE;
    }
    nbPath2[nbBlock - 1] = getNbPath() - (nbBlock - 1) * BLOCK_SIZE;
    double[][] impactAmount = decision.getImpactAmount();
    double pv = 0;
    double[] pvBlock = new double[nbBlock];
    // Backward sweep (init)
    double pvBar = 1.0;
    double[] pvBlockBar = new double[nbBlock];
    for (int loopblock = 0; loopblock < nbBlock; loopblock++) {
      pvBlockBar[loopblock] = pDN / getNbPath() * pvBar;
    }
    double[][] impactAmountBar = new double[nbJump][];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      impactAmountBar[loopjump] = new double[impactAmount[loopjump].length];
    }
    // Forward sweep (end) and backward sweep (main)
    double[][] pDIBar = new double[nbJump][];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      pDIBar[loopjump] = new double[impactAmount[loopjump].length];
    }
    for (int loopblock = 0; loopblock < nbBlock; loopblock++) {
      double[][] x = getNormalArray(nbJump, nbPath2[loopblock]);
      double[][] y = new double[nbJump][nbPath2[loopblock]]; // jump/path
      for (int looppath = 0; looppath < nbPath2[loopblock]; looppath++) {
        for (int i = 0; i < nbJump; i++) {
          for (int j = 0; j < nbJump; j++) {
            y[i][looppath] += x[j][looppath] * covCD[i][j];
          }
        }
      }
      Double[][][] pD = pathGeneratorDiscount(pDI, y, h, h2, gamma);
      MonteCarloDiscountFactorDerivativeDataBundle mcdDB = new MonteCarloDiscountFactorDerivativeDataBundle(pD, impactAmount);
      pvBlock[loopblock] = MCDC.visit(instrument, mcdDB) * nbPath2[loopblock];
      pv += pvBlock[loopblock];
      // Backward sweep (in block loop)
      for (int loopjump = 0; loopjump < nbJump; loopjump++) {
        for (int loopimp = 0; loopimp < impactAmount[loopjump].length; loopimp++) {
          impactAmountBar[loopjump][loopimp] += mcdDB.getImpactAmountDerivative()[loopjump][loopimp] * nbPath2[loopblock] * pvBlockBar[loopblock];
        }
      }
      Double[][][] pDBar = new Double[nbPath2[loopblock]][nbJump][];
      for (int looppath = 0; looppath < nbPath2[loopblock]; looppath++) {
        for (int loopjump = 0; loopjump < nbJump; loopjump++) {
          pDBar[looppath][loopjump] = new Double[impactAmount[loopjump].length];
          for (int loopimp = 0; loopimp < impactAmount[loopjump].length; loopimp++) {
            pDBar[looppath][loopjump][loopimp] = mcdDB.getPathDiscountingFactorDerivative()[looppath][loopjump][loopimp] * nbPath2[loopblock] * pvBlockBar[loopblock];
          }
        }
      }
      double[][] pDIBarTemp = pathGeneratorDiscountAdjointIDF(pDI, y, h, h2, gamma, pDBar);
      for (int loopjump = 0; loopjump < nbJump; loopjump++) {
        for (int loopimp = 0; loopimp < impactAmount[loopjump].length; loopimp++) {
          pDIBar[loopjump][loopimp] += pDIBarTemp[loopjump][loopimp];
        }
      }
    }
    pv *= pDN / getNbPath(); // Multiply by the numeraire.
    // Backward sweep (end)
    double pDNBar = pv / pDN * pvBar;
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      for (int loopimp = 0; loopimp < impactTime[loopjump].length; loopimp++) {
        pDNBar += -dsc.getDiscountFactor(impactTime[loopjump][loopimp]) / (pDN * pDN) * pDIBar[loopjump][loopimp];
      }
    }
    final Map<String, List<DoublesPair>> resultMap = new HashMap<String, List<DoublesPair>>();
    final List<DoublesPair> listDiscounting = new ArrayList<DoublesPair>();
    listDiscounting.add(new DoublesPair(numeraireTime, -numeraireTime * pDN * pDNBar));
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      for (int loopimp = 0; loopimp < impactTime[loopjump].length; loopimp++) {
        listDiscounting.add(new DoublesPair(impactTime[loopjump][loopimp], -impactTime[loopjump][loopimp] * pDI[loopjump][loopimp] * pDIBar[loopjump][loopimp]));
      }
    }
    resultMap.put(dscName, listDiscounting);
    InterestRateCurveSensitivity result = new InterestRateCurveSensitivity(resultMap);
    // Adding sensitivity due to cash flow equivalent sensitivity to curves.
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      Map<Double, InterestRateCurveSensitivity> impactAmountDerivative = decision.getImpactAmountDerivative().get(loopjump);
      for (int loopimp = 0; loopimp < impactTime[loopjump].length; loopimp++) {
        InterestRateCurveSensitivity sensiCfe = impactAmountDerivative.get(impactTime[loopjump][loopimp]);
        if (!(sensiCfe == null)) { // There is some sensitivity to that cfe.
          result = result.plus(sensiCfe.multipliedBy(impactAmountBar[loopjump][loopimp]));
        }
      }
    }
    result = result.cleaned();
    return result;
  }

  /**
   * Gets a 2D-array of independent normally distributed variables.
   * @param nbJump The number of jumps.
   * @param nbPath The number of paths.
   * @return The array of variables.
   */
  private double[][] getNormalArray(int nbJump, int nbPath) {
    double[][] result = new double[nbJump][nbPath];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      result[loopjump] = getNumberGenerator().getVector(nbPath);
    }
    return result;
  }

  /**
   * Construct the discount factors on the simulated paths from the random variables and the model constants.
   * @param initDiscountFactor The initial discount factors.
   * @param y The correlated random variables. jump/path
   * @param h The H parameters. jump/cf
   * @param h2 The H^2 parameters.
   * @param gamma The gamma parameters.
   * @return The discount factor paths (path/jump/cf).
   */
  private Double[][][] pathGeneratorDiscount(double[][] initDiscountFactor, double[][] y, double[][] h, double[][] h2, double[] gamma) {
    int nbJump = y.length;
    int nbPath = y[0].length;
    Double[][][] pD = new Double[nbPath][nbJump][];
    double[] h2gamma;
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      int nbCF = h[loopjump].length;
      h2gamma = new double[nbCF];
      for (int loopcf = 0; loopcf < nbCF; loopcf++) {
        h2gamma[loopcf] = h2[loopjump][loopcf] * gamma[loopjump];
      }
      for (int looppath = 0; looppath < nbPath; looppath++) {
        pD[looppath][loopjump] = new Double[nbCF];
        for (int loopcf = 0; loopcf < nbCF; loopcf++) {
          pD[looppath][loopjump][loopcf] = initDiscountFactor[loopjump][loopcf] * Math.exp(-h[loopjump][loopcf] * y[loopjump][looppath] - h2gamma[loopcf]);
        }
      }
    }
    return pD;
  }

  /**
   * Computes the initial discount factors adjoint values with respect to the initDiscountFactor.
   * @param initDiscountFactor The initial discount factors.
   * @param y The correlated random variables.
   * @param h The H parameters.
   * @param h2 The H^2 parameters.
   * @param gamma The gamma parameters.
   * @param pDBar The simulated discount factor adjoints (path/jump/cf).
   * @return The initial discount factor adjoints (jump/cf).
   */
  private double[][] pathGeneratorDiscountAdjointIDF(double[][] initDiscountFactor, double[][] y, double[][] h, double[][] h2, double[] gamma, Double[][][] pDBar) {
    int nbJump = y.length;
    int nbPath = y[0].length;
    double[] h2gamma;
    double[][] initDiscountFactorBar = new double[nbJump][];
    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
      int nbCF = h[loopjump].length;
      h2gamma = new double[nbCF];
      for (int loopcf = 0; loopcf < nbCF; loopcf++) {
        h2gamma[loopcf] = h2[loopjump][loopcf] * gamma[loopjump];
      }
      // Backward sweep
      initDiscountFactorBar[loopjump] = new double[nbCF];
      for (int looppath = 0; looppath < nbPath; looppath++) {
        for (int loopcf = 0; loopcf < nbCF; loopcf++) {
          initDiscountFactorBar[loopjump][loopcf] += Math.exp(-h[loopjump][loopcf] * y[loopjump][looppath] - h2gamma[loopcf]) * pDBar[looppath][loopjump][loopcf];
        }
      }
    }
    return initDiscountFactorBar;
  }

  //  /**
  //   * Computes the initial discount factors adjoint values with respect to y.
  //   * @param initDiscountFactor The initial discount factors.
  //   * @param y The correlated random variables.
  //   * @param h The H parameters.
  //   * @param h2 The H^2 parameters.
  //   * @param gamma The gamma parameters.
  //   * @param pDBar The simulated discount factor adjoints (path/jump/cf).
  //   * @return The y adjoints (jump/path).
  //   */
  //  private double[][] pathGeneratorDiscountAdjointY(double[][] initDiscountFactor, double[][] y, double[][] h, double[][] h2, double[] gamma, Double[][][] pDBar) {
  //    int nbJump = y.length;
  //    int nbPath = y[0].length;
  //    double[] h2gamma;
  //    double[][] yBar = new double[nbJump][nbPath];
  //    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
  //      int nbCF = h[loopjump].length;
  //      h2gamma = new double[nbCF];
  //      for (int loopcf = 0; loopcf < nbCF; loopcf++) {
  //        h2gamma[loopcf] = h2[loopjump][loopcf] * gamma[loopjump];
  //      }
  //      // Backward sweep
  //      for (int looppath = 0; looppath < nbPath; looppath++) {
  //        for (int loopcf = 0; loopcf < nbCF; loopcf++) {
  //          y[loopjump][looppath] += initDiscountFactor[loopjump][loopcf] * Math.exp(-h[loopjump][loopcf] * y[loopjump][looppath] - h2gamma[loopcf]) * -h[loopjump][loopcf]
  //              * pDBar[looppath][loopjump][loopcf];
  //        }
  //      }
  //    }
  //    return yBar;
  //  }
  //
  //  /**
  //   * Computes the initial discount factors adjoint values with respect to gamma.
  //   * @param initDiscountFactor The initial discount factors.
  //   * @param y The correlated random variables.
  //   * @param h The H parameters.
  //   * @param h2 The H^2 parameters.
  //   * @param gamma The gamma parameters.
  //   * @param pDBar The simulated discount factor adjoints (path/jump/cf).
  //   * @return The y adjoints (jump/path).
  //   */
  //  private double[] pathGeneratorDiscountAdjointGamma(double[][] initDiscountFactor, double[][] y, double[][] h, double[][] h2, double[] gamma, Double[][][] pDBar) {
  //    int nbJump = y.length;
  //    int nbPath = y[0].length;
  //    double[] h2gamma;
  //    double[] h2gammaBar;
  //    double[] gammaBar = new double[nbJump];
  //    for (int loopjump = 0; loopjump < nbJump; loopjump++) {
  //      int nbCF = h[loopjump].length;
  //      h2gamma = new double[nbCF];
  //      for (int loopcf = 0; loopcf < nbCF; loopcf++) {
  //        h2gamma[loopcf] = h2[loopjump][loopcf] * gamma[loopjump];
  //      }
  //      // Backward sweep
  //      h2gammaBar = new double[nbCF];
  //      for (int looppath = 0; looppath < nbPath; looppath++) {
  //        for (int loopcf = 0; loopcf < nbCF; loopcf++) {
  //          h2gammaBar[loopcf] += -initDiscountFactor[loopjump][loopcf] * Math.exp(-h[loopjump][loopcf] * y[loopjump][looppath] - h2gamma[loopcf]) * pDBar[looppath][loopjump][loopcf];
  //        }
  //      }
  //      for (int loopcf = 0; loopcf < nbCF; loopcf++) {
  //        gammaBar[loopjump] += h2[loopjump][loopcf] * h2gammaBar[loopcf];
  //      }
  //    }
  //    return gammaBar;
  //  }

  @Override
  public CurrencyAmount presentValue(InstrumentDerivative instrument, YieldCurveBundle curves) {
    Validate.isTrue(curves instanceof HullWhiteOneFactorPiecewiseConstantDataBundle, "Bundle should contain Hull-White data");
    // TODO: Remove currency and dsc curve name (should be available from the instrument)
    return null;
  }

}