text:
/** xmlparse.c

    Main focal point of XML parser. Made up of lexer, parser and load/save routines/support.
*/

#include <errno.h>
#include "xmlparse.h"
#include "xmltree.h"
#include "qalloc.h"

struct XmlNodeListElem {
    XmlNode *node;
    struct XmlNodeListElem *next;
};

struct XmlContentListElem {
    char *content;
    int size;
    int totalSize;
    struct XmlContentListElem *next;
};

enum XmlParserState {
    STATE_START,
    STATE_TAG_OPENED,
    STATE_INSIDE_TAG,
    STATE_GET_ATTR_EQ,
    STATE_GET_ATTR_VAL,
    STATE_GET_POSSIBLE_CONTENT,
    STATE_END_TAG_OPENED,
    STATE_EXPECT_END_TAG_CLOSE,
};

/* parser internal variables... obviously, we're not thread-safe :P */
static int lineNo;
static int linesSkipped;
static const char *xmlFile;
static bool inTag;
static void *xmlHeap;
static XmlParserState parserState;
static char *attrName;
static int attrNameLen;
static XmlNodeListElem *nodeStack;
static XmlNode *xmlRoot;

static void initializeParser(const char *fileName, void *heap, int heapSize)
{
    lineNo = 1;
    linesSkipped = 0;
    xmlFile = strrchr(fileName, '\\');
    xmlFile = xmlFile ? xmlFile + 1 : fileName;
    inTag = false;
    qHeapInit(heap, heapSize);
    xmlHeap = heap;
    parserState = STATE_START;
    nodeStack = nullptr;
    attrName = nullptr;
    attrNameLen = 0;
    xmlRoot = nullptr;
}

#ifdef DEBUG
static void report(const char *text)
{
    WriteToLog("%s(%d): %s", xmlFile, lineNo, text);
}
#else
#define report(text) ((void)0)
#endif

static const char *SymToStr(XmlSymbol sym)
{
    static_assert(XML_SYM_MAX == 7, "Xml symbols changed.");
    switch (sym) {
    case XML_SYM_TAG_OPEN:
        return "<";
    case XML_SYM_TAG_OPEN_END_TAG:
        return "</";
    case XML_SYM_TAG_CLOSE:
        return ">";
    case XML_SYM_TAG_CLOSE_SOLO_TAG:
        return "/>";
    case XML_SYM_EQ:
        return "=";
    case XML_SYM_TEXT:
        return "<text>";
    case XML_SYM_EOF:
        return "end of file";
    case XML_SYM_MAX:
        return "invalid symbol";
    default:
        assert_msg(0, "who was messing with xml symbols enum?");
        return "";
    }
}

static void *XmlAlloc(int size)
{
    void *mem = qHeapAlloc(xmlHeap, size);
    assert(xmlHeap && size > 0);

    if (!mem)
        report("error: Out of memory.");

    return mem;
}

static char *XmlStrdup(char *data, int len)
{
    char *copy = (char *)XmlAlloc(len + 1);
    assert(len > 0);

    if (copy) {
        memcpy(copy, data, len);
        copy[len] = '\0';
        return copy;
    }

    return nullptr;
}

static void XmlFree(void *ptr)
{
    qHeapFree(xmlHeap, ptr);
}

static bool PushNode(XmlNode *node)
{
    XmlNodeListElem *elem = (XmlNodeListElem *)XmlAlloc(sizeof(XmlNodeListElem));
    assert(xmlHeap);

    if (!elem)
        return false;

    elem->node = node;
    elem->next = nodeStack;

    if (nodeStack)
        AddXmlNode(nodeStack->node, node);

    nodeStack = elem;
    return true;
}

static XmlNode *PopNode()
{
    XmlNodeListElem *elem = nodeStack;
    assert(xmlHeap && nodeStack);
    nodeStack = nodeStack->next;
    return elem->node;
}

static XmlNode *TopNode()
{
    assert(xmlHeap && nodeStack);
    return nodeStack->node;
}

static XmlNode *PeekTopNode()
{
    assert(xmlHeap);
    return nodeStack ? nodeStack->node : nullptr;
}

/** GetXmlEscape

    file -> buffered XML file to read from

    & was already encountered, by using state matching determine if we have XML escape, one of:

    <    <   less than
    >    >   greater than
    &   &   ampersand
    '  '   apostrophe
    "  "   quotation mark

    Return character replacement or 0 if not escape sequence.
*/
static char GetXmlEscape(BFile *file)
{
    int readChars[4];       /* hold all characters encountered so far */
    int count = 1;          /* keep count of read characters */
    readChars[0] = GetCharBFile(file);

    assert(file);
    /* < */
    if (readChars[0] == 'l') {
        readChars[count++] = GetCharBFile(file);
        if (readChars[1] == 't') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[2] == ';')
                return '<';
        }
    /* > */
    } else if (readChars[0] == 'g') {
        readChars[count++] = GetCharBFile(file);
        if (readChars[1] == 't') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[2] == ';')
                return '>';
        }
    /* & and ' */
    } else if (readChars[0] == 'a') {
        readChars[count++] = GetCharBFile(file);
        if (readChars[1] == 'm') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[2] == 'p') {
                readChars[count++] = GetCharBFile(file);
                if (readChars[3] == ';')
                    return '&';
            }
        } else if (readChars[1] == 'p') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[2] == 'o') {
                readChars[count++] = GetCharBFile(file);
                if (readChars[3] == 's') {
                    readChars[count++] = GetCharBFile(file);
                    if (readChars[4] == ';')
                        return '\'';
                }
            }
        }
    /* " */
    } else if (readChars[0] == 'q') {
        readChars[count++] = GetCharBFile(file);
        if (readChars[1] == 'u') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[2] == 'o') {
                readChars[count++] = GetCharBFile(file);
                if (readChars[3] == 't') {
                    readChars[count++] = GetCharBFile(file);
                    if (readChars[4] == ';')
                        return '"';
                }
            }
        }
    }

    /* no match, return all read characters to stream */
    while (count--)
        UngetCharBFile(file, readChars[count]);

    return 0;
}

/** GetStringEscape

    file -> buffered XML file to read from

    Slash inside a string was encountered, resolve and return any escaped characters.
    Return -1 for invalid escape sequence.
*/
static int GetStringEscape(BFile *file)
{
    int readChars[3];
    size_t count = 1;

    assert(file);
    readChars[0] = GetCharBFile(file);

    if (readChars[0] == '\\')
        return '\\';
    else if (readChars[0] == 'n')
        return '\n';
    else if (readChars[0] == 'r')
        return '\r';
    else if (readChars[0] == 't')
        return '\t';
    else if (readChars[0] == 'b')
        return '\b';
    else if (readChars[0] == '"')
        return '"';
    else if (readChars[0] == '\'')
        return '\'';
    else if (readChars[0] == 'x') {
        uint32_t val = 0;
        int c;
        int hexCount = 0;

        while (c = GetCharBFile(file), isxdigit(c) && hexCount++ < 2) {
            if (count < sizeofarray(readChars)) {
                readChars[count++] = c;
                val = (val << 4) | (c > '9' ? (c | 0x20) - 'a' + 10 : c - '0');
            }
        }

        UngetCharBFile(file, c);

        if (!hexCount)
            report("\\x used with no following hex digits.");

        if (hexCount > 0)
            return val & 0xff;
    } else if (isdigit(readChars[0])) {
        int c;
        int digitCount = 1;
        int val = readChars[0] - '0';
        while (c = GetCharBFile(file), isdigit(c)) {
            if (count < sizeofarray(readChars)) {
                /* screw octal, who the hell needs that */
                readChars[count++] = c;
                val = val * 10 + c - '0';
            }
            digitCount++;
        }

        UngetCharBFile(file, c);

        if (digitCount > 3 || val > 255)
            report("Numeric escape sequence out of range.");
        return val & 0xff;
    }
    /* no match, return all read characters to stream */
    assert((int)count >= 0 && count < sizeofarray(readChars));

    while (count--)
        UngetCharBFile(file, readChars[count]);

    return -1;
}

/** SkipXmlComment

    file -> buffered XML file to read from

    Start XML comment symbol has already been found, now skip everything until end of comment symbol.
*/
static void SkipXmlComment(BFile *file)
{
    int c;
    int count;
    char readChars[2];
    assert(file);

    while ((c = GetCharBFile(file)) >= 0) {
        count = 0;
        if (c == '-') {
            readChars[count++] = GetCharBFile(file);
            if (readChars[0] == '-') {
                readChars[count++] = GetCharBFile(file);
                if (readChars[1] == '>')
                    return;
            }
        } else if (c == '\n')
            lineNo++;
        while (count--)
            UngetCharBFile(file, readChars[count]);
    }

    if (c < 0)
        report("Unterminated comment found.");

    UngetCharBFile(file, c);
}

