text:
#include "includes.h"

static int
ParseSyncRequestControlVal(
    VDIR_OPERATION *            op,
    BerValue *                  controlValue,       // Input: control value encoded as ber
    SyncRequestControlValue *   syncReqCtrlVal,     // Output
    VDIR_LDAP_RESULT *          lr                  // Output
    );

static int
_ParsePagedResultControlVal(
    VDIR_OPERATION *                    op,
    BerValue *                          controlValue,       // Input: control value encoded as ber
    VDIR_PAGED_RESULT_CONTROL_VALUE*    pageResultCtrlVal,     // Output
    VDIR_LDAP_RESULT *                  lr                  // Output
    );

/*
 * RFC 4511:
 * Section 4.1.1 Message Envelope:
 *
 *    LDAPMessage ::= SEQUENCE {
 *       messageID   MessageID,
 *       protocolOp   CHOICE {
 *          bindRequest BindRequest,
 *          bindResponse BindResponse,
 *          ... },
 *       controls [0] Controls OPTIONAL }
 *
 * Section 4.1.11 Controls:
 *
 *    Controls ::= SEQUENCE OF control Control
 *    Control ::= SEQUENCE {
 *       controlType LDAPOID,
 *       criticality BOOLEAN DEFAULT FALSE,
 *       controlValue OCTET STRING OPTIONAL }
 *
 */

int
ParseRequestControls(
   VDIR_OPERATION *    op,
   VDIR_LDAP_RESULT *  lr
   )
{
    int                     retVal = LDAP_SUCCESS;
    ber_tag_t               tag = LBER_ERROR;
    ber_len_t               len = 0;
    char *                  endOfCtrlsMarker = NULL;
    VDIR_LDAP_CONTROL **    control = &(op->reqControls);
    BerValue                lberBervType = {0};
    BerValue                lberBervCtlValue = {0};
    PSTR                    pszLocalErrorMsg = NULL;

    VmDirLog( LDAP_DEBUG_TRACE, "ParseRequestControls: Begin." );

    *control = NULL;

#ifndef _WIN32
    if (ber_pvt_ber_remaining(op->ber) != 0)
#else
    if (LBER_DEFAULT != ber_peek_tag (op->ber, &len))
#endif
    {
        if (ber_peek_tag( op->ber, &len ) != LDAP_TAG_CONTROLS )
        {
            lr->errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                           "ParseRequestControls: Request controls expected, but something else is there in the PDU.");
        }

        // Get controls. ber_first_element => skip the sequence header, set the cursor at the 1st control in the SEQ of SEQ
        for( tag = ber_first_element( op->ber, &len, &endOfCtrlsMarker ); tag != LBER_ERROR;
             tag = ber_next_element( op->ber, &len, endOfCtrlsMarker ) )
        {
            // m => in-place
            if (ber_scanf( op->ber, "{m", &lberBervType ) == LBER_ERROR)
            {
                lr->errCode = LDAP_PROTOCOL_ERROR;
                retVal = LDAP_NOTICE_OF_DISCONNECT;
                BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                              "ParseRequestControls Error in reading control type from the PDU.");
            }
            if ( VmDirLogGetMask() & LDAP_DEBUG_ARGS)
            {
                VMDIR_LOG_INFO( LDAP_DEBUG_ARGS, "    Request Control: %s", lberBervType.bv_val );
            }
            if (VmDirAllocateMemory( sizeof( VDIR_LDAP_CONTROL), (PVOID *)control ) != 0)
            {
                retVal = lr->errCode = LDAP_OPERATIONS_ERROR;
                BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                                "ParseRequestControls: VmDirAllocateMemory failed");
            }
            // type points into in-place ber and does NOT own its content
            (*control)->type = lberBervType.bv_val;
            (*control)->criticality = FALSE;
            tag = ber_peek_tag( op->ber, &len );

            if (tag == LBER_BOOLEAN)
            {
                ber_int_t criticality;
                if (ber_scanf( op->ber, "b", &criticality) == LBER_ERROR)
                {
                    lr->errCode = LDAP_PROTOCOL_ERROR;
                    retVal = LDAP_NOTICE_OF_DISCONNECT;
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                            "ParseRequestControls: Error in reading control criticality from the PDU.");
                }
                if (criticality)
                {
                    (*control)->criticality = TRUE;
                }
                tag = ber_peek_tag( op->ber, &len );
            }

            if (tag == LBER_OCTETSTRING)
            {
                if (ber_scanf( op->ber, "m", &lberBervCtlValue) == LBER_ERROR)
                {
                    lr->errCode = LDAP_PROTOCOL_ERROR;
                    retVal = LDAP_NOTICE_OF_DISCONNECT;
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                             "ParseRequestControls: ber_scanf failed while parsing the control value.");
                }
            }

            // SJ-TBD: Make sure that the control appears only once in the request, and it is present only in a search
            // request
            if (VmDirStringCompareA( (*control)->type, LDAP_CONTROL_SYNC, TRUE ) == 0)
            {
                if (VmDirdGetRunMode() != VMDIR_RUNMODE_NORMAL)
                {
                    // Why block out-bound replication when catching up during restore mode?
                    //
                    // Reason: Partners have high-water-mark (lastLocalUsn) corresponding to this replica that is being
                    // restored. If out-bound replication is not blocked while restore/catching-up is going on, originating
                    // or replicated updates (if this replica is the only partner) made between the current-local-usn and
                    // high-water-marks, that partners remember, will not get replicated out (even if the invocationId
                    // has been fixed/changed).

                    retVal = lr->errCode = LDAP_UNWILLING_TO_PERFORM;
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                 "ParseRequestControls: Server in not in normal mode, not allowing outward replication.");
                }

                if ((retVal = ParseSyncRequestControlVal( op, &lberBervCtlValue, &((*control)->value.syncReqCtrlVal),
                                                          lr)) != LDAP_SUCCESS)
                {
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                                  "ParseRequestControls: ParseSyncRequestControlVal failed.");
                }
                op->syncReqCtrl = *control;
            }
            if (VmDirStringCompareA( (*control)->type, VDIR_LDAP_CONTROL_SHOW_DELETED_OBJECTS, TRUE ) == 0)
            {
                op->showDeletedObjectsCtrl = *control;
            }

            if (VmDirStringCompareA( (*control)->type, VDIR_LDAP_CONTROL_SHOW_MASTER_KEY, TRUE ) == 0)
            {
                op->showMasterKeyCtrl = *control;
            }

            if (VmDirStringCompareA( (*control)->type, LDAP_CONTROL_PAGEDRESULTS, TRUE ) == 0)
            {
                retVal = _ParsePagedResultControlVal( op,
                                                &lberBervCtlValue,
                                                &((*control)->value.pagedResultCtrlVal),
                                                lr);
                if (retVal != LDAP_SUCCESS)
                {
                    BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                                  "ParseRequestControls: _ParsePagedResultControlVal failed.");
                }
                op->showPagedResultsCtrl = *control;
            }

            if ( ber_scanf( op->ber, "}") == LBER_ERROR ) // end of control
            {
                lr->errCode = LDAP_PROTOCOL_ERROR;
                retVal = LDAP_NOTICE_OF_DISCONNECT;
                BAIL_ON_VMDIR_ERROR_WITH_MSG( retVal, (pszLocalErrorMsg),
                                              "ParseRequestControls: ber_scanf failed while parsing the end of control");

            }
            control = &((*control)->next);
        }

        retVal = LDAP_SUCCESS;
    }

cleanup:
    VmDirLog( LDAP_DEBUG_TRACE, "ParseRequestControls: End." );
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);

    return retVal;

error:
    DeleteControls(&(op->reqControls));

    if (pszLocalErrorMsg)
    {
        VmDirLog( LDAP_DEBUG_ANY, pszLocalErrorMsg);
        VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg);
    }

    goto cleanup;
}

void
DeleteControls(
   VDIR_LDAP_CONTROL ** controls
   )
{
   VDIR_LDAP_CONTROL * curr = NULL;
   VDIR_LDAP_CONTROL * next = NULL;

   VmDirLog( LDAP_DEBUG_TRACE, "DeleteControls: Begin." );

   if (controls != NULL)
   {
      for (curr = *controls; curr != NULL; curr = next)
      {
         next = curr->next;
         VMDIR_SAFE_FREE_MEMORY( curr );
      }
      *controls = NULL;
   }

   VmDirLog( LDAP_DEBUG_TRACE, "DeleteControls: End." );
}

