text:
using namespace BloombergLP;
using namespace BloombergLP::bslalg;

// ============================================================================
//                             TEST PLAN
// ----------------------------------------------------------------------------
//                             Overview
//                             --------
//
// ----------------------------------------------------------------------------
// [  ] ...
// ----------------------------------------------------------------------------
// [  ] void insertLinkBeforeTarget(Link *newNode, Link* target);
// [  ] void insertLinkAfterTarget(Link *newNode, Link *target);
// [  ] bool isWellFormed(Link *head, Link *tail);
// [  ] void spliceListBeforeTarget(Link *first, Link *last, Link *target);
// [ 1] BREATHING TEST
// [  ] USAGE EXAMPLE
//
// ============================================================================
//                      STANDARD BDE ASSERT TEST MACROS
// ----------------------------------------------------------------------------
// NOTE: THIS IS A LOW-LEVEL COMPONENT AND MAY NOT USE ANY C++ LIBRARY
// FUNCTIONS, INCLUDING IOSTREAMS.

namespace {

int testStatus = 0;

void aSsErT(bool b, const char *s, int i)
{
    if (b) {
        printf("Error " __FILE__ "(%d): %s    (failed)\n", i, s);
        if (testStatus >= 0 && testStatus <= 100) ++testStatus;
    }
}

}  // close unnamed namespace

//=============================================================================
//                       STANDARD BDE TEST DRIVER MACROS
//-----------------------------------------------------------------------------

#define ASSERT       BSLS_BSLTESTUTIL_ASSERT
#define LOOP_ASSERT  BSLS_BSLTESTUTIL_LOOP_ASSERT
#define LOOP0_ASSERT BSLS_BSLTESTUTIL_LOOP0_ASSERT
#define LOOP1_ASSERT BSLS_BSLTESTUTIL_LOOP1_ASSERT
#define LOOP2_ASSERT BSLS_BSLTESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLS_BSLTESTUTIL_LOOP3_ASSERT
#define lOOP4_ASSERT BSLS_BSLTESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLS_BSLTESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLS_BSLTESTUTIL_LOOP6_ASSERT
#define ASSERTV      BSLS_BSLTESTUTIL_ASSERTV

#define Q   BSLS_BSLTESTUTIL_Q   // Quote identifier literally.
#define P   BSLS_BSLTESTUTIL_P   // Print identifier and value.
#define P_  BSLS_BSLTESTUTIL_P_  // P(X) without '\n'.
#define T_  BSLS_BSLTESTUTIL_T_  // Print a tab (w/o newline).
#define L_  BSLS_BSLTESTUTIL_L_  // current Line number

#define RUN_EACH_TYPE BSLTF_TEMPLATETESTFACILITY_RUN_EACH_TYPE

// ============================================================================
//                  NEGATIVE-TEST MACRO ABBREVIATIONS
// ----------------------------------------------------------------------------

#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)
#define ASSERT_PASS(EXPR)      BSLS_ASSERTTEST_ASSERT_PASS(EXPR)
#define ASSERT_FAIL(EXPR)      BSLS_ASSERTTEST_ASSERT_FAIL(EXPR)
#define ASSERT_OPT_PASS(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR)
#define ASSERT_OPT_FAIL(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR)

typedef BidirectionalLink         Link;
typedef BidirectionalLinkListUtil Obj;

// First, since 'Link' neither has a constructor nor is a POD (which would make
// aggregate initialization possible), we create a function 'makeLink' to
// assemble a link from two pointers:

Link makeLink(Link *prev, Link *next)
{
    Link result;
    result.setPreviousLink(prev);
    result.setNextLink(    next);

    return result;
}

// Then, we create a function that will, passed two links that are endpoints
// of a linked list from the specified 'first' to 'last' though the 'nextLink'
// pointers, count the number of nodes in the list including both endpoints.

int length(Link *first, Link *last)
{
    int result = 0;
    Link *p = first;
    while (p && ++result && last != p) {
        p = p->nextLink();
    }

    return result;
}

struct Bucket {
    // DATA
    Link *d_first;
    Link *d_last;

    // MANIPULATORS
    void clone(const Bucket& bucket, bslma::Allocator *alloc = 0);
        // Make a copy of the specified 'bucket' using the specified allocator
        // 'alloc'.  Note that all links are copied, with new copies being
        // allocated with the specified 'alloc'.

    void destroy(bslma::Allocator *alloc = 0);
        // Destroy the nodes in the list ranging from 'this->d_first' to
        // 'this->d_last'.  Note that if any surving nodes are pointing at
        // either of those nodes, they will be left dangling.

    // ACCESSORS
    int length() const;
        // Returns the number of nodes in the range '[ d_first, d_last ]'.  If
        // the bucket is not well-formed, and return a negative value.  This
        // should work for any bucket that is well-formed.
};

void Bucket::clone(const Bucket& bucket, bslma::Allocator *alloc)
{
    alloc = bslma::Default::allocator(alloc);

    ASSERT(Obj::isWellFormed(bucket.d_first, bucket.d_last));

    this->d_first = 0;
    for (Link *link = bucket.d_first, *prev = 0, *newLink; link;
                                     link = link->nextLink(), prev = newLink) {
        newLink = static_cast<Link *>(alloc->allocate(sizeof(Link)));
        newLink->setPreviousLink(prev);
        if (!prev) {
            this->d_first = newLink;
        }
        else {
            prev->setNextLink(newLink);
        }

        if (bucket.d_last == link) {
            newLink->setNextLink(0);
            this->d_last = newLink;
            return;                                                   // RETURN
        }
    }

    ASSERT(0 == this->d_first);
    this->d_last = 0;
}

void Bucket::destroy(bslma::Allocator *alloc)
{
    alloc = bslma::Default::allocator(alloc);

    ASSERT(Obj::isWellFormed(this->d_first, this->d_last));

    if (!this->d_first) {
        return;                                                       // RETURN
    }

    Link *link = this->d_first, *toDelete;
    do {
        toDelete = link;
        link = link->nextLink();

        alloc->deallocate(toDelete);
    } while (this->d_last != toDelete);

    this->d_first = this->d_last = 0;
}

int Bucket::length() const
{
    if (!Obj::isWellFormed(this->d_first, this->d_last)) {
        return -1;                                                    // RETURN
    }

    return ::length(d_first, d_last);
}

static
Link links[] = {
    makeLink(0,         links + 1),
    makeLink(links + 0, links + 2),
    makeLink(links + 1, links + 3),
    makeLink(links + 2, links + 4),
    makeLink(links + 3, links + 5),
    makeLink(links + 4, links + 6),
    makeLink(links + 5, 0)          };
enum { NUM_LINKS = sizeof links / sizeof *links,
       LAST_LINK = NUM_LINKS - 1 };

const Bucket linksBucket = { &links[0], &links[ NUM_LINKS - 1 ] };

struct DefaultDataRow {
    int    d_line;
    Bucket d_bucket;
    bool   d_isWellFormed;
    int    d_length;
};

Link *DEFAULT_BOGUS = (Link *) 0xBADA55E5;

const DefaultDataRow DEFAULT_DATA[] = {
    { L_, { 0,         0                   }, 1,  0 },
    { L_, { DEFAULT_BOGUS, 0               }, 0, -1 },
    { L_, { 0        , DEFAULT_BOGUS       }, 0, -1 },
    { L_, { &links[0], &links[0]           }, 1,  1 },
    { L_, { &links[0], &links[LAST_LINK]   }, 1,  7 },
    { L_, { &links[0], &links[1]           }, 1,  2 },
    { L_, { &links[1], &links[LAST_LINK-1] }, 1,  5 },
    { L_, { &links[1], &links[0]           }, 0, -1 },
    { L_, { &links[LAST_LINK-1], &links[1] }, 0, -1 },
    { L_, { &links[LAST_LINK], &links[0]   }, 0, -1 } };

enum { NUM_DEFAULT_DATA = sizeof DEFAULT_DATA / sizeof *DEFAULT_DATA };

//=============================================================================
//                              MAIN PROGRAM
//-----------------------------------------------------------------------------