/** GetText

    file    -> buffered XML file to read from
    inTag   -  true if we are inside XML tag, break text into tokens then
    buf     -> buffer to receive collected text
    bufSize -> maximum size of text buffer

    Terminate buffer with zero and return number of characters written to buffer (not counting ending zero).
    Any text blocks interspersed with strings will be merged and returned as a single block.
*/
static int GetText(BFile *file, bool inTag, char *buf, int bufSize)
{
    int c;
    int inQuote = 0;
    char *p = buf, *stringEnd = buf;

    assert(file);
    assert(bufSize >= 0);
    assert(buf);

    /* get rid of initial whitespace */
    while (isspace(PeekCharBFile(file)))
        lineNo += GetCharBFile(file) == '\n';

    while ((c = GetCharBFile(file)) >= 0) {
        if (c == '&') {
            char escaped = GetXmlEscape(file);
            if (escaped)
                c = escaped;
        } else if (c == '"') {
            /* get rid of whitespaces before and after strings */
            if (!(inQuote ^= 1)) {
                stringEnd = max(p - 1, buf);
                if (!inTag)
                    while (isspace(PeekCharBFile(file)))
                        lineNo += GetCharBFile(file) == '\n';
            } else
                while (p - 1 > stringEnd && isspace(p[-1]))
                    lineNo -= *--p == '\n';
            continue;
        } else if (inQuote) {
            if (c == '\\') {
                int escaped = GetStringEscape(file);
                if (escaped >= 0)
                    c = escaped;
            }
        } else if (c == '<') {
            /* we can't warn about nested tags here, as it might only be a comment */
            UngetCharBFile(file, '<');
            break;
        } else if (c == '/') {
            if (PeekCharBFile(file) == '>') {
                UngetCharBFile(file, '/');
                break;
            }
        } else if (c == '>') {
            UngetCharBFile(file, '>');
            break;
        } else if (inTag) {
            if (c == '=') {
                UngetCharBFile(file, '=');
                break;
            } else if (isspace(c)) {
                while (isspace(PeekCharBFile(file)))
                    lineNo += GetCharBFile(file) == '\n';
                break;
            }
        }

        if (bufSize > 0) {
            *p++ = c;
            bufSize--;
            lineNo += c == '\n';
        }
    }
    if (inQuote) {
        report("Unterminated string found.");
    } else {
        /* remove trailing whitespace if not quoted */
        if (p > buf) {
            int currentLineNo = lineNo;

            while (isspace(p[-1]) && p > stringEnd + 1)
                lineNo -= *--p == '\n';

            /* we have to report line number for this symbol correctly, but we also have to
               maintain correct line number for the symbol that follows */
            linesSkipped = currentLineNo - lineNo;
            assert(linesSkipped >= 0);
        }
    }
    assert(p >= buf);
    if (bufSize > 0)
        *p = '\0';

    else if (p > buf)
        *--p = '\0';

    return p - buf;
}

/** GetSymbol

    file    -> buffered file to read from
    buf     -> buffer to store found text to
    bufSize -> the size of given buffer on entry,
               number of characters written on exit

    Main lexer routine. Return symbol found, along with text, if any. Buffer will always be
    null-terminated if it's size is at least one. Size returned will not include ending zero.
*/
static XmlSymbol GetSymbol(BFile *file, char *buf, int *bufSize)
{
    int numCharsMatched;
    int matchedChars[3];

    int c = GetCharBFile(file);
    lineNo += linesSkipped;
    linesSkipped = 0;

    switch (c) {
    case '<':
        /* this could be open tag, open ending tag or an xml comment */
        numCharsMatched = 1;
        matchedChars[0] = GetCharBFile(file);
        if (matchedChars[0] == '/') {
            inTag = true;
            return XML_SYM_TAG_OPEN_END_TAG;
        } else if (matchedChars[0] == '!') {
            matchedChars[numCharsMatched++] = GetCharBFile(file);
            if (matchedChars[1] == '-') {
                matchedChars[numCharsMatched++] = GetCharBFile(file);
                if (matchedChars[2] == '-') {
                    SkipXmlComment(file);
                    return GetSymbol(file, buf, bufSize);
                }
            }
        }
        while (numCharsMatched--)
            UngetCharBFile(file, matchedChars[numCharsMatched]);
        inTag = true;
        return XML_SYM_TAG_OPEN;

    case '>':
        inTag = false;
        return XML_SYM_TAG_CLOSE;

    case '/':
        if (PeekCharBFile(file) == '>') {
            GetCharBFile(file);
            inTag = false;
            return XML_SYM_TAG_CLOSE_SOLO_TAG;
        }
        break;

    case '=':
        if (inTag)
            return XML_SYM_EQ;
        break;

    case -1:
        return XML_SYM_EOF;
    }

    UngetCharBFile(file, c);
    /* don't return 0-sized text */
    return (*bufSize = GetText(file, inTag, buf, *bufSize)) ? XML_SYM_TEXT : GetSymbol(file, buf, bufSize);
}

static bool Expect(XmlSymbol expected, XmlSymbol given)
{
    if (expected != given) {
        WriteToLog("%s(%d): error: Expected '%s', got '%s' instead.",
            xmlFile, lineNo, SymToStr(expected), SymToStr(given));
        return false;
    }

    return true;
}

static bool FixXmlNodeContent(XmlNode *node)
{
    XmlContentListElem *elem;
    char *contents;
    int currentOffset, totalSize;
    assert(node);

    if (node->type != XML_STRING && node->type != XML_ARRAY)
        return true;

    if (node->type == XML_STRING && !node->value.ptr) {
        node->value.ptr = (char *)XmlAlloc(1);
        node->value.ptr[0] = '\0';
        node->length = 1;
        return true;
    }

    assert(node->value.ptr);
    totalSize = ((XmlContentListElem *)node->value.ptr)->totalSize;
    assert(totalSize > 0);
    contents = (char *)XmlAlloc(totalSize + (node->type == XML_STRING));
    assert(contents);

    if (!contents)
        return false;

    elem = (XmlContentListElem *)node->value.ptr;
    currentOffset = totalSize;

    if (node->type == XML_STRING)
        contents[currentOffset] = '\0';

    while (elem) {
        currentOffset -= elem->size;
        memcpy(contents + currentOffset, elem->content, elem->size);
        elem = elem->next;
    }

    assert(currentOffset == 0);
    node->value.ptr = contents;
    node->length = totalSize + (node->type == XML_STRING);
    return true;
}

static bool AddXmlPartialContent(XmlNode *node, char *content, int size)
{
    int value, error, length;
    const char *endPtr;
    bool outOfRange = false;
    XmlNodeType type;

    assert(node && content && size >= 0);
    type = XmlNodeGetType(node);

    if (type == XML_EMPTY) {
        report("error: Empty node can't have content.");
        return false;
    } else if (type != XML_STRING && type != XML_ARRAY) {
        if (XmlNodeHasContent(node)) {
            report("error: Only strings and arrays are allowed to be splitted.");
            return false;
        }
        switch (type) {
        case XML_CHAR:
        case XML_SHORT:
        case XML_INT:
            value = strtol(content, &endPtr, 10, &error);
            if (error == ERANGE)
                outOfRange = true;
            else if (error == EZERO && endPtr == content + size) {
                if (type == XML_CHAR && (value < -128 || value > 127))
                    outOfRange = true;
                else if (type == XML_SHORT && (value < -32768 || value > 32767))
                    outOfRange = true;
            }
            if (outOfRange) {
                report("Numerical value out of specified range.");
            } else if (error != EZERO || endPtr != content + size) {
                report("error: Invalid numerical constant.");
                return false;
            }
            length = 1;
            if (type == XML_SHORT)
                length = 2;
            else if (type == XML_INT)
                length = 4;
            return AddXmlContent(node, type, &value, length);
        default:
            return AddXmlContent(node, type, content, size);
        }
    } else {
        XmlContentListElem *lastElem = (XmlContentListElem *)node->value.ptr;
        XmlContentListElem *elem = (XmlContentListElem *)XmlAlloc(sizeof(XmlContentListElem));

        if (!elem)
            return false;

        elem->content = XmlStrdup(content, size);
        elem->size = elem->totalSize = size;

        if (lastElem)
            elem->totalSize += lastElem->totalSize;

        elem->next = lastElem;
        node->value.ptr = (char *)elem;
    }

    return true;
}

/** ProcessSymbol

    sym      - symbol found
    buf     -> buffer containing symbol data; always zero-terminated if size is at least 1
    bufSize  - size of given buffer

    Parsing work horse. Driven by state machine. Goes to next state based on current state and input.
*/
static bool ProcessSymbol(XmlSymbol sym, char *buf, int bufSize)
{
    XmlNode *newNode;
    switch (parserState) {
    case STATE_START:
        if (sym == XML_SYM_EOF) {
            if (!xmlRoot) {
                report("error: Root element missing.");
                return false;
            }
            return true;
        }

        if (!PeekTopNode() && !Expect(XML_SYM_TAG_OPEN, sym))
            return false;

        parserState = STATE_TAG_OPENED;
        return true;

    case STATE_TAG_OPENED:
        if (!Expect(XML_SYM_TEXT, sym))
            return false;
        assert(bufSize);
        parserState = STATE_INSIDE_TAG;

        /* new node opened, it is root if node stack is empty */
        newNode = NewEmptyXmlNode(buf, bufSize);
        if (!PeekTopNode()) {
            if (xmlRoot) {
                report("error: More than one root element found.");
                return false;
            }
            xmlRoot = newNode;
        }
        return PushNode(newNode);

    case STATE_INSIDE_TAG:
        if (sym == XML_SYM_TAG_CLOSE || sym == XML_SYM_TAG_CLOSE_SOLO_TAG) {
            assert(TopNode());
            if (sym == XML_SYM_TAG_CLOSE_SOLO_TAG) {
                if (!FixXmlNodeContent(TopNode()))
                    return false;
                PopNode();
            }
            parserState = PeekTopNode() ? STATE_GET_POSSIBLE_CONTENT : STATE_START;
            return true;
        } else if (sym == XML_SYM_TEXT) {
            XmlFree(attrName);

            if (!(attrName = XmlStrdup(buf, bufSize)))
                return false;

            attrNameLen = bufSize;
            parserState = STATE_GET_ATTR_EQ;
            return true;
        } else {
            char error[128];
            sprintf(error, "error: Unexpected symbol '%s' inside a tag.", SymToStr(sym));
            report(error);
            return false;
        }
        /* assume fall-through */

    case STATE_GET_ATTR_EQ:
        if (!Expect(XML_SYM_EQ, sym))
            return false;
        parserState = STATE_GET_ATTR_VAL;
        return true;

    case STATE_GET_ATTR_VAL:
        if (!(Expect(XML_SYM_TEXT, sym)))
            return false;

        parserState = STATE_INSIDE_TAG;
        assert(attrName && attrNameLen);
        return AddXmlNodeAttribute(TopNode(), attrName, attrNameLen, buf, bufSize);

    case STATE_GET_POSSIBLE_CONTENT:
        if (sym == XML_SYM_TEXT) {
            /* remain in this state */
            return AddXmlPartialContent(TopNode(), buf, bufSize);
        } else if (sym == XML_SYM_TAG_OPEN) {
            parserState = STATE_TAG_OPENED;
            return true;
        } else if (sym == XML_SYM_TAG_OPEN_END_TAG) {
            parserState = STATE_END_TAG_OPENED;
            return true;
        } else {
            char error[128];
            sprintf(error, "error: Unexpected symbol '%s' found inside tag content.", SymToStr(sym));
            report(error);
            return false;
        }
        /* assume fall-through */

    case STATE_END_TAG_OPENED:
        if (!Expect(XML_SYM_TEXT, sym))
            return false;

        if (strncmp(TopNode()->name, buf, bufSize)) {
            report("error: Closing tag doesn't match opening.");
            return false;
        }

        parserState = STATE_EXPECT_END_TAG_CLOSE;
        return true;

    case STATE_EXPECT_END_TAG_CLOSE:
        if (!Expect(XML_SYM_TAG_CLOSE, sym))
            return false;

        if (!FixXmlNodeContent(TopNode()))
            return false;

        PopNode();
        /* go back to start state if we're not inside any tag */
        parserState = PeekTopNode() ? STATE_GET_POSSIBLE_CONTENT : STATE_START;
        return true;

    default:
        assert_msg(0, "Unhandled xml parser state encountered.");
    }

    return false;
}