int
CreateSyncRequestControl(
    VMDIR_REPLICATION_AGREEMENT *   replAgr,
    LDAPControl *           syncReqCtrl
    )
{
    int                 retVal = LDAP_SUCCESS;
    BerElementBuffer    berbuf;
    BerElement *        ber = (BerElement *) &berbuf;
    ber_len_t           iSize = 0;

    VmDirLog( LDAP_DEBUG_TRACE, "CreateSyncRequestControl: Begin." );

    assert ( syncReqCtrl != NULL );

    ber_init2( ber, NULL, LBER_USE_DER );

    VmDirLog( LDAP_DEBUG_REPL, "CreateSyncRequestControl: ServerId: %s, lastLocalUsnProcessed: %s, utdVector: %s",
              gVmdirServerGlobals.invocationId.lberbv.bv_val, replAgr->lastLocalUsnProcessed.lberbv.bv_val,
              gVmdirServerGlobals.utdVector.lberbv.bv_val );

    if ( ber_printf( ber, "{i{OOO}}", REFRESH_ONLY,
                    &gVmdirServerGlobals.invocationId.lberbv,
                    &replAgr->lastLocalUsnProcessed.lberbv,
                    &gVmdirServerGlobals.utdVector.lberbv ) == -1)
    {
        VmDirLog( LDAP_DEBUG_ANY, "CreateSyncRequestControl: ber_printf (to construct Sync Request control value ...) "
                  "failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    memset( syncReqCtrl, 0, sizeof( LDAPControl ));
    syncReqCtrl->ldctl_oid = LDAP_CONTROL_SYNC;
    syncReqCtrl->ldctl_iscritical = '1';

    iSize = ber->ber_ptr - ber->ber_buf;

    if (VmDirAllocateMemory(iSize + 1, (PVOID*)&syncReqCtrl->ldctl_value.bv_val) != 0)
    {
        VmDirLog( LDAP_DEBUG_ANY, "CreateSyncRequestControl: alloc syncReqCtrl->ldctl_value failed." );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    if (VmDirCopyMemory(syncReqCtrl->ldctl_value.bv_val, iSize, ber->ber_buf, iSize) != 0)
    {
        VmDirLog( LDAP_DEBUG_ANY, "CreateSyncRequestControl: copy syncReqCtrl->ldctl_value failed." );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }
    syncReqCtrl->ldctl_value.bv_len = iSize;

cleanup:
    ber_free_buf( ber );
    VmDirLog( LDAP_DEBUG_TRACE, "CreateSyncRequestControl: End." );
    return retVal;

error:
    VMDIR_SAFE_FREE_MEMORY( syncReqCtrl->ldctl_value.bv_val );
    goto cleanup;
}

int
WriteSyncDoneControl(
    VDIR_OPERATION *     op,
    BerElement *    ber
    )
{
    int                     retVal = LDAP_OPERATIONS_ERROR;
    PLW_HASHTABLE_NODE   pNode = NULL;
    LW_HASHTABLE_ITER       iter = LW_HASHTABLE_ITER_INIT;
    UptoDateVectorEntry *   pUtdVectorEntry = NULL;
    VDIR_BERVALUE           bvCtrlVal = VDIR_BERVALUE_INIT;
    VDIR_BERVALUE           syncDoneCtrlType = {
                                {VmDirStringLenA( LDAP_CONTROL_SYNC_DONE ), LDAP_CONTROL_SYNC_DONE}, 0, 0, NULL };

    VmDirLog( LDAP_DEBUG_TRACE, "WriteSyncDoneControl: Begin." );

    if ( op->syncDoneCtrl != NULL)
    {
        if (ber_printf( ber, "t{{O", LDAP_TAG_CONTROLS, &(syncDoneCtrlType.lberbv) ) == -1 )
        {
            VmDirLog( LDAP_DEBUG_ANY, "WriteSyncDoneControl: ber_printf (to print Sync Done Control ...) failed" );
            retVal = LDAP_OPERATIONS_ERROR;
            BAIL_ON_VMDIR_ERROR( retVal );
        }
        { // Construct string format of utdVector
            int     numEntries = LwRtlHashTableGetCount( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector );
            char *  writer = NULL;
            size_t  tmpLen = 0;
            size_t bufferSize = (numEntries + 1 /* for lastLocalUsn */) *
                                (VMDIR_GUID_STR_LEN + 1 + VMDIR_MAX_USN_STR_LEN + 1);

            // Sync Done control value looks like: <lastLocalUsnChanged>,<serverId1>:<server 1 last originating USN>,
            // <serverId2>,<server 2 originating USN>,...

            if (VmDirAllocateMemory( bufferSize, (PVOID *)&bvCtrlVal.lberbv.bv_val) != 0)
            {
                retVal = LDAP_OPERATIONS_ERROR;
                BAIL_ON_VMDIR_ERROR( retVal );
            }
            writer = bvCtrlVal.lberbv.bv_val;
            bvCtrlVal.lberbv.bv_len = 0;

            VmDirStringPrintFA( writer, bufferSize, "%ld,", op->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed );
            tmpLen = VmDirStringLenA( writer );
            writer += tmpLen;
            bufferSize -= tmpLen;
            bvCtrlVal.lberbv.bv_len += tmpLen;

            while ((pNode = LwRtlHashTableIterate(op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, &iter)))
            {
                pUtdVectorEntry = LW_STRUCT_FROM_FIELD(pNode, UptoDateVectorEntry, Node);
                VmDirStringPrintFA( writer, bufferSize, "%s:%ld,", pUtdVectorEntry->invocationId.lberbv.bv_val,
                                    pUtdVectorEntry->currMaxOrigUsnProcessed );
                tmpLen = VmDirStringLenA( writer );
                writer += tmpLen;
                bufferSize -= tmpLen;
                bvCtrlVal.lberbv.bv_len += tmpLen;
            }
        }

        if (ber_printf( ber, "O}}", &bvCtrlVal.lberbv) == -1 )
        {
            VmDirLog( LDAP_DEBUG_ANY, "WriteSyncDoneControl: ber_printf (to print Sync Done Control ...) failed" );
            retVal = LDAP_OPERATIONS_ERROR;
            BAIL_ON_VMDIR_ERROR( retVal );
        }

        VmDirLog( LDAP_DEBUG_REPL, "WriteSyncDoneControl: Sync Done Control Value: %s", bvCtrlVal.lberbv.bv_val );
    }

    retVal = LDAP_SUCCESS;

cleanup:
    VMDIR_SAFE_FREE_MEMORY( bvCtrlVal.lberbv.bv_val );
    VmDirLog( LDAP_DEBUG_TRACE, "WriteSyncDoneControl: Begin." );
    return retVal;

error:
    goto cleanup;
}

int
WritePagedSearchDoneControl(
    VDIR_OPERATION *     op,
    BerElement *    ber
    )
{
    int                 retVal = LDAP_OPERATIONS_ERROR;
    BerElementBuffer    ctrlValBerbuf;
    BerElement *        ctrlValBer = (BerElement *) &ctrlValBerbuf;
    VDIR_BERVALUE       bvCtrlVal = VDIR_BERVALUE_INIT;

    if (!op || !op->showPagedResultsCtrl)
    {
        retVal = LDAP_PROTOCOL_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    if ( op->showPagedResultsCtrl)
    {
        VDIR_PAGED_RESULT_CONTROL_VALUE*    prCtrlVal = &op->showPagedResultsCtrl->value.pagedResultCtrlVal;
        VmDirLog( LDAP_DEBUG_TRACE,
                "WritePagedSearchDoneControl: Paged Search Done Control Value: pageSize[%d] cookie[%s]",
                prCtrlVal->pageSize,
                prCtrlVal->cookie );

        (void) memset( (char *)&ctrlValBerbuf, '\0', sizeof( BerElementBuffer ));
        ber_init2( ctrlValBer, NULL, LBER_USE_DER );

        if (ber_printf( ctrlValBer, "{is}", 0, prCtrlVal->cookie) == -1 )
        {
            VmDirLog( LDAP_DEBUG_ANY, "SendLdapResult: ber_printf (to print Paged Search Done Control ...) failed" );
            retVal = LDAP_OPERATIONS_ERROR;
            BAIL_ON_VMDIR_ERROR( retVal );
        }

        bvCtrlVal.lberbv.bv_val = ctrlValBer->ber_buf;
        bvCtrlVal.lberbv.bv_len = ctrlValBer->ber_ptr - ctrlValBer->ber_buf;

        if (ber_printf(ber, "t{{sO}}", LDAP_TAG_CONTROLS, LDAP_CONTROL_PAGEDRESULTS, &bvCtrlVal.lberbv ) == -1)
        {
            VmDirLog( LDAP_DEBUG_ANY, "WritePagedSearchDoneControl: ber_printf (to print Search Done Control ...) failed" );
            retVal = LDAP_OPERATIONS_ERROR;
            BAIL_ON_VMDIR_ERROR( retVal );
        }
    }

    retVal = LDAP_SUCCESS;

cleanup:
    ber_free_buf( ctrlValBer );
    return retVal;

error:
    goto cleanup;
}

/* On the wire, write the Sync State Control associated with a search result entry. Sync State Control is part of the
 * LDAP Content Synchronization protocol.
 */

int
WriteSyncStateControl(
   VDIR_OPERATION *   op,
   VDIR_ATTRIBUTE *   pAttr,
   BerElement *       ber,
   PSTR*              ppszErrorMsg
   )
{
    int                 retVal = LDAP_SUCCESS;
    VDIR_BERVALUE       syncStateCtrlType = {
                            {VmDirStringLenA( LDAP_CONTROL_SYNC_STATE ), LDAP_CONTROL_SYNC_STATE}, 0, 0, NULL };
    int                 entryState = LDAP_SYNC_MODIFY;
    BerElementBuffer    ctrlValBerbuf;
    BerElement *        ctrlValBer = (BerElement *) &ctrlValBerbuf;
    VDIR_BERVALUE       bvCtrlVal = VDIR_BERVALUE_INIT;
    PSTR                pszLocalErrorMsg = NULL;

    VmDirLog( LDAP_DEBUG_TRACE, "WriteSyncStateControl: Begin" );

    /* Logic to determine the entry state is:
     *  Default entry state is LDAP_SYNC_MODIFY
     *
     *  If ATTR_USN_CREATED value is greater than the last local USN that the consumer has seen so far,
     *  entry state is LDAP_SYNC_ADD.
     *  Otherwise, if isDeleted=TRUE is in the replication scope, entry state is LDAP_SYNC_DELETE.
     *
     *  NOTE: The logic is based on the things (entry state + what has the consumer seen so far) seen by the supplier
     *  at this point in time. Things/state could be different at the time when consumer tries to apply this change.
     *  => may lead to various conflict resolution scenarios.
     */

    for ( ; pAttr != NULL; pAttr = pAttr->next)
    {
        if (pAttr->metaData[0] != '\0') // We are sending back this attribute's meta data. => Attribute is in
                                        // replication scope. SJ-TBD: we are overloading pAttr->metaData
                                        // field. Should we have another field (e.g. inReplScope) in Attribute
        {
            if ( VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_IS_DELETED, FALSE ) == 0 &&
                 VmDirStringCompareA( pAttr->vals[0].lberbv.bv_val, VMDIR_IS_DELETED_TRUE_STR, FALSE ) == 0)
            {
                entryState = LDAP_SYNC_DELETE;
                continue; // Look if it is LDAP_SYNC_ADD case
            }

            if (VmDirStringCompareA( pAttr->type.lberbv.bv_val, ATTR_USN_CREATED, FALSE ) == 0)
            {
                entryState = LDAP_SYNC_ADD;
                break;
            }
        }
    }

    if (ber_printf( ber, "t{{O", LDAP_TAG_CONTROLS, &(syncStateCtrlType.lberbv) ) == -1 )
    {
        VmDirLog( LDAP_DEBUG_ANY, "WriteSyncStateControl: ber_printf (to print attribute name ...) failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Encoding sync state control failed.");
    }

    ////////// Build ber for the control value

    (void) memset( (char *)&ctrlValBerbuf, '\0', sizeof( BerElementBuffer ));
    ber_init2( ctrlValBer, NULL, LBER_USE_DER );

    if (ber_printf( ctrlValBer, "{i}", entryState ) == -1 )
    {
        VmDirLog( LDAP_DEBUG_ANY, "SendLdapResult: ber_printf (to print Sync Done Control ...) failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Encoding sync state control failed.");
    }

    ////////////// Building ber for the control value done

    bvCtrlVal.lberbv.bv_val = ctrlValBer->ber_buf;
    bvCtrlVal.lberbv.bv_len = ctrlValBer->ber_ptr - ctrlValBer->ber_buf;

    if (ber_printf( ber, "O", &bvCtrlVal.lberbv ) == -1 )
    {
        VmDirLog( LDAP_DEBUG_ANY, "SendLdapResult: ber_printf (to print Sync Done Control ...) failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Encoding sync state control failed.");
    }

    if (ber_printf( ber, "}}" ) == -1 )
    {
        VmDirLog( LDAP_DEBUG_ANY, "SendLdapResult: ber_printf (to print Sync Done Control ...) failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(retVal, (pszLocalErrorMsg),
                                     "Encoding sync state control failed.");
    }

cleanup:
    ber_free_buf( ctrlValBer );

    if (ppszErrorMsg)
    {
        *ppszErrorMsg = pszLocalErrorMsg;
    }
    else
    {
        VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    }

    VmDirLog( LDAP_DEBUG_TRACE, "WriteSyncStateControl: End" );

    return( retVal );

error:

    goto cleanup;
}

int
ParseSyncStateControlVal(
    BerValue *  controlValue,   // Input: control value encoded as ber,
    int *       entryState)     // Output
{
    int                 retVal = LDAP_SUCCESS;
    BerElementBuffer    berbuf;
    BerElement *        ber = (BerElement *)&berbuf;

    VmDirLog( LDAP_DEBUG_TRACE, "ParseSyncStateControlVal: Begin." );

    ber_init2( ber, controlValue, LBER_USE_DER );

    if (ber_scanf( ber, "{i}", entryState ) == -1 )
    {
        VmDirLog( LDAP_DEBUG_ANY, "ParseSyncStateControlVal: ber_scanf to read entryState failed" );
        retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }

cleanup:
    VmDirLog( LDAP_DEBUG_TRACE, "ParseSyncStateControlVal: Begin." );
    return retVal;

error:
    goto cleanup;
}

static int
ParseSyncRequestControlVal(
    VDIR_OPERATION *            op,
    BerValue *                  controlValue,       // Input: control value encoded as ber
    SyncRequestControlValue *   syncReqCtrlVal,     // Output
    VDIR_LDAP_RESULT *          lr                  // Output
    )
{
    int                     retVal = LDAP_SUCCESS;
    ber_tag_t               tag = LBER_ERROR;
    ber_len_t               len = 0;
    UptoDateVectorEntry *   utdVectorEntry = NULL;
    BerElementBuffer        berbuf;
    BerElement *            ber = (BerElement *)&berbuf;
    PSTR                    pszLocalErrorMsg = NULL;

    VmDirLog( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: Begin." );

    ber_init2( ber, controlValue, LBER_USE_DER );

    /* http://www.rfc-editor.org/rfc/rfc4533.txt
     *
     *  syncCookie ::= OCTET STRING
     *
     *  syncRequestValue ::= SEQUENCE {
     *          mode ENUMERATED {
     *              -- 0 unused
     *              refreshOnly       (1),
     *              -- 2 reserved
     *              refreshAndPersist (3)
     *          },
     *          cookie     syncCookie OPTIONAL,
     *          reloadHint BOOLEAN DEFAULT FALSE
     *  }
    */

    if (ber_scanf( ber, "{i", &(syncReqCtrlVal->mode) ) == LBER_ERROR)
    {
        VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: ber_scanf failed while parsing the sync request "
                  "control mode" );
        lr->errCode = LDAP_PROTOCOL_ERROR;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Error in reading sync request control mode from PDU.");
    }

    syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val = "";
    syncReqCtrlVal->intLastLocalUsnProcessed = 0;

    if (VmDirAllocateMemory( sizeof( VDIR_LDAP_CONTROL ), (PVOID *)&op->syncDoneCtrl) != 0)
    {
        VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " );
        lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "ParseSyncRequestControlVal: VmDirAllocateMemory failed.");
    }
    op->syncDoneCtrl->type = LDAP_CONTROL_SYNC_DONE;
    if (LwRtlCreateHashTable( &op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector, UtdVectorEntryGetKey,
                              LwRtlHashDigestPstr, LwRtlHashEqualPstr, NULL, VMDIR_UTD_VECTOR_HASH_TABLE_SIZE ) != 0)
    {
        VmDirLog( LDAP_DEBUG_ANY, "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed" );
        lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "UpdateSyncDoneUtdVectorEntry: LwRtlCreateHashTable failed");

    }

    tag = ber_peek_tag( ber, &len );

    if (tag == LBER_SEQUENCE)
    { // syncCookie

        /* syncCookie ::= SEQUENCE {
         *                      reqServerId             LDAPString,
         *                      lastLocalUsnProcessed   INTEGER (0 .. maxInt),
         *                      utdVector               UptoDateVectorEntryList }
         *
         *   UptoDateVectorEntryList ::= SEQUENCE OF uptoDateVectorEntry UptoDateVectorEntry
         *
         *   UptoDateVectorEntry ::= SEQUENCE {
         *                            serverId              LDAPString,
         *                            lastOrigUsnProcessed  INTEGER (0 .. maxInt) }
         */
        // {lastLocalUsnProcessed{{<serverid1><lastOrigUsnProcessed1>}{<serverid2><lastOrigUsnProcessed2>}...}}

        if (ber_scanf( ber, "{mmm}",
                        &syncReqCtrlVal->reqInvocationId.lberbv,
                        &syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv,
                        &syncReqCtrlVal->bvUtdVector.lberbv ) == LBER_ERROR )
        {
            VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: ber_scanf failed while parsing "
                      "lastLocalUsnProcessed in the sync request control value" );
            lr->errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                            "Error in reading lastLocalUsnProcessed in the sync request control value");
        }

        VmDirLog( LDAP_DEBUG_REPL, "ParseSyncRequestControlVal: ServerId: %s, lastLocalUsnProcessed: %s, utdVector: %s",
                  syncReqCtrlVal->reqInvocationId.lberbv.bv_val, syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val,
                  syncReqCtrlVal->bvUtdVector.lberbv.bv_val );

        syncReqCtrlVal->intLastLocalUsnProcessed = op->syncDoneCtrl->value.syncDoneCtrlVal.intLastLocalUsnProcessed =
                                   VmDirStringToLA( syncReqCtrlVal->bvLastLocalUsnProcessed.lberbv.bv_val, NULL, 10 );
        {
            char *                  nextServerIdStr = NULL;
            char *                  nextOrigUsnStr = NULL;

            nextServerIdStr = syncReqCtrlVal->bvUtdVector.lberbv.bv_val;

            while( nextServerIdStr != NULL && nextServerIdStr[0] != '\0')
            {
                PLW_HASHTABLE_NODE pNode = NULL;

                if (VmDirAllocateMemory( sizeof(UptoDateVectorEntry), (PVOID *)&utdVectorEntry ) != 0)
                {
                    VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: VmDirAllocateMemory failed " );
                    lr->errCode = retVal = LDAP_OPERATIONS_ERROR;
                    BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                                    "ParseSyncRequestControlVal: VmDirAllocateMemory failed");
                }

                nextOrigUsnStr = VmDirStringChrA( nextServerIdStr, ':');
                *nextOrigUsnStr = '\0';
                nextOrigUsnStr++;
                utdVectorEntry->invocationId.lberbv.bv_val = nextServerIdStr;
                utdVectorEntry->invocationId.lberbv.bv_len = VmDirStringLenA( nextServerIdStr );

                nextServerIdStr = VmDirStringChrA( nextOrigUsnStr, ',');
                *nextServerIdStr = '\0';
                nextServerIdStr++;

                utdVectorEntry->currMaxOrigUsnProcessed = utdVectorEntry->reqLastOrigUsnProcessed =
                                                              atol( nextOrigUsnStr );

                LwRtlHashTableResizeAndInsert( op->syncDoneCtrl->value.syncDoneCtrlVal.htUtdVector,
                                               &utdVectorEntry->Node, &pNode);
                assert( pNode == NULL );    // assert the key of added node is unique.
            }
        }

        tag = ber_peek_tag( ber, &len );
    }
    if (tag == LBER_BOOLEAN)
    {
        ber_int_t reloadHint;
        if (ber_scanf( ber, "b", &reloadHint) == LBER_ERROR)
        {
            VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: Error in reading reloadHint from the PDU" );
            lr->errCode = LDAP_PROTOCOL_ERROR;
            retVal = LDAP_NOTICE_OF_DISCONNECT;
            BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                            "Error in reading reloadHint from the PDU.");
        }
        if (reloadHint)
        {
            syncReqCtrlVal->reloadHint = TRUE;
        }
    }
    if ( ber_scanf( ber, "}") == LBER_ERROR ) // End of control value
    {
        VmDirLog( LDAP_DEBUG_ANY, "ParseSyncRequestControlVal: ber_scanf failed while parsing the end of "
                  "sync request control value." );
        lr->errCode = LDAP_PROTOCOL_ERROR;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Decoding error while parsing the end of sync request control value.");
    }