int main(int argc, char *argv[])
{
    int  test                = argc > 1 ? atoi(argv[1]) : 0;
    bool verbose             = argc > 2;
    bool veryVerbose         = argc > 3;
    bool veryVeryVerbose     = argc > 4;
    bool veryVeryVeryVerbose = argc > 5;

    printf("TEST " __FILE__ " CASE %d\n", test);

    ASSERT(Obj::isWellFormed(linksBucket.d_first, linksBucket.d_last));

    switch (test) { case 0:
      case 8: {
        // --------------------------------------------------------------------
        // TESTING USAGE
        // --------------------------------------------------------------------

        if (verbose) printf("Usage Example\n"
                            "=============\n");

// Next, in our 'main', we declare a 'typedef' for the component name and a
// a contanst 'invalid' garbage pointer we use when we want data to be garbage.

        typedef BidirectionalLinkListUtil Util;
        Link * const invalid = (Link *) 0XBADDEED5;

// Then, we create a linked list of links and use 'isWellFormed' to verify
// that it is well formed, and call the 'length' method we just created to
// verify its length.

        Link usageData[] = {
            makeLink(0,             &usageData[1]),
            makeLink(&usageData[0], &usageData[2]),
            makeLink(&usageData[1], &usageData[3]),
            makeLink(&usageData[2], 0            )  };

        ASSERT(Util::isWellFormed(      &usageData[0], &usageData[3]));
        ASSERT(4 == length(&usageData[0], &usageData[3]));

// Next, we create two new links 'front' and 'back', and initialize them with
// garbage:

        Link front = makeLink(invalid, invalid);
        Link back  = makeLink(invalid, invalid);

// Then, we use our component's 'insertLinkBeforeTarget' and
// 'insertLinkAfterTarget' to concatenate 'front' to the front of the list and
// 'back' to its rear:

        Util::insertLinkBeforeTarget(&front, &usageData[0]);
        Util::insertLinkAfterTarget( &back,  &usageData[3]);

// Next, We examine the new list and verify we now have a well-formed list, 2
// longer than the old list:

        ASSERT(0 == front.previousLink());
        ASSERT(0 == back .nextLink());
        ASSERT(Util::isWellFormed(          &front, &back));
        ASSERT(6 == length(&front, &back));

// Then, we use our component's 'unlink' method to remove two nodes from our
// list.  Note that the state of the removed nodes is undefined:

        Util::unlink(&usageData[1]);
        Util::unlink(&usageData[3]);

// Next, we verify that the new list is well formed and 2 elements shorter than
// it was before we removed those two nodes:

        ASSERT(Util::isWellFormed(&front, &back));
        ASSERT(4 == length(&front, &back));

// Then, we weave the two discarded nodes into a new, second list of two nodes,
// and use 'isWellFormed' and 'length' to verify it is as we expect:

        usageData[1] = makeLink(0, &usageData[3]);
        usageData[3] = makeLink(&usageData[1], 0);
        ASSERT(Util::isWellFormed(&usageData[1], &usageData[3]));
        ASSERT(2 ==        length(&usageData[1], &usageData[3]));

// Next, we use our component's 'spliceListBeforeTarget' method to remove the
// middle nodes from the longer list and append them to the end of shorter
// list.  Note that the splicing function not only adds the sequence to the new
// list, it also splices the list the sequence is removed from so that both are
// well-formed lists:

        Util::spliceListBeforeTarget(&usageData[0],
                                     &usageData[2],
                                     &usageData[3]);

// Then, we use 'isWellFormed' and 'length' to verify the state of our two
// lists:

        ASSERT(Util::isWellFormed(&usageData[1], &usageData[3]));
        ASSERT(4 ==        length(&usageData[1], &usageData[3]));

        ASSERT(Util::isWellFormed(&front, &back));
        ASSERT(2 ==        length(&front, &back));

// Next, we call 'spliceListBeforeTarget' again to join our two lists into one:

        Util::spliceListBeforeTarget(&usageData[1],
                                     &usageData[3],
                                     &back);

// Now, we use 'isWellFormed' and 'length' to verify the state of our one
// remaining list:

        ASSERT(Util::isWellFormed(&front, &back));
        ASSERT(6 ==        length(&front, &back));
        ASSERT(0 == front.previousLink());
        ASSERT(0 == back .nextLink());

// Finally, we traverse our list in both directions, examining each node to
// verify all the links and that the sequence is as expected:

        Link *p = &front;
        ASSERT(0 == p->previousLink());
        p = p->nextLink();
        ASSERT(&usageData[1] == p);
        p = p->nextLink();
        ASSERT(&usageData[0] == p);
        p = p->nextLink();
        ASSERT(&usageData[2] == p);
        p = p->nextLink();
        ASSERT(&usageData[3] == p);
        p = p->nextLink();
        ASSERT(&back         == p);
        ASSERT(0 == p->nextLink());

        p = p->previousLink();
        ASSERT(&usageData[3] == p);
        p = p->previousLink();
        ASSERT(&usageData[2] == p);
        p = p->previousLink();
        ASSERT(&usageData[0] == p);
        p = p->previousLink();
        ASSERT(&usageData[1] == p);
        p = p->previousLink();
        ASSERT(&front        == p);
        ASSERT(0 == p->previousLink());
      } break;
      case 7: {
        // --------------------------------------------------------------------
        // TESTING 'spliceListBeforeTarget'
        //
        // Concerns:
        //: That the 'spliceListBeforeTarget' works correctly
        //
        // Plan:
        // Test all combinations of the following:
        //: 1 Target is:
        //:   o Zero.
        //:   o The beginning of a list.
        //:   o The last node of a list.
        //: 2 Inserted is (A: a single node, B: a list of nodes)
        //:   o By itself.
        //:   o At the beginning of a list.
        //:   o At the end of a list.
        //:   o In the middle of a list.
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING spliceListBeforeTarget\n"
                            "==============================\n");

        if (verbose) printf("insert single link, target == 0\n");
        {
            Link   toInsertLink = makeLink(0, 0);
            Obj::spliceListBeforeTarget(&toInsertLink,
                                        &toInsertLink,
                                        0);
            ASSERT(0 == toInsertLink.previousLink());
            ASSERT(0 == toInsertLink.nextLink());
            ASSERT(Obj::isWellFormed(&toInsertLink, &toInsertLink));
        }

        if (verbose) printf("insert full list, target == 0\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);

            Obj::spliceListBeforeTarget(toInsert.d_first,
                                        toInsert.d_last,
                                        0);
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));

            toInsert.destroy(&ta);
        }

        if (verbose) printf("insert single node from start of list,"
                            " target == 0\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link   *first  = toInsert.d_first;
            Link   *second = toInsert.d_first->nextLink();

            Obj::spliceListBeforeTarget(first,
                                        first,
                                        0);
            ASSERT(0 == first->previousLink());
            ASSERT(0 == first->nextLink());
            ASSERT(0 == second->previousLink());
            ASSERT(Obj::isWellFormed(first, first));
            ASSERT(1 == length(first, first));

            toInsert.d_first = second;
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            Obj::spliceListBeforeTarget(first,
                                        first,
                                        toInsert.d_first);
            toInsert.d_first = first;
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            toInsert.destroy(&ta);
        }

        if (verbose) printf("insert single node from end of list,"
                            " target == 0\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *last = toInsert.d_last;
            Link *prev = toInsert.d_last->previousLink();

            Obj::spliceListBeforeTarget(last, last, 0);
            ASSERT(0 == last->previousLink());
            ASSERT(0 == last->nextLink());
            ASSERT(0 == prev->nextLink());
            ASSERT(Obj::isWellFormed(last, last));
            ASSERT(1 == length(last, last));

            toInsert.d_last = prev;
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            Obj::spliceListBeforeTarget(last,
                                        last,
                                        toInsert.d_first);
            toInsert.d_first = last;
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            toInsert.destroy(&ta);
        }

        if (verbose) printf("insert single node from middle of list,"
                            " target == 0\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *middle = toInsert.d_first->nextLink()->nextLink();
            Link *prev   = middle->previousLink();
            Link *next   = middle->nextLink();

            Obj::spliceListBeforeTarget(middle, middle, 0);
            ASSERT(0 == middle->previousLink());
            ASSERT(0 == middle->nextLink());
            ASSERT(next == prev->nextLink());
            ASSERT(prev == next->previousLink());
            ASSERT(Obj::isWellFormed(middle, middle));
            ASSERT(1 == length(middle, middle));

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            Obj::spliceListBeforeTarget(middle,
                                        middle,
                                        next);
            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            toInsert.destroy(&ta);
        }

        if (verbose) printf("insert single link, target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);

            Link   toInsertLink = makeLink(0, 0);
            Obj::spliceListBeforeTarget(&toInsertLink,
                                        &toInsertLink,
                                        dest.d_first);
            ASSERT(0 == toInsertLink.previousLink());
            ASSERT(dest.d_first == toInsertLink.nextLink());
            ASSERT(Obj::isWellFormed(&toInsertLink, dest.d_last));
            ASSERT(NUM_LINKS + 1 == length(&toInsertLink, dest.d_last));

            dest.destroy(&ta);
        }

        if (verbose) printf("insert full list, target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);

            Obj::spliceListBeforeTarget(toInsert.d_first,
                                        toInsert.d_last,
                                        dest.d_first);
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(dest.d_first    == toInsert.d_last->nextLink());
            ASSERT(toInsert.d_last == dest.d_first->previousLink());
            ASSERT(0 == dest.d_last ->nextLink());
            ASSERT(Obj::isWellFormed(toInsert.d_first, dest.d_last));
            ASSERT(2 * NUM_LINKS == length(toInsert.d_first, dest.d_last));

            toInsert.d_last = dest.d_last;

            toInsert.destroy(&ta);
        }

        if (verbose) printf("insert single node from start of list,"
                            " target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link   *first  = toInsert.d_first;
            Link   *second = toInsert.d_first->nextLink();

            Obj::spliceListBeforeTarget(first,
                                        first,
                                        dest.d_first);
            ASSERT(0 == first->previousLink());
            ASSERT(dest.d_first == first->nextLink());
            ASSERT(first        == dest.d_first->previousLink());
            ASSERT(0 == second->previousLink());

            toInsert.d_first = second;
            dest.    d_first = first;

            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());
            ASSERT(0 == dest.d_first->previousLink());
            ASSERT(0 == dest.d_last ->nextLink());

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());

            toInsert.destroy(&ta);
            dest.    destroy(&ta);
        }

        if (verbose) printf("insert single node from end of list,"
                            " target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *last = toInsert.d_last;
            Link *prev = toInsert.d_last->previousLink();

            Obj::spliceListBeforeTarget(last, last, dest.d_first);
            ASSERT(0 == last->previousLink());
            ASSERT(0 == prev->nextLink());

            ASSERT(last == dest.d_first->previousLink());
            ASSERT(dest.d_first == last->nextLink());

            toInsert.d_last  = prev;
            dest.    d_first = last;

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());

            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());
            ASSERT(0 == dest    .d_first->previousLink());
            ASSERT(0 == dest    .d_last ->nextLink());

            toInsert.destroy(&ta);
            dest    .destroy(&ta);
        }

        if (verbose) printf("insert single node from middle of list,"
                            " target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *middle = toInsert.d_first->nextLink()->nextLink();
            Link *prev   = middle->previousLink();
            Link *next   = middle->nextLink();

            Obj::spliceListBeforeTarget(middle, middle, dest.d_first);
            ASSERT(0 == middle->previousLink());
            ASSERT(dest.d_first == middle->nextLink());
            ASSERT(next == prev->nextLink());
            ASSERT(prev == next->previousLink());
            ASSERT(Obj::isWellFormed(middle, dest.d_last));
            ASSERT(1 == length(middle, middle));

            dest.d_first = middle;

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());
            ASSERT(0 == dest    .d_first->previousLink());
            ASSERT(0 == dest    .d_last ->nextLink());

            toInsert.destroy(&ta);
            dest    .destroy(&ta);
        }

        if (verbose) printf("insert single link, target == end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);
            Link *destPrev = dest.d_last->previousLink();

            Link   toInsertLink = makeLink(0, 0);
            Obj::spliceListBeforeTarget(&toInsertLink,
                                        &toInsertLink,
                                        dest.d_last);
            ASSERT(destPrev      == toInsertLink.previousLink());
            ASSERT(&toInsertLink == destPrev->nextLink());
            ASSERT(dest.d_last   == toInsertLink.nextLink());
            ASSERT(&toInsertLink == dest.d_last->previousLink());
            ASSERT(Obj::isWellFormed(dest.d_first, &toInsertLink));
            ASSERT(NUM_LINKS + 1 == dest.length());

            Obj::unlink(&toInsertLink);

            dest.destroy(&ta);
        }

        if (verbose) printf("insert full list, target == end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);
            Link *destPrev = dest.d_last->previousLink();

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);

            Obj::spliceListBeforeTarget(toInsert.d_first,
                                        toInsert.d_last,
                                        dest.d_last);
            ASSERT(destPrev         == toInsert.d_first->previousLink());
            ASSERT(dest.d_last      == toInsert.d_last->nextLink());
            ASSERT(toInsert.d_last  == dest.d_last->previousLink());
            ASSERT(toInsert.d_first == destPrev->nextLink());
            ASSERT(0 == dest.d_last ->nextLink());
            ASSERT(0 == dest.d_first->previousLink());

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(    NUM_LINKS == toInsert.length());

            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(2 * NUM_LINKS == dest    .length());

            dest.destroy(&ta);
        }

        if (verbose) printf("insert single node from start of list,"
                            " target == end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);
            Link *destPrev = dest.d_last->previousLink();

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link   *first  = toInsert.d_first;
            Link   *second = toInsert.d_first->nextLink();

            Obj::spliceListBeforeTarget(first,
                                        first,
                                        dest.d_last);
            ASSERT(destPrev == first->previousLink());
            ASSERT(dest.d_last == first->nextLink());
            ASSERT(first       == dest.d_last->previousLink());
            ASSERT(first       == destPrev->nextLink());
            ASSERT(0 == second->previousLink());

            toInsert.d_first = second;

            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());
            ASSERT(0 == dest    .d_first->previousLink());
            ASSERT(0 == dest    .d_last ->nextLink());

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());

            toInsert.destroy(&ta);
            dest.    destroy(&ta);
        }

        if (verbose) printf("insert single node from end of list,"
                            " target == end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);
            Link *destPrev = dest.d_last->previousLink();

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *last = toInsert.d_last;
            Link *prev = toInsert.d_last->previousLink();

            Obj::spliceListBeforeTarget(last, last, dest.d_last);
            ASSERT(destPrev == last->previousLink());
            ASSERT(0 == prev->nextLink());
            ASSERT(dest.d_last == last->nextLink());
            ASSERT(last == dest.d_last->previousLink());

            toInsert.d_last  = prev;

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());

            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());
            ASSERT(0 == dest    .d_first->previousLink());
            ASSERT(0 == dest    .d_last ->nextLink());

            toInsert.destroy(&ta);
            dest    .destroy(&ta);
        }

        if (verbose) printf("insert single node from middle of list,"
                            " target == front of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket dest;
            dest.clone(linksBucket, &ta);
            Link *destPrev = dest.d_last->previousLink();

            Bucket toInsert;
            toInsert.clone(linksBucket, &ta);
            Link *middle = toInsert.d_first->nextLink()->nextLink();
            Link *prev   = middle->previousLink();
            Link *next   = middle->nextLink();

            Obj::spliceListBeforeTarget(middle, middle, dest.d_last);
            ASSERT(destPrev    == middle->previousLink());
            ASSERT(dest.d_last == middle->nextLink());
            ASSERT(next == prev->nextLink());
            ASSERT(prev == next->previousLink());

            ASSERT(Obj::isWellFormed(toInsert.d_first, toInsert.d_last));
            ASSERT(NUM_LINKS - 1 == toInsert.length());
            ASSERT(0 == toInsert.d_first->previousLink());
            ASSERT(0 == toInsert.d_last ->nextLink());

            ASSERT(Obj::isWellFormed(dest    .d_first, dest    .d_last));
            ASSERT(NUM_LINKS + 1 == dest    .length());
            ASSERT(0 == dest    .d_first->previousLink());
            ASSERT(0 == dest    .d_last ->nextLink());

            toInsert.destroy(&ta);
            dest    .destroy(&ta);
        }
      } break;
      case 6: {
        // --------------------------------------------------------------------
        // TESTING 'insertLinkAfterTarget'
        //
        // Concerns:
        //: 1 That the function works correctly when 'target' is at the
        //:   end of the list.
        //: 2 That the function works correctly when 'target' is the only
        //:   element in a list.
        //: 3 That the function works correctly when 'target' is in the middle
        //:   of a list.
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING 'insertLinkAfterTarget'\n"
                            "================================\n");

        Link bogusLink;
        bogusLink.setPreviousLink(DEFAULT_BOGUS);
        bogusLink.setNextLink(    DEFAULT_BOGUS);

        if (verbose) printf("at the end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link newLink = bogusLink;

            Obj::insertLinkAfterTarget(&newLink, bucket.d_last);
            ASSERTV(0             == newLink.nextLink());
            ASSERTV(bucket.d_last == newLink.previousLink());

            ASSERTV(Obj::isWellFormed(bucket.d_first, &newLink));
            ASSERTV(NUM_LINKS == bucket.length());

            bucket.destroy(&ta);
        }

        if (verbose) printf("where there's only one element in the list\n");
        {
            Link oldLink = makeLink(0, 0);
            Link newLink = bogusLink;

            Obj::insertLinkAfterTarget(&newLink, &oldLink);
            ASSERTV(0        == newLink.nextLink());
            ASSERTV(&oldLink == newLink.previousLink());

            ASSERTV(0        == oldLink.previousLink());
            ASSERTV(Obj::isWellFormed(&oldLink, &newLink));
        }

        if (verbose) printf("in the middle of the list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link *at = bucket.d_first->nextLink()->nextLink();

            Link newLink = bogusLink;

            Obj::insertLinkAfterTarget(&newLink, at);
            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS + 1 == bucket.length());

            ASSERTV(at == newLink.previousLink());

            Obj::unlink(&newLink);
            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            bucket.destroy(&ta);
        }
      } break;
      case 5: {
        // --------------------------------------------------------------------
        // Testing 'insertLinkBeforeTarget'
        //
        // Concerns:
        //: 1 That the function works correctly when '0 == target'.
        //: 2 That the function works correctly when 'target' is at the
        //:   beginning of the list.
        //: 3 That the function works correctly when 'target' is the only
        //:   element in a list.
        //: 4 That the function works correctly when 'target' is in the middle
        //:   of a list.
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING 'insertLinkBeforeTarget'\n"
                            "================================\n");

        Link bogusLink;
        bogusLink.setPreviousLink(DEFAULT_BOGUS);
        bogusLink.setNextLink(    DEFAULT_BOGUS);

        if (verbose) printf("target == 0\n");
        {
            Link newLink = bogusLink;

            Obj::insertLinkBeforeTarget(&newLink, 0);
            ASSERT(0 == newLink.nextLink());
            ASSERT(0 == newLink.previousLink());
        }

        if (verbose) printf("at the beginning of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link newLink = bogusLink;

            Obj::insertLinkBeforeTarget(&newLink, bucket.d_first);
            ASSERTV(0              == newLink.previousLink());
            ASSERTV(bucket.d_first == newLink.nextLink());

            ASSERTV(Obj::isWellFormed(&newLink, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            bucket.destroy(&ta);
        }

        if (verbose) printf("where there's only one element in the list\n");
        {
            Link oldLink = makeLink(0, 0);
            Link newLink = bogusLink;

            Obj::insertLinkBeforeTarget(&newLink, &oldLink);
            ASSERTV(0        == newLink.previousLink());
            ASSERTV(&oldLink == newLink.nextLink());

            ASSERTV(0        == oldLink.nextLink());
            ASSERTV(Obj::isWellFormed(&newLink, &oldLink));
        }

        if (verbose) printf("in the middle of the list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link *at = bucket.d_first->nextLink()->nextLink();

            Link newLink = bogusLink;

            Obj::insertLinkBeforeTarget(&newLink, at);
            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS + 1 == bucket.length());

            ASSERTV(at == newLink.nextLink());

            Obj::unlink(&newLink);
            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            bucket.destroy(&ta);
        }
      } break;
      case 4: {
        // --------------------------------------------------------------------
        // TESTING 'unlink'
        //
        // Concerns:
        //: 1 'unlink' successfully removes a node in the middle of a list.
        //: 2 'unlink' successfully removes a node at either end of the list.
        //
        // Plan:
        //: Clone 'linksBucket' and operate on cloned strings, being sure to
        //: explicitly delete the 'unlinked' nodes.
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING 'unlink'\n"
                            "================\n");

        if (verbose) printf("unlink in middle of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link *toDelete = bucket.d_first->nextLink()->nextLink();

            Obj::unlink(toDelete);
            memset(toDelete, 'x', sizeof(Link));

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS - 1 == bucket.length());

            ta.deallocate(toDelete);
            bucket.destroy(&ta);
        }

        if (verbose) printf("unlink at start of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link *toDelete = bucket.d_first;
            bucket.d_first = toDelete->nextLink();

            Obj::unlink(toDelete);
            memset(toDelete, 'x', sizeof(Link));

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS - 1 == bucket.length());

            ta.deallocate(toDelete);
            bucket.destroy(&ta);
        }

        if (verbose) printf("unlink at end of list\n");
        {
            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(linksBucket, &ta);

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS == bucket.length());

            Link *toDelete = bucket.d_last;
            bucket.d_last = toDelete->previousLink();

            Obj::unlink(toDelete);
            memset(toDelete, 'x', sizeof(Link));

            ASSERTV(Obj::isWellFormed(bucket.d_first, bucket.d_last));
            ASSERTV(NUM_LINKS - 1 == bucket.length());

            ta.deallocate(toDelete);
            bucket.destroy(&ta);
        }
      } break;
      case 3: {
        // --------------------------------------------------------------------
        // TESTING Bucket: 'clone', 'destroy', 'length'
        //
        // Concern:
        //: 1 That 'clone' accuratel copies a bucket, and 'destroy'
        //:   effectively destroys it.
        //: 2 That 'length' accurately measures the length of a bucket.
        //
        // Plan:
        //: 1 Call 'length' on each bucket in the test data and verify we are
        //:   getting the proper results.
        //: 2 Clone a copy of the bucket using a test allocator, verify that
        //:   'isWellFormed' and 'length' return the same values as they
        //:   returned for the original bucket.
        //: 3 Verify the ends of the list in the cloned bucket are 0.
        //: 4 Call 'destroy'.  The test allocator will inform us of any
        //:   redundant frees or leaked memory.
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING isWellFormed\n"
                            "====================\n");

        enum { NUM_DATA                        = NUM_DEFAULT_DATA };
        const DefaultDataRow (&DATA)[NUM_DATA] = DEFAULT_DATA;

        for (int i = 0; i < NUM_DATA; ++i) {
            const int LINE         = DATA[i].d_line;
            const Bucket& BUCKET   = DATA[i].d_bucket;
            Link *FIRST            = BUCKET.d_first;
            Link *LAST             = BUCKET.d_last;
            const bool WELL_FORMED = DATA[i].d_isWellFormed;
            const int  LENGTH      = DATA[i].d_length;

            LOOP_ASSERT(LINE, WELL_FORMED == Obj::isWellFormed(FIRST, LAST));
            LOOP_ASSERT(LINE, LENGTH      == BUCKET.length());

            if (!WELL_FORMED) {
                continue;
            }

            bslma::TestAllocator ta("testAllocator", veryVeryVeryVerbose);

            Bucket bucket;
            bucket.clone(BUCKET, &ta);

            ASSERTV(LINE, !!LENGTH == (0 != ta.numBlocksInUse()));
            ASSERTV(LINE, WELL_FORMED == Obj::isWellFormed(bucket.d_first,
                                                           bucket.d_last));
            ASSERTV(LINE, LENGTH      == bucket.length());

            if (LENGTH > 0) {
                ASSERTV(LINE, 0 == bucket.d_first->previousLink());
                ASSERTV(LINE, 0 == bucket.d_last->nextLink());
            }
            else {
                ASSERTV(LINE, 0 == bucket.d_first && 0 == bucket.d_last);
            }

            bucket.destroy(&ta);
        }
      } break;
      case 2: {
        // --------------------------------------------------------------------
        // TESTING 'isWellFormed'
        //
        // Concern:
        //: 1 'isWellFormed' correctly assesses the state of ranges of links.
        //
        // Plan:
        //: 1 Feed all combinations of ranges of links to 'isWellFormed
        // --------------------------------------------------------------------

        if (verbose) printf("TESTING isWellFormed\n"
                            "====================\n");

        enum { NUM_DATA                        = NUM_DEFAULT_DATA };
        const DefaultDataRow (&DATA)[NUM_DATA] = DEFAULT_DATA;

        for (int i = 0; i < NUM_DATA; ++i) {
            const int LINE         = DATA[i].d_line;
            const Bucket& BUCKET   = DATA[i].d_bucket;
            Link *FIRST            = BUCKET.d_first;
            Link *LAST             = BUCKET.d_last;
            const bool WELL_FORMED = DATA[i].d_isWellFormed;

            ASSERTV(LINE, WELL_FORMED == Obj::isWellFormed(FIRST, LAST));
        }
      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST
        //   This case exercises (but does not fully test) basic functionality.
        //
        // Concerns:
        //: 1 The class is sufficiently functional to enable comprehensive
        //:   testing in subsequent test cases.
        //
        // Plan:
        //: 1 Perform and ad-hoc test of the primary modifiers and accessors.
        //
        // Testing:
        //   BREATHING TEST
        // --------------------------------------------------------------------

        if (verbose) printf("\nBREATHING TEST"
                            "\n==============\n");

        bslma::TestAllocator da("defaultAllocator", veryVeryVeryVerbose);
        bslma::TestAllocatorMonitor dm(&da);
        bslma::DefaultAllocatorGuard defaultGuard(&da);

        bslma::TestAllocator oa("objectAllocator", veryVeryVeryVerbose);
        bslma::TestAllocatorMonitor om(&oa);

        Link *DEFAULT1 = (Link *)(0xdeadbeef);
        Link *DEFAULT2 = (Link *)(0xfeedbeef);

// [  ] void insertLinkBeforeTarget(Link *newNode, Link* target);
// [  ] void insertLinkAfterTarget(Link *newNode, Link *target);
// [  ] bool isWellFormed(Link *head, Link *tail);
// [  ] void spliceListBeforeTarget(Link *first, Link *last, Link *target);
        if(veryVerbose) printf("Testing 'insertLinkBeforeTarget'"
                               " and 'unlink'\n");
        {
            if(veryVeryVerbose) printf("Create H\n");
            Link head; Link *H = &head;
            head.reset();
            ASSERTV(Obj::isWellFormed(H, H));

            // x-H-x

            Link link1; Link *L1 = &link1;
            link1.setNextLink(DEFAULT1);
            link1.setPreviousLink(DEFAULT2);

            if(veryVeryVerbose) printf("Insert L1 before H\n");
            Obj::insertLinkBeforeTarget(L1, H);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == H);
            ASSERTV(L1->previousLink() == 0);
            ASSERTV(Obj::isWellFormed(L1, H));

            // x-L1-H-x

            if(veryVeryVerbose) printf("Unlink L1\n");
            Obj::unlink(L1);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == H);
            ASSERTV(L1->previousLink() == 0);
            ASSERTV(Obj::isWellFormed(H, H));

            // x-H-x

            if(veryVeryVerbose) printf("Reinsert L1 before H\n");
            Obj::insertLinkBeforeTarget(L1, H);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == H);
            ASSERTV(L1->previousLink() == 0);
            ASSERTV(Obj::isWellFormed(L1, H));

            // x-L1-H-x

            if(veryVeryVerbose) printf("Insert L2 before H\n");
            Link link2; Link *L2 = &link2;
            link2.setNextLink(DEFAULT1);
            link2.setPreviousLink(DEFAULT2);

            Obj::insertLinkBeforeTarget(L2, H);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == H);
            ASSERTV(L2->previousLink() == L1);
            ASSERTV(Obj::isWellFormed(L2, H));
            ASSERTV(Obj::isWellFormed(L1, H));

            // x-L1-L2-H-x

            if(veryVeryVerbose) printf("Unlink L2\n");
            Obj::unlink(L2);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == H);
            ASSERTV(L2->previousLink() == L1);
            ASSERTV(Obj::isWellFormed(L1, H));

            // x-L1-H-x

            if(veryVeryVerbose) printf("Insert L2 before H\n");
            Obj::insertLinkBeforeTarget(L2, H);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == H);
            ASSERTV(L2->previousLink() == L1);
            ASSERTV(Obj::isWellFormed(L2, H));
            ASSERTV(Obj::isWellFormed(L1, H));

            // x-L1-L2-H-x

            if(veryVeryVerbose) printf("Insert L3 before L1\n");
            Link link3; Link *L3 = &link3;
            link3.setNextLink(DEFAULT1);
            link3.setPreviousLink(DEFAULT2);

            Obj::insertLinkBeforeTarget(L3, L1);
            ASSERTV(L3->nextLink() != DEFAULT1);
            ASSERTV(L3->previousLink() != DEFAULT1);
            ASSERTV(L3->nextLink() == L1);
            ASSERTV(L3->previousLink() == 0);
            ASSERTV(Obj::isWellFormed(L3, H));

            // x-L3-L1-L2-H-x

            if(veryVeryVerbose) printf("Remove all\n");
            Obj::unlink(H);
            Obj::isWellFormed(L3, L2);
            Obj::isWellFormed(L1, L2);
            Obj::isWellFormed(L2, L2);
            Obj::unlink(L2);
            Obj::isWellFormed(L3, L1);
            Obj::isWellFormed(L1, L1);
            Obj::unlink(L1);
            Obj::isWellFormed(L3, L3);
        }
        ASSERTV(dm.isTotalSame());
        ASSERTV(om.isTotalSame());

        if(veryVerbose) printf("Testing 'insertLinkAfterLink'"
                               " and 'unlink'\n");
        {
            if(veryVeryVerbose) printf("Create H\n");
            Link head; Link *H = &head;
            head.reset();
            ASSERTV(Obj::isWellFormed(H, H));

            // x-H-x

            Link link1; Link *L1 = &link1;
            link1.setNextLink(DEFAULT1);
            link1.setPreviousLink(DEFAULT2);

            if(veryVeryVerbose) printf("Insert L1 after H\n");
            Obj::insertLinkAfterTarget(L1, H);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == 0);
            ASSERTV(L1->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L1-x

            if(veryVeryVerbose) printf("Unlink L1\n");
            Obj::unlink(L1);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == 0);
            ASSERTV(L1->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, H));

            // x-H-x

            if(veryVeryVerbose) printf("Reinsert L1 after H\n");
            Obj::insertLinkAfterTarget(L1, H);
            ASSERTV(L1->nextLink() != DEFAULT1);
            ASSERTV(L1->previousLink() != DEFAULT1);
            ASSERTV(L1->nextLink() == 0);
            ASSERTV(L1->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L1-x

            if(veryVeryVerbose) printf("Insert L2 after H\n");
            Link link2; Link *L2 = &link2;
            link2.setNextLink(DEFAULT1);
            link2.setPreviousLink(DEFAULT2);

            Obj::insertLinkAfterTarget(L2, H);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == L1);
            ASSERTV(L2->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L2-L1-x

            if(veryVeryVerbose) printf("Unlink L2\n");
            Obj::unlink(L2);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == L1);
            ASSERTV(L2->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L1-x

            if(veryVeryVerbose) printf("Re Insert L2 after H\n");
            Obj::insertLinkAfterTarget(L2, H);
            ASSERTV(L2->nextLink() != DEFAULT1);
            ASSERTV(L2->previousLink() != DEFAULT1);
            ASSERTV(L2->nextLink() == L1);
            ASSERTV(L2->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L2-L1-x

            if(veryVeryVerbose) printf("Insert L3 after H\n");
            Link link3; Link *L3 = &link3;
            link3.setNextLink(DEFAULT1);
            link3.setPreviousLink(DEFAULT2);

            Obj::insertLinkAfterTarget(L3, H);
            ASSERTV(L3->nextLink() != DEFAULT1);
            ASSERTV(L3->previousLink() != DEFAULT1);
            ASSERTV(L3->nextLink() == L2);
            ASSERTV(L3->previousLink() == H);
            ASSERTV(Obj::isWellFormed(H, L1));

            // x-H-L3-L2-L1-x

            if(veryVeryVerbose) printf("Remove all\n");
            Obj::unlink(H);
            Obj::isWellFormed(L3, L1);
            Obj::isWellFormed(L1, L1);
            Obj::isWellFormed(L2, L1);
            Obj::unlink(L3);
            Obj::isWellFormed(L2, L1);
            Obj::isWellFormed(L1, L1);
            Obj::unlink(L2);
            Obj::isWellFormed(L1, L1);
        }
        ASSERTV(dm.isTotalSame());
        ASSERTV(om.isTotalSame());

        if(veryVerbose) printf("Testing 'insertLinkAfterLink'"
                               " and 'unlink'\n");
        {

            Link head1; Link *H1 = &head1;
            head1.reset();
            ASSERTV(Obj::isWellFormed(H1, H1));

            Link link11; Link link12; Link link13;  // link_listIndex_nodeIndex
            Obj::insertLinkAfterTarget(&link11, H1);
            Obj::insertLinkAfterTarget(&link12, &link11);
            Obj::insertLinkAfterTarget(&link13, &link12);
            ASSERTV(Obj::isWellFormed(H1, &link13));

            // x-H1-L11-L12-L13-x

            Link head2; Link *H2 = &head2;
            head2.reset();
            ASSERTV(Obj::isWellFormed(H2, H2));

            Link link21; Link link22; Link link23;  // link_listIndex_nodeIndex
            Obj::insertLinkAfterTarget(&link21, H2);
            Obj::insertLinkAfterTarget(&link22, &link21);
            Obj::insertLinkAfterTarget(&link23, &link22);
            ASSERTV(Obj::isWellFormed(H2, &link23));

            // x-H1-L11-L12-L13-x
            // x-H2-L21-L22-L23-x

            Obj::spliceListBeforeTarget(&link21, &link23, 0);
            ASSERTV(H2->nextLink() == 0);
            ASSERTV(Obj::isWellFormed(H2, H2));
            ASSERTV(Obj::isWellFormed(&link21, &link23));

            // x-H1-L11-L12-L13-x
            // x-H2-x
            // x-L21-L22-L23-x

            // Restore original state

            Obj::insertLinkBeforeTarget(H2, &link21);
            ASSERTV(H2->nextLink() == &link21);
            ASSERTV(Obj::isWellFormed(H2, &link23));

            // x-H1-L11-L12-L13-x
            // x-H2-L21-L22-L23-x

            Obj::spliceListBeforeTarget(&link21, &link22, &link11);
            ASSERTV(H2->nextLink() == &link23);
            ASSERTV(Obj::isWellFormed(H2, &link23));
            ASSERTV(H1->nextLink() == &link21);
            ASSERTV(link22.nextLink() == &link11);
            ASSERTV(Obj::isWellFormed(H1, &link13));

            // x-H1-L21-L22-L11-L12-L13-x
            // x-H2-L23-x

            Obj::spliceListBeforeTarget(&link23, &link23, H1);
            ASSERTV(0 == H2->nextLink());
            ASSERTV(0 == H2->previousLink());
            ASSERTV(link23.nextLink() == H1);
            ASSERTV(link23.previousLink() == 0);
            ASSERTV(H1->nextLink() == &link21);
            ASSERTV(H1->previousLink() == &link23);
            ASSERTV(Obj::isWellFormed(&link23, &link13));
            ASSERTV(Obj::isWellFormed(H2, H2));

            // x-L23-H1-L21-L22-L11-L12-L13-x
            // x-H2-x
        }
      } break;
      default: {
        fprintf(stderr, "WARNING: CASE `%d' NOT FOUND.\n", test);
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        fprintf(stderr, "Error, non-zero test status = %d.\n", testStatus);
    }
    return testStatus;
}

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------