bool LoadXmlFile(XmlNode **root, const char *fileName, XmlSymbolProcessingFunction symProc)
{
    XmlSymbol sym;
    char xmlBuf[8 * 1024];
    int bufSize = sizeof(xmlBuf);
    char miniHeap[32 * 1024];
    bool success = true;
    BFile *file;

    if (root)
        *root = nullptr;

    if (!(file = OpenBFile(F_READ_ONLY, fileName)))
        return false;

    initializeParser(fileName, miniHeap, sizeof(miniHeap));
    auto oldSplitSize = qSetMinSplitSize(16);

    if (!symProc)
        symProc = ProcessSymbol;

    while ((sym = GetSymbol(file, xmlBuf, &bufSize)) != XML_SYM_EOF) {
        //WriteToLog("state: %d symbol: %s '%s'", parserState, SymToStr(sym), sym == XML_SYM_TEXT ? xmlBuf : "");
        if (!symProc(sym, xmlBuf, bufSize)) {
            qSetMinSplitSize(oldSplitSize);
            CloseBFile(file);
            return false;
        }
        bufSize = sizeof(xmlBuf);
    }

    /* notify callback about EOF too */
    success = symProc(sym, xmlBuf, bufSize);

    CloseBFile(file);
    qSetMinSplitSize(oldSplitSize);

    if (root) {
        ReverseChildren(xmlRoot);
        *root = xmlRoot;
    }

    return success;
}

static bool NeedsQuotes(const char *str, size_t len)
{
    assert(str);
    while (len--) {
        if (*str < 32 || *str > 126)
            return true;

        switch (*str) {
        case '"':
        case '=':
        case '<':
        case '>':
        case '/':
        case '\\':
        case ' ':
            return true;
        }

        str++;
    }
    return false;
}

/* saves a lot of typing :P */
#define OUT_CHAR(c)         { if (!PutCharBFile(file, c)) return false; }
#define OUT_STR(str, len)   { if (!WriteStringToFile(file, str, len, indent, true)) return false; }
#define INDENT(len)         { int i; for (i = 0; i < (len); i++) OUT_CHAR(' '); }

static bool WriteStringToFile(BFile *file, const char *string, size_t stringLen, int indent, bool zeroTerminated)
{
    assert(file && string);
    if (NeedsQuotes(string, stringLen)) {
        int lineChars = indent + 1 + 4;
        OUT_CHAR('"');

        while (stringLen-- && (!zeroTerminated || *string)) {
            if (*string < 32 || *string > 126) {
                int hiByte = (*string & 0xf0) >> 4;
                int loByte = *string & 0x0f;
                OUT_CHAR('\\');
                OUT_CHAR('x');
                OUT_CHAR(hiByte + (hiByte > 9 ? 'a' - 10 : '0'));
                OUT_CHAR(loByte + (loByte > 9 ? 'a' - 10 : '0'));
                lineChars += 4;
            } else if (*string == '"') {
                OUT_CHAR('\\');
                OUT_CHAR('"');
                lineChars += 2;
            } else if (*string == '\\') {
                OUT_CHAR('\\');
                OUT_CHAR('\\');
                lineChars += 4;
            } else if (*string == '\r') {
                OUT_CHAR('\\');
                OUT_CHAR('r');
                lineChars += 4;
            } else if (*string == '\n') {
                OUT_CHAR('\\');
                OUT_CHAR('n');
                lineChars += 4;
            } else if (*string == '\t') {
                OUT_CHAR('\\');
                OUT_CHAR('t');
                lineChars += 4;
            } else {
                OUT_CHAR(*string);
                lineChars++;
            }
            string++;
            if (lineChars > 99 && stringLen) {
                OUT_CHAR('"');
                OUT_CHAR('\n');
                INDENT(indent + 4);
                OUT_CHAR('"');
                lineChars = indent + 1 + 4;
            }
        }

        OUT_CHAR('"');
        return true;
    } else {
        if (stringLen > 100) {
            while (stringLen > 0) {
                INDENT(indent);
                OUT_CHAR('"');
                if (WriteBFile(file, string, 100) != 100)
                    return false;
                OUT_CHAR('"');
                OUT_CHAR('\n');
                stringLen -= 100;
            }
            return true;
        } else
            return WriteBFile(file, string, stringLen) == (int)stringLen;
    }
}

static bool WriteNodeContent(BFile *file, const XmlNode *node, int indent)
{
    int val = 0;
    char *numStr;
    assert(file && node);

    switch (XmlNodeGetType(node)) {
    case XML_CHAR:
        val = *node->value.charVal;
        break;

    case XML_SHORT:
        val = *node->value.shortVal;
        break;

    case XML_INT:
        val = *node->value.intVal;
        break;

    case XML_STRING:
    case XML_ARRAY:
        return WriteStringToFile(file, node->value.ptr, node->length - XmlNodeIsString(node),
            indent, XmlNodeIsString(node));

    case XML_EMPTY:
    case XML_FUNC:  // FIXME
        return true;

    default:
        assert_msg(0, "Don't know how to write this content type!");
    }

    numStr = int2str(val);
    return WriteBFile(file, numStr, strlen(numStr));
}

static bool WriteTreeToFile(BFile *file, const XmlNode *root, int indent)
{
    bool soloNode = false;
    bool isNumericNode;
    static XmlAttributeInfo attributes[64];
    size_t numAttributes;

    if (!root || XmlNodeIsAnonymous(root))
        return true;

    do {
        if (XmlNodeIsAnonymous(root)) {
            root = XmlNodeGetNextSibling(root);
            continue;
        }

        isNumericNode = XmlNodeIsNumeric(root);

        /* open tag and write name */
        INDENT(indent);
        OUT_CHAR('<');
        OUT_STR(XmlNodeGetName(root), XmlNodeGetNameLength(root));

        numAttributes = GetXmlNodeNumAttributes(root);
        /* make sure to write type attribute even if it's not explicitly added, and in 1st spot */
        if (!XmlNodeIsEmpty(root) && !XmlNodeIsFunc(root) && !GetXmlNodeAttribute(root, "type", 4, nullptr)) {
            size_t typeNameLen;
            const char *typeName = XmlNodeTypeToString(XmlNodeGetType(root), &typeNameLen);
            OUT_CHAR(' ');
            OUT_STR("type", 4);
            OUT_CHAR('=');
            OUT_CHAR('"');
            OUT_STR(typeName, typeNameLen);
            OUT_CHAR('"');
        }

        /* write other attributes, if present */
        assert(numAttributes <= sizeofarray(attributes));
        GetXmlNodeAttributes(root, attributes);

        for (size_t i = 0; i < numAttributes; i++) {
            OUT_CHAR(' ');
            OUT_STR(attributes[i].name, attributes[i].nameLength);
            OUT_CHAR('=');
            OUT_STR(attributes[i].value, attributes[i].valueLength);
        }

        if (XmlNodeIsLeaf(root) && !XmlNodeHasContent(root)) {
            soloNode = true;
            OUT_CHAR(' ');
            OUT_CHAR('/');
        } else
            soloNode = false;

        OUT_CHAR('>');

        /* tag closed, write content, if present */
        if (XmlNodeHasContent(root)) {
            if (!isNumericNode) {
                OUT_CHAR('\n');
                INDENT(indent + 4);
            }
            if (!WriteNodeContent(file, root, indent))
                return false;

            if (!isNumericNode)
                OUT_CHAR('\n');
        } else
            OUT_CHAR('\n');

        /* handle custom data nodes */
        if (XmlNodeIsFunc(root))
            RefreshFuncData(root);

        /* write subtree if present */
        if (!XmlNodeIsLeaf(root) && !WriteTreeToFile(file, root->children, indent + (soloNode ? 0 : 4)))
            return false;

        if (!soloNode) {
            if (!isNumericNode)
                INDENT(indent);
            OUT_CHAR('<');
            OUT_CHAR('/');
            OUT_STR(XmlNodeGetName(root), XmlNodeGetNameLength(root));
            OUT_CHAR('>');
            OUT_CHAR('\n');
        }
        root = XmlNodeGetNextSibling(root);
    } while (root);

    return true;
}

bool SaveXmlFile(XmlNode *root, const char *fileName, bool checkIfNeeded)
{
    BFile *file;
    bool result;

    if (!root)
        return false;

    if (checkIfNeeded && XmlTreeUnmodified(root)) {
        WriteToLog("%s not modified, returning.", fileName);
        return true;
    }

    if (!(file = CreateBFile(ATTR_NONE, fileName))) {
        WriteToLog("Failed to create %s.", fileName);
        return false;
    }

    /* mark it as unmodified if we saved it successfully */
    if ((result = WriteTreeToFile(file, root, 0)))
        XmlTreeSnapshot(root);

    if (result)
        WriteToLog("%s written successfully.", fileName);

    CloseBFile(file);
    return result;
}


