text:
/*jshint globalstrict:false, strict:false, maxlen: 500 */
/*global assertEqual, assertNotEqual, assertTrue, assertFalse, assertNull, assertMatch, fail, AQL_EXECUTE, AQL_EXPLAIN */

////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

const internal = require("internal");
const db = require("@arangodb").db;
const jsunity = require("jsunity");
const helper = require("@arangodb/aql-helper");
const getModifyQueryResults = helper.getModifyQueryResults;
const assertQueryError = helper.assertQueryError;
const sanitizeStats = helper.sanitizeStats;
const errors = internal.errors;

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlModifySuite () {
  const cn1 = "UnitTestsAhuacatlModify1";
  const cn2 = "UnitTestsAhuacatlModify2";

  let c1, c2;

  return {

    setUp : function () {
      db._drop(cn1);
      c1 = db._create(cn1, {numberOfShards:5});

      let docs = [];
      for (let i = 0; i < 1000; ++i) {
        docs.push({name: `test${i}`});
      }
      c1.insert(docs);
    },

    tearDown : function () {
      db._drop(cn1);
      db._drop(cn2);
      c1 = null;
      c2 = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery
////////////////////////////////////////////////////////////////////////////////

    testDynamicOptions1 : function () {
      assertQueryError(errors.ERROR_QUERY_COMPILE_TIME_OPTIONS.code, "FOR d IN @@cn REMOVE d IN @@cn OPTIONS { foo: d }", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery
////////////////////////////////////////////////////////////////////////////////

    testDynamicOptions2 : function () {
      assertQueryError(errors.ERROR_QUERY_COMPILE_TIME_OPTIONS.code, "FOR d IN @@cn REMOVE d IN @@cn OPTIONS { foo: MERGE(d, { }) }", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test subquery
////////////////////////////////////////////////////////////////////////////////

    testInvalidOptions : function () {
      assertQueryError(errors.ERROR_QUERY_PARSE.code, "FOR d IN @@cn REMOVE d IN @@cn OPTIONS 'foo'", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert update with empty update object
////////////////////////////////////////////////////////////////////////////////

    testUpsertUpdateEmpty: function () {
      for (let i = 0; i < 5; ++i) {
        const actual = AQL_EXECUTE(`UPSERT {name: "test1500"} INSERT {name: "test1500"} UPDATE {} IN ${cn1} OPTIONS { } RETURN { new: NEW, old: OLD }`);
        const res = actual.json[0];
        if (i > 0) {
          assertEqual(res.old._rev, res.new._rev);
          assertEqual(res.old.name, "test1500");
          assertEqual(4, Object.keys(res.old).length);
        }
        assertEqual(1001, c1.count());
        assertEqual(4, Object.keys(res.new).length);
        assertEqual(res.new.name, "test1500");
      }
    },

/////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert replace with empty replace object
/// in 5 iterations, starting with size 1000:
/// i = 0, document with name "test1500" doesn't exist, so inserts it size = 1001
/// i = 1, document exists so replaces it with empty document  size = 1001
/// i = 2, document with name "test1500" doesn't exist, so inserts it size = 1002
/// i = 3, document exists so replaces it with empty document  size = 1002
/// i = 4, document with name "test1500" doesn't exist, so inserts it size = 1003
/////////////////////////////////////////////////////////////////////////////////

    testUpsertReplaceEmpty: function () {
      for (let i = 0; i < 5; ++i) {
        const actual = AQL_EXECUTE(`UPSERT {name: "test1500"} INSERT {name: "test1500"} REPLACE {} IN ${cn1} OPTIONS { } RETURN { new: NEW, old: OLD }`);
        const res = actual.json[0];
        if (i % 2 !== 0) {
          assertNotEqual(res.old._rev, res.new._rev);
          assertEqual(res.old.name, "test1500");
          assertEqual(4, Object.keys(res.old).length);
          assertEqual(3, Object.keys(res.new).length);
          assertFalse(res.new.hasOwnProperty("name"));
          assertTrue(res.old.hasOwnProperty("name"));
        } else {
          assertEqual(4, Object.keys(res.new).length);
        }
      }
      assertEqual(1003, c1.count());
    },

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlRemoveSuite () {
  const cn1 = "UnitTestsAhuacatlRemove1";
  const cn2 = "UnitTestsAhuacatlRemove2";
  let c1;
  let c2;

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var i;
      db._drop(cn1);
      db._drop(cn2);
      c1 = db._create(cn1, {numberOfShards:5});
      c2 = db._create(cn2, {numberOfShards:5});

      for (i = 0; i < 100; ++i) {
        c1.save({ _key: "test" + i, value1: i, value2: "test" + i });
      }
      for (i = 0; i < 50; ++i) {
        c2.save({ _key: "test" + i, value1: i, value2: "test" + i });
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      db._drop(cn1);
      db._drop(cn2);
      c1 = null;
      c2 = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveNothing : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      let query = "FOR d IN " + cn1 + " FILTER d.value1 < 0 REMOVE d IN " + cn1;
      var actual = getModifyQueryResults(query);

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));

      let rules = AQL_EXPLAIN(query).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveNothingBind : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      let query = "FOR d IN @@cn FILTER d.value1 < 0 REMOVE d IN @@cn";
      var actual = getModifyQueryResults(query, { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveInvalid1 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn REMOVE d.foobar IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveInvalid2 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_KEY_MISSING.code, "FOR d IN @@cn REMOVE { } IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveInvalid3 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, "FOR d IN @@cn REMOVE 'foobar' IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveReturn : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = AQL_EXECUTE("FOR d IN @@cn REMOVE d IN @@cn LET removed = OLD RETURN removed", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.value1 - r.value1;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveIgnore1 : function () {
      var expected = { writesExecuted: 0, writesIgnored: 17 };
      let query = "FOR d IN @@cn REMOVE 'foo' IN @@cn OPTIONS { ignoreErrors: true }";
      var actual = getModifyQueryResults(query, { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertTrue(-1 !== rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveIgnore2 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 1 };
      var actual = getModifyQueryResults("FOR i IN 0..100 REMOVE CONCAT('test', i) IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveAll1 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn REMOVE d IN @@cn", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveAll2 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn REMOVE d._key IN @@cn", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveAll3 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn REMOVE { _key: d._key } IN @@cn", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveAll4 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 0..99 REMOVE { _key: CONCAT('test', i) } IN @@cn", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveAll5 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn REMOVE d INTO @@cn", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveHalf : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 0..99 FILTER i % 2 == 0 REMOVE { _key: CONCAT('test', i) } IN @@cn", { "@cn": cn1 });

      assertEqual(50, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testSingleRemoveNotFound : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, "REMOVE 'foobar' IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testSingleRemove : function () {
      var expected = { writesExecuted: 1, writesIgnored: 0 };
      var actual = getModifyQueryResults("REMOVE 'test0' IN @@cn", { "@cn": cn1 });

      assertEqual(99, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testTwoCollectionsNotFound : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, "FOR d IN @@cn1 REMOVE { _key: d._key } IN @@cn2", { "@cn1": cn1, "@cn2": cn2 });

      assertEqual(100, c1.count());
      assertEqual(50, c2.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testTwoCollectionsJoin1 : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn1 FILTER d.value1 < 50 REMOVE { _key: d._key } IN @@cn2", { "@cn1": cn1, "@cn2": cn2 });

      assertEqual(100, c1.count());
      assertEqual(0, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testTwoCollectionsJoin2 : function () {
      var expected = { writesExecuted: 48, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn1 FILTER d.value1 >= 2 && d.value1 < 50 REMOVE { _key: d._key } IN @@cn2", { "@cn1": cn1, "@cn2": cn2 });

      assertEqual(100, c1.count());
      assertEqual(2, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testTwoCollectionsIgnoreErrors1 : function () {
      var expected = { writesExecuted: 50, writesIgnored: 50 };
      var actual = getModifyQueryResults("FOR d IN @@cn1 REMOVE { _key: d._key } IN @@cn2 OPTIONS { ignoreErrors: true }", { "@cn1": cn1, "@cn2": cn2 });

      assertEqual(100, c1.count());
      assertEqual(0, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testTwoCollectionsIgnoreErrors2 : function () {
      var expected = { writesExecuted: 0, writesIgnored: 100 };
      var actual = getModifyQueryResults("FOR d IN @@cn1 REMOVE { _key: CONCAT('foo', d._key) } IN @@cn2 OPTIONS { ignoreErrors: true }", { "@cn1": cn1, "@cn2": cn2 });

      assertEqual(100, c1.count());
      assertEqual(50, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveWaitForSync : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn REMOVE d IN @@cn OPTIONS { waitForSync: true }", { "@cn": cn1 });

      assertEqual(0, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test remove
////////////////////////////////////////////////////////////////////////////////

    testRemoveEdge : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      for (var i = 0; i < 100; ++i) {
        edge.save("UnitTestsAhuacatlRemove1/foo" + i, "UnitTestsAhuacatlRemove2/bar", { what: i, _key: "test" + i });
      }
      var expected = { writesExecuted: 10, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 0..9 REMOVE CONCAT('test', i) IN @@cn", { "@cn": edge.name() });

      assertEqual(100, c1.count());
      assertEqual(90, edge.count());
      assertEqual(expected, sanitizeStats(actual));
      db._drop("UnitTestsAhuacatlEdge");
    }

  };
}

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlInsertSuite () {
  var cn1 = "UnitTestsAhuacatlInsert1";
  var cn2 = "UnitTestsAhuacatlInsert2";
  var cn3 = "UnitTestsAhuacatlInsert3";
  var c1;
  var c2;
  var c3;

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var i;
      db._drop(cn1);
      db._drop(cn2);
      db._drop(cn3);
      c1 = db._create(cn1, {numberOfShards: 5});
      c2 = db._create(cn2, {numberOfShards: 5});
      c3 = db._create(cn3, {numberOfShards: 2, shardKeys: [ "a", "b" ] });

      for (i = 0; i < 100; ++i) {
        c1.save({ _key: "test" + i, value1: i, value2: "test" + i });
      }
      for (i = 0; i < 50; ++i) {
        c2.save({ _key: "test" + i, value1: i, value2: "test" + i });
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      db._drop(cn1);
      db._drop(cn2);
      db._drop(cn3);
      c1 = null;
      c2 = null;
      c3 = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertDouble : function () {
      c1.truncate({ compact: false });
      c2.truncate({ compact: false });

      const query = `LET d1 = {name : 'foo'}
                     LET d2 = {name : 'bar'}
                     INSERT d1 IN @@c1
                     INSERT d2 IN @@c2
                     RETURN $NEW`;
      const bind = { "@c1" : cn1, "@c2" : cn2 };
      const options = { optimizer : {
                          rules : [ "+restrict-to-single-shard",
                                    "-optimize-cluster-single-document-operations",
                                    "-remove-unnecessary-remote-scatter"
                                  ]
                      } };
      db._query(query, bind, options);
      assertEqual(1, c1.count());
      assertEqual(1, c2.count());
    },

    testInsertTripleWithSub : function () {
      c1.truncate({ compact: false });
      c2.truncate({ compact: false });

      c3.drop();
      c3 = db._createEdgeCollection(cn3);

      const query = `WITH @@usersCollection, @@emailsCollection, @@userToEmailEdges
                     LET user = FIRST(INSERT @user IN @@usersCollection RETURN NEW)
                     INSERT @email IN @@emailsCollection
                     INSERT @edge IN @@userToEmailEdges
                     RETURN user`;
      const bind = { "@usersCollection" : cn1,
                     "@emailsCollection" : cn2,
                     "@userToEmailEdges" : cn3,
                     "user" : { "name" : "ulf" },
                     "email" : { "addr" : "ulf@ulf.de"},
                     "edge" : { "_from" : "usersCollection/abc" , "_to" : "emailsCollection/def"}
                   };
      const options = {optimizer : { rules : ["+all"] } };

      db._query(query, bind, options);
      assertEqual(1, c1.count());
      assertEqual(1, c2.count());
      assertEqual(1, c3.count());
    },
////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertNothing : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN " + cn1 + " FILTER d.value1 < 0 INSERT { foxx: true } IN " + cn1);

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertNothingBind : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn FILTER d.value1 < 0 INSERT { foxx: true } IN @@cn", { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertInvalid1 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn INSERT d.foobar IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertInvalid2 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn INSERT [ ] IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertInvalid3 : function () {
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR d IN @@cn INSERT 'foo' IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertInvalid4 : function () {
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR d IN @@cn INSERT { _key: 'foo' } IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertUniqueConstraint1 : function () {
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR d IN @@cn INSERT d IN @@cn", { "@cn": cn1 });
      assertEqual(100, c1.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertUniqueConstraint2 : function () {
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR i IN 0..100 INSERT { _key: CONCAT('test', i) } IN @@cn", { "@cn": cn2 });
      assertEqual(50, c2.count());
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    // This is disabled for the cluster because we do not yet have
    // full atomic transactions.
    //testInsertUniqueConstraint3 : function () {
    //  assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR i IN 0..50 INSERT { _key: 'foo' } IN @@cn", { "@cn": cn1 });
    //  assertEqual(100, c1.count());
    //},

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertReturn : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // key is specified
      var actual = AQL_EXECUTE("FOR d IN 0..99 INSERT { _key: CONCAT('foo', d), bar: d } IN @@cn LET result = NEW RETURN result", { "@cn": cn1 });

      assertEqual(200, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.bar - r.bar;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("foo" + i);
        assertEqual("foo" + i, doc._key);
        assertEqual(i, doc.bar);

        var doc2 = actual.json[i];
        assertEqual("foo" + i, doc2._key);
        assertEqual(i, doc2.bar);
        assertTrue(doc2.hasOwnProperty("_rev"));
        assertTrue(doc2.hasOwnProperty("_id"));
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertReturnNoKey : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // key is specified
      var actual = AQL_EXECUTE("FOR d IN 0..99 INSERT { bar: d } IN @@cn LET result = NEW RETURN result", { "@cn": cn1 });

      assertEqual(200, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.bar - r.bar;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertMatch(/^\d+$/, doc._key);
        assertEqual(i, doc.bar);
        assertTrue(doc.hasOwnProperty("_rev"));
        assertTrue(doc.hasOwnProperty("_id"));

        var doc2 = c1.document(doc._key);
        assertEqual(doc._key, doc2._key);
        assertEqual(doc._rev, doc2._rev);
        assertEqual(doc._id, doc2._id);
        assertEqual(i, doc2.bar);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertReturnShardKeys : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // key is specified
      var actual = AQL_EXECUTE("FOR d IN 0..99 INSERT { a: d, b: d + 1, bar: d } IN @@cn LET result = NEW RETURN result", { "@cn": cn3 });

      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.bar - r.bar;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertMatch(/^\d+$/, doc._key);
        assertTrue(doc.hasOwnProperty("_rev"));
        assertTrue(doc.hasOwnProperty("_id"));
        assertEqual(i, doc.bar);
        assertEqual(i, doc.a);
        assertEqual(i + 1, doc.b);

        var doc2 = c3.document(doc._key);
        assertEqual(doc._key, doc2._key);
        assertEqual(doc._rev, doc2._rev);
        assertEqual(doc._id, doc2._id);
        assertEqual(i, doc2.bar);
        assertEqual(i, doc2.a);
        assertEqual(i + 1, doc2.b);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey1 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // key is specified
      var actual = getModifyQueryResults("FOR d IN 0..99 INSERT { _key: CONCAT('foo', d), bar: d } IN @@cn", { "@cn": cn1 });

      assertEqual(200, c1.count());
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("foo" + i);
        assertEqual("foo" + i, doc._key);
        assertEqual(i, doc.bar);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey2 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // no key is specified, must be created automatically
      var actual = getModifyQueryResults("FOR d IN 0..99 INSERT { bar: d } IN @@cn", { "@cn": cn1 });

      assertEqual(200, c1.count());
      assertEqual(expected, sanitizeStats(actual));

      var docs = db._query("FOR doc IN @@cn FILTER doc.bar >= 0 SORT doc.bar RETURN doc", { "@cn": cn1 }).toArray();

      for (var i = 0; i < 100; ++i) {
        var doc = docs[i];
        assertMatch(/^\d+$/, doc._key);
        assertEqual(i, doc.bar);

        var doc2 = c1.document(doc._key);
        assertEqual(doc._key, doc2._key);
        assertEqual(doc._rev, doc2._rev);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey3 : function () {
      // key is specified, but sharding is by different attributes
      assertQueryError(errors.ERROR_CLUSTER_MUST_NOT_SPECIFY_KEY.code, "FOR i IN 0..50 INSERT { _key: 'foo' } IN @@cn", { "@cn": cn3 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey4 : function () {
      // key is specified, but sharding is by different attributes
      assertQueryError(errors.ERROR_CLUSTER_MUST_NOT_SPECIFY_KEY.code, "FOR i IN 0..50 INSERT { _key: 'foo', a: i, b: i } IN @@cn", { "@cn": cn3 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey5 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // no key is specified, must be created automatically
      var actual = getModifyQueryResults("FOR d IN 0..99 INSERT { bar: d, a: d, b: d } IN @@cn", { "@cn": cn3 });

      assertEqual(100, c3.count());
      assertEqual(expected, sanitizeStats(actual));

      var docs = db._query("FOR doc IN @@cn FILTER doc.bar >= 0 SORT doc.bar RETURN doc", { "@cn" : cn3 }).toArray();

      for (var i = 0; i < 100; ++i) {
        var doc = docs[i];
        assertMatch(/^\d+$/, doc._key);
        assertEqual(i, doc.bar);
        assertEqual(i, doc.a);
        assertEqual(i, doc.b);

        var doc2 = c3.document(doc._key);
        assertEqual(doc._key, doc2._key);
        assertEqual(doc._rev, doc2._rev);
        assertEqual(doc.a, doc2.a);
        assertEqual(doc.b, doc2.b);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertKey6 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      // no key is specified, must be created automatically
      var actual = getModifyQueryResults("FOR d IN 0..99 INSERT { bar: d, a: d } IN @@cn", { "@cn": cn3 });

      assertEqual(100, c3.count());
      assertEqual(expected, sanitizeStats(actual));

      var docs = db._query("FOR doc IN @@cn FILTER doc.bar >= 0 SORT doc.bar RETURN doc", { "@cn" : cn3 }).toArray();

      for (var i = 0; i < 100; ++i) {
        var doc = docs[i];
        assertMatch(/^\d+$/, doc._key);
        assertEqual(i, doc.bar);
        assertEqual(i, doc.a);

        var doc2 = c3.document(doc._key);
        assertEqual(doc._key, doc2._key);
        assertEqual(doc._rev, doc2._rev);
        assertEqual(doc.a, doc2.a);
        assertEqual(doc.b, doc2.b);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertIgnore1 : function () {
      var expected = { writesExecuted: 0, writesIgnored: 100 };
      var actual = getModifyQueryResults("FOR d IN @@cn INSERT d IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertIgnore2 : function () {
      var expected = { writesExecuted: 1, writesIgnored: 50 };
      var actual = getModifyQueryResults("FOR i IN 50..100 INSERT { _key: CONCAT('test', i) } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn1 });

      assertEqual(101, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertIgnore3 : function () {
      var expected = { writesExecuted: 51, writesIgnored: 50 };
      var actual = getModifyQueryResults("FOR i IN 0..100 INSERT { _key: CONCAT('test', i) } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn2 });

      assertEqual(101, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertIgnore4 : function () {
      var expected = { writesExecuted: 0, writesIgnored: 100 };
      var actual = getModifyQueryResults("FOR i IN 0..99 INSERT { _key: CONCAT('test', i) } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertIgnore5 : function () {
      var expected = { writesExecuted: 50, writesIgnored: 50 };
      var actual = getModifyQueryResults("FOR i IN 0..99 INSERT { _key: CONCAT('test', i) } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn2 });

      assertEqual(100, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEmpty : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn INSERT { } IN @@cn", { "@cn": cn1 });

      assertEqual(200, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertCopy : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 50..99 INSERT { _key: CONCAT('test', i) } IN @@cn", { "@cn": cn2 });

      assertEqual(100, c1.count());
      assertEqual(100, c2.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testSingleInsert : function () {
      var expected = { writesExecuted: 1, writesIgnored: 0 };
      var actual = getModifyQueryResults("INSERT { value: 'foobar', _key: 'test' } IN @@cn", { "@cn": cn1 });

      assertEqual(101, c1.count());
      assertEqual("foobar", c1.document("test").value);
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertWaitForSync : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 1..50 INSERT { value: i } INTO @@cn OPTIONS { waitForSync: true }", { "@cn": cn2 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEdgeInvalid : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { } INTO @@cn", { "@cn": edge.name() });
      assertEqual(0, edge.count());

      db._drop("UnitTestsAhuacatlEdge");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEdgeNoFrom : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _to: CONCAT('UnitTestsAhuacatlInsert1/', i) } INTO @@cn", { "@cn": edge.name() });
      assertEqual(0, edge.count());

      db._drop("UnitTestsAhuacatlEdge");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEdgeNoTo : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      assertQueryError(errors.ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE.code, "FOR i IN 1..50 INSERT { _from: CONCAT('UnitTestsAhuacatlInsert1/', i) } INTO @@cn", { "@cn": edge.name() });
      assertEqual(0, edge.count());

      db._drop("UnitTestsAhuacatlEdge");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEdge : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 1..50 INSERT { _key: CONCAT('test', i), _from: CONCAT('UnitTestsAhuacatlInsert1/', i), _to: CONCAT('UnitTestsAhuacatlInsert2/', i), value: [ i ], sub: { foo: 'bar' } } INTO @@cn", { "@cn": edge.name() });

      assertEqual(expected, sanitizeStats(actual));
      assertEqual(50, edge.count());

      for (var i = 1; i <= 50; ++i) {
        var doc = edge.document("test" + i);
        assertEqual("UnitTestsAhuacatlInsert1/" + i, doc._from);
        assertEqual("UnitTestsAhuacatlInsert2/" + i, doc._to);
        assertEqual([ i ], doc.value);
        assertEqual({ foo: "bar" }, doc.sub);
      }
      db._drop("UnitTestsAhuacatlEdge");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertEdgeReturn : function () {
      db._drop("UnitTestsAhuacatlEdge");
      var edge = db._createEdgeCollection("UnitTestsAhuacatlEdge");

      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = AQL_EXECUTE("FOR i IN 0..49 INSERT { _key: CONCAT('test', i), _from: CONCAT('UnitTestsAhuacatlInsert1/', i), _to: CONCAT('UnitTestsAhuacatlInsert2/', i), value: [ i ], sub: { foo: 'bar' } } INTO @@cn LET result = NEW RETURN result", { "@cn": edge.name() });

      assertEqual(expected, sanitizeStats(actual.stats));
      assertEqual(50, edge.count());

      actual.json = actual.json.sort(function(l, r) {
        return l.value[0] - r.value[0];
      });

      for (var i = 0; i < 50; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertEqual("UnitTestsAhuacatlInsert1/" + i, doc._from);
        assertEqual("UnitTestsAhuacatlInsert2/" + i, doc._to);
        assertEqual([ i ], doc.value);
        assertEqual({ foo: "bar" }, doc.sub);

        var doc2 = edge.document("test" + i);
        assertEqual(doc._rev, doc2._rev);
        assertEqual(doc._id, doc2._id);
        assertEqual(doc._from, doc2._from);
        assertEqual(doc._to, doc2._to);
        assertEqual([ i ], doc2.value);
        assertEqual({ foo: "bar" }, doc2.sub);
      }

      db._drop("UnitTestsAhuacatlEdge");
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test insert
////////////////////////////////////////////////////////////////////////////////

    testInsertOverwrite : function () {
      c1.truncate({ compact: false });
      assertEqual(0, c1.count());

      var rv1 = db._query(" INSERT { _key: '123', name: 'ulf' } IN @@cn OPTIONS { overwrite: false } RETURN NEW", { "@cn": cn1 });
      assertEqual(1, c1.count());
      var doc1 = rv1.toArray()[0];
      assertEqual(doc1._key, '123');
      assertEqual(doc1.name, 'ulf');

      var rv2 = db._query(" INSERT { _key: '123', name: 'ulfine' } IN @@cn OPTIONS { overwriteMode: 'replace' } RETURN {old: OLD, new: NEW}", { "@cn": cn1 });
      assertEqual(1, c1.count());
      var doc2 = rv2.toArray()[0];
      assertEqual(doc2.new._key, '123');
      assertEqual(doc2.new.name, 'ulfine');
      assertEqual(doc2.old._rev, doc1._rev);
      assertEqual(doc2.old._key, doc1._key);
      assertEqual(doc2.old.name, doc1.name);

      var rv3 = db._query(`
          LET x = (
            FOR a IN 3..5
              INSERT { _key: CONCAT('12',a), name: a }
            IN @@cn
              OPTIONS { overwrite: true }
              RETURN {old: OLD, new: NEW}
          )

          FOR d IN x SORT d.new._key
            RETURN d
        `, { "@cn": cn1 });

      var resultArray3 = rv3.toArray();
      assertEqual(3, c1.count());

      var doc3a = resultArray3[0];
      var doc3b = resultArray3[1];
      var doc3c = resultArray3[2];

      assertEqual(doc3a.old._rev, doc2.new._rev);
      assertEqual(doc3a.old._key, doc2.new._key);
      assertEqual(doc3a.old.name, "ulfine");
      assertEqual(doc3a.new.name, 3);
      assertEqual(doc3b.old, null);
      assertEqual(doc3b.new.name, 4);
      assertEqual(doc3c.old, null);
      assertEqual(doc3c.new.name, 5);

    },

    testInsertOverwriteUpsert : function () {
      c1.truncate({ compact: false });
      assertEqual(0, c1.count());

      var rv1 = db._query(" INSERT { _key: '123', name: 'ulf', drinks : { hard : 'korn' } } IN @@cn OPTIONS { overwrite: false } RETURN NEW", { "@cn": cn1 });
      assertEqual(1, c1.count());
      var doc1 = rv1.toArray()[0];
      assertEqual(doc1._key, '123');
      assertEqual(doc1.name, 'ulf');

      var rv2 = db._query(`
        INSERT { _key: '123'
               , partner: 'ulfine'
               , drinks : { soft : 'korn' }
               } IN @@cn OPTIONS { overwriteMode : 'update'
                                 , mergeObjects: false
                                 }
          RETURN {old: OLD, new: NEW}`
      , { "@cn": cn1 });
      assertEqual(1, c1.count());
      var doc2 = rv2.toArray()[0];
      assertEqual(doc2.new._key, '123');
      assertEqual(doc2.new.name, 'ulf');
      assertEqual(doc2.new.partner, 'ulfine');
      assertEqual(doc2.new.drinks, { 'soft' : 'korn'});
      assertEqual(doc2.old._rev, doc1._rev);
      assertEqual(doc2.old._key, doc1._key);
      assertEqual(doc2.old.name, doc1.name);
    },

  }; // end insert tests
}

////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////

function ahuacatlUpdateSuite () {
  var cn1 = "UnitTestsAhuacatlUpdate1";
  var cn2 = "UnitTestsAhuacatlUpdate2";
  var cn3 = "UnitTestsAhuacatlUpdate3";
  var cn4 = "UnitTestsAhuacatlUpdate4";
  var c1, c2, c3, c4;

  return {

////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////

    setUp : function () {
      var i;
      db._drop(cn1);
      db._drop(cn2);
      db._drop(cn3);
      c1 = db._create(cn1, {numberOfShards: 5});
      c2 = db._create(cn2, {numberOfShards: 5});
      c3 = db._create(cn3, {numberOfShards: 1});

      let docs = [];
      for (i = 0; i < 100; ++i) {
        docs.push({ _key: "test" + i, value1: i, value2: "test" + i });
      }
      c1.insert(docs);
      docs = [];
      for (let i = 0; i < 1000; ++i) {
        docs.push({name: `test${i}`});
      }
      c2.insert(docs);
      docs = [];
      for (i = 0; i < 100; ++i) {
        docs.push({ _key: "test" + i, value1: i, value2: "test" + i });
      }
      c3.insert(docs);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////

    tearDown : function () {
      db._drop(cn1);
      db._drop(cn2);
      db._drop(cn3);
      c1 = null;
      c2 = null;
      c3 = null;
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateNothing : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN " + cn1 + " FILTER d.value1 < 0 UPDATE { foxx: true } IN " + cn1);

      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateNothingBind : function () {
      var expected = { writesExecuted: 0, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn FILTER d.value1 < 0 UPDATE { foxx: true } IN @@cn", { "@cn": cn1 });

      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateInvalidType1 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn UPDATE d.foobar IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateInvalidType2 : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn UPDATE [ ] IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateInvalidType : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_TYPE_INVALID.code, "FOR d IN @@cn UPDATE 'foo' IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateInvalidKey : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, "FOR d IN @@cn UPDATE { _key: 'foo' } IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateUniqueConstraint1 : function () {
      try {
        c1.ensureIndex({ type: "hash", fields: ["value1"], unique: true });
        fail();
      }
      catch (e) {
        assertEqual(errors.ERROR_CLUSTER_UNSUPPORTED.code, e.errorNum);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateUniqueConstraint2 : function () {
      c3.ensureIndex({ type: "hash", fields: ["value1"], unique: true });
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR d IN @@cn UPDATE d._key WITH { value1: 1 } IN @@cn", { "@cn": cn3 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateUniqueConstraint3 : function () {
      c3.ensureIndex({ type: "hash", fields: ["value3"], unique: true, sparse: true });
      assertQueryError(errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code, "FOR d IN @@cn UPDATE d._key WITH { value3: 1 } IN @@cn", { "@cn": cn3 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateIgnore1 : function () {
      c3.ensureIndex({ type: "hash", fields: ["value3"], unique: true, sparse: true });
      var expected = { writesExecuted: 1, writesIgnored: 99 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d WITH { value3: 1 } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn3 });

      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateIgnore2 : function () {
      c3.ensureIndex({ type: "hash", fields: ["value1"], unique: true });
      var expected = { writesExecuted: 0, writesIgnored: 51 };
      var actual = getModifyQueryResults("FOR i IN 50..100 UPDATE { _key: CONCAT('test', i), value1: 1 } IN @@cn OPTIONS { ignoreErrors: true }", { "@cn": cn3 });

      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateEmpty1 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE { _key: d._key } IN @@cn", { "@cn": cn1 });

      assertEqual(expected, sanitizeStats(actual));
      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateEmpty2 : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d IN @@cn", { "@cn": cn1 });

      assertEqual(expected, sanitizeStats(actual));
      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
      }
    },

///////////////////////////////////////////////////////////////////////////////
/// @brief test update with empty object
////////////////////////////////////////////////////////////////////////////////

    testUpdateEmpty3: function () {
      const actual = AQL_EXECUTE(`FOR doc IN ${cn2} UPDATE doc WITH {} IN ${cn2} RETURN {old: OLD, new: NEW}`);
      const res = actual.json;
      assertEqual(res.length, 1000);
      for (let i = 0; i < res.length; ++i) {
        assertEqual(res[i].old._rev, res[i].new._rev);
        assertEqual(res[i].old.name, res[i].new.name);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update and return
////////////////////////////////////////////////////////////////////////////////

    testUpdateAndReturn : function () {
      const expected = { writesExecuted: 100, writesIgnored: 0 };
      const query = `
        FOR d IN @@cn
          UPDATE d WITH { updated: true } IN @@cn
          FILTER NEW._key == "test0"
          RETURN NEW`;

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));

      const actual = getModifyQueryResults(query, { "@cn": cn1 });

      assertEqual(expected, sanitizeStats(actual));
      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
        assertTrue(doc.updated);
      }

    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testSingleUpdateNotFound : function () {
      assertQueryError(errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code, "UPDATE { _key: 'foobar' } WITH { value1: 1 } IN @@cn", { "@cn": cn1 });
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testSingleUpdate : function () {
      var expected = { writesExecuted: 1, writesIgnored: 0 };
      var actual = getModifyQueryResults("UPDATE { value: 'foobar', _key: 'test17' } IN @@cn", { "@cn": cn1 });

      assertEqual("foobar", c1.document("test17").value);
      assertEqual(expected, sanitizeStats(actual));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateOldValue : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE { _key: d._key, value1: d.value2, value2: d.value1, value3: d.value1 + 5 } IN @@cn", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual("test" + i, doc.value1);
        assertEqual(i, doc.value2);
        assertEqual(i + 5, doc.value3);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateWaitForSync : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR i IN 1..50 UPDATE { _key: CONCAT('test', i) } INTO @@cn OPTIONS { waitForSync: true }", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateKeepNullDefault : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d._key WITH { value1: null, value3: 'foobar', value9: null, a: { b: null } } INTO @@cn", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertNull(doc.value1);
        assertEqual("test" + i, doc.value2);
        assertEqual("foobar", doc.value3);
        assertTrue(doc.hasOwnProperty("value9"));
        assertNull(doc.value9);
        assertTrue(doc.hasOwnProperty("a"));
        assertNull(doc.a.b);
        assertTrue(doc.a.hasOwnProperty("b"));
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateKeepNullTrue : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d._key WITH { value1: null, value3: 'foobar', value9: null, a: { b: null } } INTO @@cn OPTIONS { keepNull: true }", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertNull(doc.value1);
        assertEqual("test" + i, doc.value2);
        assertEqual("foobar", doc.value3);
        assertTrue(doc.hasOwnProperty("value9"));
        assertNull(doc.value9);
        assertTrue(doc.hasOwnProperty("a"));
        assertNull(doc.a.b);
        assertTrue(doc.a.hasOwnProperty("b"));
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateKeepNullFalse : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d._key WITH { value1: null, value3: 'foobar', value9: null, a: { b: null } } INTO @@cn OPTIONS { keepNull: false }", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertFalse(doc.hasOwnProperty("value1"));
        assertEqual("test" + i, doc.value2);
        assertEqual("foobar", doc.value3);
        assertFalse(doc.hasOwnProperty("value9"));
        assertTrue(doc.hasOwnProperty("a"));
        assertEqual({}, doc.a);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateFilter : function () {
      var expected = { writesExecuted: 50, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn FILTER d.value1 % 2 == 0 UPDATE d._key WITH { value2: 100 } INTO @@cn", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        if (i % 2 === 0) {
          assertEqual(100, doc.value2);
        }
        else {
          assertEqual("test" + i, doc.value2);
        }
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateUpdate : function () {
      var i;
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      for (i = 0; i < 5; ++i) {
        var actual = getModifyQueryResults("FOR d IN @@cn UPDATE d._key WITH { counter: HAS(d, 'counter') ? d.counter + 1 : 1 } INTO @@cn", { "@cn": cn1 });
        assertEqual(expected, sanitizeStats(actual));
      }

      for (i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(5, doc.counter);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateAfterInsert : function () {
      AQL_EXECUTE("FOR i IN 0..99 INSERT { _key: CONCAT('sometest', i), value: i, wantToFind: true } IN @@cn", { "@cn": cn1 });

      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = getModifyQueryResults("FOR d IN @@cn FILTER d.wantToFind UPDATE d._key WITH { value2: d.value % 2 == 0 ? d.value : d.value + 1 } INTO @@cn", { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("sometest" + i);
        assertTrue(doc.wantToFind);
        assertEqual(i, doc.value);
        assertEqual(i % 2 === 0 ? i : i + 1, doc.value2);
        assertEqual(i, doc.value);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update with search document
////////////////////////////////////////////////////////////////////////////////

    testUpdateSubKeepNullFalse : function () {
      let expected = { writesExecuted: 1, writesIgnored: 0 };
      c1.truncate({ compact: false });
      c1.insert({ _key: "foo" });

      // Patch non-existing substructure:
      var q = `FOR doc IN ${cn1}
  UPDATE doc WITH { foo: {
 bark: 'bart',
 foxx: null,
 a: null }}
 IN ${cn1} OPTIONS { keepNull: false }
 RETURN NEW`;
      var actual = AQL_EXECUTE(q, {});
      assertEqual(1, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));
      assertTrue(actual.json[0].hasOwnProperty("foo"));
      assertFalse(actual.json[0].foo.hasOwnProperty("a"));
      assertFalse(actual.json[0].foo.hasOwnProperty("foxx"));
      assertTrue(actual.json[0].foo.hasOwnProperty("bark"));
      assertEqual("bart", actual.json[0].foo.bark);

      var doc = c1.toArray()[0];
      assertEqual("foo", doc._key);
      assertTrue(doc.hasOwnProperty("foo"));
      assertFalse(doc.foo.hasOwnProperty("a"));
      assertFalse(doc.foo.hasOwnProperty("foxx"));
      assertEqual("bart", doc.foo.bark);

      actual = AQL_EXECUTE(q, {});

      assertEqual(1, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      doc = c1.toArray()[0];
      assertEqual("foo", doc._key);
      assertTrue(doc.hasOwnProperty("foo"));
      assertFalse(doc.foo.hasOwnProperty("a"));
      assertFalse(doc.foo.hasOwnProperty("foxx"));
      assertEqual("bart", doc.foo.bark);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update with search document
////////////////////////////////////////////////////////////////////////////////

    testUpdateSubKeepNullArrayFalse : function () {
      let expected = { writesExecuted: 1, writesIgnored: 0 };
      c1.truncate({ compact: false });
      c1.insert({ _key: "foo" });

      // Patch non-existing substructure:
      var q = `FOR doc IN ${cn1}
  UPDATE doc WITH { foo: [{
 bark: 'bart',
 foxx: null,
 a: null },
null,
"abc",
false
]}
 IN ${cn1} OPTIONS { keepNull: false }
 RETURN NEW`;
      var actual = AQL_EXECUTE(q, {});
      assertEqual(1, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));
      assertTrue(actual.json[0].hasOwnProperty("foo"));
      assertFalse(actual.json[0].foo.hasOwnProperty("a"));
      assertFalse(actual.json[0].foo.hasOwnProperty("foxx"));
      assertFalse(actual.json[0].foo.hasOwnProperty("bark"));
      assertEqual("bart", actual.json[0].foo[0].bark);

      var doc = c1.toArray()[0];
      assertEqual("foo", doc._key);
      assertTrue(doc.hasOwnProperty("foo"));
      assertFalse(doc.foo.hasOwnProperty("a"));
      assertFalse(doc.foo.hasOwnProperty("foxx"));
      assertEqual("bart", doc.foo[0].bark);

      actual = AQL_EXECUTE(q, {});

      assertEqual(1, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      doc = c1.toArray()[0];
      assertEqual("foo", doc._key);
      assertTrue(doc.hasOwnProperty("foo"));
      assertFalse(doc.foo.hasOwnProperty("a"));
      assertFalse(doc.foo.hasOwnProperty("foxx"));
      assertEqual("bart", doc.foo[0].bark);
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateReturnOld : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = AQL_EXECUTE("FOR d IN @@cn UPDATE d WITH { value3: d.value1 + 5 } IN @@cn LET previous = OLD RETURN previous", { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.value1 - r.value1;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
        assertFalse(doc.hasOwnProperty("value3"));
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test update
////////////////////////////////////////////////////////////////////////////////

    testUpdateReturnNew : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      var actual = AQL_EXECUTE("FOR d IN @@cn UPDATE d WITH { value3: d.value1 + 5 } IN @@cn LET now = NEW RETURN now", { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.value1 - r.value1;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
        assertEqual(i + 5, doc.value3);
      }
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplace1 : function () {
      var i;
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn REPLACE d._key WITH { value4: 12 } INTO @@cn";
      var actual = getModifyQueryResults(query, { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertFalse(doc.hasOwnProperty("value1"));
        assertFalse(doc.hasOwnProperty("value2"));
        assertFalse(doc.hasOwnProperty("value3"));
        assertEqual(12, doc.value4);
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplace2 : function () {
      var i;
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn REPLACE { _key: d._key, value4: 13 } INTO @@cn";
      var actual = getModifyQueryResults(query, { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertFalse(doc.hasOwnProperty("value1"));
        assertFalse(doc.hasOwnProperty("value2"));
        assertFalse(doc.hasOwnProperty("value3"));
        assertEqual(13, doc.value4);
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplaceReplace : function () {
      var i;
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn REPLACE d._key WITH { value1: d.value1 + 1 } INTO @@cn";
      for (i = 0; i < 5; ++i) {
        var actual = getModifyQueryResults(query, { "@cn": cn1 });
        assertEqual(expected, sanitizeStats(actual));
      }

      for (i = 0; i < 100; ++i) {
        var doc = c1.document("test" + i);
        assertEqual(i + 5, doc.value1);
        assertFalse(doc.hasOwnProperty("value2"));
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplaceReturnOld : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn REPLACE d WITH { value3: d.value1 + 5 } IN @@cn LET previous = OLD RETURN previous";
      var actual = AQL_EXECUTE(query, { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.value1 - r.value1;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertEqual(i, doc.value1);
        assertEqual("test" + i, doc.value2);
        assertFalse(doc.hasOwnProperty("value3"));
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplaceReturnNew : function () {
      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn REPLACE d WITH { value3: d.value1 + 5 } IN @@cn LET now = NEW RETURN now";
      var actual = AQL_EXECUTE(query, { "@cn": cn1 });

      assertEqual(100, c1.count());
      assertEqual(expected, sanitizeStats(actual.stats));

      actual.json = actual.json.sort(function(l, r) {
        return l.value3 - r.value3;
      });

      for (var i = 0; i < 100; ++i) {
        var doc = actual.json[i];
        assertEqual("test" + i, doc._key);
        assertTrue(doc.hasOwnProperty("_id"));
        assertTrue(doc.hasOwnProperty("_rev"));
        assertFalse(doc.hasOwnProperty("value1"));
        assertFalse(doc.hasOwnProperty("value2"));
        assertEqual(i + 5, doc.value3);
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

////////////////////////////////////////////////////////////////////////////////
/// @brief test replace
////////////////////////////////////////////////////////////////////////////////

    testReplaceAfterInsert : function () {
      AQL_EXECUTE("FOR i IN 0..99 INSERT { _key: CONCAT('sometest', i), value: i, wantToFind: true } IN @@cn", { "@cn" : cn1 });

      var expected = { writesExecuted: 100, writesIgnored: 0 };
      let query = "FOR d IN @@cn FILTER d.wantToFind REPLACE d._key WITH { value2: d.value % 2 == 0 ? d.value : d.value + 1 } INTO @@cn";
      var actual = getModifyQueryResults(query, { "@cn": cn1 });
      assertEqual(expected, sanitizeStats(actual));

      for (var i = 0; i < 100; ++i) {
        var doc = c1.document("sometest" + i);
        assertEqual(i % 2 === 0 ? i : i + 1, doc.value2);
        assertFalse(doc.hasOwnProperty("value"));
        assertFalse(doc.hasOwnProperty("wantToFind"));
      }

      let rules = AQL_EXPLAIN(query, { "@cn": cn1 }).plan.rules;
      assertEqual(-1, rules.indexOf("restrict-to-single-shard"));
    },

///////////////////////////////////////////////////////////////////////////////
/// @brief test replace with empty object
/// replaces all documents with empty object, hence, the old documents would
/// have the "name" key, as the new documents wouldn't
////////////////////////////////////////////////////////////////////////////////

    testReplaceEmpty: function () {
      const actual = AQL_EXECUTE(`FOR doc IN ${cn2} REPLACE doc WITH {} IN ${cn2} RETURN {old: OLD, new: NEW}`);
      const res = actual.json;
      assertEqual(res.length, 1000);
      for (let i = 0; i < res.length; ++i) {
        assertNotEqual(res[i].old._rev, res[i].new._rev);
        assertFalse(res[i].new.hasOwnProperty("name"));
        assertTrue(res[i].old.hasOwnProperty("name"));
      }
    },

  };
}

jsunity.run(ahuacatlModifySuite);
jsunity.run(ahuacatlRemoveSuite);
jsunity.run(ahuacatlInsertSuite);
jsunity.run(ahuacatlUpdateSuite);

return jsunity.done();


text:
Fixed Width Icons

  Home

  Library

  Applications

  Settings

                Use fa-fw to set icons at a fixed width. Great to use when variable icon widths throw off
                alignment.
                Especially useful in things like nav lists.

            {% highlight html %}

 Home

 Library

 Applications

 Settings

            {% endhighlight %}

redpajama_set_name: RedPajamaGithub


text:
package ru.spoddubnyak.model;

import java.io.FileNotFoundException;
import java.util.*;

/**
 * Abstract Class Parsers parsing and output to the screen on the job.
 *
 * @author Sergei Poddubnyak (forvvard09@gmail.com)
 * @version 1.0
 * @since 05.02.2018
 */
public abstract class Parsers {
    /**
     * property for save path by file for parsing.
     */
    private static final String FILE_PATH = "D:/orders.xml";
    /**
     * property for a format print to empty value.
     */
    private static final String EMPTY_VALUE = "-----";
    /**
     * property for a format print to display.
     */
    private static final String NEW_LINE = System.getProperty("line.separator");
    /**
     * property Map for storage formating data and printing.
     */
    private final Map<String, AskBid> finalDataMap = new HashMap<>();
    /**
     * property allOrders for result parsing.
     */
    private Set<Order> allOrders = new HashSet<>();
    /**
     * property Map for storage all orders by algoritm for job.
     */
    private Map<String, BookOrder> ordersMap;
    /**
     * Obgect for storage final data.
     */
    private AskBid dataAskBid;

    /**
     * Getter for property FILE_PATH.
     *
     * @return path file for parsing
     */
    public String getFilePath() {
        return this.FILE_PATH;
    }

    /**
     * Getter for property allOrders.
     *
     * @return property allOrders
     */
    public final Set<Order> getAllOrders() {
        return this.allOrders;
    }

    /**
     * Method formating sorting Map of all olders.
     *
     * @param allOrders - all orders after pretreatment
     */
    private void formating(Set<Order> allOrders) {
        this.ordersMap = new HashMap<>();
        for (Order order : allOrders) {
            if (this.ordersMap.containsKey(order.getName())) {
                this.ordersMap.get(order.getName()).addOrder(order);
            } else if (!this.ordersMap.containsKey(order.getName())) {
                BookOrder bookOrder = new BookOrder();
                bookOrder.addOrder(order);
                this.ordersMap.put(order.getName(), bookOrder);
            }
        }
    }

    /**
     * Method formating data by algoritm job.
     *
     * @throws NoSuchElementException if not found elemeent in collections
     */
    private void formatingAskBid() throws NoSuchElementException {
        Iterator<String> mapIterator = this.ordersMap.keySet().iterator();
        while (mapIterator.hasNext()) {
            this.dataAskBid = new AskBid();
            String key = mapIterator.next().toString();
            this.finalDataMap.put(key, this.dataAskBid);
            BookOrder printCollections = this.ordersMap.get(key);
            Iterator<Order> buyIterator = printCollections.getBuyTree().iterator();
            Iterator<Order> sellIterator = printCollections.getSellTree().iterator();

            while (buyIterator.hasNext() || sellIterator.hasNext()) {
                Order buy;
                Order sell;
                if (!sellIterator.hasNext()) {
                    this.dataAskBid.getBid().add(buyIterator.next().toString());
                    this.dataAskBid.getAsk().add(this.EMPTY_VALUE);
                } else if (!buyIterator.hasNext()) {
                    this.dataAskBid.getAsk().add(sellIterator.next().toString());
                    this.dataAskBid.getBid().add(this.EMPTY_VALUE);
                } else if (buyIterator.hasNext() && sellIterator.hasNext()) {
                    buy = buyIterator.next();
                    sell = sellIterator.next();
                    if (buy.getPrice() <= sell.getPrice()) {
                        this.dataAskBid.getAsk().add(buy.toString());
                        this.dataAskBid.getBid().add(sell.toString());
                    }
                }
            }
        }
    }

    /**
     * Method print result.
     */
    private void printResult() {
        formatingAskBid();
        List<String> key = sortingByNameBook();
        for (int i = 0; i < key.size(); i++) {
            System.out.printf("%s      %s%s   %s ---> %s%s", this.NEW_LINE, key.get(i), this.NEW_LINE, "BID", "ASK", this.NEW_LINE);
            this.finalDataMap.get(key.get(i)).printAskBid();
        }
    }

    /**
     * Method sorting Map by name book for print.
     *
     * @return keyList sortng list, name book for print
     */
    private List<String> sortingByNameBook() {
        Iterator<String> mapIterator = this.finalDataMap.keySet().iterator();
        List<String> keyList = new ArrayList(this.finalDataMap.size());
        while (mapIterator.hasNext()) {
            keyList.add(mapIterator.next().toString());
        }
        Collections.sort(keyList);
        return keyList;
    }

    /**
     * Method start parsing and print result.
     *
     * @throws FileNotFoundException errors with xml file
     */
    public void toStart() throws FileNotFoundException {
        formating(parsingTo());
        printResult();
    }

    /**
     * abstartct method for parsing various methods .
     *
     * @return collections Set result parsing
     * @throws FileNotFoundException errors with xml file
     */
    public abstract Set<Order> parsingTo() throws FileNotFoundException;
}


text:
<?xml version="1.0" encoding="UTF-8"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>CLAROS — bringing classical art to a global public </title>
        <author><hi>Donna Kurtz</hi> (Beazley Archive, Classics),
	  <hi>David Shotton</hi> (Department of Zoology),
	  <hi>Florian Schroff</hi> (Engineering Science),
	  <hi>Yorick Wilks</hi> (Oxford Internet Institute),
	  <hi>Greg Parker</hi> (Beazley Archive),
	  <hi>Graham Klyne</hi> (Department of Zoology), and
	  <hi>Andrew Zisserman</hi> (Engineering Science). <lb/><emph>Presented by Sebastian
	Rahtz <lb/>(Oxford University Computing Services).</emph></author>
      </titleStmt>
      <editionStmt>
        <edition>
          <date>Oxford, December 12th 2009</date>
        </edition>
      </editionStmt>
      <publicationStmt>
        <publisher>University of Oxford</publisher>
        <availability>

Freely available for use and derivative works under a Creative Commons Attribution
            license.

        </availability>
      </publicationStmt>
      <sourceDesc>

Conference paper, and Shotton talk

      </sourceDesc>
    </fileDesc>
    <revisionDesc>
      <change>
        <date>$LastChangedDate: 2014-04-21 17:17:33 +0100 (Mon, 21 Apr 2014) $.</date>
        <name>$LastChangedBy: rahtz $</name>
        <note>$LastChangedRevision: 3477 $</note>
      </change>
    </revisionDesc>
  </teiHeader>
  <text>

        CLAROS: data resources

Target: <list>
	  <item>data web integrating access to the world's scholarly information on classical art</item>
	  <item>semantic integration of the distributed, heterogeneous
	  and non-interoperable digital resources held by CLAROS
	  partners</item>
	</list>

          <hi>University of Oxford – Beazley Archive:</hi>
          <list>
            <item>Electronic documentation started 1979</item>
            <item>150,000 Pottery records and 130,000 images</item>
            <item>50,000 Engraved gem and cameo records and 30,000 images</item>
            <item>900 Plaster casts records (classical sculpture) and 1000 images</item>
            <item>900 Antiquarian photographs</item>
          </list>

          <hi>University of Oxford - Lexicon of Greek Personal Names:</hi>
          <list>
            <item>Electronic documentation started 1975.</item>
            <item>400,000 recorded individuals. Over 35,000 unique  personal names.</item>
          </list>

	  CLAROS datasets (2)

	    <hi>University of Cologne – Research Sculpture Archive:</hi>
	    <list>
	      <item>Electronic documentation started 1972</item>
	      <item>250,000 Sculpture records, 490,000 images.</item>
	    </list>

	    <hi>German Archaeological Institute:</hi>
	    <list>
	      <item>1,500,000 photographs</item>
	    </list>

	    <hi>University of Paris X - Lexicon Iconographicum Mythologiae Classicae:</hi>
	    <list>
	      <item>Created 1972.</item>
	      <item>100,000 records, 180,000 images of mythological and religious iconography from 2,000 museums and collections.</item>
	    </list>

A total of 2 million records and images

	  Disparate technologies
	  <list type="gloss">
	    Beazley Archive
	    <item> 'XDB' – XML data, SQL Server Database, ASP front end.</item>
	    Cologne Research Archive and German Archaeological Institute
	    <item> 'Arachne'  - MySQL database, PHP front end.</item>
	    LIMC
            <item> MySQL database, PHP front end.</item>
            LGPN
            <item> Ingres relational database, also available as an
	    eXist XML database serving TEI-XML data. XQuery front end.</item>
          </list>

          The CLAROS data web approach
	  <list>
	    <item><hi>No changes</hi> to the databases of the individual sources</item>

	    <item><hi>Semantic differences</hi> between data sources
	    are resolved by mapping selected metadata from each source
	    to CIDOC-CRM</item>

	    <item><hi>Syntactic differences</hi> between data sources are
	    resolved by converting the selected metadata to RDF,
	    accessed from a single triple store using SPARQL</item>
	  </list>

	  Combining data

	    <graphic height="80%" url="combiningdata.png"/>

	    System Components

	      <graphic height="85%" url="systemcomponents.png"/>

	    Technicalities

	      <graphic width="90%" url="technicalities.png"/>

	    CLAROS and CIDOC CRM

We have found CIDOC CRM to be extremely well suited for CLAROS data

	    <list>
	      <item>We focused initially on the CIDOC CRM Core terms, and employed additional terms as necessary</item>

	      <item>CIDOC CRM Core can describe the complex provenance of artefacts and
	      their relationships with key events, people, places and times</item>
	      <item>The necessary complexity of the resulting RDF/XML
	      is mostly invisible to developers, and entirely hidden
	      from users </item>

	      <item>The CIDOC CRM "E55.Type" system is particularly
	      useful to permit faceted/drill-down queries,
	      e.g. restricting results by the shape of a pot
	      </item>
	    </list>

	    RDF example
	    <egXML xmlns="http://www.tei-c.org/ns/Examples" rend="tiny">
    <E21.Person xmlns="http://purl.org/NET/crm-owl#" rdf:about="http://clas-lgpn2.classics.ox.ac.uk/id/V1-85238">
        <P131.is_identified_by xml:lang="el-grc">
            <E82.Actor_Appellation>
                <rdf:value>Παράμονος</rdf:value>
            </E82.Actor_Appellation>
        </P131.is_identified_by>
        <P131.is_identified_by xml:lang="el-grc-x-lgpn">
            <E82.Actor_Appellation>
                <rdf:value>Paramonos</rdf:value>
            </E82.Actor_Appellation>
        </P131.is_identified_by>
        <P98.was_born>
            <E67.Birth>
                <P4.has_time-span>
                    <E52.Time-Span>
                        <P79.at_some_time_within>
                            <E61.Time_Primitive>
                                <claros:not_before xmlns:claros="http://purl.org/NET/Claros/vocab#" rdf:datatype="http://www.w3.org/2001/XMLSchema#gYear">-0225</claros:not_before>
                                <claros:not_after xmlns:claros="http://purl.org/NET/Claros/vocab#" rdf:datatype="http://www.w3.org/2001/XMLSchema#gYear">-0175</claros:not_after>
                            </E61.Time_Primitive>
                        </P79.at_some_time_within>
                    </E52.Time-Span>
                </P4.has_time-span>
                <P7.took_place_at rdf:resource="http://clas-lgpn2.classics.ox.ac.uk/placeid/LGPN_11270"/>
            </E67.Birth>
        </P98.was_born>
    </E21.Person>
	    </egXML>

	    CLAROS extensions to CIDOC CRM

A very few extensions were needed. e.g.
	    <list>
	    <item> some additional RDF
	vocabulary for time metadata relating to imprecise periods and eras
	i.e. claros:not_before and claros:not_after, applied to a
	crm:E61.Time_Primitive object</item>
	    </list>

This allows us to capture partial or imprecise quantitative
	information that is not expressed by a crm:has_PrimitiveTime
	property

New	properties have been introduced as OWL datatype properties on the
	primtive value objects

	    CLAROS dataweb delivery

CLAROS is simply a resource discovery service using
	    minimal metadata — the user is ultimately directed back to
	    the original data publisher's site for full information
	    about an event, object, place or person of interest.

        The CLAROS interface
	    <list>
	      <item>Each partner can integrate CLAROS data from the other partners using his own programming platform.</item>
	      <item>As an example Beazley Archive set up a <emph>CLAROS Explorer</emph> show what is possible.</item>
	    </list>

	      <graphic width="80%" url="explorer.jpg"/>

	      The CLAROS homepage

		<graphic height="70%" url="homepage.png"/>

	      CLAROS faceted browser

		<graphic  height="70%"  url="faceted.png"/>

        Image recognition

            <graphic url="imagerecognition.jpg"/>

          Shape representation

            <graphic url="shaperepresentation.jpg"/>

          Vase shape space

            <graphic   height="80%" url="vasespace.jpg"/>

          Compute three nearest neighbours for each vase

            <graphic  width="80%" url="vaseneighbours.jpg"/>

        Companions
	<list>
	  <item>Take the interface up a level from text
	  searching</item>
	  <item>Provide a personalized avatar: an agent or 'presence'
	  that stays with the user for long periods of time,
	  developing a relationship and 'knowing' its owners
	  preferences and wishes. It will communicate with the user
	  primarily by using and understanding speech.</item>
	</list>

Part of larger EU <hi>Companions</hi> project: <ptr target="http://www.companions-project.org/"/>

	The relevance of CLAROS

We believe that CLAROS is important because
	<list>
	  <item>It is not designed to be a demonstrator, but to
	  deliver real, complete, data</item>
	  <item>We are testing an ontology, CIDOC CRM, on a proper scale</item>
	  <item>There is a genuine collaboration between humanities,
	  engineering and computer science</item>
	  <item>We show the rest of humanities that the dataweb
	  approach can work</item>
	</list>

	  The future of CLAROS
	  <list>
	    <item>Enhance performance to a level acceptable to the
	    general public</item>
	    <item>Bring in new partners with more classical art
	    data</item>
	    <item>Develop visual search and analysis interfaces</item>
	    <item>Research dynamic aggregation</item>
	    <item>Expand the humanities dataweb concepts
	    chronologically and geographically</item>
	  </list>

  </text>
</TEI>


text:
<?php

require __DIR__ . '/../bootstrap.php';

// ### Create Web Profile
// Use the /web-profiles resource to create seamless payment experience profiles. See the payment experience overview for further information about using the /payment resource to create the PayPal payment and pass the experience_profile_id.
// Documentation available at https://developer.paypal.com/webapps/developer/docs/api/#create-a-web-experience-profile

// Lets create an instance of FlowConfig and add
// landing page type information
$flowConfig = new \PayPal\Api\FlowConfig();
// Type of PayPal page to be displayed when a user lands on the PayPal site for checkout. Allowed values: Billing or Login. When set to Billing, the Non-PayPal account landing page is used. When set to Login, the PayPal account login landing page is used.
$flowConfig->setLandingPageType("Billing");
// The URL on the merchant site for transferring to after a bank transfer payment.
$flowConfig->setBankTxnPendingUrl("http://www.yeowza.com/");

// Parameters for style and presentation.
$presentation = new \PayPal\Api\Presentation();

// A URL to logo image. Allowed vaues: .gif, .jpg, or .png.
$presentation->setLogoImage("http://www.yeowza.com/favico.ico")
//	A label that overrides the business name in the PayPal account on the PayPal pages.
    ->setBrandName("YeowZa! Paypal")
//  Locale of pages displayed by PayPal payment experience.
    ->setLocaleCode("US");

// Parameters for input fields customization.
$inputFields = new \PayPal\Api\InputFields();
// Enables the buyer to enter a note to the merchant on the PayPal page during checkout.
$inputFields->setAllowNote(true)
    // Determines whether or not PayPal displays shipping address fields on the experience pages. Allowed values: 0, 1, or 2. When set to 0, PayPal displays the shipping address on the PayPal pages. When set to 1, PayPal does not display shipping address fields whatsoever. When set to 2, if you do not pass the shipping address, PayPal obtains it from the buyer's account profile. For digital goods, this field is required, and you must set it to 1.
    ->setNoShipping(1)
    // Determines whether or not the PayPal pages should display the shipping address and not the shipping address on file with PayPal for this buyer. Displaying the PayPal street address on file does not allow the buyer to edit that address. Allowed values: 0 or 1. When set to 0, the PayPal pages should not display the shipping address. When set to 1, the PayPal pages should display the shipping address.
    ->setAddressOverride(0);

// #### Payment Web experience profile resource
$webProfile = new \PayPal\Api\WebProfile();

// Name of the web experience profile. Required. Must be unique
$webProfile->setName("YeowZa! T-Shirt Shop" . uniqid())
    // Parameters for flow configuration.
    ->setFlowConfig($flowConfig)
    // Parameters for style and presentation.
    ->setPresentation($presentation)
    // Parameters for input field customization.
    ->setInputFields($inputFields);

// For Sample Purposes Only.
$request = clone $webProfile;

try {
    // Use this call to create a profile.
    $createProfileResponse = $webProfile->create($apiContext);
} catch (\PayPal\Exception\PayPalConnectionException $ex) {
    // NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY
    ResultPrinter::printError("Created Web Profile", "Web Profile", null, $request, $ex);
    exit(1);
}

// NOTE: PLEASE DO NOT USE RESULTPRINTER CLASS IN YOUR ORIGINAL CODE. FOR SAMPLE ONLY
 ResultPrinter::printResult("Created Web Profile", "Web Profile", $createProfileResponse->getId(), $request, $createProfileResponse);

return $createProfileResponse;


text:
module.exports = function(e, {{from.column}}, request, action) {
	{{#if to.many}}{{else}}
	//case for -> a {{from.schema.name}} having only one {{to.schema.name}}
	//also send up the link between a {{from.schema.name}} and a {{to.schema.name}}
	if(parseInt({{from.column}}) && parseInt(request.data.{{to.column}})) {
		var {{to.column}} = request.data.{{to.column}};
		//send
		var url = this.Controller().getServerUrl() + '/{{name}}/create/';

		$.getJSON(url + {{from.column}} + '/' + {{to.column}}, function(response) {
			//if error
			if(response.error) {
				this.Controller().trigger('{{name}}-create-error',
				response.message, {{from.column}}, {{to.column}}, request, action);
				return;
			}

			this.Controller().trigger('{{name}}-create-success', {{from.column}}, {{to.column}}, request, action);
		}.bind(this));
	}
	{{/if}}
	{{#if from.many}}
	//case for -> a {{to.schema.name}} having many {{from.schema.name}}
	//when we create a {{to.schema.name}} and we know the {{from.schema.name}} id
	//lets make the link between a {{from.schema.name}} and a {{to.schema.name}}
	if(request.path.indexOf('/{{from.schema.name}}/create/{{name}}/') === 0) {
		//link to {{from.schema.name}}
		var {{to.column}} = request.variables[1];

		//send
		var url = this.Controller().getServerUrl() + '/{{name}}/create/';

		$.getJSON(url + {{from.column}} + '/' + {{to.column}}, function(response) {
			//if error
			if(response.error) {
				this.Controller().trigger('{{name}}-create-error',
				response.message, {{from.column}}, {{to.column}}, request, action);
				return;
			}

			this.Controller().trigger('{{name}}-create-success', {{from.column}}, {{to.column}}, request, action);
		}.bind(this));
	}
	{{/if}}
};


text:
<?php
/**
 * Created by PhpStorm.
 * User: Keegan Laur
 * Date: 21/04/2015
 * Time: 7:18 PM
 */
class listForm implements IModule {
    private $response;
    public function __construct(Request $request) {
        if(count($request->getParameters(true)) > 2) {
            $this->response = Response::fourOhFour();
            return;
        }
        if(! PermissionEngine::getInstance()->currentUserCanDo("canListUsers")) {
            $this->response = Response::fourOhThree();
            return;
        }
        $database = Database::getInstance();
        if(! $database->isConnected()) {
            $this->response = Response::fiveHundred();
            return;
        }
        $results = $database->getData("*", "user");
        if($results === false) {
            $this->response = Response::fiveHundred();
            return;
        }
        if($results === null) {
            $results = array();
        }
        $users = array();
        foreach($results as $rawData) {
            if($rawData['userID'] == 0) {
                continue;
            }
            $profilePictureLocation = new Link($rawData['profilePictureLocation']);
            $birthday = new DateTime($rawData['birthday']);
            if($rawData['active'] == 1) {
                $active = true;
            } else {
                $active = false;
            }
            if($rawData['isExternalAuthentication']) {
                $externalAuth = true;
            } else {
                $externalAuth = false;
            }
            $users[] = new User($rawData['userID'], $rawData['roleID'], $rawData['givenIdentifier'], $rawData['userName'], $rawData['firstName'], $rawData['lastName'], $rawData['email'], $profilePictureLocation, $birthday, $active, $externalAuth);
        }
        $this->response = new Response(200, "@users/list.twig", "All Users", "user", $users);
    }
    public function getResponse() {
        return $this->response;
    }
}


text:
@echo off
mkdir nupkgs
cd nupkgs
del /F /Q *.*
cd ..
set /p projectName="Enter ProjectName: "
cd %projectName%
dotnet restore
dotnet build -c Release
dotnet pack -c Release --no-build --output ../nupkgs
set /p key="Enter Key: "
cd ../nupkgs
dotnet nuget push *.nupkg -s https://www.myget.org/F/ruhul-amin/api/v2/package -k %key%
cd ..
cd ..


text:
import Ember from 'ember';

export default Ember.Component.extend({
  localClassNames: ['canvas-title-byline']
});