text:
'use strict';

/**
* Apply a function to each nested element in a three-dimensional nested array and assign the result to a nested element in a new three-dimensional nested array.
*
* @module @stdlib/utils/map3d
*
* @example
* var naryFunction = require( '@stdlib/utils/nary-function' );
* var abs = require( '@stdlib/math/base/special/abs' );
* var map3d = require( '@stdlib/utils/map3d' );
*
* var arr = [
*     [ [ -1, -2, -3 ] ],
*     [ [ -4, -5, -6 ] ]
* ];
*
* var out = map3d( arr, naryFunction( abs, 1 ) );
* // returns [ [ [ 1, 2, 3 ] ], [ [ 4, 5, 6 ] ] ]
*/

// MODULES //

var main = require( './main.js' );

// EXPORTS //

module.exports = main;

redpajama_set_name: RedPajamaGithub


text:
module Manifestly
  class ManifestDiff

    class ItemDiff
      def initialize(from_item, to_item)
        @from_item = from_item
        @to_item = to_item

        @markdown = "## #{to_item.repository_name}#{item_source_info}\n\n#{commits_markdown}\n"
      end

      def to_markdown
        @markdown
      end

      def from_sha
        @from_item.commit.sha
      end

      def to_sha
        @to_item.commit.sha
      end

      def item_source_info
        new_item? ?
          " (new manifest entry)" :
          " (`#{from_sha[0..9]}` to `#{to_sha[0..9]}`)"
      end

      def new_item?
        @from_item.nil?
      end

      def commits_markdown
        if new_item?
          "* This manifest item was not in the prior manifest, so all of its commits are new."
        else
          repository = @from_item.repository
          repository.toggle_prs_only

          is_rollback = false

          commits = repository.commits(between: [from_sha, to_sha])

          if commits.size == 0
            # This might be a rollback, so try them backwards
            commits = repository.commits(between: [to_sha, from_sha])
            is_rollback = commits.size != 0
          end

          if commits.size == 0
            "* There were no pull requests merged in this range of commits."
          else
            entries = commits.collect do |commit|
              wrapper = Commit.new(commit)
              entry = wrapper.summarized_message

              entry = "[#{entry}](https://github.com/#{repository.display_name}/pull/#{wrapper.pr_number})" if wrapper.is_pr?

              "1. #{entry}"
            end.join("\n")

            is_rollback ? "These commits were ***rolled back***:\n\n#{entries}" : entries
          end
        end
      end
    end

    def initialize(from_manifest, to_manifest)
      @from_manifest = from_manifest
      @to_manifest = to_manifest

      @item_diffs = @to_manifest.items.collect do |to_item|
        from_item = @from_manifest.items.detect do |from_item|
          from_item.repository_name == to_item.repository_name
        end

        ItemDiff.new(from_item, to_item)
      end
    end

    def to_markdown
      "# Manifest Diff\n\n#{manifest_source_info}\n\n#{@item_diffs.collect(&:to_markdown).join("\n")}"
    end

    def manifest_source_info
      repository = @from_manifest.manifest_repository
      file = @from_manifest.manifest_file
      from_sha = @from_manifest.manifest_sha
      to_sha = @to_manifest.manifest_sha

      if repository && file && from_sha && to_sha
        "Comparing manifest ***#{file}*** on repository ***#{repository.display_name}*** from commit `#{from_sha[0..9]}` to `#{to_sha[0..9]}`."
      else
        "Manifest source info is *unknown*."
      end
    end

  end