text:
'''
This module consists of test cases where IronPython was broken under standard CPython
Python-based modules.
'''

import os
import sys
import unittest

from iptest import IronPythonTestCase, is_cpython, is_netcoreapp, is_posix, run_test, skipUnlessIronPython

class StdModulesTest(IronPythonTestCase):

    def test_cp8678(self):
        from itertools import izip
        x = iter(range(4))
        expected = ([0, 1], [2, 3])
        actual = []

        for i, j in izip(x, x):
            actual.append([i, j])

        self.assertEqual(len(expected), len(actual))
        for i in xrange(len(expected)):
            self.assertEqual(expected[i], actual[i])

    def test_cp10825(self):
        import urllib
        from time import sleep

        #Give it five chances to connect
        temp_url = None

        for i in xrange(5):
            try:
                temp_url = urllib.urlopen("http://www.microsoft.com")
                break
            except Exception, e:
                print ".",
                sleep(5)
                continue
        if temp_url==None: raise e

        try:
            self.assertTrue(temp_url.url.startswith("http://www.microsoft.com"))
        finally:
            temp_url.close()

    def test_cp5566(self):
        import base64
        self.assertEqual(base64.decodestring('w/=='), '\xc3')
        test_str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+-=[]\{}|;':,.//<>?\""
        test_str+= "/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/0/1/2/3/4/5/6/7/8/9/~/!/@/#/$/%/^/&/*/(/)/_/+/-/=/[/]/\/{/}/|/;/'/:/,/.///</>/?\""

        for str_function in [str, unicode]:
            self.assertEqual(base64.decodestring(str_function(test_str)),
                    'i\xb7\x1dy\xf8!\x8a9%\x9az)\xaa\xbb-\xba\xfc1\xcb0\x01\x081\x05\x18r\t(\xb3\r8\xf4\x11I5\x15Yv\x19\xd3]\xb7\xe3\x9e\xbb\xf3\xdf')

    def test_cp35507(self):
        import base64
        self.assertEqual(base64.b64decode('MTIzNP8='), '1234\xff')
        self.assertEqual(base64.b64decode(b'MTIzNP8='), '1234\xff')
        self.assertEqual(base64.b64encode('1234\xff'), 'MTIzNP8=')
        self.assertEqual(base64.b64encode(b'1234\xff'), 'MTIzNP8=')

        import cPickle
        one = cPickle.dumps(1)
        self.assertEqual(1, cPickle.loads("I1\n."))
        self.assertEqual(1, cPickle.loads(b"I1\n."))
        self.assertEqual(1, cPickle.loads(one))
        self.assertEqual(1, cPickle.loads(bytes(one)))

    @skipUnlessIronPython()
    def test_cp13618(self):
        import os
        from System.IO.Path import PathSeparator
        self.assertEqual(os.pathsep, PathSeparator)

    def test_cp12907(self):
        #from codeop import compile_command, PyCF_DONT_IMPLY_DEDENT
        from os import unlink

        f_name = "fake_stdout.txt"
        test_list = [
                        ("print 1",
                            "single", ["1\n"]),
                        ("print 1",
                            "exec", ["1\n"]),
                        ("1",
                            "single", ["1\n"]),
                        ("1",
                            "exec", []),
                        ("def f(n):\n    return n*n\nprint f(3)",
                            "exec", ["9\n"]),
                        ("if 1:\n    print 1\n",
                            "single", ["1\n"]),
                        ("if 1:\n    print 1\n",
                            "exec", ["1\n"]),
                    ]

        if is_cpython: #http://ironpython.codeplex.com/workitem/28221
            test_list.append(("if 1:\n    print 1", "exec", ["1\n"]))

        for test_case, kind, expected in test_list:

            c = compile(test_case, "", kind, 0x200, 1)
            try:
                orig_stdout = sys.stdout

                sys.stdout = open(f_name, "w")
                exec c
                sys.stdout.close()

                t_file = open(f_name, "r")
                lines = t_file.readlines()
                t_file.close()

                self.assertEqual(lines, expected)

            finally:
                sys.stdout = orig_stdout
        os.unlink(f_name)

        #negative cases
        bad_test_list = [
                        ("def f(n):\n    return n*n\n\nf(3)\n", "single"),
                        ("def f(n):\n    return n*n\n\nf(3)",   "single"),
                        ("def f(n):\n    return n*n\n\nf(3)\n", "single"),
                        ("if 1:\n    print 1",                  "single"),
                    ]
        if not is_cpython: #http://ironpython.codeplex.com/workitem/28221
            bad_test_list.append(("if 1:\n    print 1",                  "exec"))

        for test_case, kind in bad_test_list:
            print test_case, kind
            self.assertRaises(SyntaxError, compile, test_case, "", kind, 0x200, 1)

    def test_cp12009(self):
        import os
        import shutil

        dir1 = "temp_test_stdmodules_dir"
        dir2 = dir1 + "2"

        os.mkdir(dir1)
        f = open(os.path.join(dir1, "stuff.txt"), "w")
        f.close()

        try:
            shutil.copytree(dir1, dir2)
            self.assertTrue("stuff.txt" in os.listdir(dir2))
        finally:
            for t_dir in [dir1, dir2]:
                os.unlink(os.path.join(t_dir, "stuff.txt"))
                os.rmdir(t_dir)

    @unittest.skipIf(is_netcoreapp and is_posix, 'TODO: figure out')
    def test_cp17040(self):
        ec = os.system("%s -tt -c \"import os\"" %
                    (sys.executable))
        self.assertEqual(ec, 0)

    @skipUnlessIronPython()
    def test_cp13401(self):
        import System
        import copy

        #A few special cases
        self.assertEqual(System.Char.MinValue, copy.copy(System.Char.MinValue))
        self.assertTrue(System.Char.MinValue != copy.copy(System.Char.MaxValue))
        self.assertEqual(System.StringSplitOptions.None, copy.copy(System.StringSplitOptions.None))
        self.assertEqual(System.StringSplitOptions.RemoveEmptyEntries, copy.copy(System.StringSplitOptions.RemoveEmptyEntries))
        self.assertTrue(System.StringSplitOptions.None != copy.copy(System.StringSplitOptions.RemoveEmptyEntries))

        #Normal cases
        test_dict = {   System.Byte : [System.Byte.MinValue, System.Byte.MinValue+1, System.Byte.MaxValue, System.Byte.MaxValue-1],
                        System.Char : [],
                        System.Boolean : [True, False],
                        System.SByte   : [System.SByte.MinValue, System.SByte.MinValue+1, System.SByte.MaxValue, System.SByte.MaxValue-1],
                        System.UInt32  : [System.UInt32.MinValue, System.UInt32.MinValue+1, System.UInt32.MaxValue, System.UInt32.MaxValue-1],
                        System.Int64   : [System.Int64.MinValue, System.Int64.MinValue+1, System.Int64.MaxValue, System.Int64.MaxValue-1],
                        System.Double  : [0.00, 3.14],
                        }

        for key in test_dict.keys():
            temp_type = key
            self.assertTrue(hasattr(temp_type, "__reduce_ex__"),
                "%s has no attribute '%s'" % (str(temp_type), "__reduce_ex__"))

            for temp_value in test_dict[key]:
                x = temp_type(temp_value)
                x_copy = copy.copy(x)
                self.assertEqual(x, x_copy)
                self.assertEqual(x, temp_value)

    def test_cp7008(self):
        import os
        import sys

        self.assertTrue(os.path.isfile(sys.executable))
        self.assertTrue(not os.path.isfile('"' + sys.executable + '"'))

    @skipUnlessIronPython()
    def test_get_set_locale(self):
        import locale
        locale.setlocale(locale.LC_ALL, 'en-US')
        loc = locale.getlocale(locale.LC_ALL)
        self.assertEqual(loc, ('en_US','ISO8859-1'))

        locale.setlocale(locale.LC_ALL, 'C')
        loc = locale.getlocale(locale.LC_ALL)
        self.assertEqual(loc, (None,None))

        self.assertTrue(locale.setlocale(locale.LC_ALL, '') != None)
        if not is_posix: # TODO: figure this out
            self.assertTrue(locale.getlocale() != None)

    def test_cp17819(self):
        import xml.sax
        self.assertEqual(xml.sax._false, 0)

    #@unittest.skipIf(is_cli, 'CPython')
    def test_cp20162(self):
        import collections
        self.assertRaisesMessage(TypeError, "deque() takes at most 2 arguments (3 given)",
                            collections.deque, 'abc', 2, 2)

    def test_cp20603(self):
        '''
        Just ensure this does not throw a ValueError.
        '''
        import os
        for root, files, dirs in os.walk(''):
            for f in files:
                temp = os.path.join(root, f)

    def test_cp21929(self):
        import os
        self.assertEqual(os.listdir("."),
                os.listdir(os.getcwd()))
        self.assertRaises(WindowsError, os.listdir, "")

    def test_cp34188(self):
        import locale
        locale.setlocale(locale.LC_COLLATE,"de_CH")
        self.assertTrue(sorted([u'a', u'z', u'�'], cmp=locale.strcoll) == sorted([u'a', u'z', u'�'], key=locale.strxfrm))

    def test_gh1144(self):
        from collections import deque
        a = deque(maxlen=0)
        a.append("a")
        self.assertEqual(len(a), 0)

run_test(__name__)

redpajama_set_name: RedPajamaGithub


text:
package com.mad.openisdm.madnew.app;

import android.app.IntentService;
import android.content.Intent;

/**
 * This class is an intent service(a worker thread) that downloads JSON file (in plain text format) and store it
 * in DataHolder.jsonStr.
 *
 * The context(activity) that starts this intent service should register a broadcast receiver in order to receive the result
 * */
public class FetchJSONIntentService extends IntentService {
    public final static String URL_KEY = "URL_KEY";
    public final static String JSON_OBJECT_KEY = "JSONOBJECT_KEY";
    public final static String EXCEPTION_KEY = "EXCEPTION_KEY";

