finished & tested DeleteStore
This commit is contained in:
		
							parent
							
								
									420821be31
								
							
						
					
					
						commit
						5e0d602e12
					
				@ -63,11 +63,12 @@ var options = minimist(process.argv.slice(2), {
 | 
				
			|||||||
    testfiles: 'src/**/*.js'
 | 
					    testfiles: 'src/**/*.js'
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					var yfiles = polyfills.concat(['src/y.js', 'src/Connector.js', 'src/OperationStore.js', 'src/Struct.js', 'src/Utils.js',
 | 
				
			||||||
 | 
					    'src/OperationStores/RedBlackTree.js', 'src/Memory.js', 'src/**/*.js'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var files = {
 | 
					var files = {
 | 
				
			||||||
  y: polyfills.concat(['src/y.js', 'src/Connector.js', 'src/OperationStore.js', 'src/Struct.js', 'src/Utils.js',
 | 
					  y: yfiles.concat(['!src/**/*.spec.js']),
 | 
				
			||||||
    'src/OperationStores/RedBlackTree.js', 'src/**/*.js', '!src/**/*.spec.js']),
 | 
					  test: yfiles.concat([options.testfiles]),
 | 
				
			||||||
  test: polyfills.concat([options.testfiles]),
 | 
					 | 
				
			||||||
  build_test: ['build_test/y.js']
 | 
					  build_test: ['build_test/y.js']
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -51,30 +51,63 @@ async function applyRandomTransactions (users, objects, transactions, numberOfTr
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
async function compareAllUsers(users){//eslint-disable-line
 | 
					async function compareAllUsers(users){//eslint-disable-line
 | 
				
			||||||
  var s1, s2
 | 
					  var s1, s2, ds1, ds2, allDels1, allDels2
 | 
				
			||||||
  var db1 = []
 | 
					  var db1 = []
 | 
				
			||||||
  function * t1 () {
 | 
					  function * t1 () {
 | 
				
			||||||
    s1 = yield* this.getStateSet()
 | 
					    s1 = yield* this.getStateSet()
 | 
				
			||||||
 | 
					    ds1 = yield* this.getDeletionSet()
 | 
				
			||||||
 | 
					    allDels1 = []
 | 
				
			||||||
 | 
					    yield* this.ds.iterate(null, null, function (d) {
 | 
				
			||||||
 | 
					      allDels1.push(d)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  function * t2 () {
 | 
					  function * t2 () {
 | 
				
			||||||
    s2 = yield* this.getStateSet()
 | 
					    s2 = yield* this.getStateSet()
 | 
				
			||||||
 | 
					    ds2 = yield* this.getDeletionSet()
 | 
				
			||||||
 | 
					    allDels2 = []
 | 
				
			||||||
 | 
					    yield* this.ds.iterate(null, null, function (d) {
 | 
				
			||||||
 | 
					      allDels2.push(d)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  await users[0].connector.flushAll()
 | 
					  await users[0].connector.flushAll()
 | 
				
			||||||
  for (var uid = 0; uid < users.length; uid++) {
 | 
					  for (var uid = 0; uid < users.length; uid++) {
 | 
				
			||||||
    if (s1 == null) {
 | 
					 | 
				
			||||||
    var u = users[uid]
 | 
					    var u = users[uid]
 | 
				
			||||||
 | 
					    // compare deleted ops against deleteStore
 | 
				
			||||||
 | 
					    u.db.os.iterate(null, null, function (o) {
 | 
				
			||||||
 | 
					      if (o.deleted === true) {
 | 
				
			||||||
 | 
					        expect(u.db.ds.isDeleted(o.id)).toBeTruthy()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    // compare deleteStore against deleted ops
 | 
				
			||||||
 | 
					    u.db.requestTransaction(function * () {
 | 
				
			||||||
 | 
					      var ds = []
 | 
				
			||||||
 | 
					      u.db.ds.iterate(null, null, function (d) {
 | 
				
			||||||
 | 
					        ds.push(d)
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      for (var j in ds) {
 | 
				
			||||||
 | 
					        var d = ds[j]
 | 
				
			||||||
 | 
					        for (var i = 0; i < d.len; i++) {
 | 
				
			||||||
 | 
					          var o = yield* this.getOperation([d.id[0], d.id[1] + i])
 | 
				
			||||||
 | 
					          expect(o.deleted).toBeTruthy()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    // compare allDels tree
 | 
				
			||||||
 | 
					    await wait()
 | 
				
			||||||
 | 
					    if (s1 == null) {
 | 
				
			||||||
      u.db.requestTransaction(t1)
 | 
					      u.db.requestTransaction(t1)
 | 
				
			||||||
      await wait()
 | 
					      await wait()
 | 
				
			||||||
      u.db.os.iterate(null, null, function(o){//eslint-disable-line
 | 
					      u.db.os.iterate(null, null, function(o){//eslint-disable-line
 | 
				
			||||||
        db1.push(o)
 | 
					        db1.push(o)
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      var u2 = users[uid]
 | 
					      u.db.requestTransaction(t2)
 | 
				
			||||||
      u2.db.requestTransaction(t2)
 | 
					 | 
				
			||||||
      await wait()
 | 
					      await wait()
 | 
				
			||||||
      expect(s1).toEqual(s2)
 | 
					      expect(s1).toEqual(s2)
 | 
				
			||||||
 | 
					      expect(allDels1).toEqual(allDels2) // inner structure
 | 
				
			||||||
 | 
					      expect(ds1).toEqual(ds2) // exported structure
 | 
				
			||||||
      var count = 0
 | 
					      var count = 0
 | 
				
			||||||
      u2.db.os.iterate(null, null, function(o){//eslint-disable-line
 | 
					      u.db.os.iterate(null, null, function(o){//eslint-disable-line
 | 
				
			||||||
        expect(db1[count++]).toEqual(o)
 | 
					        expect(db1[count++]).toEqual(o)
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -166,6 +166,9 @@ class AbstractOperationStore { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
          yield* Struct[op.struct].execute.call(this, op)
 | 
					          yield* Struct[op.struct].execute.call(this, op)
 | 
				
			||||||
          yield* this.addOperation(op)
 | 
					          yield* this.addOperation(op)
 | 
				
			||||||
          yield* this.store.operationAdded(this, op)
 | 
					          yield* this.store.operationAdded(this, op)
 | 
				
			||||||
 | 
					          if (op.deleted === true) {
 | 
				
			||||||
 | 
					            this.ds.delete(op.id)
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          // find next operation to execute
 | 
					          // find next operation to execute
 | 
				
			||||||
          op = this.store.waitingOperations.find([op.id[0], state.clock])
 | 
					          op = this.store.waitingOperations.find([op.id[0], state.clock])
 | 
				
			||||||
          if (op != null) {
 | 
					          if (op != null) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
/* global Struct, RBTree, Y */
 | 
					/* global Struct, RBTree, Y, compareIds */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function copyObject (o) {
 | 
					function copyObject (o) {
 | 
				
			||||||
  var c = {}
 | 
					  var c = {}
 | 
				
			||||||
@ -8,9 +8,13 @@ function copyObject (o) {
 | 
				
			|||||||
  return c
 | 
					  return c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DeletionStore { // eslint-disable-line
 | 
					class DeleteStore extends RBTree { // eslint-disable-line
 | 
				
			||||||
  constructor () {
 | 
					  constructor () {
 | 
				
			||||||
    this.ds = {}
 | 
					    super()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  isDeleted (id) {
 | 
				
			||||||
 | 
					    var n = this.findNodeWithUpperBound(id)
 | 
				
			||||||
 | 
					    return n !== null && n.val.id[0] === id[0] && id[0] < n.val.id[0] + n.val.len
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  delete (id) {
 | 
					  delete (id) {
 | 
				
			||||||
    var n = this.findNodeWithUpperBound(id)
 | 
					    var n = this.findNodeWithUpperBound(id)
 | 
				
			||||||
@ -18,43 +22,46 @@ class DeletionStore { // eslint-disable-line
 | 
				
			|||||||
      if (n.val.id[1] === id[1]) {
 | 
					      if (n.val.id[1] === id[1]) {
 | 
				
			||||||
        // already deleted
 | 
					        // already deleted
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      } else if (n.val.id[1] + n.val.length === id[1]) {
 | 
					      } else if (n.val.id[1] + n.val.len === id[1]) {
 | 
				
			||||||
        // can extend existing deletion
 | 
					        // can extend existing deletion
 | 
				
			||||||
        n.val.length++
 | 
					        n.val.len++
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        // cannot extend left
 | 
					        // cannot extend left
 | 
				
			||||||
        n = this.add({id: id, length: 1})
 | 
					        n = this.add({id: id, len: 1})
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      // cannot extend left
 | 
					      // cannot extend left
 | 
				
			||||||
      n = this.add({id: id, length: 1})
 | 
					      n = this.add({id: id, len: 1})
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    // can extend right?
 | 
				
			||||||
    var next = n.next()
 | 
					    var next = n.next()
 | 
				
			||||||
    if compareIds([n.val.id[0], n.val.id[1] + n.val.length], next.val.id) {
 | 
					    if (next !== null && compareIds([n.val.id[0], n.val.id[1] + n.val.len], next.val.id)) {
 | 
				
			||||||
      n.val.length += next.val.length
 | 
					      n.val.len = n.val.len + next.val.len
 | 
				
			||||||
      this.delete(next.val.id)
 | 
					      super.delete(next.val.id)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  // a DeleteSet (ds) describes all the deleted ops in the OS
 | 
					  // a DeleteSet (ds) describes all the deleted ops in the OS
 | 
				
			||||||
  toDeleteSet () {
 | 
					  toDeleteSet () {
 | 
				
			||||||
    var ds = {}
 | 
					    var ds = {}
 | 
				
			||||||
    this.iterate(null, null, function (n) {
 | 
					    this.iterate(null, null, function (n) {
 | 
				
			||||||
      var user = n.val.id[0]
 | 
					      var user = n.id[0]
 | 
				
			||||||
      var counter = n.val.id[1]
 | 
					      var counter = n.id[1]
 | 
				
			||||||
      var length = n.val.length
 | 
					      var len = n.len
 | 
				
			||||||
      var dv = ds[user]
 | 
					      var dv = ds[user]
 | 
				
			||||||
      if (dv === void 0) {
 | 
					      if (dv === void 0) {
 | 
				
			||||||
        dv = []
 | 
					        dv = []
 | 
				
			||||||
        ds[user] = dv
 | 
					        ds[user] = dv
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      dv.push([counter, length])
 | 
					      dv.push([counter, len])
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					    return ds
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  // returns a set of deletions that need to be applied in order to get to
 | 
					  // returns a set of deletions that need to be applied in order to get to
 | 
				
			||||||
  // the state of the supplied ds
 | 
					  // the state of the supplied ds
 | 
				
			||||||
  getDeletions (ds) {
 | 
					  getDeletions (ds) {
 | 
				
			||||||
    var deletions = []
 | 
					    var deletions = []
 | 
				
			||||||
      function createDeletions (user, start, length) {
 | 
					    function createDeletions (user, start, len) {
 | 
				
			||||||
        for (var c = start; c < start + length; c++) {
 | 
					      for (var c = start; c < start + len; c++) {
 | 
				
			||||||
        deletions.push({
 | 
					        deletions.push({
 | 
				
			||||||
          target: [user, c],
 | 
					          target: [user, c],
 | 
				
			||||||
          struct: 'Delete'
 | 
					          struct: 'Delete'
 | 
				
			||||||
@ -78,18 +85,18 @@ class DeletionStore { // eslint-disable-line
 | 
				
			|||||||
        //  *)=> if d does not delete anything anymore, go to next d (continue)
 | 
					        //  *)=> if d does not delete anything anymore, go to next d (continue)
 | 
				
			||||||
        while (d != null) {
 | 
					        while (d != null) {
 | 
				
			||||||
          var diff // describe the diff of length in 1) and 2)
 | 
					          var diff // describe the diff of length in 1) and 2)
 | 
				
			||||||
            if (n.val.id[1] + n.val.length <= d[0]) {
 | 
					          if (n.id[1] + n.len <= d[0]) {
 | 
				
			||||||
            // 1)
 | 
					            // 1)
 | 
				
			||||||
            break
 | 
					            break
 | 
				
			||||||
            } else if (d[0] < n.val.id[1]) {
 | 
					          } else if (d[0] < n.id[1]) {
 | 
				
			||||||
            // 2)
 | 
					            // 2)
 | 
				
			||||||
              // delete maximum the length of d
 | 
					            // delete maximum the len of d
 | 
				
			||||||
            // else delete as much as possible
 | 
					            // else delete as much as possible
 | 
				
			||||||
              diff = Math.min(n.val.id[1]-d[0], d[1])
 | 
					            diff = Math.min(n.id[1] - d[0], d[1])
 | 
				
			||||||
            createDeletions(user, d[0], diff)
 | 
					            createDeletions(user, d[0], diff)
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            // 3)
 | 
					            // 3)
 | 
				
			||||||
              diff = n.val.id[1] + n.val.length - d[0] // never null (see 1)
 | 
					            diff = n.id[1] + n.len - d[0] // never null (see 1)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          if (d[1] <= diff) {
 | 
					          if (d[1] <= diff) {
 | 
				
			||||||
            // d doesn't delete anything anymore
 | 
					            // d doesn't delete anything anymore
 | 
				
			||||||
@ -100,9 +107,11 @@ class DeletionStore { // eslint-disable-line
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      for (; pos < dv.len; pos++) {
 | 
				
			||||||
 | 
					        d = dv[pos]
 | 
				
			||||||
 | 
					        createDeletions(user, d[0], d[1])
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
      this.iterater()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -113,6 +122,16 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
      super(store)
 | 
					      super(store)
 | 
				
			||||||
      this.ss = store.ss
 | 
					      this.ss = store.ss
 | 
				
			||||||
      this.os = store.os
 | 
					      this.os = store.os
 | 
				
			||||||
 | 
					      this.ds = store.ds
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    * getDeletionSet (id) {
 | 
				
			||||||
 | 
					      return this.ds.toDeleteSet(id)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    * isDeleted (id) {
 | 
				
			||||||
 | 
					      return this.ds.isDeleted(id)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    * getDeletions (ds) {
 | 
				
			||||||
 | 
					      return this.ds.getDeletions(ds)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    * setOperation (op) { // eslint-disable-line
 | 
					    * setOperation (op) { // eslint-disable-line
 | 
				
			||||||
      // TODO: you can remove this step! probs..
 | 
					      // TODO: you can remove this step! probs..
 | 
				
			||||||
@ -209,6 +228,10 @@ Y.Memory = (function () { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
      this.ss = {}
 | 
					      this.ss = {}
 | 
				
			||||||
      this.waitingTransactions = []
 | 
					      this.waitingTransactions = []
 | 
				
			||||||
      this.transactionInProgress = false
 | 
					      this.transactionInProgress = false
 | 
				
			||||||
 | 
					      this.ds = new DeleteStore()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    logTable () {
 | 
				
			||||||
 | 
					      this.os.logTable()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    requestTransaction (_makeGen) {
 | 
					    requestTransaction (_makeGen) {
 | 
				
			||||||
      if (!this.transactionInProgress) {
 | 
					      if (!this.transactionInProgress) {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										23
									
								
								src/OperationStores/Memory.spec.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/OperationStores/Memory.spec.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					/* global DeleteStore */
 | 
				
			||||||
 | 
					/* eslint-env browser,jasmine,console */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe('Memory', function () {
 | 
				
			||||||
 | 
					  describe('DeleteStore', function () {
 | 
				
			||||||
 | 
					    var ds
 | 
				
			||||||
 | 
					    beforeEach(function () {
 | 
				
			||||||
 | 
					      ds = new DeleteStore()
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    it('Deleted operation is deleted', function () {
 | 
				
			||||||
 | 
					      ds.delete(['u1', 10])
 | 
				
			||||||
 | 
					      expect(ds.isDeleted(['u1', 10])).toBeTruthy()
 | 
				
			||||||
 | 
					      expect(ds.toDeleteSet()).toBeTruthy({'u1': [10, 1]})
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    it('Deleted operation extends other deleted operation', function () {
 | 
				
			||||||
 | 
					      ds.delete(['u1', 10])
 | 
				
			||||||
 | 
					      ds.delete(['u1', 11])
 | 
				
			||||||
 | 
					      expect(ds.isDeleted(['u1', 10])).toBeTruthy()
 | 
				
			||||||
 | 
					      expect(ds.isDeleted(['u1', 11])).toBeTruthy()
 | 
				
			||||||
 | 
					      expect(ds.toDeleteSet()).toBeTruthy({'u1': [10, 2]})
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
/* global compareIds */
 | 
					/* global compareIds, copyObject */
 | 
				
			||||||
function smaller (a, b) {
 | 
					function smaller (a, b) {
 | 
				
			||||||
  return a[0] < b[0] || (a[0] === b[0] && a[1] < b[1])
 | 
					  return a[0] < b[0] || (a[0] === b[0] && a[1] < b[1])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -192,6 +192,18 @@ class RBTree { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return true
 | 
					    return true
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  logTable (from = null, to = null) {
 | 
				
			||||||
 | 
					    var os = []
 | 
				
			||||||
 | 
					    this.iterate(from, to, function (o) {
 | 
				
			||||||
 | 
					      var o_ = copyObject(o)
 | 
				
			||||||
 | 
					      var id = o_.id
 | 
				
			||||||
 | 
					      delete o_.id
 | 
				
			||||||
 | 
					      o_['id[0]'] = id[0]
 | 
				
			||||||
 | 
					      o_['id[1]'] = id[1]
 | 
				
			||||||
 | 
					      os.push(o_)
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					    console.table(os)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  find (id) {
 | 
					  find (id) {
 | 
				
			||||||
    return this.findNode(id).val
 | 
					    return this.findNode(id).val
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -382,7 +394,7 @@ class RBTree { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
            p = p.right
 | 
					            p = p.right
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          return false
 | 
					          return null
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this._fixInsert(node)
 | 
					      this._fixInsert(node)
 | 
				
			||||||
@ -391,6 +403,7 @@ class RBTree { // eslint-disable-line no-unused-vars
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    this.length++
 | 
					    this.length++
 | 
				
			||||||
    this.root.blacken()
 | 
					    this.root.blacken()
 | 
				
			||||||
 | 
					    return node
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  _fixInsert (n) {
 | 
					  _fixInsert (n) {
 | 
				
			||||||
    if (n.parent === null) {
 | 
					    if (n.parent === null) {
 | 
				
			||||||
 | 
				
			|||||||
@ -32,6 +32,7 @@ var Struct = {
 | 
				
			|||||||
      if (!target.deleted) {
 | 
					      if (!target.deleted) {
 | 
				
			||||||
        target.deleted = true
 | 
					        target.deleted = true
 | 
				
			||||||
        yield* this.setOperation(target)
 | 
					        yield* this.setOperation(target)
 | 
				
			||||||
 | 
					        this.ds.delete(target.id)
 | 
				
			||||||
        var t = this.store.initializedTypes[JSON.stringify(target.parent)]
 | 
					        var t = this.store.initializedTypes[JSON.stringify(target.parent)]
 | 
				
			||||||
        if (t != null) {
 | 
					        if (t != null) {
 | 
				
			||||||
          yield* t._changed(this, copyObject(op))
 | 
					          yield* t._changed(this, copyObject(op))
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user