end


text:
export const ADDON_ID = 'storybook/addon-events';

export const PANEL_ID = `${ADDON_ID}/panel`;

export const EVENT_PREFIX = `${ADDON_ID}/event`;

export const EVENTS = {
  ADD: 'add',
  EMIT: 'emit',
};


text:
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <string.h>

#include <memory>

#include "base/macros.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
#include "chrome/renderer/autofill/fake_content_password_manager_driver.h"
#include "chrome/renderer/autofill/fake_password_manager_client.h"
#include "chrome/renderer/autofill/password_generation_test_utils.h"
#include "chrome/test/base/chrome_render_view_test.h"
#include "components/autofill/content/renderer/autofill_agent.h"
#include "components/autofill/content/renderer/test_password_generation_agent.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_generation_util.h"
#include "content/public/common/associated_interface_provider.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebWidget.h"
#include "ui/events/keycodes/keyboard_codes.h"

using blink::WebDocument;
using blink::WebElement;
using blink::WebInputElement;
using blink::WebNode;
using blink::WebString;

namespace autofill {

class PasswordGenerationAgentTest : public ChromeRenderViewTest {
 public:
  PasswordGenerationAgentTest() {}

  void RegisterMainFrameRemoteInterfaces() override {
    // We only use the fake driver for main frame
    // because our test cases only involve the main frame.
    service_manager::InterfaceProvider* remote_interfaces =
        view_->GetMainRenderFrame()->GetRemoteInterfaces();
    service_manager::InterfaceProvider::TestApi test_api(remote_interfaces);
    test_api.SetBinderForName(
        mojom::PasswordManagerDriver::Name_,
        base::Bind(&PasswordGenerationAgentTest::BindPasswordManagerDriver,
                   base::Unretained(this)));

    // Because the test cases only involve the main frame in this test,
    // the fake password client is only used for the main frame.
    content::AssociatedInterfaceProvider* remote_associated_interfaces =
        view_->GetMainRenderFrame()->GetRemoteAssociatedInterfaces();
    remote_associated_interfaces->OverrideBinderForTesting(
        mojom::PasswordManagerClient::Name_,
        base::Bind(&PasswordGenerationAgentTest::BindPasswordManagerClient,
                   base::Unretained(this)));
  }