    public FetchJSONIntentService() {
        super("FetchJSONIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        /*Get the url of the JSON file*/
        String url = intent.getStringExtra(URL_KEY);
        /*The result(JSON file in plain text format)*/
        String jsonText = null;
        /*An boolean indicator, if this is true, an IOException has occured while downloading the JSON file(probably because there is no internet access), otherwise this will be false*/
        boolean exception = false;
        try{
            jsonText = JsonReader.readJsonFromUrl(url);
        }catch (Exception e){
            exception = true;
        }

        /*Send an implicit Intent once this intent service ends.
        * The context(activity) that are registered to listen for this implicit intent will receive the intent, and retrieve the result of this worker thread*/
        Intent broadcastIntent = new Intent();
        broadcastIntent.setAction(ShelterManager.JSONBroadcastReceiver.RECEIVE_JSON_ACTION);

        /*Directly modifying static variable is a bad design.
        * It would be safer and more secure to pass jsonText as intent extras, but in this case, it is possible that jsonText exceeds the 1MB maximum size limit
        * for intent extras. Thus the less favourable method. More thinking required*/
        DataHolder.jsonStr = jsonText;
        //broadcastIntent.putExtra(JSON_OBJECT_KEY, jsonText);
        broadcastIntent.putExtra(EXCEPTION_KEY, exception);
        broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
        sendBroadcast(broadcastIntent);
    }
}


text:
//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vhudson-jaxb-ri-2.1-2
// See http://java.sun.com/xml/jaxb
// Any modifications to this file will be lost upon recompilation of the source schema.
// Generated on: 2014.01.30 at 01:53:29 PM CET
//

package ExternalPackages.org.hupo.psi.ms.traml;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

/**
 * List of contacts referenced in the generation or validation of transitions
 *

 *
Java class for ContactListType complex type.
 *

 *
The following schema fragment specifies the expected content contained within this class.
 *

 *

 * <complexType name="ContactListType">
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Contact" type="{http://psi.hupo.org/ms/traml}ContactType" maxOccurs="unbounded"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 *

 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ContactListType", propOrder = {
        "contact"
})
public class ContactListType {

    @XmlElement(name = "Contact", required = true)
    protected List<ContactType> contact;

    /**
     * Gets the value of the contact property.
     *

     *

     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a set method for the contact property.
     *

     *

     * For example, to add a new item, do as follows:
     *

     *    getContact().add(newItem);
     *

     *

     *

     *

     * Objects of the following type(s) are allowed in the list
     * {@link ContactType }
     */
    public List<ContactType> getContact() {
        if (contact == null) {
            contact = new ArrayList<ContactType>();
        }
        return this.contact;
    }

}


text:
package uk.theretiredprogrammer.racetrainingdemonstrator.complexflow;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.text.NumberFormat;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.api.Flow;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.api.FlowElement;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.api.Location;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.ScenarioElement;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.api.KeyPair;
import uk.theretiredprogrammer.racetrainingdemonstrator.core.api.KeyPair.Status;
import static uk.theretiredprogrammer.racetrainingdemonstrator.core.api.KeyPair.Status.BADKEY;
import static uk.theretiredprogrammer.racetrainingdemonstrator.core.api.KeyPair.Status.BADVALUE;
import static uk.theretiredprogrammer.racetrainingdemonstrator.core.api.KeyPair.Status.OK;

/**
 * The ComplexFlow Class - represents a flow which is described by flows (speed
 * and direction) at the four corners points. Flows within the described area
 * are interpolated.
 *
 * @author Richard Linsdale (richard at theretiredprogrammer.uk)
 */
public class ComplexFlow extends FlowElement {

    /**
     * the North East location (top right)
     */
    protected Location northeast = new Location();

    /**
     * the flow at the North East location
     */
    protected Flow northeastFlow = new Flow();

    /**
     * the North West location (top left)
     */
    protected Location northwest = new Location();

    /**
     * the flow at the North West location
     */
    protected Flow northwestFlow = new Flow();

    /**
     * the South East location (bottom right)
     */
    protected Location southeast = new Location();

    /**
     * the flow at the South East location
     */
    protected Flow southeastFlow = new Flow();

    /**
     * the South West location (bottom left)
     */
    protected Location southwest = new Location();

    /**
     * the flow at the South West location
     */
    protected Flow southwestFlow = new Flow();
    private boolean showFlow = false;
    private double showFlowInterval = 100;
    private Color showFlowColour = Color.BLACK;
    private int swing = 10;
    private int period = 120;
    private int shift = 10;
    private int shiftperiod = 120;
    private boolean randomshifts = false;
    //
    private boolean swinging = false;
    private boolean shifting = false;
    private int swingNow = 0;
    private int shiftNow = 0;
    //
    private final double eastedge;
    private final double westedge;
    private final double northedge;
    private final double southedge;

    /**
     * Constructor
     *
     * @param name the instance name to be associated with the flow
     * @param scenario the field of play
     */
    public ComplexFlow(String name, ScenarioElement scenario) {
        super(name, scenario);
        eastedge = scenario.getEast();
        westedge = scenario.getWest();
        northedge = scenario.getNorth();
        southedge = scenario.getSouth();
    }

    /**
     * Advance time.  Recalculate the flow.
     * @param time the new time
     */
    @Override
    public void timerAdvance(int time) {
        // as we are using a sine rule for swing - convert to an angle (in radians)
        double radians = Math.toRadians(((double) time % period) / period * 360);
        swingNow = (int) (Math.sin(radians) * swing);
        // now dela with shifts
        int shiftval;
        double delta = randomshifts ? Math.random() * shiftperiod : time % shiftperiod;
        double quarterPeriod = shiftperiod / 4;
        if (delta < quarterPeriod) {
            shiftval = 0;
        } else if (delta < quarterPeriod * 2) {
            shiftval = -shift;
        } else if (delta < quarterPeriod * 3) {
            shiftval = 0;
        } else {
            shiftval = shift;
        }
        if (randomshifts) {
            // only apply the random shift in 2% of cases - otherwise leave alone
            if (Math.random() <= 0.02) {
                shiftNow = shiftval;
            }
        } else {
            shiftNow = shiftval; // apply the shift
        }
    }

    /**
     * Draw the Flow arrows on the display canvas.
     *
     * @param g2D the 2D graphics object
     * @param pixelsPerMetre the scale factor
     */
    @Override
    public void draw(Graphics2D g2D, double pixelsPerMetre) {
        if (showFlow) { // draw the flow arrows
            //
            double x = westedge + showFlowInterval;
            while (x < eastedge) {
                double y = southedge + showFlowInterval;
                while (y < northedge) {
                    displayWindGraphic(g2D, pixelsPerMetre, x, y);
                    y += showFlowInterval;
                }
                x += showFlowInterval;
            }
        }
    }

    private void displayWindGraphic(Graphics2D g2D, double pixelsPerMetre, double x, double y) {
        GeneralPath p = new GeneralPath();
        p.moveTo(0, 15);
        p.lineTo(0, -15);
        p.moveTo(4, 7);
        p.lineTo(0, 15);
        p.lineTo(-4, 7);
        //
        AffineTransform xform = g2D.getTransform();
        g2D.translate(x, y);
        g2D.scale(1 / pixelsPerMetre, -1 / pixelsPerMetre);
        Flow flow = getFlow(new Location(x, y));
        g2D.rotate(flow.getDirection().getRadians());
        g2D.setColor(showFlowColour);
        g2D.setStroke(new BasicStroke(1));
        g2D.draw(p);
        //
        g2D.setFont(new Font("Sans Serif", Font.PLAIN, 10));
        NumberFormat nf = NumberFormat.getInstance();
        nf.setMaximumFractionDigits(1);
        nf.setMinimumFractionDigits(1);
        String windspeedText = nf.format(flow.getSpeedKnots());
        if (flow.getAngle() >= 0) {
            g2D.translate(-2, 4);
            g2D.rotate(-Math.PI / 2);
        } else {
            g2D.translate(+2, -15);
            g2D.rotate(Math.PI / 2);
        }
        g2D.drawString(windspeedText, 0, 0);
        g2D.setTransform(xform);
    }

    /**
     * Get the Flow at the current time, at the requested location.
     *
     * @param pos location
     * @return the flow
     */
    @Override
    public Flow getFlow(Location pos) {
        Flow f = getFlowWithoutSwing(pos);
        if (swinging) {
            f = new Flow(f);
            f.getDirection().add(swingNow);
        }
        if (shifting) {
            f = new Flow(f);
            f.getDirection().add(shiftNow);
        }
        return f;
    }

    private Flow getFlowWithoutSwing(Location pos) {
        // the flow is modelled over 9 sectors
        // first we can sort out the corner 4 sectors
        if (pos.x <= northwest.x && pos.y >= northwest.y) {
            return northwestFlow;
        }
        if (pos.x >= northeast.x && pos.y >= northeast.y) {
            return northeastFlow;
        }
        if (pos.x <= southwest.x && pos.y <= southwest.y) {
            return southwestFlow;
        }
        if (pos.x >= southeast.x && pos.y <= southeast.y) {
            return southeastFlow;
        }
        // calculate the locations and flows at the edges of the centre sector
        Location west = new Location(getX(northwest, southwest, pos.y), pos.y);
        Flow westFlow = flowAtY(northwest, northwestFlow, southwest, southwestFlow, pos.y);
        Location east = new Location(getX(northeast, southeast, pos.y), pos.y);
        Flow eastFlow = flowAtY(northeast, northeastFlow, southeast, southeastFlow, pos.y);
        Location north = new Location(pos.x, getY(northeast, northwest, pos.x));
        Flow northFlow = flowAtX(northeast, northeastFlow, northwest, northwestFlow, pos.x);
        Location south = new Location(pos.x, getY(southeast, southwest, pos.x));
        Flow southFlow = flowAtX(southeast, southeastFlow, southwest, southwestFlow, pos.x);
        // now look for the 4 centre out sectors
        if (pos.y > north.y) {
            return northFlow;
        }
        if (pos.y < south.y) {
            return southFlow;
        }
        if (pos.x < west.x) {
            return westFlow;
        }
        if (pos.x > east.x) {
            return eastFlow;
        }
        // must be the cental sector
        return flowAtY(north, northFlow, south, southFlow, pos.y);
    }