cleanup:
    // Even in the error case, syncDoneCtrl should be freed during operation delete.
    VmDirLog( LDAP_DEBUG_TRACE, "ParseSyncRequestControlVal: End." );

    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);

    return retVal;

error:

    VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg);

    goto cleanup;
}

static int
_ParsePagedResultControlVal(
    VDIR_OPERATION *                    op,
    BerValue *                          controlValue,       // Input: control value encoded as ber
    VDIR_PAGED_RESULT_CONTROL_VALUE *   pageResultCtrlVal,     // Output
    VDIR_LDAP_RESULT *                  lr                  // Output
    )
{
    int                     retVal = LDAP_SUCCESS;
    BerElementBuffer        berbuf;
    BerElement *            ber = (BerElement *)&berbuf;
    PSTR                    pszLocalErrorMsg = NULL;
    PSTR                    pszCookie = NULL;

    VmDirLog( LDAP_DEBUG_TRACE, "_ParsePagedResultControlVal: Start." );

    if (!op)
    {
        retVal = LDAP_PROTOCOL_ERROR;
        BAIL_ON_VMDIR_ERROR( retVal );
    }

    ber_init2( ber, controlValue, LBER_USE_DER );

    /* http://www.ietf.org/rfc/rfc2696.txt
     *
     * The searchControlValue is an OCTET STRING wrapping the BER-encoded version of the following SEQUENCE:
     *
     * realSearchControlValue ::= SEQUENCE {
     *        size            INTEGER (0..maxInt),
     *                                -- requested page size from client
     *                                -- result set size estimate from server
     *        cookie          OCTET STRING
    }
    */

    if (ber_scanf(ber, "{ia}",
                    &pageResultCtrlVal->pageSize,
                    &pszCookie) == LBER_ERROR)
    {
        VmDirLog( LDAP_DEBUG_ANY, "_ParsePagedResultControlVal: ber_scanf failed while parsing "
                  "pageSize and cookie in the page result control value" );
        lr->errCode = LDAP_PROTOCOL_ERROR;
        retVal = LDAP_NOTICE_OF_DISCONNECT;
        BAIL_ON_VMDIR_ERROR_WITH_MSG(   retVal, (pszLocalErrorMsg),
                                        "Error in reading pageSize and cookie in the page result control value");
    }

    if (pageResultCtrlVal->pageSize == 0)
    {
        retVal = LDAP_CANCELLED;
        VmDirLog( LDAP_DEBUG_TRACE, "Search query was cancelled.");
        BAIL_ON_VMDIR_ERROR(retVal);
    }

    VmDirStringNCpyA( pageResultCtrlVal->cookie, VMDIR_MAX_I64_ASCII_STR_LEN, pszCookie, VMDIR_MAX_I64_ASCII_STR_LEN-1);

    VmDirLog( LDAP_DEBUG_TRACE, "pageSize:%d", pageResultCtrlVal->pageSize );
    VmDirLog( LDAP_DEBUG_TRACE, "cookie:%s", pageResultCtrlVal->cookie );

cleanup:
    if (pszCookie)
    {
        ber_memfree(pszCookie);
    }
    // Even in the error case, syncDoneCtrl should be freed during operation delete.
    VmDirLog( LDAP_DEBUG_TRACE, "_ParsePagedResultControlVal: End." );
    VMDIR_SAFE_FREE_MEMORY(pszLocalErrorMsg);
    return retVal;

error:
    VMDIR_APPEND_ERROR_MSG(lr->pszErrMsg, pszLocalErrorMsg);
    goto cleanup;
}