  void TearDown() override {
    LoadHTML("");
    ChromeRenderViewTest::TearDown();
  }

  void LoadHTMLWithUserGesture(const char* html) {
    LoadHTML(html);

    // Enable show-ime event when element is focused by indicating that a user
    // gesture has been processed since load.
    EXPECT_TRUE(SimulateElementClick("dummy"));
  }

  void FocusField(const char* element_id) {
    WebDocument document = GetMainFrame()->document();
    blink::WebElement element =
        document.getElementById(blink::WebString::fromUTF8(element_id));
    ASSERT_FALSE(element.isNull());
    ExecuteJavaScriptForTests(
        base::StringPrintf("document.getElementById('%s').focus();",
                           element_id).c_str());
  }

  void ExpectGenerationAvailable(const char* element_id,
                                 bool available) {
    FocusField(element_id);
    base::RunLoop().RunUntilIdle();
    fake_pw_client_.Flush();
    bool called = fake_pw_client_.called_show_pw_generation_popup();
    if (available)
      ASSERT_TRUE(called);
    else
      ASSERT_FALSE(called);

    fake_pw_client_.reset_called_show_pw_generation_popup();
  }

  void AllowToRunFormClassifier() {
    password_generation_->AllowToRunFormClassifier();
  }

  void ExpectFormClassifierVoteReceived(
      bool received,
      const base::string16& expected_generation_element) {
    base::RunLoop().RunUntilIdle();
    if (received) {
      ASSERT_TRUE(fake_driver_.called_save_generation_field());
      EXPECT_EQ(expected_generation_element,
                fake_driver_.save_generation_field());
    } else {
      ASSERT_FALSE(fake_driver_.called_save_generation_field());
    }

    fake_driver_.reset_save_generation_field();
  }