    private double getX(Location to, Location from, double y) {
        return from.x + (to.x - from.x) * (y - from.y) / (to.y - from.y);
    }

    private double getY(Location to, Location from, double x) {
        return from.y + (to.y - from.y) * (x - from.x) / (to.x - from.x);
    }

    private Flow flowAtX(Location to, Flow toFlow, Location from, Flow fromFlow, double x) {
        double ratio = (x - from.x) / (to.x - from.x);
        return new Flow((int) (fromFlow.getAngle() + ratio * (toFlow.getAngle() - fromFlow.getAngle())),
                fromFlow.getSpeedKnots() + ratio * (toFlow.getSpeedKnots() - fromFlow.getSpeedKnots()));
    }

    private Flow flowAtY(Location to, Flow toFlow, Location from, Flow fromFlow, double y) {
        double ratio = (y - from.y) / (to.y - from.y);
        return new Flow((int) (fromFlow.getAngle() + ratio * (toFlow.getAngle() - fromFlow.getAngle())),
                fromFlow.getSpeedKnots() + ratio * (toFlow.getSpeedKnots() - fromFlow.getSpeedKnots()));
    }

    /**
     * Get the Average flow across the total area.
     *
     * @return the average flow
     */
    @Override
    public Flow getMeanFlow() {
        return new Flow((northeastFlow.getAngle() + northwestFlow.getAngle()
                + southeastFlow.getAngle() + southwestFlow.getAngle()) / 4,
                (northeastFlow.getSpeedKnots() + northwestFlow.getSpeedKnots()
                + southeastFlow.getSpeedKnots() + southwestFlow.getSpeedKnots()) / 4);
    }

    @Override
    protected Status setParameter(KeyPair kp) {
        try {
            switch (kp.key) {
                case "northeastposition":
                    northeast = parseLocation(kp.value);
                    return OK;
                case "northeastfrom":
                    northeastFlow.setAngle(Integer.parseInt(kp.value));
                    return OK;
                case "northeastspeed":
                    northeastFlow.setSpeedKnots(Double.parseDouble(kp.value));
                    return OK;
                case "northwestposition":
                    northwest = parseLocation(kp.value);
                    return OK;
                case "northwestfrom":
                    northwestFlow.setAngle(Integer.parseInt(kp.value));
                    return OK;
                case "northwestspeed":
                    northwestFlow.setSpeedKnots(Double.parseDouble(kp.value));
                    return OK;
                case "southeastposition":
                    southeast = parseLocation(kp.value);
                    return OK;
                case "southeastfrom":
                    southeastFlow.setAngle(Integer.parseInt(kp.value));
                    return OK;
                case "southeastspeed":
                    southeastFlow.setSpeedKnots(Double.parseDouble(kp.value));
                    return OK;
                case "southwestposition":
                    southwest = parseLocation(kp.value);
                    return OK;
                case "southwestfrom":
                    southwestFlow.setAngle(Integer.parseInt(kp.value));
                    return OK;
                case "southwestspeed":
                    southwestFlow.setSpeedKnots(Double.parseDouble(kp.value));
                    return OK;
                case "showflow":
                    showFlow = parseYesNo(kp.value);
                    return OK;
                case "showflowinterval":
                    showFlowInterval = Double.parseDouble(kp.value);
                    return OK;
                case "showflowcolour":
                    showFlowColour = parseColour(kp.value);
                    return OK;
                case "swingangle":
                    swing = Integer.parseInt(kp.value);
                    swinging = period > 0;
                    return OK;
                case "swingperiod":
                    period = Integer.parseInt(kp.value);
                    swinging = period > 0;
                    return OK;
                case "shiftangle":
                    shift = Integer.parseInt(kp.value);
                    shifting = shiftperiod > 0 || randomshifts;
                    return OK;
                case "shiftperiod":
                    shiftperiod = Integer.parseInt(kp.value);
                    shifting = shiftperiod > 0 || randomshifts;
                    return OK;
                case "randomshifts":
                    randomshifts = parseYesNo(kp.value);
                    shifting = shiftperiod > 0 || randomshifts;
                    return OK;
                default:
                    return BADKEY;
            }
        } catch (NumberFormatException numberFormatException) {
            return BADVALUE;
        }
    }

    @Override
    protected Status checkParameter(KeyPair kp) {
        try {
            switch (kp.key) {
                case "northeastposition":
                    parseLocation(kp.value);
                    return OK;
                case "northeastfrom":
                    Integer.parseInt(kp.value);
                    return OK;
                case "northeastspeed":
                    Double.parseDouble(kp.value);
                    return OK;
                case "northwestposition":
                    parseLocation(kp.value);
                    return OK;
                case "northwestfrom":
                    Integer.parseInt(kp.value);
                    return OK;
                case "northwestspeed":
                    Double.parseDouble(kp.value);
                    return OK;
                case "southeastposition":
                    parseLocation(kp.value);
                    return OK;
                case "southeastfrom":
                    Integer.parseInt(kp.value);
                    return OK;
                case "southeastspeed":
                    Double.parseDouble(kp.value);
                    return OK;
                case "southwestposition":
                    parseLocation(kp.value);
                    return OK;
                case "southwestfrom":
                    Integer.parseInt(kp.value);
                    return OK;
                case "southwestspeed":
                    Double.parseDouble(kp.value);
                    return OK;
                case "showflow":
                    parseYesNo(kp.value);
                    return OK;
                case "showflowinterval":
                    Double.parseDouble(kp.value);
                    return OK;
                case "showflowcolour":
                    parseColour(kp.value);
                    return OK;
                case "swingangle":
                    Integer.parseInt(kp.value);
                    return OK;
                case "swingperiod":
                    Integer.parseInt(kp.value);
                    return OK;
                case "shiftangle":
                    Integer.parseInt(kp.value);
                    return OK;
                case "shiftperiod":
                    Integer.parseInt(kp.value);
                    return OK;
                case "randomshifts":
                    parseYesNo(kp.value);
                    return OK;
                default:
                    return BADKEY;
            }
        } catch (NumberFormatException numberFormatException) {
            return BADVALUE;
        }
    }
}


text:
//
//  IGBannerItem.h
//  IGBannerDemo
//
//  Created by 桂强 何 on 15/12/11.
//  Copyright © 2015年 桂强 何. All rights reserved.
//

#import <Foundation/Foundation.h>

#import "IGBannerSupport.h"

@interface IGBannerItem : NSObject<IGBannerSupport>

@property (nonatomic,copy   ,getter = ig_title) NSString  *title;
@property (nonatomic,strong ,getter = ig_image) id        image;

@property (nonatomic,strong ) id        extra;
@property (nonatomic, assign) NSInteger tag;

/**
 *  构造方法
 *
 *  @param atitle 标题
 *  @param aimage 图片,UIImage、NSURL和NSString都可以
 *  @param atag   标记
 *
 *  @return 返回Item实例
 */
- (instancetype)initWithTitle:(NSString *)title image:(id)image tag:(NSInteger)tag;

/**
 *  构造方法-类方法版本
 *
 *  @param atitle 标题
 *  @param aimage 图片,UIImage、NSURL和NSString都可以
 *  @param atag   标记
 *
 *  @return 返回Item实例
 */
+ (instancetype)itemWithTitle:(NSString *)title image:(id)image tag:(NSInteger)tag;

@end


text: require 'gh_trending'


text:
Mazuma - a sales app built on Heroku, Stripe, and Mailgun
=========================================================