text:
'use strict';

describe ('Controller: RepoController', function () {
    var fixtures, createController, $scope;

    // load the controller's module
    beforeEach (module ('geckoboardGithubApp'));

    // Initialize the controller and a mock scope
    beforeEach (inject (function ($injector) {
        var $controller = $injector.get ('$controller') ,
            $rootScope = $injector.get ('$rootScope') ,
            $filter = $injector.get ('$filter');

        createController = function (user, repo) {
            user = user || {};
            repo = repo || {};

            $scope = $rootScope.$new ();

            fixtures = {
                user: {
                    "login": "mikermcneil",
                    "id": 618009,
                    "url": "https://api.github.com/users/mikermcneil",
                    "starred_url": "https://api.github.com/users/mikermcneil/starred",
                    "type": "User",
                    "name": "Mike McNeil",
                    "location": "Austin, TX",
                    "email": "customers@balderdash.co",
                    "followers": 222,
                    "following": 161,
                    "created_at": "2011-02-14T20:51:12Z"
                },
                repo: {
                    "name": "sails",
                    "id": 3757512,
                    "description": "Realtime MVC Framework for Node.js",
                    "fork": false,
                    "stargazers_count": 4989,
                    "forks_count": 534,
                    "subscribers_count": 449,
                    "languages": {
                        "Javascript": 600,
                        "Ruby": 250,
                        "Python": 100,
                        "PHP": 50,
                        "Java": 2
                    }
                }
            };

            return $controller ('RepoController', {
                $scope: $scope ,
                $filter: $filter ,
                user: user ,
                repo: repo
            });
        };
    }));

    describe ('when user and repo data are not loaded yet', function () {
        it ('should return empty user data', function () {
            var controller = createController ();

            expect($scope.user.hasData).toBe (false);
        });

        it ('should return empty repository data', function () {
            var controller = createController ();

            expect($scope.repo.hasData).toBe (false);
            expect($scope.repo.languages).toBeUndefined ();
        });
    });

    describe ('when user and repo are loaded', function () {
        it ('should set user hasData flag', function () {
            var controller = createController (fixtures.user, fixtures.repo);

            expect($scope.user.hasData).toBe (true);
        });

        it ('should set repo hasData flag', function () {
            var controller = createController (fixtures.user, fixtures.repo);

            expect($scope.repo.hasData).toBe (true);
        });

        it ('should format repo languages', function () {
            var controller = createController (fixtures.user, fixtures.repo);

            expect($scope.repo.languages).toEqual ([{
                name: 'Javascript' ,
                percentage: 60
            } , {
                name: 'Ruby' ,
                percentage: 25
            } , {
                name: 'Python' ,
                percentage: 10
            } , {
                name: 'PHP' ,
                percentage: 5
            }]);
        });
    });
});

redpajama_set_name: RedPajamaGithub


text:
<!--

"wenn abnehmer mit produkt nicht einverstanden ist, von gutachter/anwält\*in gelesen"

* was war aufgabe? (~ pflichtenheft)
* welche grundlagen / ressourcen / state-of-the-art? (e.g. vorhandene libs)
* was getan?
 * entscheidungen nachvollziehbar dokumentieren
 * für lva ok: "wir hatten nicht genug zeit den fall weiter zu verfolgen"

kurz / knapp und präzise. synonyme vermeiden. möglichst wenig juristische angriffsfläche.

Additional: write in a way that it can be used as docs on gh

-->

## Goal

An application for writing and managing posts which are consumed by an arbitrary Static Site Generator^[a program that generates static (html and otherwise) content to be served by a simple web server] (e.g. Hakyll). The application should be web-based, have a rich text editor^[showing an approximation of the final document in the editor and allowing shortcuts to change formatting] for posts, save the content as markdown files and be written in Haskell.

<!--
Additional features required for a production ready minimum viable product would include:

* saving the posts to and loading them from the hard disk
*

Einfach zu serven/deployen
Verbrauchen wenig Ressourcen
Beliebiger Text-Editor
Posten...
Braucht technische Skills
Aufwändig

Git (oder SSH-Access)
Text-Datei anlegen
Markdown
Generator in Shell ausführen

Zugriff via Browser-URL
Recognition over Recall bez Markdown-Syntax
Veröffentlichen via Button-Click
Informative Übersicht über Artikel
Aber auch: Vorteile von SSG

-->

## State-Of-The-Art and Tooling Decisions

### Text-Editor Library

<!-- https://github.com/Haskell-Praxis/hakyll-cms/issues/1 -->

We tried out demos of all currently available javascript-based text-editors we found and compared them by:

* Uncompressed Size
* Whether they support rich-editing or exposed the markdown to users
* Whether they can directly export the markdown we needed for the posts or HTML we'd need to convert first
* Whether or not they offer a toolbar that allows recognizing markup options instead of needing to recall them.

The comparison-table below is sorted by uncompressed size. Bootstrap is about 28k uncompressed, jQuery about 91k. Sizes have been determined by looking at the network tab on the demo pages (subtracting any content, like images, in those demos).