  bool GetCalledShowPasswordGenerationPopup() {
    fake_pw_client_.Flush();
    return fake_pw_client_.called_show_pw_generation_popup();
  }

  void ShowGenerationPopUpManually(const char* element_id) {
    FocusField(element_id);
    password_generation_->UserTriggeredGeneratePassword();
  }

  void BindPasswordManagerDriver(mojo::ScopedMessagePipeHandle handle) {
    fake_driver_.BindRequest(
        mojo::MakeRequest<mojom::PasswordManagerDriver>(std::move(handle)));
  }

  void BindPasswordManagerClient(mojo::ScopedInterfaceEndpointHandle handle) {
    fake_pw_client_.BindRequest(
        mojo::MakeAssociatedRequest<mojom::PasswordManagerClient>(
            std::move(handle)));
  }

  FakeContentPasswordManagerDriver fake_driver_;
  FakePasswordManagerClient fake_pw_client_;

 private:
  DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest);
};

const char kSigninFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'password'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kAccountCreationFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/pa/th?q=1&p=3#first'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'text' id = 'address'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kAccountCreationNoForm[] =
    "<INPUT type = 'text' id = 'username'/> "
    "<INPUT type = 'password' id = 'first_password' size = 5/>"
    "<INPUT type = 'password' id = 'second_password' size = 5/> "
    "<INPUT type = 'text' id = 'address'/> "
    "<INPUT type = 'button' id = 'dummy'/> "
    "<INPUT type = 'submit' value = 'LOGIN' />";

const char kDisabledElementAccountCreationFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' "
    "         autocomplete = 'off' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'text' id = 'address'/> "
    "  <INPUT type = 'text' id = 'disabled' disabled/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kHiddenPasswordAccountCreationFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password'/> "
    "  <INPUT type = 'password' id = 'second_password' style='display:none'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kInvalidActionAccountCreationFormHTML[] =
    "<FORM name = 'blah' action = 'invalid'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password'/> "
    "  <INPUT type = 'password' id = 'second_password'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kMultipleAccountCreationFormHTML[] =
    "<FORM name = 'login' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' id = 'random'/> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'password'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>"
    "<FORM name = 'signup' action = 'http://www.random.com/signup'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' "
    "         autocomplete = 'off' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'text' id = 'address'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kBothAutocompleteAttributesFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' autocomplete='username' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' "
    "         autocomplete = 'new-password' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kUsernameAutocompleteAttributeFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' autocomplete='username' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char kNewPasswordAutocompleteAttributeFormHTML[] =
    "<FORM name = 'blah' action = 'http://www.random.com/'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'first_password' "
    "         autocomplete='new-password' size = 5/>"
    "  <INPUT type = 'password' id = 'second_password' size = 5/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'LOGIN' />"
    "</FORM>";

const char ChangeDetectionScript[] =
    "<script>"
    "  firstOnChangeCalled = false;"
    "  secondOnChangeCalled = false;"
    "  document.getElementById('first_password').onchange = function() {"
    "    firstOnChangeCalled = true;"
    "  };"
    "  document.getElementById('second_password').onchange = function() {"
    "    secondOnChangeCalled = true;"
    "  };"
    "</script>";

const char kPasswordChangeFormHTML[] =
    "<FORM name = 'ChangeWithUsernameForm' action = 'http://www.bidule.com'> "
    "  <INPUT type = 'text' id = 'username'/> "
    "  <INPUT type = 'password' id = 'password'/> "
    "  <INPUT type = 'password' id = 'newpassword'/> "
    "  <INPUT type = 'password' id = 'confirmpassword'/> "
    "  <INPUT type = 'button' id = 'dummy'/> "
    "  <INPUT type = 'submit' value = 'Login'/> "
    "</FORM>";

TEST_F(PasswordGenerationAgentTest, DetectionTest) {
  // Don't shown the icon for non account creation forms.
  LoadHTMLWithUserGesture(kSigninFormHTML);
  ExpectGenerationAvailable("password", false);

  // We don't show the decoration yet because the feature isn't enabled.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  ExpectGenerationAvailable("first_password", false);

  // Pretend like We have received message indicating site is not blacklisted,
  // and we have received message indicating the form is classified as
  // ACCOUNT_CREATION_FORM form Autofill server. We should show the icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);

  // Hidden fields are not treated differently.
  LoadHTMLWithUserGesture(kHiddenPasswordAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kHiddenPasswordAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);

  // This doesn't trigger because the form action is invalid.
  LoadHTMLWithUserGesture(kInvalidActionAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kInvalidActionAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", false);
}

TEST_F(PasswordGenerationAgentTest, FillTest) {
  // Make sure that we are enabled before loading HTML.
  std::string html = std::string(kAccountCreationFormHTML) +
      ChangeDetectionScript;
  LoadHTMLWithUserGesture(html.c_str());
  SetNotBlacklistedMessage(password_generation_, html.c_str());
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);

  WebDocument document = GetMainFrame()->document();
  WebElement element =
      document.getElementById(WebString::fromUTF8("first_password"));
  ASSERT_FALSE(element.isNull());
  WebInputElement first_password_element = element.to<WebInputElement>();
  element = document.getElementById(WebString::fromUTF8("second_password"));
  ASSERT_FALSE(element.isNull());
  WebInputElement second_password_element = element.to<WebInputElement>();

  // Both password fields should be empty.
  EXPECT_TRUE(first_password_element.value().isNull());
  EXPECT_TRUE(second_password_element.value().isNull());

  base::string16 password = base::ASCIIToUTF16("random_password");
  password_generation_->GeneratedPasswordAccepted(password);

  // Password fields are filled out and set as being autofilled.
  EXPECT_EQ(password, first_password_element.value());
  EXPECT_EQ(password, second_password_element.value());
  EXPECT_TRUE(first_password_element.isAutofilled());
  EXPECT_TRUE(second_password_element.isAutofilled());

  // Make sure onchange events are called.
  int first_onchange_called = -1;
  int second_onchange_called = -1;
  ASSERT_TRUE(
      ExecuteJavaScriptAndReturnIntValue(
          base::ASCIIToUTF16("firstOnChangeCalled ? 1 : 0"),
          &first_onchange_called));
  EXPECT_EQ(1, first_onchange_called);
  ASSERT_TRUE(
      ExecuteJavaScriptAndReturnIntValue(
          base::ASCIIToUTF16("secondOnChangeCalled ? 1 : 0"),
          &second_onchange_called));
  EXPECT_EQ(1, second_onchange_called);

  // Focus moved to the next input field.
  // TODO(zysxqn): Change this back to the address element once Bug 90224
  // https://bugs.webkit.org/show_bug.cgi?id=90224 has been fixed.
  element = document.getElementById(WebString::fromUTF8("first_password"));
  ASSERT_FALSE(element.isNull());
  EXPECT_EQ(element, document.focusedElement());
}

TEST_F(PasswordGenerationAgentTest, EditingTest) {
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);

  WebDocument document = GetMainFrame()->document();
  WebElement element =
      document.getElementById(WebString::fromUTF8("first_password"));
  ASSERT_FALSE(element.isNull());
  WebInputElement first_password_element = element.to<WebInputElement>();
  element = document.getElementById(WebString::fromUTF8("second_password"));
  ASSERT_FALSE(element.isNull());
  WebInputElement second_password_element = element.to<WebInputElement>();

  base::string16 password = base::ASCIIToUTF16("random_password");
  password_generation_->GeneratedPasswordAccepted(password);

  // Passwords start out the same.
  EXPECT_EQ(password, first_password_element.value());
  EXPECT_EQ(password, second_password_element.value());

  // After editing the first field they are still the same.
  std::string edited_password_ascii = "edited_password";
  SimulateUserInputChangeForElement(&first_password_element,
                                    edited_password_ascii);
  base::string16 edited_password = base::ASCIIToUTF16(edited_password_ascii);
  EXPECT_EQ(edited_password, first_password_element.value());
  EXPECT_EQ(edited_password, second_password_element.value());

  fake_driver_.reset_called_password_no_longer_generated();

  // Verify that password mirroring works correctly even when the password
  // is deleted.
  SimulateUserInputChangeForElement(&first_password_element, std::string());
  EXPECT_EQ(base::string16(), first_password_element.value());
  EXPECT_EQ(base::string16(), second_password_element.value());

  // Should have notified the browser that the password is no longer generated
  // and trigger generation again.
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(fake_driver_.called_password_no_longer_generated());
  EXPECT_TRUE(GetCalledShowPasswordGenerationPopup());
}