**Mazuma is a simple sales application written in Ruby.** It uses [Sinatra](http://www.sinatrarb.com/) and [ERB](http://ruby-doc.org/stdlib-1.9.3/libdoc/erb/rdoc/ERB.html) templates to produce an attractive two-column web application suitable for selling a product, service, or subscription online. The application is capable of delivering a file download link on a successful transaction and/or sending the file as an email attachment.

Mazuma is designed for easy deployment to [Heroku's](http://heroku.com). [Stripe](http://stripe.com) is used to charge the user's credit card, and [Mailgun](http://mailgun.net) is used to send the user a receipt for successful transactions, as well as send all purchasers update emails via a simple command line interface. [Mailcheck.js](https://github.com/Kicksend/mailcheck) automatically catches common email typos.

All pages in the application default to SSL via [rack-ssl-enforcer](https://github.com/tobmatth/rack-ssl-enforcer). Using an SSL connection allows you to securely transmit user credit card information to Stripe without storing it in your application, ensuring full PCI compliance. Piggyback SSL is available by default for apps on subdomain.herokuapp.com, or inexpensively via Heroku's wildcard SSL add-on.

_("Mazuma" is the Yiddish word for money.)_

Getting Started
---------------

    $ git clone git://github.com/worldlywisdom/mazuma.git

    $ gem install bundler

    $ bundle install

    $ git init .

    $ git commit -m "Initial commit"

    $ heroku create yourappname

    $ git push heroku master

Setting Global and Environment Variables
----------------------------------------

Global variables are set in the /config/globals.rb file. This file is read by both the Sinatra application and the Rakefile, ensuring these items are consistent and available across the application.

Once you've set up accounts at [Stripe](http://stripe.com) and [Mailgun](http://mailgun.net), you'll need to add your API keys to Heroku as environment variables. This help you keep your private keys secure if you contribute to open source or in the event your machine is compromised. (Be sure to replace "t0psecretkey" with your personal key.)

**Set Stripe.com Keys**

    $ heroku config:add STRIPE_SECRET_KEY=t0psecretkey

    $ heroku config:add STRIPE_PUBLISHABLE_KEY=publickey

**Set Mailgun.net Keys**

    $ heroku config:add MAILGUN_PRIVATE_KEY=t0psecretkey

Changing Page Copy & Design
---------------------------

All pages in this application are ERB templates, which can be found in the /views directory.

The general page layout is set in /views/layout.erb. The site uses [Bootstrap](http://getbootstrap.com/) as a design framework, modified by a custom stylesheet in /public/css/stylesheet.css. Fancy fonts are provided by [Google Web Fonts](http://www.google.com/webfonts), which are included in the header of /views/layout.erb and set in /public/css/stylesheet.css.

Notably, it's easy to change the default layout to a single-column format by removing the sidebar div in /views/layout.erb and changing the container div to "span8 offset1"

Sending Email Broadcasts
------------------------

The included Rakefile contains two Rake tasks that make it easy to send broadcast emails to your paid users. For security, broadcast emails to your users are sent via the command line vs. a web-based interface, since Heroku command line logins require both your SSH key file and password.

### Step 1: Upload Files

Add your email message to /email/messages, and upload the fie to Heroku by running $ git push heroku master after adding and committing the file to your repo. Text or HTML files are supported. I recommend using a YEAR-MONTH-DAY-filename.extention naming scheme to make your messages easy to find later.

Add file attachments to /email/attachments.

### Step 2: Preview Your Email

Use this command to send a preview email to the administrator email set in the /config/globals.rb file.

    $ heroku rake 'email:preview["Subject Line","2012-01-01-message.extention"]'

If you'd like to include an attachment, use this command:

    $ heroku rake 'email:preview["Subject Line","2012-01-01-message.extention","attachment.extention"]'

### Step 3: Send the Broadcast

Use this command to send a broadcast email to the Mailgun list set in the /config/globals.rb file.

    $ heroku rake 'email:broadcast["Subject Line","2012-01-01-message.extention"]'

If you'd like to include an attachment, use this command:

    $ heroku rake 'email:broadcast["Subject Line","2012-01-01-message.extention","attachment.extention"]'

These commands change to $ heroku run rake if you deploy to Heroku's Cedar stack.

Extending Mazuma
----------------

**You can extend the features of Mazuma however you desire.** Want to add your customers to a database? Integrate with other APIs? Change mailing or credit card services? Mazuma is simple enough to change: everything you need is in application.rb and /modules/mailer.rb.

Enjoy!


text:
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

using System;
using System.ComponentModel;
using System.Reflection;
using System.Threading.Tasks;
using System.Web;

namespace Microsoft.TestCommon
{
    public partial class Assert
    {
        /// <summary>
        /// Verifies that the exact exception is thrown (and not a derived exception type).
        /// </summary>
        /// <typeparam name="T">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static T Throws<T>(Action testCode)
            where T : Exception
        {
            return (T)Throws(typeof(T), testCode);
        }

        /// <summary>
        /// Verifies that the exact exception is thrown (and not a derived exception type).
        /// Generally used to test property accessors.
        /// </summary>
        /// <typeparam name="T">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static T Throws<T>(Func<object> testCode)
            where T : Exception
        {
            return (T)Throws(typeof(T), testCode);
        }

        /// <summary>
        /// Verifies that the exact exception is thrown (and not a derived exception type).
        /// </summary>
        /// <param name="exceptionType">The type of the exception expected to be thrown</param>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static Exception Throws(Type exceptionType, Action testCode)
        {
            Exception exception = RecordException(testCode);
            return VerifyException(exceptionType, exception);
        }

        /// <summary>
        /// Verifies that the exact exception is thrown (and not a derived exception type).
        /// Generally used to test property accessors.
        /// </summary>
        /// <param name="exceptionType">The type of the exception expected to be thrown</param>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static Exception Throws(Type exceptionType, Func<object> testCode)
        {
            return Throws(exceptionType, () => { testCode(); });
        }

        /// <summary>
        /// Verifies that an exception of the given type (or optionally a derived type) is thrown.
        /// </summary>
        /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static TException Throws<TException>(Action testCode, bool allowDerivedExceptions)
            where TException : Exception
        {
            Type exceptionType = typeof(TException);
            Exception exception = RecordException(testCode);

            TargetInvocationException tie = exception as TargetInvocationException;
            if (tie != null)
            {
                exception = tie.InnerException;
            }

            if (exception == null)
            {
                throw new ThrowsException(exceptionType);
            }

            var typedException = exception as TException;
            if (typedException == null || (!allowDerivedExceptions && typedException.GetType() != typeof(TException)))
            {
                throw new ThrowsException(exceptionType, exception);
            }

            return typedException;
        }

        /// <summary>
        /// Verifies that an exception of the given type (or optionally a derived type) is thrown.
        /// Generally used to test property accessors.
        /// </summary>
        /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static TException Throws<TException>(Func<object> testCode, bool allowDerivedExceptions)
            where TException : Exception
        {
            return Throws<TException>(() => { testCode(); }, allowDerivedExceptions);
        }

        /// <summary>
        /// Verifies that an exception of the given type (or optionally a derived type) is thrown.
        /// Also verifies that the exception message matches.
        /// </summary>
        /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="exceptionMessage">The exception message to verify</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static TException Throws<TException>(Action testCode, string exceptionMessage, bool allowDerivedExceptions = false)
            where TException : Exception
        {
            var ex = Throws<TException>(testCode, allowDerivedExceptions);
            VerifyExceptionMessage(ex, exceptionMessage);
            return ex;
        }

        /// <summary>
        /// Verifies that an exception of the given type (or optionally a derived type) is thrown.
        /// Also verified that the exception message matches.
        /// </summary>
        /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="exceptionMessage">The exception message to verify</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static TException Throws<TException>(Func<object> testCode, string exceptionMessage, bool allowDerivedExceptions = false)
            where TException : Exception
        {
            return Throws<TException>(() => { testCode(); }, exceptionMessage, allowDerivedExceptions);
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentException ThrowsArgument(Action testCode, string paramName, bool allowDerivedExceptions = false)
        {
            var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);

            if (paramName != null)
            {
                Equal(paramName, ex.ParamName);
            }

            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentException"/> (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="exceptionMessage">The exception message to verify</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentException ThrowsArgument(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false)
        {
            var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);

            if (paramName != null)
            {
                Equal(paramName, ex.ParamName);
            }

            VerifyExceptionMessage(ex, exceptionMessage, partialMatch: true);

            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an ArgumentException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentException ThrowsArgument(Func<object> testCode, string paramName, bool allowDerivedExceptions = false)
        {
            var ex = Throws<ArgumentException>(testCode, allowDerivedExceptions);

            if (paramName != null)
            {
                Equal(paramName, ex.ParamName);
            }

            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an ArgumentNullException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentNullException ThrowsArgumentNull(Action testCode, string paramName)
        {
            var ex = Throws<ArgumentNullException>(testCode, allowDerivedExceptions: false);

            if (paramName != null)
            {
                Equal(paramName, ex.ParamName);
            }

            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot
        /// be null or empty.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentException ThrowsArgumentNullOrEmpty(Action testCode, string paramName)
        {
            return Throws<ArgumentException>(testCode, "Value cannot be null or empty.\r\nParameter name: " + paramName, allowDerivedExceptions: false);
        }

        /// <summary>
        /// Verifies that the code throws an ArgumentNullException with the expected message that indicates that the value cannot
        /// be null or empty string.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentException ThrowsArgumentNullOrEmptyString(Action testCode, string paramName)
        {
            return ThrowsArgument(testCode, paramName, "Value cannot be null or an empty string.", allowDerivedExceptions: true);
        }

        /// <summary>
        /// Verifies that the code throws an ArgumentOutOfRangeException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="exceptionMessage">The exception message to verify</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <param name="actualValue">The actual value provided</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentOutOfRangeException ThrowsArgumentOutOfRange(Action testCode, string paramName, string exceptionMessage, bool allowDerivedExceptions = false, object actualValue = null)
        {
            if (exceptionMessage != null)
            {
                exceptionMessage = exceptionMessage + "\r\nParameter name: " + paramName;
                if (actualValue != null)
                {
                    exceptionMessage += String.Format(CultureReplacer.DefaultCulture, "\r\nActual value was {0}.", actualValue);
                }
            }

            var ex = Throws<ArgumentOutOfRangeException>(testCode, exceptionMessage, allowDerivedExceptions);

            if (paramName != null)
            {
                Equal(paramName, ex.ParamName);
            }

            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
        /// the value must be greater than the given <paramref name="value"/>.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="actualValue">The actual value provided.</param>
        /// <param name="value">The expected limit value.</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentOutOfRangeException ThrowsArgumentGreaterThan(Action testCode, string paramName, string value, object actualValue = null)
        {
            return ThrowsArgumentOutOfRange(
                        testCode,
                        paramName,
                        String.Format(CultureReplacer.DefaultCulture, "Value must be greater than {0}.", value), false, actualValue);
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
        /// the value must be greater than or equal to the given value.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="value">The expected limit value.</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentOutOfRangeException ThrowsArgumentGreaterThanOrEqualTo(Action testCode, string paramName, string value, object actualValue = null)
        {
            return ThrowsArgumentOutOfRange(
                        testCode,
                        paramName,
                        String.Format(CultureReplacer.DefaultCulture, "Value must be greater than or equal to {0}.", value), false, actualValue);
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
        /// the value must be less than the given <paramref name="maxValue"/>.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="actualValue">The actual value provided.</param>
        /// <param name="maxValue">The expected limit value.</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentOutOfRangeException ThrowsArgumentLessThan(Action testCode, string paramName, string maxValue, object actualValue = null)
        {
            return ThrowsArgumentOutOfRange(
                        testCode,
                        paramName,
                        String.Format(CultureReplacer.DefaultCulture, "Value must be less than {0}.", maxValue), false, actualValue);
        }

        /// <summary>
        /// Verifies that the code throws an <see cref="ArgumentOutOfRangeException"/> with the expected message that indicates that
        /// the value must be less than or equal to the given <paramref name="maxValue"/>.
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="actualValue">The actual value provided.</param>
        /// <param name="maxValue">The expected limit value.</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ArgumentOutOfRangeException ThrowsArgumentLessThanOrEqualTo(Action testCode, string paramName, string maxValue, object actualValue = null)
        {
            return ThrowsArgumentOutOfRange(
                        testCode,
                        paramName,
                        String.Format(CultureReplacer.DefaultCulture, "Value must be less than or equal to {0}.", maxValue), false, actualValue);
        }

        /// <summary>
        /// Verifies that the code throws an HttpException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="exceptionMessage">The exception message to verify</param>
        /// <param name="httpCode">The expected HTTP status code of the exception</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static HttpException ThrowsHttpException(Action testCode, string exceptionMessage, int httpCode, bool allowDerivedExceptions = false)
        {
            var ex = Throws<HttpException>(testCode, exceptionMessage, allowDerivedExceptions);
            Equal(httpCode, ex.GetHttpCode());
            return ex;
        }

        /// <summary>
        /// Verifies that the code throws an InvalidEnumArgumentException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="paramName">The name of the parameter that should throw the exception</param>
        /// <param name="invalidValue">The expected invalid value that should appear in the message</param>
        /// <param name="enumType">The type of the enumeration</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static InvalidEnumArgumentException ThrowsInvalidEnumArgument(Action testCode, string paramName, int invalidValue, Type enumType, bool allowDerivedExceptions = false)
        {
            string message = String.Format(CultureReplacer.DefaultCulture,
                                           "The value of argument '{0}' ({1}) is invalid for Enum type '{2}'.{3}Parameter name: {0}",
                                           paramName, invalidValue, enumType.Name, Environment.NewLine);
            return Throws<InvalidEnumArgumentException>(testCode, message, allowDerivedExceptions);
        }

        /// <summary>
        /// Verifies that the code throws an HttpException (or optionally any exception which derives from it).
        /// </summary>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <param name="objectName">The name of the object that was dispose</param>
        /// <param name="allowDerivedExceptions">Pass true to allow exceptions which derive from TException; pass false, otherwise</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        public static ObjectDisposedException ThrowsObjectDisposed(Action testCode, string objectName, bool allowDerivedExceptions = false)
        {
            var ex = Throws<ObjectDisposedException>(testCode, allowDerivedExceptions);

            if (objectName != null)
            {
                Equal(objectName, ex.ObjectName);
            }

            return ex;
        }

        /// <summary>
        /// Verifies that an exception of the given type is thrown.
        /// </summary>
        /// <typeparam name="TException">The type of the exception expected to be thrown</typeparam>
        /// <param name="testCode">A delegate to the code to be tested</param>
        /// <returns>The exception that was thrown, when successful</returns>
        /// <exception cref="ThrowsException">Thrown when an exception was not thrown, or when an exception of the incorrect type is thrown</exception>
        /// <remarks>
        /// Unlike other Throws* methods, this method does not enforce running the exception delegate with a known Thread Culture.
        /// </remarks>
        public static async Task<TException> ThrowsAsync<TException>(Func<Task> testCode)
            where TException : Exception
        {
            Exception exception = null;
            try
            {
                // The 'testCode' Task might execute asynchronously in a different thread making it hard to enforce the thread culture.
                // The correct way to verify exception messages in such a scenario would be to run the task synchronously inside of a
                // culture enforced block.
                await testCode();
            }
            catch (Exception ex)
            {
                exception = ex;
            }
            VerifyException(typeof(TException), exception);
            return (TException)exception;
        }

        // We've re-implemented all the xUnit.net Throws code so that we can get this
        // updated implementation of RecordException which silently unwraps any instances
        // of AggregateException. In addition to unwrapping exceptions, this method ensures
        // that tests are executed in with a known set of Culture and UICulture. This prevents
        // tests from failing when executed on a non-English machine.
        private static Exception RecordException(Action testCode)
        {
            try
            {
                using (new CultureReplacer())
                {
                    testCode();
                }
                return null;
            }
            catch (Exception exception)
            {
                return UnwrapException(exception);
            }
        }

        private static Exception UnwrapException(Exception exception)
        {
            AggregateException aggEx = exception as AggregateException;
            if (aggEx != null)
            {
                return aggEx.GetBaseException();
            }
            return exception;
        }

        private static Exception VerifyException(Type exceptionType, Exception exception)
        {
            if (exception == null)
            {
                throw new ThrowsException(exceptionType);
            }
            else if (exceptionType != exception.GetType())
            {
                throw new ThrowsException(exceptionType, exception);
            }

            return exception;
        }

        private static void VerifyExceptionMessage(Exception exception, string expectedMessage, bool partialMatch = false)
        {
            if (expectedMessage != null)
            {
                if (!partialMatch)
                {
                    Equal(expectedMessage, exception.Message);
                }
                else
                {
                    Contains(expectedMessage, exception.Message);
                }
            }
        }

        // Custom ThrowsException so we can filter the stack trace.
        [Serializable]
        private class ThrowsException : Xunit.Sdk.ThrowsException
        {
            public ThrowsException(Type type) : base(type) { }

            public ThrowsException(Type type, Exception ex) : base(type, ex) { }

            protected override bool ExcludeStackFrame(string stackFrame)
            {
                if (stackFrame.StartsWith("at Microsoft.TestCommon.Assert.", StringComparison.OrdinalIgnoreCase))
                {
                    return true;
                }

                return base.ExcludeStackFrame(stackFrame);
            }
        }
    }
}


text:
layout: page
title: Custom validation
hide_hero: true
show_sidebar: false
menubar: docs-menu
---

# Custom validation

ACH files can vary sometimes from the official NACHA guidelines due to vendor changes. Moov ACH defaults to NACHA guidelines, so to handle this there's an exported `ValidateWith(opts)` method on some structures (`File`, `FileHeader`, etc).

The [`ValidateOpts`](https://godoc.org/github.com/moov-io/ach#ValidateOpts) struct can have fields added in minor releases without breaking API compatibility with callers. The default values in this struct match with NACHA's guidelines.

## Validation options

The following options can be used with `File.ValidateWith` and `File.SetValidation` to alter the default NACHA validation rules.

### Origin

`RequireABAOrigin bool` can be set to enable routing number validation over the `ImmediateOrigin` file header field. Often the origin can be another value which is significant to the Financial Institution you're uploading ACH Files to.

```
// One-time change to the NACHA validation rules
opts := &ValidateOpts{RequireABAOrigin: true}
if err := file.Header.ValidateWith(opts); err != nil {
    // do something...
}
```

`BypassOriginValidation bool` can be set to skip all validation for the `ImmediateOrigin` file header field. This also allows for custom TraceNumbers which aren't prefixed with a routing number as required by the NACHA specification.

```
// Override the default validation rules on an *ach.File object.
file.SetValidation(&ValidateOpts{
    BypassOriginValidation: true,
})
if err := file.Validate(); err != nil {
    // do something...
}
```

### Destination

`BypassDestinationValidation bool` can be set to skip validation for the `ImmediateDestination` file header field.

### Transaction Codes

```
// CheckTransactionCode allows for custom validation of TransactionCode values
CheckTransactionCode func(code int) error
```

### Trace Numbers

The Nacha/ACH spec requires that trace numbers follow a few rules. This validation option disables them.

- Ascending order of trace numbers within batches
- Trace numbers beginning with their ODFI's routing number
- `AddendaRecordIndicator` is set correctly

```
// CustomTraceNumbers disables validation of TraceNumbers
CustomTraceNumbers bool `json:"customTraceNumbers"`
```

### Batches

```
// AllowZeroBatches allows the file to have zero batches
AllowZeroBatches bool `json:"allowZeroBatches"`

// BypassCompanyIdentificationMatch allows batches in which the Company Identification field
// in the batch header and control do not match.
BypassCompanyIdentificationMatch bool `json:"bypassCompanyIdentificationMatch"`

// UnequalServiceClassCode skips equality checks for the ServiceClassCode in each pair of BatchHeader
// and BatchControl records.
UnequalServiceClassCode bool `json:"unequalServiceClassCode"`

// AllowUnorderedBatchNumebrs allows a file to be read with unordered batch numbers.
AllowUnorderedBatchNumbers bool `json:"allowUnorderedBatchNumbers"`

// UnequalAddendaCounts skips checking that Addenda Count fields match their expected and computed values.
UnequalAddendaCounts bool `json:"unequalAddendaCounts"`
```

### File Header

```
// AllowMissingFileHeader allows a file to be read without a FileHeader record.
AllowMissingFileHeader bool `json:"allowMissingFileHeader"`
```

### File Control

```
// AllowMissingFileControl allows a file to be read without a FileControl record.
AllowMissingFileControl bool `json:"allowMissingFileControl"`
```

### Returns

```
// CustomReturnCodes can be set to skip validation for the Return Code field in an Addenda99
// This allows for non-standard/deprecated return codes (e.g. R97)
CustomReturnCodes bool `json:"customReturnCodes"`
```

## Reader

An `ach.Reader` can have custom validation rules as well, simply set them prior to reading.

```
r := ach.NewReader(fd) // create an ach.Reader from an os.File
r.SetValidation(&ach.ValidateOpts{
    BypassDestinationValidation: true,
})
file, err := r.Read()
if err != nil {
    // do something...
}
```

## JSON Options

The JSON representation includes the `ValidateOpts` if specified on the `*ach.File` instance.

## HTTP server

The ACH HTTP server can accept `ValidateOpts` when [Validating a file](https://moov-io.github.io/ach/api/#get-/files/{fileID}/validate). This will leverage the above one-off validation methods and return any errors.

**Create a file**
```
curl -X POST --data-binary @test/testdata/ppd-debit.ach http://localhost:8080/files/create
```
```
{"id":"b1910446fd904abc8b2cee358ffb3673c2cb8a62","error":null}
```

**Apply custom validation rules**

```
curl -X POST --data-binary '{"requireABAOrigin": true}' http://localhost:8080/files/b1910446fd904abc8b2cee358ffb3673c2cb8a62/validate
```
```
{"error":null}
```