| Editor | Size | Editing | Exports | Toolbar | Notes |
| --- | --- | --- | --- | --- | --- |
| [Medium.js](http://jakiestfu.github.io/Medium.js/docs/) | 18k | rich | html | JS-API | |
| [Trumbowyg](http://alex-d.github.io/Trumbowyg/) | 21k + jQuery | rich | html | at top | |
| [pen](http://sofish.github.io/pen/) | 32k | rich | md | mouse-over ||
| [EpicEditor](http://stacks.math.columbia.edu/js/EpicEditor/) | 34k | md  with preview | md | none | |
| [bootstrap-markdown](http://www.codingdrama.com/bootstrap-markdown/) | 49k + Bootstrap | md with preview | md | at top | |
| [CLEditor](http://premiumsoftware.net/cleditor/) | 9k + jQuery | rich | html | at top | win95 style |
| [bootstrap-wysiwyg](http://mindmup.github.io/bootstrap-wysiwyg/) | 5k + jQuery + Bootstrap | rich | html export | at top ||
| [Lepture's Editor](http://lab.lepture.com/editor/) | 247k | md with preview | md | at top ||
| [Vue.js](https://vuejs.org/v2/examples/) | 273k | md with preview | md | none ||
| [SimpleMDE](https://simplemde.com/) | 280k | md with preview | md | at top ||
| [Grafikart/JS-Markdown-Editor](https://github.com/Grafikart/JS-Markdown-Editor) | 189k + jQuery + Bootstrap | md  with preview | md | at top ||
| [medium-editor](https://github.com/daviferreira/medium-editor) | 311k | rich | html | mouse-over ||
| [bootstrap-wysihtml5](http://jhollingworth.github.com/bootstrap-wysihtml5/) | 325k | rich |  html | at top ||
| [TinyMCE](https://www.tinymce.com/) | 405k | rich | html | at top | many markup options |
| [ACE](https://ace.c9.io/build/kitchen-sink.html) | 645k | md amongst others | md if md is written | none | code editor with syntax highlighting. pre-existing reflex-wrapper(!) |
| [Hallo.js](http://hallojs.org/demo/markdown/) | 106k + 566k dependencies | rich + md | md | at top ||
| [CKEditor + Markdown Plugin](http://ckeditor.com/addon/markdown) | ~820k | rich + md | md | at top | many markup options, [configuration-tool](http://ckeditor.com/builder), uses iframes |
| [jbt/markdown-editor](https://jbt.github.io/markdown-editor/) | 823k with various dependencies | md with preview | md | none | default style unusable on small screens |
| [Markdown-It](https://markdown-it.github.io/) | 250k + 850k dependencies | md  with preview | md | none ||
| [Substance](http://substance.io/) | 1.14M | rich | html | at top | |
| [Stackedit](https://stackedit.io/) | 1.48M | md with preview | md | at top | requires nodejs server |
| [Woofmark](https://bevacqua.github.io/woofmark/) | 1.4M | rich + md | md | at top | |
| [Pandao/Editor.md](https://pandao.github.io/editor.md/en.html) | ~1.7M with various dependencies | md with preview | md | at top | many markup options; [github-repo](https://github.com/pandao/editor.md)
| [Dillinger](http://dillinger.io/) | 1.8M | md with preview | md | none | various import/export options |
| [Markdown-Plus](http://mdp.tylingsoft.com/) | 6M with various dependencies | md  with preview | md | at top ||
| Aloha | | | | | discontinued |

Other comparisons:

* [This issue](https://github.com/Semantic-Org/Semantic-UI/issues/222) on Semantic-Org/Semantic-UI lists a few editors
* [Top 7: Best Markdown editors Javascript and jQuery plugins](http://ourcodeworld.com/articles/read/359/top-7-best-markdown-editors-javascript-and-jquery-plugins) (2017/01)
* [Coding 10 Awesome JavaScript WYSIWYG & Markdown Editors](http://www.developersfeed.com/awesome-javascript-wysiwyg-markdown-editors/) (2016)

#### Decision

Going through the editors by size, [SimpleMDE](https://simplemde.com/) seems to be the right choice for our project. It is the smallest library that satisfies:

* Good usability
  * A toolbar for markup-options ("recognition over recall"), as opposed to Epic and Vue.js.
  * Rich-looking code-styling (e.g. headings are larger), as opposed to bootstrap-md
  * A split-screen preview of the resulting HTML
  * Relatively modern looking, clean styling / visual design, as opposed to CLE
* Markdown-editing (no conversion to and from HTML necessary as with Pen)
* A mature API that gives us refined change events and that distinguishes it from the smaller [Pen](http://sofish.github.io/pen/) and [Lepture's Editor](http://lab.lepture.com/editor/))

### CSS-Library

There are wide-variety of different CSS-libraries. To name the more widely used:

* [Bootstrap](http://getbootstrap.com/)
* [Semantic-UI](http://semantic-ui.com/)
* [Tachyons](http://tachyons.io/)
* ...

**Decision:** For Semantic-UI, there exists a Reflex-based wrapper in the form of [reflex-frp-semui](https://github.com/reflex-frp/reflex-dom-semui) that provides everything we need for the prototype.

### Web Interface Structure

One of the goals of the application was that most parts should be written in Haskell. This did not leave many options for the architecture.

| Solution | Description | Backend Option |
| -------- | -------- | ------- |
| HTML/JavaScript | Using Static HTML supplemented with JavaScript for the dynamic parts of the application | HTML Renderer |
| Elm | A Haskell-like client language which compiles to JavaScript | REST Server |
| Fay | An older Haskell to JavaScript compiler which only supports a small subset of Haskell | REST Server |
| Haste | A Haskell Backend/Frontend combination with a predefined interface between the two | Haste |
| GHCJS | A full Haskell-to-JS compiler with support for JavaScript FFI | REST Server |

Some more options are available in the Haskell Wiki^[[https://wiki.haskell.org/The_JavaScript_Problem](https://wiki.haskell.org/The_JavaScript_Problem)]. But almost all of them were unmaintained at time of writing.

Since the application was assumed to have a very dynamic frontend, rendering static HTML and supplementing it with JavaScript was quickly abandoned as a solution.

Using Elm in the frontend did also not meet the criterium of using mostly Haskell as a programming language. This would have introduced a separate codebase to maintain as well as a boundary layer problem between Haskell and Elm.

Of the Haskell-to-JS compilers, only GHCJS was maintained and stable enough for actual use. Its binary output size is very big - around 300kb overhead pre-gzip (we assume mostly due to support for things like lazy-evaluation). This was not a big problem for our use-case however, since we did not expect many new users to visit the application. Rather, users would use the application more often, making caching very efficient and reducing the overall impact of a big JavaScript-bundle.

**Decision:** We decided to use GHCJS on the client side because it provided us with a unified codebase.

#### Frontend

In addition to the frontend language, we needed a method to produce HTML and support interaction with the application. The most prominent GHCJS project to fill this gap was Reflex-DOM, an FRP implementation for web frontends.

Other solutions found - e.g. a wrapper around React - were generally not as well supported.

**Decision:** We opted for Reflex-DOM as the rendering solution for its rather big community and good maintenance, as well as its FRP paradigm.

#### Backend

Since the client side was decided to be an independent Haskell application, the backend would be a REST Server.
Since there is a best-practice solution for creating REST-APIs in Haskell, no extensive research was done before choosing a backend.

**Decision:** Servant and Servant-Server were chosen as the backend because they were the go-to solution for creating and serving REST-APIs in Haskell and provided a type-safe method of defining the API.

### Build Setup

At time of writing there were four major build setups for Haskell applications.

* Cabal
* Cabal New-Build
* Nix
* Stack

Cabal had been superseded by Cabal New-Build, although this transition was not complete at the time this project started.

Cabal New-Build looked promising, but had some major tooling flaws. For one, most of our major dependencies -- Reflex and Reflex-DOM -- were not actually in Hackage, and Cabal New-Build did not provide a standard way to fetch these packages from Git. Also, most code-sensing tools and IDEs were not compatible with Cabal New-Build, making development more tedious.

Nix was the build-tool of choice for the reflex-platform, but required an additional program to be installed on developers' systems, introduced a new programming language for configuration and added a lot of complexity to the build.

Finally Stack supported multiple compilers in its configuration and allowed pulling dependencies from Git. It was also the most widely used solution for developing Haskell.

**Decision:** We decided to use Stack as it provided the features we needed and was the industry-standard at the time.

<!-- cabal (newbuild) vs stack -->

<!--
haskell-webapps vs reflex-platform vs custom
Servant
Text-Editor Vergleich (gh-issue)
cabal new-build vs stack vs nix
JSaddle und GHCJS

Probleme:
GHCJS wird von Stack nicht sehr gut supported
Cabal-Newbuild wird von devtools nicht richtig unterstützt
Ghc-mod crashes...
GHCJS ist nicht mit allen dependencies kompatibel
Stacks versprechen zu portable builds nicht ganz richtig
Sehr viele stack files...

-->

## Development

### Wrapper for SimpleMDE

We implemted a minimal, reflex- and JSM-based wrapper for SimpleMDE that allows instantiating a fully styled editor with a custom, initial text-value and yields a `Dynamic t Text` that holds the current text-value of the editor and "notifies subscribers" of changes.

We had to work around [a bug in Simple-MDE](https://github.com/nestor-qa/nestor/issues/98) that requires calling `simplemde.codemirror.refresh()` a second after it's initialisation, to make the initial text-value show.

From the general experience, I can recommend to start learning reflex and jsaddle/JSM using pre-wrapped widgets and elements, as writing a wrapper is more complicated, requires understanding and interfacing with several libraries, especially with less documented or more complicated functions of those. Also, I'd recommend using the `MonadWidget` catch-all type-constraint, as using a smaller / more selective constraint requires understanding and constructing a more complicated type-signature (`MonadWidget` hides a lot of those issues)

The hakyll-cms/simple-mde sub-project also contains a simple usage example.

Gabriel has started defining a data-type for the full set of SimpleMDE's configuration options. The structure is inspired by the work done on the [ACE-wrapper for reflex-dom](https://github.com/reflex-frp/reflex-dom-ace)

### Servant-API

<!--

issues / hoisting

autogen of handlers. client-side wrappers using `IO`. ...

-->

Servant provides a simple way to define APIs using Data Kinds^[[https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/type-level-literals.html](https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/type-level-literals.html)]. Since now each API has an associated type, the endpoints are also typed, allowing extra checks about whether a server or client conforms to the specification. We were also able to automatically generate a Haskell client for our REST Api. There were a few pain points in this process, because the type of the client handlers is somewhat opaque, and they are "extracted" from the `client` call by pattern matching.

```haskell
getPostSummariesGeneric :<|> createPostGeneric :<|> postApi = client api

getPostGeneric id =
  let getPostGeneric' :<|> _ :<|> _ = postApi id
  in getPostGeneric'

updatePostGeneric id =
  let _ :<|> updatePostGeneric' :<|> _ = postApi id
  in updatePostGeneric'

deletePostGeneric id =
  let _ :<|> _ :<|> deletePostGeneric' = postApi id
  in deletePostGeneric'
```

Defining the API and handler on the server-side was straightforward for static content. Reading posts from and storing them to disk on the other hand required the addition of multiple monad transformers. Parsing strings into `Path`s required a `MonadThrow` monad for example. Since servants `Handler` wraps an `ExceptT ServantErro IO` the underlying monad needed to be changed. Servant provides a facility for hoisting to this end. A function can be defined to convert one monad transformer stack into another. For using a `Reader String` the function would look like this:

```haskell
let nt = generalizeNat . (runReaderTNat "hi") :: Reader String :~> Handler
```

Adding the monad transformers we need via this method proved to be difficult however, and due to time constraints the implementation of a file-backend was scrapped. Instead an in-memory backend was implemented via `STM`, lifting all `STM`-actions into `IO`

```haskell
didFail <- liftIO $ atomically $ do
        currentState <- readTVar tvar
        if member id currentState then
            return True
        else do
            writeTVar tvar (insert id post currentState)
            return False
```

This method removed a lot of the power for error-handling from Haskell's monad stacks and is only suitable for a rough prototype, but it provided the full backend functionality to our client interface.

### Overview and Edit-View

The client-app-prototype consists of three views:

* The overview (see screenshot), that shows post-teasers, post-titles and placeholder-images (that are to be replaced with proper images or removed for the MVP)
* An edit-view (see screenshot), that allows editing posts
* A post-creation view, that allows creating new posts and GUI-wise only differs to the edit-view by the title.

![Overview](https://i.imgur.com/BBstgut.png)

![Edit-view](https://i.imgur.com/hyfy4HK.png)

To allow navigating between these views, we used the basic routing-utilities from `reflex-frp/reflex-dom-contrib`. Even though these are experimental, these utilities -- and the more powerful but also more complicated `MonadRouted` that builds upon these -- are the best solution available in Reflex at the time of this writing. Routing happens via URL-fragments. This allows us to use plain links for navigation (with no additional wiring required). Also, it avoided extra configuration effort with jsaddle-warp (or a custom HTTP-server) to redirect HTTP-requests to always serve `index.html`, regardless of which route was requested (as described in [this issue](https://github.com/ghcjs/jsaddle/issues/34)). E.g. `http://localhost:8081/#/edit/getting-started_2017-01-10` automatically loads `index.html`.

For the form, we implemented a small widget, that groups a text-field with it's label and that should be part of `reflex-frp/reflex-dom-semui`, as it's a Semantic-UI staple.

## Future Work

To make this very crude prototype into something more of a minimum viable product that can be properly released the following tasks need to be done:

* [GHCJS compiler issues](https://github.com/Haskell-Praxis/hakyll-cms/issues/12) with some use of template-haskell.
* Saving posts as files with correct YAML-frontmatter
* Show rendered HTML -- instead of markdown -- in the content-teaser in the overview (as described in [this issue](https://github.com/Haskell-Praxis/hakyll-cms/issues/14)).
* [Error recovery](https://github.com/Haskell-Praxis/hakyll-cms/issues/11) for problems users might encounter in the wild
* [Elipses](https://github.com/Haskell-Praxis/hakyll-cms/issues/10) at the end of post-summaries, that don't already include the entire post.
* Deleting posts.
* Fixing the initialization bug in SimpleMDE -- via a pull-request to their repository.
* Access-control
* Optional: Interactions with Git, as this gives us versioning and allows interactions with other systems (e.g. people using their own text-editor on their own machine)

As an optional side-project we could/will finish wrapping the entirety of SimpleMDE (i.e. all configuration options and events it emits) and publishing that library as contribution to the Reflex-/GHCJS-community.

Also we found several places where we could/will contribute to reflex-dom-contrib and reflex-dom-semui.


text:
import java.util.*;

class Program
{
  public static void main(String[] args)
  {
  	Scanner reader = new Scanner(System.in);

  	System.out.println("Jak Ci na imię?");
  	String imie = reader.next();

  	System.out.println("Ile masz lat?");
  	String wiek = reader.next();

  	System.out.println("Użytkownik " + imie + " ma " + wiek + " lat");
  }
}


text:
package com.yanzhenjie.album.app.album.data;

import android.content.Context;
import android.os.AsyncTask;

import com.yanzhenjie.album.AlbumFile;

import java.util.ArrayList;

/**
 * Created by YanZhenjie on 2017/10/15.
 */
public class ThumbnailBuildTask extends AsyncTask<Void, Void, ArrayList<AlbumFile>> {

    public interface Callback {
        /**
         * The task begins.
         */
        void onThumbnailStart();

        /**
         * Callback results.
         *
         * @param albumFiles result.
         */
        void onThumbnailCallback(ArrayList<AlbumFile> albumFiles);
    }

    private ArrayList<AlbumFile> mAlbumFiles;
    private Callback mCallback;

    private ThumbnailBuilder mThumbnailBuilder;

    public ThumbnailBuildTask(Context context, ArrayList<AlbumFile> albumFiles, Callback callback) {
        this.mAlbumFiles = albumFiles;
        this.mCallback = callback;
        this.mThumbnailBuilder = new ThumbnailBuilder(context);
    }

    @Override
    protected void onPreExecute() {
        mCallback.onThumbnailStart();
    }

    @Override
    protected ArrayList<AlbumFile> doInBackground(Void... params) {
        for (AlbumFile albumFile : mAlbumFiles) {
            int mediaType = albumFile.getMediaType();
            if (mediaType == AlbumFile.TYPE_IMAGE) {
                albumFile.setThumbPath(mThumbnailBuilder.createThumbnailForImage(albumFile.getPath()));
            } else if (mediaType == AlbumFile.TYPE_VIDEO) {
                albumFile.setThumbPath(mThumbnailBuilder.createThumbnailForVideo(albumFile.getPath()));
            }
        }
        return mAlbumFiles;
    }

    @Override
    protected void onPostExecute(ArrayList<AlbumFile> albumFiles) {
        mCallback.onThumbnailCallback(albumFiles);
    }
}


text:
package br.gov.servicos.config;

import org.apache.coyote.http11.AbstractHttp11Protocol;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.MimeMappings;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;

import javax.servlet.Filter;

import static org.apache.commons.lang.StringUtils.join;

@Configuration
public class ServletContainerConfig {

    public static final String COMPRESSIBLE_MEDIA_TYPES = join(new String[]{
            "text/html",
            "text/xml",
            "text/plain",
            "application/json",
            "application/javascript",
            "application/x-font-woff",
            "text/css"
    }, ',');

    @Bean
    public EmbeddedServletContainerCustomizer servletContainerCustomizer() {
        return servletContainer -> {
            addMimeMappingsForFonts(servletContainer);

            TomcatEmbeddedServletContainerFactory container = (TomcatEmbeddedServletContainerFactory) servletContainer;

            container.setRegisterJspServlet(false);

            container.addContextCustomizers(customizer -> customizer.addWelcomeFile("index.html"));
            container.addConnectorCustomizers(
                    connector -> {
                        AbstractHttp11Protocol httpProtocol = (AbstractHttp11Protocol) connector.getProtocolHandler();
                        httpProtocol.setCompression("on");
                        httpProtocol.setCompressionMinSize(256);
                        httpProtocol.setCompressableMimeTypes(COMPRESSIBLE_MEDIA_TYPES);
                    }
            );
        };
    }

    private void addMimeMappingsForFonts(ConfigurableEmbeddedServletContainer servletContainer) {
        MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
        mappings.add("eot", "application/vnd.ms-fontobject");
        mappings.add("ttf", "application/font-sfnt");
        mappings.add("otf", "application/font-sfnt");
        mappings.add("woff", "application/font-woff");
        mappings.add("woff2", "application/font-woff");
        servletContainer.setMimeMappings(mappings);
    }

    @Bean
    public Filter characterEncodingFilter() {
        CharacterEncodingFilter filter = new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        filter.setForceEncoding(true);
        return filter;
    }

}


text:
class KrMemoryBitmap : public IGBitmap
{

public:

  KrMemoryBitmap (int aWidth, int aHeight);      // Constructor for bitmap of size _width x _height

  IGList * setList (IGList & list);              // Sets a new graphicList.
                                                 //   Returns a pointer to the old one.
  IGList * list ();                              // Returns a pointer to the current graphicList
  void addList (IGList & list);                  // Adds a new graphicList; draws all new graphics elements.

  void erase (const IColor & color = IGUIColor (IGUIColor::windowBgnd) );
                                                 // Fills the bitmap with the given color
  KrCoordSystemTranslator * setCoordSystem (KrCoordSystemTranslator * aTrans,
                                            const KrPoint & aP1, const KrPoint & aP2);
                                                 // Maps the Bitmap in the rectangle between aP1 and aP2
                                                 //   in the coordinate system aTrans. Returns the old
                                                 //   coordinate system translator.

  virtual KrMemoryBitmap & drawOn (IGraphicContext & graphicContext);
  virtual KrMemoryBitmap & drawOn( IGraphicContext & graphicContext, const IPoint& targetBottomLeft,
             const IPoint& targetTopRight, const IPoint& sourceBottomLeft, const IPoint& sourceTopRight,
             long rasterOperation = normal, CompressMode compressMode = ignore);
  virtual KrMemoryBitmap & drawOn( IGraphicContext& graphicContext, long rasterOperation);
                                                 // Overloads of all IBitmap::drawOn functions

private:

  KrCoordSystemTranslator * trans;               // For the coordinate system the bitmap is drawn into

  IHandle::Value createHbm (short aWidth, short aHeight);
                                                 // Create the Bitmap in the memory.
                                                 //   Creates also device context and the presentation space
                                                 //   as side effects (intended)

  void drawOnBitmap (IGList * list);             // Draw the contents of list on the bitmap

  IGList *graphicsList;                          // List of graphics elements drawn on the bitmap

  KrPoint p1, p2;                                // Corners of the Bitmap in "trans" coordinates.

  short width, height;                           // Size of the bitmap
  IHandle::Value hdcMem;                         // Memory Device Context handle
  IHandle::Value hpsMem;                         // Memory Presentation Space handle
  IHandle::Value hbmMem;                         // Handle to the bitmap itself

  static short widthS, heightS;                  // Temporary values required for initilization
  static IHandle::Value hdcMemS;
  static IHandle::Value hpsMemS;
  static IHandle::Value hbmMemS;

};

#endif


text:
package com.github.antennaesdk.common.messages.util;

import org.json.JSONException;
import org.json.JSONObject;

/**
 * JsonUtil contains utility methods that operate on JSON.
 */
public class JsonUtil {

    public static String identifyClassType( String json  ){

        String classtype =null;
        try {

            JSONObject jsonObject = new JSONObject(json);
            classtype = (String) jsonObject.get("classType");

        }catch( JSONException e){

        }

        return classtype;
    }
}


text:
"""Contains data after processing is done."""

from shatter.code import Code
from shatter.constants import *
from shatter.rules import *
from shatter.util.frozen_dict import FrozenDict

__author__ = 'juan pablo isaza'

class ProcessedRules:
    """
    Has 2 properties, the 'default' value of the output and the 'tables'.

    Tables is a dict() where each (key, value) pair are a truth table. Tables have:
    Keys = possible function outputs.
    Values = Are the tables represented with lists containing tuples eg:

    >>> [(True, False), (False, True)]

    These tuples are rows of the truth table where the function should return the output value (the key).

    So we have a collection of tables; each one with its own output as key.

    Example:
    >>> ProcessedRules().tables
    is of the form:
    >>> {1: [(True, Code('1==3')), (False, False)], 2: [(False, True), (True, False)]}

    In this case 1 and 2 are the outputs while (True, Code('1==3')), (False, False) are the rows of the truth table
    , ie the cases where 1 should be returned.
    """

    def __init__(self, tables=FrozenDict(), default=False):
        self.tables = tables
        self.default = default

def get_default_output(rules):
    """
    Gets the default value by iterating over all rows until a default word is caught.
    :param rules: a Rules obj.
    :return: the default value or False if None is found or if rules is not a obj.
    """
    if isinstance(rules, Rules) and rules:
        for row in rules:
            if KEYWORDS[DEFAULT] in row:
                return row[KEYWORDS[DEFAULT]]

        return False
    else:
        return False

def get_processed_rules(rules, function_args):
    """
    :param rules:
    :param function_args: args
    :return: processedRules instance
    """
    tables = get_truth_tables(rules, function_args)
    return ProcessedRules(tables, get_default_output(rules))


text:
<?xml version="1.0" encoding="UTF-8"?>
<x xmlns='jabber:x:data' type='form'>
  <page xmlns='http://jabber.org/protocol/xdata-layout' label='Label - & é á '>
    <fieldref var='testField1' />

      <text>SectionText - & é á </text>

    <text>PageText - & é á </text>

Number of Persons by<br/> Nationality and Status</html>'>
      <reportedref />

    <text><![CDATA[DO NOT DELAY
supply further information]]></text>
  </page>
</x>


text:
function Desc(value) {
  this.value = value; //TODO Remove when done debugging
}
module.exports = Desc;

var Error = require(__dirname+"/error.js");

Desc.prototype.toJSON = function() {
  throw new Error.ReqlRuntimeError('DESC may only be used as an argument to ORDER_BY', [])
}

Desc.prototype.toDatum = function(query) {
  //TODO check everywhere that an instance of DESC is not returned.
  throw new Error.ReqlRuntimeError('DESC may only be used as an argument to ORDER_BY', query.frames)
}


text:
using System;
using System.Collections.Generic;
using Google.Apis.ShoppingContent.v2_1;
using Google.Apis.ShoppingContent.v2_1.Data;

namespace ShoppingSamples.Content
{
    ///
    /// A sample consumer that runs multiple requests against the
    /// Accountstatuses service in the Content API for Shopping.
    /// <para>These include:
    /// <list type="bullet">
    /// <item>
    /// <description>Accountstatuses.get</description>
    /// </item>
    /// <item>
    /// <description>Accountstatuses.list</description>
    /// </item></list></para>
    ///
    public class AccountstatusesSample
    {
        private ShoppingContentService service;
        private int maxListPageSize;

        public AccountstatusesSample(ShoppingContentService service, int maxPageListSize)
        {
            this.service = service;
            this.maxListPageSize = maxPageListSize;
        }

        /// Runs requests for non-multi-client Merchant Center accounts
        /// against the Content API for Shopping.
        internal void RunCalls(ulong merchantId)
        {
            GetAccount(merchantId, merchantId);
        }

        /// Runs requests for multi-client Merchant Center accounts
        /// against the Content API for Shopping.
        internal void RunMultiCalls(ulong merchantId)
        {
            GetAllAccounts(merchantId);
        }

        ///
        /// Retrieves the status of a particular account.
        ///
        /// <returns>The status information for the specified account.</returns>
        private AccountStatus GetAccount(ulong merchantId, ulong accountId)
        {
            Console.WriteLine("=================================================================");
            Console.WriteLine("Getting Product Status for {0}", accountId);
            Console.WriteLine("=================================================================");

            AccountStatus status = service.Accountstatuses.Get(merchantId, accountId).Execute();
            PrintAccountStatus(status);
            Console.WriteLine();

            return status;
        }

        ///
        /// Retrieves the statuses of all subaccounts.
        ///
        /// <returns>The last page of account statuses.</returns>
        private AccountstatusesListResponse GetAllAccounts(ulong merchantId)
        {
            Console.WriteLine("=================================================================");
            Console.WriteLine("Listing all Account Statuses");
            Console.WriteLine("=================================================================");

            // Retrieve account list in pages and display data as we receive it.
            string pageToken = null;
            AccountstatusesListResponse statusesResponse = null;

            do
            {
                AccountstatusesResource.ListRequest statusesRequest =
                    service.Accountstatuses.List(merchantId);
                statusesRequest.MaxResults = maxListPageSize;
                statusesRequest.PageToken = pageToken;

                statusesResponse = statusesRequest.Execute();

                if (statusesResponse.Resources != null && statusesResponse.Resources.Count != 0)
                {
                    foreach (var status in statusesResponse.Resources)
                    {
                        PrintAccountStatus(status);
                    }
                }
                else
                {
                    Console.WriteLine("No accounts found.");
                }

                pageToken = statusesResponse.NextPageToken;
            } while (pageToken != null);
            Console.WriteLine();

            // Return the last page of accounts.
            return statusesResponse;
        }

        private void PrintAccountStatus(AccountStatus status)
        {
            Console.WriteLine("Account {0} found.", status.AccountId);
            IList<AccountStatusProducts> products = status.Products;

            if (products == null)
            {
                Console.WriteLine("- No data quality issues.");
            }
            else
            {
                int issueCount = 0;

                foreach (var product in products)
                {
                    if (product.ItemLevelIssues == null)
                    {
                        break;
                    }
                    foreach (var issue in product.ItemLevelIssues)
                    {
                        issueCount++;
                        Console.WriteLine("- Issue Code {0} [{1}]", issue.Code, issue.Detail);
                        Console.WriteLine("  Affects {0} items.", issue.NumItems);
                    }
                }

                Console.WriteLine("{0} data quality issues found.", issueCount);
            }
        }
    }
}


text:
package commands

import (
	"github.com/cloudfoundry/cli/cf/api/stacks"
	"github.com/cloudfoundry/cli/cf/command_registry"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/simonleung8/flags"
)

type ListStacks struct {
	ui         terminal.UI
	config     core_config.Reader
	stacksRepo stacks.StackRepository
}

func init() {
	command_registry.Register(&ListStacks{})
}

func (cmd *ListStacks) MetaData() command_registry.CommandMetadata {
	return command_registry.CommandMetadata{
		Name:        "stacks",
		Description: T("List all stacks (a stack is a pre-built file system, including an operating system, that can run apps)"),
		Usage:       T("CF_NAME stacks"),
	}
}

func (cmd *ListStacks) Requirements(requirementsFactory requirements.Factory, fc flags.FlagContext) (reqs []requirements.Requirement, err error) {
	if len(fc.Args()) != 0 {
		cmd.ui.Failed(T("Incorrect Usage. No argument required\n\n") + command_registry.Commands.CommandUsage("stacks"))
	}

	reqs = append(reqs, requirementsFactory.NewLoginRequirement())
	return
}

func (cmd *ListStacks) SetDependency(deps command_registry.Dependency, pluginCall bool) command_registry.Command {
	cmd.ui = deps.Ui
	cmd.config = deps.Config
	cmd.stacksRepo = deps.RepoLocator.GetStackRepository()
	return cmd
}

func (cmd *ListStacks) Execute(c flags.FlagContext) {
	cmd.ui.Say(T("Getting stacks in org {{.OrganizationName}} / space {{.SpaceName}} as {{.Username}}...",
		map[string]interface{}{"OrganizationName": terminal.EntityNameColor(cmd.config.OrganizationFields().Name),
			"SpaceName": terminal.EntityNameColor(cmd.config.SpaceFields().Name),
			"Username":  terminal.EntityNameColor(cmd.config.Username())}))

	stacks, apiErr := cmd.stacksRepo.FindAll()
	if apiErr != nil {
		cmd.ui.Failed(apiErr.Error())
		return
	}

	cmd.ui.Ok()
	cmd.ui.Say("")

	table := terminal.NewTable(cmd.ui, []string{T("name"), T("description")})

	for _, stack := range stacks {
		table.Add(stack.Name, stack.Description)
	}

	table.Print()
}


text:
#ifndef __PHLIBC_ASSERT_H
#define __PHLIBC_ASSERT_H

#ifdef NDEBUG
#define assert(exp)
#else
#define assert(exp) (void)((exp) || (_PHAssert(#exp, __FILE__, __LINE__),0))
#endif

#if defined(__cplusplus)
extern "C" {
#endif

void _PHAssert(const char *expr, const char *file, int line);

#if defined(__cplusplus)
} /* extern "C" */
#endif

#endif


text:
require 'hutch/logging'

module Hutch
  module Acknowledgements
    class NackOnAllFailures
      include Logging

      def handle(delivery_info, properties, broker, ex)
        prefix = "message(#{properties.message_id || '-'}): "
        logger.debug "#{prefix} nacking message"

        broker.nack delivery_info.delivery_tag

        true
      end
    end
  end
end


text:
module Registry
  class Folder < Registry::Entry

    def folder?
      true
    end

  end # class Folder
end # module Registry


text:
import angr

######################################
# fcntl
######################################

class fcntl(angr.SimProcedure):
    #pylint:disable=arguments-differ

    def run(self, fd, cmd):
        #  this is a stupid stub that does not do anything besides returning an unconstrained variable.
        return self.state.solver.BVS('fcntl_retval', self.state.arch.bits)


text:
class CDispSvrPropPage : public CBasePropertyPage
{
public:
	CDispSvrPropPage(IUnknown *pUnk);
	~CDispSvrPropPage();

	static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr);
	virtual HRESULT OnActivate();
	virtual HRESULT OnConnect(IUnknown *pUnknown);
    virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);

protected:
	//WM Message
	//BOOL OnInitDialog();
protected:
	IKsPropertySet *m_pKsSet;
	DWORD m_DispSvrInitFlags;
};


text:
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision: 317663 $ -->

<refentry xml:id="solrquery.sethighlightformatter" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
 <refnamediv>
  <refname>SolrQuery::setHighlightFormatter</refname>
  <refpurpose>Specify a formatter for the highlight output</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <type>SolrQuery</type><methodname>SolrQuery::setHighlightFormatter</methodname>
   <methodparam><type>string</type><parameter>formatter</parameter></methodparam>
   <methodparam choice="opt"><type>string</type><parameter>field_override</parameter></methodparam>
  </methodsynopsis>
  <para>
   Specify a formatter for the highlight output.
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>formatter</parameter></term>
     <listitem>
      <para>
       Currently the only legal value is "simple"
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term><parameter>field_override</parameter></term>
     <listitem>
      <para>
       The name of the field.
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>
 </refsect1>
</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->


text:
<?xml version="1.0" encoding="UTF-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping
                  http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">

    <entity name="App\Entity\User" table="user" repository-class="App\Repository\UserRepository">
        <id name="id" type="integer" column="id">
            <generator strategy="AUTO"/>
        </id>

        <field name="username" column="username" type="string" length="255" unique="true"/>

        <field name="email" column="email" type="string" length="255" unique="true"/>

        <field name="enabled" column="enabled" type="boolean"/>

        <field name="salt" column="salt" type="string"/>

        <field name="password" column="password" type="string"/>

        <field name="lastLogin" column="last_login" type="datetime" nullable="true"/>

        <field name="confirmationToken" column="confirmation_token" type="string" nullable="true"/>

        <field name="resetPasswordToken" column="reset_password_token" type="string" nullable="true"/>

        <field name="passwordRequestedAt" column="password_requested_at" type="datetime" nullable="true"/>

        <field name="roles" column="roles" type="array"/>

        <one-to-many field="ownedCompanies" target-entity="Company" mapped-by="owner">
            <cascade>
                <cascade-all/>
            </cascade>
        </one-to-many>

        <one-to-many field="accountedCompanies" target-entity="Company" mapped-by="accountant">
            <cascade>
                <cascade-persist/>
            </cascade>
        </one-to-many>

        <many-to-many field="managedCompanies" target-entity="Company" mapped-by="managers">
            <cascade>
                <cascade-persist/>
            </cascade>
        </many-to-many>

        <many-to-many field="marketedCompanies" target-entity="Company" mapped-by="salesAgents">
            <cascade>
                <cascade-persist/>
            </cascade>
        </many-to-many>

        <one-to-many field="receivedInvites" target-entity="Invite" mapped-by="receiver">
            <cascade>
                <cascade-all/>
            </cascade>
        </one-to-many>

        <one-to-many field="sentInvites" target-entity="Invite" mapped-by="sender">
            <cascade>
                <cascade-all/>
            </cascade>
        </one-to-many>

    </entity>

</doctrine-mapping>


text:
package org.evilco.mc.defense.common.tile.machine;

import net.minecraft.entity.item.EntityItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import org.evilco.mc.defense.common.tile.AbstractTileEntity;
import org.evilco.mc.defense.common.tile.IRotateableTileEntity;

import java.util.HashMap;
import java.util.Map;

/**
 * @auhtor Johannes Donath <johannesd@evil-co.com>
 * @copyright Copyright (C) 2014 Evil-Co <http://www.evil-co.org>
 */
public class RollingMillTileEntity extends AbstractTileEntity implements IRotateableTileEntity {

	/**
	 * Defines the drum rotation speed.
	 */
	public static final double DRUM_SPEED = 3;

	/**
	 * Defines how often a player has to click the rolling mill to get the result.
	 */
	public static final int PROCESSING_HITS = 30;

	/**
	 * Stores all possible crafting recipes.
	 */
	protected static final Map<Item, ItemStack> craftingMap = new HashMap<Item, ItemStack> ();

	/**
	 * Stores the current drum angle.
	 */
	protected double drumAngle = 0.0;

	/**
	 * Stores the currently active item.
	 */
	protected Item item = null;

	/**
	 * Stores the amount of ticks left until processing finishes.
	 */
	protected int processing = 0;

	/**
	 * Adds a recipe to the rolling mill.
	 * @param item The item.
	 * @param itemStack The result item.
	 */
	public static void addRecipe (Item item, ItemStack itemStack) {
		craftingMap.put (item, itemStack);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Packet getDescriptionPacket () {
		// create compound
		NBTTagCompound compound = new NBTTagCompound ();

		// write data
		this.writeToNBT (compound);

		// create packet
		return (new S35PacketUpdateTileEntity (this.xCoord, this.yCoord, this.zCoord, this.getBlockMetadata (), compound));
	}

	/**
	 * Returns the drum rotation.
	 * @param partialTicks The ticks since last render.
	 * @return The rotation angle for the drums.
	 */
	public double getDrumRotation (float partialTicks) {
		return Math.toRadians (this.drumAngle);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getRotationAngle () {
		return (this.getBlockMetadata () * 90.0f + 90.0f);
	}

	/**
	 * Inserts an item into the rolling mill.
	 * @param item The item.
	 * @return True if the insertion was successful.
	 */
	public boolean insertItem (Item item) {
		if (this.item != null) return false;
		if (!this.craftingMap.containsKey (item)) return false;

		// input item
		this.item = item;

		// reset processing timer
		this.processing = PROCESSING_HITS;
		this.drumAngle = 0;

		// mark update
		this.worldObj.markTileEntityChunkModified (this.xCoord, this.yCoord, this.zCoord, this);
		this.worldObj.markBlockForUpdate (this.xCoord, this.yCoord, this.zCoord);

		// notify
		return true;
	}

	/**
	 * Checks whether the mill is processing.
	 * @return True if the mill is processing.
	 */
	public boolean isProcessing () {
		return (this.item != null);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onDataPacket (NetworkManager net, S35PacketUpdateTileEntity pkt) {
		this.readFromNBT (pkt.func_148857_g ());
	}

	/**
	 * Processes an item.
	 */
	public void process () {
		// update drum angle
		if (this.worldObj.isRemote) {
			// update drum angle
			this.drumAngle += DRUM_SPEED;

			// exit
			return;
		}

		// reduce ticks
		this.processing = Math.max (0, (this.processing - 1));

		// mark update
		this.worldObj.markTileEntityChunkModified (this.xCoord, this.yCoord, this.zCoord, this);
		this.worldObj.markBlockForUpdate (this.xCoord, this.yCoord, this.zCoord);
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void readFromNBT (NBTTagCompound p_145839_1_) {
		super.readFromNBT (p_145839_1_);

		if (p_145839_1_.hasKey ("item"))
			this.item = ((Item) Item.itemRegistry.getObject (p_145839_1_.getString ("item")));
		else
			this.item = null;

		this.processing = p_145839_1_.getInteger ("processing");
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void updateEntity () {
		super.updateEntity ();

		// skip client execution
		if (this.worldObj.isRemote) return;

		// skip if no item is inside
		if (this.item == null) return;

		// spit out result
		if (this.processing == 0) {
			// find result
			ItemStack result = craftingMap.get (this.item).copy ();

			// create entity
			EntityItem item = new EntityItem (this.worldObj, this.xCoord, (this.yCoord + 1), this.zCoord, result);

			// set velocity
			item.addVelocity (0, 0.25f, 0);

			// drop in world
			this.worldObj.spawnEntityInWorld (item);

			// delete item
			this.item = null;

			// mark update
			this.worldObj.markTileEntityChunkModified (this.xCoord, this.yCoord, this.zCoord, this);
			this.worldObj.markBlockForUpdate (this.xCoord, this.yCoord, this.zCoord);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void writeToNBT (NBTTagCompound p_145841_1_) {
		super.writeToNBT (p_145841_1_);

		if (this.item != null) p_145841_1_.setString ("item", Item.itemRegistry.getNameForObject (this.item));
		p_145841_1_.setInteger ("processing", this.processing);
	}
}


text:
<?xml version="1.0" encoding="UTF-8" ?>
<!--

    Copyright (C) 2016 DANS - Data Archiving and Networked Services (info@dans.knaw.nl)

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.0.0"
		  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		  xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.0.0 http://maven.apache.org/xsd/assembly-2.0.0.xsd">
	<id>bin</id>
	<baseDirectory>${artifactId}-${version}</baseDirectory>
	<formats>
		<format>tar.gz</format>
	</formats>
	<fileSets>
		<fileSet>
			<directory>${project.build.directory}</directory>
			<outputDirectory>bin</outputDirectory>
			<includes>
				<include>*.jar</include>
			</includes>
			<excludes>
				<exclude>*.sh</exclude>
				<exclude>version</exclude>
			</excludes>
		</fileSet>
		<fileSet>
			<directory>${project.basedir}/src/main/assembly/dist/bin</directory>
			<outputDirectory>bin</outputDirectory>
			<includes>
				<include>easy-deposit-agreement-creator</include>
			</includes>
			<fileMode>0755</fileMode>
		</fileSet>
		<fileSet>
			<directory>${project.basedir}/src/main/assembly/dist/bin</directory>
			<outputDirectory>bin</outputDirectory>
			<filtered>true</filtered>
			<includes>
				<include>version</include>
			</includes>
			<fileMode>0444</fileMode>
		</fileSet>
		<fileSet>
			<directory>${project.basedir}/src/main/assembly/dist</directory>
			<outputDirectory />
			<excludes>
				<exclude>bin</exclude>
			</excludes>
		</fileSet>
	</fileSets>
	<dependencySets>
		<dependencySet>
			<outputDirectory>lib</outputDirectory>
			<useProjectArtifact>false</useProjectArtifact>
		</dependencySet>
	</dependencySets>
</assembly>


text:
using System;

namespace GenArt.Classes
{
    public static class Tools
    {
        private static readonly Random random = new Random();

        public static readonly int MaxPolygons = 250;

        public static System.Drawing.Color avgColour;

        public static int GetRandomNumber(int min, int max)
        {
            return random.Next(min, max);
        }

        public static int MaxWidth = 200; //why hard-coded to 200? This might be a problem for images of other sizes
        public static int MaxHeight = 200;

        public static bool WillMutate(int mutationRate) //find out if a point should mutate based on mutation rate
        {
            if (GetRandomNumber(0, mutationRate) == 1) //so there will be a 1 in mutationRate (1500) chance of it mutating
                return true;
            return false;
        }
    }
}


text:
<?php

namespace Poe\BehatTrainingBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class PoeBehatTrainingBundle extends Bundle
{
}


text: class Specinfra::Command::Fedora; end


text:
using System.Collections;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SistemaJBSHealth.TestesUnitarios;

namespace SistemaJBSHealth.TestesIntegrados
{
    [TestClass]
    public class TestesIntegrados
    {
        ///[TestMethod]
        //public void TesteIntegradoComoAtendenteQueroCadastrarUmAgendamento()
        //{
        //    //Arrange
        //    Agendamento agendamento =
        //       (new FabricaDeAgendamento())
        //            .InformarExame("234", "Exame 2", 200)
        //            .InformarMedico("444", "Dr.Joao")
        //            .InformarPaciente("12345", "Fabio Margarito")
        //            .InformarExame("1234", "Exame Sangue Completo", 100)
        //            .Criar();

        //    bool retorno;
        //    ISessionORM sessaoNHibernate = new SessionORM();
        //    using (var sessao = NHibernateSessionFactory.Criar().OpenSession())
        //    {
        //        //((SessionORM)sessaoNHibernate).Sessao = sessao;
        //        IServicoDeCadastramentoDeAgendamento servicoDeCadastramentoDeAgendamento = new ServicoDeCadastramentoDeAgendamentoFake(sessaoNHibernate);
        //        retorno = servicoDeCadastramentoDeAgendamento.Cadastrar(agendamento);
        //        sessao.Flush();
        //    }

        //    //Assert
        //    Assert.IsTrue(agendamento.Medico != null);
        //    Assert.IsTrue(agendamento.Paciente != null);
        //    Assert.IsTrue(((IList)agendamento.Exames).Count > 0);
        //    Assert.IsTrue(retorno);
        //}
    }
}


text:
#import <OfficeImport/EXRow.h>

@interface EXRow (Private)
+ (void)edRowFrom:(struct _xmlTextReader *)arg1 edRowInfo:(struct EDRowInfo *)arg2 edRowBlock:(id)arg3 edRowBlocks:(id)arg4 state:(id)arg5;
@end


text:
'use strict';

let errorHandler = function(err, req, res, next) {
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};
  res.status(err.status || 500).send(err.message);
};

module.exports = errorHandler;


text:
package com.intellij.util.xml;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author peter
 * @see DomFileDescription#getAllowedNamespaces(String, com.intellij.psi.xml.XmlFile)
 * @see DomFileDescription#registerNamespacePolicy(String, String...)
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Namespace {
  /**
   * @return logical namespace identifier
   */
  String value();
}


text:
namespace views {
namespace test {

InkDropRippleTestApi::InkDropRippleTestApi(InkDropRipple* ink_drop_ripple)
    : ui::test::MultiLayerAnimatorTestController(this),
      ink_drop_ripple_(ink_drop_ripple) {}

InkDropRippleTestApi::~InkDropRippleTestApi() = default;

std::vector<ui::LayerAnimator*> InkDropRippleTestApi::GetLayerAnimators() {
  return std::vector<ui::LayerAnimator*>();
}

}  // namespace test
}  // namespace views