TEST_F(PasswordGenerationAgentTest, BlacklistedTest) {
  // Did not receive not blacklisted message. Don't show password generation
  // icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", false);

  // Receive one not blacklisted message for non account creation form. Don't
  // show password generation icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kSigninFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", false);

  // Receive one not blacklisted message for account creation form. Show
  // password generation icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);

  // Receive two not blacklisted messages, one is for account creation form and
  // the other is not. Show password generation icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kSigninFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);
}

TEST_F(PasswordGenerationAgentTest, AccountCreationFormsDetectedTest) {
  // Did not receive account creation forms detected message. Don't show
  // password generation icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  ExpectGenerationAvailable("first_password", false);

  // Receive the account creation forms detected message. Show password
  // generation icon.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);
}

TEST_F(PasswordGenerationAgentTest, MaximumOfferSize) {
  base::HistogramTester histogram_tester;

  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);
  ExpectGenerationAvailable("first_password", true);

  WebDocument document = GetMainFrame()->document();
  WebElement element =
      document.getElementById(WebString::fromUTF8("first_password"));
  ASSERT_FALSE(element.isNull());
  WebInputElement first_password_element = element.to<WebInputElement>();

  // Make a password just under maximum offer size.
  SimulateUserInputChangeForElement(
      &first_password_element,
      std::string(password_generation_->kMaximumOfferSize - 1, 'a'));
  // There should now be a message to show the UI.
  EXPECT_TRUE(GetCalledShowPasswordGenerationPopup());
  fake_pw_client_.reset_called_show_pw_generation_popup();

  fake_pw_client_.reset_called_hide_pw_generation_popup();
  // Simulate a user typing a password just over maximum offer size.
  SimulateUserTypingASCIICharacter('a', false);
  SimulateUserTypingASCIICharacter('a', true);
  // There should now be a message to hide the UI.
  fake_pw_client_.Flush();
  EXPECT_TRUE(fake_pw_client_.called_hide_pw_generation_popup());
  fake_pw_client_.reset_called_show_pw_generation_popup();

  // Simulate the user deleting characters. The generation popup should be shown
  // again.
  SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
  // There should now be a message to show the UI.
  EXPECT_TRUE(GetCalledShowPasswordGenerationPopup());
  fake_pw_client_.reset_called_show_pw_generation_popup();

  // Change focus. Bubble should be hidden, but that is handled by AutofilAgent,
  // so no messages are sent.
  ExecuteJavaScriptForTests("document.getElementById('username').focus();");
  EXPECT_FALSE(GetCalledShowPasswordGenerationPopup());
  fake_pw_client_.reset_called_show_pw_generation_popup();

  // Focusing the password field will bring up the generation UI again.
  ExecuteJavaScriptForTests(
      "document.getElementById('first_password').focus();");
  EXPECT_TRUE(GetCalledShowPasswordGenerationPopup());
  fake_pw_client_.reset_called_show_pw_generation_popup();

  // Loading a different page triggers UMA stat upload. Verify that only one
  // display event is sent even though
  LoadHTMLWithUserGesture(kSigninFormHTML);

  histogram_tester.ExpectBucketCount(
      "PasswordGeneration.Event",
      autofill::password_generation::GENERATION_POPUP_SHOWN,
      1);
}

TEST_F(PasswordGenerationAgentTest, DynamicFormTest) {
  LoadHTMLWithUserGesture(kSigninFormHTML);
  SetNotBlacklistedMessage(password_generation_, kSigninFormHTML);

  ExecuteJavaScriptForTests(
      "var form = document.createElement('form');"
      "form.action='http://www.random.com';"
      "var username = document.createElement('input');"
      "username.type = 'text';"
      "username.id = 'dynamic_username';"
      "var first_password = document.createElement('input');"
      "first_password.type = 'password';"
      "first_password.id = 'first_password';"
      "first_password.name = 'first_password';"
      "var second_password = document.createElement('input');"
      "second_password.type = 'password';"
      "second_password.id = 'second_password';"
      "second_password.name = 'second_password';"
      "form.appendChild(username);"
      "form.appendChild(first_password);"
      "form.appendChild(second_password);"
      "document.body.appendChild(form);");
  WaitForAutofillDidAssociateFormControl();

  // This needs to come after the DOM has been modified.
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 1, 1);

  // TODO(gcasto): I'm slightly worried about flakes in this test where
  // didAssociateFormControls() isn't called. If this turns out to be a problem
  // adding a call to OnDynamicFormsSeen(GetMainFrame()) will fix it, though
  // it will weaken the test.
  ExpectGenerationAvailable("first_password", true);
}

TEST_F(PasswordGenerationAgentTest, MultiplePasswordFormsTest) {
  // If two forms on the page looks like possible account creation forms, make
  // sure to trigger on the one that is specified from Autofill.
  LoadHTMLWithUserGesture(kMultipleAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kMultipleAccountCreationFormHTML);

  // Should trigger on the second form.
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 1, 1);

  ExpectGenerationAvailable("password", false);
  ExpectGenerationAvailable("first_password", true);
}

TEST_F(PasswordGenerationAgentTest, MessagesAfterAccountSignupFormFound) {
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);

  // Generation should be enabled.
  ExpectGenerationAvailable("first_password", true);

  // Extra not blacklisted messages can be sent. Make sure that they are handled
  // correctly (generation should still be available).
  SetNotBlacklistedMessage(password_generation_, kAccountCreationFormHTML);

  // Need to focus another field first for verification to work.
  ExpectGenerationAvailable("second_password", false);
  ExpectGenerationAvailable("first_password", true);
}

// Losing focus should not trigger a password generation popup.
TEST_F(PasswordGenerationAgentTest, BlurTest) {
  LoadHTMLWithUserGesture(kDisabledElementAccountCreationFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kDisabledElementAccountCreationFormHTML);
  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 1);

  // Focus on the first password field: password generation popup should show
  // up.
  ExpectGenerationAvailable("first_password", true);

  fake_pw_client_.reset_called_generation_available_for_form();
  // Remove focus from everywhere by clicking an unfocusable element: password
  // generation popup should not show up.
  EXPECT_TRUE(SimulateElementClick("disabled"));
  fake_pw_client_.Flush();
  EXPECT_FALSE(fake_pw_client_.called_generation_available_for_form());
  EXPECT_FALSE(GetCalledShowPasswordGenerationPopup());
}

TEST_F(PasswordGenerationAgentTest, AutocompleteAttributesTest) {
  // Verify that autocomplete attributes can override Autofill to enable
  // generation
  LoadHTMLWithUserGesture(kBothAutocompleteAttributesFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kBothAutocompleteAttributesFormHTML);

  ExpectGenerationAvailable("first_password", true);

  // Only setting one of the two attributes doesn't trigger generation.
  LoadHTMLWithUserGesture(kUsernameAutocompleteAttributeFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kUsernameAutocompleteAttributeFormHTML);

  ExpectGenerationAvailable("first_password", false);

  LoadHTMLWithUserGesture(kNewPasswordAutocompleteAttributeFormHTML);
  SetNotBlacklistedMessage(password_generation_,
                           kNewPasswordAutocompleteAttributeFormHTML);

  ExpectGenerationAvailable("first_password", false);
}

TEST_F(PasswordGenerationAgentTest, ChangePasswordFormDetectionTest) {
  // Verify that generation is shown on correct field after message receiving.
  LoadHTMLWithUserGesture(kPasswordChangeFormHTML);
  SetNotBlacklistedMessage(password_generation_, kPasswordChangeFormHTML);
  ExpectGenerationAvailable("password", false);
  ExpectGenerationAvailable("newpassword", false);
  ExpectGenerationAvailable("confirmpassword", false);

  SetAccountCreationFormsDetectedMessage(password_generation_,
                                         GetMainFrame()->document(), 0, 2);
  ExpectGenerationAvailable("password", false);
  ExpectGenerationAvailable("newpassword", true);
  ExpectGenerationAvailable("confirmpassword", false);
}

TEST_F(PasswordGenerationAgentTest, ManualGenerationInFormTest) {
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  ShowGenerationPopUpManually("first_password");
  ExpectGenerationAvailable("first_password", true);
  ExpectGenerationAvailable("second_password", false);
}

TEST_F(PasswordGenerationAgentTest, ManualGenerationNoFormTest) {
  LoadHTMLWithUserGesture(kAccountCreationNoForm);
  ShowGenerationPopUpManually("first_password");
  ExpectGenerationAvailable("first_password", true);
  ExpectGenerationAvailable("second_password", false);
}

TEST_F(PasswordGenerationAgentTest, ManualGenerationChangeFocusTest) {
  // This test simulates focus change after user triggered password generation.
  // PasswordGenerationAgent should save last focused password element and
  // generate password, even if focused element has changed.
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  FocusField("first_password");
  ShowGenerationPopUpManually("username" /* current focus */);
  ExpectGenerationAvailable("first_password", true);
  ExpectGenerationAvailable("second_password", false);
}

TEST_F(PasswordGenerationAgentTest, PresavingGeneratedPassword) {
  const struct {
    const char* form;
    const char* generation_element;
  } kTestCases[] = {{kAccountCreationFormHTML, "first_password"},
                    {kAccountCreationNoForm, "first_password"},
                    {kPasswordChangeFormHTML, "newpassword"}};
  for (auto& test_case : kTestCases) {
    SCOPED_TRACE(testing::Message("form: ") << test_case.form);
    LoadHTMLWithUserGesture(test_case.form);
    // To be able to work with input elements outside <form>'s, use manual
    // generation.
    ShowGenerationPopUpManually(test_case.generation_element);
    ExpectGenerationAvailable(test_case.generation_element, true);

    base::string16 password = base::ASCIIToUTF16("random_password");
    password_generation_->GeneratedPasswordAccepted(password);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(fake_driver_.called_presave_generated_password());
    fake_driver_.reset_called_presave_generated_password();

    FocusField(test_case.generation_element);
    SimulateUserTypingASCIICharacter('a', true);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(fake_driver_.called_presave_generated_password());
    fake_driver_.reset_called_presave_generated_password();

    for (size_t i = 0; i < password.length(); ++i)
      SimulateUserTypingASCIICharacter(ui::VKEY_BACK, false);
    SimulateUserTypingASCIICharacter(ui::VKEY_BACK, true);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(fake_driver_.called_password_no_longer_generated());
    fake_driver_.reset_called_password_no_longer_generated();
  }
}

TEST_F(PasswordGenerationAgentTest, FormClassifierVotesSignupForm) {
  AllowToRunFormClassifier();
  LoadHTMLWithUserGesture(kAccountCreationFormHTML);
  ExpectFormClassifierVoteReceived(true /* vote is expected */,
                                   base::ASCIIToUTF16("first_password"));
}

TEST_F(PasswordGenerationAgentTest, FormClassifierVotesSigninForm) {
  AllowToRunFormClassifier();
  LoadHTMLWithUserGesture(kSigninFormHTML);
  ExpectFormClassifierVoteReceived(true /* vote is expected */,
                                   base::string16());
}

TEST_F(PasswordGenerationAgentTest, FormClassifierDisabled) {
  LoadHTMLWithUserGesture(kSigninFormHTML);
  ExpectFormClassifierVoteReceived(false /* vote is not expected */,
                                   base::string16());
}

}  // namespace autofill


text:
package org.jivesoftware.admin;

import org.junit.Test;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class AuthCheckFilterTest {

    // login.jsp,index.jsp?logout=true,setup/index.jsp,setup/setup-,.gif,.png,error-serverdown.jsp

    @Test
    public void testExcludeRules() {
        assertFalse(AuthCheckFilter.testURLPassesExclude("blahblah/login.jsp", "login.jsp"));
        assertTrue(AuthCheckFilter.testURLPassesExclude("login.jsp", "login.jsp"));
        assertTrue(AuthCheckFilter.testURLPassesExclude("login.jsp?yousuck&blah", "login.jsp"));
        assertTrue(AuthCheckFilter.testURLPassesExclude("login.jsp?another=true&login.jsp?true", "login.jsp"));
        assertFalse(AuthCheckFilter.testURLPassesExclude("blahblah/login.jsp", "login.jsp?logout=false"));
        assertTrue(AuthCheckFilter.testURLPassesExclude("login.jsp?logout=false", "login.jsp?logout=false"));
        assertFalse(AuthCheckFilter.testURLPassesExclude("login.jsp?logout=false&another=true", "login.jsp?logout=false"));
        assertFalse(AuthCheckFilter.testURLPassesExclude("login.jsp?logout=false&another=true", "login.jsp?logout=false"));

        assertFalse(AuthCheckFilter.testURLPassesExclude("setup/setup-/../../log.jsp?log=info&mode=asc&lines=All","setup/setup-*"));
        assertFalse(AuthCheckFilter.testURLPassesExclude("setup/setup-/%2E/%2E/log.jsp?log=info&mode=asc&lines=All","setup/setup-*"));

        assertTrue(AuthCheckFilter.testURLPassesExclude("setup/setup-new.jsp","setup/setup-*"));

        assertFalse(AuthCheckFilter.testURLPassesExclude("another.jsp?login.jsp", "login.jsp"));
    }
}


text:
<?php

/**
 * Class OxpsOxid2Paymorrow.
 * OXID to Paymorrow gateway bootstrap.
 */
class OxpsOxid2Paymorrow
{

    /**
     * Get Paymorrow module settings instance.
     *
     * @return OxpsPaymorrowSettings
     */
    public function getPaymorrowSettings()
    {
        return oxNew( 'OxpsPaymorrowSettings' );
    }

    /**
     * Get Paymorrow gateway instance.
     *
     * @return OxpsPaymorrowGateway|PaymorrowGateway
     */
    public function getPaymorrowGateway()
    {
        return oxNew( 'OxpsPaymorrowGateway' );
    }

    /**
     * Get request controller instance.
     *
     * @return RequestController
     */
    public function getPaymorrowRequestController()
    {
        return oxNew( 'RequestController' );
    }

    /**
     * Get Paymorrow client instance.
     *
     * @return OxpsPaymorrowClient
     */
    public function getPaymorrowClient()
    {
        return oxNew( 'OxpsPaymorrowClient' );
    }

    /**
     * Get data provider instance.
     *
     * @return OxpsPaymorrowEshopDataProvider
     */
    public function getEshopDataProvider()
    {
        return oxNew( 'OxpsPaymorrowEshopDataProvider' );
    }

    /**
     * Get built resource proxy with merchant and endpoint url set.
     *
     * @return PaymorrowResourceProxy
     */
    public function getBuiltPaymorrowResourceProxy()
    {
        /** @var  $oPmResourceProxy PaymorrowResourceProxy */
        $oPmResourceProxy = oxNew( 'PaymorrowResourceProxy' );

        $oPmSettings = $this->getPaymorrowSettings();

        $oPmResourceProxy->setMerchantId( $oPmSettings->getMerchantId() );
        $oPmResourceProxy->setEndPointUrl( $oPmSettings->getPaymorrowResourcePath() );

        return $oPmResourceProxy;
    }

    /**
     * Collects user data for Paymorrow JavaScript library.
     *
     * @codeCoverageIgnore
     *
     * @return string
     */
    public function getPaymorrowPrintData()
    {
        return $this->getEshopDataProvider()->printPmData();
    }

    /**
     * Get initialized Paymorrow gateway instance.
     *
     * @return OxpsPaymorrowGateway
     */
    public function buildPaymorrowGateway()
    {
        $oPmGateway = $this->getPaymorrowGateway();
        $oPmGateway->setPmClient( $this->getPaymorrowClient() );
        $oPmGateway->setEshopDataProvider( $this->getEshopDataProvider() );
        $oPmGateway->setEndPointUrl( $this->getPaymorrowSettings()->getEndPointURL() );

        /**
         * Using singleton pattern in order to get access to this object later
         * and check response from Paymorrow
         */
        $oPmGateway->setResponseHandler( oxRegistry::get( 'OxpsPaymorrowResponseHandler' ) );

        return $oPmGateway;
    }

    /**
     * Get built Paymorrow request controller with Paymorrow gateway set.
     *
     * @return RequestController
     */
    public function getBuiltPaymorrowRequestController()
    {
        $oPmRequestController = $this->getPaymorrowRequestController();

        $oPmGateway = $this->buildPaymorrowGateway();

        $oPmRequestController->setGateway( $oPmGateway );

        return $oPmRequestController;
    }

    /**
     * Get Paymorrow error handler instance.
     *
     * @return OxpsPaymorrowErrorHandler
     */
    public function getPaymorrowErrorHandler()
    {
        return oxNew( 'OxpsPaymorrowErrorHandler' );
    }
}


text:
isPullRequest() {
    # Bash treats 0 as non-failure/success and non-zero as failure
    [[ "$GITHUB_EVENT_NAME" == "pull_request" ]] && return 0 || return 255
}

exitOnFailedBuild() {
    if [ $? -ne 0 ]; then
        exit 1
    fi
}

boxOut(){
    local s="$*"
    tput setaf 3
    echo -e " =${s//?/=}=\n| $(tput setaf 4)$s$(tput setaf 3) |\n =${s//?/=}=\n"
    tput sgr 0
}

acceptLicenses() {
    mkdir -p ${ANDROID_HOME}licenses
    echo -e "\nd56f5187479451eabf01fb78af6dfcb131a6481e\n24333f8a63b6825ea9c5514f83c2829b004d1fee" > ${ANDROID_HOME}licenses/android-sdk-license
}

buildBelvedere() {
    ./gradlew :belvedere-core:assembleRelease :belvedere:assembleRelease
    exitOnFailedBuild
}

testBelvedere() {
    ./gradlew clean :belvedere-core:lintRelease :belvedere:lintRelease :belvedere-core:testRelease :belvedere:testRelease
    exitOnFailedBuild
}

uploadSnapshotSdk() {
    export LOCAL_BUILD="false"

    ./gradlew --settings-file scripts/gradle/build-belvedere-core.gradle -Pandroid.useAndroidX=true clean :belvedere-core:uploadArchive
    exitOnFailedBuild

    ./gradlew --settings-file scripts/gradle/build-belvedere.gradle -Pandroid.useAndroidX=true clean :belvedere:uploadArchive
    exitOnFailedBuild

    buildSampleApp
    exitOnFailedBuild

    unset LOCAL_BUILD
}

# SampleApp specific stuff
buildSampleApp() {
    ./gradlew :belvedere-sample:assembleTravis
    exitOnFailedBuild
}

uploadSampleApp() {
    ./gradlew :SampleApp:uploadDebugToHockeyApp
    exitOnFailedBuild
}

# Build types
pullRequestBuild() {
    export LOCAL_BUILD="true"

    boxOut "Build Belvedere Core SDK"
    buildBelvedere

    boxOut "Test Belvedere"
    testBelvedere

    boxOut "Build Sample App"
    buildSampleApp

    unset LOCAL_BUILD
}

branchBuild() {
    pullRequestBuild

    boxOut "Upload Belvedere Snapshots"
    uploadSnapshotSdk
}

acceptLicenses

# do the thing
if isPullRequest ; then
    boxOut "This is a PR"
    pullRequestBuild
else
    boxOut "This is not a PR"
    branchBuild
fi